]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR c++/60364 - noreturn after first decl not diagnosed.
authormpolacek <mpolacek@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 19 Jun 2019 21:27:45 +0000 (21:27 +0000)
committermpolacek <mpolacek@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 19 Jun 2019 21:27:45 +0000 (21:27 +0000)
* attribs.c (get_attribute_namespace): No longer static.
(decl_attributes): Avoid shadowing.  Preserve the C++11 form for C++11
attributes.
(attr_noreturn_exclusions): Make it extern.
* attribs.h (get_attribute_namespace): Declare.
* tree-inline.c (function_attribute_inlinable_p): Use
get_attribute_name.

* c-attribs.c (handle_noreturn_attribute): No longer static.
* c-common.h (handle_noreturn_attribute, attr_noreturn_exclusions):
Declare.
* c-format.c (check_function_format): Use get_attribute_name.

* decl.c (duplicate_decls): Give an error when a function is
declared [[noreturn]] after its first declaration.
* parser.c (cp_parser_std_attribute): Don't treat C++11 noreturn
attribute as equivalent to GNU's.
* tree.c (std_attribute_table): Add noreturn.

* g++.dg/warn/noreturn-8.C: New test.
* g++.dg/warn/noreturn-9.C: New test.
* g++.dg/warn/noreturn-10.C: New test.
* g++.dg/warn/noreturn-11.C: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@272486 138bc75d-0d04-0410-961f-82ee72b054a4

17 files changed:
gcc/ChangeLog
gcc/attribs.c
gcc/attribs.h
gcc/c-family/ChangeLog
gcc/c-family/c-attribs.c
gcc/c-family/c-common.h
gcc/c-family/c-format.c
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/parser.c
gcc/cp/tree.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/warn/noreturn-10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/noreturn-11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/noreturn-8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/noreturn-9.C [new file with mode: 0644]
gcc/tree-inline.c

index bf5ae3e2dc2100d4b7e834ef05abea262d564fda..3f868bacad45f3a5abca5fe7ab28d3b2ef7de9f4 100644 (file)
@@ -1,3 +1,14 @@
+2019-06-19  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/60364 - noreturn after first decl not diagnosed.
+       * attribs.c (get_attribute_namespace): No longer static.
+       (decl_attributes): Avoid shadowing.  Preserve the C++11 form for C++11
+       attributes.
+       (attr_noreturn_exclusions): Make it extern.
+       * attribs.h (get_attribute_namespace): Declare.
+       * tree-inline.c (function_attribute_inlinable_p): Use
+       get_attribute_name.
+
 2019-06-19  Martin Sebor  <msebor@redhat.com>
 
        PR tree-optimization/90626
index 4441922543f3c187cdf57ff7b4a66e939a68b32c..8e54016559723fbe79e7bd4edf3cd90720264d50 100644 (file)
@@ -340,7 +340,7 @@ lookup_attribute_spec (const_tree name)
    Please read the comments of cxx11_attribute_p to understand the
    format of attributes.  */
 
