On Mon, Aug 19, 2024 at 05:05:51PM -0400, Jason Merrill wrote: > > 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. > > On the other side, clang++ diagnoses > > enum B { B0 } [[deprecated]]; > > but GCC with all the patches I've posted today doesn't, is that a GCC bug? > > I think so, yes.
Fixed in the just posted 2 patches. > > The FIXMEs are where there is agreement with clang++, but I'm not sure. > > One thing is I'm not sure if "a variable" above is meant to include function > > parameters, and/or unused function parameters without a specified name, > > function parameters inside of a function declaration rather than definition > > and/or static data members. > > All of those, I believe. Removed the FIXMEs. > > Also unsure about > > [[deprecated]] int : 0; > > at class scope, that isn't a non-static data member... > > Indeed, pedantically the standard says it can't apply to an unnamed > bit-field. And the following updated version on top of the https://gcc.gnu.org/pipermail/gcc-patches/2024-August/661904.html https://gcc.gnu.org/pipermail/gcc-patches/2024-August/661905.html patches also diagnoses the attribute on unnamed bit-fields. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2024-08-30 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. --- gcc/cp/parser.cc.jj 2024-08-30 11:13:18.612089567 +0200 +++ gcc/cp/parser.cc 2024-08-30 12:55:17.875362909 +0200 @@ -30357,12 +30357,11 @@ cp_parser_std_attribute (cp_parser *pars /* 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)) --- gcc/cp/tree.cc.jj 2024-08-15 22:23:07.908239976 +0200 +++ gcc/cp/tree.cc 2024-08-30 13:15:26.863829810 +0200 @@ -5087,6 +5087,25 @@ handle_likeliness_attribute (tree *node, return error_mark_node; } +/* 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[] = { @@ -5110,6 +5129,8 @@ static const attribute_spec std_attribut { /* { 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, --- gcc/testsuite/g++.dg/cpp0x/attr-deprecated1.C.jj 2024-08-30 12:55:17.877362884 +0200 +++ gcc/testsuite/g++.dg/cpp0x/attr-deprecated1.C 2024-08-30 16:05:10.939240604 +0200 @@ -0,0 +1,131 @@ +// 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) {} +} + +[[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 () +{ +} +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]; Jakub