On Thu, Aug 22, 2019 at 11:49:49AM -0700, Jason Merrill wrote: > On Thu, Aug 22, 2019 at 11:01 AM Nathan Sidwell <nat...@acm.org> wrote: > > > > On 8/20/19 9:03 PM, Marek Polacek wrote: > > > > > 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. > > > > > > > > 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)); > > > > CP_DECL_CONTEXT would be clearer, here and elsewhere.
Oh right, I failed to adjust that. Fixed now. > > > /* 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) > > > > Do we need to walk non-namespace scopes here? can we just bail if NS is > > not a namespace? if can legitimately not be a namespace, calling it NS > > is confusing :) > > It seems like it can be a class in some cases, and I would want to > warn about deprecated classes named in a nested-name-specifier. Did > we not already warn about that? I know of at least this case: namespace N { enum [[deprecated]] E { X }; } int i = N::E::X; we didn't warn about the deprecated 'E' but with this patch we do. > I agree that the parameter name is confusing. True, I didn't realize. Fixed now. > > > +{ > > > + while (ns > > > + && ns != error_mark_node > > > + && ns != global_namespace) > > > + { > > > + cp_warn_deprecated_use (ns); > > > + if (TYPE_P (ns)) > > ... and does this ever trigger? Yeah, it can, see the testcase above. > > > + ns = CP_TYPE_CONTEXT (ns); > > > + else > > > + ns = CP_DECL_CONTEXT (ns); > > > + } > > > +} > > > > I always worry about such recursive lookups. NAMESPACE_DECL has so many > > spare flags, could we take one to say 'is, or contained in, deprecated', > > and thus know whether we can bail early. And stop at the first > > deprecated one -- though not sure why someone would deprecate more than > > one namespace in a nest. thoughts? Well, this patch uses the TREE_DEPRECATED bit for a NAMESPACE_DECL. I'm not exactly sure how another bit would help us, where I would set it (I guess the innermost scope, but that doesn't have to be a NAMESPACE_DECL), and how that would play with diagnostics -- i.e. if we'd print the correct name. > I can imagine deprecating an inner namespace and later deprecating an > outer namespace, but I don't think it's important to warn about more > than one in that case. Agreed, and to that effect I tweaked cp_warn_deprecated_use_scopes to return if cp_warn_deprecated_use issued a warning. Thank you both! Bootstrapped/regtested on x86_64-linux, ok for trunk? 2019-08-23 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 88aa69ce5de..cb5571e4f24 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 (CP_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 (CP_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..aca37a28f49 100644 --- gcc/cp/decl2.c +++ gcc/cp/decl2.c @@ -5407,6 +5407,24 @@ 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 scope) +{ + while (scope + && scope != error_mark_node + && scope != global_namespace) + { + if (cp_warn_deprecated_use (scope)) + return; + if (TYPE_P (scope)) + scope = CP_TYPE_CONTEXT (scope); + else + scope = CP_DECL_CONTEXT (scope); + } +} + /* 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 504f77a4908..53514787554 100644 --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -19378,6 +19378,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); @@ -19492,6 +19493,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 @@ -19752,6 +19755,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 {}