aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclTemplate.h4
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.def4
-rw-r--r--lib/AST/DeclCXX.cpp1
-rw-r--r--lib/Sema/Sema.h21
-rw-r--r--lib/Sema/SemaDecl.cpp13
-rw-r--r--lib/Sema/SemaDeclCXX.cpp135
-rw-r--r--lib/Sema/SemaTemplate.cpp125
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp121
-rw-r--r--lib/Sema/SemaType.cpp18
-rw-r--r--test/SemaTemplate/class-template-id-2.cpp7
-rw-r--r--test/SemaTemplate/class-template-spec.cpp6
-rw-r--r--test/SemaTemplate/instantiation-default-2.cpp18
12 files changed, 371 insertions, 102 deletions
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 92c2d6b8f6..d93bbf5562 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -590,6 +590,10 @@ public:
return template_arg_begin() + NumTemplateArgs;
}
+ const TemplateArgument *getTemplateArgs() const {
+ return template_arg_begin();
+ }
+
unsigned getNumTemplateArgs() const { return NumTemplateArgs; }
/// \brief Determine the kind of specialization that this
diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def
index 781daad31a..042b155479 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.def
+++ b/include/clang/Basic/DiagnosticSemaKinds.def
@@ -627,6 +627,10 @@ DIAG(err_template_spec_redecl_out_of_scope, ERROR,
DIAG(err_template_spec_redecl_global_scope, ERROR,
"class template specialization of %0 must occur in at global scope")
+// C++ Template Instantiation
+DIAG(err_template_implicit_instantiate_undefined, ERROR,
+ "implicit instantiation of undefined template %0")
+
DIAG(err_unexpected_typedef, ERROR,
"unexpected type name %0: expected expression")
DIAG(err_unexpected_namespace, ERROR,
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index b1394fe788..45a3372ada 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -52,6 +52,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
if (this->Bases)
delete [] this->Bases;
+ // FIXME: allocate using the ASTContext
this->Bases = new CXXBaseSpecifier[NumBases];
this->NumBases = NumBases;
for (unsigned i = 0; i < NumBases; ++i)
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index b9cce4b215..77f2a3d8b6 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1501,11 +1501,19 @@ public:
//
/// ActOnBaseSpecifier - Parsed a base specifier
+ CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class,
+ SourceRange SpecifierRange,
+ bool Virtual, AccessSpecifier Access,
+ QualType BaseType,
+ SourceLocation BaseLoc);
virtual BaseResult ActOnBaseSpecifier(DeclTy *classdecl,
SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
- TypeTy *basetype, SourceLocation BaseLoc);
+ TypeTy *basetype, SourceLocation
+ BaseLoc);
+ bool AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
+ unsigned NumBases);
virtual void ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases,
unsigned NumBases);
@@ -1542,6 +1550,7 @@ public:
SourceLocation DefaultLoc,
TypeTy *Default);
+ QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc);
virtual DeclTy *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
unsigned Depth,
unsigned Position);
@@ -1615,7 +1624,8 @@ public:
bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
NamedDecl *&Entity);
bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member);
- bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Expr *&Arg,
+ bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
+ QualType InstantiatedParamType, Expr *&Arg,
llvm::SmallVectorImpl<TemplateArgument> *Converted = 0);
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg);
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
@@ -1634,6 +1644,13 @@ public:
QualType InstantiateType(QualType T, const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceLocation Loc, DeclarationName Entity);
+ bool
+ InstantiateBaseSpecifiers(ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ ClassTemplateDecl *ClassTemplate);
+ bool
+ InstantiateClassTemplateSpecialization(
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ bool ExplicitInstantiation);
// Objective-C declarations.
virtual DeclTy *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 33e3921688..8d32578c98 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2174,13 +2174,16 @@ void Sema::ActOnUninitializedDecl(DeclTy *dcl) {
if (Var->getStorageClass() != VarDecl::Extern &&
Var->getStorageClass() != VarDecl::PrivateExtern &&
InitType->isRecordType()) {
- const CXXConstructorDecl *Constructor
- = PerformInitializationByConstructor(InitType, 0, 0,
- Var->getLocation(),
+ const CXXConstructorDecl *Constructor = 0;
+ if (!DiagnoseIncompleteType(Var->getLocation(), InitType,
+ diag::err_invalid_incomplete_type_use))
+ Constructor
+ = PerformInitializationByConstructor(InitType, 0, 0,
+ Var->getLocation(),
SourceRange(Var->getLocation(),
Var->getLocation()),
- Var->getDeclName(),
- IK_Default);
+ Var->getDeclName(),
+ IK_Default);
if (!Constructor)
Var->setInvalidDecl();
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 1c98529fa8..3e8ee5ed1f 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -311,39 +311,48 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
return false;
}
-/// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is
-/// one entry in the base class list of a class specifier, for
-/// example:
-/// class foo : public bar, virtual private baz {
-/// 'public bar' and 'virtual private baz' are each base-specifiers.
-Sema::BaseResult
-Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
+/// \brief Check the validity of a C++ base class specifier.
+///
+/// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics
+/// and returns NULL otherwise.
+CXXBaseSpecifier *
+Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
+ SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
- TypeTy *basetype, SourceLocation BaseLoc) {
- CXXRecordDecl *Decl = (CXXRecordDecl*)classdecl;
- QualType BaseType = QualType::getFromOpaquePtr(basetype);
+ QualType BaseType,
+ SourceLocation BaseLoc) {
+ // C++ [class.union]p1:
+ // A union shall not have base classes.
+ if (Class->isUnion()) {
+ Diag(Class->getLocation(), diag::err_base_clause_on_union)
+ << SpecifierRange;
+ return 0;
+ }
+
+ if (BaseType->isDependentType())
+ return new CXXBaseSpecifier(SpecifierRange, Virtual,
+ Class->getTagKind() == RecordDecl::TK_class,
+ Access, BaseType);
// Base specifiers must be record types.
- if (!BaseType->isRecordType())
- return Diag(BaseLoc, diag::err_base_must_be_class) << SpecifierRange;
+ if (!BaseType->isRecordType()) {
+ Diag(BaseLoc, diag::err_base_must_be_class) << SpecifierRange;
+ return 0;
+ }
// C++ [class.union]p1:
// A union shall not be used as a base class.
- if (BaseType->isUnionType())
- return Diag(BaseLoc, diag::err_union_as_base_class) << SpecifierRange;
-
- // C++ [class.union]p1:
- // A union shall not have base classes.
- if (Decl->isUnion())
- return Diag(Decl->getLocation(), diag::err_base_clause_on_union)
- << SpecifierRange;
+ if (BaseType->isUnionType()) {
+ Diag(BaseLoc, diag::err_union_as_base_class) << SpecifierRange;
+ return 0;
+ }
// C++ [class.derived]p2:
// The class-name in a base-specifier shall not be an incompletely
// defined class.
if (DiagnoseIncompleteType(BaseLoc, BaseType, diag::err_incomplete_base_class,
SpecifierRange))
- return true;
+ return 0;
// If the base class is polymorphic, the new one is, too.
RecordDecl *BaseDecl = BaseType->getAsRecordType()->getDecl();
@@ -351,25 +360,45 @@ Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
BaseDecl = BaseDecl->getDefinition(Context);
assert(BaseDecl && "Base type is not incomplete, but has no definition");
if (cast<CXXRecordDecl>(BaseDecl)->isPolymorphic())
- Decl->setPolymorphic(true);
+ Class->setPolymorphic(true);
// C++ [dcl.init.aggr]p1:
// An aggregate is [...] a class with [...] no base classes [...].
- Decl->setAggregate(false);
- Decl->setPOD(false);
+ Class->setAggregate(false);
+ Class->setPOD(false);
// Create the base specifier.
+ // FIXME: Allocate via ASTContext?
return new CXXBaseSpecifier(SpecifierRange, Virtual,
- BaseType->isClassType(), Access, BaseType);
+ Class->getTagKind() == RecordDecl::TK_class,
+ Access, BaseType);
}
-/// ActOnBaseSpecifiers - Attach the given base specifiers to the
-/// class, after checking whether there are any duplicate base
-/// classes.
-void Sema::ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases,
- unsigned NumBases) {
- if (NumBases == 0)
- return;
+/// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is
+/// one entry in the base class list of a class specifier, for
+/// example:
+/// class foo : public bar, virtual private baz {
+/// 'public bar' and 'virtual private baz' are each base-specifiers.
+Sema::BaseResult
+Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
+ bool Virtual, AccessSpecifier Access,
+ TypeTy *basetype, SourceLocation BaseLoc) {
+ CXXRecordDecl *Class = (CXXRecordDecl*)classdecl;
+ QualType BaseType = QualType::getFromOpaquePtr(basetype);
+ if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange,
+ Virtual, Access,
+ BaseType, BaseLoc))
+ return BaseSpec;
+
+ return true;
+}
+
+/// \brief Performs the actual work of attaching the given base class
+/// specifiers to a C++ class.
+bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
+ unsigned NumBases) {
+ if (NumBases == 0)
+ return false;
// Used to keep track of which base types we have already seen, so
// that we can properly diagnose redundant direct base types. Note
@@ -378,40 +407,56 @@ void Sema::ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases,
std::map<QualType, CXXBaseSpecifier*, QualTypeOrdering> KnownBaseTypes;
// Copy non-redundant base specifiers into permanent storage.
- CXXBaseSpecifier **BaseSpecs = (CXXBaseSpecifier **)Bases;
unsigned NumGoodBases = 0;
+ bool Invalid = false;
for (unsigned idx = 0; idx < NumBases; ++idx) {
QualType NewBaseType
- = Context.getCanonicalType(BaseSpecs[idx]->getType());
+ = Context.getCanonicalType(Bases[idx]->getType());
NewBaseType = NewBaseType.getUnqualifiedType();
if (KnownBaseTypes[NewBaseType]) {
// C++ [class.mi]p3:
// A class shall not be specified as a direct base class of a
// derived class more than once.
- Diag(BaseSpecs[idx]->getSourceRange().getBegin(),
+ Diag(Bases[idx]->getSourceRange().getBegin(),
diag::err_duplicate_base_class)
<< KnownBaseTypes[NewBaseType]->getType()
- << BaseSpecs[idx]->getSourceRange();
+ << Bases[idx]->getSourceRange();
// Delete the duplicate base class specifier; we're going to
// overwrite its pointer later.
- delete BaseSpecs[idx];
+ delete Bases[idx];
+
+ Invalid = true;
} else {
// Okay, add this new base class.
- KnownBaseTypes[NewBaseType] = BaseSpecs[idx];
- BaseSpecs[NumGoodBases++] = BaseSpecs[idx];
+ KnownBaseTypes[NewBaseType] = Bases[idx];
+ Bases[NumGoodBases++] = Bases[idx];
}
}
// Attach the remaining base class specifiers to the derived class.
- CXXRecordDecl *Decl = (CXXRecordDecl*)ClassDecl;
- Decl->setBases(BaseSpecs, NumGoodBases);
+ Class->setBases(Bases, NumGoodBases);
// Delete the remaining (good) base class specifiers, since their
// data has been copied into the CXXRecordDecl.
for (unsigned idx = 0; idx < NumGoodBases; ++idx)
- delete BaseSpecs[idx];
+ delete Bases[idx];
+
+ return Invalid;
+}
+
+/// ActOnBaseSpecifiers - Attach the given base specifiers to the
+/// class, after checking whether there are any duplicate base
+/// classes.
+void Sema::ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases,
+ unsigned NumBases) {
+ if (!ClassDecl || !Bases || !NumBases)
+ return;
+
+ AdjustDeclIfTemplate(ClassDecl);
+ AttachBaseSpecifiers(cast<CXXRecordDecl>((Decl*)ClassDecl),
+ (CXXBaseSpecifier**)(Bases), NumBases);
}
//===----------------------------------------------------------------------===//
@@ -760,11 +805,13 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclTy *TagDecl,
SourceLocation LBrac,
SourceLocation RBrac) {
- AdjustDeclIfTemplate(TagDecl);
+ TemplateDecl *Template = AdjustDeclIfTemplate(TagDecl);
ActOnFields(S, RLoc, TagDecl,
(DeclTy**)FieldCollector->getCurFields(),
FieldCollector->getCurNumFields(), LBrac, RBrac, 0);
- AddImplicitlyDeclaredMembersToClass(cast<CXXRecordDecl>((Decl*)TagDecl));
+
+ if (!Template)
+ AddImplicitlyDeclaredMembersToClass(cast<CXXRecordDecl>((Decl*)TagDecl));
}
/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
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;
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 6b43463777..faeebc0680 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -399,3 +399,124 @@ QualType Sema::InstantiateType(QualType T,
Loc, Entity);
return Instantiator(T);
}
+
+/// \brief Instantiate the base class specifiers of the given class
+/// template specialization.
+///
+/// Produces a diagnostic and returns true on error, returns false and
+/// attaches the instantiated base classes to the class template
+/// specialization if successful.
+bool
+Sema::InstantiateBaseSpecifiers(
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ ClassTemplateDecl *ClassTemplate) {
+ bool Invalid = false;
+ llvm::SmallVector<CXXBaseSpecifier*, 8> InstantiatedBases;
+ for (ClassTemplateSpecializationDecl::base_class_iterator
+ Base = ClassTemplate->getTemplatedDecl()->bases_begin(),
+ BaseEnd = ClassTemplate->getTemplatedDecl()->bases_end();
+ Base != BaseEnd && !Invalid; ++Base) {
+ if (!Base->getType()->isDependentType()) {
+ // FIXME: Allocate via ASTContext
+ InstantiatedBases.push_back(new CXXBaseSpecifier(*Base));
+ continue;
+ }
+
+ QualType BaseType = InstantiateType(Base->getType(),
+ ClassTemplateSpec->getTemplateArgs(),
+ ClassTemplateSpec->getNumTemplateArgs(),
+ Base->getSourceRange().getBegin(),
+ DeclarationName());
+ if (BaseType.isNull()) {
+ Invalid = true;
+ continue;
+ }
+
+ if (CXXBaseSpecifier *InstantiatedBase
+ = CheckBaseSpecifier(ClassTemplateSpec,
+ Base->getSourceRange(),
+ Base->isVirtual(),
+ Base->getAccessSpecifierAsWritten(),
+ BaseType,
+ /*FIXME: Not totally accurate */
+ Base->getSourceRange().getBegin()))
+ InstantiatedBases.push_back(InstantiatedBase);
+ else
+ Invalid = true;
+ }
+
+ if (AttachBaseSpecifiers(ClassTemplateSpec, &InstantiatedBases[0],
+ InstantiatedBases.size()))
+ Invalid = true;
+
+ return Invalid;
+}
+
+bool
+Sema::InstantiateClassTemplateSpecialization(
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ bool ExplicitInstantiation) {
+ // Perform the actual instantiation on the canonical declaration.
+ ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
+ Context.getCanonicalDecl(ClassTemplateSpec));
+
+ // We can only instantiate something that hasn't already been
+ // instantiated or specialized. Fail without any diagnostics: our
+ // caller will provide an error message.
+ if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared)
+ return true;
+
+ // FIXME: Push this class template instantiation onto the
+ // instantiation stack, checking for recursion that exceeds a
+ // certain depth.
+
+ // FIXME: Perform class template partial specialization to select
+ // the best template.
+ ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
+
+ if (!Template->getTemplatedDecl()->getDefinition(Context)) {
+ Diag(ClassTemplateSpec->getLocation(),
+ diag::err_template_implicit_instantiate_undefined)
+ << Context.getTypeDeclType(ClassTemplateSpec);
+ Diag(Template->getTemplatedDecl()->getLocation(),
+ diag::note_template_decl_here);
+ return true;
+ }
+
+ // Note that this is an instantiation.
+ ClassTemplateSpec->setSpecializationKind(
+ ExplicitInstantiation? TSK_ExplicitInstantiation
+ : TSK_ImplicitInstantiation);
+
+
+ bool Invalid = false;
+
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ DeclContext *PreviousContext = CurContext;
+ CurContext = ClassTemplateSpec;
+
+ // Start the definition of this instantiation.
+ ClassTemplateSpec->startDefinition();
+
+ // FIXME: Create the injected-class-name for the
+ // instantiation. Should this be a typedef or something like it?
+
+ // Instantiate the base class specifiers.
+ if (InstantiateBaseSpecifiers(ClassTemplateSpec, Template))
+ Invalid = true;
+
+ // FIXME: Instantiate all of the members.
+
+ // Add any implicitly-declared members that we might need.
+ AddImplicitlyDeclaredMembersToClass(ClassTemplateSpec);
+
+ // Finish the definition of this instantiation.
+ // FIXME: ActOnFields does more checking, which we'll eventually need.
+ ClassTemplateSpec->completeDefinition(Context);
+
+ // Exit the scope of this instantiation.
+ CurContext = PreviousContext;
+
+ return Invalid;
+}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 69cd884300..96d17be931 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -14,6 +14,7 @@
#include "Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/Parse/DeclSpec.h"
using namespace clang;
@@ -473,7 +474,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
/// This routine checks the function type according to C++ rules and
/// under the assumption that the result type and parameter types have
/// just been instantiated from a template. It therefore duplicates
-/// some of the behavior of GetTypeForDeclaration, but in a much
+/// some of the behavior of GetTypeForDeclarator, but in a much
/// simpler form that is only suitable for this narrow use case.
///
/// \param T The return type of the function.
@@ -1033,6 +1034,21 @@ bool Sema::DiagnoseIncompleteType(SourceLocation Loc, QualType T, unsigned diag,
if (!T->isIncompleteType())
return false;
+ // If we have a class template specialization, try to instantiate
+ // it.
+ if (const RecordType *Record = T->getAsRecordType())
+ if (ClassTemplateSpecializationDecl *ClassTemplateSpec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl()))
+ if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) {
+ // Update the class template specialization's location to
+ // refer to the point of instantiation.
+ if (Loc.isValid())
+ ClassTemplateSpec->setLocation(Loc);
+ return InstantiateClassTemplateSpecialization(ClassTemplateSpec,
+ /*ExplicitInstantiation=*/false);
+ }
+
+
if (PrintType.isNull())
PrintType = T;
diff --git a/test/SemaTemplate/class-template-id-2.cpp b/test/SemaTemplate/class-template-id-2.cpp
index dee4735de9..3014208b6e 100644
--- a/test/SemaTemplate/class-template-id-2.cpp
+++ b/test/SemaTemplate/class-template-id-2.cpp
@@ -1,16 +1,17 @@
// RUN: clang -fsyntax-only -verify %s
namespace N {
- template<typename T> class A;
+ template<typename T> class A { };
template<> class A<int> { };
+ template<> class A<float>; // expected-note{{forward declaration of 'class A'}}
+
class B : public A<int> { };
}
class C1 : public N::A<int> { };
-class C2 : public N::A<float> { }; // expected-error{{base class has incomplete type}} \
- // FIXME: expected-note{{forward declaration of 'class A'}}
+class C2 : public N::A<float> { }; // expected-error{{base class has incomplete type}}
struct D1 {
operator N::A<int>();
diff --git a/test/SemaTemplate/class-template-spec.cpp b/test/SemaTemplate/class-template-spec.cpp
index e4900838f1..023ba381ec 100644
--- a/test/SemaTemplate/class-template-spec.cpp
+++ b/test/SemaTemplate/class-template-spec.cpp
@@ -1,5 +1,5 @@
// RUN: clang -fsyntax-only -verify %s
-template<typename T, typename U = int> struct A; // expected-note{{template is declared here}}
+template<typename T, typename U = int> struct A; // expected-note 2{{template is declared here}}
template<> struct A<double, double>; // expected-note{{forward declaration}}
@@ -16,10 +16,10 @@ int test_specs(A<float, float> *a1, A<float, int> *a2) {
}
int test_incomplete_specs(A<double, double> *a1,
- A<double> *a2) // FIXME: expected-note{{forward declaration}}
+