https://gcc.gnu.org/g:fa56ffaf81b9417d6f302f9b21bb5ea9da77ca06
commit r17-4946-gfa56ffaf81b9417d6f302f9b21bb5ea9da77ca06 Author: Jason Merrill <[email protected]> Date: Fri Sep 11 00:45:03 2026 -0400 c++: class conflict with using-decl [PR115806] 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. Diff: --- 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 067ae20c828e..24c5f0337b9c 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 f89f5643d86c..183ea403ef8c 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 697a654aacb5..e11f39c58403 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 8279c73bfc4f..e6a82243715d 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 6eb2be5c19ca..aa9cdea1d157 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 dbe8d9f3c01e..9f738d0310a4 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" } }
