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]

PATCH RFA: Patch for extern inline in mainline


I'm proposing this patch to fix the extern inline situation in
mainline.  This patch does the following:

* Adds an option -fgnu89-extern-inline which may be used in gnu99 or
  c99 mode to request the old GNU behaviour for inline functions.

* Defines either __GNUC_GNU_EXTERN_INLINE or __GNUC_STDC_EXTERN_INLINE
  to indicate which definition of "extern inline" is in effect.

* Documents all of this.

I believe this follows the plans discussed previously.  If this patch
is approved, I plan to backport the appropriate parts to the 4.2 and
4.1 branches, as discussed.

I'm currently bootstrapping and testing this on i686-pc-linux-gnu.
I'm confident this will pass.  I'm sending the patch out early in case
people would prefer a different approach.

Ian


gcc/ChangeLog:
2007-02-28  Ian Lance Taylor  <iant@google.com>

	* c.opt (fgnu89-extern-inline): New option.
	* c-opts.c (c_common_post_options): Set default value for
	flag_gnu89_extern_inline.
	* c-decl.c (WANT_C99_INLINE_SEMANTICS): Remove.
	(grokdeclarator): If flag_gnu89_extern_inline is set, add the
	gnu_inline attribute to every non-static inline function.
	* c-cppbuiltin.c (c_cpp_builtins): Define either
	__GNUC_GNU_EXTERN_INLINE__ or __GNUC_STDC_EXTERN_INLINE__.
	* doc/invoke.texi (Option Summary): Mention
	-fgnu89-extern-inline.
	(C Dialect Options): Document -fgnu89-extern-inline.
	* doc/extend.texi (Function Attributes): Explain what the
	gnu_inline attribute does.
	* doc/cpp.texi (Common Predefined Macros): Document
	__GNUC_GNU_EXTERN_INLINE__ and __GNUC_STDC_EXTERN_INLINE__.

gcc/testsuite/ChangeLog:
2007-02-28  Ian Lance Taylor  <iant@google.com>

	* gcc.dg/inline-18.c: New test.
	* gcc.dg/inline-19.c: New test.
	* gcc.dg/inline-20.c: New test.
	* gcc.dg/inline-21.c: New test.


Index: gcc/doc/cpp.texi
===================================================================
--- gcc/doc/cpp.texi	(revision 122421)
+++ gcc/doc/cpp.texi	(working copy)
@@ -2014,6 +2014,25 @@ functions.  You should not use these mac
 sure that programs will execute with the same effect whether or not they
 are defined.  If they are defined, their value is 1.
 
+@item __GNUC_GNU_EXTERN_INLINE__
+GCC defines this macro if functions declared @code{extern inline} will
+be handled in GCC's traditional gnu89 mode.  In this mode an
+@code{extern inline} function will never be compiled as a standalone
+function.
+
+@item __GNUC_STDC_EXTERN_INLINE__
+GCC defines this macro if functions declared @code{extern inline} will
+be handled according to the ISO C99 standard.  In this mode an
+@code{extern inline} function will always be compiled as a standalone
+externally visible function.
+
+If this macro is defined, GCC supports the @code{gnu_inline} function
+attribute as a way to get the gnu89 behaviour.  Support for this and
+@code{__GNUC_GNU_EXTERN_INLINE__} was added in GCC 4.1.3.  If neither
+macro is defined, an older version of GCC is being used: @code{extern
+inline} functions will be compiled in gnu89 mode, and the
+@code{gnu_inline} function attribute will not be recognized.
+
 @item __CHAR_UNSIGNED__
 GCC defines this macro if and only if the data type @code{char} is
 unsigned on the target machine.  It exists to cause the standard header
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 122421)
+++ gcc/doc/extend.texi	(working copy)
@@ -1618,8 +1618,28 @@ 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.
+This definition of the function is used only for inlining.  In no case
+is the function compiled as a standalone function, not even if you
+refer to its address explicitly.  Such an address becomes an external
+reference, as if you had only declared the function, and had not
+defined it.  This has almost the effect of a macro.  The way to use
+this is to put a function definition in a header file with this
+attribute, and put another copy of the function, without the
+attribute, in a library file.  The definition in the header file will
+cause most calls to the function to be inlined.  If any uses of the
+function remain, they will refer to the single copy in the library.
+Note that the two definitions of the functions need not be precisely
+the same, although if they do not have the same effect your program
+may behave oddly.
+
+This is how GCC traditionally handled functions declared @code{extern
+inline}.  Since ISO C99 specifies a different semantics for
+@code{extern inline}, this function attribute is provided as a
+transition measure and as a useful feature in its own right.  This
+attribute is available in GCC 4.1.3 and later.  It is available if
+either of the preprocessor macros @code{__GNUC_GNU_EXTERN_INLINE__} or
+@code{__GNUC_STDC_EXTERN_INLINE__} are defined.  @xref{Inline,,An
+Inline Function is As Fast As a Macro}.
 
 @cindex @code{flatten} function attribute
 @item flatten
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 122421)
+++ gcc/doc/invoke.texi	(working copy)
@@ -166,7 +166,8 @@ in the following sections.
 
 @item C Language Options
 @xref{C Dialect Options,,Options Controlling C Dialect}.
