Change some bad uses of C2x attributes into pedwarns.
authorJoseph Myers <joseph@codesourcery.com>
Tue, 19 Nov 2019 00:21:49 +0000 (00:21 +0000)
committerJoseph Myers <jsm28@gcc.gnu.org>
Tue, 19 Nov 2019 00:21:49 +0000 (00:21 +0000)
Certain bad uses of C2x standard attributes (that is, attributes
inside [[]] with only a name but no namespace specified) are
constraint violations, and so should be diagnosed with a pedwarn (or
error) where GCC currently uses a warning.  This patch implements this
in some cases (not yet for attributes used on types, nor for some bad
uses of fallthrough attributes).  Specifically, this applies to
unknown standard attributes (taking care not to pedwarn for nodiscard,
which is known but not implemented for C), and to all currently
implemented standard attributes in attribute declarations (including
when mixed with fallthrough) and on statements.

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

gcc/c:
* c-decl.c (c_warn_unused_attributes): Use pedwarn not warning for
standard attributes.
* c-parser.c (c_parser_std_attribute): Take argument for_tm.  Use
pedwarn for unknown standard attributes and return error_mark_node
for them.

gcc/c-family:
* c-common.c (attribute_fallthrough_p): In C, use pedwarn not
warning for standard attributes mixed with fallthrough attributes.

gcc/testsuite:
* gcc.dg/c2x-attr-fallthrough-5.c, gcc.dg/c2x-attr-syntax-5.c: New
tests.
* gcc.dg/c2x-attr-deprecated-2.c, gcc.dg/c2x-attr-deprecated-4.c,
gcc.dg/c2x-attr-fallthrough-2.c, gcc.dg/c2x-attr-maybe_unused-2.c,
gcc.dg/c2x-attr-maybe_unused-4.c: Expect errors in place of some
warnings.

From-SVN: r278428

13 files changed:
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c/ChangeLog
gcc/c/c-decl.c
gcc/c/c-parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/c2x-attr-deprecated-2.c
gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c
gcc/testsuite/gcc.dg/c2x-attr-fallthrough-2.c
gcc/testsuite/gcc.dg/c2x-attr-fallthrough-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-2.c
gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-4.c
gcc/testsuite/gcc.dg/c2x-attr-syntax-5.c [new file with mode: 0644]

index c7420f647d808ca48ea27a703a5017cd73607730..e1b437bf92ed50a32d7c5f504d08539ebd92e79b 100644 (file)
@@ -1,3 +1,8 @@
+2019-11-19  Joseph Myers  <joseph@codesourcery.com>
+
+       * c-common.c (attribute_fallthrough_p): In C, use pedwarn not
+       warning for standard attributes mixed with fallthrough attributes.
+
 2019-11-15  Joseph Myers  <joseph@codesourcery.com>
 
        * c-attribs.c (handle_fallthrough_attribute): Remove static.
index 48811994f3894b6642603f39be3b0cf57f37ef90..f779acc03873d354e4f9407e5318b993c735bb75 100644 (file)
@@ -5702,7 +5702,15 @@ attribute_fallthrough_p (tree attr)
     {
       tree name = get_attribute_name (t);
       if (!is_attribute_p ("fallthrough", name))
-       warning (OPT_Wattributes, "%qE attribute ignored", name);
+       {
+         if (!c_dialect_cxx () && get_attribute_namespace (t) == NULL_TREE)
+           /* The specifications of standard attributes in C mean
+              this is a constraint violation.  */
+           pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored",
+                    get_attribute_name (t));
+         else
+           warning (OPT_Wattributes, "%qE attribute ignored", name);
+       }
     }
   return true;
 }
index 0658ea0d2a69d65d1d342883ba78784d5e68e493..fff7dc6328ab645ad5f28af284353ad80ab510f9 100644 (file)
@@ -1,3 +1,11 @@
+2019-11-19  Joseph Myers  <joseph@codesourcery.com>
+
+       * c-decl.c (c_warn_unused_attributes): Use pedwarn not warning for
+       standard attributes.
+       * c-parser.c (c_parser_std_attribute): Take argument for_tm.  Use
+       pedwarn for unknown standard attributes and return error_mark_node
+       for them.
+
 2019-11-18  Matthew Malcomson  <matthew.malcomson@arm.com>
 
        * c-parser.c (c_parser_parse_rtl_body): Always call
