aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaTemplate.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-03-03 04:44:36 +0000
committerDouglas Gregor <dgregor@apple.com>2009-03-03 04:44:36 +0000
commit2943aed177b33ae3f14273b11a7b398e5276ec62 (patch)
tree91c3c315bf9f253eaff75ff8fd25cd634f2460aa /lib/Sema/SemaTemplate.cpp
parent3c59823096fe28a69a81f899c7f9f0e6eb8071a0 (diff)
Implement the basics of implicit instantiation of class templates, in
response to attempts to diagnose an "incomplete" type. This will force us to use DiagnoseIncompleteType more regularly (rather than looking at isIncompleteType), but that's also a good thing. Implicit instantiation is still very simplistic, and will create a new definition for the class template specialization (as it should) but it only actually instantiates the base classes and attaches those. Actually instantiating class members will follow. Also, instantiate the types of non-type template parameters before checking them, allowing, e.g., template<typename T, T Value> struct Constant; to work properly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65924 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r--lib/Sema/SemaTemplate.cpp125
1 files changed, 81 insertions, 44 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 54f1d87cc8..ed50722d2f 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -85,7 +85,7 @@ bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
return true;
}
-/// AdjustDeclForTemplates - If the given decl happens to be a template, reset
+/// AdjustDeclIfTemplate - If the given decl happens to be a template, reset
/// the parameter D to reference the templated declaration and return a pointer
/// to the template declaration. Otherwise, do nothing to D and return null.
TemplateDecl *Sema::AdjustDeclIfTemplate(DeclTy *&D)
@@ -164,27 +164,13 @@ void Sema::ActOnTypeParameterDefault(DeclTy *TypeParam,
Parm->setDefaultArgument(Default, DefaultLoc, false);
}
-/// ActOnNonTypeTemplateParameter - Called when a C++ non-type
-/// template parameter (e.g., "int Size" in "template<int Size>
-/// class Array") has been parsed. S is the current scope and D is
-/// the parsed declarator.
-Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
- unsigned Depth,
- unsigned Position) {
- QualType T = GetTypeForDeclarator(D, S);
-
- assert(S->isTemplateParamScope() &&
- "Non-type template parameter not in template parameter scope!");
- bool Invalid = false;
-
- IdentifierInfo *ParamName = D.getIdentifier();
- if (ParamName) {
- NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName);
- if (PrevDecl && PrevDecl->isTemplateParameter())
- Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
- PrevDecl);
- }
-
+/// \brief Check that the type of a non-type template parameter is
+/// well-formed.
+///
+/// \returns the (possibly-promoted) parameter type if valid;
+/// otherwise, produces a diagnostic and returns a NULL type.
+QualType
+Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
// C++ [temp.param]p4:
//
// A non-type template-parameter shall have one of the following
@@ -202,9 +188,8 @@ Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
T->isMemberPointerType() ||
// If T is a dependent type, we can't do the check now, so we
// assume that it is well-formed.
- T->isDependentType()) {
- // Okay: The template parameter is well-formed.
- }
+ T->isDependentType())
+ return T;
// C++ [temp.param]p8:
//
// A non-type template-parameter of type "array of T" or
@@ -212,16 +197,42 @@ Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
// T" or "pointer to function returning T", respectively.
else if (T->isArrayType())
// FIXME: Keep the type prior to promotion?
- T = Context.getArrayDecayedType(T);
+ return Context.getArrayDecayedType(T);
else if (T->isFunctionType())
// FIXME: Keep the type prior to promotion?
- T = Context.getPointerType(T);
- else {
- Diag(D.getIdentifierLoc(), diag::err_template_nontype_parm_bad_type)
- << T;
- return 0;
+ return Context.getPointerType(T);
+
+ Diag(Loc, diag::err_template_nontype_parm_bad_type)
+ << T;
+
+ return QualType();
+}
+
+/// ActOnNonTypeTemplateParameter - Called when a C++ non-type
+/// template parameter (e.g., "int Size" in "template<int Size>
+/// class Array") has been parsed. S is the current scope and D is
+/// the parsed declarator.
+Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
+ unsigned Depth,
+ unsigned Position) {
+ QualType T = GetTypeForDeclarator(D, S);
+
+ assert(S->isTemplateParamScope() &&
+ "Non-type template parameter not in template parameter scope!");
+ bool Invalid = false;
+
+ IdentifierInfo *ParamName = D.getIdentifier();
+ if (ParamName) {
+ NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName);
+ if (PrevDecl && PrevDecl->isTemplateParameter())
+ Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
+ PrevDecl);
}
+ T = CheckNonTypeTemplateParameterType(T, D.getIdentifierLoc());
+ if (T.isNull())
+ T = Context.IntTy; // Recover with an 'int' type.
+
NonTypeTemplateParmDecl *Param
= NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(),
Depth, Position, ParamName, T);
@@ -250,7 +261,7 @@ void Sema::ActOnNonTypeTemplateParameterDefault(DeclTy *TemplateParamD,
// FIXME: Implement this check! Needs a recursive walk over the types.
// Check the well-formedness of the default template argument.
- if (CheckTemplateArgument(TemplateParm, Default)) {
+ if (CheckTemplateArgument(TemplateParm, TemplateParm->getType(), Default)) {
TemplateParm->setInvalidDecl();
return;
}
@@ -774,6 +785,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if (!NTTP->hasDefaultArgument())
break;
+ // FIXME: Instantiate default argument
ArgExpr = NTTP->getDefaultArgument();
ArgLoc = NTTP->getDefaultArgumentLoc();
} else {
@@ -783,6 +795,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if (!TempParm->hasDefaultArgument())
break;
+ // FIXME: Instantiate default argument
ArgExpr = TempParm->getDefaultArgument();
ArgLoc = TempParm->getDefaultArgumentLoc();
}
@@ -822,8 +835,30 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
} else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
// Check non-type template parameters.
+
+ // Instantiate the type of the non-type template parameter with
+ // the template arguments we've seen thus far.
+ QualType NTTPType = NTTP->getType();
+ if (NTTPType->isDependentType()) {
+ // Instantiate the type of the non-type template parameter.
+ NTTPType = InstantiateType(NTTPType,
+ &Converted[0], Converted.size(),
+ NTTP->getLocation(),
+ NTTP->getDeclName());
+ // If that worked, check the non-type template parameter type
+ // for validity.
+ if (!NTTPType.isNull())
+ NTTPType = CheckNonTypeTemplateParameterType(NTTPType,
+ NTTP->getLocation());
+
+ if (NTTPType.isNull()) {
+ Invalid = true;
+ break;
+ }
+ }
+
if (ArgExpr) {
- if (CheckTemplateArgument(NTTP, ArgExpr, &Converted))
+ if (CheckTemplateArgument(NTTP, NTTPType, ArgExpr, &Converted))
Invalid = true;
continue;
}
@@ -1062,18 +1097,20 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
/// \brief Check a template argument against its corresponding
/// non-type template parameter.
///
-/// This routine implements the semantics of C++ [temp.arg.nontype].
-/// It returns true if an error occurred, and false otherwise.
+/// This routine implements the semantics of C++ [temp.arg.nontype].
+/// It returns true if an error occurred, and false otherwise. \p
+/// InstantiatedParamType is the type of the non-type template
+/// parameter after it has been instantiated.
///
/// 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,
+ QualType InstantiatedParamType, 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())
+ if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent())
return false;
// C++ [temp.arg.nontype]p5:
@@ -1086,7 +1123,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// -- for a non-type template-parameter of integral or
// enumeration type, integral promotions (4.5) and integral
// conversions (4.7) are applied.
- QualType ParamType = Param->getType();
+ QualType ParamType = InstantiatedParamType;
QualType ArgType = Arg->getType();
if (ParamType->isIntegralType() || ParamType->isEnumeralType()) {
// C++ [temp.arg.nontype]p1:
@@ -1130,7 +1167,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// We can't perform this conversion.
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_convertible)
- << Arg->getType() << Param->getType() << Arg->getSourceRange();
+ << Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
@@ -1202,7 +1239,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// We can't perform this conversion.
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_convertible)
- << Arg->getType() << Param->getType() << Arg->getSourceRange();
+ << Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
@@ -1248,7 +1285,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// We can't perform this conversion.
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_convertible)
- << Arg->getType() << Param->getType() << Arg->getSourceRange();
+ << Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
@@ -1276,7 +1313,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (!Context.hasSameUnqualifiedType(ParamRefType->getPointeeType(), ArgType)) {
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_no_ref_bind)
- << Param->getType() << Arg->getType()
+ << InstantiatedParamType << Arg->getType()
<< Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
return true;
@@ -1289,7 +1326,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if ((ParamQuals | ArgQuals) != ParamQuals) {
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_ref_bind_ignores_quals)
- << Param->getType() << Arg->getType()
+ << InstantiatedParamType << Arg->getType()
<< Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
return true;
@@ -1317,7 +1354,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// We can't perform this conversion.
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_convertible)
- << Arg->getType() << Param->getType() << Arg->getSourceRange();
+ << Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}