Implement template instantiation for member class templates.

When performing template instantiation of the definitions of member
templates (or members thereof),  we build a data structure containing
the template arguments from each "level" of template
instantiation. During template instantiation, we substitute all levels
of template arguments simultaneously. 

llvm-svn: 80389
This commit is contained in:
Douglas Gregor 2009-08-28 20:31:08 +00:00
parent d65d22a0c5
commit 01afeeff1d
7 changed files with 161 additions and 135 deletions

View File

@ -2903,29 +2903,28 @@ public:
void PerformPendingImplicitInstantiations();
QualType SubstType(QualType T, const TemplateArgumentList &TemplateArgs,
QualType SubstType(QualType T,
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc, DeclarationName Entity);
OwningExprResult SubstExpr(Expr *E, const TemplateArgumentList &TemplateArgs);
OwningExprResult SubstExpr(Expr *E,
const MultiLevelTemplateArgumentList &TemplateArgs);
OwningStmtResult SubstStmt(Stmt *S, const TemplateArgumentList &TemplateArgs);
OwningStmtResult SubstStmt(Stmt *S,
const MultiLevelTemplateArgumentList &TemplateArgs);
Decl *SubstDecl(Decl *D, DeclContext *Owner,
const TemplateArgumentList &TemplateArgs);
const MultiLevelTemplateArgumentList &TemplateArgs);
bool
SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
CXXRecordDecl *Pattern,
const TemplateArgumentList &TemplateArgs);
bool
InstantiateTemplatePattern(SourceLocation PointOfInstantiation,
CXXRecordDecl *Pattern);
const MultiLevelTemplateArgumentList &TemplateArgs);
bool
InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
const TemplateArgumentList &TemplateArgs,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool ExplicitInstantiation,
bool Complain = true);
@ -2936,7 +2935,7 @@ public:
void InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation,
const TemplateArgumentList &TemplateArgs);
const MultiLevelTemplateArgumentList &TemplateArgs);
void InstantiateClassTemplateSpecializationMembers(
SourceLocation PointOfInstantiation,
@ -2945,13 +2944,13 @@ public:
NestedNameSpecifier *
SubstNestedNameSpecifier(NestedNameSpecifier *NNS,
SourceRange Range,
const TemplateArgumentList &TemplateArgs);
const MultiLevelTemplateArgumentList &TemplateArgs);
TemplateName
SubstTemplateName(TemplateName Name, SourceLocation Loc,
const TemplateArgumentList &TemplateArgs);
const MultiLevelTemplateArgumentList &TemplateArgs);
TemplateArgument Subst(TemplateArgument Arg,
const TemplateArgumentList &TemplateArgs);
const MultiLevelTemplateArgumentList &TemplateArgs);
void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function,

View File

@ -2473,14 +2473,14 @@ Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
Expr *UninstExpr = Param->getUninstantiatedDefaultArg();
// Instantiate the expression.
const TemplateArgumentList &ArgList = getTemplateInstantiationArgs(FD);
MultiLevelTemplateArgumentList ArgList = getTemplateInstantiationArgs(FD);
// FIXME: We should really make a new InstantiatingTemplate ctor
// that has a better message - right now we're just piggy-backing
// off the "default template argument" error message.
InstantiatingTemplate Inst(*this, CallLoc, FD->getPrimaryTemplate(),
ArgList.getFlatArgumentList(),
ArgList.flat_size());
ArgList.getInnermost().getFlatArgumentList(),
ArgList.getInnermost().flat_size());
OwningExprResult Result = SubstExpr(UninstExpr, ArgList);
if (Result.isInvalid())

View File

