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]

Re: [testcase] Simplified testcases why current gcc trunk cannot compile glibc


On Oct 17, 2001, Alexandre Oliva <aoliva@redhat.com> wrote:

> This is a bit tricky to implement, because DECL_INLINE doesn't imply
> the function was *declared* as inline, and DECL_DECLARED_INLINE_P is
> only available in c-tree.h, so we shouldn't use it in attribs.c, that
> is front end-neutral.

Well, it turned out that this wasn't a problem, since the attribute
only applied to C-like languages anyway.  But it was of no help to
detect the conditions in which you wanted warnings, because the
attribute could be applied to a decl that was not inline itself, but
that would end up being merged with another decl that was, or
vice-versa, and we'd fail to detect and report the inconsistency.

> The latter may give false positives in case we set
> DECL_UNINLINABLE for other reasons

But lookup_attribute() was enough to disambiguate, so I took this
path.  Here's the patch I bootstrapped and tested on
athlon-pc-linux-gnu for the past few hours.  Ok to install?

Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* attribs.c (handle_noinline_attribute): New function.
	(handle_used_attribute): Likewise.
	(c_common_attribute_table): Added noinline and used.
	* doc/extend.texi (Function Attributes): Document them.
	* c-decl.c (duplicate_decls): Propagate DECL_UNINLINABLE.
	Warn when merging inline with attribute noinline.
	(start_decl, start_function): Warn if inline and attribute
	noinline appear in the same declaration.

Index: gcc/cp/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* decl.c (duplicate_decls): Propagate DECL_UNINLINABLE.
	Warn when merging inline with attribute noinline.
	(start_decl, start_function): Warn if inline and attribute
	noinline appear in the same declaration.

Index: gcc/testsuite/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* gcc.dg/attr-noinline.c, gcc.dg/attr-used.c: New tests.

Index: gcc/attribs.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/attribs.c,v
retrieving revision 1.2
diff -u -p -r1.2 attribs.c
--- gcc/attribs.c 2001/10/02 07:12:20 1.2
+++ gcc/attribs.c 2001/10/18 00:21:56
@@ -49,6 +49,10 @@ static tree handle_common_attribute	PARA
 						 bool *));
 static tree handle_noreturn_attribute	PARAMS ((tree *, tree, tree, int,
 						 bool *));
