https://gcc.gnu.org/g:cd647514a539943ade6461efbf056a7c3f4305c6

commit r15-6384-gcd647514a539943ade6461efbf056a7c3f4305c6
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Fri Dec 20 10:12:08 2024 +0100

    c++: Disallow [[deprecated]] on types other than class/enum definitions 
[PR110345]
    
    For C++ 26 P2552R3 I went through all the spots (except modules) where
    attribute-specifier-seq appears in the grammar and tried to construct
    a testcase in all those spots, for now for [[deprecated]] attribute.
    
    The patch below contains that testcase.  One needed change for this
    particular attribute was that currently we handle [[deprecated]]
    exactly the same as [[gnu::deprecated]], but for the latter unlike C++14
    or later we allow it also on almost all types, while the standard
    is strict and allows it only on
    https://eel.is/c++draft/dcl.attr#deprecated-2
    The attribute may be applied to the declaration of a class, a typedef-name,
    a variable, a non-static data member, a function, a namespace,
    an enumeration, an enumerator, a concept, or a template specialization.
    
    The following patch just adds a pedwarn for the cases that gnu::deprecated
    allows but C++14 disallows, so integral/floating/boolean types,
    pointers/references, array types, function types etc.
    Basically, for TYPE_P, if the attribute is applied in place (which means
    the struct/union/class/enum definition), it is allowed, otherwise pedwarned.
    
    I've tried to compile it also with latest clang and there is agreement in
    most of the diagnostics, just at block scope (inside of foo) it doesn't
    diagnose
      auto e = new int [n] [[deprecated]];
      auto e2 = new int [n] [[deprecated]] [42];
      [[deprecated]] lab:;
    and at namespace scope
    [[deprecated]];
    I think that all feels like clang++ bug.
    
    Also this pedwarns on
      [[deprecated]] int : 0;
    at class scope, that isn't a non-static data member...
    
    I guess to mark the paper as implemented (or what has been already voted
    into C++23 earlier) we'll need to add similar testcase for all the other
    standard attributes and make sure we check what the attributes can appertain
    to and what they can't.
    
    2024-12-19  Jakub Jelinek  <ja...@redhat.com>
    
            PR c++/110345
            * parser.cc (cp_parser_std_attribute): Don't transform
            [[deprecated]] into [[gnu::deprecated]].
            * tree.cc (handle_std_deprecated_attribute): New function.
            (std_attributes): Add deprecated entry.
    
            * g++.dg/cpp0x/attr-deprecated1.C: New test.

Diff:
---
 gcc/cp/parser.cc                              |   9 +-
 gcc/cp/tree.cc                                |  21 ++++
 gcc/testsuite/g++.dg/cpp0x/attr-deprecated1.C | 152 ++++++++++++++++++++++++++
 3 files changed, 177 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 23c6a2fd30e4..892d3e6a8ac2 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -30783,12 +30783,11 @@ cp_parser_std_attribute (cp_parser *parser, tree 
attr_ns)
 
       /* 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.  */
-      if (is_attribute_p ("deprecated", attr_id))
-       TREE_PURPOSE (TREE_PURPOSE (attribute)) = gnu_identifier;
+        __attribute__((noreturn)) apart.
+        Similarly for C++14 deprecated attribute, we need to emit extra
+        diagnostics for [[deprecated]] compared to [[gnu::deprecated]].  */
       /* C++17 fallthrough attribute is equivalent to GNU's.  */
-      else if (is_attribute_p ("fallthrough", attr_id))
+      if (is_attribute_p ("fallthrough", attr_id))
        TREE_PURPOSE (TREE_PURPOSE (attribute)) = gnu_identifier;
       /* C++23 assume attribute is equivalent to GNU's.  */
       else if (is_attribute_p ("assume", attr_id))
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 1eef600c79a4..12d0831e4c4c 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5143,6 +5143,25 @@ handle_alignas_attribute (tree *node, tree name, tree 
args, int flags,
   return ret;
 }
 
