diff mbox series

Change some bad uses of C2x attributes into pedwarns

Message ID alpine.DEB.2.21.1911190021530.23687@digraph.polyomino.org.uk
State New
Headers show
Series Change some bad uses of C2x attributes into pedwarns | expand

Commit Message

Joseph Myers Nov. 19, 2019, 12:22 a.m. UTC
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.  Applied to 
mainline.

gcc/c:
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.

gcc/c-family:
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.

gcc/testsuite:
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.
diff mbox series

Patch

Index: gcc/c/c-decl.c
===================================================================
--- gcc/c/c-decl.c	(revision 278418)
+++ gcc/c/c-decl.c	(working copy)
@@ -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));
 }
 
 /* Called when a declaration is seen that contains no names to declare.
Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 278418)
+++ gcc/c/c-parser.c	(working copy)
@@ -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 @@  static tree
   attribute = build_tree_list (build_tree_list (ns, name), NULL_TREE);
 
   /* Parse the arguments, if any.  */
+  const attribute_spec *as = lookup_attribute_spec (TREE_PURPOSE (attribute));
   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))
+    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))
     {
-      error_at (open_loc, "%qE attribute does not take any arguments", name);
-      parens.skip_until_found_close (parser);
+      /* 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
 	  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: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 278418)
+++ gcc/c-family/c-common.c	(working copy)
@@ -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: gcc/testsuite/gcc.dg/c2x-attr-deprecated-2.c
===================================================================
--- gcc/testsuite/gcc.dg/c2x-attr-deprecated-2.c	(revision 278418)
+++ gcc/testsuite/gcc.dg/c2x-attr-deprecated-2.c	(working copy)
@@ -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: gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c
===================================================================
--- gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c	(revision 278418)
+++ gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c	(working copy)
@@ -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: gcc/testsuite/gcc.dg/c2x-attr-fallthrough-2.c
===================================================================
--- gcc/testsuite/gcc.dg/c2x-attr-fallthrough-2.c	(revision 278418)
+++ gcc/testsuite/gcc.dg/c2x-attr-fallthrough-2.c	(working copy)
@@ -31,5 +31,5 @@  f (int a)
       b += 5;
       break;
     }
-  [[fallthrough]] return b; /* { dg-warning "ignored" } */
+  [[fallthrough]] return b; /* { dg-error "ignored" } */
 }
Index: gcc/testsuite/gcc.dg/c2x-attr-fallthrough-5.c
===================================================================
--- gcc/testsuite/gcc.dg/c2x-attr-fallthrough-5.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/c2x-attr-fallthrough-5.c	(working copy)
@@ -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: gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-2.c
===================================================================
--- gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-2.c	(revision 278418)
+++ gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-2.c	(working copy)
@@ -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: gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-4.c
===================================================================
--- gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-4.c	(revision 278418)
+++ gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-4.c	(working copy)
@@ -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.  */
Index: gcc/testsuite/gcc.dg/c2x-attr-syntax-5.c
===================================================================
--- gcc/testsuite/gcc.dg/c2x-attr-syntax-5.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/c2x-attr-syntax-5.c	(working copy)
@@ -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" } */