@ -1243,7 +1243,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
TemplateArgumentList TemplateArgs(Context, Converted,
/*TakeArgs=*/false);
ArgType = SubstType(ArgType, TemplateArgs,
ArgType = SubstType(ArgType,
MultiLevelTemplateArgumentList(TemplateArgs),
TTP->getDefaultArgumentLoc(),
TTP->getDeclName());
}
@ -1265,8 +1266,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
TemplateArgumentList TemplateArgs(Context, Converted,
/*TakeArgs=*/false);
Sema::OwningExprResult E = SubstExpr(NTTP->getDefaultArgument(),
TemplateArgs);
Sema::OwningExprResult E
= SubstExpr(NTTP->getDefaultArgument(),
MultiLevelTemplateArgumentList(TemplateArgs));
if (E.isInvalid())
return true;

View File

@ -46,8 +46,8 @@ namespace clang {
MultiLevelTemplateArgumentList() { }
/// \brief Construct a single-level template argument list.
MultiLevelTemplateArgumentList(const TemplateArgumentList *TemplateArgs) {
TemplateArgumentLists.push_back(TemplateArgs);
MultiLevelTemplateArgumentList(const TemplateArgumentList &TemplateArgs) {
TemplateArgumentLists.push_back(&TemplateArgs);
}
/// \brief Determine the number of levels in this template argument
@ -57,8 +57,21 @@ namespace clang {
/// \brief Retrieve the template argument at a given depth and index.
const TemplateArgument &operator()(unsigned Depth, unsigned Index) const {
assert(Depth < TemplateArgumentLists.size());
assert(Index < TemplateArgumentLists[getNumLevels() - Depth]->size());
return TemplateArgumentLists[getNumLevels() - Depth]->get(Index);
assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1]->size());
return TemplateArgumentLists[getNumLevels() - Depth - 1]->get(Index);
}
/// \brief Determine whether there is a non-NULL template argument at the
/// given depth and index.
///
/// There must exist a template argument list at the given depth.
bool hasTemplateArgument(unsigned Depth, unsigned Index) const {
assert(Depth < TemplateArgumentLists.size());
if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1]->size())
return false;
return !(*this)(Depth, Index).isNull();
}
/// \brief Add a new outermost level to the multi-level template argument
@ -67,6 +80,11 @@ namespace clang {
TemplateArgumentLists.push_back(TemplateArgs);
}
/// \brief Retrieve the innermost template argument list.
const TemplateArgumentList &getInnermost() const {
return *TemplateArgumentLists.front();
}
// Implicit conversion to a single template argument list, to facilitate a
// gradual transition to MultiLevelTemplateArgumentLists.
operator const TemplateArgumentList &() const {

View File

@ -26,8 +26,8 @@ using namespace clang;
// Template Instantiation Support
//===----------------------------------------------------------------------===/
/// \brief Retrieve the template argument list that should be used to
/// instantiate the given declaration.
/// \brief Retrieve the template argument list(s) that should be used to
/// instantiate the definition of the given declaration.
MultiLevelTemplateArgumentList
Sema::getTemplateInstantiationArgs(NamedDecl *D) {
// Accumulate the set of template argument lists in this structure.
@ -298,7 +298,7 @@ namespace {
class VISIBILITY_HIDDEN TemplateInstantiator
: public TreeTransform<TemplateInstantiator>
{
const TemplateArgumentList &TemplateArgs;
const MultiLevelTemplateArgumentList &TemplateArgs;
SourceLocation Loc;
DeclarationName Entity;
@ -306,7 +306,7 @@ namespace {
typedef TreeTransform<TemplateInstantiator> inherited;
TemplateInstantiator(Sema &SemaRef,
const TemplateArgumentList &TemplateArgs,
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc,
DeclarationName Entity)
: inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
@ -353,15 +353,24 @@ namespace {
Decl *TemplateInstantiator::TransformDecl(Decl *D) {
if (TemplateTemplateParmDecl *TTP
= dyn_cast_or_null<TemplateTemplateParmDecl>(D)) {
// FIXME: Depth reduction
assert(TTP->getDepth() == 0 &&
"Cannot reduce depth of a template template parameter");
assert(TemplateArgs[TTP->getPosition()].getAsDecl() &&
"Wrong kind of template template argument");
TemplateDecl *Template
= dyn_cast<TemplateDecl>(TemplateArgs[TTP->getPosition()].getAsDecl());
assert(Template && "Expected a template");
return Template;
if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
assert(TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsDecl() &&
"Wrong kind of template template argument");
return cast<TemplateDecl>(TemplateArgs(TTP->getDepth(),
TTP->getPosition()).getAsDecl());
}
// If the corresponding template argument is NULL or non-existent, it's
// because we are performing instantiation from explicitly-specified
// template arguments in a function template, but there were some
// arguments left unspecified.
if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
TTP->getPosition()))
return D;
// FIXME: Implement depth reduction of template template parameters
assert(false &&
"Reducing depth of template template parameters is not yet implemented");
}
return SemaRef.FindInstantiatedDecl(cast_or_null<NamedDecl>(D));
@ -395,59 +404,65 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
// FIXME: Clean this up a bit
NamedDecl *D = E->getDecl();
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
assert(NTTP->getDepth() == 0 && "No nested templates yet");
if (NTTP->getDepth() >= TemplateArgs.getNumLevels()) {
assert(false && "Cannot reduce non-type template parameter depth yet");
return getSema().ExprError();
}
// If the corresponding template argument is NULL or non-existent, it's
// because we are performing instantiation from explicitly-specified
// template arguments in a function template, but there were some
// arguments left unspecified.
if (NTTP->getPosition() >= TemplateArgs.size() ||
TemplateArgs[NTTP->getPosition()].isNull())
return SemaRef.Owned(E); // FIXME: Clone the expression!
if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(),
NTTP->getPosition()))
return SemaRef.Owned(E->Retain());
const TemplateArgument &Arg = TemplateArgs[NTTP->getPosition()];
const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(),
NTTP->getPosition());
// The template argument itself might be an expression, in which
// case we just return that expression.
if (Arg.getKind() == TemplateArgument::Expression)
// FIXME: Clone the expression!
return SemaRef.Owned(Arg.getAsExpr());
return SemaRef.Owned(Arg.getAsExpr()->Retain());
if (Arg.getKind() == TemplateArgument::Declaration) {
ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
// FIXME: Can VD ever have a dependent type?
VD = cast_or_null<ValueDecl>(getSema().FindInstantiatedDecl(VD));
if (!VD)
return SemaRef.ExprError();
return SemaRef.BuildDeclRefExpr(VD, VD->getType(), E->getLocation(),
false, false);
/*FIXME:*/false, /*FIXME:*/false);
}
assert(Arg.getKind() == TemplateArgument::Integral);
QualType T = Arg.getIntegralType();
if (T->isCharType() || T->isWideCharType())
return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral(
Arg.getAsIntegral()->getZExtValue(),
T->isWideCharType(),
T,
E->getSourceRange().getBegin()));
Arg.getAsIntegral()->getZExtValue(),
T->isWideCharType(),
T,
E->getSourceRange().getBegin()));
if (T->isBooleanType())
return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr(
Arg.getAsIntegral()->getBoolValue(),
T,
E->getSourceRange().getBegin()));
Arg.getAsIntegral()->getBoolValue(),
T,
E->getSourceRange().getBegin()));
assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T));
return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral(
*Arg.getAsIntegral(),
T,
E->getSourceRange().getBegin()));
*Arg.getAsIntegral(),
T,
E->getSourceRange().getBegin()));
}
if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) {
// FIXME: instantiate each decl in the overload set
return SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(Ovl,
SemaRef.Context.OverloadTy,
E->getLocation(),
false, false));
SemaRef.Context.OverloadTy,
E->getLocation(),
false, false));
}
NamedDecl *InstD = SemaRef.FindInstantiatedDecl(D);
@ -464,31 +479,30 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
QualType
TemplateInstantiator::TransformTemplateTypeParmType(
const TemplateTypeParmType *T) {
if (T->getDepth() == 0) {
if (T->getDepth() < TemplateArgs.getNumLevels()) {
// Replace the template type parameter with its corresponding
// template argument.
// FIXME: When dealing with member templates, we might end up with multiple
/// levels of template arguments that we're substituting into concurrently.
// If the corresponding template argument is NULL or doesn't exist, it's
// because we are performing instantiation from explicitly-specified
// template arguments in a function template class, but there were some
// arguments left unspecified.
if (T->getIndex() >= TemplateArgs.size() ||
TemplateArgs[T->getIndex()].isNull())
return QualType(T, 0); // Would be nice to keep the original type here
assert(TemplateArgs[T->getIndex()].getKind() == TemplateArgument::Type &&
if (!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex()))
return QualType(T, 0);
assert(TemplateArgs(T->getDepth(), T->getIndex()).getKind()
== TemplateArgument::Type &&
"Template argument kind mismatch");
return TemplateArgs[T->getIndex()].getAsType();
return TemplateArgs(T->getDepth(), T->getIndex()).getAsType();
}
// The template type parameter comes from an inner template (e.g.,
// the template parameter list of a member template inside the
// template we are instantiating). Create a new template type
// parameter with the template "level" reduced by one.
return getSema().Context.getTemplateTypeParmType(T->getDepth() - 1,
return getSema().Context.getTemplateTypeParmType(
T->getDepth() - TemplateArgs.getNumLevels(),
T->getIndex(),
T->isParameterPack(),
T->getName());
@ -522,7 +536,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(
/// \returns If the instantiation succeeds, the instantiated
/// type. Otherwise, produces diagnostics and returns a NULL type.
QualType Sema::SubstType(QualType T,
const TemplateArgumentList &TemplateArgs,
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc, DeclarationName Entity) {
assert(!ActiveTemplateInstantiations.empty() &&
"Cannot perform an instantiation without some context on the "
@ -545,7 +559,7 @@ QualType Sema::SubstType(QualType T,
bool
Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
CXXRecordDecl *Pattern,
const TemplateArgumentList &TemplateArgs) {
const MultiLevelTemplateArgumentList &TemplateArgs) {
bool Invalid = false;
llvm::SmallVector<CXXBaseSpecifier*, 4> InstantiatedBases;
for (ClassTemplateSpecializationDecl::base_class_iterator
@ -586,38 +600,6 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
return Invalid;
}
/// \brief Force a template's pattern class to be instantiated.
///
/// \returns true if an error occurred
bool Sema::InstantiateTemplatePattern(SourceLocation PointOfInstantiation,
CXXRecordDecl *Pattern) {
if (Pattern->getDefinition(Context)) return false;
ClassTemplateDecl *PatternTemp = Pattern->getDescribedClassTemplate();
if (!PatternTemp) return false;
// Check whether this template is a lazy instantiation of a
// dependent member template, e.g. Inner<U> in
// Outer<int>::Inner<U>.
ClassTemplateDecl *PatternPatternTemp
= PatternTemp->getInstantiatedFromMemberTemplate();
if (!PatternPatternTemp) return false;
ClassTemplateSpecializationDecl *Spec = 0;
for (DeclContext *Parent = Pattern->getDeclContext();
Parent && !Spec; Parent = Parent->getParent())
Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent);
assert(Spec && "Not a member of a class template specialization?");
// TODO: the error message from a nested failure here is probably
// not ideal.
return InstantiateClass(PointOfInstantiation,
Pattern,
PatternPatternTemp->getTemplatedDecl(),
Spec->getTemplateArgs(),
/* ExplicitInstantiation = */ false);
}
/// \brief Instantiate the definition of a class from a given pattern.
///
/// \param PointOfInstantiation The point of instantiation within the
@ -644,15 +626,11 @@ bool Sema::InstantiateTemplatePattern(SourceLocation PointOfInstantiation,
bool
Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
const TemplateArgumentList &TemplateArgs,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool ExplicitInstantiation,
bool Complain) {
bool Invalid = false;
// Lazily instantiate member templates here.
if (InstantiateTemplatePattern(PointOfInstantiation, Pattern))
return true;
CXXRecordDecl *PatternDef
= cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
if (!PatternDef) {
@ -745,9 +723,7 @@ Sema::InstantiateClassTemplateSpecialization(
return true;
ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
CXXRecordDecl *Pattern = Template->getTemplatedDecl();
const TemplateArgumentList *TemplateArgs
= &ClassTemplateSpec->getTemplateArgs();
CXXRecordDecl *Pattern = 0;
// C++ [temp.class.spec.match]p1:
// When a class template is used in a context that requires an
@ -782,7 +758,6 @@ Sema::InstantiateClassTemplateSpecialization(
// -- If exactly one matching specialization is found, the
// instantiation is generated from that specialization.
Pattern = Matched[0].first;
TemplateArgs = Matched[0].second;
ClassTemplateSpec->setInstantiationOf(Matched[0].first, Matched[0].second);
} else if (Matched.size() > 1) {
// -- If more than one matching specialization is found, the
@ -796,21 +771,31 @@ Sema::InstantiateClassTemplateSpecialization(
// specializations.
Diag(ClassTemplateSpec->getLocation(),
diag::unsup_template_partial_spec_ordering);
// FIXME: Temporary hack to fall back to the primary template
ClassTemplateDecl *OrigTemplate = Template;
while (OrigTemplate->getInstantiatedFromMemberTemplate())
OrigTemplate = OrigTemplate->getInstantiatedFromMemberTemplate();
Pattern = OrigTemplate->getTemplatedDecl();
} else {
// -- If no matches are found, the instantiation is generated
// from the primary template.
// Since we initialized the pattern and template arguments from
// the primary template, there is nothing more we need to do here.
ClassTemplateDecl *OrigTemplate = Template;
while (OrigTemplate->getInstantiatedFromMemberTemplate())
OrigTemplate = OrigTemplate->getInstantiatedFromMemberTemplate();
Pattern = OrigTemplate->getTemplatedDecl();
}
// Note that this is an instantiation.
// Note that this is an instantiation.
ClassTemplateSpec->setSpecializationKind(
ExplicitInstantiation? TSK_ExplicitInstantiation
: TSK_ImplicitInstantiation);
bool Result = InstantiateClass(ClassTemplateSpec->getLocation(),
ClassTemplateSpec, Pattern, *TemplateArgs,
ClassTemplateSpec, Pattern,
getTemplateInstantiationArgs(ClassTemplateSpec),
ExplicitInstantiation,
Complain);
@ -829,7 +814,7 @@ Sema::InstantiateClassTemplateSpecialization(
void
Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation,
const TemplateArgumentList &TemplateArgs) {
const MultiLevelTemplateArgumentList &TemplateArgs) {
for (DeclContext::decl_iterator D = Instantiation->decls_begin(),
DEnd = Instantiation->decls_end();
D != DEnd; ++D) {
@ -866,11 +851,11 @@ void Sema::InstantiateClassTemplateSpecializationMembers(
// containing the explicit instantiation, except as described
// below.
InstantiateClassMembers(PointOfInstantiation, ClassTemplateSpec,
ClassTemplateSpec->getTemplateArgs());
getTemplateInstantiationArgs(ClassTemplateSpec));
}
Sema::OwningStmtResult
Sema::SubstStmt(Stmt *S, const TemplateArgumentList &TemplateArgs) {
Sema::SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs) {
if (!S)
return Owned(S);
@ -881,7 +866,7 @@ Sema::SubstStmt(Stmt *S, const TemplateArgumentList &TemplateArgs) {
}
Sema::OwningExprResult
Sema::SubstExpr(Expr *E, const TemplateArgumentList &TemplateArgs) {
Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
if (!E)
return Owned(E);
@ -894,8 +879,8 @@ Sema::SubstExpr(Expr *E, const TemplateArgumentList &TemplateArgs) {
/// \brief Do template substitution on a nested-name-specifier.
NestedNameSpecifier *
Sema::SubstNestedNameSpecifier(NestedNameSpecifier *NNS,
SourceRange Range,
const TemplateArgumentList &TemplateArgs) {
SourceRange Range,
const MultiLevelTemplateArgumentList &TemplateArgs) {
TemplateInstantiator Instantiator(*this, TemplateArgs, Range.getBegin(),
DeclarationName());
return Instantiator.TransformNestedNameSpecifier(NNS, Range);
@ -903,14 +888,14 @@ Sema::SubstNestedNameSpecifier(NestedNameSpecifier *NNS,
TemplateName
Sema::SubstTemplateName(TemplateName Name, SourceLocation Loc,
const TemplateArgumentList &TemplateArgs) {
const MultiLevelTemplateArgumentList &TemplateArgs) {
TemplateInstantiator Instantiator(*this, TemplateArgs, Loc,
DeclarationName());
return Instantiator.TransformTemplateName(Name);
}
TemplateArgument Sema::Subst(TemplateArgument Arg,
const TemplateArgumentList &TemplateArgs) {
const MultiLevelTemplateArgumentList &TemplateArgs) {
TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
DeclarationName());
return Instantiator.TransformTemplateArgument(Arg);

View File

@ -25,13 +25,13 @@ namespace {
: public DeclVisitor<TemplateDeclInstantiator, Decl *> {
Sema &SemaRef;
DeclContext *Owner;
const TemplateArgumentList &TemplateArgs;
const MultiLevelTemplateArgumentList &TemplateArgs;
public:
typedef Sema::OwningExprResult OwningExprResult;
TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
const TemplateArgumentList &TemplateArgs)
const MultiLevelTemplateArgumentList &TemplateArgs)
: SemaRef(SemaRef), Owner(Owner), TemplateArgs(TemplateArgs) { }
// FIXME: Once we get closer to completion, replace these manually-written
@ -457,8 +457,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
if (FunctionTemplate) {
llvm::FoldingSetNodeID ID;
FunctionTemplateSpecializationInfo::Profile(ID,
TemplateArgs.getFlatArgumentList(),
TemplateArgs.flat_size(),
TemplateArgs.getInnermost().getFlatArgumentList(),
TemplateArgs.getInnermost().flat_size(),
SemaRef.Context);
FunctionTemplateSpecializationInfo *Info
@ -513,7 +513,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
// Record this function template specialization.
Function->setFunctionTemplateSpecialization(SemaRef.Context,
FunctionTemplate,
&TemplateArgs,
&TemplateArgs.getInnermost(),
InsertPos);
}
@ -531,8 +531,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
// specialization for this particular set of template arguments.
llvm::FoldingSetNodeID ID;
FunctionTemplateSpecializationInfo::Profile(ID,
TemplateArgs.getFlatArgumentList(),
TemplateArgs.flat_size(),
TemplateArgs.getInnermost().getFlatArgumentList(),
TemplateArgs.getInnermost().flat_size(),
SemaRef.Context);
FunctionTemplateSpecializationInfo *Info
@ -646,7 +646,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
// Record this function template specialization.
Method->setFunctionTemplateSpecialization(SemaRef.Context,
FunctionTemplate,
&TemplateArgs,
&TemplateArgs.getInnermost(),
InsertPos);
bool Redeclaration = false;
@ -760,7 +760,7 @@ TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) {
}
Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
const TemplateArgumentList &TemplateArgs) {
const MultiLevelTemplateArgumentList &TemplateArgs) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
return Instantiator.Visit(D);
}

View File

@ -21,3 +21,25 @@ void test_X0(int *ip, double *dp) {
double *&dpr2 = xv.f1(ip, dp);
}
template<typename T>
struct X1 {
template<typename U>
struct Inner0 {
U x;
T y; // expected-error{{void}}
};
template<typename U>
struct Inner1 {
U x; // expected-error{{void}}
T y;
};
};
void test_X1() {
X1<void>::Inner0<int> *xvip; // okay
X1<void>::Inner0<int> xvi; // expected-note{{instantiation}}
X1<int>::Inner1<void> *xivp; // okay
X1<int>::Inner1<void> xiv; // expected-note{{instantiation}}
}