Implement template instantiation for ClassTemplateSpecializationTypes,
such as replacing 'T' in vector<T>. There are a few aspects to this:
- Extend TemplateArgument to allow arbitrary expressions (an
Expr*), and switch ClassTemplateSpecializationType to store
TemplateArguments rather than it's own type-or-expression
representation.
- ClassTemplateSpecializationType can now store dependent types. In
that case, the canonical type is another
ClassTemplateSpecializationType (with default template arguments
expanded) rather than a declaration (we don't build Decls for
dependent types).
- Split ActOnClassTemplateId into ActOnClassTemplateId (called from
the parser) and CheckClassTemplateId (called from
ActOnClassTemplateId and InstantiateType). They're smart enough to
handle dependent types, now.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66509 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 4ac8ffc..83be895 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1601,6 +1601,13 @@
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists);
+ QualType CheckClassTemplateId(ClassTemplateDecl *ClassTemplate,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation RAngleLoc);
+
virtual TypeResult
ActOnClassTemplateId(DeclTy *Template, SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
@@ -1630,8 +1637,8 @@
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- ASTTemplateArgsPtr& TemplateArgs,
- SourceLocation *TemplateArgLocs,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
SourceLocation RAngleLoc,
llvm::SmallVectorImpl<TemplateArgument> &Converted);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 7773b9e..e9e2e3c 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -383,7 +383,8 @@
Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
TypeTy *basetype, SourceLocation BaseLoc) {
- CXXRecordDecl *Class = (CXXRecordDecl*)classdecl;
+ AdjustDeclIfTemplate(classdecl);
+ CXXRecordDecl *Class = cast<CXXRecordDecl>((Decl*)classdecl);
QualType BaseType = QualType::getFromOpaquePtr(basetype);
if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange,
Virtual, Access,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index a55e3a5..281984d 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -658,61 +658,115 @@
return Invalid;
}
+/// \brief Translates template arguments as provided by the parser
+/// into template arguments used by semantic analysis.
+static void
+translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
+ SourceLocation *TemplateArgLocs,
+ llvm::SmallVector<TemplateArgument, 16> &TemplateArgs) {
+ TemplateArgs.reserve(TemplateArgsIn.size());
+
+ void **Args = TemplateArgsIn.getArgs();
+ bool *ArgIsType = TemplateArgsIn.getArgIsType();
+ for (unsigned Arg = 0, Last = TemplateArgsIn.size(); Arg != Last; ++Arg) {
+ TemplateArgs.push_back(
+ ArgIsType[Arg]? TemplateArgument(TemplateArgLocs[Arg],
+ QualType::getFromOpaquePtr(Args[Arg]))
+ : TemplateArgument(reinterpret_cast<Expr *>(Args[Arg])));
+ }
+}
+
+QualType Sema::CheckClassTemplateId(ClassTemplateDecl *ClassTemplate,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation RAngleLoc) {
+ // Check that the template argument list is well-formed for this
+ // template.
+ llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs;
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateLoc, LAngleLoc,
+ TemplateArgs, NumTemplateArgs, RAngleLoc,
+ ConvertedTemplateArgs))
+ return QualType();
+
+ assert((ConvertedTemplateArgs.size() ==
+ ClassTemplate->getTemplateParameters()->size()) &&
+ "Converted template argument list is too short!");
+
+ QualType CanonType;
+
+ if (ClassTemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs,
+ NumTemplateArgs)) {
+ // This class template specialization is a dependent
+ // type. Therefore, its canonical type is another class template
+ // specialization type that contains all of the converted
+ // arguments in canonical form. This ensures that, e.g., A<T> and
+ // A<T, T> have identical types when A is declared as:
+ //
+ // template<typename T, typename U = T> struct A;
+
+ CanonType = Context.getClassTemplateSpecializationType(ClassTemplate,
+ &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size());
+ } else {
+ // Find the class template specialization declaration that
+ // corresponds to these arguments.
+ llvm::FoldingSetNodeID ID;
+ ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size());
+ void *InsertPos = 0;
+ ClassTemplateSpecializationDecl *Decl
+ = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+ if (!Decl) {
+ // This is the first time we have referenced this class template
+ // specialization. Create the canonical declaration and add it to
+ // the set of specializations.
+ Decl = ClassTemplateSpecializationDecl::Create(Context,
+ ClassTemplate->getDeclContext(),
+ TemplateLoc,
+ ClassTemplate,
+ &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size(),
+ 0);
+ ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
+ Decl->setLexicalDeclContext(CurContext);
+ }
+
+ CanonType = Context.getTypeDeclType(Decl);
+ }
+
+ // Build the fully-sugared type for this class template
+ // specialization, which refers back to the class template
+ // specialization we created or found.
+ return Context.getClassTemplateSpecializationType(ClassTemplate,
+ TemplateArgs,
+ NumTemplateArgs,
+ CanonType);
+}
+
Action::TypeResult
Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- ASTTemplateArgsPtr TemplateArgs,
+ ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc,
const CXXScopeSpec *SS) {
TemplateDecl *Template = cast<TemplateDecl>(static_cast<Decl *>(TemplateD));
ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(Template);
- // Check that the template argument list is well-formed for this
- // template.
- llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs;
- if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc,
- TemplateArgs, TemplateArgLocs, RAngleLoc,
- ConvertedTemplateArgs))
- return true;
+ // Translate the parser's template argument list in our AST format.
+ llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
- assert((ConvertedTemplateArgs.size() ==
- Template->getTemplateParameters()->size()) &&
- "Converted template argument list is too short!");
+ QualType Result = CheckClassTemplateId(ClassTemplate, TemplateLoc,
+ LAngleLoc,
+ &TemplateArgs[0],
+ TemplateArgs.size(),
+ RAngleLoc);
- // Find the class template specialization declaration that
- // corresponds to these arguments.
- llvm::FoldingSetNodeID ID;
- ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
- ConvertedTemplateArgs.size());
- void *InsertPos = 0;
- ClassTemplateSpecializationDecl *Decl
- = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
- if (!Decl) {
- // This is the first time we have referenced this class template
- // specialization. Create the canonical declaration and add it to
- // the set of specializations.
- Decl = ClassTemplateSpecializationDecl::Create(Context,
- ClassTemplate->getDeclContext(),
- TemplateLoc,
- ClassTemplate,
- &ConvertedTemplateArgs[0],
- ConvertedTemplateArgs.size(),
- 0);
- ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
- Decl->setLexicalDeclContext(CurContext);
- }
-
- // Build the fully-sugared type for this class template
- // specialization, which refers back to the class template
- // specialization we created or found.
- QualType Result
- = Context.getClassTemplateSpecializationType(Template,
- TemplateArgs.size(),
- reinterpret_cast<uintptr_t *>(TemplateArgs.getArgs()),
- TemplateArgs.getArgIsType(),
- Context.getTypeDeclType(Decl));
- TemplateArgs.release();
+ TemplateArgsIn.release();
return Result.getAsOpaquePtr();
}
@@ -721,13 +775,13 @@
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- ASTTemplateArgsPtr& Args,
- SourceLocation *TemplateArgLocs,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
SourceLocation RAngleLoc,
llvm::SmallVectorImpl<TemplateArgument> &Converted) {
TemplateParameterList *Params = Template->getTemplateParameters();
unsigned NumParams = Params->size();
- unsigned NumArgs = Args.size();
+ unsigned NumArgs = NumTemplateArgs;
bool Invalid = false;
if (NumArgs > NumParams ||
@@ -737,7 +791,7 @@
// arguments.
SourceRange Range;
if (NumArgs > NumParams)
- Range = SourceRange(TemplateArgLocs[NumParams], RAngleLoc);
+ Range = SourceRange(TemplateArgs[NumParams].getLocation(), RAngleLoc);
Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
<< (NumArgs > NumParams)
<< (isa<ClassTemplateDecl>(Template)? 0 :
@@ -759,9 +813,7 @@
ParamEnd = Params->end();
Param != ParamEnd; ++Param, ++ArgIdx) {
// Decode the template argument
- QualType ArgType;
- Expr *ArgExpr = 0;
- SourceLocation ArgLoc;
+ TemplateArgument Arg;
if (ArgIdx >= NumArgs) {
// Retrieve the default template argument from the template
// parameter.
@@ -769,7 +821,7 @@
if (!TTP->hasDefaultArgument())
break;
- ArgType = TTP->getDefaultArgument();
+ QualType ArgType = TTP->getDefaultArgument();
// If the argument type is dependent, instantiate it now based
// on the previously-computed template arguments.
@@ -781,15 +833,14 @@
if (ArgType.isNull())
return true;
- ArgLoc = TTP->getDefaultArgumentLoc();
+ Arg = TemplateArgument(TTP->getLocation(), ArgType);
} else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
if (!NTTP->hasDefaultArgument())
break;
// FIXME: Instantiate default argument
- ArgExpr = NTTP->getDefaultArgument();
- ArgLoc = NTTP->getDefaultArgumentLoc();
+ Arg = TemplateArgument(NTTP->getDefaultArgument());
} else {
TemplateTemplateParmDecl *TempParm
= cast<TemplateTemplateParmDecl>(*Param);
@@ -798,29 +849,24 @@
break;
// FIXME: Instantiate default argument
- ArgExpr = TempParm->getDefaultArgument();
- ArgLoc = TempParm->getDefaultArgumentLoc();
+ Arg = TemplateArgument(TempParm->getDefaultArgument());
}
} else {
// Retrieve the template argument produced by the user.
- ArgLoc = TemplateArgLocs[ArgIdx];
-
- if (Args.getArgIsType()[ArgIdx])
- ArgType = QualType::getFromOpaquePtr(Args.getArgs()[ArgIdx]);
- else
- ArgExpr = reinterpret_cast<Expr *>(Args.getArgs()[ArgIdx]);
+ Arg = TemplateArgs[ArgIdx];
}
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
// Check template type parameters.
- if (!ArgType.isNull()) {
- if (CheckTemplateArgument(TTP, ArgType, ArgLoc))
+ if (Arg.getKind() == TemplateArgument::Type) {
+ if (CheckTemplateArgument(TTP, Arg.getAsType(), Arg.getLocation()))
Invalid = true;
// Add the converted template type argument.
Converted.push_back(
- TemplateArgument(Context.getCanonicalType(ArgType)));
+ TemplateArgument(Arg.getLocation(),
+ Context.getCanonicalType(Arg.getAsType())));
continue;
}
@@ -829,9 +875,8 @@
// type shall be a type-id.
// We have a template type parameter but the template argument
- // is an expression.
- Diag(ArgExpr->getSourceRange().getBegin(),
- diag::err_template_arg_must_be_type);
+ // is not a type.
+ Diag(Arg.getLocation(), diag::err_template_arg_must_be_type);
Diag((*Param)->getLocation(), diag::note_template_param_here);
Invalid = true;
} else if (NonTypeTemplateParmDecl *NTTP
@@ -859,50 +904,81 @@
}
}
- if (ArgExpr) {
- if (CheckTemplateArgument(NTTP, NTTPType, ArgExpr, &Converted))
+ switch (Arg.getKind()) {
+ case TemplateArgument::Expression: {
+ Expr *E = Arg.getAsExpr();
+ if (CheckTemplateArgument(NTTP, NTTPType, E, &Converted))
Invalid = true;
- continue;
+ break;
}
- // We have a non-type template parameter but the template
- // argument is a type.
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Integral:
+ // We've already checked this template argument, so just copy
+ // it to the list of converted arguments.
+ Converted.push_back(Arg);
+ break;
- // C++ [temp.arg]p2:
- // In a template-argument, an ambiguity between a type-id and
- // an expression is resolved to a type-id, regardless of the
- // form of the corresponding template-parameter.
- //
- // We warn specifically about this case, since it can be rather
- // confusing for users.
- if (ArgType->isFunctionType())
- Diag(ArgLoc, diag::err_template_arg_nontype_ambig)
- << ArgType;
- else
- Diag(ArgLoc, diag::err_template_arg_must_be_expr);
- Diag((*Param)->getLocation(), diag::note_template_param_here);
- Invalid = true;
+ case TemplateArgument::Type:
+ // We have a non-type template parameter but the template
+ // argument is a type.
+
+ // C++ [temp.arg]p2:
+ // In a template-argument, an ambiguity between a type-id and
+ // an expression is resolved to a type-id, regardless of the
+ // form of the corresponding template-parameter.
+ //
+ // We warn specifically about this case, since it can be rather
+ // confusing for users.
+ if (Arg.getAsType()->isFunctionType())
+ Diag(Arg.getLocation(), diag::err_template_arg_nontype_ambig)
+ << Arg.getAsType();
+ else
+ Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr);
+ Diag((*Param)->getLocation(), diag::note_template_param_here);
+ Invalid = true;
+ }
} else {
// Check template template parameters.
TemplateTemplateParmDecl *TempParm
= cast<TemplateTemplateParmDecl>(*Param);
- if (ArgExpr && isa<DeclRefExpr>(ArgExpr) &&
- isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) {
- if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr)))
- Invalid = true;
-
- // Add the converted template argument.
- // FIXME: Need the "canonical" template declaration!
- Converted.push_back(
- TemplateArgument(cast<DeclRefExpr>(ArgExpr)->getDecl()));
- continue;
+ switch (Arg.getKind()) {
+ case TemplateArgument::Expression: {
+ Expr *ArgExpr = Arg.getAsExpr();
+ if (ArgExpr && isa<DeclRefExpr>(ArgExpr) &&
+ isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) {
+ if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr)))
+ Invalid = true;
+
+ // Add the converted template argument.
+ // FIXME: Need the "canonical" template declaration!
+ Converted.push_back(
+ TemplateArgument(Arg.getLocation(),
+ cast<DeclRefExpr>(ArgExpr)->getDecl()));
+ continue;
+ }
+ }
+ // fall through
+
+ case TemplateArgument::Type: {
+ // We have a template template parameter but the template
+ // argument does not refer to a template.
+ Diag(Arg.getLocation(), diag::err_template_arg_must_be_template);
+ Invalid = true;
+ break;
}
- // We have a template template parameter but the template
- // argument does not refer to a template.
- Diag(ArgLoc, diag::err_template_arg_must_be_template);
- Invalid = true;
+ case TemplateArgument::Declaration:
+ // We've already checked this template argument, so just copy
+ // it to the list of converted arguments.
+ Converted.push_back(Arg);
+ break;
+
+ case TemplateArgument::Integral:
+ assert(false && "Integral argument with template template parameter");
+ break;
+ }
}
}
@@ -1109,11 +1185,16 @@
bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType InstantiatedParamType, Expr *&Arg,
llvm::SmallVectorImpl<TemplateArgument> *Converted) {
+ SourceLocation StartLoc = Arg->getSourceRange().getBegin();
+
// If either the parameter has a dependent type or the argument is
// type-dependent, there's nothing we can check now.
// FIXME: Add template argument to Converted!
- if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent())
+ if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) {
+ // FIXME: Produce a cloned, canonical expression?
+ Converted->push_back(TemplateArgument(Arg));
return false;
+ }
// C++ [temp.arg.nontype]p5:
// The following conversions are performed on each expression used
@@ -1188,7 +1269,7 @@
IntegerType->isSignedIntegerType());
CanonicalArg = Value;
- Converted->push_back(TemplateArgument(CanonicalArg));
+ Converted->push_back(TemplateArgument(StartLoc, CanonicalArg));
}
return false;
@@ -1252,7 +1333,7 @@
return true;
if (Converted)
- Converted->push_back(TemplateArgument(Member));
+ Converted->push_back(TemplateArgument(StartLoc, Member));
return false;
}
@@ -1262,7 +1343,7 @@
return true;
if (Converted)
- Converted->push_back(TemplateArgument(Entity));
+ Converted->push_back(TemplateArgument(StartLoc, Entity));
return false;
}
@@ -1297,7 +1378,7 @@
return true;
if (Converted)
- Converted->push_back(TemplateArgument(Entity));
+ Converted->push_back(TemplateArgument(StartLoc, Entity));
return false;
}
@@ -1339,7 +1420,7 @@
return true;
if (Converted)
- Converted->push_back(TemplateArgument(Entity));
+ Converted->push_back(TemplateArgument(StartLoc, Entity));
return false;
}
@@ -1366,7 +1447,7 @@
return true;
if (Converted)
- Converted->push_back(TemplateArgument(Member));
+ Converted->push_back(TemplateArgument(StartLoc, Member));
return false;
}
@@ -1649,7 +1730,7 @@
DeclTy *TemplateD,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
- ASTTemplateArgsPtr TemplateArgs,
+ ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc,
AttributeList *Attr,
@@ -1701,12 +1782,16 @@
Kind = ClassTemplate->getTemplatedDecl()->getTagKind();
}
+ // Translate the parser's template argument list in our AST format.
+ llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
+
// Check that the template argument list is well-formed for this
// template.
llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs;
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
- TemplateArgs, TemplateArgLocs, RAngleLoc,
- ConvertedTemplateArgs))
+ &TemplateArgs[0], TemplateArgs.size(),
+ RAngleLoc, ConvertedTemplateArgs))
return 0;
assert((ConvertedTemplateArgs.size() ==
@@ -1786,11 +1871,10 @@
// template arguments in the specialization.
Specialization->setTypeAsWritten(
Context.getClassTemplateSpecializationType(ClassTemplate,
+ &TemplateArgs[0],
TemplateArgs.size(),
- reinterpret_cast<uintptr_t *>(TemplateArgs.getArgs()),
- TemplateArgs.getArgIsType(),
Context.getTypeDeclType(Specialization)));
- TemplateArgs.release();
+ TemplateArgsIn.release();
// C++ [temp.expl.spec]p9:
// A template explicit specialization is in the scope of the
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index faeebc0..71bba49 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -302,9 +302,44 @@
InstantiateClassTemplateSpecializationType(
const ClassTemplateSpecializationType *T,
unsigned Quals) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate ClassTemplateSpecializationType yet");
- return QualType();
+ llvm::SmallVector<TemplateArgument, 16> InstantiatedTemplateArgs;
+ InstantiatedTemplateArgs.reserve(T->getNumArgs());
+ for (ClassTemplateSpecializationType::iterator Arg = T->begin(),
+ ArgEnd = T->end();
+ Arg != ArgEnd; ++Arg) {
+ switch (Arg->getKind()) {
+ case TemplateArgument::Type: {
+ QualType T = SemaRef.InstantiateType(Arg->getAsType(),
+ TemplateArgs, NumTemplateArgs,
+ Arg->getLocation(),
+ DeclarationName());
+ if (T.isNull())
+ return QualType();
+
+ InstantiatedTemplateArgs.push_back(
+ TemplateArgument(Arg->getLocation(), T));
+ break;
+ }
+
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Integral:
+ InstantiatedTemplateArgs.push_back(*Arg);
+ break;
+
+ case TemplateArgument::Expression:
+ assert(false && "Cannot instantiate expressions yet");
+ break;
+ }
+ }
+
+ // FIXME: We're missing the locations of the template name, '<', and
+ // '>'.
+ return SemaRef.CheckClassTemplateId(cast<ClassTemplateDecl>(T->getTemplate()),
+ Loc,
+ SourceLocation(),
+ &InstantiatedTemplateArgs[0],
+ InstantiatedTemplateArgs.size(),
+ SourceLocation());
}
QualType