Diagnose duplicate C2x standard attributes.
authorJoseph Myers <joseph@codesourcery.com>
Fri, 15 Nov 2019 23:22:41 +0000 (23:22 +0000)
committerJoseph Myers <jsm28@gcc.gnu.org>
Fri, 15 Nov 2019 23:22:41 +0000 (23:22 +0000)
For each of the attributes currently included in C2x, it has a
constraint that the attribute shall appear at most once in each
attribute list (attribute-list being what appear between a single [[
and ]]).

This patch implements that check.  As the corresponding check in the
C++ front end (cp_parser_check_std_attribute) makes violations into
errors, I made them into errors, with the same wording, for C as well.

There is an existing check in the case of the fallthrough attribute,
with a warning rather than an error, in attribute_fallthrough_p.  That
is more general, as it also covers __attribute__ ((fallthrough)) and
the case of [[fallthrough]] [[fallthrough]] (multiple attribute-lists
in a single attribute-specifier-sequence), which is not a constraint
violation.  To avoid some [[fallthrough, fallthrough]] being diagnosed
twice, the check I added avoids adding duplicate attributes to the
list.

Bootstrapped with no regressions on x86_64-pc-linux-gnu.

gcc/c:
* c-parser.c (c_parser_std_attribute_specifier): Diagnose
duplicate standard attributes.

gcc/testsuite:
* gcc.dg/c2x-attr-deprecated-4.c, gcc.dg/c2x-attr-fallthrough-4.c,
gcc.dg/c2x-attr-maybe_unused-4.c: New tests.

From-SVN: r278324

gcc/c/ChangeLog
gcc/c/c-parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c2x-attr-fallthrough-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-4.c [new file with mode: 0644]

index 75a44e289278f34a425367036bc080351ccf25f7..0076e83688803729a53feec5bf1e4805a97288ff 100644 (file)
@@ -1,3 +1,8 @@
+2019-11-15  Joseph Myers  <joseph@codesourcery.com>
+
+       * c-parser.c (c_parser_std_attribute_specifier): Diagnose
+       duplicate standard attributes.
+
 2019-11-15  Joseph Myers  <joseph@codesourcery.com>
 
        * c-decl.c (std_attribute_table): Add maybe_unused.