index cb6169c464245096617a0a7349818706bd28ad23..746339d12edc7519e21aa7dbe0712010da274416 100644 (file)
@@ -4516,8 +4516,14 @@ void
 c_warn_unused_attributes (tree attrs)
 {
   for (tree t = attrs; t != NULL_TREE; t = TREE_CHAIN (t))
-    warning (OPT_Wattributes, "%qE attribute ignored",
-            get_attribute_name (t));
+    if (get_attribute_namespace (t) == NULL_TREE)
+      /* The specifications of standard attributes mean this is a
+        constraint violation.  */
+      pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored",
+              get_attribute_name (t));
+    else
+      warning (OPT_Wattributes, "%qE attribute ignored",
+              get_attribute_name (t));
 }
 \f
 /* Called when a declaration is seen that contains no names to declare.
index 2efa23424ffb5f2b707e9b8521ee15202b18e322..03194b438f23e7abc63845c63185ee696f447ef1 100644 (file)
@@ -4803,7 +4803,7 @@ c_parser_balanced_token_sequence (c_parser *parser)
 */
 
 static tree
-c_parser_std_attribute (c_parser *parser)
+c_parser_std_attribute (c_parser *parser, bool for_tm)
 {
   c_token *token = c_parser_peek_token (parser);
   tree ns, name, attribute;
@@ -4834,39 +4834,53 @@ c_parser_std_attribute (c_parser *parser)
   attribute = build_tree_list (build_tree_list (ns, name), NULL_TREE);
 
   /* Parse the arguments, if any.  */
-  if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
-    return attribute;
-  location_t open_loc = c_parser_peek_token (parser)->location;
-  matching_parens parens;
-  parens.consume_open (parser);
   const attribute_spec *as = lookup_attribute_spec (TREE_PURPOSE (attribute));
-  if ((as && as->max_length == 0)
-      /* Special-case the transactional-memory attribute "outer",
-        which is specially handled but not registered as an
-        attribute, to avoid allowing arbitrary balanced token
-        sequences as arguments.  */
-      || is_attribute_p ("outer", name))
-    {
-      error_at (open_loc, "%qE attribute does not take any arguments", name);
-      parens.skip_until_found_close (parser);
+  if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
+    goto out;
+  {
+    location_t open_loc = c_parser_peek_token (parser)->location;
+    matching_parens parens;
+    parens.consume_open (parser);
+    if ((as && as->max_length == 0)
+       /* Special-case the transactional-memory attribute "outer",
+          which is specially handled but not registered as an
+          attribute, to avoid allowing arbitrary balanced token
+          sequences as arguments.  */
+       || is_attribute_p ("outer", name))
+      {
+       error_at (open_loc, "%qE attribute does not take any arguments", name);
+       parens.skip_until_found_close (parser);
+       return error_mark_node;
+      }
+    if (as)
+      {
+       bool takes_identifier
+         = (ns != NULL_TREE
+            && strcmp (IDENTIFIER_POINTER (ns), "gnu") == 0
+            && attribute_takes_identifier_p (name));
+       bool require_string
+         = (ns == NULL_TREE
+            && strcmp (IDENTIFIER_POINTER (name), "deprecated") == 0);
+       TREE_VALUE (attribute)
+         = c_parser_attribute_arguments (parser, takes_identifier,
+                                         require_string, false);
+      }
+    else
+      c_parser_balanced_token_sequence (parser);
+    parens.require_close (parser);
+  }
+ out:
+  if (ns == NULL_TREE && !for_tm && !as && !is_attribute_p ("nodiscard", name))
+    {
+      /* An attribute with standard syntax and no namespace specified
+        is a constraint violation if it is not one of the known
+        standard attributes (of which nodiscard is the only one
+        without a handler in GCC).  Diagnose it here with a pedwarn
+        and then discard it to prevent a duplicate warning later.  */
+      pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored",
+              name);
       return error_mark_node;
     }
-  if (as)
-    {
-      bool takes_identifier
-       = (ns != NULL_TREE
-          && strcmp (IDENTIFIER_POINTER (ns), "gnu") == 0
-          && attribute_takes_identifier_p (name));
-      bool require_string
-       = (ns == NULL_TREE
-          && strcmp (IDENTIFIER_POINTER (name), "deprecated") == 0);
-      TREE_VALUE (attribute)
-       = c_parser_attribute_arguments (parser, takes_identifier,
-                                       require_string, false);
-    }
-  else
-    c_parser_balanced_token_sequence (parser);
-  parens.require_close (parser);
   return attribute;
 }
 
@@ -4898,7 +4912,7 @@ c_parser_std_attribute_specifier (c_parser *parser, bool for_tm)
          c_parser_consume_token (parser);
          continue;
        }
