Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk? The older regression does not seem worth fixing.
-- >8 -- 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 only base is B<T> which 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 won't search it ahead of time and in turn name lookup 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. It seems sufficient to 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 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. --- gcc/cp/search.cc | 5 ++-- .../g++.dg/template/dependent-base4.C | 23 +++++++++++++++++++ .../g++.dg/template/dependent-base5.C | 22 ++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/dependent-base4.C create mode 100644 gcc/testsuite/g++.dg/template/dependent-base5.C diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc index d438e18b74b..8a65dd3b68e 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,8 @@ 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) + || 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 00000000000..84e53b5f3fb --- /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 00000000000..2e9cdaa242b --- /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>; -- 2.47.1.440.gcaacdb5dfd