Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit a7d7e42

Browse files
committed
PR40329: [adl] Fix determination of associated classes when searching a
member enum and then its enclosing class. There are situations where ADL will collect a class but not the complete set of associated classes / namespaces of that class. When that happened, and we later tried to collect those associated classes / namespaces, we would previously short-circuit the lookup and not find them. Eg, for: struct A : B { enum E; }; if we first looked for associated classes/namespaces of A::E, we'd find only A. But if we then tried to also collect associated classes/namespaces of A (which should include the base class B), we would not add B because we had already visited A. This also fixes a minor issue where we would fail to collect associated classes from an overloaded class member access expression naming a static member function. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@351382 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 6b961fe commit a7d7e42

File tree

3 files changed

+66
-18
lines changed

3 files changed

+66
-18
lines changed

lib/Sema/SemaLookup.cpp

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2417,10 +2417,18 @@ namespace {
24172417
InstantiationLoc(InstantiationLoc) {
24182418
}
24192419

2420+
bool addClassTransitive(CXXRecordDecl *RD) {
2421+
Classes.insert(RD);
2422+
return ClassesTransitive.insert(RD);
2423+
}
2424+
24202425
Sema &S;
24212426
Sema::AssociatedNamespaceSet &Namespaces;
24222427
Sema::AssociatedClassSet &Classes;
24232428
SourceLocation InstantiationLoc;
2429+
2430+
private:
2431+
Sema::AssociatedClassSet ClassesTransitive;
24242432
};
24252433
} // end anonymous namespace
24262434

@@ -2521,15 +2529,6 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
25212529
// Add the associated namespace for this class.
25222530
CollectEnclosingNamespace(Result.Namespaces, Ctx);
25232531

2524-
// Add the class itself. If we've already seen this class, we don't
2525-
// need to visit base classes.
2526-
//
2527-
// FIXME: That's not correct, we may have added this class only because it
2528-
// was the enclosing class of another class, and in that case we won't have
2529-
// added its base classes yet.
2530-
if (!Result.Classes.insert(Class))
2531-
return;
2532-
25332532
// -- If T is a template-id, its associated namespaces and classes are
25342533
// the namespace in which the template is defined; for member
25352534
// templates, the member template's class; the namespaces and classes
@@ -2552,6 +2551,11 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
25522551
addAssociatedClassesAndNamespaces(Result, TemplateArgs[I]);
25532552
}
25542553

2554+
// Add the class itself. If we've already transitively visited this class,
2555+
// we don't need to visit base classes.
2556+
if (!Result.addClassTransitive(Class))
2557+
return;
2558+
25552559
// Only recurse into base classes for complete types.
25562560
if (!Result.S.isCompleteType(Result.InstantiationLoc,
25572561
Result.S.Context.getRecordType(Class)))
@@ -2577,7 +2581,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
25772581
if (!BaseType)
25782582
continue;
25792583
CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl());
2580-
if (Result.Classes.insert(BaseDecl)) {
2584+
if (Result.addClassTransitive(BaseDecl)) {
25812585
// Find the associated namespace for this base class.
25822586
DeclContext *BaseCtx = BaseDecl->getDeclContext();
25832587
CollectEnclosingNamespace(Result.Namespaces, BaseCtx);
@@ -2793,15 +2797,9 @@ void Sema::FindAssociatedClassesAndNamespaces(
27932797
// in which the function or function template is defined and the
27942798
// classes and namespaces associated with its (non-dependent)
27952799
// parameter types and return type.
2796-
Arg = Arg->IgnoreParens();
2797-
if (UnaryOperator *unaryOp = dyn_cast<UnaryOperator>(Arg))
2798-
if (unaryOp->getOpcode() == UO_AddrOf)
2799-
Arg = unaryOp->getSubExpr();
2800-
2801-
UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Arg);
2802-
if (!ULE) continue;
2800+
OverloadExpr *OE = OverloadExpr::find(Arg).Expression;
28032801

2804-
for (const auto *D : ULE->decls()) {
2802+
for (const NamedDecl *D : OE->decls()) {
28052803
// Look through any using declarations to find the underlying function.
28062804
const FunctionDecl *FDecl = D->getUnderlyingDecl()->getAsFunction();
28072805

test/CXX/drs/dr0xx.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,36 @@ namespace dr33 { // dr33: yes
413413
void g(X::S);
414414
template<typename Z> Z g(Y::T);
415415
void h() { f(&g); } // expected-error {{ambiguous}}
416+
417+
template<typename T> void t(X::S);
418+
template<typename T, typename U = void> void u(X::S); // expected-error 0-1{{default template argument}}
419+
void templ() { f(t<int>); f(u<int>); }
420+
421+
// Even though v<int> cannot select the first overload, ADL considers it
422+
// and adds namespace Z to the set of associated namespaces, and then picks
423+
// Z::f even though that function has nothing to do with any associated type.
424+
namespace Z { struct Q; void f(void(*)()); }
425+
template<int> Z::Q v();
426+
template<typename> void v();
427+
void unrelated_templ() { f(v<int>); }
428+
429+
namespace dependent {
430+
struct X {};
431+
template<class T> struct Y {
432+
friend int operator+(X, void(*)(Y)) {}
433+
};
434+
435+
template<typename T> void f(Y<T>);
436+
int use = X() + f<int>; // expected-error {{invalid operands}}
437+
}
438+
439+
namespace member {
440+
struct Q {};
441+
struct Y { friend int operator+(Q, Y (*)()); };
442+
struct X { template<typename> static Y f(); };
443+
int m = Q() + X().f<int>; // ok
444+
int n = Q() + (&(X().f<int>)); // ok
445+
}
416446
}
417447

418448
// dr34: na

test/SemaCXX/adl.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %clang_cc1 -std=c++11 -verify %s
2+
3+
namespace PR40329 {
4+
struct A {
5+
A(int);
6+
friend int operator->*(A, A);
7+
};
8+
struct B : A {
9+
B();
10+
enum E { e };
11+
};
12+
// Associated classes for B are {B, A}
13+
// Associated classes for B::E are {B} (non-transitive in this case)
14+
//
15+
// If we search B::E first, we must not mark B "visited" and shortcircuit
16+
// visiting it later, or we won't find the associated class A.
17+
int k0 = B::e ->* B::e; // expected-error {{non-pointer-to-member type}}
18+
int k1 = B::e ->* B();
19+
int k2 = B() ->* B::e;
20+
}

0 commit comments

Comments
 (0)