-      tree attribute = c_parser_std_attribute (parser);
+      tree attribute = c_parser_std_attribute (parser, for_tm);
       if (attribute != error_mark_node)
        {
          bool duplicate = false;
index f05382c87a730e194a0a36c919607b5a653ccd12..d258749ef5b544e4d63aed0fb269afe4b4963f8f 100644 (file)
@@ -1,3 +1,12 @@
+2019-11-19  Joseph Myers  <joseph@codesourcery.com>
+
+       * gcc.dg/c2x-attr-fallthrough-5.c, gcc.dg/c2x-attr-syntax-5.c: New
+       tests.
+       * gcc.dg/c2x-attr-deprecated-2.c, gcc.dg/c2x-attr-deprecated-4.c,
+       gcc.dg/c2x-attr-fallthrough-2.c, gcc.dg/c2x-attr-maybe_unused-2.c,
+       gcc.dg/c2x-attr-maybe_unused-4.c: Expect errors in place of some
+       warnings.
+
 2019-11-18  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * g++.dg/cpp0x/addressof2.C: Test locations too.
index 2d47606cce8127a13ad4d2ba68a9be35e514305f..0f0b1749ae4fdc24dcd5f0a9f10239705f480adc 100644 (file)
@@ -5,7 +5,7 @@
 /* This attribute is not valid in most cases on types other than their
    definitions, or on statements, or as an attribute-declaration.  */
 
-[[deprecated]]; /* { dg-warning "ignored" } */
+[[deprecated]]; /* { dg-error "ignored" } */
 
 int [[deprecated]] var; /* { dg-warning "ignored" } */
 /* { dg-message "that appertains to a type-specifier" "appertains" { target *-*-* } .-1 } */
@@ -20,6 +20,6 @@ void
 f (void)
 {
   int a;
-  [[deprecated]]; /* { dg-warning "ignored" } */
-  [[deprecated]] a = 1; /* { dg-warning "ignored" } */
+  [[deprecated]]; /* { dg-error "ignored" } */
+  [[deprecated]] a = 1; /* { dg-error "ignored" } */
 }
index ce6615b4ba15735c8de136aca53685039336f2e9..f1848a20cd54a72ea108e5e1874a9f3c2e123a9d 100644 (file)
@@ -6,7 +6,7 @@
 [[__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 } */
+/* { dg-error "ignored" "ignored" { target *-*-* } .-1 } */
 
 /* Separate attribute lists in the same attribute specifier sequence,
    with the same attribute in them, are OK.  */
index e396a60ea0c77c8432b8e0eec6431415fe5582bc..33e3ec282279c2b1ea53d1f6ea4ce81edd343f14 100644 (file)
@@ -31,5 +31,5 @@ f (int a)
       b += 5;
       break;
     }
-  [[fallthrough]] return b; /* { dg-warning "ignored" } */
+  [[fallthrough]] return b; /* { dg-error "ignored" } */
 }
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-fallthrough-5.c b/gcc/testsuite/gcc.dg/c2x-attr-fallthrough-5.c
new file mode 100644 (file)
index 0000000..c614ceb
--- /dev/null
@@ -0,0 +1,30 @@
+/* Test C2x fallthrough attribute: mixtures with other attributes.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+/* Use of other standard attributes together with "fallthrough" goes
+   through a different path to diagnosing ignored attributes from that
+   used in attribute declarations without "fallthrough".  Verify that
+   such ignored attributes result in a pedwarn (for use in a context
+   not permitted in the constraints for those attributes) in this case
+   as well.  */
+
+int
+f (int a)
+{
+  switch (a)
+    {
+    case 1:
+      a++;
+      [[fallthrough, deprecated]]; /* { dg-error "attribute ignored" } */
+    case 2:
+      a++;
+      [[maybe_unused]] [[fallthrough]]; /* { dg-error "attribute ignored" } */
+    case 3:
+      a++;
+      [[__nodiscard__, fallthrough]]; /* { dg-error "attribute ignored" } */
+    case 4:
+      a++;
+    }
+  return a;
+}
index 9b5055bad480ef3fb2a2d2e30d19d39b1384d90c..7f06581f949ac482e580dad5d6671e35d96f7560 100644 (file)
@@ -5,7 +5,7 @@
 /* This attribute is not valid in most cases on types other than their
    definitions, or on statements, or as an attribute-declaration.  */
 
-[[maybe_unused]]; /* { dg-warning "ignored" } */
+[[maybe_unused]]; /* { dg-error "ignored" } */
 
 int [[maybe_unused]] var; /* { dg-warning "ignored" } */
 /* { dg-message "that appertains to a type-specifier" "appertains" { target *-*-* } .-1 } */
