c tree inlining vs dwarf2

Richard Henderson rth@redhat.com
Mon Oct 8 09:42:00 GMT 2001


Dwarf2 expects any function that has been inlined to have the DECL_INLINE
bit set.  Failure to do so will get it confused and abort trying to create
a second die for the function.

The C++ front end distinguishes between whether a function is declared
inline, and whether it is inlinable.  At -O3, it sets DECL_INLINE on
pretty much all functions.

This changes the C front end to do the same thing.

Bootstrapped on alpha (dwarf2) and i686 (stabs) linux.


r~


        * c-common.h (struct c_lang_decl): Add declared_inline.
        * c-tree.h (DECL_DECLARED_INLINE_P): New.
        * c-lang.c (c_disregard_inline_limits): Use it.
        * c-decl.c (duplicate_decls): Likewise.
        (pushdecl, redeclaration_error_message): Likewise.
        (pushdecl): Allocate DECL_LANG_SPECIFIC if needed.
        (grokdeclarator): Likewise.  Set DECL_DECLARED_INLINE_P.
        Set DECL_INLINE if -finline-functions.
        (store_parm_decls): Don't allocate DECL_LANG_SPECIFIC here.

        * cp-tree.h (struct lang_decl_flags): Remove declared_inline.
        (DECL_DECLARED_INLINE_P): Use the bit in struct c_lang_decl.

Index: c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.88
diff -c -p -d -r1.88 c-common.h
*** c-common.h	2001/10/05 02:49:15	1.88
--- c-common.h	2001/10/08 16:27:48
*************** extern void mark_stmt_tree              
*** 338,344 ****
     DECL_LANG_SPECIFIC field.  */
  
  struct c_lang_decl {
!   char dummy;
  };
  
  /* In a FUNCTION_DECL for which DECL_BUILT_IN does not hold, this is
--- 338,344 ----
     DECL_LANG_SPECIFIC field.  */
  
  struct c_lang_decl {
!   unsigned declared_inline : 1;
  };
  
  /* In a FUNCTION_DECL for which DECL_BUILT_IN does not hold, this is
Index: c-decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-decl.c,v
retrieving revision 1.250
diff -c -p -d -r1.250 c-decl.c
*** c-decl.c	2001/10/07 18:02:43	1.250
--- c-decl.c	2001/10/08 16:27:48
*************** duplicate_decls (newdecl, olddecl, diffe
*** 1727,1738 ****
  	  /* Warn if function is now inline
  	     but was previously declared not inline and has been called.  */
  	  if (TREE_CODE (olddecl) == FUNCTION_DECL
! 	      && ! DECL_INLINE (olddecl) && DECL_INLINE (newdecl)
  	      && TREE_USED (olddecl))
  	    warning_with_decl (newdecl,
  			       "`%s' declared inline after being called");
  	  if (TREE_CODE (olddecl) == FUNCTION_DECL
! 	      && ! DECL_INLINE (olddecl) && DECL_INLINE (newdecl)
  	      && DECL_INITIAL (olddecl) != 0)
  	    warning_with_decl (newdecl,
  			       "`%s' declared inline after its definition");
--- 1727,1740 ----
  	  /* Warn if function is now inline
  	     but was previously declared not inline and has been called.  */
  	  if (TREE_CODE (olddecl) == FUNCTION_DECL
! 	      && ! DECL_DECLARED_INLINE_P (olddecl)
! 	      && DECL_DECLARED_INLINE_P (newdecl)
  	      && TREE_USED (olddecl))
  	    warning_with_decl (newdecl,
  			       "`%s' declared inline after being called");
  	  if (TREE_CODE (olddecl) == FUNCTION_DECL
! 	      && ! DECL_DECLARED_INLINE_P (olddecl)
! 	      && DECL_DECLARED_INLINE_P (newdecl)
  	      && DECL_INITIAL (olddecl) != 0)
  	    warning_with_decl (newdecl,
  			       "`%s' declared inline after its definition");