index 5b290bf7567cdb8b9eaae619c6c57b1cbcfeda2b..e48760dfd633bee3f270fce83c84d1990b4441ad 100644 (file)
@@ -4873,6 +4873,9 @@ c_parser_std_attribute (c_parser *parser)
 static tree
 c_parser_std_attribute_specifier (c_parser *parser, bool for_tm)
 {
+  bool seen_deprecated = false;
+  bool seen_fallthrough = false;
+  bool seen_maybe_unused = false;
   location_t loc = c_parser_peek_token (parser)->location;
   if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>"))
     return NULL_TREE;
@@ -4898,8 +4901,55 @@ c_parser_std_attribute_specifier (c_parser *parser, bool for_tm)
       tree attribute = c_parser_std_attribute (parser);
       if (attribute != error_mark_node)
        {
-         TREE_CHAIN (attribute) = attributes;
-         attributes = attribute;
+         bool duplicate = false;
+         tree name = get_attribute_name (attribute);
+         tree ns = get_attribute_namespace (attribute);
+         if (ns == NULL_TREE)
+           {
+             /* Some standard attributes may appear at most once in
+                each attribute list.  Diagnose duplicates and remove
+                them from the list to avoid subsequent diagnostics
+                such as the more general one for multiple
+                "fallthrough" attributes in the same place (including
+                in separate attribute lists in the same attribute
+                specifier sequence, which is not a constraint
+                violation).  */
+             if (is_attribute_p ("deprecated", name))
+               {
+                 if (seen_deprecated)
+                   {
+                     error ("attribute %<deprecated%> can appear at most "
+                            "once in an attribute-list");
+                     duplicate = true;
+                   }
+                 seen_deprecated = true;
+               }
+             else if (is_attribute_p ("fallthrough", name))
+               {
+                 if (seen_fallthrough)
+                   {
+                     error ("attribute %<fallthrough%> can appear at most "
+                            "once in an attribute-list");
+                     duplicate = true;
+                   }
+                 seen_fallthrough = true;
+               }
+             else if (is_attribute_p ("maybe_unused", name))
+               {
+                 if (seen_maybe_unused)
+                   {
+                     error ("attribute %<maybe_unused%> can appear at most "
+                            "once in an attribute-list");
+                     duplicate = true;
+                   }
+                 seen_maybe_unused = true;
+               }
+           }
+         if (!duplicate)
+           {
+             TREE_CHAIN (attribute) = attributes;
+             attributes = attribute;
+           }
        }
       if (c_parser_next_token_is_not (parser, CPP_COMMA))
        break;
index 997096cf1d67b1fdeae6d217b06a02cd3c4fa6e3..4376337e333e75430ce84bed7cf67e2d0916c4e4 100644 (file)
@@ -1,3 +1,8 @@
+2019-11-15  Joseph Myers  <joseph@codesourcery.com>
+
+       * gcc.dg/c2x-attr-deprecated-4.c, gcc.dg/c2x-attr-fallthrough-4.c,
+       gcc.dg/c2x-attr-maybe_unused-4.c: New tests.
+
 2019-11-15  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * g++.dg/warn/Walways-true-1.C: Check locations too.
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c b/gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c
new file mode 100644 (file)
index 0000000..ce6615b
--- /dev/null
@@ -0,0 +1,13 @@
+/* Test C2x deprecated attribute: duplicates.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+[[deprecated, __deprecated__]] int a; /* { dg-error "can appear at most once" } */
+[[__deprecated__, deprecated("message")]] int b; /* { dg-error "can appear at most once" } */
+int c [[deprecated("message"), deprecated]]; /* { dg-error "can appear at most once" } */
+[[deprecated, deprecated]]; /* { dg-error "can appear at most once" } */
+/* { dg-warning "ignored" "ignored" { target *-*-* } .-1 } */
+
+/* Separate attribute lists in the same attribute specifier sequence,
+   with the same attribute in them, are OK.  */
+[[deprecated]] [[deprecated]] int d [[deprecated]] [[deprecated]];
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-fallthrough-4.c b/gcc/testsuite/gcc.dg/c2x-attr-fallthrough-4.c
new file mode 100644 (file)
index 0000000..75aceff
--- /dev/null
@@ -0,0 +1,23 @@
+/* Test C2x fallthrough attribute: duplicates.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+int
+f (int a)
+{
+  switch (a)
+    {
+    case 1:
+      a++;
+      [[fallthrough, __fallthrough__]]; /* { dg-error "can appear at most once" } */
+    case 2:
+      a++;
+      /* Separate attribute lists in the same attribute specifier
+        sequence, with the same attribute in them, are OK (but
+        receive a warning).  */
+      [[fallthrough]] [[fallthrough]]; /* { dg-warning "specified multiple times" } */
+    case 3:
+      a++;
+    }
+  return a;
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-4.c b/gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-4.c
new file mode 100644 (file)
index 0000000..ae7e1dc
--- /dev/null
@@ -0,0 +1,13 @@
+/* Test C2x maybe_unused attribute: duplicates.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+[[maybe_unused, __maybe_unused__]] int a; /* { dg-error "can appear at most once" } */
+[[__maybe_unused__, maybe_unused]] int b; /* { dg-error "can appear at most once" } */
+int c [[maybe_unused, maybe_unused]]; /* { dg-error "can appear at most once" } */
+[[maybe_unused, maybe_unused]]; /* { dg-error "can appear at most once" } */
+/* { dg-warning "ignored" "ignored" { target *-*-* } .-1 } */
+
+/* Separate attribute lists in the same attribute specifier sequence,
+   with the same attribute in them, are OK.  */
+[[maybe_unused]] [[maybe_unused]] int d [[maybe_unused]] [[maybe_unused]];