This PR complains that we are not handling the attribute deprecated on namespaces. This has gotten more important now because of ranges-v3 which renamed its "view" namespace to "views", following the PascalCase to snake_case change, and "view" is now deprecated.
Unfortunately we can't just call cp_warn_deprecated_use_scopes in cp_parser_nested_name_specifier_opt and call it a day because we shouldn't warn for code like namespace [[deprecated]] N { void fn(); } void N::fn(); // here void N::fn() { } // and here and in cp_parser_nested_name_specifier_opt we simply don't know if we're dealing with a function decl. Calling cp_warn_deprecated_use_scopes from cp_parser_type_specifier resulted int duplicated diagnostics so that one is out too. So I did the following which doesn't seem too bad. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2019-08-20 Marek Polacek <pola...@redhat.com> PR c++/79817 - attribute deprecated on namespace. * cp-tree.h (cp_warn_deprecated_use_scopes): Declare. * decl.c (grokdeclarator): Call cp_warn_deprecated_use_scopes. (type_is_deprecated): Likewise. * decl2.c (cp_warn_deprecated_use_scopes): New function. * name-lookup.c (handle_namespace_attrs): Handle attribute deprecated. * parser.c (cp_parser_namespace_alias_definition): Call cp_warn_deprecated_use_scopes. (cp_parser_using_declaration): Likewise. (cp_parser_using_directive): Likewise. * semantics.c (finish_id_expression_1): Likewise. * g++.dg/cpp0x/attributes-namespace1.C: New test. * g++.dg/cpp0x/attributes-namespace2.C: New test. * g++.dg/cpp0x/attributes-namespace3.C: New test. * g++.dg/cpp0x/attributes-namespace4.C: New test. * g++.dg/cpp0x/attributes-namespace5.C: New test. * g++.dg/cpp1z/namespace-attribs.C: Adjust. * g++.dg/cpp1z/namespace-attribs2.C: Adjust. diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h index 05f91861b42..42f180d1dd3 100644 --- gcc/cp/cp-tree.h +++ gcc/cp/cp-tree.h @@ -6264,6 +6264,7 @@ extern bool is_list_ctor (tree); extern void validate_conversion_obstack (void); extern void mark_versions_used (tree); extern bool cp_warn_deprecated_use (tree, tsubst_flags_t = tf_warning_or_error); +extern void cp_warn_deprecated_use_scopes (tree); extern tree get_function_version_dispatcher (tree); /* in class.c */ diff --git gcc/cp/decl.c gcc/cp/decl.c index 08b7baa40e0..46ad0271f7b 100644 --- gcc/cp/decl.c +++ gcc/cp/decl.c @@ -10791,6 +10791,7 @@ grokdeclarator (const cp_declarator *declarator, cp_warn_deprecated_use (type); if (type && TREE_CODE (type) == TYPE_DECL) { + cp_warn_deprecated_use_scopes (DECL_CONTEXT (type)); typedef_decl = type; type = TREE_TYPE (typedef_decl); if (DECL_ARTIFICIAL (typedef_decl)) @@ -13230,7 +13231,10 @@ type_is_deprecated (tree type) if (TREE_DEPRECATED (TYPE_NAME (type))) return type; else - return NULL_TREE; + { + cp_warn_deprecated_use_scopes (DECL_CONTEXT (TYPE_NAME (type))); + return NULL_TREE; + } } /* Do warn about using typedefs to a deprecated class. */ diff --git gcc/cp/decl2.c gcc/cp/decl2.c index a32108f9d16..d6f407d7aef 100644 --- gcc/cp/decl2.c +++ gcc/cp/decl2.c @@ -5407,6 +5407,23 @@ cp_warn_deprecated_use (tree decl, tsubst_flags_t complain) return warned; } +/* Like above, but takes into account outer scopes. */ + +void +cp_warn_deprecated_use_scopes (tree ns) +{ + while (ns + && ns != error_mark_node + && ns != global_namespace) + { + cp_warn_deprecated_use (ns); + if (TYPE_P (ns)) + ns = CP_TYPE_CONTEXT (ns); + else + ns = CP_DECL_CONTEXT (ns); + } +} + /* Mark DECL (either a _DECL or a BASELINK) as "used" in the program. If DECL is a specialization or implicitly declared class member, generate the actual definition. Return false if something goes diff --git gcc/cp/name-lookup.c gcc/cp/name-lookup.c index 5f5ff81f405..a8ab4db4d0d 100644 --- gcc/cp/name-lookup.c +++ gcc/cp/name-lookup.c @@ -4905,6 +4905,24 @@ handle_namespace_attrs (tree ns, tree attributes) DECL_ATTRIBUTES (ns) = tree_cons (name, args, DECL_ATTRIBUTES (ns)); } + else if (is_attribute_p ("deprecated", name)) + { + if (!DECL_NAME (ns)) + { + warning (OPT_Wattributes, "ignoring %qD attribute on anonymous " + "namespace", name); + continue; + } + if (args && TREE_CODE (TREE_VALUE (args)) != STRING_CST) + { + error ("deprecated message is not a string"); + continue; + } + TREE_DEPRECATED (ns) = 1; + if (args) + DECL_ATTRIBUTES (ns) = tree_cons (name, args, + DECL_ATTRIBUTES (ns)); + } else { warning (OPT_Wattributes, "%qD attribute directive ignored", diff --git gcc/cp/parser.c gcc/cp/parser.c index dbbfe1dbc2f..82d4949b30b 100644 --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -19374,6 +19374,7 @@ cp_parser_namespace_alias_definition (cp_parser* parser) /* Look for the qualified-namespace-specifier. */ namespace_specifier = cp_parser_qualified_namespace_specifier (parser); + cp_warn_deprecated_use_scopes (namespace_specifier); /* Look for the `;' token. */ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); @@ -19488,6 +19489,8 @@ cp_parser_using_declaration (cp_parser* parser, && !TYPE_FUNCTION_SCOPE_P (qscope)) qscope = CP_TYPE_CONTEXT (qscope); + cp_warn_deprecated_use_scopes (qscope); + if (access_declaration_p && cp_parser_error_occurred (parser)) /* Something has already gone wrong; there's no need to parse further. Since an error has occurred, the return value of @@ -19748,6 +19751,7 @@ cp_parser_using_directive (cp_parser* parser) /*is_declaration=*/true); /* Get the namespace being used. */ namespace_decl = cp_parser_namespace_name (parser); + cp_warn_deprecated_use_scopes (namespace_decl); /* And any specified attributes. */ attribs = cp_parser_attributes_opt (parser); diff --git gcc/cp/semantics.c gcc/cp/semantics.c index 7ac1ba058e5..8aec4eff9b3 100644 --- gcc/cp/semantics.c +++ gcc/cp/semantics.c @@ -3811,6 +3811,8 @@ finish_id_expression_1 (tree id_expression, if (TREE_CODE (decl) == FUNCTION_DECL) mark_used (decl); + cp_warn_deprecated_use_scopes (scope); + if (TYPE_P (scope)) decl = finish_qualified_id_expr (scope, decl, diff --git gcc/testsuite/g++.dg/cpp0x/attributes-namespace1.C gcc/testsuite/g++.dg/cpp0x/attributes-namespace1.C new file mode 100644 index 00000000000..d49ebb0b721 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/attributes-namespace1.C @@ -0,0 +1,50 @@ +// PR c++/79817 - attribute deprecated on namespace. +// { dg-do compile { target c++11 } } + +namespace [[deprecated]] ns1 { int i; } +namespace [[deprecated("foo")]] ns2 { int i; } +namespace __attribute__((deprecated)) ns3 { int i; } +namespace __attribute__((deprecated("foo"))) ns4 { int i; } + +namespace [[deprecated]] ns6 +{ + enum E { X }; + void fn(); +} + +namespace [[deprecated]] ns7 +{ + namespace ns8 { + int x; + struct Z { }; + } + struct S { }; +} + +namespace N1 +{ + namespace N2 + { + namespace [[deprecated]] N3 + { + namespace N4 { int x; } + } + } +} + +void +f () +{ + ns1::i = 0; // { dg-warning ".ns1. is deprecated" } + ns2::i = 0; // { dg-warning ".ns2. is deprecated: foo" } + ns3::i = 0; // { dg-warning ".ns3. is deprecated" } + ns4::i = 0; // { dg-warning ".ns4. is deprecated" } + int i = ns1::i; // { dg-warning ".ns1. is deprecated" } + int k = ns6::E::X; // { dg-warning ".ns6. is deprecated" } + ns7::ns8::x = 42; // { dg-warning ".ns7. is deprecated" } + N1::N2::N3::N4::x = 42; // { dg-warning ".N1::N2::N3. is deprecated" } + ns6::fn(); // { dg-warning ".ns6. is deprecated" } + ns7::S s; // { dg-warning ".ns7. is deprecated" } + ns7::S sfn(int); // { dg-warning ".ns7. is deprecated" } + ns7::ns8::Z sfn2(int); // { dg-warning ".ns7. is deprecated" } +} diff --git gcc/testsuite/g++.dg/cpp0x/attributes-namespace2.C gcc/testsuite/g++.dg/cpp0x/attributes-namespace2.C new file mode 100644 index 00000000000..08a043a24e3 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/attributes-namespace2.C @@ -0,0 +1,27 @@ +// PR c++/79817 - attribute deprecated on namespace. +// { dg-do compile { target c++11 } } + +namespace [[deprecated]] { // { dg-warning "ignoring .deprecated. attribute on anonymous namespace" } + int nn; +} + +inline namespace [[deprecated]] I { + int x; +} + +namespace M { + int y; + inline namespace [[deprecated]] N { + int x; + } +} + +void +g () +{ + nn = 42; + I::x = 42; // { dg-warning ".I. is deprecated" } + M::x = 42; + M::y = 42; + M::N::x = 42; // { dg-warning ".M::N. is deprecated" } +} diff --git gcc/testsuite/g++.dg/cpp0x/attributes-namespace3.C gcc/testsuite/g++.dg/cpp0x/attributes-namespace3.C new file mode 100644 index 00000000000..81355ab5677 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/attributes-namespace3.C @@ -0,0 +1,33 @@ +// PR c++/79817 - attribute deprecated on namespace. +// { dg-do compile { target c++11 } } + +namespace [[deprecated]] N +{ + typedef decltype(sizeof(int)) T; + int x; + + namespace N2 { + typedef decltype(sizeof(int)) T; + int y; + } +} + +namespace M { + namespace [[deprecated]] M2 { + typedef decltype(sizeof(int)) T; + int z; + } +} + +void +fn2 () +{ + using N::x; // { dg-warning ".N. is deprecated" } + N::T j; // { dg-warning ".N. is deprecated" } + + using M::M2::z; // { dg-warning ".M::M2. is deprecated" } + M::M2::T l; // { dg-warning ".M::M2. is deprecated" } + + using N::N2::y; // { dg-warning ".N. is deprecated" } + N::N2::T k; // { dg-warning ".N. is deprecated" } +} diff --git gcc/testsuite/g++.dg/cpp0x/attributes-namespace4.C gcc/testsuite/g++.dg/cpp0x/attributes-namespace4.C new file mode 100644 index 00000000000..de0c6df8d9d --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/attributes-namespace4.C @@ -0,0 +1,45 @@ +// PR c++/79817 - attribute deprecated on namespace. +// { dg-do compile { target c++11 } } + +namespace [[deprecated]] N { + struct S { }; + using T = int; + const int value = 42; + int arr[10]; +} + +namespace [[deprecated]] Y { + int x; + int i = x; +} + +namespace [[deprecated]] M { + namespace M2 { + } +} + +enum E { F = N::value }; // { dg-warning ".N. is deprecated" } + +template<N::T> // { dg-warning ".N. is deprecated" } +struct X { }; + +N::T foo(); // { dg-warning ".N. is deprecated" } + +void +g(N::T p) // { dg-warning ".N. is deprecated" } +{ + N::S s; // { dg-warning ".N. is deprecated" } + N::arr[0] = 42; // { dg-warning ".N. is deprecated" } +} + +namespace Z = Y; // { dg-warning ".Y. is deprecated" } +namespace Z2 = M::M2; // { dg-warning ".M. is deprecated" } + +void +g2 () +{ + using namespace Y; // { dg-warning ".Y. is deprecated" } + using namespace M::M2; // { dg-warning ".M. is deprecated" } + using TT = N::T; // { dg-warning ".N. is deprecated" } + using N::T; // { dg-warning ".N. is deprecated" } +} diff --git gcc/testsuite/g++.dg/cpp0x/attributes-namespace5.C gcc/testsuite/g++.dg/cpp0x/attributes-namespace5.C new file mode 100644 index 00000000000..6dbcf326061 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/attributes-namespace5.C @@ -0,0 +1,20 @@ +// PR c++/79817 - attribute deprecated on namespace. +// { dg-do compile { target c++11 } } + +namespace [[deprecated]] Y { + void f(); + void f2(int); + + template<typename> + struct S { + void f3 (); + }; +} + +void Y::f(); +void Y::f() { } +void Y::f2(int); +void Y::f2([[maybe_unused]] int); +void Y::f2(int) { } +template <> void Y::S<int>::f3(); +template <> void Y::S<int>::f3() { } diff --git gcc/testsuite/g++.dg/cpp1z/namespace-attribs.C gcc/testsuite/g++.dg/cpp1z/namespace-attribs.C index dd1855137de..29f8ce472be 100644 --- gcc/testsuite/g++.dg/cpp1z/namespace-attribs.C +++ gcc/testsuite/g++.dg/cpp1z/namespace-attribs.C @@ -3,9 +3,8 @@ namespace A __attribute ((visibility ("default"))) {} -namespace B [[deprecated]] {} // { dg-warning "ignored" } +namespace B [[deprecated]] {} namespace __attribute ((visibility ("default"))) C {} -namespace [[deprecated]] D {} // { dg-warning "ignored" } - +namespace [[deprecated]] D {} diff --git gcc/testsuite/g++.dg/cpp1z/namespace-attribs2.C gcc/testsuite/g++.dg/cpp1z/namespace-attribs2.C index 193dbf6e017..7996b4b680c 100644 --- gcc/testsuite/g++.dg/cpp1z/namespace-attribs2.C +++ gcc/testsuite/g++.dg/cpp1z/namespace-attribs2.C @@ -1,7 +1,6 @@ // { dg-do compile { target c++17 } } // { dg-additional-options "-pedantic" } -namespace B [[deprecated]] {} // { dg-warning "ignored|must precede" } - -namespace [[deprecated]] D {} // { dg-warning "ignored" } +namespace B [[deprecated]] {} // { dg-error "must precede" } +namespace [[deprecated]] D {}