+static tree handle_noinline_attribute	PARAMS ((tree *, tree, tree, int,
+						 bool *));
+static tree handle_used_attribute	PARAMS ((tree *, tree, tree, int,
+						 bool *));
 static tree handle_unused_attribute	PARAMS ((tree *, tree, tree, int,
 						 bool *));
 static tree handle_const_attribute	PARAMS ((tree *, tree, tree, int,
@@ -100,6 +104,10 @@ static const struct attribute_spec c_com
 			      handle_noreturn_attribute },
   { "volatile",               0, 0, true,  false, false,
 			      handle_noreturn_attribute },
+  { "noinline",               0, 0, true,  false, false,
+			      handle_noinline_attribute },
+  { "used",                   0, 0, true,  false, false,
+			      handle_used_attribute },
   { "unused",                 0, 0, false, false, false,
 			      handle_unused_attribute },
   /* The same comments as for noreturn attributes apply to const ones.  */
@@ -500,6 +508,51 @@ handle_noreturn_attribute (node, name, a
       = build_pointer_type
 	(build_type_variant (TREE_TYPE (type),
 			     TREE_READONLY (TREE_TYPE (type)), 1));
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "noinline" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_noinline_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    DECL_UNINLINABLE (*node) = 1;
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "used" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_used_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (*node))
+      = TREE_USED (*node) = 1;
   else
     {
       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
Index: gcc/c-decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-decl.c,v
retrieving revision 1.254
diff -u -p -r1.254 c-decl.c
--- gcc/c-decl.c 2001/10/11 03:15:18 1.254
+++ gcc/c-decl.c 2001/10/18 00:21:57
@@ -1405,9 +1405,44 @@ duplicate_decls (newdecl, olddecl, diffe
   int errmsg = 0;
 
   if (DECL_P (olddecl))
-    DECL_ATTRIBUTES (newdecl)
-      = (*targetm.merge_decl_attributes) (olddecl, newdecl);
+    {
+      if (TREE_CODE (newdecl) == FUNCTION_DECL
+	  && TREE_CODE (olddecl) == FUNCTION_DECL
+	  && (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl)))
+	{
+	  if (DECL_DECLARED_INLINE_P (newdecl)
+	      && DECL_UNINLINABLE (newdecl)
+	      && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
+	    /* Already warned elsewhere.  */;
+	  else if (DECL_DECLARED_INLINE_P (olddecl)
+		   && DECL_UNINLINABLE (olddecl)
+		   && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
+	    /* Already warned.  */;
+	  else if (DECL_DECLARED_INLINE_P (newdecl)
+		   && ! DECL_DECLARED_INLINE_P (olddecl)
+		   && DECL_UNINLINABLE (olddecl)
+		   && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
+	    {
+	      warning_with_decl (newdecl,
+				 "function `%s' redeclared as inline");
+	      warning_with_decl (olddecl,
+				 "previous declaration of function `%s' with attribute noinline");
+	    }
+	  else if (DECL_DECLARED_INLINE_P (olddecl)
+		   && DECL_UNINLINABLE (newdecl)
+		   && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
+	    {
+	      warning_with_decl (newdecl,
+				 "function `%s' redeclared with attribute noinline");
+	      warning_with_decl (olddecl,
+				 "previous declaration of function `%s' was inline");
+	    }
+	}
 
+      DECL_ATTRIBUTES (newdecl)
+	= (*targetm.merge_decl_attributes) (olddecl, newdecl);
+    }
+
   if (TREE_CODE (newtype) == ERROR_MARK
       || TREE_CODE (oldtype) == ERROR_MARK)
     types_match = 0;
@@ -1983,6 +2018,9 @@ duplicate_decls (newdecl, olddecl, diffe
 	    DECL_DECLARED_INLINE_P (olddecl) = 1;
 
 	  DECL_DECLARED_INLINE_P (newdecl) = DECL_DECLARED_INLINE_P (olddecl);
+
+	  DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl)
+	    = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl));
 	}
 
       if (DECL_BUILT_IN (olddecl))
@@ -3483,6 +3521,13 @@ start_decl (declarator, declspecs, initi
   /* Set attributes here so if duplicate decl, will have proper attributes.  */
   decl_attributes (&decl, attributes, 0);
 
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && DECL_DECLARED_INLINE_P (decl)
+      && DECL_UNINLINABLE (decl)
+      && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl)))
+    warning_with_decl (decl,
+		       "inline function `%s' given attribute noinline");
+
   /* Add this decl to the current binding level.
      TEM may equal DECL or it may be a previous decl of the same name.  */
   tem = pushdecl (decl);
@@ -6021,6 +6066,12 @@ start_function (declspecs, declarator, a
     }
 
   decl_attributes (&decl1, attributes, 0);
+
+  if (DECL_DECLARED_INLINE_P (decl1)
+      && DECL_UNINLINABLE (decl1)
+      && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl1)))
+    warning_with_decl (decl1,
+		       "inline function `%s' given attribute noinline");
 
   announce_function (decl1);
 
Index: gcc/cp/decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.820
diff -u -p -r1.820 decl.c
--- gcc/cp/decl.c 2001/10/16 13:01:44 1.820
+++ gcc/cp/decl.c 2001/10/18 00:21:58
@@ -3093,6 +3093,39 @@ duplicate_decls (newdecl, olddecl)
       || TREE_TYPE (olddecl) == error_mark_node)
     types_match = 1;
 
