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:
parent
820640d39f
commit
64621e6eb3
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue