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 {}

Reply via email to