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]
Other format: [Raw text]

Re: add #define to revert C99 inlining behaviour


On Sun, Nov 05, 2006 at 10:00:38AM -0800, Mark Mitchell wrote:
> It looks to me like we've got a variety of opinions:
> 
> * Steven B. and Joseph think the patch should stay in, but Joseph thinks 
> we should back it out at the end of Stage 1 if we haven't added the 
> attribute Ian proposed, or if GLIBC has yet to be changed to use the 
> attribute.  Joseph's a C maintainer, so I give his opinion a lot of weight.

Attached is a patch that adds the gnu_inline attribute which enables the
old GNU inline semantics rather than the ISO C99 mandated one.
As is the patch requires that either the attribute is not present,
or is present on all the inline decls of the same function (which is
ok for glibc's use I think).

> quite rightly indicates that we need.)  Ian points out that Geoff's 
> original mail says that "only" GLIBC seems to be obviously affected by 
> this change, but since GLIBC is in fact the C library for the GNU 
> system, it's certainly important.

Not just GLIBC headers, but also e.g. alsa-libs, e2fsprogs, elfutils, glib2
or gmp to name a few other projects.

> I'm not sure how we make progress.  I requested the patch be reverted, 
> but it takes two maintainers to start the 48-hour reversion clock, and I 
> never got a second.  Geoff's checked in an #ifdef, but the default is 
> still the new behavior, and as Ian indicates, this isn't how we normally 
> do things.

Furthermore tha #ifdef doesn't cover all the places that were changed,
e.g. diagnose_mismatched_decls would still prohibit redefinition of
extern inline function which GLIBC relies on.

2006-11-06  Jakub Jelinek  <jakub@redhat.com>

	* c-common.c (c_common_attributes): Add gnu_inline attribyte.
	(handle_gnu_inline_attribute): New function.
	* c-decl.c (diagnose_mismatched_decls): Handle gnu_inline attribute.
	(merge_decls, start_decl, start_function): Likewise.
	* doc/extend.texi: Document gnu_inline attribute.

	* gcc.dg/inline-17.c: New test.

--- gcc/c-decl.c.jj	2006-11-06 13:02:32.000000000 +0100
+++ gcc/c-decl.c	2006-11-06 17:06:51.000000000 +0100
@@ -63,7 +63,7 @@ Software Foundation, 51 Franklin Street,
 #include "pointer-set.h"
 
 /* Set this to 1 if you want the standard ISO C99 semantics of 'inline'
-   when you specify -std=c99 or -std=gnuc99, and to 0 if you want
+   when you specify -std=c99 or -std=gnu99, and to 0 if you want
    behaviour compatible with the nonstandard semantics implemented by
    GCC 2.95 through 4.2.  */
 #define WANT_C99_INLINE_SEMANTICS 1
@@ -1339,7 +1339,16 @@ diagnose_mismatched_decls (tree newdecl,
 		 unit.  */
 	      if ((!DECL_EXTERN_INLINE (olddecl)
 		   || DECL_EXTERN_INLINE (newdecl)
-		   || flag_isoc99)
+#if WANT_C99_INLINE_SEMANTICS
+		   || (flag_isoc99
+		       && (!DECL_DECLARED_INLINE_P (olddecl)
+			   || !lookup_attribute ("gnu_inline",
+						 DECL_ATTRIBUTES (olddecl)))
+		       && (!DECL_DECLARED_INLINE_P (newdecl)
+			   || !lookup_attribute ("gnu_inline",
+						 DECL_ATTRIBUTES (newdecl))))
+#endif /* WANT_C99_INLINE_SEMANTICS */
+		  )
 		  && same_translation_unit_p (newdecl, olddecl))
 		{
 		  error ("redefinition of %q+D", newdecl);
@@ -1399,6 +1408,23 @@ diagnose_mismatched_decls (tree newdecl,
 	      warned = true;
 	    }
 	}
