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
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_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_attribute_table[] =
                              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 *node, tree name,
   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.  */
 
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'
-   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, tree olddecl,
                 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, tree olddecl,
              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, tree olddecl,
         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, tree newtype, tree oldtype)
     }
 
 #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 *declarator, struct c_declspecs *declspecs,
   /* 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 *declspecs, struct c_declarator *declarator,
     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))))
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{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 unless optimization is 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
@@ -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
-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++.
 
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
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; }