Support C2x [[deprecated]] attribute.
authorJoseph Myers <joseph@codesourcery.com>
Fri, 15 Nov 2019 00:06:30 +0000 (00:06 +0000)
committerJoseph Myers <jsm28@gcc.gnu.org>
Fri, 15 Nov 2019 00:06:30 +0000 (00:06 +0000)
This patch adds support for the C2x [[deprecated]] attribute.  All the
actual logic for generating warnings can be identical to the GNU
__attribute__ ((deprecated)), as can the attribute handler, so this is
just a matter of wiring things up appropriately and adding the checks
specified in the standard.  Unlike for C++, this patch gives
"deprecated" an entry in a table of standard attributes rather than
remapping it internally to the GNU attribute, as that seems a cleaner
approach to me.

Specifically, the only form of arguments to the attribute permitted in
the standard is (string-literal); empty parentheses are not permitted
in the case of no arguments, and a string literal (which includes
concatenated adjacent string literals, because concatenation is an
earlier phase of translation) cannot have further redundant
parentheses around it.  For the case of empty parentheses, this patch
makes the C parser disallow them for all known attributes using the
[[]] syntax, as done for C++.  For string literals (where the C++
front end is missing the check to avoid redundant parentheses, 92521
filed for that issue), a special case is inserted in the C parser.

A known issue that I think can be addressed later as a bug fix is that
the warnings for the attribute being ignored in certain cases
(attribute declarations, statements, most uses on types) ought to be
pedwarns, as those usages are constraint violations.

Bad handling of wide string literals with this attribute is also a
pre-existing bug (91182 - although that's filed as a C++ bug, the code
in question is language-independent, in tree.c).

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

gcc/c:
* c-decl.c (std_attribute_table): New.
(c_init_decl_processing): Register attributes from
std_attribute_table.
* c-parser.c (c_parser_attribute_arguments): Add arguments
require_string and allow_empty_args.  All callers changed.
(c_parser_std_attribute): Set require_string argument for
"deprecated" attribute.

gcc/c-family:
* c-attribs.c (handle_deprecated_attribute): Remove static.
* c-common.h (handle_deprecated_attribute): Declare.

gcc/testsuite:
* gcc.dg/c2x-attr-deprecated-1.c, gcc.dg/c2x-attr-deprecated-2.c,
gcc.dg/c2x-attr-deprecated-3.c: New tests.

From-SVN: r278268

gcc/c-family/ChangeLog
gcc/c-family/c-attribs.c
gcc/c-family/c-common.h
gcc/c/ChangeLog
gcc/c/c-decl.c
gcc/c/c-parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/c2x-attr-deprecated-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c2x-attr-deprecated-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c2x-attr-deprecated-3.c [new file with mode: 0644]

index f4fdccc448afa28a5d4e0c5d685fd949c2824cdd..571cf2bc1b7523293ca208cbb2b0d99eac51fdea 100644 (file)
@@ -1,3 +1,8 @@
+2019-11-15  Joseph Myers  <joseph@codesourcery.com>
+
+       * c-attribs.c (handle_deprecated_attribute): Remove static.
+       * c-common.h (handle_deprecated_attribute): Declare.
+
 2019-11-14  Joseph Myers  <joseph@codesourcery.com>
 
        * c-lex.c (lex_charconst): Make CPP_UTF8CHAR constants unsigned
index c62cebf7bfdbf86f5adcef85af84ab4b0c349027..18b829f47fe594e5d84dfd5a5e10e90c9af9441f 100644 (file)
@@ -115,8 +115,6 @@ static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
 static tree handle_tm_attribute (tree *, tree, tree, int, bool *);
 static tree handle_tm_wrap_attribute (tree *, tree, tree, int, bool *);
 static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
-static tree handle_deprecated_attribute (tree *, tree, tree, int,
-                                        bool *);
 static tree handle_vector_size_attribute (tree *, tree, tree, int,
                                          bool *);
 static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
