Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

A class using-declaration followed by a class definition is not a
redefinition, but a conflict of two different kinds of declaration.

        PR c++/115806

gcc/cp/ChangeLog:

        * decl.cc (lookup_and_check_tag): Strip using here...
        * name-lookup.cc (lookup_elaborated_type): ...not here.

gcc/testsuite/ChangeLog:

        * g++.dg/lookup/using29.C: Adjust diagnostics.
        * g++.dg/lookup/using68.C: Likewise.
        * g++.dg/modules/using-19_b.C: Likewise.
        * g++.dg/lookup/using53.C: Remove xfails.
---
 gcc/cp/decl.cc                            | 14 ++++++++++++++
 gcc/cp/name-lookup.cc                     | 12 ++++++------
 gcc/testsuite/g++.dg/lookup/using29.C     |  4 ++--
 gcc/testsuite/g++.dg/lookup/using53.C     | 18 ++++++++----------
 gcc/testsuite/g++.dg/lookup/using68.C     |  6 +++---
 gcc/testsuite/g++.dg/modules/using-19_b.C |  4 ++--
 6 files changed, 35 insertions(+), 23 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 067ae20c828..24c5f0337b9 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -18490,6 +18490,20 @@ lookup_and_check_tag (enum tag_types tag_code, tree 
name,
       || (how != TAG_how::CURRENT_ONLY && DECL_TEMPLATE_TEMPLATE_PARM_P 
(decl)))
     decl = DECL_TEMPLATE_RESULT (decl);
 
+  if (TREE_CODE (decl) == USING_DECL)
+    {
+      tree u = decl;
+      decl = strip_using_decl (decl);
+      if (how == TAG_how::CURRENT_ONLY)
+       {
+         auto_diagnostic_group _;
+         error ("%qD conflicts with a previous declaration", name);
+         inform (location_of (u), "previous declaration %qD", u);
+         inform (location_of (decl), "%qD declared here", decl);
+         return error_mark_node;
+       }
+    }
+
   if (TREE_CODE (decl) != TYPE_DECL)
     /* Found not-a-type.  */
     return NULL_TREE;
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index f89f5643d86..183ea403ef8 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -8492,7 +8492,7 @@ lookup_elaborated_type (tree name, TAG_how how)
             typedef struct C {} C;
           correctly.  */
 