+/* The C++14 [[deprecated]] attribute mostly maps to the GNU deprecated
+   attribute.  */
+
+static tree
+handle_std_deprecated_attribute (tree *node, tree name, tree args, int flags,
+                                bool *no_add_attrs)
+{
+  tree t = *node;
+  tree ret = handle_deprecated_attribute (node, name, args, flags,
+                                         no_add_attrs);
+  if (TYPE_P (*node) && t != *node)
+    pedwarn (input_location, OPT_Wattributes,
+            "%qE on a type other than class or enumeration definition", name);
+  else if (TREE_CODE (*node) == FIELD_DECL && DECL_UNNAMED_BIT_FIELD (*node))
+    pedwarn (input_location, OPT_Wattributes, "%qE on unnamed bit-field",
+            name);
+  return ret;
+}
+
 /* Table of valid C++ attributes.  */
 static const attribute_spec cxx_gnu_attributes[] =
 {
@@ -5166,6 +5185,8 @@ static const attribute_spec std_attributes[] =
 {
   /* { 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_std_deprecated_attribute, NULL },
   { "maybe_unused", 0, 0, false, false, false, false,
     handle_unused_attribute, NULL },
   { "nodiscard", 0, 1, false, false, false, false,
diff --git a/gcc/testsuite/g++.dg/cpp0x/attr-deprecated1.C 
b/gcc/testsuite/g++.dg/cpp0x/attr-deprecated1.C
new file mode 100644
index 000000000000..7a75e6c653aa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/attr-deprecated1.C
@@ -0,0 +1,152 @@
+// C++ 26 P2552R3 - On the ignorability of standard attributes
+// { dg-do compile { target c++11 } }
+
+int arr[2];
+struct S { int a, b; };
+S arr2[2];
+
+void
+foo (int n)
+{
+  [[deprecated]] int x1;
+  [[deprecated ("foobar")]] int x2;
+  [[deprecated (0)]] int x3;                   // { dg-error "deprecated 
message is not a string" }
+                                               // { dg-error "expected 
string-literal before numeric constant" "" { target c++26 } .-1 }
+  [[deprecated ("foo", "bar", "baz")]] int x4; // { dg-error "wrong number of 
arguments specified for 'deprecated' attribute" }
+  [[deprecated (0, 1, 2)]] int x5;             // { dg-error "wrong number of 
arguments specified for 'deprecated' attribute" }
+                                               // { dg-error "expected 
string-literal before numeric constant" "" { target c++26 } .-1 }
+
+  auto a = [] [[deprecated]] () {};
+  auto b = [] constexpr [[deprecated]] {};     // { dg-error "'deprecated' on 
a type other than class or enumeration definition" }
+                                               // { dg-error "parameter 
declaration before lambda declaration specifiers only optional with" "" { 
target c++20_down } .-1 }
+                                               // { dg-error "'constexpr' 
lambda only available with" "" { target c++14_down } .-2 }
+  auto c = [] noexcept [[deprecated]] {};      // { dg-error "'deprecated' on 
a type other than class or enumeration definition" }
+                                               // { dg-error "parameter 
declaration before lambda exception specification only optional with" "" { 
target c++20_down } .-1 }
+  auto d = [] () [[deprecated]] {};            // { dg-error "'deprecated' on 
a type other than class or enumeration definition" }
+  auto e = new int [n] [[deprecated]];         // { dg-warning "attributes 
ignored on outermost array type in new expression" }
+  auto e2 = new int [n] [[deprecated]] [42];   // { dg-warning "attributes 
ignored on outermost array type in new expression" }
+  auto f = new int [n][42] [[deprecated]];     // { dg-error "'deprecated' on 
a type other than class or enumeration definition" }
+  [[deprecated]];                              // { dg-warning "attributes at 
the beginning of statement are ignored" }
+  [[deprecated]] {}                            // { dg-warning "attributes at 
the beginning of statement are ignored" }
+  [[deprecated]] if (true) {}                  // { dg-warning "attributes at 
the beginning of statement are ignored" }
+  [[deprecated]] while (false) {}              // { dg-warning "attributes at 
the beginning of statement are ignored" }
+  [[deprecated]] goto lab;                     // { dg-warning "attributes at 
the beginning of statement are ignored" }
+  [[deprecated]] lab:;                         // { dg-error "'deprecated' 
attribute ignored" }
+  [[deprecated]] try {} catch (int) {}         // { dg-warning "attributes at 
the beginning of statement are ignored" }
+  if ([[deprecated]] int x = 0) {}
+  switch (n)
+    {
+    [[deprecated]] case 1:                     // { dg-error "'deprecated' 
attribute ignored" }
+    [[deprecated]] break;                      // { dg-warning "attributes at 
the beginning of statement are ignored" }
+    [[deprecated]] default:                    // { dg-error "'deprecated' 
attribute ignored" }
+        break;
+    }
+  for ([[deprecated]] auto a : arr) {}
+  for ([[deprecated]] auto [a, b] : arr2) {}   // { dg-error "structured 
bindings only available with" "" { target c++14_down } }
+  [[deprecated]] asm ("");                     // { dg-warning "attributes 
ignored on 'asm' declaration" }
+  try {} catch ([[deprecated]] int x) {}
+  try {} catch ([[deprecated]] int) {}
+  try {} catch (int [[deprecated]] x) {}       // { dg-warning "attribute 
ignored" }
+  try {} catch (int [[deprecated]]) {}         // { dg-warning "attribute 
ignored" }
+  try {} catch (int x [[deprecated]]) {}
+}
+
+[[deprecated]] int bar ();
+using foobar [[deprecated]] = int;
+[[deprecated]] int a;
+[[deprecated]] auto [b, c] = arr;              // { dg-error "structured 
bindings only available with" "" { target c++14_down } }
+[[deprecated]];                                        // { dg-warning 
"attribute ignored" }
+inline [[deprecated]] void baz () {}           // { dg-warning "attribute 
ignored" }
+                                               // { dg-error "standard 
attributes in middle of decl-specifiers" "" { target *-*-* } .-1 }
+constexpr [[deprecated]] int qux () { return 0; }      // { dg-warning 
"attribute ignored" }
+                                               // { dg-error "standard 
attributes in middle of decl-specifiers" "" { target *-*-* } .-1 }
+int [[deprecated]] d;                          // { dg-warning "attribute 
ignored" }
+int const [[deprecated]] e = 1;                        // { dg-warning 
"attribute ignored" }
+struct A {} [[deprecated]];                    // { dg-warning "attribute 
ignored in declaration of 'struct A'" }
+struct A [[deprecated]];                       // { dg-warning "attribute 
ignored" }
+struct A [[deprecated]] a1;                    // { dg-warning "attribute 
ignored" }
+A [[deprecated]] a2;                           // { dg-warning "attribute 
ignored" }
+enum B { B0 } [[deprecated]];                  // { dg-warning "attribute 
ignored in declaration of 'enum B'" }
+enum B [[deprecated]];                         // { dg-warning "attribute 
ignored" }
+enum B [[deprecated]] b1;                      // { dg-warning "attribute 
ignored" }
+B [[deprecated]] b2;                           // { dg-warning "attribute 
ignored" }
+struct [[deprecated]] C {};
+int f [[deprecated]];
+int g[2] [[deprecated]];                       // { dg-error "'deprecated' on 
a type other than class or enumeration definition" }
+int g2 [[deprecated]] [2];
+int corge () [[deprecated]];                   // { dg-error "'deprecated' on 
a type other than class or enumeration definition" }
+int *[[deprecated]] h;                         // { dg-error "'deprecated' on 
a type other than class or enumeration definition" }
+int & [[deprecated]] i = f;                    // { dg-error "'deprecated' on 
a type other than class or enumeration definition" }
+                                               // { dg-warning "'f' is 
deprecated" "" { target *-*-* } .-1 }
+int && [[deprecated]] j = 0;                   // { dg-error "'deprecated' on 
a type other than class or enumeration definition" }
+int S::* [[deprecated]] k;                     // { dg-error "'deprecated' on 
a type other than class or enumeration definition" }
+auto l = sizeof (int [2] [[deprecated]]);      // { dg-error "'deprecated' on 
a type other than class or enumeration definition" }
+int freddy ([[deprecated]] int a,
+           [[deprecated]] int,
+           [[deprecated]] int c = 0,
+           [[deprecated]] int = 0);
+void
+corge ([[deprecated]] int a,
+       [[deprecated]] int,
+       [[deprecated]] int c = 0,
+       [[deprecated]] int = 0)
+{
+}
+[[deprecated]] void
+garply ()
+{
+}
+int grault (int [[deprecated]] a,              // { dg-warning "attribute 
ignored" }
+           int [[deprecated]],                 // { dg-warning "attribute 
ignored" }
+           int [[deprecated]] c = 0,           // { dg-warning "attribute 
ignored" }
+           int [[deprecated]] = 0);            // { dg-warning "attribute 
ignored" }
+void
+waldo (int [[deprecated]] a,                   // { dg-warning "attribute 
ignored" }
+       int [[deprecated]],                     // { dg-warning "attribute 
ignored" }
+       int [[deprecated]] c = 0,               // { dg-warning "attribute 
ignored" }
+       int [[deprecated]] = 0)                 // { dg-warning "attribute 
ignored" }
+{
+}
+int plugh (int a [[deprecated]],
+           int b [[deprecated]] = 0);
+void
+thud (int a [[deprecated]],
+      int b [[deprecated]] = 0)
+{
+}
+enum [[deprecated]] D { D0 };
+enum class [[deprecated]] E { E0 };
+enum F {};
+enum [[deprecated]] F;                         // { dg-warning "type 
attributes ignored after type is already defined" }
+enum G {
+  G0 [[deprecated]],
+  G1 [[deprecated]] = 2
+};
+namespace [[deprecated]] H { using H0 = int; }
+namespace [[deprecated]] {}                    // { dg-warning "ignoring 
'deprecated' attribute on anonymous namespace" }
+[[deprecated]] using namespace H;              // { dg-warning "'deprecated' 
attribute directive ignored" }
+                                               // { dg-warning "'H' is 
deprecated" "" { target *-*-* } .-1 }
+struct [[deprecated]] I
+{
+  [[deprecated]];                              // { dg-error "declaration does 
not declare anything" }
+  [[deprecated]] int i;
+  [[deprecated]] int foo ();
+  [[deprecated]] int bar () { return 1; }
+  [[deprecated]] int : 0;                      // { dg-error "'deprecated' on 
unnamed bit-field" }
+  [[deprecated]] int i2 : 5;
+  [[deprecated]] static int i3;
+  static int i4;
+};
+[[deprecated]] int I::i4 = 0;
+struct J : [[deprecated]] C {};                        // { dg-warning 
"attributes on base specifiers are ignored" }
+#if __cpp_concepts >= 201907L
+template <typename T>
+concept K [[deprecated]] = requires { true; };
+#endif
+typedef int L [[deprecated]];
+template <typename T>
+struct M {};
+template <>
+struct [[deprecated]] M<int> { int m; };
+typedef int N[2] [[deprecated]];               // { dg-error "'deprecated' on 
a type other than class or enumeration definition" }
+typedef int O [[deprecated]] [2];

Reply via email to