Teach Sema::FindInstantiatedDecl to find instantiated RecordDecls even

when we are not instantiating the corresponding "current
instantiation." This happens, e.g., when we are instantiating a
declaration reference that refers into the "current instantiation" but
occurs in a default function argument. The libstdc++ vector default
constructor now instantiates properly.

llvm-svn: 82069
This commit is contained in:
Douglas Gregor 2009-09-16 18:34:49 +00:00
parent 820640d39f
commit 64621e6eb3
4 changed files with 81 additions and 24 deletions

View File

@ -3103,8 +3103,10 @@ public:
const CXXConstructorDecl *Tmpl,
const MultiLevelTemplateArgumentList &TemplateArgs);
NamedDecl *FindInstantiatedDecl(NamedDecl *D);
DeclContext *FindInstantiatedContext(DeclContext *DC);
NamedDecl *FindInstantiatedDecl(NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs);
DeclContext *FindInstantiatedContext(DeclContext *DC,
const MultiLevelTemplateArgumentList &TemplateArgs);
// Objective-C declarations.
virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,

View File

@ -429,7 +429,7 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) {
"Reducing depth of template template parameters is not yet implemented");
}
return SemaRef.FindInstantiatedDecl(cast<NamedDecl>(D));
return SemaRef.FindInstantiatedDecl(cast<NamedDecl>(D), TemplateArgs);
}
Decl *TemplateInstantiator::TransformDefinition(Decl *D) {
@ -533,7 +533,8 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
if (Arg.getKind() == TemplateArgument::Declaration) {
ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
VD = cast_or_null<ValueDecl>(getSema().FindInstantiatedDecl(VD));
VD = cast_or_null<ValueDecl>(
getSema().FindInstantiatedDecl(VD, TemplateArgs));
if (!VD)
return SemaRef.ExprError();
@ -562,7 +563,7 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
E->getSourceRange().getBegin()));
}
NamedDecl *InstD = SemaRef.FindInstantiatedDecl(D);
NamedDecl *InstD = SemaRef.FindInstantiatedDecl(D, TemplateArgs);
if (!InstD)
return SemaRef.ExprError();

View File

@ -491,7 +491,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
return 0;
// Build the instantiated method declaration.
DeclContext *DC = SemaRef.FindInstantiatedContext(D->getDeclContext());
DeclContext *DC = SemaRef.FindInstantiatedContext(D->getDeclContext(),
TemplateArgs);
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
D->getDeclName(), T, D->getDeclaratorInfo(),
@ -1176,9 +1177,10 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
// Is this an anonymous union?
if (FieldDecl *UnionInit = Init->getAnonUnionMember())
Member = cast<FieldDecl>(FindInstantiatedDecl(UnionInit));
Member = cast<FieldDecl>(FindInstantiatedDecl(UnionInit, TemplateArgs));
else
Member = cast<FieldDecl>(FindInstantiatedDecl(Init->getMember()));
Member = cast<FieldDecl>(FindInstantiatedDecl(Init->getMember(),
TemplateArgs));
NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(),
NewArgs.size(),
@ -1333,9 +1335,10 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx,
/// within the current instantiation.
///
/// \returns NULL if there was an error
DeclContext *Sema::FindInstantiatedContext(DeclContext* DC) {
DeclContext *Sema::FindInstantiatedContext(DeclContext* DC,
const MultiLevelTemplateArgumentList &TemplateArgs) {
if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) {
Decl* ID = FindInstantiatedDecl(D);
Decl* ID = FindInstantiatedDecl(D, TemplateArgs);
return cast_or_null<DeclContext>(ID);
} else return DC;
}
@ -1366,7 +1369,8 @@ DeclContext *Sema::FindInstantiatedContext(DeclContext* DC) {
/// X<T>::<Kind>::KnownValue) to its instantiation
/// (X<int>::<Kind>::KnownValue). InstantiateCurrentDeclRef() performs
/// this mapping from within the instantiation of X<int>.
NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D) {
NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs) {
if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) {
// Transform all of the elements of the overloaded function set.
OverloadedFunctionDecl *Result
@ -1376,7 +1380,8 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D) {
FEnd = Ovl->function_end();
F != FEnd; ++F) {
Result->addOverload(
AnyFunctionDecl::getFromNamedDecl(FindInstantiatedDecl(*F)));
AnyFunctionDecl::getFromNamedDecl(FindInstantiatedDecl(*F,
TemplateArgs)));
}
return Result;
@ -1389,29 +1394,68 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D) {
return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D));
}
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D))
if (ClassTemplateDecl *ClassTemplate
= Record->getDescribedClassTemplate()) {
// When the declaration D was parsed, it referred to the current
// instantiation. Therefore, look through the current context,
// which contains actual instantiations, to find the
// instantiation of the "current instantiation" that D refers
// to. Alternatively, we could just instantiate the
// injected-class-name with the current template arguments, but
// such an instantiation is far more expensive.
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(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.
QualType T;
ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate();
if (ClassTemplate) {
T = ClassTemplate->getInjectedClassNameType(Context);
} else if (ClassTemplatePartialSpecializationDecl *PartialSpec
= 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?
T = SubstType(T, TemplateArgs, SourceLocation(), DeclarationName());
assert(!T.isNull() && "Instantiation of injected-class-name cannot fail.");
if (!T->isDependentType()) {
assert(T->isRecordType() && "Instantiation must produce a record type");
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.
for (DeclContext *DC = CurContext; !DC->isFileContext();
DC = DC->getParent()) {
if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(DC))
if (isInstantiationOf(ClassTemplate, Spec->getSpecializedTemplate()))
if (isInstantiationOf(ClassTemplate,
Spec->getSpecializedTemplate()))
return Spec;
}
assert(false &&
"Unable to find declaration for the current instantiation");
return Record;
}
// Fall through to deal with other dependent record types (e.g.,
// anonymous unions in class templates).
}
ParentDC = FindInstantiatedContext(ParentDC);
if (!ParentDC->isDependentContext())
return D;
ParentDC = FindInstantiatedContext(ParentDC, TemplateArgs);
if (!ParentDC)
return 0;

View File

@ -68,3 +68,13 @@ void test_x0_not_default_constructible(X0<NotDefaultConstructible> xn) {
xn.f(42);
xn.f(); // expected-note{{in instantiation of default function argument}}
}
template<typename T>
struct X1 {
typedef T value_type;
X1(const value_type& value = value_type());
};
void test_X1() {
X1<int> x1;
}