-@gccoptlist{-ansi  -std=@var{standard}  -aux-info @var{filename} @gol
+@gccoptlist{-ansi  -std=@var{standard}  -fgnu89-extern-inline @gol
+-aux-info @var{filename} @gol
 -fno-asm  -fno-builtin  -fno-builtin-@var{function} @gol
 -fhosted  -ffreestanding -fopenmp -fms-extensions @gol
 -trigraphs  -no-integrated-cpp  -traditional  -traditional-cpp @gol
@@ -1351,6 +1352,28 @@ the @code{inline} keyword in ISO C99) ar
 @xref{Standards,,Language Standards Supported by GCC}, for details of
 these standard versions.
 
+@item -fgnu89-extern-inline
+@opindex gnu89-extern-inline
+The option @option{-fgnu89-extern-inline} tells GCC to use the
+traditional GNU semantics for @code{extern inline} when in C99 mode.
+@xref{Inline,,An Inline Function is As Fast As a Macro}.  This option
+is accepted and ignored by GCC versions 4.1.3 up to but not including
+4.3.  In GCC versions 4.3 and later it changes the behavior of GCC in
+C99 mode.  Using this option is equivalent to adding the
+@code{gnu_inline} function attribute to all inline functions
+(@pxref{Function Attributes}).
+
+The option @option{-fno-gnu89-extern-inline} explicitly tells GCC to
+use the C99 semantics for @code{extern inline} when in C99 or GNU99
+mode (i.e., it specifies the default behavior).  This option was first
+supported in GCC 4.3.  This option is not supported in C89 or GNU89
+mode.
+
+The preprocesor macros @code{__GNUC_GNU_EXTERN_INLINE__} and
+@code{__GNUC_STDC_EXTERN_INLINE__} may be used to check which
+semantics are in effect for @code{extern inline}.  @xref{Common
+Predefined Macros,,,cpp.info,The C Preprocessor}.
+
 @item -aux-info @var{filename}
 @opindex aux-info
 Output to the given filename prototyped declarations for all functions
Index: gcc/c-cppbuiltin.c
===================================================================
--- gcc/c-cppbuiltin.c	(revision 122421)
+++ gcc/c-cppbuiltin.c	(working copy)
@@ -495,6 +495,11 @@ c_cpp_builtins (cpp_reader *pfile)
   /* Misc.  */
   builtin_define_with_value ("__VERSION__", version_string, 1);
 
+  if (!flag_isoc99 || flag_gnu89_extern_inline)
+    cpp_define (pfile, "__GNUC_GNU_EXTERN_INLINE__");
+  else
+    cpp_define (pfile, "__GNUC_STDC_EXTERN_INLINE__");
+
   /* Definitions for LP64 model.  */
   if (TYPE_PRECISION (long_integer_type_node) == 64
       && POINTER_SIZE == 64
Index: gcc/testsuite/gcc.dg/inline-19.c
===================================================================
--- gcc/testsuite/gcc.dg/inline-19.c	(revision 0)
+++ gcc/testsuite/gcc.dg/inline-19.c	(revision 0)
@@ -0,0 +1,28 @@
+/* Test -fgnu89-extern-inline.  */
+/* { dg-do compile } */
+/* { dg-options "-fgnu89-extern-inline" } */
+/* { dg-final { scan-assembler "func1" } } */
+/* { dg-final { scan-assembler-not "func2" } } */
+/* { dg-final { scan-assembler "func3" } } */
+/* { dg-final { scan-assembler "func4" } } */
+
+#ifndef __GNUC_GNU_EXTERN_INLINE__
+#error __GNUC_GNU_EXTERN_INLINE__ is not defined
+#endif
+
+#ifdef __GNUC_STDC_EXTERN_INLINE__
+#error __GNUC_STDC_EXTERN_INLINE__ is defined
+#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; }
Index: gcc/testsuite/gcc.dg/inline-21.c
===================================================================
--- gcc/testsuite/gcc.dg/inline-21.c	(revision 0)
+++ gcc/testsuite/gcc.dg/inline-21.c	(revision 0)
@@ -0,0 +1,4 @@
+/* Test -fno-gnu89-extern-inline.  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89 -fno-gnu89-extern-inline" } */
+/* { dg-error "only supported in GNU99 or C99 mode" "" { target *-*-* } 0 } */
Index: gcc/testsuite/gcc.dg/inline-18.c
===================================================================
--- gcc/testsuite/gcc.dg/inline-18.c	(revision 0)
+++ gcc/testsuite/gcc.dg/inline-18.c	(revision 0)
@@ -0,0 +1,28 @@
+/* Test -fgnu89-extern-inline.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c99 -fgnu89-extern-inline" } */
+/* { dg-final { scan-assembler "func1" } } */
+/* { dg-final { scan-assembler-not "func2" } } */
+/* { dg-final { scan-assembler "func3" } } */
+/* { dg-final { scan-assembler "func4" } } */
+
+#ifndef __GNUC_GNU_EXTERN_INLINE__
+#error __GNUC_GNU_EXTERN_INLINE__ is not defined
+#endif
+
+#ifdef __GNUC_STDC_EXTERN_INLINE__
+#error __GNUC_STDC_EXTERN_INLINE__ is defined
+#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; }
Index: gcc/testsuite/gcc.dg/inline-20.c
===================================================================
--- gcc/testsuite/gcc.dg/inline-20.c	(revision 0)
+++ gcc/testsuite/gcc.dg/inline-20.c	(revision 0)
@@ -0,0 +1,64 @@
+/* Test -fno-gnu89-extern-inline.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c99 -fno-gnu89-extern-inline" } */
+/* { dg-final { scan-assembler-not "dontgenerate" } } */
+/* { dg-final { scan-assembler "func1" } } */
+/* { dg-final { scan-assembler "func2" } } */
+/* { dg-final { scan-assembler "func3" } } */
+/* { dg-final { scan-assembler "func4" } } */
+/* { dg-final { scan-assembler "func5" } } */
+/* { dg-final { scan-assembler "func6" } } */
+/* { dg-final { scan-assembler "func7" } } */
+/* { dg-final { scan-assembler "func8" } } */
+/* { dg-final { scan-assembler "func9" } } */
+
+#ifdef __GNUC_GNU_EXTERN_INLINE__
+#error __GNUC_GNU_EXTERN_INLINE__ is defined
+#endif
+
+#ifndef __GNUC_STDC_EXTERN_INLINE__
+#error __GNUC_STDC_EXTERN_INLINE__ is not defined
+#endif
+
+inline int dontgenerate1 (void)
+{
+  return 1;
+}
+
+inline int dontgenerate2 (void);
+inline int dontgenerate2 (void)
+{
+  return 2;
+}
+
+inline int dontgenerate3 (void)
+{
+  return 3;
+}
+inline int dontgenerate3 (void);
+
+extern inline int func1 (void) { return 1; }
+
+extern inline int func2 (void);
+inline int func2 (void) { return 2; }
+
+inline int func3 (void) { return 3; }
+extern inline int func3 (void);
+
+inline int func4 (void);
+extern inline int func4 (void) { return 4; }
+
+extern inline int func5 (void) { return 5; }
+inline int func5 (void);
+
+extern int func6 (void);
+inline int func6 (void) { return 6; }
+
+inline int func7 (void) { return 7; }
+extern int func7 (void);
+
+inline int func8 (void);
+extern int func8 (void) { return 8; }
+
+extern int func9 (void) { return 9; }
+inline int func9 (void);
Index: gcc/c-decl.c
===================================================================
--- gcc/c-decl.c	(revision 122421)
+++ gcc/c-decl.c	(working copy)
@@ -62,12 +62,6 @@ Software Foundation, 51 Franklin Street,
 #include "langhooks-def.h"
 #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=gnu99, and to 0 if you want
-   behavior compatible with the nonstandard semantics implemented by
-   GCC 2.95 through 4.2.  */
-#define WANT_C99_INLINE_SEMANTICS 1
-
 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
 enum decl_context
 { NORMAL,			/* Ordinary declaration */
@@ -1330,7 +1324,6 @@ diagnose_mismatched_decls (tree newdecl,
 		 unit.  */
 	      if ((!DECL_EXTERN_INLINE (olddecl)
 		   || DECL_EXTERN_INLINE (newdecl)
-#if WANT_C99_INLINE_SEMANTICS
 		   || (flag_isoc99
 		       && (!DECL_DECLARED_INLINE_P (olddecl)
 			   || !lookup_attribute ("gnu_inline",
@@ -1338,7 +1331,6 @@ diagnose_mismatched_decls (tree newdecl,
 		       && (!DECL_DECLARED_INLINE_P (newdecl)
 			   || !lookup_attribute ("gnu_inline",
 						 DECL_ATTRIBUTES (newdecl))))
-#endif /* WANT_C99_INLINE_SEMANTICS */
 		  )
 		  && same_translation_unit_p (newdecl, olddecl))
 		{
@@ -1783,7 +1775,6 @@ 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, unless 'gnu_inline' attribute
      is present.  */
@@ -1797,7 +1788,6 @@ merge_decls (tree newdecl, tree olddecl,
       && DECL_EXTERNAL (newdecl)
       && !lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (newdecl)))
     DECL_EXTERNAL (newdecl) = 0;
-#endif /* WANT_C99_INLINE_SEMANTICS */
 
   if (DECL_EXTERNAL (newdecl))
     {
@@ -3309,7 +3299,6 @@ 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
@@ -3321,7 +3310,6 @@ start_decl (struct c_declarator *declara
       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)))
@@ -4819,11 +4807,7 @@ grokdeclarator (const struct c_declarato
 	   in this file, C99 6.7.4p6.  In GNU C89, a function declared
 	   'extern inline' is an external reference.  */
 	else if (declspecs->inline_p && storage_class != csc_static)
-#if WANT_C99_INLINE_SEMANTICS
 	  DECL_EXTERNAL (decl) = (storage_class == csc_extern) == !flag_isoc99;
-#else
-	  DECL_EXTERNAL (decl) = (storage_class == csc_extern);
-#endif
 	else
 	  DECL_EXTERNAL (decl) = !initialized;
 
@@ -4966,6 +4950,19 @@ grokdeclarator (const struct c_declarato
 
     decl_attributes (&decl, returned_attrs, 0);
 
+    /* In C99/GNU99 mode, if -fgnu89-extern-inline, add a gnu_inline
+       attribute to every non-static inline function.  */
+    if (TREE_CODE (decl) == FUNCTION_DECL
+	&& DECL_DECLARED_INLINE_P (decl)
+	&& storage_class != csc_static
+	&& (storage_class != csc_auto || current_scope == file_scope)
+	&& flag_isoc99
+	&& flag_gnu89_extern_inline
+	&& !lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl)))
+      DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("gnu_inline"),
+					  NULL_TREE,
+					  DECL_ATTRIBUTES (decl));
+
     return decl;
   }
 }
@@ -6085,7 +6082,6 @@ 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
@@ -6095,7 +6091,6 @@ start_function (struct c_declspecs *decl
       if (declspecs->storage_class != csc_static)
 	DECL_EXTERNAL (decl1) = !DECL_EXTERNAL (decl1);
     }
-#endif /* WANT_C99_INLINE_SEMANTICS */
 
   announce_function (decl1);
 
Index: gcc/c.opt
===================================================================
--- gcc/c.opt	(revision 122421)
+++ gcc/c.opt	(working copy)
@@ -554,6 +554,10 @@ fgnu-runtime
 ObjC ObjC++
 Generate code for GNU runtime environment
 
+fgnu89-extern-inline
+C Var(flag_gnu89_extern_inline) Init(-1)
+Use traditional GNU semantics for \"extern inline\"
+
 fguiding-decls
 C++ ObjC++
 
Index: gcc/c-opts.c
===================================================================
--- gcc/c-opts.c	(revision 122421)
+++ gcc/c-opts.c	(working copy)
@@ -1023,6 +1023,14 @@ c_common_post_options (const char **pfil
   if (flag_inline_functions)
     flag_inline_trees = 2;
 
+  /* By default we use C99 extern inline semantics in GNU99 or C99
+     mode.  C99 extern inline semantics are not supported in GNU89 or
+     C89 mode.  */
+  if (flag_gnu89_extern_inline == -1)
+    flag_gnu89_extern_inline = !flag_isoc99;
+  else if (!flag_gnu89_extern_inline && !flag_isoc99)
+    error ("-fno-gnu89-extern-inline is only supported in GNU99 or C99 mode");
+
   /* If we are given more than one input file, we must use
      unit-at-a-time mode.  */
   if (num_in_fnames > 1)

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