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 <jason@redhat.com>
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;
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;
--- /dev/null
+// 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" }
+ }
+};
--- /dev/null
+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>;