aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaTemplate.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-02-17 01:05:43 +0000
committerDouglas Gregor <dgregor@apple.com>2009-02-17 01:05:43 +0000
commit3e00bad490f1bae8a2c60f934e7eb5dbb9752c5d (patch)
treecd116f187b667c5f88dd380a317592ad5ccdb287 /lib/Sema/SemaTemplate.cpp
parentf50adff9997578a021c5fb1689852949e8e4d9b4 (diff)
Added ClassTemplateSpecializationDecl, which is a subclass of
CXXRecordDecl that is used to represent class template specializations. These are canonical declarations that can refer to either an actual class template specialization in the code, e.g., template<> class vector<bool> { }; or to a template instantiation. However, neither of these features is actually implemented yet, so really we're just using (and uniqing) the declarations to make sure that, e.g., A<int> is a different type from A<float>. Note that we carefully distinguish between what the user wrote in the source code (e.g., "A<FLOAT>") and the semantic entity it represents (e.g., "A<float, int>"); the former is in the sugared Type, the latter is an actual Decl. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64716 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r--lib/Sema/SemaTemplate.cpp176
1 files changed, 152 insertions, 24 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index b339a7ba38..8c2a8bcd4a 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -654,21 +654,51 @@ Sema::ActOnClassTemplateSpecialization(DeclTy *TemplateD,
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))
+ TemplateArgs, TemplateArgLocs, RAngleLoc,
+ ConvertedTemplateArgs))
return 0;
- // Yes, all class template specializations are just silly sugar for
- // 'int'. Gotta problem wit dat?
+ assert((ConvertedTemplateArgs.size() ==
+ Template->getTemplateParameters()->size()) &&
+ "Converted template argument list is too short!");
+
+ // 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 an appropriate declaration node and add
+ // it to the list of specializations. This is the canonical
+ // declaration of the class template.
+ Decl = ClassTemplateSpecializationDecl::Create(Context,
+ ClassTemplate->getDeclContext(),
+ TemplateLoc,
+ ClassTemplate,
+ &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size());
+ ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
+ }
+
+ // 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.IntTy);
+ Context.getTypeDeclType(Decl));
TemplateArgs.release();
return Result.getAsOpaquePtr();
}
@@ -680,7 +710,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr& Args,
SourceLocation *TemplateArgLocs,
- SourceLocation RAngleLoc) {
+ SourceLocation RAngleLoc,
+ llvm::SmallVectorImpl<TemplateArgument> &Converted) {
TemplateParameterList *Params = Template->getTemplateParameters();
unsigned NumParams = Params->size();
unsigned NumArgs = Args.size();
@@ -719,22 +750,51 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
Expr *ArgExpr = 0;
SourceLocation ArgLoc;
if (ArgIdx >= NumArgs) {
- // FIXME: Get the default argument here, which might
- // (eventually) require instantiation.
- break;
- } else
+ // Retrieve the default template argument from the template
+ // parameter.
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+ if (!TTP->hasDefaultArgument())
+ break;
+
+ ArgType = TTP->getDefaultArgument();
+ ArgLoc = TTP->getDefaultArgumentLoc();
+ } else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
+ if (!NTTP->hasDefaultArgument())
+ break;
+
+ ArgExpr = NTTP->getDefaultArgument();
+ ArgLoc = NTTP->getDefaultArgumentLoc();
+ } else {
+ TemplateTemplateParmDecl *TempParm
+ = cast<TemplateTemplateParmDecl>(*Param);
+
+ if (!TempParm->hasDefaultArgument())
+ break;
+
+ ArgExpr = TempParm->getDefaultArgument();
+ ArgLoc = TempParm->getDefaultArgumentLoc();
+ }
+ } 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]);
+ if (Args.getArgIsType()[ArgIdx])
+ ArgType = QualType::getFromOpaquePtr(Args.getArgs()[ArgIdx]);
+ else
+ ArgExpr = reinterpret_cast<Expr *>(Args.getArgs()[ArgIdx]);
+ }
+
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
// Check template type parameters.
if (!ArgType.isNull()) {
if (CheckTemplateArgument(TTP, ArgType, ArgLoc))
Invalid = true;
+
+ // Add the converted template type argument.
+ Converted.push_back(
+ TemplateArgument(Context.getCanonicalType(ArgType)));
continue;
}
@@ -752,7 +812,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
// Check non-type template parameters.
if (ArgExpr) {
- if (CheckTemplateArgument(NTTP, ArgExpr))
+ if (CheckTemplateArgument(NTTP, ArgExpr, &Converted))
Invalid = true;
continue;
}
@@ -783,6 +843,11 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
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;
}
@@ -828,7 +893,8 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
/// \brief Checks whether the given template argument is the address
/// of an object or function according to C++ [temp.arg.nontype]p1.
-bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg) {
+bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
+ NamedDecl *&Entity) {
bool Invalid = false;
// See through any implicit casts we added to fix the type.
@@ -895,6 +961,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg) {
}
// Okay: we've named a function with external linkage.
+ Entity = Func;
return Invalid;
}
@@ -909,6 +976,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg) {
}
// Okay: we've named an object with external linkage
+ Entity = Var;
return Invalid;
}
@@ -923,7 +991,8 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg) {
/// \brief Checks whether the given template argument is a pointer to
/// member constant according to C++ [temp.arg.nontype]p1.
-bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg) {
+bool
+Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
bool Invalid = false;
// See through any implicit casts we added to fix the type.
@@ -966,6 +1035,7 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg) {
// Okay: this is the address of a non-static member, and therefore
// a member pointer constant.
+ Member = DRE->getDecl();
return Invalid;
}
@@ -983,10 +1053,15 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg) {
///
/// This routine implements the semantics of C++ [temp.arg.nontype].
/// It returns true if an error occurred, and false otherwise.
+///
+/// If Converted is non-NULL and no errors occur, the value
+/// of this argument will be added to the end of the Converted vector.
bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
- Expr *&Arg) {
+ Expr *&Arg,
+ llvm::SmallVectorImpl<TemplateArgument> *Converted) {
// 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 (Param->getType()->isDependentType() || Arg->isTypeDependent())
return false;
@@ -1011,6 +1086,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// type; or
// -- the name of a non-type template-parameter; or
SourceLocation NonConstantLoc;
+ llvm::APSInt Value;
if (!ArgType->isIntegralType() && !ArgType->isEnumeralType()) {
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_integral_or_enumeral)
@@ -1018,7 +1094,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
Diag(Param->getLocation(), diag::note_template_param_here);
return true;
} else if (!Arg->isValueDependent() &&
- !Arg->isIntegerConstantExpr(Context, &NonConstantLoc)) {
+ !Arg->isIntegerConstantExpr(Value, Context, &NonConstantLoc)) {
Diag(NonConstantLoc, diag::err_template_arg_not_ice)
<< ArgType << Arg->getSourceRange();
return true;
@@ -1048,6 +1124,23 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
+ // FIXME: Check overflow of template arguments?
+
+ if (Converted) {
+ // Add the value of this argument to the list of converted
+ // arguments. We use the bitwidth and signedness of the template
+ // parameter.
+ QualType IntegerType = Context.getCanonicalType(ParamType);
+ if (const EnumType *Enum = IntegerType->getAsEnumType())
+ IntegerType = Enum->getDecl()->getIntegerType();
+
+ llvm::APInt CanonicalArg(Context.getTypeSize(IntegerType), 0,
+ IntegerType->isSignedIntegerType());
+ CanonicalArg = Value;
+
+ Converted->push_back(TemplateArgument(CanonicalArg));
+ }
+
return false;
}
@@ -1100,10 +1193,24 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
- if (ParamType->isMemberPointerType())
- return CheckTemplateArgumentPointerToMember(Arg);
+ if (ParamType->isMemberPointerType()) {
+ NamedDecl *Member = 0;
+ if (CheckTemplateArgumentPointerToMember(Arg, Member))
+ return true;
+
+ if (Converted)
+ Converted->push_back(TemplateArgument(Member));
+
+ return false;
+ }
- return CheckTemplateArgumentAddressOfObjectOrFunction(Arg);
+ NamedDecl *Entity = 0;
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
+ return true;
+
+ if (Converted)
+ Converted->push_back(TemplateArgument(Entity));
+ return false;
}
if (const PointerType *ParamPtrType = ParamType->getAsPointerType()) {
@@ -1132,7 +1239,14 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
- return CheckTemplateArgumentAddressOfObjectOrFunction(Arg);
+ NamedDecl *Entity = 0;
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
+ return true;
+
+ if (Converted)
+ Converted->push_back(TemplateArgument(Entity));
+
+ return false;
}
if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) {
@@ -1167,7 +1281,14 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
- return CheckTemplateArgumentAddressOfObjectOrFunction(Arg);
+ NamedDecl *Entity = 0;
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
+ return true;
+
+ if (Converted)
+ Converted->push_back(TemplateArgument(Entity));
+
+ return false;
}
// -- For a non-type template-parameter of type pointer to data
@@ -1187,7 +1308,14 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
- return CheckTemplateArgumentPointerToMember(Arg);
+ NamedDecl *Member = 0;
+ if (CheckTemplateArgumentPointerToMember(Arg, Member))
+ return true;
+
+ if (Converted)
+ Converted->push_back(TemplateArgument(Member));
+
+ return false;
}
/// \brief Check a template argument against its corresponding