aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2024-12-20 10:12:08 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2024-12-20 10:12:08 +0100
commitcd647514a539943ade6461efbf056a7c3f4305c6 (patch)
tree7782c5b1240cc7f18cd43e6fb570445b33575fc1 /gcc
parenta25cc26884663244c3b936af785854abee8949dd (diff)
downloadgcc-cd647514a539943ade6461efbf056a7c3f4305c6.zip
gcc-cd647514a539943ade6461efbf056a7c3f4305c6.tar.gz
gcc-cd647514a539943ade6461efbf056a7c3f4305c6.tar.bz2
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 <jakub@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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/parser.cc9
-rw-r--r--gcc/cp/tree.cc21
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/attr-deprecated1.C152
3 files changed, 177 insertions, 5 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 23c6a2f..892d3e6 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 1eef600..12d0831 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 0000000..7a75e6c
--- /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];