This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

PATCH: better diagnostic on inline failure


Hi,
here is a patch for both gcc and g++ which gives a better diagnostic when a
function cannot be inlined due to it not being defined yet. The current
behaviour is to warn at the point of inlining. With the patch, the location of
the declaration of the inlined function is also shown. In addition, the
function which first calls the inlined function is remembered. When the
definition of the inline function is met, a diagnostic indicates that it has
already been called and shows that point. This gives the programmer more
information about how to rearrange code to get the ordering correct. These
diagnostics only occur with optimization enabled (-O2), and the inline warnings
enabled (-Winline).

Here is an example of the patched output,

warn4.C: In function `void Fn()':
warn4.C:24: warning: cannot inline before definition
warn4.C:9: warning: of `int F2()' declared here
warn4.C: In function `int F2()':
warn4.C:27: warning: already failed to inline, first called
warn4.C:22: warning: within `void Fn()' defined here

I've made this work by adding a first_callee member to a tree_decl, and then
defining some macros to set and access this member. An attempt at inlining,
sets this member and the start of function definition checks it and issues a
diagnostic if not empty.

Enjoy,

nathan
-- 
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
      You can up the bandwidth, but you can't up the speed of light      
nathan@acm.org  http://www.cs.bris.ac.uk/~nathan/  nathan@cs.bris.ac.uk
egcs/gcc/ChangeLog:
Mon Feb  8 16:50:06 GMT 1999  Nathan Sidwell  <nathan@acm.org>

	* tree.h (DECL_FIRST_CALLEE): New macro.
	(tree_decl) Add first_callee member.
	* c-decl.c (duplicate_decls): Preserve DECL_FIRST_CALLEE from
	old decl.
	(start_function): Check DECL_FIRST_CALLEE, and issue inline failure
	warning if set.
	* calls.c (expand_call): Set DECL_FIRST_CALLEE, if failed to
	inline because no definition.

egcs/gcc/cp/ChangeLog:
Mon Feb  8 16:50:06 GMT 1999  Nathan Sidwell  <nathan@acm.org>

	* decl.c (duplicate_decls): Preserve DECL_FIRST_CALLEE from old
	decl.
	(start_function): Check DECL_FIRST_CALLEE, and issue inline
	failure warning if set.

Index: egcs/gcc/tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/tree.h,v
retrieving revision 1.63
diff -c -3 -p -r1.63 tree.h
*** tree.h	1999/01/24 07:24:00	1.63
--- tree.h	1999/02/08 16:47:51
*************** struct tree_type
*** 1098,1103 ****
--- 1098,1105 ----
  #define DECL_SET_FUNCTION_CODE(NODE,VAL) (DECL_CHECK (NODE)->decl.frame_size.f = (VAL))
  /* For a FIELD_DECL, holds the size of the member as an integer.  */
  #define DECL_FIELD_SIZE(NODE) (DECL_CHECK (NODE)->decl.saved_insns.i)
+ /* For a FUNCTION_DECL, holds the first caller */
+ #define DECL_FIRST_CALLEE(NODE) (DECL_CHECK (NODE)->decl.first_callee)
  
  /* The DECL_VINDEX is used for FUNCTION_DECLS in two different ways.
     Before the struct containing the FUNCTION_DECL is laid out,
*************** struct tree_decl
*** 1350,1355 ****
--- 1352,1360 ----
    int pointer_alias_set;
    /* Points to a structure whose details depend on the language in use.  */
    struct lang_decl *lang_specific;
