Implement C++ [temp.local]p4, which specifies how we eliminate

name-lookup ambiguities when there are multiple base classes that are
all specializations of the same class template. This is part of a
general cleanup for ambiguities in template-name lookup. Fixes
PR6717.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101065 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2010-04-12 20:54:26 +00:00
Родитель ec55c941f2
Коммит 01e56aecb7
4 изменённых файлов: 64 добавлений и 10 удалений

Просмотреть файл

@ -343,6 +343,11 @@ public:
} else {
ResultKind = Found;
resolveKind();
if (Paths && (ResultKind != Ambiguous)) {
deletePaths(Paths);
Paths = 0;
}
}
}

Просмотреть файл

@ -2454,7 +2454,8 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType,
}
}
assert(BaseType->isDependentType() || Name.isDependentName());
assert(BaseType->isDependentType() || Name.isDependentName() ||
isDependentScopeSpecifier(SS));
// Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
// must have pointer type, and the accessed type is the pointee.
@ -3200,7 +3201,8 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
Expr *Base = BaseArg.takeAs<Expr>();
OwningExprResult Result(*this);
if (Base->getType()->isDependentType() || Name.isDependentName()) {
if (Base->getType()->isDependentType() || Name.isDependentName() ||
isDependentScopeSpecifier(SS)) {
Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(),
IsArrow, OpLoc,
SS, FirstQualifierInScope,

Просмотреть файл

@ -63,14 +63,34 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) {
}
static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) {
// The set of class templates we've already seen.
llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates;
LookupResult::Filter filter = R.makeFilter();
while (filter.hasNext()) {
NamedDecl *Orig = filter.next();
NamedDecl *Repl = isAcceptableTemplateName(C, Orig->getUnderlyingDecl());
if (!Repl)
filter.erase();
else if (Repl != Orig)
else if (Repl != Orig) {
// C++ [temp.local]p3:
// A lookup that finds an injected-class-name (10.2) can result in an
// ambiguity in certain cases (for example, if it is found in more than
// one base class). If all of the injected-class-names that are found
// refer to specializations of the same class template, and if the name
// is followed by a template-argument-list, the reference refers to the
// class template itself and not a specialization thereof, and is not
// ambiguous.
//
// FIXME: Will we eventually have to do the same for alias templates?
if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl))
if (!ClassTemplates.insert(ClassTmpl)) {
filter.erase();
continue;
}
filter.replace(Repl);
}
}
filter.done();
}
@ -109,7 +129,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
LookupOrdinaryName);
R.suppressDiagnostics();
LookupTemplateName(R, S, SS, ObjectType, EnteringContext);
if (R.empty())
if (R.empty() || R.isAmbiguous())
return TNK_Non_template;
TemplateName Template;
@ -227,10 +247,6 @@ void Sema::LookupTemplateName(LookupResult &Found,
LookupName(Found, S);
}
// FIXME: Cope with ambiguous name-lookup results.
assert(!Found.isAmbiguous() &&
"Cannot handle template name-lookup ambiguities");
if (Found.empty() && !isDependent) {
// If we did not find any names, attempt to correct any typos.
DeclarationName Name = Found.getLookupName();
@ -271,8 +287,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
LookupOrdinaryName);
LookupName(FoundOuter, S);
FilterAcceptableTemplateNames(Context, FoundOuter);
// FIXME: Handle ambiguities in this lookup better
if (FoundOuter.empty()) {
// - if the name is not found, the name found in the class of the
// object expression is used, otherwise

Просмотреть файл

@ -0,0 +1,32 @@
// RUN: %clang_cc1 -verify %s
template <class T> struct Base { // expected-note 4 {{member found by ambiguous name lookup}}
static void f();
};
struct X0 { };
template <class T> struct Derived: Base<int>, Base<char> {
typename Derived::Base b; // expected-error{{member 'Base' found in multiple base classes of different types}}
typename Derived::Base<double> d; // OK
void g(X0 *t) {
t->Derived::Base<T>::f();
t->Base<T>::f();
t->Base::f(); // expected-error{{member 'Base' found in multiple base classes of different types}} \
// expected-error{{no member named 'f' in 'X0'}} \
// expected-error{{expected a class or namespace}}
}
};
namespace PR6717 {
template <typename T>
class WebVector {
}
WebVector(const WebVector<T>& other) { }
template <typename C>
WebVector<T>& operator=(const C& other) { } // expected-error{{unknown type name 'WebVector'}} \
// expected-error{{unqualified-id}}
}