c-common.c (c_common_attributes): Add gnu_inline attribyte.
authorJakub Jelinek <jakub@redhat.com>
Tue, 7 Nov 2006 23:01:23 +0000 (00:01 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 7 Nov 2006 23:01:23 +0000 (00:01 +0100)
* 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.

From-SVN: r118567

gcc/ChangeLog
gcc/c-common.c
gcc/c-decl.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/inline-17.c [new file with mode: 0644]

index 1d01bd5c484afa40ca0dc7c7a2a0e4dd8e066248..38eed0db8bdf9deb970bb1251515cdded17e6bfc 100644 (file)
@@ -1,3 +1,11 @@
+2006-11-07  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.
+
 2006-11-07  Steve Ellcey  <sje@cup.hp.com>
 
        PR other/25028
 2006-11-07  Steve Ellcey  <sje@cup.hp.com>
 
        PR other/25028
index 47cda1b6413efcb3714c4d6fb309f8babb3c5e2a..0603da65bc1ba6b082201fade3dd754599b9019b 100644 (file)
@@ -510,6 +510,8 @@ static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
 static tree handle_always_inline_attribute (tree *, tree, tree, int,
                                            bool *);
 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 *);
 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_attribute_table[] =
                              handle_noinline_attribute },
   { "always_inline",          0, 0, true,  false, false,
                              handle_always_inline_attribute },
                              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,
   { "flatten",                0, 0, true,  false, false,
                              handle_flatten_attribute },
   { "used",                   0, 0, true,  false, false,
@@ -4268,6 +4272,29 @@ handle_always_inline_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
   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.  */
 
 /* Handle a "flatten" attribute; arguments as in
    struct attribute_spec.handler.  */
 
index a49b88b199b48970baf91ade7494d4d62a38f281..80f1a1a621f61da66373951f5b797b73d2b5b022 100644 (file)
@@ -63,7 +63,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "pointer-set.h"
 
 /* Set this to 1 if you want the standard ISO C99 semantics of 'inline'
 #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
    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, tree olddecl,
                 unit.  */
              if ((!DECL_EXTERN_INLINE (olddecl)
                   || DECL_EXTERN_INLINE (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);
                  && same_translation_unit_p (newdecl, olddecl))
                {
                  error ("redefinition of %q+D", newdecl);
@@ -1399,6 +1408,23 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
              warned = true;
            }
        }
              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)
     {
     }
   else if (TREE_CODE (newdecl) == VAR_DECL)
     {
@@ -1531,9 +1557,9 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
         mode and can get it right?
         Definitely don't complain if the decls are in different translation
         units.
         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)
       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, tree newtype, tree oldtype)
     }
 
 #if WANT_C99_INLINE_SEMANTICS
     }
 
 #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))
 #endif /* WANT_C99_INLINE_SEMANTICS */
 
   if (DECL_EXTERNAL (newdecl))
@@ -3292,6 +3320,20 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
   /* Set attributes here so if duplicate decl, will have proper attributes.  */
   decl_attributes (&decl, attributes, 0);
 
   /* 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)))
     {
   if (TREE_CODE (decl) == FUNCTION_DECL
       && targetm.calls.promote_prototypes (TREE_TYPE (decl)))
     {
@@ -6053,6 +6095,18 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
     warning (OPT_Wattributes, "inline function %q+D given attribute noinline",
             decl1);
 
     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))))
   announce_function (decl1);
 
   if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1))))
index 9ec4460bb6ac5cdc2568b0d9c6ef484575df9590..1579b94a9708518b239cb92043d547e3b47eda58 100644 (file)
@@ -1581,8 +1581,8 @@ attributes are currently defined for functions on all targets:
 @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{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}).
 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 unless optimization is specified.
 For functions declared inline, this attribute inlines the function even
 if no optimization level was specified.
 
 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
 @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 ``simple enough'' functions
 into their callers with the option @option{-finline-functions}.
 
 GCC implements three different semantics of declaring a function
 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++.
 
 @option{-std=c99} or @option{-std=gnu99}, and the third is used when
 compiling C++.
 
index 22e43d0f23ace6436211c9f733f07f381f7e319c..29dfb3f80c3729e271c20f1084430685a3086139 100644 (file)
@@ -1,3 +1,7 @@
+2006-11-07  Jakub Jelinek  <jakub@redhat.com>
+
+       * gcc.dg/inline-17.c: New test.
+
 2006-11-07  Steve Ellcey  <sje@cup.hp.com>
 
        PR other/25028
 2006-11-07  Steve Ellcey  <sje@cup.hp.com>
 
        PR other/25028
diff --git a/gcc/testsuite/gcc.dg/inline-17.c b/gcc/testsuite/gcc.dg/inline-17.c
new file mode 100644 (file)
index 0000000..235ad8b
--- /dev/null
@@ -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; }