@@ -3468,7 +3466,7 @@ handle_novops_attribute (tree *node, tree ARG_UNUSED (name),
 /* Handle a "deprecated" attribute; arguments as in
    struct attribute_spec.handler.  */
 
-static tree
+tree
 handle_deprecated_attribute (tree *node, tree name,
                             tree args, int flags,
                             bool *no_add_attrs)
index 80a8c9f45432d2a4c640ada4accdc22b9fbdefbd..ad40c15d92fdfa238a17b308fcc1b2690ff24ad6 100644 (file)
@@ -1357,6 +1357,7 @@ extern void warn_for_multistatement_macros (location_t, location_t,
 
 /* In c-attribs.c.  */
 extern bool attribute_takes_identifier_p (const_tree);
+extern tree handle_deprecated_attribute (tree *, tree, tree, int, bool *);
 extern tree handle_unused_attribute (tree *, tree, tree, int, bool *);
 extern int parse_tm_stmt_attr (tree, int);
 extern int tm_attr_to_mask (tree);
index b881cab75ded4a2055ef3452034d567fda293a3e..fdc915329c83c1e6adebaa3d572eaa35f905ea58 100644 (file)
@@ -1,3 +1,13 @@
+2019-11-15  Joseph Myers  <joseph@codesourcery.com>
+
+       * c-decl.c (std_attribute_table): New.
+       (c_init_decl_processing): Register attributes from
+       std_attribute_table.
+       * c-parser.c (c_parser_attribute_arguments): Add arguments
+       require_string and allow_empty_args.  All callers changed.
+       (c_parser_std_attribute): Set require_string argument for
+       "deprecated" attribute.
+
 2019-11-14  Joseph Myers  <joseph@codesourcery.com>
 
        * c-parser.c (c_parser_postfix_expression)
index f8090597cdfd5ebf3e414000381bee1b5a0bc0af..a7f7c69678850d79ae7edd241d572fc291a543c2 100644 (file)
@@ -4336,6 +4336,16 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
 }
 
 \f
+/* Table of supported standard (C2x) attributes.  */
+const struct attribute_spec std_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
+       affects_type_identity, handler, exclude } */
+  { "deprecated", 0, 1, false, false, false, false,
+    handle_deprecated_attribute, NULL },
+  { NULL, 0, 0, false, false, false, false, NULL, NULL }
+};
+
 /* Create the predefined scalar types of C,
    and some nodes representing standard constants (0, 1, (void *) 0).
    Initialize the global scope.
@@ -4349,6 +4359,8 @@ c_init_decl_processing (void)
   /* Initialize reserved words for parser.  */
   c_parse_init ();
 
+  register_scoped_attributes (std_attribute_table, NULL);
+
   current_function_decl = NULL_TREE;
 
   gcc_obstack_init (&parser_obstack);
index 8ce4e70a0fc0d224c6c0a5978d5fd359713381b4..721158a2c3e979113faf735dbdb39c7703a0f90a 100644 (file)
@@ -4478,7 +4478,8 @@ c_parser_gnu_attribute_any_word (c_parser *parser)
    allow identifiers declared as types to start the arguments?  */
 
 static tree
