forked from OSchip/llvm-project
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. llvm-svn: 65924
This commit is contained in:
parent
9c51e8f962
commit
463421deb1
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -311,6 +311,69 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
|
|||
return false;
|
||||
}
|
||||
|
||||
/// \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,
|
||||
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()) {
|
||||
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()) {
|
||||
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 0;
|
||||
|
||||
// If the base class is polymorphic, the new one is, too.
|
||||
RecordDecl *BaseDecl = BaseType->getAsRecordType()->getDecl();
|
||||
assert(BaseDecl && "Record type has no declaration");
|
||||
BaseDecl = BaseDecl->getDefinition(Context);
|
||||
assert(BaseDecl && "Base type is not incomplete, but has no definition");
|
||||
if (cast<CXXRecordDecl>(BaseDecl)->isPolymorphic())
|
||||
Class->setPolymorphic(true);
|
||||
|
||||
// C++ [dcl.init.aggr]p1:
|
||||
// An aggregate is [...] a class with [...] no base classes [...].
|
||||
Class->setAggregate(false);
|
||||
Class->setPOD(false);
|
||||
|
||||
// Create the base specifier.
|
||||
// FIXME: Allocate via ASTContext?
|
||||
return new CXXBaseSpecifier(SpecifierRange, Virtual,
|
||||
Class->getTagKind() == RecordDecl::TK_class,
|
||||
Access, BaseType);
|
||||
}
|
||||
|
||||
/// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is
|
||||
/// one entry in the base class list of a class specifier, for
|
||||
/// example:
|
||||
|
@ -320,56 +383,22 @@ Sema::BaseResult
|
|||
Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
|
||||
bool Virtual, AccessSpecifier Access,
|
||||
TypeTy *basetype, SourceLocation BaseLoc) {
|
||||
CXXRecordDecl *Decl = (CXXRecordDecl*)classdecl;
|
||||
CXXRecordDecl *Class = (CXXRecordDecl*)classdecl;
|
||||
QualType BaseType = QualType::getFromOpaquePtr(basetype);
|
||||
|
||||
// Base specifiers must be record types.
|
||||
if (!BaseType->isRecordType())
|
||||
return Diag(BaseLoc, diag::err_base_must_be_class) << SpecifierRange;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
// If the base class is polymorphic, the new one is, too.
|
||||
RecordDecl *BaseDecl = BaseType->getAsRecordType()->getDecl();
|
||||
assert(BaseDecl && "Record type has no declaration");
|
||||
BaseDecl = BaseDecl->getDefinition(Context);
|
||||
assert(BaseDecl && "Base type is not incomplete, but has no definition");
|
||||
if (cast<CXXRecordDecl>(BaseDecl)->isPolymorphic())
|
||||
Decl->setPolymorphic(true);
|
||||
|
||||
// C++ [dcl.init.aggr]p1:
|
||||
// An aggregate is [...] a class with [...] no base classes [...].
|
||||
Decl->setAggregate(false);
|
||||
Decl->setPOD(false);
|
||||
|
||||
// Create the base specifier.
|
||||
return new CXXBaseSpecifier(SpecifierRange, Virtual,
|
||||
BaseType->isClassType(), Access, BaseType);
|
||||
if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange,
|
||||
Virtual, Access,
|
||||
BaseType, BaseLoc))
|
||||
return BaseSpec;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 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;
|
||||
/// \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
|
||||
|
|
|
@ -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,6 +164,50 @@ void Sema::ActOnTypeParameterDefault(DeclTy *TypeParam,
|
|||
Parm->setDefaultArgument(Default, DefaultLoc, false);
|
||||
}
|
||||
|
||||
/// \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
|
||||
// (optionally cv-qualified) types:
|
||||
//
|
||||
// -- integral or enumeration type,
|
||||
if (T->isIntegralType() || T->isEnumeralType() ||
|
||||
// -- pointer to object or pointer to function,
|
||||
(T->isPointerType() &&
|
||||
(T->getAsPointerType()->getPointeeType()->isObjectType() ||
|
||||
T->getAsPointerType()->getPointeeType()->isFunctionType())) ||
|
||||
// -- reference to object or reference to function,
|
||||
T->isReferenceType() ||
|
||||
// -- pointer to member.
|
||||
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())
|
||||
return T;
|
||||
// C++ [temp.param]p8:
|
||||
//
|
||||
// A non-type template-parameter of type "array of T" or
|
||||
// "function returning T" is adjusted to be of type "pointer to
|
||||
// T" or "pointer to function returning T", respectively.
|
||||
else if (T->isArrayType())
|
||||
// FIXME: Keep the type prior to promotion?
|
||||
return Context.getArrayDecayedType(T);
|
||||
else if (T->isFunctionType())
|
||||
// FIXME: Keep the type prior to promotion?
|
||||
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
|
||||
|
@ -185,42 +229,9 @@ Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
|
|||
PrevDecl);
|
||||
}
|
||||
|
||||
// C++ [temp.param]p4:
|
||||
//
|
||||
// A non-type template-parameter shall have one of the following
|
||||
// (optionally cv-qualified) types:
|
||||
//
|
||||
// -- integral or enumeration type,
|
||||
if (T->isIntegralType() || T->isEnumeralType() ||
|
||||
// -- pointer to object or pointer to function,
|
||||
(T->isPointerType() &&
|
||||
(T->getAsPointerType()->getPointeeType()->isObjectType() ||
|
||||
T->getAsPointerType()->getPointeeType()->isFunctionType())) ||
|
||||
// -- reference to object or reference to function,
|
||||
T->isReferenceType() ||
|
||||
// -- pointer to member.
|
||||
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.
|
||||
}
|
||||
// C++ [temp.param]p8:
|
||||
//
|
||||
// A non-type template-parameter of type "array of T" or
|
||||
// "function returning T" is adjusted to be of type "pointer to
|
||||
// T" or "pointer to function returning T", respectively.
|
||||
else if (T->isArrayType())
|
||||
// FIXME: Keep the type prior to promotion?
|
||||
T = 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;
|
||||
}
|
||||
T = CheckNonTypeTemplateParameterType(T, D.getIdentifierLoc());
|
||||
if (T.isNull())
|
||||
T = Context.IntTy; // Recover with an 'int' type.
|
||||
|
||||
NonTypeTemplateParmDecl *Param
|
||||
= NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(),
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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}}
|
||||
A<double> *a2)
|
||||
{
|
||||
(void)a1->x; // expected-error{{incomplete definition of type 'A<double, double>'}}
|
||||
(void)a2->x; // expected-error{{incomplete definition of type 'A<double>'}}
|
||||
(void)a2->x; // expected-error{{implicit instantiation of undefined template 'struct A'}}
|
||||
}
|
||||
|
||||
typedef float FLOAT;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// RUN: clang -fsyntax-only -verify %s
|
||||
|
||||
template<typename T, T Value> struct Constant; // expected-note{{template parameter is declared here}} \
|
||||
// FIXME: bad location expected-error{{a non-type template parameter cannot have type 'float'}}
|
||||
|
||||
Constant<int, 5> *c1;
|
||||
|
||||
int x;
|
||||
float f(int, double);
|
||||
|
||||
Constant<int&, x> *c2;
|
||||
Constant<int*, &x> *c3;
|
||||
Constant<float (*)(int, double), f> *c4;
|
||||
Constant<float (*)(int, double), &f> *c5;
|
||||
|
||||
Constant<float (*)(int, int), f> *c6; // expected-error{{non-type template argument of type 'float (*)(int, double)' cannot be converted to a value of type 'float (*)(int, int)'}}
|
||||
|
||||
Constant<float, 0> *c7;
|
Loading…
Reference in New Issue