-       if (tree type = strip_using_decl (iter->type))
+       if (tree type = iter->type)
          {
            if (qualify_lookup (type, LOOK_want::TYPE)
                && (how != TAG_how::CURRENT_ONLY
@@ -8508,7 +8508,7 @@ lookup_elaborated_type (tree name, TAG_how how)
          }
        else
          {
-           tree value = strip_using_decl (iter->value);
+           tree value = iter->value;
            if (qualify_lookup (value, LOOK_want::TYPE)
                && (how != TAG_how::CURRENT_ONLY
                    || !INHERITED_VALUE_BINDING_P (iter)))
@@ -8548,7 +8548,7 @@ lookup_elaborated_type (tree name, TAG_how how)
       if (bind)
        {
          /* If this is the kind of thing we're looking for, we're done.  */
-         if (tree type = strip_using_decl (MAYBE_STAT_TYPE (bind)))
+         if (tree type = MAYBE_STAT_TYPE (bind))
            {
              if (how != TAG_how::HIDDEN_FRIEND)
                /* No longer hidden.  */
@@ -8556,7 +8556,7 @@ lookup_elaborated_type (tree name, TAG_how how)
 
              return type;
            }
-         else if (tree decl = strip_using_decl (MAYBE_STAT_DECL (bind)))
+         else if (tree decl = MAYBE_STAT_DECL (bind))
            {
              if (qualify_lookup (decl, LOOK_want::TYPE))
                {
@@ -8637,10 +8637,10 @@ lookup_elaborated_type (tree name, TAG_how how)
                  }
 
                if (type && qualify_lookup (type, LOOK_want::TYPE))
-                 return strip_using_decl (type);
+                 return type;
 
                if (bind && qualify_lookup (bind, LOOK_want::TYPE))
-                 return strip_using_decl (bind);
+                 return bind;
              }
 
          if (!module_purview_p ())
diff --git a/gcc/testsuite/g++.dg/lookup/using29.C 
b/gcc/testsuite/g++.dg/lookup/using29.C
index 697a654aacb..e11f39c5840 100644
--- a/gcc/testsuite/g++.dg/lookup/using29.C
+++ b/gcc/testsuite/g++.dg/lookup/using29.C
@@ -51,7 +51,7 @@ struct I2 : H
 
 struct J
 {
-  struct type {}; // { dg-message "previous" }
+  struct type {}; // { dg-message "here" }
 };
 
 struct K : J
@@ -63,7 +63,7 @@ struct K : J
 struct L : J
 {
   using J::type;
-  struct type {}; // { dg-error "redefinition" }
+  struct type {}; // { dg-error "conflicts" }
 };
 
 struct M
diff --git a/gcc/testsuite/g++.dg/lookup/using53.C 
b/gcc/testsuite/g++.dg/lookup/using53.C
index 8279c73bfc4..e6a82243715 100644
--- a/gcc/testsuite/g++.dg/lookup/using53.C
+++ b/gcc/testsuite/g++.dg/lookup/using53.C
@@ -1,23 +1,21 @@
 // PR c++/20420
-// FIXME: These error messages aren't great, rather than multiple definition
-// we should talk about conflicting declarations with the using-decl.
 
 class B
 {
 protected:
-  enum E { E1, E2, E3 };     // { dg-message "previous" }
-  struct S { int i; E e; };  // { dg-message "previous" }
+  enum E { E1, E2, E3 };     // { dg-message "here" }
+  struct S { int i; E e; };  // { dg-message "here" }
 };
 
 class D : private B
 {
 public:
-  using B::E;
-  using B::S;
+  using B::E;                  // { dg-message "previous" }
+  using B::S;                  // { dg-message "previous" }
 
 private:
-  enum E {};        // { dg-error "multiple definition" }
-  struct S {};      // { dg-error "redefinition" }
+  enum E {};        // { dg-error "conflicts" }
+  struct S {};      // { dg-error "conflicts" }
 };
 
 template<typename T>
@@ -32,11 +30,11 @@ template<typename T>
 class DT : private BT<T>
 {
 public:
-  using BT<T>::E;   // { dg-message "previous" "PR c++/115806" { xfail *-*-* } 
}
+  using BT<T>::E;   // { dg-message "previous" }
   using BT<T>::S;   // { dg-message "previous" }
 
 private:
-  enum E {};        // { dg-error "conflicts" "PR c++/115806" { xfail *-*-* } }
+  enum E {};        // { dg-error "conflicts" }
   struct S {};      // { dg-error "conflicts" }
 };
 
diff --git a/gcc/testsuite/g++.dg/lookup/using68.C 
b/gcc/testsuite/g++.dg/lookup/using68.C
index 6eb2be5c19c..aa9cdea1d15 100644
--- a/gcc/testsuite/g++.dg/lookup/using68.C
+++ b/gcc/testsuite/g++.dg/lookup/using68.C
@@ -1,7 +1,7 @@
 // { dg-do compile }
 
-struct S {}; // { dg-message "previous" }
+struct S {}; // { dg-message "here" }
 void foo() {
-  using ::S;
-  struct S {};  // { dg-error "redefinition" }
+  using ::S; // { dg-message "previous" }
+  struct S {};  // { dg-error "conflicts" }
 }
diff --git a/gcc/testsuite/g++.dg/modules/using-19_b.C 
b/gcc/testsuite/g++.dg/modules/using-19_b.C
index dbe8d9f3c01..9f738d0310a 100644
--- a/gcc/testsuite/g++.dg/modules/using-19_b.C
+++ b/gcc/testsuite/g++.dg/modules/using-19_b.C
@@ -3,8 +3,8 @@
 import M;
 
 namespace exposed {
-  struct S {};  // { dg-error "redefinition" }
-  enum E { x };  // { dg-error "multiple definition" }
+  struct S {};  // { dg-error "conflicts" }
+  enum E { x };  // { dg-error "conflicts" }
   int e();  // { dg-error "redeclared" }
   int f;  // { dg-error "redeclared" }
 }

base-commit: f73ad52c42f610dea1027342134d7ba624a291f9
-- 
2.55.0

Reply via email to