+
+      /* Make sure gnu_inline attribute is either not present, or
+	 present on all inline decls.  */
+      if (DECL_DECLARED_INLINE_P (olddecl)
+	  && DECL_DECLARED_INLINE_P (newdecl))
+	{
+	  bool newa = lookup_attribute ("gnu_inline",
+					DECL_ATTRIBUTES (newdecl)) != NULL;
+	  bool olda = lookup_attribute ("gnu_inline",
+					DECL_ATTRIBUTES (olddecl)) != NULL;
+	  if (newa != olda)
+	    {
+	      error ("%<gnu_inline%> attribute present on %q+D",
+		     newa ? newdecl : olddecl);
+	      error ("%Jbut not here", newa ? olddecl : newdecl);
+	    }
+	}
     }
   else if (TREE_CODE (newdecl) == VAR_DECL)
     {
@@ -1531,9 +1557,9 @@ diagnose_mismatched_decls (tree newdecl,
 	 mode and can get it right?
 	 Definitely don't complain if the decls are in different translation
 	 units.
-         C99 permits this, so don't warn in that case.  (The function
-         may not be inlined everywhere in function-at-a-time mode, but
-         we still shouldn't warn.)  */
+	 C99 permits this, so don't warn in that case.  (The function
+	 may not be inlined everywhere in function-at-a-time mode, but
+	 we still shouldn't warn.)  */
       if (DECL_DECLARED_INLINE_P (newdecl) && !DECL_DECLARED_INLINE_P (olddecl)
 	  && same_translation_unit_p (olddecl, newdecl)
 	  && ! flag_isoc99)
@@ -1767,17 +1793,19 @@ merge_decls (tree newdecl, tree olddecl,
     }
 
 #if WANT_C99_INLINE_SEMANTICS
-   /* In c99, 'extern' declaration before (or after) 'inline' means this
-      function is not DECL_EXTERNAL.  */
-   if (TREE_CODE (newdecl) == FUNCTION_DECL
-       && (DECL_DECLARED_INLINE_P (newdecl) 
-	   || DECL_DECLARED_INLINE_P (olddecl))
-       && (!DECL_DECLARED_INLINE_P (newdecl) 
-	   || !DECL_DECLARED_INLINE_P (olddecl)
-	   || !DECL_EXTERNAL (olddecl))
-       && DECL_EXTERNAL (newdecl)
-       && flag_isoc99)
-     DECL_EXTERNAL (newdecl) = 0;
+  /* In c99, 'extern' declaration before (or after) 'inline' means this
+     function is not DECL_EXTERNAL, unless 'gnu_inline' attribute
+     is present.  */
+  if (TREE_CODE (newdecl) == FUNCTION_DECL
+      && flag_isoc99
+      && (DECL_DECLARED_INLINE_P (newdecl)
+	  || DECL_DECLARED_INLINE_P (olddecl))
+      && (!DECL_DECLARED_INLINE_P (newdecl)
+	  || !DECL_DECLARED_INLINE_P (olddecl)
+	  || !DECL_EXTERNAL (olddecl))
+      && DECL_EXTERNAL (newdecl)
+      && !lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (newdecl)))
+    DECL_EXTERNAL (newdecl) = 0;
 #endif /* WANT_C99_INLINE_SEMANTICS */
 
   if (DECL_EXTERNAL (newdecl))
@@ -3292,6 +3320,20 @@ start_decl (struct c_declarator *declara
   /* Set attributes here so if duplicate decl, will have proper attributes.  */
   decl_attributes (&decl, attributes, 0);
 
+#if WANT_C99_INLINE_SEMANTICS
+  /* Handle gnu_inline attribute.  */
+  if (declspecs->inline_p
+      && flag_isoc99
+      && TREE_CODE (decl) == FUNCTION_DECL
+      && lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl)))
+    {
+      if (declspecs->storage_class == csc_auto && current_scope != file_scope)
+	;
+      else if (declspecs->storage_class != csc_static)
+	DECL_EXTERNAL (decl) = !DECL_EXTERNAL (decl);
+    }
+#endif /* WANT_C99_INLINE_SEMANTICS */
+
   if (TREE_CODE (decl) == FUNCTION_DECL
       && targetm.calls.promote_prototypes (TREE_TYPE (decl)))
     {
@@ -6053,6 +6095,18 @@ start_function (struct c_declspecs *decl
     warning (OPT_Wattributes, "inline function %q+D given attribute noinline",
 	     decl1);
 
+#if WANT_C99_INLINE_SEMANTICS
+  /* Handle gnu_inline attribute.  */
+  if (declspecs->inline_p
+      && flag_isoc99
+      && TREE_CODE (decl1) == FUNCTION_DECL
+      && lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl1)))
+    {
+      if (declspecs->storage_class != csc_static)
+	DECL_EXTERNAL (decl1) = !DECL_EXTERNAL (decl1);
+    }
+#endif /* WANT_C99_INLINE_SEMANTICS */
+
   announce_function (decl1);
 
   if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1))))