-c_parser_attribute_arguments (c_parser *parser, bool takes_identifier)
+c_parser_attribute_arguments (c_parser *parser, bool takes_identifier,
+                             bool require_string, bool allow_empty_args)
 {
   vec<tree, va_gc> *expr_list;
   tree attr_args;
@@ -4518,7 +4519,21 @@ c_parser_attribute_arguments (c_parser *parser, bool takes_identifier)
   else
     {
       if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
-       attr_args = NULL_TREE;
+       {
+         if (!allow_empty_args)
+           error_at (c_parser_peek_token (parser)->location,
+                     "parentheses must be omitted if "
+                     "attribute argument list is empty");
+         attr_args = NULL_TREE;
+       }
+      else if (require_string)
+       {
+         /* The only valid argument for this attribute is a string
+            literal.  Handle this specially here to avoid accepting
+            string literals with excess parentheses.  */
+         tree string = c_parser_string_literal (parser, false, true).value;
+         attr_args = build_tree_list (NULL_TREE, string);
+       }
       else
        {
          expr_list = c_parser_expr_list (parser, false, true,
@@ -4601,7 +4616,8 @@ c_parser_gnu_attribute (c_parser *parser, tree attrs,
 
   tree attr_args
     = c_parser_attribute_arguments (parser,
-                                   attribute_takes_identifier_p (attr_name));
+                                   attribute_takes_identifier_p (attr_name),
+                                   false, true);
 
   attr = build_tree_list (attr_name, attr_args);
   if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
@@ -4835,8 +4851,12 @@ c_parser_std_attribute (c_parser *parser)
        = (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);
+       = c_parser_attribute_arguments (parser, takes_identifier,
+                                       require_string, false);
     }
   else
     c_parser_balanced_token_sequence (parser);
index 51624b7212e42b5e963ac14c6834e761695d5c9e..17494d02032f4fba61300e2d27a3f5d82acdfeaf 100644 (file)
@@ -1,3 +1,8 @@
+2019-11-15  Joseph Myers  <joseph@codesourcery.com>
+
+       * gcc.dg/c2x-attr-deprecated-1.c, gcc.dg/c2x-attr-deprecated-2.c,
+       gcc.dg/c2x-attr-deprecated-3.c: New tests.
+
 2019-11-14  Joseph Myers  <joseph@codesourcery.com>
 
        * gcc.dg/c11-utf8char-1.c, gcc.dg/c2x-utf8char-1.c,
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-deprecated-1.c b/gcc/testsuite/gcc.dg/c2x-attr-deprecated-1.c
new file mode 100644 (file)
index 0000000..de0ae51
--- /dev/null
@@ -0,0 +1,91 @@
+/* Test C2x deprecated attribute: valid uses.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+/* Similar to tests from gnu2x-attrs-1.c, but using the standard
+   attribute instead of gnu::deprecated, and sometimes using
+   __deprecated__ or a string-literal argument.  */
+
+[[deprecated]] void f1 (void);
+
+[[deprecated]] typedef int dep_int;
+
+dep_int dv; /* { dg-warning "deprecated" } */
+
+void
+g (void)
+{
+  f1 (); /* { dg-warning "deprecated" } */
+}
+
+int
+f2 (void)
+{
+  [[deprecated ("for this reason")]] int a = 1;
+  return a; /* { dg-warning "for this reason" } */
+}
+
+int
+f3 (void)
+{
+  int a [[__deprecated__]] = 1;
+  return a; /* { dg-warning "deprecated" } */
+}
+
+struct s2 { [[__deprecated__("some other message")]] int a; int b [[deprecated]]; } x;
+
+int
+f4 (void)
+{
+  return x.a; /* { dg-warning "some other message" } */
+}
+
+int
+f5 (void)
+{
+  return x.b; /* { dg-warning "deprecated" } */
+}
+
+enum e { E1 [[deprecated("third message")]] };
+
+enum e
+f6 (void)
+{
+  return E1; /* { dg-warning "third message" } */
+}
+
+int
+f7 ([[deprecated]] int y)
+{
+  return y; /* { dg-warning "deprecated" } */
+}
+
+union [[__deprecated__]] u { int x; };
+
+void
+f8 (void)
+{
+  union u var; /* { dg-warning "deprecated" } */
+}
+
+enum [[deprecated("edep reason")]] edep { E2 };
+
+void
+f9 (void)
+{
+  enum edep var; /* { dg-warning "edep reason" } */
+}
+
+union u2 { [[__deprecated__]] int a; int b [[deprecated]]; } y;
+
+int
+f10 (void)
+{
+  return y.a; /* { dg-warning "deprecated" } */
+}
+
+int
+f11 (void)
+{
+  return y.b; /* { dg-warning "deprecated" } */
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-deprecated-2.c b/gcc/testsuite/gcc.dg/c2x-attr-deprecated-2.c
new file mode 100644 (file)
index 0000000..2d47606
--- /dev/null
@@ -0,0 +1,25 @@
+/* Test C2x deprecated attribute: invalid contexts.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+/* 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" } */
+
+int [[deprecated]] var; /* { dg-warning "ignored" } */
+/* { dg-message "that appertains to a type-specifier" "appertains" { target *-*-* } .-1 } */
+
+int array_with_dep_type[2] [[deprecated]]; /* { dg-warning "ignored" } */
+/* { dg-message "that appertains to a type-specifier" "appertains" { target *-*-* } .-1 } */
+
+void fn_with_dep_type () [[deprecated]]; /* { dg-warning "ignored" } */
+/* { dg-message "that appertains to a type-specifier" "appertains" { target *-*-* } .-1 } */
+
+void
+f (void)
+{
+  int a;
+  [[deprecated]]; /* { dg-warning "ignored" } */
+  [[deprecated]] a = 1; /* { dg-warning "ignored" } */
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-deprecated-3.c b/gcc/testsuite/gcc.dg/c2x-attr-deprecated-3.c
new file mode 100644 (file)
index 0000000..044725e
--- /dev/null
@@ -0,0 +1,11 @@
+/* Test C2x deprecated attribute: invalid syntax.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+[[deprecated()]] int a; /* { dg-error "parentheses must be omitted if attribute argument list is empty" } */
+
+[[deprecated(0)]] int b; /* { dg-error "expected" } */
+
+[[deprecated("", 123)]] int c; /* { dg-error "expected" } */
+
+[[deprecated((""))]] int d; /* { dg-error "expected" } */