@@ -20,6 +20,6 @@ void
 f (void)
 {
   int a;
-  [[maybe_unused]]; /* { dg-warning "ignored" } */
-  [[maybe_unused]] a = 1; /* { dg-warning "ignored" } */
+  [[maybe_unused]]; /* { dg-error "ignored" } */
+  [[maybe_unused]] a = 1; /* { dg-error "ignored" } */
 }
index ae7e1dcd0b762ea6a5a2deed0f0765e30a5f84ef..300c0dae73c16ef9674db80d715d1d240358ff64 100644 (file)
@@ -6,7 +6,7 @@
 [[__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 } */
+/* { dg-error "ignored" "ignored" { target *-*-* } .-1 } */
 
 /* Separate attribute lists in the same attribute specifier sequence,
    with the same attribute in them, are OK.  */
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-syntax-5.c b/gcc/testsuite/gcc.dg/c2x-attr-syntax-5.c
new file mode 100644 (file)
index 0000000..37a2411
--- /dev/null
@@ -0,0 +1,56 @@
+/* Test C2x attribute syntax.  Test unknown standard attributes
+   diagnosed with a pedwarn.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+[[unknown_attribute]]; /* { dg-error "attribute ignored" } */
+
+[[unknown_attribute]] extern int a; /* { dg-error "attribute ignored" } */
+extern int [[unknown_attribute(123)]] a; /* { dg-error "attribute ignored" } */
+extern int a [[unknown_attribute("")]]; /* { dg-error "attribute ignored" } */
+
+int f () [[unknown_attribute]]; /* { dg-error "attribute ignored" } */
+int f (void) [[unknown_attribute(1)]]; /* { dg-error "attribute ignored" } */
+int g ([[unknown_attribute]] int a); /* { dg-error "attribute ignored" } */
+int g (int [[unknown_attribute]] a); /* { dg-error "attribute ignored" } */
+int g (int a [[unknown_attribute]]); /* { dg-error "attribute ignored" } */
+int g ([[unknown_attribute]] int); /* { dg-error "attribute ignored" } */
+int g (int [[unknown_attribute]]); /* { dg-error "attribute ignored" } */
+int g (int) [[unknown_attribute]]; /* { dg-error "attribute ignored" } */
+
+int *[[unknown_attribute]] p; /* { dg-error "attribute ignored" } */
+int b[3] [[unknown_attribute]]; /* { dg-error "attribute ignored" } */
+
+int h (int () [[unknown_attribute]]); /* { dg-error "attribute ignored" } */
+
+struct [[unknown_attribute]] s; /* { dg-error "attribute ignored" } */
+union [[unknown_attribute]] u; /* { dg-error "attribute ignored" } */
+
+struct [[unknown_attribute]] s2 { int a; }; /* { dg-error "attribute ignored" } */
+union [[unknown_attribute(x)]] u2 { int a; }; /* { dg-error "attribute ignored" } */
+
+struct s3 { [[unknown_attribute]] int a; }; /* { dg-error "attribute ignored" } */
+struct s4 { int [[unknown_attribute]] a; }; /* { dg-error "attribute ignored" } */
+union u3 { [[unknown_attribute]] int a; }; /* { dg-error "attribute ignored" } */
+union u4 { int [[unknown_attribute]] a; }; /* { dg-error "attribute ignored" } */
+
+int z = sizeof (int [[unknown_attribute]]); /* { dg-error "attribute ignored" } */
+
+enum [[unknown_attribute]] { E1 }; /* { dg-error "attribute ignored" } */
+enum { E2 [[unknown_attribute]] }; /* { dg-error "attribute ignored" } */
+enum { E3 [[unknown_attribute]] = 4 }; /* { dg-error "attribute ignored" } */
+
+void
+func (void) [[unknown_attribute]] { /* { dg-error "attribute ignored" } */
+  [[unknown_attribute]] int var; /* { dg-error "attribute ignored" } */
+  [[unknown_attribute]] { } /* { dg-error "attribute ignored" } */
+  [[unknown_attribute(!)]]; /* { dg-error "attribute ignored" } */
+  [[unknown_attribute]] var = 1; /* { dg-error "attribute ignored" } */
+  [[unknown_attribute]] x: var = 2; /* { dg-error "attribute ignored" } */
+  for ([[unknown_attribute]] int zz = 1; zz < 10; zz++) ; /* { dg-error "attribute ignored" } */
+}
+
+/* nodiscard is not yet implemented, but is a standard attribute, so
+   its use is not a constraint violation and should only receive a
+   warning.  */
+[[nodiscard]] int ndfunc (void); /* { dg-warning "attribute directive ignored" } */