-static tree
+tree
 get_attribute_namespace (const_tree attr)
 {
   if (cxx11_attribute_p (attr))
@@ -469,7 +469,6 @@ tree
 decl_attributes (tree *node, tree attributes, int flags,
                 tree last_decl /* = NULL_TREE */)
 {
-  tree a;
   tree returned_attrs = NULL_TREE;
 
   if (TREE_TYPE (*node) == error_mark_node || attributes == error_mark_node)
@@ -548,22 +547,23 @@ decl_attributes (tree *node, tree attributes, int flags,
 
   /* Note that attributes on the same declaration are not necessarily
      in the same order as in the source.  */
-  for (a = attributes; a; a = TREE_CHAIN (a))
+  for (tree attr = attributes; attr; attr = TREE_CHAIN (attr))
     {
-      tree ns = get_attribute_namespace (a);
-      tree name = get_attribute_name (a);
-      tree args = TREE_VALUE (a);
+      tree ns = get_attribute_namespace (attr);
+      tree name = get_attribute_name (attr);
+      tree args = TREE_VALUE (attr);
       tree *anode = node;
       const struct attribute_spec *spec
        = lookup_scoped_attribute_spec (ns, name);
       int fn_ptr_quals = 0;
       tree fn_ptr_tmp = NULL_TREE;
+      const bool cxx11_attr_p = cxx11_attribute_p (attr);
 
       if (spec == NULL)
        {
          if (!(flags & (int) ATTR_FLAG_BUILT_IN))
            {
-             if (ns == NULL_TREE || !cxx11_attribute_p (a))
+             if (ns == NULL_TREE || !cxx11_attr_p)
                warning (OPT_Wattributes, "%qE attribute directive ignored",
                         name);
              else
@@ -584,7 +584,7 @@ decl_attributes (tree *node, tree attributes, int flags,
       gcc_assert (is_attribute_p (spec->name, name));
 
       if (TYPE_P (*node)
-         && cxx11_attribute_p (a)
+         && cxx11_attr_p
          && !(flags & ATTR_FLAG_TYPE_IN_PLACE))
        {
          /* This is a c++11 attribute that appertains to a
@@ -707,8 +707,7 @@ decl_attributes (tree *node, tree attributes, int flags,
 
       if (spec->handler != NULL)
        {
-         int cxx11_flag =
-           cxx11_attribute_p (a) ? ATTR_FLAG_CXX11 : 0;
+         int cxx11_flag = (cxx11_attr_p ? ATTR_FLAG_CXX11 : 0);
 
          /* Pass in an array of the current declaration followed
             by the last pushed/merged declaration if  one exists.
@@ -756,17 +755,23 @@ decl_attributes (tree *node, tree attributes, int flags,
          if (a == NULL_TREE)
            {
              /* This attribute isn't already in the list.  */
+             tree r;
+             /* Preserve the C++11 form.  */
+             if (cxx11_attr_p)
+               r = tree_cons (build_tree_list (ns, name), args, old_attrs);
+             else
+               r = tree_cons (name, args, old_attrs);
+
              if (DECL_P (*anode))
-               DECL_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
+               DECL_ATTRIBUTES (*anode) = r;
              else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
                {
-                 TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
+                 TYPE_ATTRIBUTES (*anode) = r;
                  /* If this is the main variant, also push the attributes
                     out to the other variants.  */
                  if (*anode == TYPE_MAIN_VARIANT (*anode))
                    {
-                     tree variant;
-                     for (variant = *anode; variant;
+                     for (tree variant = *anode; variant;
                           variant = TYPE_NEXT_VARIANT (variant))
                        {
                          if (TYPE_ATTRIBUTES (variant) == old_attrs)
@@ -780,9 +785,7 @@ decl_attributes (tree *node, tree attributes, int flags,
                    }
                }
              else
-               *anode = build_type_attribute_variant (*anode,
-                                                      tree_cons (name, args,
-                                                                 old_attrs));
+               *anode = build_type_attribute_variant (*anode, r);
            }
        }
 
index 83ecbbbeec90178c5519e89e7dea4ef19b779224..23a7321e04ad78ffa2525d1fce6081d97a2faf20 100644 (file)
@@ -35,6 +35,7 @@ extern tree decl_attributes (tree *, tree, int, tree = NULL_TREE);
 
 extern bool cxx11_attribute_p (const_tree);
 extern tree get_attribute_name (const_tree);
+extern tree get_attribute_namespace (const_tree);
 extern void apply_tm_attr (tree, tree);
 extern tree make_attribute (const char *, const char *, tree);
 
index f64b749e86beb1d3da2c38f7e32bb29e30d47969..e744561f67a9cd4e6b92157a2603d23fabfe63f9 100644 (file)
@@ -1,3 +1,11 @@
+2019-06-19  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/60364 - noreturn after first decl not diagnosed.
+       * c-attribs.c (handle_noreturn_attribute): No longer static.
+       * c-common.h (handle_noreturn_attribute, attr_noreturn_exclusions):
+       Declare.
+       * c-format.c (check_function_format): Use get_attribute_name.
+
 2019-06-19  Martin Sebor  <msebor@redhat.com>
 
        PR translation/90156
index 7a8d3935d7991ecf96cb4747cf7f93892ce3360e..48819e74e5b619639fd4293b605d12d7ee6a809c 100644 (file)
@@ -49,7 +49,6 @@ along with GCC; see the file COPYING3.  If not see
 static tree handle_packed_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *);
 static tree handle_common_attribute (tree *, tree, tree, int, bool *);
-static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
 static tree handle_hot_attribute (tree *, tree, tree, int, bool *);
 static tree handle_cold_attribute (tree *, tree, tree, int, bool *);
 static tree handle_no_sanitize_attribute (tree *, tree, tree, int, bool *);
@@ -190,7 +189,7 @@ static const struct attribute_spec::exclusions attr_noinline_exclusions[] =
   ATTR_EXCL (NULL, false, false, false),
 };
 
-static const struct attribute_spec::exclusions attr_noreturn_exclusions[] =
+extern const struct attribute_spec::exclusions attr_noreturn_exclusions[] =
 {
   ATTR_EXCL ("alloc_align", true, true, true),
   ATTR_EXCL ("alloc_size", true, true, true),
@@ -779,7 +778,7 @@ handle_common_attribute (tree *node, tree name, tree ARG_UNUSED (args),
 /* Handle a "noreturn" attribute; arguments as in
    struct attribute_spec.handler.  */
 
-static tree
+tree
 handle_noreturn_attribute (tree *node, tree name, tree ARG_UNUSED (args),
                           int ARG_UNUSED (flags), bool *no_add_attrs)
 {
index 1cf2cae63951ede2ab14c258c62120655f523829..5ac6e5eacf94513f349b0bab64539e4d12786631 100644 (file)
@@ -1344,6 +1344,8 @@ extern int tm_attr_to_mask (tree);
 extern tree tm_mask_to_attr (int);
 extern tree find_tm_attribute (tree);
 extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[];
+extern const struct attribute_spec::exclusions attr_noreturn_exclusions[];
+extern tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
 
 /* In c-format.c.  */
 extern bool valid_format_string_type_p (tree);
index a790f3c0394bab3cfcee68dc068e0c3f4594463b..6363fa4f686c2d56886dc66ea6d7ce1321c20ecd 100644 (file)
@@ -1168,7 +1168,7 @@ check_function_format (const_tree fntype, tree attrs, int nargs,
   /* See if this function has any format attributes.  */
   for (a = attrs; a; a = TREE_CHAIN (a))
     {
-      if (is_attribute_p ("format", TREE_PURPOSE (a)))
+      if (is_attribute_p ("format", get_attribute_name (a)))
        {
          /* Yup; check it.  */
          function_format_info info;
index f5dab5493adfb299b3908228788497e5b1ab822f..5b659269b1f1b7bf253553b99fd3c11e1eedffda 100644 (file)
@@ -1,3 +1,12 @@
+2019-06-19  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/60364 - noreturn after first decl not diagnosed.
+       * decl.c (duplicate_decls): Give an error when a function is
+       declared [[noreturn]] after its first declaration.
+       * parser.c (cp_parser_std_attribute): Don't treat C++11 noreturn
+       attribute as equivalent to GNU's.
+       * tree.c (std_attribute_table): Add noreturn.
+
 2019-06-19  Jakub Jelinek  <jakub@redhat.com>
 
        * cp-gimplify.c (cp_genericize_r): Handle OMP_CLAUSE_{IN,EX}CLUSIVE
index 0a3ef452536fa836c3b37e227304ebccd878ee41..85f96f7373966a0ee9dd45c02d33720928795692 100644 (file)
@@ -1922,10 +1922,29 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
 
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
-      if (merge_attr && diagnose_mismatched_attributes (olddecl, newdecl))
-       inform (olddecl_loc, DECL_INITIAL (olddecl)
-               ? G_("previous definition of %qD here")
-               : G_("previous declaration of %qD here"), olddecl);
+      if (merge_attr)
+       {
+         if (diagnose_mismatched_attributes (olddecl, newdecl))
+           inform (olddecl_loc, DECL_INITIAL (olddecl)
+                   ? G_("previous definition of %qD here")
+                   : G_("previous declaration of %qD here"), olddecl);
+
+         /* [dcl.attr.noreturn]: The first declaration of a function shall
+            specify the noreturn attribute if any declaration of that function
+            specifies the noreturn attribute.  */
+         tree a;
+         if (TREE_THIS_VOLATILE (newdecl)
+             && !TREE_THIS_VOLATILE (olddecl)
+             /* This applies to [[noreturn]] only, not its GNU variants.  */
+             && (a = lookup_attribute ("noreturn", DECL_ATTRIBUTES (newdecl)))
+             && cxx11_attribute_p (a)
+             && get_attribute_namespace (a) == NULL_TREE)
+           {
+             error_at (newdecl_loc, "function %qD declared %<[[noreturn]]%> "
+                       "but its first declaration was not", newdecl);
+             inform (olddecl_loc, "previous declaration of %qD", olddecl);
+           }
+       }
 
       /* Now that functions must hold information normally held
         by field decls, there is extra work to do so that
index 6b4aab8a12f3b3d4c1b3e564490ebc5927e2afad..561d0e2d6ee8ece6eccd5f7ad6e89bf98fbcc5d2 100644 (file)
@@ -26121,11 +26121,11 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
       attr_id = canonicalize_attr_name (attr_id);
       attribute = build_tree_list (build_tree_list (NULL_TREE, attr_id),
                                   NULL_TREE);
-      /* C++11 noreturn attribute is equivalent to GNU's.  */
-      if (is_attribute_p ("noreturn", attr_id))
-       TREE_PURPOSE (TREE_PURPOSE (attribute)) = gnu_identifier;
+      /* We used to treat C++11 noreturn attribute as equivalent to GNU's,
+        but no longer: we have to be able to tell [[noreturn]] and
+        __attribute__((noreturn)) apart.  */
       /* C++14 deprecated attribute is equivalent to GNU's.  */
-      else if (is_attribute_p ("deprecated", attr_id))
+      if (is_attribute_p ("deprecated", attr_id))
        TREE_PURPOSE (TREE_PURPOSE (attribute)) = gnu_identifier;
       /* C++17 fallthrough attribute is equivalent to GNU's.  */
       else if (is_attribute_p ("fallthrough", attr_id))
index cd021b7f594e9b258d7cc9c4e4dffb969712e62c..978aea56193592fb3a92bc77068c7bb434aadc4a 100644 (file)
@@ -4453,6 +4453,8 @@ const struct attribute_spec std_attribute_table[] =
     handle_likeliness_attribute, attr_cold_hot_exclusions },
   { "unlikely", 0, 0, false, false, false, false,
     handle_likeliness_attribute, attr_cold_hot_exclusions },
+  { "noreturn", 0, 0, true, false, false, false,
+    handle_noreturn_attribute, attr_noreturn_exclusions },
   { NULL, 0, 0, false, false, false, false, NULL, NULL }
 };
 
index 76f06225d3c7784753b05ec9139e9a745fa7cac4..521be1fba16c1acf0c92023f8d981dbbecca7da6 100644 (file)
@@ -1,3 +1,11 @@
+2019-06-19  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/60364 - noreturn after first decl not diagnosed.
+       * g++.dg/warn/noreturn-8.C: New test.
+       * g++.dg/warn/noreturn-9.C: New test.
+       * g++.dg/warn/noreturn-10.C: New test.
+       * g++.dg/warn/noreturn-11.C: New test.
+
 2019-06-19  Martin Sebor  <msebor@redhat.com>
 
        PR tree-optimization/90626
diff --git a/gcc/testsuite/g++.dg/warn/noreturn-10.C b/gcc/testsuite/g++.dg/warn/noreturn-10.C
new file mode 100644 (file)
index 0000000..6f7df48
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/60364
+// { dg-do compile { target c++11 } }
+
+void* fn1 [[gnu::returns_twice, noreturn]] (); // { dg-warning "ignoring attribute 'noreturn' because it conflicts with attribute 'returns_twice'" }
+void* fn2 [[gnu::alloc_align(1), noreturn]] (int); // { dg-warning "ignoring attribute 'noreturn' because it conflicts with attribute 'alloc_align'" }
+void* fn3 [[gnu::alloc_size(1), noreturn]] (int); // { dg-warning "ignoring attribute 'noreturn' because it conflicts with attribute 'alloc_size'" }
+void* fn4 [[gnu::const, noreturn]] (); // { dg-warning "ignoring attribute 'noreturn' because it conflicts with attribute 'const'" }
+void* fn5 [[gnu::malloc, noreturn]] (int); // { dg-warning "ignoring attribute 'noreturn' because it conflicts with attribute 'malloc'" }
+void* fn6 [[gnu::pure, noreturn]] (); // { dg-warning "ignoring attribute 'noreturn' because it conflicts with attribute 'pure'" }
+void* fn7 [[gnu::warn_unused_result, noreturn]] (); // { dg-warning "ignoring attribute 'noreturn' because it conflicts with attribute 'warn_unused_result'" }
diff --git a/gcc/testsuite/g++.dg/warn/noreturn-11.C b/gcc/testsuite/g++.dg/warn/noreturn-11.C
new file mode 100644 (file)
index 0000000..e0265eb
--- /dev/null
@@ -0,0 +1,25 @@
+// PR c++/60364
+// { dg-do compile { target c++11 } }
+
+void f1 ();
+void f1 [[gnu::noreturn]] ();
+void f1 [[noreturn]] ();
+
+void f2 ();
+__attribute__((noreturn)) void f2 ();
+void f2 [[noreturn]] ();
+
+void f3 ();
+void f3 [[gnu::noreturn]] ();
+void f3 ();
+void f3 [[noreturn]] ();
+
+void f4 ();
+void f4 ();
+void f4 ();
+void f4 [[noreturn]] (); // { dg-error "declared '\\\[\\\[noreturn\\\]\\\]' but its first declaration was not" }
+
+void f5 [[noreturn]] ();
+void f5 ();
+void f5 ();
+void f5 [[noreturn]] ();
diff --git a/gcc/testsuite/g++.dg/warn/noreturn-8.C b/gcc/testsuite/g++.dg/warn/noreturn-8.C
new file mode 100644 (file)
index 0000000..d465468
--- /dev/null
@@ -0,0 +1,21 @@
+// PR c++/60364
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wpedantic" }
+
+void f (); // { dg-message "previous declaration" }
+void f [[noreturn]] (); // { dg-error "declared '\\\[\\\[noreturn\\\]\\\]' but its first declaration was not" }
+
+void f2 ();
+void f2 [[gnu::noreturn]] ();
+
+void f3 ();
+__attribute__((noreturn)) void f3 ();
+
+void f4 () { __builtin_abort (); } // { dg-message "previous declaration" }
+void f4 [[noreturn]] (); // { dg-error "declared '\\\[\\\[noreturn\\\]\\\]' but its first declaration was not" }
+
+void f5 () { __builtin_abort (); }
+void f5 [[gnu::noreturn]] ();
+
+void f6 () { __builtin_abort (); }
+__attribute__((noreturn)) void f6 ();
diff --git a/gcc/testsuite/g++.dg/warn/noreturn-9.C b/gcc/testsuite/g++.dg/warn/noreturn-9.C
new file mode 100644 (file)
index 0000000..f7ede57
--- /dev/null
@@ -0,0 +1,21 @@
+// PR c++/60364
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wpedantic" }
+
+void f1 [[gnu::noreturn]] ();
+void f1 [[noreturn]] ();
+
+void f2 [[noreturn]] ();
+void f2 [[gnu::noreturn]] ();
+
+__attribute__((noreturn)) void f3 ();
+void f3 [[noreturn]] ();
+
+void f4 [[noreturn]] ();
+__attribute__((noreturn)) void f4 ();
+
+__attribute__((noreturn)) void f5 ();
+void f5 [[gnu::noreturn]] ();
+
+void f6 [[gnu::noreturn]] ();
+__attribute__((noreturn)) void f6 ();
index 52f45a73b1d71e7a5ac63dd6f1f60e7f9c96cc70..2de5e22f10fd60bee904de1f77578424b82fb7bf 100644 (file)
@@ -3899,7 +3899,7 @@ function_attribute_inlinable_p (const_tree fndecl)
 
       for (a = DECL_ATTRIBUTES (fndecl); a; a = TREE_CHAIN (a))
        {
-         const_tree name = TREE_PURPOSE (a);
+         const_tree name = get_attribute_name (a);
          int i;
 
          for (i = 0; targetm.attribute_table[i].name != NULL; i++)