--- gcc/doc/extend.texi.jj	2006-11-01 10:31:23.000000000 +0100
+++ gcc/doc/extend.texi	2006-11-06 16:08:55.000000000 +0100
@@ -1581,8 +1581,8 @@ attributes are currently defined for fun
 @code{format}, @code{format_arg}, @code{no_instrument_function},
 @code{section}, @code{constructor}, @code{destructor}, @code{used},
 @code{unused}, @code{deprecated}, @code{weak}, @code{malloc},
-@code{alias}, @code{warn_unused_result}, @code{nonnull}
-and @code{externally_visible}.  Several other
+@code{alias}, @code{warn_unused_result}, @code{nonnull},
+@code{gnu_inline} and @code{externally_visible}.  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}).
@@ -1620,6 +1620,11 @@ Generally, functions are not inlined unl
 For functions declared inline, this attribute inlines the function even
 if no optimization level was specified.
 
+@item gnu_inline
+@cindex @code{gnu_inline} function attribute
+This attribute on an inline declaration results in the old GNU C89
+inline behavior even in the ISO C99 mode.
+
 @cindex @code{flatten} function attribute
 @item flatten
 Generally, inlining into a function is limited.  For a function marked with
@@ -3802,7 +3807,8 @@ also direct GCC to try to integrate all 
 into their callers with the option @option{-finline-functions}.
 
 GCC implements three different semantics of declaring a function
-inline.  One is available with @option{-std=gnu89}, another when
+inline.  One is available with @option{-std=gnu89} or when @code{gnu_inline}
+attribute is present on all inline declarations, another when
 @option{-std=c99} or @option{-std=gnu99}, and the third is used when
 compiling C++.
 
--- gcc/c-common.c.jj	2006-11-06 13:02:32.000000000 +0100
+++ gcc/c-common.c	2006-11-06 16:53:41.000000000 +0100
@@ -510,6 +510,8 @@ static tree handle_noreturn_attribute (t
 static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
 static tree handle_always_inline_attribute (tree *, tree, tree, int,
 					    bool *);
+static tree handle_gnu_inline_attribute (tree *, tree, tree, int,
+					 bool *);
 static tree handle_flatten_attribute (tree *, tree, tree, int, bool *);
 static tree handle_used_attribute (tree *, tree, tree, int, bool *);
 static tree handle_unused_attribute (tree *, tree, tree, int, bool *);
@@ -578,6 +580,8 @@ const struct attribute_spec c_common_att
 			      handle_noinline_attribute },
   { "always_inline",          0, 0, true,  false, false,
 			      handle_always_inline_attribute },
+  { "gnu_inline",             0, 0, true,  false, false,
+			      handle_gnu_inline_attribute },
   { "flatten",                0, 0, true,  false, false,
 			      handle_flatten_attribute },
   { "used",                   0, 0, true,  false, false,
@@ -4268,6 +4272,29 @@ handle_always_inline_attribute (tree *no
   return NULL_TREE;
 }
 
+/* Handle a "gnu_inline" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_gnu_inline_attribute (tree *node, tree name,
+			     tree ARG_UNUSED (args),
+			     int ARG_UNUSED (flags),
+			     bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (*node))
+    {
+      /* Do nothing else, just set the attribute.  We'll get at
+	 it later with lookup_attribute.  */
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "flatten" attribute; arguments as in
    struct attribute_spec.handler.  */
 
--- gcc/testsuite/gcc.dg/inline-17.c.jj	2006-11-06 15:07:50.000000000 +0100
+++ gcc/testsuite/gcc.dg/inline-17.c	2006-11-06 15:54:29.000000000 +0100
@@ -0,0 +1,24 @@
+/* Test __attribute__((gnu_inline)).  */
+/* { dg-do compile } */
+/* { dg-options "-std=c99" } */
+/* { dg-final { scan-assembler "func1" } } */
+/* { dg-final { scan-assembler-not "func2" } } */
+/* { dg-final { scan-assembler "func3" } } */
+/* { dg-final { scan-assembler "func4" } } */
+
+#if __STDC_VERSION__ >= 199901L
+# define inline __attribute__((gnu_inline)) inline
+#endif
+
+extern inline int func1 (void) { return 0; }
+inline int func1 (void) { return 1; }
+
+extern int func2 (void);
+extern inline int func2 (void) { return 2; }
+
+inline int func3 (void);
+inline int func3 (void) { return 3; }
+
+extern int func4 (void);
+extern inline int func4 (void) { return 4; }
+int func4 (void) { return 5; }


	Jakub


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