https://gcc.gnu.org/g:57904dc27d5b27226912838cdd6b5272cec4d050
commit r15-6737-g57904dc27d5b27226912838cdd6b5272cec4d050 Author: Patrick Palka <ppa...@redhat.com> Date: Thu Jan 9 10:50:06 2025 -0500 c++: current inst w/ indirect dependent bases [PR117993] In the first testcase we're overeagerly diagnosing qualified name lookup failure for f from the current instantiation B<T>::C ahead of time because we (correctly) deem C to not have any direct dependent bases: its direct base B<T> is part of the current instantiation and therefore not a dependent base, and we decide it's safe to diagnose name lookup failure ahead of time. But this testcase demonstrates it's not enough to consider only direct dependent bases: f is defined in A<T> which is a dependent base of B<T>, so qualified name lookup from C won't search it ahead of time and in turn won't be exhaustive, and so it's wrong to diagnose lookup failure ahead of time. This ultimately suggests that any_dependent_bases_p needs to consider indirect bases as well. To that end it seems sufficient to make the predicate recurse into any !BINFO_DEPENDENT_BASE_P base since the recursive call will exit early for non-dependent types. So effectively we'll only recurse into bases belonging to the current instantiation. I considered more narrowly making only dependentish_scope_p consider indirect dependent bases, but it seems other any_dependent_bases_p callers also want this behavior, e.g. build_new_method_call for benefit of the second testcase (which is an even older regression since GCC 7). PR c++/117993 gcc/cp/ChangeLog: * search.cc (any_dependent_bases_p): Recurse into bases (of dependent type) that are not BINFO_DEPENDENT_BASE_P. Document default argument. gcc/testsuite/ChangeLog: * g++.dg/template/dependent-base4.C: New test. * g++.dg/template/dependent-base5.C: New test. Reviewed-by: Jason Merrill <ja...@redhat.com> Diff: --- gcc/cp/search.cc | 7 +++++-- gcc/testsuite/g++.dg/template/dependent-base4.C | 23 +++++++++++++++++++++++ gcc/testsuite/g++.dg/template/dependent-base5.C | 22 ++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc index af6c892d702d..cea9f7c689ba 100644 --- a/gcc/cp/search.cc +++ b/gcc/cp/search.cc @@ -2843,7 +2843,7 @@ original_binfo (tree binfo, tree here) TYPE). */ bool -any_dependent_bases_p (tree type) +any_dependent_bases_p (tree type /* = current_nonlambda_class_type () */) { if (!type || !CLASS_TYPE_P (type) || !uses_template_parms (type)) return false; @@ -2858,7 +2858,10 @@ any_dependent_bases_p (tree type) unsigned i; tree base_binfo; FOR_EACH_VEC_SAFE_ELT (BINFO_BASE_BINFOS (TYPE_BINFO (type)), i, base_binfo) - if (BINFO_DEPENDENT_BASE_P (base_binfo)) + if (BINFO_DEPENDENT_BASE_P (base_binfo) + /* Recurse to also consider possibly dependent bases of a base that + is part of the current instantiation. */ + || any_dependent_bases_p (BINFO_TYPE (base_binfo))) return true; return false; diff --git a/gcc/testsuite/g++.dg/template/dependent-base4.C b/gcc/testsuite/g++.dg/template/dependent-base4.C new file mode 100644 index 000000000000..84e53b5f3fb7 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/dependent-base4.C @@ -0,0 +1,23 @@ +// PR c++/117993 + +template<class T> +struct A { + void f(); + typedef void type; +}; + +template<class T> +struct B : A<T> { + template<class U> struct C; +}; + +template<class T> +template<class U> +struct B<T>::C : B { + void g(C& c) { + this->f(); // { dg-bogus "member" } + c.f(); // { dg-bogus "member" } + C::f(); // { dg-bogus "member" } + typename C::type* p; // { dg-bogus "not name a type" } + } +}; diff --git a/gcc/testsuite/g++.dg/template/dependent-base5.C b/gcc/testsuite/g++.dg/template/dependent-base5.C new file mode 100644 index 000000000000..2e9cdaa242bc --- /dev/null +++ b/gcc/testsuite/g++.dg/template/dependent-base5.C @@ -0,0 +1,22 @@ +template<class T> +struct A { }; + +template<class T> +struct B : A<T> { + template<class U> struct C; +}; + +struct D { void f(); }; + +template<class T> +template<class U> +struct B<T>::C : B { + void g() { + D::f(); // { dg-bogus "without object" } + } +}; + +template<> +struct A<int> : D { }; + +template struct B<int>::C<int>;