*************** duplicate_decls (newdecl, olddecl, diffe
*** 1976,1985 ****
  	{
  	  /* If either decl says `inline', this fn is inline,
  	     unless its definition was passed already.  */
! 	  if (DECL_INLINE (newdecl) && DECL_INITIAL (olddecl) == 0)
! 	    DECL_INLINE (olddecl) = 1;
  
! 	  DECL_INLINE (newdecl) = DECL_INLINE (olddecl);
  	}
  
        if (DECL_BUILT_IN (olddecl))
--- 1978,1988 ----
  	{
  	  /* If either decl says `inline', this fn is inline,
  	     unless its definition was passed already.  */
! 	  if (DECL_DECLARED_INLINE_P (newdecl)
! 	      && DECL_DECLARED_INLINE_P (olddecl) == 0)
! 	    DECL_DECLARED_INLINE_P (olddecl) = 1;
  
! 	  DECL_DECLARED_INLINE_P (newdecl) = DECL_DECLARED_INLINE_P (olddecl);
  	}
  
        if (DECL_BUILT_IN (olddecl))
*************** pushdecl (x)
*** 2056,2061 ****
--- 2059,2069 ----
    register tree name = DECL_NAME (x);
    register struct binding_level *b = current_binding_level;
  
+   /* Functions need the lang_decl data.  */
+   if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_LANG_SPECIFIC (x))
+     DECL_LANG_SPECIFIC (x) = (struct lang_decl *)
+       ggc_alloc_cleared (sizeof (struct lang_decl));
+ 
    DECL_CONTEXT (x) = current_function_decl;
    /* A local extern declaration for a function doesn't constitute nesting.
       A local auto declaration does, since it's a forward decl
*************** pushdecl (x)
*** 2351,2357 ****
  	      && oldglobal != 0
  	      && TREE_CODE (x) == FUNCTION_DECL
  	      && TREE_CODE (oldglobal) == FUNCTION_DECL
! 	      && DECL_EXTERNAL (x) && ! DECL_INLINE (x))
  	    {
  	      /* We have one.  Their types must agree.  */
  	      if (! comptypes (TREE_TYPE (x),
--- 2359,2366 ----
  	      && oldglobal != 0
  	      && TREE_CODE (x) == FUNCTION_DECL
  	      && TREE_CODE (oldglobal) == FUNCTION_DECL
! 	      && DECL_EXTERNAL (x)
! 	      && ! DECL_DECLARED_INLINE_P (x))
  	    {
  	      /* We have one.  Their types must agree.  */
  	      if (! comptypes (TREE_TYPE (x),
*************** pushdecl (x)
*** 2361,2368 ****
  		{
  		  /* Inner extern decl is inline if global one is.
  		     Copy enough to really inline it.  */
! 		  if (DECL_INLINE (oldglobal))
  		    {
  		      DECL_INLINE (x) = DECL_INLINE (oldglobal);
  		      DECL_INITIAL (x) = (current_function_decl == oldglobal
  					  ? 0 : DECL_INITIAL (oldglobal));
--- 2370,2379 ----
  		{
  		  /* Inner extern decl is inline if global one is.
  		     Copy enough to really inline it.  */
! 		  if (DECL_DECLARED_INLINE_P (oldglobal))
  		    {
+ 		      DECL_DECLARED_INLINE_P (x)
+ 		        = DECL_DECLARED_INLINE_P (oldglobal);
  		      DECL_INLINE (x) = DECL_INLINE (oldglobal);
  		      DECL_INITIAL (x) = (current_function_decl == oldglobal
  					  ? 0 : DECL_INITIAL (oldglobal));
*************** redeclaration_error_message (newdecl, ol
*** 2613,2620 ****
        if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0
  	  /* However, defining once as extern inline and a second
  	     time in another way is ok.  */
! 	  && ! (DECL_INLINE (olddecl) && DECL_EXTERNAL (olddecl)
! 	       && ! (DECL_INLINE (newdecl) && DECL_EXTERNAL (newdecl))))
  	return 1;
        return 0;
      }
--- 2624,2632 ----
        if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0
  	  /* However, defining once as extern inline and a second
  	     time in another way is ok.  */
! 	  && ! (DECL_DECLARED_INLINE_P (olddecl) && DECL_EXTERNAL (olddecl)
! 	       && ! (DECL_DECLARED_INLINE_P (newdecl)
! 		     && DECL_EXTERNAL (newdecl))))
  	return 1;
        return 0;
      }
*************** grokdeclarator (declarator, declspecs, d
*** 4913,4918 ****
--- 4925,4933 ----
  	decl = build_decl (FUNCTION_DECL, declarator, type);
  	decl = build_decl_attribute_variant (decl, decl_attr);
  
+ 	DECL_LANG_SPECIFIC (decl) = (struct lang_decl *)
+ 	  ggc_alloc_cleared (sizeof (struct lang_decl));
+ 
  	if (pedantic && type_quals && ! DECL_IN_SYSTEM_HEADER (decl))
  	  pedwarn ("ISO C forbids qualified function types");
  
*************** grokdeclarator (declarator, declspecs, d
*** 4929,4945 ****
  	  = !(specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_AUTO)));
  
  	/* Record presence of `inline', if it is reasonable.  */
! 	if (inlinep)
  	  {
! 	    if (MAIN_NAME_P (declarator))
  	      warning ("cannot inline function `main'");
! 	    else
! 	      /* Assume that otherwise the function can be inlined.  */
! 	      DECL_INLINE (decl) = 1;
  
  	    if (specbits & (1 << (int) RID_EXTERN))
  	      current_extern_inline = 1;
  	  }
        }
      else
        {
--- 4944,4971 ----
  	  = !(specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_AUTO)));
  
  	/* Record presence of `inline', if it is reasonable.  */
! 	if (MAIN_NAME_P (declarator))
  	  {
! 	    if (inlinep)
  	      warning ("cannot inline function `main'");
! 	  }
! 	else if (inlinep)
! 	  {
! 	    /* Assume that otherwise the function can be inlined.  */
! 	    DECL_INLINE (decl) = 1;
! 	    DECL_DECLARED_INLINE_P (decl) = 1;
  
  	    if (specbits & (1 << (int) RID_EXTERN))
  	      current_extern_inline = 1;
  	  }
+ 	/* If -finline-functions, assume it can be inlined.  This does
+ 	   two things: let the function be deferred until it is actually
+ 	   needed, and let dwarf2 know that the function is inlinable.  */
+ 	else if (flag_inline_trees == 2)
+ 	  {
+ 	    DECL_INLINE (decl) = 1;
+ 	    DECL_DECLARED_INLINE_P (decl) = 0;
+ 	  }
        }
      else
        {
*************** store_parm_decls ()
*** 6593,6600 ****
    init_function_start (fndecl, input_filename, lineno);
  
    /* Begin the statement tree for this function.  */
-   DECL_LANG_SPECIFIC (current_function_decl)
-     =((struct lang_decl *) ggc_alloc_cleared (sizeof (struct lang_decl)));
    begin_stmt_tree (&DECL_SAVED_TREE (current_function_decl));
  
    /* If this is a nested function, save away the sizes of any
--- 6619,6624 ----
Index: c-lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-lang.c,v
retrieving revision 1.55
diff -c -p -d -r1.55 c-lang.c
*** c-lang.c	2001/10/05 04:20:27	1.55
--- c-lang.c	2001/10/08 16:27:48
*************** static int
*** 340,346 ****
  c_disregard_inline_limits (fn)
       tree fn;
  {
!   return DECL_INLINE (fn) && DECL_EXTERNAL (fn);
  }
  
  static tree inline_forbidden_p PARAMS ((tree *, int *, void *));
--- 340,346 ----
  c_disregard_inline_limits (fn)
       tree fn;
  {
!   return DECL_DECLARED_INLINE_P (fn) && DECL_EXTERNAL (fn);
  }
  
  static tree inline_forbidden_p PARAMS ((tree *, int *, void *));
Index: c-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-tree.h,v
retrieving revision 1.68
diff -c -p -d -r1.68 c-tree.h
*** c-tree.h	2001/09/06 08:59:36	1.68
--- c-tree.h	2001/10/08 16:27:48
*************** struct lang_decl
*** 98,105 ****
  /* In an IDENTIFIER_NODE, nonzero if this identifier is actually a
     keyword.  C_RID_CODE (node) is then the RID_* value of the keyword,
     and C_RID_YYCODE is the token number wanted by Yacc.  */
- 
  #define C_IS_RESERVED_WORD(id) TREE_LANG_FLAG_0 (id)
  
  /* In a RECORD_TYPE, a sorted array of the fields of the type.  */
  struct lang_type
--- 98,110 ----
  /* In an IDENTIFIER_NODE, nonzero if this identifier is actually a
     keyword.  C_RID_CODE (node) is then the RID_* value of the keyword,
     and C_RID_YYCODE is the token number wanted by Yacc.  */
  #define C_IS_RESERVED_WORD(id) TREE_LANG_FLAG_0 (id)
+ 
+ /* This function was declared inline.  This flag controls the linkage
+    semantics of 'inline'; whether or not the function is inlined is
+    controlled by DECL_INLINE.  */
+ #define DECL_DECLARED_INLINE_P(NODE) \
+   (DECL_LANG_SPECIFIC (NODE)->base.declared_inline)
  
  /* In a RECORD_TYPE, a sorted array of the fields of the type.  */
  struct lang_type
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.645
diff -c -p -d -r1.645 cp-tree.h
*** cp-tree.h	2001/10/05 02:48:44	1.645
--- cp-tree.h	2001/10/08 16:27:52
*************** struct lang_decl_flags
*** 1705,1721 ****
    unsigned deferred : 1;
    unsigned use_template : 2;
    unsigned nonconverting : 1;
-   unsigned declared_inline : 1;
    unsigned not_really_extern : 1;
    unsigned needs_final_overrider : 1;
    unsigned initialized_in_class : 1;
- 
    unsigned pending_inline_p : 1;
    unsigned global_ctor_p : 1;
    unsigned global_dtor_p : 1;
    unsigned assignment_operator_p : 1;
    unsigned anticipated_p : 1;
!   /* Three unused bits.  */
  
    union {
      /* In a FUNCTION_DECL, VAR_DECL, TYPE_DECL, or TEMPLATE_DECL, this
--- 1705,1720 ----
    unsigned deferred : 1;
    unsigned use_template : 2;
    unsigned nonconverting : 1;
    unsigned not_really_extern : 1;
    unsigned needs_final_overrider : 1;
    unsigned initialized_in_class : 1;
    unsigned pending_inline_p : 1;
+ 
    unsigned global_ctor_p : 1;
    unsigned global_dtor_p : 1;
    unsigned assignment_operator_p : 1;
    unsigned anticipated_p : 1;
!   /* Four unused bits.  */
  
    union {
      /* In a FUNCTION_DECL, VAR_DECL, TYPE_DECL, or TEMPLATE_DECL, this
*************** enum ptrmemfunc_vbit_where_t
*** 2838,2844 ****
     semantics of 'inline'; whether or not the function is inlined is
     controlled by DECL_INLINE.  */
  #define DECL_DECLARED_INLINE_P(NODE) \
!   (DECL_LANG_SPECIFIC (NODE)->decl_flags.declared_inline)
  
  /* DECL_EXTERNAL must be set on a decl until the decl is actually emitted,
     so that assemble_external will work properly.  So we have this flag to
--- 2837,2843 ----
     semantics of 'inline'; whether or not the function is inlined is
     controlled by DECL_INLINE.  */
  #define DECL_DECLARED_INLINE_P(NODE) \
!   (DECL_LANG_SPECIFIC (NODE)->decl_flags.base.declared_inline)
  
  /* DECL_EXTERNAL must be set on a decl until the decl is actually emitted,
     so that assemble_external will work properly.  So we have this flag to



More information about the Gcc-patches mailing list