+   /* For FUNCTION_DECLs points to decl of first function which calls this
+    * one. Used to help in diagnostics of inline failures */
+   tree first_callee;
  };
  
  /* Define the overall contents of a tree node.
Index: egcs/gcc/c-decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-decl.c,v
retrieving revision 1.58
diff -c -3 -p -r1.58 c-decl.c
*** c-decl.c	1999/01/27 01:41:43	1.58
--- c-decl.c	1999/02/08 16:47:56
*************** duplicate_decls (newdecl, olddecl, diffe
*** 2124,2137 ****
      }
  
    /* Copy most of the decl-specific fields of NEWDECL into OLDDECL.
!      But preserve OLDDECL's DECL_UID.  */
    {
      register unsigned olddecl_uid = DECL_UID (olddecl);
  
      bcopy ((char *) newdecl + sizeof (struct tree_common),
  	   (char *) olddecl + sizeof (struct tree_common),
  	   sizeof (struct tree_decl) - sizeof (struct tree_common));
      DECL_UID (olddecl) = olddecl_uid;
    }
  
    /* NEWDECL contains the merged attribute lists.
--- 2124,2139 ----
      }
  
    /* Copy most of the decl-specific fields of NEWDECL into OLDDECL.
!      But preserve OLDDECL's DECL_UID and DECL_FIRST_CALLEE.  */
    {
      register unsigned olddecl_uid = DECL_UID (olddecl);
+     tree olddecl_first_callee = DECL_FIRST_CALLEE (olddecl);
  
      bcopy ((char *) newdecl + sizeof (struct tree_common),
  	   (char *) olddecl + sizeof (struct tree_common),
  	   sizeof (struct tree_decl) - sizeof (struct tree_common));
      DECL_UID (olddecl) = olddecl_uid;
+     DECL_FIRST_CALLEE (olddecl) = olddecl_first_callee;
    }
  
    /* NEWDECL contains the merged attribute lists.
*************** start_function (declspecs, declarator, p
*** 6417,6422 ****
--- 6419,6425 ----
    tree decl1, old_decl;
    tree restype;
    int old_immediate_size_expand = immediate_size_expand;
+   tree first_callee;
  
    current_function_returns_value = 0;  /* Assume, until we see it does.  */
    current_function_returns_null = 0;
*************** start_function (declspecs, declarator, p
*** 6600,6605 ****
--- 6603,6614 ----
       use the old decl.  */
  
    current_function_decl = pushdecl (decl1);
+ 
+   first_callee = DECL_FIRST_CALLEE (current_function_decl);
+   if (first_callee)
+     {
+       warning_with_decl (first_callee, "already failed to inline in `%s'");
+     }
  
    pushlevel (0);
    declare_parm_level (1);
Index: egcs/gcc/calls.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/calls.c,v
retrieving revision 1.42
diff -c -3 -p -r1.42 calls.c
*** calls.c	1999/01/27 01:41:50	1.42
--- calls.c	1999/02/08 16:47:59
*************** expand_call (exp, target, ignore)
*** 977,983 ****
  		  && optimize > 0)
  		{
  		  warning_with_decl (fndecl, "can't inline call to `%s'");
! 		  warning ("called from here");
  		}
  	      mark_addressable (fndecl);
  	    }
--- 977,985 ----
  		  && optimize > 0)
  		{
  		  warning_with_decl (fndecl, "can't inline call to `%s'");
! 		  warning ("called from here before definition");
!                   if (! DECL_FIRST_CALLEE (fndecl))
!                     DECL_FIRST_CALLEE (fndecl) = current_function_decl;
  		}
  	      mark_addressable (fndecl);
  	    }
Index: egcs/gcc/cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.305
diff -c -3 -p -r1.305 decl.c
*** decl.c	1999/01/28 09:47:48	1.305
--- decl.c	1999/02/08 16:48:07
*************** duplicate_decls (newdecl, olddecl)
*** 2858,2863 ****
--- 2858,2864 ----
  {
    extern struct obstack permanent_obstack;
    unsigned olddecl_uid = DECL_UID (olddecl);
+   tree olddecl_first_callee = DECL_FIRST_CALLEE (olddecl);
    int olddecl_friend = 0, types_match = 0;
    int new_defines_function = 0;
  
*************** duplicate_decls (newdecl, olddecl)
*** 3507,3512 ****
--- 3508,3514 ----
      }
  
    DECL_UID (olddecl) = olddecl_uid;
+   DECL_FIRST_CALLEE (olddecl) = olddecl_first_callee;
    if (olddecl_friend)
      DECL_FRIEND_P (olddecl) = 1;
  
*************** start_function (declspecs, declarator, a
*** 12815,12820 ****
--- 12817,12823 ----
    extern int have_extern_spec;
    extern int used_extern_spec;
    int doing_friend = 0;
+   tree first_callee;
  
    /* Sanity check.  */
    my_friendly_assert (TREE_CODE (TREE_VALUE (void_list_node)) == VOID_TYPE, 160);
*************** start_function (declspecs, declarator, a
*** 13045,13050 ****
--- 13048,13059 ----
      }
  
    current_function_decl = decl1;
+ 
+   first_callee = DECL_FIRST_CALLEE (current_function_decl);
+   if (first_callee)
+     {
+       warning_with_decl (first_callee, "already failed to inline in `%s'");
+     }
  
    if (DECL_INTERFACE_KNOWN (decl1))
      {

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]