Cope with finding the "instantiated" declaration when we are

type-checking within a template definition. In this case, the
"instantiated" declaration is just the declaration itself, found
within the current instantiation. Fixes PR6239.

llvm-svn: 95442
This commit is contained in:
Douglas Gregor 2010-02-05 22:40:03 +00:00
parent 175629608e
commit d225fa05bd
2 changed files with 61 additions and 21 deletions

View File

@ -2170,10 +2170,11 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
if (!Record->isDependentContext()) if (!Record->isDependentContext())
return D; return D;
// If the RecordDecl is actually the injected-class-name or a "templated" // If the RecordDecl is actually the injected-class-name or a
// declaration for a class template or class template partial // "templated" declaration for a class template, class template
// specialization, substitute into the injected-class-name of the // partial specialization, or a member class of a class template,
// class template or partial specialization to find the new DeclContext. // substitute into the injected-class-name of the class template
// or partial specialization to find the new DeclContext.
QualType T; QualType T;
ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate(); ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate();
@ -2183,15 +2184,18 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
= dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) { = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) {
T = Context.getTypeDeclType(Record); T = Context.getTypeDeclType(Record);
ClassTemplate = PartialSpec->getSpecializedTemplate(); ClassTemplate = PartialSpec->getSpecializedTemplate();
} }
if (!T.isNull()) { if (!T.isNull()) {
// Substitute into the injected-class-name to get the type corresponding // Substitute into the injected-class-name to get the type
// to the instantiation we want. This substitution should never fail, // corresponding to the instantiation we want, which may also be
// since we know we can instantiate the injected-class-name or we wouldn't // the current instantiation (if we're in a template
// have gotten to the injected-class-name! // definition). This substitution should never fail, since we
// FIXME: Can we use the CurrentInstantiationScope to avoid this extra // know we can instantiate the injected-class-name or we
// instantiation in the common case? // wouldn't have gotten to the injected-class-name!
// FIXME: Can we use the CurrentInstantiationScope to avoid this
// extra instantiation in the common case?
T = SubstType(T, TemplateArgs, SourceLocation(), DeclarationName()); T = SubstType(T, TemplateArgs, SourceLocation(), DeclarationName());
assert(!T.isNull() && "Instantiation of injected-class-name cannot fail."); assert(!T.isNull() && "Instantiation of injected-class-name cannot fail.");
@ -2200,26 +2204,37 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
return T->getAs<RecordType>()->getDecl(); return T->getAs<RecordType>()->getDecl();
} }
// We are performing "partial" template instantiation to create the // We are performing "partial" template instantiation to create
// member declarations for the members of a class template // the member declarations for the members of a class template
// specialization. Therefore, D is actually referring to something in // specialization. Therefore, D is actually referring to something
// the current instantiation. Look through the current context, // in the current instantiation. Look through the current
// which contains actual instantiations, to find the instantiation of // context, which contains actual instantiations, to find the
// the "current instantiation" that D refers to. // instantiation of the "current instantiation" that D refers
// to.
bool SawNonDependentContext = false;
for (DeclContext *DC = CurContext; !DC->isFileContext(); for (DeclContext *DC = CurContext; !DC->isFileContext();
DC = DC->getParent()) { DC = DC->getParent()) {
if (ClassTemplateSpecializationDecl *Spec if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(DC)) = dyn_cast<ClassTemplateSpecializationDecl>(DC))
if (isInstantiationOf(ClassTemplate, if (isInstantiationOf(ClassTemplate,
Spec->getSpecializedTemplate())) Spec->getSpecializedTemplate()))
return Spec; return Spec;
if (!DC->isDependentContext())
SawNonDependentContext = true;
} }
assert(false && // We're performing "instantiation" of a member of the current
// instantiation while we are type-checking the
// definition. Compute the declaration context and return that.
assert(!SawNonDependentContext &&
"No dependent context while instantiating record");
DeclContext *DC = computeDeclContext(T);
assert(DC &&
"Unable to find declaration for the current instantiation"); "Unable to find declaration for the current instantiation");
return Record; return cast<CXXRecordDecl>(DC);
} }
// Fall through to deal with other dependent record types (e.g., // Fall through to deal with other dependent record types (e.g.,
// anonymous unions in class templates). // anonymous unions in class templates).
} }

View File

@ -131,3 +131,28 @@ namespace N0 {
x1.f(x0l); x1.f(x0l);
} }
} }
namespace PR6239 {
template <typename T>
struct X0 {
class type {
typedef T E;
template <E e> // subsitute T for E and bug goes away
struct sfinae { };
template <class U>
typename sfinae<&U::operator=>::type test(int);
};
};
template <typename T>
struct X1 {
typedef T E;
template <E e> // subsitute T for E and bug goes away
struct sfinae { };
template <class U>
typename sfinae<&U::operator=>::type test(int);
};
}