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

View File

@ -131,3 +131,28 @@ namespace N0 {
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);
};
}