+  if (DECL_P (olddecl)
+      && TREE_CODE (newdecl) == FUNCTION_DECL
+      && TREE_CODE (olddecl) == FUNCTION_DECL
+      && (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl)))
+    {
+      if (DECL_DECLARED_INLINE_P (newdecl)
+	  && DECL_UNINLINABLE (newdecl)
+	  && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
+	/* Already warned elsewhere.  */;
+      else if (DECL_DECLARED_INLINE_P (olddecl)
+	       && DECL_UNINLINABLE (olddecl)
+	       && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
+	/* Already warned.  */;
+      else if (DECL_DECLARED_INLINE_P (newdecl)
+	       && DECL_UNINLINABLE (olddecl)
+	       && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
+	{
+	  warning_with_decl (newdecl,
+			     "function `%s' redeclared as inline");
+	  warning_with_decl (olddecl,
+			     "previous declaration of function `%s' with attribute noinline");
+	}
+      else if (DECL_DECLARED_INLINE_P (olddecl)
+	       && DECL_UNINLINABLE (newdecl)
+	       && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
+	{
+	  warning_with_decl (newdecl,
+			     "function `%s' redeclared with attribute noinline");
+	  warning_with_decl (olddecl,
+			     "previous declaration of function `%s' was inline");
+	}
+    }
+
   /* Check for redeclaration and other discrepancies. */
   if (TREE_CODE (olddecl) == FUNCTION_DECL
       && DECL_ARTIFICIAL (olddecl))
@@ -3640,6 +3673,9 @@ duplicate_decls (newdecl, olddecl)
 	DECL_INLINE (olddecl) = 1;
       DECL_INLINE (newdecl) = DECL_INLINE (olddecl);
 
+      DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl)
+	= (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl));
+
       /* Preserve abstractness on cloned [cd]tors.  */
       DECL_ABSTRACT (newdecl) = DECL_ABSTRACT (olddecl);
 
@@ -7132,6 +7168,13 @@ start_decl (declarator, declspecs, initi
   /* Set attributes here so if duplicate decl, will have proper attributes.  */
   cplus_decl_attributes (&decl, attributes, 0);
 
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && DECL_DECLARED_INLINE_P (decl)
+      && DECL_UNINLINABLE (decl)
+      && lookup_attribute ("noinline", DECL_ATTRIBUTES (decl)))
+    warning_with_decl (decl,
+		       "inline function `%s' given attribute noinline");
+
   if (context && COMPLETE_TYPE_P (complete_type (context)))
     {
       push_nested_class (context, 2);
@@ -13327,6 +13370,11 @@ start_function (declspecs, declarator, a
 	    }
 	}
     }
+
+  if (DECL_DECLARED_INLINE_P (decl1)
+      && lookup_attribute ("noinline", attrs))
+    warning_with_decl (decl1,
+		       "inline function `%s' given attribute noinline");
 
   if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl1))
     /* This is a constructor, we must ensure that any default args
Index: gcc/doc/extend.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/doc/extend.texi,v
retrieving revision 1.31
diff -u -p -r1.31 extend.texi
--- gcc/doc/extend.texi 2001/10/11 07:07:30 1.31
+++ gcc/doc/extend.texi 2001/10/18 00:21:59
@@ -1925,13 +1925,14 @@ carefully.
 
 The keyword @code{__attribute__} allows you to specify special
 attributes when making a declaration.  This keyword is followed by an
-attribute specification inside double parentheses.  Fourteen attributes,
-@code{noreturn}, @code{pure}, @code{const}, @code{format},
-@code{format_arg}, @code{no_instrument_function}, @code{section},
-@code{constructor}, @code{destructor}, @code{unused}, @code{weak},
-@code{malloc}, @code{alias} and @code{no_check_memory_usage} are
-currently defined for functions.  Several other attributes are defined
-for functions on particular target systems.  Other attributes, including
+attribute specification inside double parentheses.  The following
+attributs are currently defined for functions on all targets:
+@code{noreturn}, @code{noinline}, @code{pure}, @code{const},
+@code{format}, @code{format_arg}, @code{no_instrument_function},
+@code{section}, @code{constructor}, @code{destructor}, @code{used},
+@code{unused}, @code{weak}, @code{malloc}, @code{alias} and
+@code{no_check_memory_usage}.  Several other attributes are defined for
+functions on particular target systems.  Other attributes, including
 @code{section} are supported for variables declarations (@pxref{Variable
 Attributes}) and for types (@pxref{Type Attributes}).
 
@@ -1987,6 +1988,11 @@ typedef void voidfn ();
 volatile voidfn fatal;
 @end smallexample
 
+@cindex @code{noinline} function attribute
+@item noinline
+This function attribute prevents a function from being considered for
+inlining.
+
 @cindex @code{pure} function attribute
 @item pure
 Many functions have no effects except the return value and their
@@ -2174,12 +2180,20 @@ the program.
 
 These attributes are not currently implemented for Objective-C@.
 
+@cindex @code{unused} attribute.
 @item unused
 This attribute, attached to a function, means that the function is meant
 to be possibly unused.  GCC will not produce a warning for this
 function.  GNU C++ does not currently support this attribute as
 definitions without parameters are valid in C++.
 
+@cindex @code{used} attribute.
+@item used
+This attribute, attached to a function, means that code must be emitted
+for the function even if it appears that the function is not referenced.
+This is useful, for example, when the function is referenced only in
+inline assembly.
+
 @item weak
 @cindex @code{weak} attribute
 The @code{weak} attribute causes the declaration to be emitted as a weak
Index: gcc/testsuite/gcc.dg/attr-noinline.c
===================================================================
RCS file: attr-noinline.c
diff -N attr-noinline.c
--- /dev/null	Tue May  5 13:32:27 1998
+++ gcc/testsuite/gcc.dg/attr-noinline.c Wed Oct 17 17:21:59 2001
@@ -0,0 +1,66 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -finline-functions" } */
+
+static inline void __attribute__((__noinline__)) function_definition(void) {} /* { dg-warning "inline function \[^\n\]* given attribute noinline" "" } */
+
+static inline void __attribute__((__noinline__)) function_declaration_both_before(void); /* { dg-warning "inline function \[^\n\]* given attribute noinline" "" } */
+
+static void function_declaration_both_before(void) {}
+
+static void function_declaration_both_after(void);
+
+static inline void __attribute__((__noinline__)) function_declaration_both_after(void); /* { dg-warning "(inline function \[^\n\]* given attribute noinline|declared inline after its definition)" "" } */
+
+static void function_declaration_both_after(void) {}
+
+static void function_declaration_noinline_before(void) __attribute__((__noinline__)); /* { dg-warning "previous declaration \[^\n\]* with attribute noinline" "" } */
+
+static inline void function_declaration_noinline_before(void) {} /* { dg-warning "function \[^\n\]* redeclared as inline" "" } */
+
+static inline void function_declaration_noinline_after(void) {} /* { dg-warning "previous declaration \[^\n\]* was inline" "" } */
+
+static void function_declaration_noinline_after(void) __attribute__((__noinline__)); /* { dg-warning "function \[^\n\]* redeclared with attribute noinline" "" } */
+
+static inline void function_declaration_inline_before(void); /* { dg-warning "previous declaration \[^\n\]* was inline" "" } */
+
+static void __attribute__((__noinline__)) function_declaration_inline_before(void) {} /* { dg-warning "function \[^\n\]* redeclared with attribute noinline" "" } */
+
+static inline void function_declaration_inline_noinline_before(void); /* { dg-warning "previous declaration \[^\n\]* was inline" "" } */
+
+static void function_declaration_inline_noinline_before(void) __attribute__((__noinline__)); /* { dg-warning "function \[^\n\]* redeclared with attribute noinline" "" } */
+
+static void function_declaration_inline_noinline_before(void) {}
+
+static inline void function_declaration_inline_noinline_after(void);
+
+static void function_declaration_inline_noinline_after(void) {} /* { dg-warning "previous declaration \[^\n\]* was inline" "" } */
+
+static void function_declaration_inline_noinline_after(void) __attribute__((__noinline__)); /* { dg-warning "function \[^\n\]* redeclared with attribute noinline" "" } */
+
+static void function_declaration_noinline_inline_before(void) __attribute__((__noinline__)); /* { dg-warning "previous declaration\[^\n\]* with attribute noinline" "" } */
+
+static inline void function_declaration_noinline_inline_before(void); /* { dg-warning "function \[^\n\]* redeclared as inline" "" } */
+
+static void function_declaration_noinline_inline_before(void) {}
+
+int f () {
+  function_definition ();
+  function_declaration_both_before ();
+  function_declaration_both_after ();
+  function_declaration_noinline_before ();
+  function_declaration_noinline_after ();
+  function_declaration_inline_before ();
+  function_declaration_inline_noinline_before ();
+  function_declaration_inline_noinline_after ();
+  function_declaration_noinline_inline_before ();
+}
+
+/* { dg-final { scan-assembler "function_definition" } } */
+/* { dg-final { scan-assembler "function_declaration_both_before" } } */
+/* { dg-final { scan-assembler "function_declaration_both_after" } } */
+/* { dg-final { scan-assembler "function_declaration_noinline_before" } } */
+/* { dg-final { scan-assembler "function_declaration_noinline_after" } } */
+/* { dg-final { scan-assembler "function_declaration_inline_before" } } */
+/* { dg-final { scan-assembler "function_declaration_inline_noinline_before" } } */
+/* { dg-final { scan-assembler "function_declaration_inline_noinline_after" } } */
+/* { dg-final { scan-assembler "function_declaration_noinline_inline_before" } } */
Index: gcc/testsuite/gcc.dg/attr-used.c
===================================================================
RCS file: attr-used.c
diff -N attr-used.c
--- /dev/null	Tue May  5 13:32:27 1998
+++ gcc/testsuite/gcc.dg/attr-used.c Wed Oct 17 17:21:59 2001
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+
+static void function_declaration_before(void) __attribute__((__used__));
+
+static void function_declaration_before(void) {}
+
+static void function_declaration_after(void) {}
+
+static void function_declaration_after(void) __attribute__((__used__));
+
+/* { dg-final { scan-assembler "function_declaration_before" } } */
+/* { dg-final { scan-assembler "function_declaration_after" } } */

-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                  aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist    *Please* write to mailing lists, not to me

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