aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorEd Schouten <ed@FreeBSD.org>2009-06-14 09:24:02 +0000
committerEd Schouten <ed@FreeBSD.org>2009-06-14 09:24:02 +0000
commit7ef7bab7e3d06f660b059b903c231f100bb13cc5 (patch)
treed472a7615b5c7e413aa62a77d0777c1a9cf76478 /lib/Sema
parent8ba99c00327a4394e7568244d6cffd6e62625a7a (diff)
downloadsrc-7ef7bab7e3d06f660b059b903c231f100bb13cc5.tar.gz
src-7ef7bab7e3d06f660b059b903c231f100bb13cc5.zip
Import Clang r73340.vendor/clang/clang-r73340
Notes
Notes: svn path=/vendor/clang/dist/; revision=194179 svn path=/vendor/clang/clang-r73340/; revision=194181; tag=vendor/clang/clang-r73340
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/Sema.cpp5
-rw-r--r--lib/Sema/Sema.h229
-rw-r--r--lib/Sema/SemaDecl.cpp16
-rw-r--r--lib/Sema/SemaDeclAttr.cpp3
-rw-r--r--lib/Sema/SemaDeclCXX.cpp15
-rw-r--r--lib/Sema/SemaExpr.cpp19
-rw-r--r--lib/Sema/SemaInherit.cpp6
-rw-r--r--lib/Sema/SemaInit.cpp2
-rw-r--r--lib/Sema/SemaLookup.cpp1
-rw-r--r--lib/Sema/SemaStmt.cpp5
-rw-r--r--lib/Sema/SemaTemplate.cpp439
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp756
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp200
-rw-r--r--lib/Sema/SemaTemplateInstantiateExpr.cpp8
-rw-r--r--lib/Sema/SemaTemplateInstantiateStmt.cpp2
-rw-r--r--lib/Sema/SemaType.cpp154
16 files changed, 1528 insertions, 332 deletions
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index e3cea5be4283..a5f243816abd 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -183,7 +183,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()),
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
- CurrentInstantiationScope(0) {
+ NumSFINAEErrors(0), CurrentInstantiationScope(0) {
StdNamespace = 0;
TUScope = 0;
@@ -316,7 +316,8 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() {
}
Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
- this->Emit();
+ if (!this->Emit())
+ return;
// If this is not a note, and we're in a template instantiation
// that is different from the last template instantiation where
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index c5582935db7f..0607a893da86 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -256,6 +256,9 @@ public:
/// unit.
bool CompleteTranslationUnit;
+ /// \brief The number of SFINAE diagnostics that have been trapped.
+ unsigned NumSFINAEErrors;
+
typedef llvm::DenseMap<Selector, ObjCMethodList> MethodPool;
/// Instance/Factory Method Pools - allows efficient lookup when typechecking
@@ -297,11 +300,38 @@ public:
SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID)
: DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { }
+ explicit SemaDiagnosticBuilder(Sema &SemaRef)
+ : DiagnosticBuilder(DiagnosticBuilder::Suppress), SemaRef(SemaRef) { }
+
~SemaDiagnosticBuilder();
};
/// \brief Emit a diagnostic.
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
+ if (isSFINAEContext() && Diagnostic::isBuiltinSFINAEDiag(DiagID)) {
+ // If we encountered an error during template argument
+ // deduction, and that error is one of the SFINAE errors,
+ // suppress the diagnostic.
+ bool Fatal = false;
+ switch (Diags.getDiagnosticLevel(DiagID)) {
+ case Diagnostic::Ignored:
+ case Diagnostic::Note:
+ case Diagnostic::Warning:
+ break;
+
+ case Diagnostic::Error:
+ ++NumSFINAEErrors;
+ break;
+
+ case Diagnostic::Fatal:
+ Fatal = true;
+ break;
+ }
+
+ if (!Fatal)
+ return SemaDiagnosticBuilder(*this);
+ }
+
DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID);
return SemaDiagnosticBuilder(DB, *this, DiagID);
}
@@ -349,6 +379,11 @@ public:
QualType *ParamTypes, unsigned NumParamTypes,
bool Variadic, unsigned Quals,
SourceLocation Loc, DeclarationName Entity);
+ QualType BuildMemberPointerType(QualType T, QualType Class,
+ unsigned Quals, SourceLocation Loc,
+ DeclarationName Entity);
+ QualType BuildBlockPointerType(QualType T, unsigned Quals,
+ SourceLocation Loc, DeclarationName Entity);
QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0,
TagDecl **OwnedDecl = 0);
DeclarationName GetNameForDeclarator(Declarator &D);
@@ -409,8 +444,14 @@ public:
SourceLocation EqualLoc,
ExprArg defarg);
virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
- SourceLocation EqualLoc);
+ SourceLocation EqualLoc,
+ SourceLocation ArgLoc);
virtual void ActOnParamDefaultArgumentError(DeclPtrTy param);
+
+ // Contains the locations of the beginning of unparsed default
+ // argument locations.
+ llvm::DenseMap<ParmVarDecl *,SourceLocation> UnparsedDefaultArgLocs;
+
virtual void AddInitializerToDecl(DeclPtrTy dcl, FullExprArg init);
void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit);
void ActOnUninitializedDecl(DeclPtrTy dcl);
@@ -1194,7 +1235,9 @@ public:
virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
FullExprArg Cond, StmtArg Body);
virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
- SourceLocation WhileLoc, ExprArg Cond);
+ SourceLocation WhileLoc,
+ SourceLocation CondLParen, ExprArg Cond,
+ SourceLocation CondRParen);
virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc,
SourceLocation LParenLoc,
@@ -1871,7 +1914,8 @@ public:
bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl);
- virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename,
+ virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
+ SourceLocation EllipsisLoc,
SourceLocation KeyLoc,
IdentifierInfo *ParamName,
SourceLocation ParamNameLoc,
@@ -1940,8 +1984,14 @@ public:
ClassTemplateSpecializationDecl *PrevDecl,
SourceLocation TemplateNameLoc,
SourceRange ScopeSpecifierRange,
+ bool PartialSpecialization,
bool ExplicitInstantiation);
+ bool CheckClassTemplatePartialSpecializationArgs(
+ TemplateParameterList *TemplateParams,
+ const TemplateArgumentListBuilder &TemplateArgs,
+ bool &MirrorsPrimaryTemplate);
+
virtual DeclResult
ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
SourceLocation KWLoc,
@@ -1985,6 +2035,10 @@ public:
SourceLocation RAngleLoc,
TemplateArgumentListBuilder &Converted);
+ bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
+ const TemplateArgument &Arg,
+ TemplateArgumentListBuilder &Converted);
+
bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg,
SourceLocation ArgLoc);
bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
@@ -1992,7 +2046,7 @@ public:
bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member);
bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType InstantiatedParamType, Expr *&Arg,
- TemplateArgumentListBuilder *Converted = 0);
+ TemplateArgument &Converted);
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg);
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
TemplateParameterList *Old,
@@ -2031,10 +2085,122 @@ public:
const IdentifierInfo &II,
SourceRange Range);
- TemplateArgumentList *
+ /// \brief Describes the result of template argument deduction.
+ ///
+ /// The TemplateDeductionResult enumeration describes the result of
+ /// template argument deduction, as returned from
+ /// DeduceTemplateArguments(). The separate TemplateDeductionInfo
+ /// structure provides additional information about the results of
+ /// template argument deduction, e.g., the deduced template argument
+ /// list (if successful) or the specific template parameters or
+ /// deduced arguments that were involved in the failure.
+ enum TemplateDeductionResult {
+ /// \brief Template argument deduction was successful.
+ TDK_Success = 0,
+ /// \brief Template argument deduction exceeded the maximum template
+ /// instantiation depth (which has already been diagnosed).
+ TDK_InstantiationDepth,
+ /// \brief Template argument deduction did not deduce a value
+ /// for every template parameter.
+ TDK_Incomplete,
+ /// \brief Template argument deduction produced inconsistent
+ /// deduced values for the given template parameter.
+ TDK_Inconsistent,
+ /// \brief Template argument deduction failed due to inconsistent
+ /// cv-qualifiers on a template parameter type that would
+ /// otherwise be deduced, e.g., we tried to deduce T in "const T"
+ /// but were given a non-const "X".
+ TDK_InconsistentQuals,
+ /// \brief Substitution of the deduced template argument values
+ /// resulted in an error.
+ TDK_SubstitutionFailure,
+ /// \brief Substitution of the deduced template argument values
+ /// into a non-deduced context produced a type or value that
+ /// produces a type that does not match the original template
+ /// arguments provided.
+ TDK_NonDeducedMismatch
+ };
+
+ /// \brief Provides information about an attempted template argument
+ /// deduction, whose success or failure was described by a
+ /// TemplateDeductionResult value.
+ class TemplateDeductionInfo {
+ /// \brief The context in which the template arguments are stored.
+ ASTContext &Context;
+
+ /// \brief The deduced template argument list.
+ ///
+ TemplateArgumentList *Deduced;
+
+ // do not implement these
+ TemplateDeductionInfo(const TemplateDeductionInfo&);
+ TemplateDeductionInfo &operator=(const TemplateDeductionInfo&);
+
+ public:
+ TemplateDeductionInfo(ASTContext &Context) : Context(Context), Deduced(0) { }
+
+ ~TemplateDeductionInfo() {
+ // FIXME: if (Deduced) Deduced->Destroy(Context);
+ }
+
+ /// \brief Take ownership of the deduced template argument list.
+ TemplateArgumentList *take() {
+ TemplateArgumentList *Result = Deduced;
+ Deduced = 0;
+ return Result;
+ }
+
+ /// \brief Provide a new template argument list that contains the
+ /// results of template argument deduction.
+ void reset(TemplateArgumentList *NewDeduced) {
+ // FIXME: if (Deduced) Deduced->Destroy(Context);
+ Deduced = NewDeduced;
+ }
+
+ /// \brief The template parameter to which a template argument
+ /// deduction failure refers.
+ ///
+ /// Depending on the result of template argument deduction, this
+ /// template parameter may have different meanings:
+ ///
+ /// TDK_Incomplete: this is the first template parameter whose
+ /// corresponding template argument was not deduced.
+ ///
+ /// TDK_Inconsistent: this is the template parameter for which
+ /// two different template argument values were deduced.
+ TemplateParameter Param;
+
+ /// \brief The first template argument to which the template
+ /// argument deduction failure refers.
+ ///
+ /// Depending on the result of the template argument deduction,
+ /// this template argument may have different meanings:
+ ///
+ /// TDK_Inconsistent: this argument is the first value deduced
+ /// for the corresponding template parameter.
+ ///
+ /// TDK_SubstitutionFailure: this argument is the template
+ /// argument we were instantiating when we encountered an error.
+ ///
+ /// TDK_NonDeducedMismatch: this is the template argument
+ /// provided in the source code.
+ TemplateArgument FirstArg;
+
+ /// \brief The second template argument to which the template
+ /// argument deduction failure refers.
+ ///
+ /// FIXME: Finish documenting this.
+ TemplateArgument SecondArg;
+ };
+
+ TemplateDeductionResult
DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
- const TemplateArgumentList &TemplateArgs);
-
+ const TemplateArgumentList &TemplateArgs,
+ TemplateDeductionInfo &Info);
+
+ void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
+ llvm::SmallVectorImpl<bool> &Deduced);
+
//===--------------------------------------------------------------------===//
// C++ Template Instantiation
//
@@ -2053,7 +2219,16 @@ public:
/// parameter. The Entity is the template, and
/// TemplateArgs/NumTemplateArguments provides the template
/// arguments as specified.
- DefaultTemplateArgumentInstantiation
+ /// FIXME: Use a TemplateArgumentList
+ DefaultTemplateArgumentInstantiation,
+
+ /// We are performing template argument deduction for a class
+ /// template partial specialization. The Entity is the class
+ /// template partial specialization, and
+ /// TemplateArgs/NumTemplateArgs provides the deduced template
+ /// arguments.
+ /// FIXME: Use a TemplateArgumentList
+ PartialSpecDeductionInstantiation
} Kind;
/// \brief The point of instantiation within the source code.
@@ -2087,6 +2262,7 @@ public:
return true;
case DefaultTemplateArgumentInstantiation:
+ case PartialSpecDeductionInstantiation:
return X.TemplateArgs == Y.TemplateArgs;
}
@@ -2143,6 +2319,15 @@ public:
unsigned NumTemplateArgs,
SourceRange InstantiationRange = SourceRange());
+ /// \brief Note that we are instantiating as part of template
+ /// argument deduction for a class template partial
+ /// specialization.
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ClassTemplatePartialSpecializationDecl *PartialSpec,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange = SourceRange());
+
/// \brief Note that we have finished instantiating this template.
void Clear();
@@ -2167,6 +2352,32 @@ public:
void PrintInstantiationStack();
+ /// \brief Determines whether we are currently in a context where
+ /// template argument substitution failures are not considered
+ /// errors.
+ ///
+ /// When this routine returns true, the emission of most diagnostics
+ /// will be suppressed and there will be no local error recovery.
+ bool isSFINAEContext() const;
+
+ /// \brief RAII class used to determine whether SFINAE has
+ /// trapped any errors that occur during template argument
+ /// deduction.
+ class SFINAETrap {
+ Sema &SemaRef;
+ unsigned PrevSFINAEErrors;
+ public:
+ explicit SFINAETrap(Sema &SemaRef)
+ : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors) { }
+
+ ~SFINAETrap() { SemaRef.NumSFINAEErrors = PrevSFINAEErrors; }
+
+ /// \brief Determine whether any SFINAE errors have been trapped.
+ bool hasErrorOccurred() const {
+ return SemaRef.NumSFINAEErrors > PrevSFINAEErrors;
+ }
+ };
+
/// \brief A stack-allocated class that identifies which local
/// variable declaration instantiations are present in this scope.
///
@@ -2285,6 +2496,8 @@ public:
TemplateName
InstantiateTemplateName(TemplateName Name, SourceLocation Loc,
const TemplateArgumentList &TemplateArgs);
+ TemplateArgument Instantiate(TemplateArgument Arg,
+ const TemplateArgumentList &TemplateArgs);
void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c67af295c18c..b995717ac87c 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -416,14 +416,14 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
if (Context.BuiltinInfo.hasVAListUse(BID))
InitBuiltinVaListType();
- Builtin::Context::GetBuiltinTypeError Error;
- QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context, Error);
+ ASTContext::GetBuiltinTypeError Error;
+ QualType R = Context.GetBuiltinType(BID, Error);
switch (Error) {
- case Builtin::Context::GE_None:
+ case ASTContext::GE_None:
// Okay
break;
- case Builtin::Context::GE_Missing_FILE:
+ case ASTContext::GE_Missing_FILE:
if (ForRedeclaration)
Diag(Loc, diag::err_implicit_decl_requires_stdio)
<< Context.BuiltinInfo.GetName(BID);
@@ -3208,7 +3208,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
if (Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx, HasVAListArg)) {
if (!FD->getAttr<FormatAttr>())
FD->addAttr(::new (Context) FormatAttr("printf", FormatIdx + 1,
- FormatIdx + 2));
+ HasVAListArg ? 0 : FormatIdx + 2));
}
// Mark const if we don't care about errno and that is the only
@@ -3239,10 +3239,12 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
// FIXME: We known better than our headers.
const_cast<FormatAttr *>(Format)->setType("printf");
} else
- FD->addAttr(::new (Context) FormatAttr("printf", 1, 2));
+ FD->addAttr(::new (Context) FormatAttr("printf", 1,
+ Name->isStr("NSLogv") ? 0 : 2));
} else if (Name->isStr("asprintf") || Name->isStr("vasprintf")) {
if (!FD->getAttr<FormatAttr>())
- FD->addAttr(::new (Context) FormatAttr("printf", 2, 3));
+ FD->addAttr(::new (Context) FormatAttr("printf", 2,
+ Name->isStr("vasprintf") ? 0 : 3));
}
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 99b4d77fad42..1afdb6011dff 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -1699,6 +1699,9 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
/// the attribute applies to decls. If the attribute is a type attribute, just
/// silently ignore it.
static void ProcessDeclAttribute(Decl *D, const AttributeList &Attr, Sema &S) {
+ if (Attr.isDeclspecAttribute())
+ // FIXME: Try to deal with __declspec attributes!
+ return;
switch (Attr.getKind()) {
case AttributeList::AT_IBOutlet: HandleIBOutletAttr (D, Attr, S); break;
case AttributeList::AT_address_space:
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index b59ac879d190..8f64e78c522b 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -108,6 +108,8 @@ void
Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc,
ExprArg defarg) {
ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>());
+ UnparsedDefaultArgLocs.erase(Param);
+
ExprOwningPtr<Expr> DefaultArg(this, defarg.takeAs<Expr>());
QualType ParamType = Param->getType();
@@ -154,16 +156,23 @@ Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc,
/// because we're inside a class definition. Note that this default
/// argument will be parsed later.
void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
- SourceLocation EqualLoc) {
+ SourceLocation EqualLoc,
+ SourceLocation ArgLoc) {
ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>());
if (Param)
Param->setUnparsedDefaultArg();
+
+ UnparsedDefaultArgLocs[Param] = ArgLoc;
}
/// ActOnParamDefaultArgumentError - Parsing or semantic analysis of
/// the default argument for the parameter param failed.
void Sema::ActOnParamDefaultArgumentError(DeclPtrTy param) {
- cast<ParmVarDecl>(param.getAs<Decl>())->setInvalidDecl();
+ ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>());
+
+ Param->setInvalidDecl();
+
+ UnparsedDefaultArgLocs.erase(Param);
}
/// CheckExtraCXXDefaultArguments - Check for any extra default
@@ -285,7 +294,7 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
// in a semantically valid state.
for (p = 0; p <= LastMissingDefaultArg; ++p) {
ParmVarDecl *Param = FD->getParamDecl(p);
- if (Param->getDefaultArg()) {
+ if (Param->hasDefaultArg()) {
if (!Param->hasUnparsedDefaultArg())
Param->getDefaultArg()->Destroy(Context);
Param->setDefaultArg(0);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index da32d4ec1061..c01c812be601 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1177,7 +1177,12 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
ValueDependent = true;
// - a constant with integral or enumeration type and is
// initialized with an expression that is value-dependent
- // (FIXME!).
+ else if (const VarDecl *Dcl = dyn_cast<VarDecl>(VD)) {
+ if (Dcl->getType().getCVRQualifiers() == QualType::Const &&
+ Dcl->getInit()) {
+ ValueDependent = Dcl->getInit()->isValueDependent();
+ }
+ }
}
return Owned(BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc,
@@ -2479,9 +2484,19 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// Pass the argument.
if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
return true;
- } else
+ } else {
+ if (FDecl->getParamDecl(i)->hasUnparsedDefaultArg()) {
+ Diag (Call->getSourceRange().getBegin(),
+ diag::err_use_of_default_argument_to_function_declared_later) <<
+ FDecl << cast<CXXRecordDecl>(FDecl->getDeclContext())->getDeclName();
+ Diag(UnparsedDefaultArgLocs[FDecl->getParamDecl(i)],
+ diag::note_default_argument_declared_here);
+ }
+
// We already type-checked the argument, so we know it works.
Arg = new (Context) CXXDefaultArgExpr(FDecl->getParamDecl(i));
+ }
+
QualType ArgType = Arg->getType();
Call->setArg(i, Arg);
diff --git a/lib/Sema/SemaInherit.cpp b/lib/Sema/SemaInherit.cpp
index 1b968f0fbcce..28ca5f64ef59 100644
--- a/lib/Sema/SemaInherit.cpp
+++ b/lib/Sema/SemaInherit.cpp
@@ -138,6 +138,12 @@ bool Sema::LookupInBases(CXXRecordDecl *Class,
// Find the record of the base class subobjects for this type.
QualType BaseType = Context.getCanonicalType(BaseSpec->getType());
BaseType = BaseType.getUnqualifiedType();
+
+ // If a base class of the class template depends on a template-parameter,
+ // the base class scope is not examined during unqualified name lookup.
+ // [temp.dep]p3.
+ if (BaseType->isDependentType())
+ continue;
// Determine whether we need to visit this base class at all,
// updating the count of subobjects appropriately.
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 4e0eb1d431fe..45085962d488 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -674,7 +674,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
// compatible structure or union type. In the latter case, the
// initial value of the object, including unnamed members, is
// that of the expression.
- if (ElemType->isRecordType() &&
+ if ((ElemType->isRecordType() || ElemType->isVectorType()) &&
SemaRef.Context.hasSameUnqualifiedType(expr->getType(), ElemType)) {
UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
++Index;
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 6212449744ca..1d26845fd8e4 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/Parse/DeclSpec.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 15262e9c3ac2..aa9b8db0c9f2 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -568,7 +568,8 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, StmtArg Body) {
Action::OwningStmtResult
Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
- SourceLocation WhileLoc, ExprArg Cond) {
+ SourceLocation WhileLoc, SourceLocation CondLParen,
+ ExprArg Cond, SourceLocation CondRParen) {
Expr *condExpr = Cond.takeAs<Expr>();
assert(condExpr && "ActOnDoStmt(): missing expression");
@@ -588,7 +589,7 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
Cond.release();
return Owned(new (Context) DoStmt(Body.takeAs<Stmt>(), condExpr, DoLoc,
- WhileLoc));
+ WhileLoc, CondRParen));
}
Action::OwningStmtResult
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index f9176ca470c0..b2a82ed74d51 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -140,7 +140,8 @@ TemplateDecl *Sema::AdjustDeclIfTemplate(DeclPtrTy &D) {
/// ParamName is the location of the parameter name (if any).
/// If the type parameter has a default argument, it will be added
/// later via ActOnTypeParameterDefault.
-Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename,
+Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
+ SourceLocation EllipsisLoc,
SourceLocation KeyLoc,
IdentifierInfo *ParamName,
SourceLocation ParamNameLoc,
@@ -162,7 +163,8 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename,
TemplateTypeParmDecl *Param
= TemplateTypeParmDecl::Create(Context, CurContext, Loc,
- Depth, Position, ParamName, Typename);
+ Depth, Position, ParamName, Typename,
+ Ellipsis);
if (Invalid)
Param->setInvalidDecl();
@@ -185,6 +187,14 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam,
= cast<TemplateTypeParmDecl>(TypeParam.getAs<Decl>());
QualType Default = QualType::getFromOpaquePtr(DefaultT);
+ // C++0x [temp.param]p9:
+ // A default template-argument may be specified for any kind of
+ // template-parameter that is not a template parameter pack.
+ if (Parm->isParameterPack()) {
+ Diag(DefaultLoc, diag::err_template_param_pack_default_arg);
+ return;
+ }
+
// C++ [temp.param]p14:
// A template-parameter shall not be used in its own default argument.
// FIXME: Implement this check! Needs a recursive walk over the types.
@@ -297,7 +307,9 @@ void Sema::ActOnNonTypeTemplateParameterDefault(DeclPtrTy TemplateParamD,
// FIXME: Implement this check! Needs a recursive walk over the types.
// Check the well-formedness of the default template argument.
- if (CheckTemplateArgument(TemplateParm, TemplateParm->getType(), Default)) {
+ TemplateArgument Converted;
+ if (CheckTemplateArgument(TemplateParm, TemplateParm->getType(), Default,
+ Converted)) {
TemplateParm->setInvalidDecl();
return;
}
@@ -579,6 +591,9 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
bool SawDefaultArgument = false;
SourceLocation PreviousDefaultArgLoc;
+ bool SawParameterPack = false;
+ SourceLocation ParameterPackLoc;
+
// Dummy initialization to avoid warnings.
TemplateParameterList::iterator OldParam = NewParams->end();
if (OldParams)
@@ -595,13 +610,27 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
// Variables used to diagnose missing default arguments
bool MissingDefaultArg = false;
+ // C++0x [temp.param]p11:
+ // If a template parameter of a class template is a template parameter pack,
+ // it must be the last template parameter.
+ if (SawParameterPack) {
+ Diag(ParameterPackLoc,
+ diag::err_template_param_pack_must_be_last_template_parameter);
+ Invalid = true;
+ }
+
// Merge default arguments for template type parameters.
if (TemplateTypeParmDecl *NewTypeParm
= dyn_cast<TemplateTypeParmDecl>(*NewParam)) {
TemplateTypeParmDecl *OldTypeParm
= OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0;
- if (OldTypeParm && OldTypeParm->hasDefaultArgument() &&
+ if (NewTypeParm->isParameterPack()) {
+ assert(!NewTypeParm->hasDefaultArgument() &&
+ "Parameter packs can't have a default argument!");
+ SawParameterPack = true;
+ ParameterPackLoc = NewTypeParm->getLocation();
+ } else if (OldTypeParm && OldTypeParm->hasDefaultArgument() &&
NewTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc();
@@ -946,6 +975,33 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name));
}
+bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
+ const TemplateArgument &Arg,
+ TemplateArgumentListBuilder &Converted) {
+ // Check template type parameter.
+ if (Arg.getKind() != TemplateArgument::Type) {
+ // C++ [temp.arg.type]p1:
+ // A template-argument for a template-parameter which is a
+ // type shall be a type-id.
+
+ // We have a template type parameter but the template argument
+ // is not a type.
+ Diag(Arg.getLocation(), diag::err_template_arg_must_be_type);
+ Diag(Param->getLocation(), diag::note_template_param_here);
+
+ return true;
+ }
+
+ if (CheckTemplateArgument(Param, Arg.getAsType(), Arg.getLocation()))
+ return true;
+
+ // Add the converted template type argument.
+ Converted.push_back(
+ TemplateArgument(Arg.getLocation(),
+ Context.getCanonicalType(Arg.getAsType())));
+ return false;
+}
+
/// \brief Check that the given template argument list is well-formed
/// for specializing the given template.
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
@@ -960,7 +1016,10 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
unsigned NumArgs = NumTemplateArgs;
bool Invalid = false;
- if (NumArgs > NumParams ||
+ bool HasParameterPack =
+ NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack();
+
+ if ((NumArgs > NumParams && !HasParameterPack) ||
NumArgs < Params->getMinRequiredArguments()) {
// FIXME: point at either the first arg beyond what we can handle,
// or the '>', depending on whether we have too many or too few
@@ -994,6 +1053,13 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// Retrieve the default template argument from the template
// parameter.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+ if (TTP->isParameterPack()) {
+ // We have an empty parameter pack.
+ Converted.BeginParameterPack();
+ Converted.EndParameterPack();
+ break;
+ }
+
if (!TTP->hasDefaultArgument())
break;
@@ -1024,8 +1090,21 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if (!NTTP->hasDefaultArgument())
break;
- // FIXME: Instantiate default argument
- Arg = TemplateArgument(NTTP->getDefaultArgument());
+ InstantiatingTemplate Inst(*this, TemplateLoc,
+ Template, Converted.getFlatArgumentList(),
+ Converted.flatSize(),
+ SourceRange(TemplateLoc, RAngleLoc));
+
+ TemplateArgumentList TemplateArgs(Context, Converted,
+ /*CopyArgs=*/false,
+ /*FlattenArgs=*/false);
+
+ Sema::OwningExprResult E = InstantiateExpr(NTTP->getDefaultArgument(),
+ TemplateArgs);
+ if (E.isInvalid())
+ return true;
+
+ Arg = TemplateArgument(E.takeAs<Expr>());
} else {
TemplateTemplateParmDecl *TempParm
= cast<TemplateTemplateParmDecl>(*Param);
@@ -1043,27 +1122,19 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
- // Check template type parameters.
- if (Arg.getKind() == TemplateArgument::Type) {
- if (CheckTemplateArgument(TTP, Arg.getAsType(), Arg.getLocation()))
+ if (TTP->isParameterPack()) {
+ Converted.BeginParameterPack();
+ // Check all the remaining arguments (if any).
+ for (; ArgIdx < NumArgs; ++ArgIdx) {
+ if (CheckTemplateTypeArgument(TTP, TemplateArgs[ArgIdx], Converted))
+ Invalid = true;
+ }
+
+ Converted.EndParameterPack();
+ } else {
+ if (CheckTemplateTypeArgument(TTP, Arg, Converted))
Invalid = true;
-
- // Add the converted template type argument.
- Converted.push_back(
- TemplateArgument(Arg.getLocation(),
- Context.getCanonicalType(Arg.getAsType())));
- continue;
}
-
- // C++ [temp.arg.type]p1:
- // A template-argument for a template-parameter which is a
- // type shall be a type-id.
-
- // We have a template type parameter but the template argument
- // 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
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
// Check non-type template parameters.
@@ -1103,8 +1174,11 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
case TemplateArgument::Expression: {
Expr *E = Arg.getAsExpr();
- if (CheckTemplateArgument(NTTP, NTTPType, E, &Converted))
+ TemplateArgument Result;
+ if (CheckTemplateArgument(NTTP, NTTPType, E, Result))
Invalid = true;
+ else
+ Converted.push_back(Result);
break;
}
@@ -1388,11 +1462,10 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
/// 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.
+/// If no error was detected, Converted receives the converted template argument.
bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType InstantiatedParamType, Expr *&Arg,
- TemplateArgumentListBuilder *Converted) {
+ TemplateArgument &Converted) {
SourceLocation StartLoc = Arg->getSourceRange().getBegin();
// If either the parameter has a dependent type or the argument is
@@ -1400,7 +1473,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// FIXME: Add template argument to Converted!
if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) {
// FIXME: Produce a cloned, canonical expression?
- Converted->push_back(TemplateArgument(Arg));
+ Converted = TemplateArgument(Arg);
return false;
}
@@ -1465,7 +1538,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType IntegerType = Context.getCanonicalType(ParamType);
if (const EnumType *Enum = IntegerType->getAsEnumType())
- IntegerType = Enum->getDecl()->getIntegerType();
+ IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType());
if (!Arg->isValueDependent()) {
// Check that an unsigned parameter does not receive a negative
@@ -1495,21 +1568,19 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
Value.setIsSigned(IntegerType->isSignedIntegerType());
}
- if (Converted) {
- // Add the value of this argument to the list of converted
- // arguments. We use the bitwidth and signedness of the template
- // parameter.
- if (Arg->isValueDependent()) {
- // The argument is value-dependent. Create a new
- // TemplateArgument with the converted expression.
- Converted->push_back(TemplateArgument(Arg));
- return false;
- }
-
- Converted->push_back(TemplateArgument(StartLoc, Value,
- ParamType->isEnumeralType() ? ParamType : IntegerType));
+ // Add the value of this argument to the list of converted
+ // arguments. We use the bitwidth and signedness of the template
+ // parameter.
+ if (Arg->isValueDependent()) {
+ // The argument is value-dependent. Create a new
+ // TemplateArgument with the converted expression.
+ Converted = TemplateArgument(Arg);
+ return false;
}
+ Converted = TemplateArgument(StartLoc, Value,
+ ParamType->isEnumeralType() ? ParamType
+ : IntegerType);
return false;
}
@@ -1576,11 +1647,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentPointerToMember(Arg, Member))
return true;
- if (Converted) {
- Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member));
- Converted->push_back(TemplateArgument(StartLoc, Member));
- }
-
+ Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member));
+ Converted = TemplateArgument(StartLoc, Member);
return false;
}
@@ -1588,10 +1656,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- if (Converted) {
- Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity));
- Converted->push_back(TemplateArgument(StartLoc, Entity));
- }
+ Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity));
+ Converted = TemplateArgument(StartLoc, Entity);
return false;
}
@@ -1629,11 +1695,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- if (Converted) {
- Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity));
- Converted->push_back(TemplateArgument(StartLoc, Entity));
- }
-
+ Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity));
+ Converted = TemplateArgument(StartLoc, Entity);
return false;
}
@@ -1673,11 +1736,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- if (Converted) {
- Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity));
- Converted->push_back(TemplateArgument(StartLoc, Entity));
- }
-
+ Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity));
+ Converted = TemplateArgument(StartLoc, Entity);
return false;
}
@@ -1705,11 +1765,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentPointerToMember(Arg, Member))
return true;
- if (Converted) {
- Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member));
- Converted->push_back(TemplateArgument(StartLoc, Member));
- }
-
+ Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member));
+ Converted = TemplateArgument(StartLoc, Member);
return false;
}
@@ -1730,7 +1787,12 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
// template template argument with the corresponding parameter;
// partial specializations are not considered even if their
// parameter lists match that of the template template parameter.
- if (!isa<ClassTemplateDecl>(Template)) {
+ //
+ // Note that we also allow template template parameters here, which
+ // will happen when we are dealing with, e.g., class template
+ // partial specializations.
+ if (!isa<ClassTemplateDecl>(Template) &&
+ !isa<TemplateTemplateParmDecl>(Template)) {
assert(isa<FunctionTemplateDecl>(Template) &&
"Only function templates are possible here");
Diag(Arg->getSourceRange().getBegin(),
@@ -1925,6 +1987,7 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
ClassTemplateSpecializationDecl *PrevDecl,
SourceLocation TemplateNameLoc,
SourceRange ScopeSpecifierRange,
+ bool PartialSpecialization,
bool ExplicitInstantiation) {
// C++ [temp.expl.spec]p2:
// An explicit specialization shall be declared in the namespace
@@ -1940,8 +2003,9 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
// that encloses the one in which the explicit specialization was
// declared.
if (CurContext->getLookupContext()->isFunctionOrMethod()) {
+ int Kind = ExplicitInstantiation? 2 : PartialSpecialization? 1 : 0;
Diag(TemplateNameLoc, diag::err_template_spec_decl_function_scope)
- << ExplicitInstantiation << ClassTemplate;
+ << Kind << ClassTemplate;
return true;
}
@@ -1956,11 +2020,12 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
if (DC != TemplateContext) {
if (isa<TranslationUnitDecl>(TemplateContext))
Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope_global)
+ << PartialSpecialization
<< ClassTemplate << ScopeSpecifierRange;
else if (isa<NamespaceDecl>(TemplateContext))
Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope)
- << ClassTemplate << cast<NamedDecl>(TemplateContext)
- << ScopeSpecifierRange;
+ << PartialSpecialization << ClassTemplate
+ << cast<NamedDecl>(TemplateContext) << ScopeSpecifierRange;
Diag(ClassTemplate->getLocation(), diag::note_template_decl_here);
}
@@ -1974,16 +2039,17 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
// FIXME: In C++98, we would like to turn these errors into warnings,
// dependent on a -Wc++0x flag.
bool SuppressedDiag = false;
+ int Kind = ExplicitInstantiation? 2 : PartialSpecialization? 1 : 0;
if (isa<TranslationUnitDecl>(TemplateContext)) {
if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
Diag(TemplateNameLoc, diag::err_template_spec_redecl_global_scope)
- << ExplicitInstantiation << ClassTemplate << ScopeSpecifierRange;
+ << Kind << ClassTemplate << ScopeSpecifierRange;
else
SuppressedDiag = true;
} else if (isa<NamespaceDecl>(TemplateContext)) {
if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
Diag(TemplateNameLoc, diag::err_template_spec_redecl_out_of_scope)
- << ExplicitInstantiation << ClassTemplate
+ << Kind << ClassTemplate
<< cast<NamedDecl>(TemplateContext) << ScopeSpecifierRange;
else
SuppressedDiag = true;
@@ -1996,6 +2062,126 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
return false;
}
+/// \brief Check the non-type template arguments of a class template
+/// partial specialization according to C++ [temp.class.spec]p9.
+///
+/// \param TemplateParams the template parameters of the primary class
+/// template.
+///
+/// \param TemplateArg the template arguments of the class template
+/// partial specialization.
+///
+/// \param MirrorsPrimaryTemplate will be set true if the class
+/// template partial specialization arguments are identical to the
+/// implicit template arguments of the primary template. This is not
+/// necessarily an error (C++0x), and it is left to the caller to diagnose
+/// this condition when it is an error.
+///
+/// \returns true if there was an error, false otherwise.
+bool Sema::CheckClassTemplatePartialSpecializationArgs(
+ TemplateParameterList *TemplateParams,
+ const TemplateArgumentListBuilder &TemplateArgs,
+ bool &MirrorsPrimaryTemplate) {
+ // FIXME: the interface to this function will have to change to
+ // accommodate variadic templates.
+ MirrorsPrimaryTemplate = true;
+
+ const TemplateArgument *ArgList = TemplateArgs.getFlatArgumentList();
+
+ for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
+ // Determine whether the template argument list of the partial
+ // specialization is identical to the implicit argument list of
+ // the primary template. The caller may need to diagnostic this as
+ // an error per C++ [temp.class.spec]p9b3.
+ if (MirrorsPrimaryTemplate) {
+ if (TemplateTypeParmDecl *TTP
+ = dyn_cast<TemplateTypeParmDecl>(TemplateParams->getParam(I))) {
+ if (Context.getCanonicalType(Context.getTypeDeclType(TTP)) !=
+ Context.getCanonicalType(ArgList[I].getAsType()))
+ MirrorsPrimaryTemplate = false;
+ } else if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(
+ TemplateParams->getParam(I))) {
+ // FIXME: We should settle on either Declaration storage or
+ // Expression storage for template template parameters.
+ TemplateTemplateParmDecl *ArgDecl
+ = dyn_cast_or_null<TemplateTemplateParmDecl>(
+ ArgList[I].getAsDecl());
+ if (!ArgDecl)
+ if (DeclRefExpr *DRE
+ = dyn_cast_or_null<DeclRefExpr>(ArgList[I].getAsExpr()))
+ ArgDecl = dyn_cast<TemplateTemplateParmDecl>(DRE->getDecl());
+
+ if (!ArgDecl ||
+ ArgDecl->getIndex() != TTP->getIndex() ||
+ ArgDecl->getDepth() != TTP->getDepth())
+ MirrorsPrimaryTemplate = false;
+ }
+ }
+
+ NonTypeTemplateParmDecl *Param
+ = dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(I));
+ if (!Param) {
+ continue;
+ }
+
+ Expr *ArgExpr = ArgList[I].getAsExpr();
+ if (!ArgExpr) {
+ MirrorsPrimaryTemplate = false;
+ continue;
+ }
+
+ // C++ [temp.class.spec]p8:
+ // A non-type argument is non-specialized if it is the name of a
+ // non-type parameter. All other non-type arguments are
+ // specialized.
+ //
+ // Below, we check the two conditions that only apply to
+ // specialized non-type arguments, so skip any non-specialized
+ // arguments.
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr))
+ if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl())) {
+ if (MirrorsPrimaryTemplate &&
+ (Param->getIndex() != NTTP->getIndex() ||
+ Param->getDepth() != NTTP->getDepth()))
+ MirrorsPrimaryTemplate = false;
+
+ continue;
+ }
+
+ // C++ [temp.class.spec]p9:
+ // Within the argument list of a class template partial
+ // specialization, the following restrictions apply:
+ // -- A partially specialized non-type argument expression
+ // shall not involve a template parameter of the partial
+ // specialization except when the argument expression is a
+ // simple identifier.
+ if (ArgExpr->isTypeDependent() || ArgExpr->isValueDependent()) {
+ Diag(ArgExpr->getLocStart(),
+ diag::err_dependent_non_type_arg_in_partial_spec)
+ << ArgExpr->getSourceRange();
+ return true;
+ }
+
+ // -- The type of a template parameter corresponding to a
+ // specialized non-type argument shall not be dependent on a
+ // parameter of the specialization.
+ if (Param->getType()->isDependentType()) {
+ Diag(ArgExpr->getLocStart(),
+ diag::err_dependent_typed_non_type_arg_in_partial_spec)
+ << Param->getType()
+ << ArgExpr->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ MirrorsPrimaryTemplate = false;
+ }
+
+ return false;
+}
+
Sema::DeclResult
Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
SourceLocation KWLoc,
@@ -2032,9 +2218,41 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
return true;
}
- // FIXME: We'll need more checks, here!
- if (TemplateParams->size() > 0)
+ if (TemplateParams->size() > 0) {
isPartialSpecialization = true;
+
+ // C++ [temp.class.spec]p10:
+ // The template parameter list of a specialization shall not
+ // contain default template argument values.
+ for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
+ Decl *Param = TemplateParams->getParam(I);
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
+ if (TTP->hasDefaultArgument()) {
+ Diag(TTP->getDefaultArgumentLoc(),
+ diag::err_default_arg_in_partial_spec);
+ TTP->setDefaultArgument(QualType(), SourceLocation(), false);
+ }
+ } else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (Expr *DefArg = NTTP->getDefaultArgument()) {
+ Diag(NTTP->getDefaultArgumentLoc(),
+ diag::err_default_arg_in_partial_spec)
+ << DefArg->getSourceRange();
+ NTTP->setDefaultArgument(0);
+ DefArg->Destroy(Context);
+ }
+ } else {
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param);
+ if (Expr *DefArg = TTP->getDefaultArgument()) {
+ Diag(TTP->getDefaultArgumentLoc(),
+ diag::err_default_arg_in_partial_spec)
+ << DefArg->getSourceRange();
+ TTP->setDefaultArgument(0);
+ DefArg->Destroy(Context);
+ }
+ }
+ }
+ }
}
// Check that the specialization uses the same tag kind as the
@@ -2066,7 +2284,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// template.
TemplateArgumentListBuilder ConvertedTemplateArgs(Context);
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
- &TemplateArgs[0], TemplateArgs.size(),
+ TemplateArgs.data(), TemplateArgs.size(),
RAngleLoc, ConvertedTemplateArgs))
return true;
@@ -2077,11 +2295,36 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// Find the class template (partial) specialization declaration that
// corresponds to these arguments.
llvm::FoldingSetNodeID ID;
- if (isPartialSpecialization)
+ if (isPartialSpecialization) {
+ bool MirrorsPrimaryTemplate;
+ if (CheckClassTemplatePartialSpecializationArgs(
+ ClassTemplate->getTemplateParameters(),
+ ConvertedTemplateArgs,
+ MirrorsPrimaryTemplate))
+ return true;
+
+ if (MirrorsPrimaryTemplate) {
+ // C++ [temp.class.spec]p9b3:
+ //
+ // -- The argument list of the specialization shall not be identical
+ // to the implicit argument list of the primary template.
+ Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
+ << (TK == TK_Definition)
+ << CodeModificationHint::CreateRemoval(SourceRange(LAngleLoc,
+ RAngleLoc));
+ return ActOnClassTemplate(S, TagSpec, TK, KWLoc, SS,
+ ClassTemplate->getIdentifier(),
+ TemplateNameLoc,
+ Attr,
+ move(TemplateParameterLists),
+ AS_none);
+ }
+
// FIXME: Template parameter list matters, too
ClassTemplatePartialSpecializationDecl::Profile(ID,
ConvertedTemplateArgs.getFlatArgumentList(),
ConvertedTemplateArgs.flatSize());
+ }
else
ClassTemplateSpecializationDecl::Profile(ID,
ConvertedTemplateArgs.getFlatArgumentList(),
@@ -2104,6 +2347,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
if (CheckClassTemplateSpecializationScope(ClassTemplate, PrevDecl,
TemplateNameLoc,
SS.getRange(),
+ isPartialSpecialization,
/*ExplicitInstantiation=*/false))
return true;
@@ -2116,8 +2360,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
Specialization->setLocation(TemplateNameLoc);
PrevDecl = 0;
} else if (isPartialSpecialization) {
- // FIXME: extra checking for partial specializations
-
// Create a new class template partial specialization declaration node.
TemplateParameterList *TemplateParams
= static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
@@ -2139,6 +2381,38 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
ClassTemplate->getPartialSpecializations().InsertNode(Partial, InsertPos);
}
Specialization = Partial;
+
+ // Check that all of the template parameters of the class template
+ // partial specialization are deducible from the template
+ // arguments. If not, this class template partial specialization
+ // will never be used.
+ llvm::SmallVector<bool, 8> DeducibleParams;
+ DeducibleParams.resize(TemplateParams->size());
+ MarkDeducedTemplateParameters(Partial->getTemplateArgs(), DeducibleParams);
+ unsigned NumNonDeducible = 0;
+ for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I)
+ if (!DeducibleParams[I])
+ ++NumNonDeducible;
+
+ if (NumNonDeducible) {
+ Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible)
+ << (NumNonDeducible > 1)
+ << SourceRange(TemplateNameLoc, RAngleLoc);
+ for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) {
+ if (!DeducibleParams[I]) {
+ NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I));
+ if (Param->getDeclName())
+ Diag(Param->getLocation(),
+ diag::note_partial_spec_unused_parameter)
+ << Param->getDeclName();
+ else
+ Diag(Param->getLocation(),
+ diag::note_partial_spec_unused_parameter)
+ << std::string("<anonymous>");
+ }
+ }
+ }
+
} else {
// Create a new class template specialization declaration node for
// this explicit specialization.
@@ -2185,7 +2459,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// template arguments in the specialization.
QualType WrittenTy
= Context.getTemplateSpecializationType(Name,
- &TemplateArgs[0],
+ TemplateArgs.data(),
TemplateArgs.size(),
Context.getTypeDeclType(Specialization));
Specialization->setTypeAsWritten(WrittenTy);
@@ -2259,6 +2533,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
if (CheckClassTemplateSpecializationScope(ClassTemplate, 0,
TemplateNameLoc,
SS.getRange(),
+ /*PartialSpecialization=*/false,
/*ExplicitInstantiation=*/true))
return true;
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index db7e622f7f68..84d802d1bf89 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -20,6 +20,14 @@
#include "llvm/Support/Compiler.h"
using namespace clang;
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(ASTContext &Context,
+ TemplateParameterList *TemplateParams,
+ const TemplateArgument &Param,
+ const TemplateArgument &Arg,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced);
+
/// \brief If the given expression is of a form that permits the deduction
/// of a non-type template parameter, return the declaration of that
/// non-type template parameter.
@@ -35,12 +43,12 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
/// \brief Deduce the value of the given non-type template parameter
/// from the given constant.
-///
-/// \returns true if deduction succeeded, false otherwise.
-static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
- NonTypeTemplateParmDecl *NTTP,
- llvm::APInt Value,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+static Sema::TemplateDeductionResult
+DeduceNonTypeTemplateArgument(ASTContext &Context,
+ NonTypeTemplateParmDecl *NTTP,
+ llvm::APInt Value,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
@@ -48,25 +56,41 @@ static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
Deduced[NTTP->getIndex()] = TemplateArgument(SourceLocation(),
llvm::APSInt(Value),
NTTP->getType());
- return true;
+ return Sema::TDK_Success;
}
- if (Deduced[NTTP->getIndex()].getKind() != TemplateArgument::Integral)
- return false;
+ assert(Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral);
// If the template argument was previously deduced to a negative value,
// then our deduction fails.
const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral();
- assert(PrevValuePtr && "Not an integral template argument?");
- if (PrevValuePtr->isSigned() && PrevValuePtr->isNegative())
- return false;
-
+ if (PrevValuePtr->isSigned() && PrevValuePtr->isNegative()) {
+ // FIXME: This is wacky; we should be dealing with APSInts and
+ // checking the actual signs.
+ Info.Param = NTTP;
+ Info.FirstArg = Deduced[NTTP->getIndex()];
+ Info.SecondArg = TemplateArgument(SourceLocation(),
+ llvm::APSInt(Value),
+ NTTP->getType());
+ return Sema::TDK_Inconsistent;
+ }
+
llvm::APInt PrevValue = *PrevValuePtr;
if (Value.getBitWidth() > PrevValue.getBitWidth())
PrevValue.zext(Value.getBitWidth());
else if (Value.getBitWidth() < PrevValue.getBitWidth())
Value.zext(PrevValue.getBitWidth());
- return Value == PrevValue;
+
+ if (Value != PrevValue) {
+ Info.Param = NTTP;
+ Info.FirstArg = Deduced[NTTP->getIndex()];
+ Info.SecondArg = TemplateArgument(SourceLocation(),
+ llvm::APSInt(Value),
+ NTTP->getType());
+ return Sema::TDK_Inconsistent;
+ }
+
+ return Sema::TDK_Success;
}
/// \brief Deduce the value of the given non-type template parameter
@@ -74,10 +98,12 @@ static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
///
/// \returns true if deduction succeeded, false otherwise.
-static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
- NonTypeTemplateParmDecl *NTTP,
- Expr *Value,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+static Sema::TemplateDeductionResult
+DeduceNonTypeTemplateArgument(ASTContext &Context,
+ NonTypeTemplateParmDecl *NTTP,
+ Expr *Value,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
assert((Value->isTypeDependent() || Value->isValueDependent()) &&
@@ -86,35 +112,73 @@ static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
if (Deduced[NTTP->getIndex()].isNull()) {
// FIXME: Clone the Value?
Deduced[NTTP->getIndex()] = TemplateArgument(Value);
- return true;
+ return Sema::TDK_Success;
}
if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral) {
// Okay, we deduced a constant in one case and a dependent expression
// in another case. FIXME: Later, we will check that instantiating the
// dependent expression gives us the constant value.
- return true;
+ return Sema::TDK_Success;
}
// FIXME: Compare the expressions for equality!
- return true;
+ return Sema::TDK_Success;
}
-static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
- QualType Arg,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(ASTContext &Context,
+ TemplateName Param,
+ TemplateName Arg,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ // FIXME: Implement template argument deduction for template
+ // template parameters.
+
+ // FIXME: this routine does not have enough information to produce
+ // good diagnostics.
+
+ TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
+ TemplateDecl *ArgDecl = Arg.getAsTemplateDecl();
+
+ if (!ParamDecl || !ArgDecl) {
+ // FIXME: fill in Info.Param/Info.FirstArg
+ return Sema::TDK_Inconsistent;
+ }
+
+ ParamDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ParamDecl));
+ ArgDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ArgDecl));
+ if (ParamDecl != ArgDecl) {
+ // FIXME: fill in Info.Param/Info.FirstArg
+ return Sema::TDK_Inconsistent;
+ }
+
+ return Sema::TDK_Success;
+}
+
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(ASTContext &Context,
+ TemplateParameterList *TemplateParams,
+ QualType ParamIn, QualType ArgIn,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
// We only want to look at the canonical types, since typedefs and
// sugar are not part of template argument deduction.
- Param = Context.getCanonicalType(Param);
- Arg = Context.getCanonicalType(Arg);
+ QualType Param = Context.getCanonicalType(ParamIn);
+ QualType Arg = Context.getCanonicalType(ArgIn);
// If the parameter type is not dependent, just compare the types
// directly.
- if (!Param->isDependentType())
- return Param == Arg;
+ if (!Param->isDependentType()) {
+ if (Param == Arg)
+ return Sema::TDK_Success;
+
+ Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn);
+ Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn);
+ return Sema::TDK_NonDeducedMismatch;
+ }
// C++ [temp.deduct.type]p9:
- //
// A template type argument T, a template template argument TT or a
// template non-type argument i can be deduced if P and A have one of
// the following forms:
@@ -123,16 +187,21 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
// cv-list T
if (const TemplateTypeParmType *TemplateTypeParm
= Param->getAsTemplateTypeParmType()) {
+ unsigned Index = TemplateTypeParm->getIndex();
+
// The argument type can not be less qualified than the parameter
// type.
- if (Param.isMoreQualifiedThan(Arg))
- return false;
+ if (Param.isMoreQualifiedThan(Arg)) {
+ Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
+ Info.FirstArg = Deduced[Index];
+ Info.SecondArg = TemplateArgument(SourceLocation(), Arg);
+ return Sema::TDK_InconsistentQuals;
+ }
assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0");
unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
QualType DeducedType = Arg.getQualifiedType(Quals);
- unsigned Index = TemplateTypeParm->getIndex();
if (Deduced[Index].isNull())
Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType);
@@ -143,55 +212,63 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
// deduced values, or if different pairs yield different deduced
// values, or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
- if (Deduced[Index].getAsType() != DeducedType)
- return false;
+ if (Deduced[Index].getAsType() != DeducedType) {
+ Info.Param
+ = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
+ Info.FirstArg = Deduced[Index];
+ Info.SecondArg = TemplateArgument(SourceLocation(), Arg);
+ return Sema::TDK_Inconsistent;
+ }
}
- return true;
+ return Sema::TDK_Success;
}
+ // Set up the template argument deduction information for a failure.
+ Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn);
+ Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn);
+
if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
- return false;
+ return Sema::TDK_NonDeducedMismatch;
switch (Param->getTypeClass()) {
// No deduction possible for these types
case Type::Builtin:
- return false;
-
+ return Sema::TDK_NonDeducedMismatch;
// T *
case Type::Pointer: {
const PointerType *PointerArg = Arg->getAsPointerType();
if (!PointerArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context,
+ return DeduceTemplateArguments(Context, TemplateParams,
cast<PointerType>(Param)->getPointeeType(),
PointerArg->getPointeeType(),
- Deduced);
+ Info, Deduced);
}
// T &
case Type::LValueReference: {
const LValueReferenceType *ReferenceArg = Arg->getAsLValueReferenceType();
if (!ReferenceArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context,
+ return DeduceTemplateArguments(Context, TemplateParams,
cast<LValueReferenceType>(Param)->getPointeeType(),
ReferenceArg->getPointeeType(),
- Deduced);
+ Info, Deduced);
}
// T && [C++0x]
case Type::RValueReference: {
const RValueReferenceType *ReferenceArg = Arg->getAsRValueReferenceType();
if (!ReferenceArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context,
+ return DeduceTemplateArguments(Context, TemplateParams,
cast<RValueReferenceType>(Param)->getPointeeType(),
ReferenceArg->getPointeeType(),
- Deduced);
+ Info, Deduced);
}
// T [] (implied, but not stated explicitly)
@@ -199,12 +276,12 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
const IncompleteArrayType *IncompleteArrayArg =
Context.getAsIncompleteArrayType(Arg);
if (!IncompleteArrayArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context,
+ return DeduceTemplateArguments(Context, TemplateParams,
Context.getAsIncompleteArrayType(Param)->getElementType(),
IncompleteArrayArg->getElementType(),
- Deduced);
+ Info, Deduced);
}
// T [integer-constant]
@@ -212,39 +289,40 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
const ConstantArrayType *ConstantArrayArg =
Context.getAsConstantArrayType(Arg);
if (!ConstantArrayArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
const ConstantArrayType *ConstantArrayParm =
Context.getAsConstantArrayType(Param);
if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize())
- return false;
+ return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context,
+ return DeduceTemplateArguments(Context, TemplateParams,
ConstantArrayParm->getElementType(),
ConstantArrayArg->getElementType(),
- Deduced);
+ Info, Deduced);
}
// type [i]
case Type::DependentSizedArray: {
const ArrayType *ArrayArg = dyn_cast<ArrayType>(Arg);
if (!ArrayArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
// Check the element type of the arrays
const DependentSizedArrayType *DependentArrayParm
= cast<DependentSizedArrayType>(Param);
- if (!DeduceTemplateArguments(Context,
- DependentArrayParm->getElementType(),
- ArrayArg->getElementType(),
- Deduced))
- return false;
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ DependentArrayParm->getElementType(),
+ ArrayArg->getElementType(),
+ Info, Deduced))
+ return Result;
// Determine the array bound is something we can deduce.
NonTypeTemplateParmDecl *NTTP
= getDeducedParameterFromExpr(DependentArrayParm->getSizeExpr());
if (!NTTP)
- return true;
+ return Sema::TDK_Success;
// We can perform template argument deduction for the given non-type
// template parameter.
@@ -254,59 +332,209 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
= dyn_cast<ConstantArrayType>(ArrayArg))
return DeduceNonTypeTemplateArgument(Context, NTTP,
ConstantArrayArg->getSize(),
- Deduced);
+ Info, Deduced);
if (const DependentSizedArrayType *DependentArrayArg
= dyn_cast<DependentSizedArrayType>(ArrayArg))
return DeduceNonTypeTemplateArgument(Context, NTTP,
DependentArrayArg->getSizeExpr(),
- Deduced);
+ Info, Deduced);
// Incomplete type does not match a dependently-sized array type
- return false;
+ return Sema::TDK_NonDeducedMismatch;
}
+ // type(*)(T)
+ // T(*)()
+ // T(*)(T)
case Type::FunctionProto: {
const FunctionProtoType *FunctionProtoArg =
dyn_cast<FunctionProtoType>(Arg);
if (!FunctionProtoArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
const FunctionProtoType *FunctionProtoParam =
cast<FunctionProtoType>(Param);
-
- // Check return types.
- if (!DeduceTemplateArguments(Context,
- FunctionProtoParam->getResultType(),
- FunctionProtoArg->getResultType(),
- Deduced))
- return false;
+
+ if (FunctionProtoParam->getTypeQuals() !=
+ FunctionProtoArg->getTypeQuals())
+ return Sema::TDK_NonDeducedMismatch;
if (FunctionProtoParam->getNumArgs() != FunctionProtoArg->getNumArgs())
- return false;
+ return Sema::TDK_NonDeducedMismatch;
+
+ if (FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic())
+ return Sema::TDK_NonDeducedMismatch;
+
+ // Check return types.
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ FunctionProtoParam->getResultType(),
+ FunctionProtoArg->getResultType(),
+ Info, Deduced))
+ return Result;
for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) {
// Check argument types.
- if (!DeduceTemplateArguments(Context,
- FunctionProtoParam->getArgType(I),
- FunctionProtoArg->getArgType(I),
- Deduced))
- return false;
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ FunctionProtoParam->getArgType(I),
+ FunctionProtoArg->getArgType(I),
+ Info, Deduced))
+ return Result;
}
- return true;
+ return Sema::TDK_Success;
}
+
+ // template-name<T> (wheretemplate-name refers to a class template)
+ // template-name<i>
+ // TT<T> (TODO)
+ // TT<i> (TODO)
+ // TT<> (TODO)
+ case Type::TemplateSpecialization: {
+ const TemplateSpecializationType *SpecParam
+ = cast<TemplateSpecializationType>(Param);
+
+ // Check whether the template argument is a dependent template-id.
+ // FIXME: This is untested code; it can be tested when we implement
+ // partial ordering of class template partial specializations.
+ if (const TemplateSpecializationType *SpecArg
+ = dyn_cast<TemplateSpecializationType>(Arg)) {
+ // Perform template argument deduction for the template name.
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context,
+ SpecParam->getTemplateName(),
+ SpecArg->getTemplateName(),
+ Info, Deduced))
+ return Result;
+
+ unsigned NumArgs = SpecParam->getNumArgs();
+
+ // FIXME: When one of the template-names refers to a
+ // declaration with default template arguments, do we need to
+ // fill in those default template arguments here? Most likely,
+ // the answer is "yes", but I don't see any references. This
+ // issue may be resolved elsewhere, because we may want to
+ // instantiate default template arguments when
+ if (SpecArg->getNumArgs() != NumArgs)
+ return Sema::TDK_NonDeducedMismatch;
+
+ // Perform template argument deduction on each template
+ // argument.
+ for (unsigned I = 0; I != NumArgs; ++I)
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ SpecParam->getArg(I),
+ SpecArg->getArg(I),
+ Info, Deduced))
+ return Result;
+
+ return Sema::TDK_Success;
+ }
+
+ // If the argument type is a class template specialization, we
+ // perform template argument deduction using its template
+ // arguments.
+ const RecordType *RecordArg = dyn_cast<RecordType>(Arg);
+ if (!RecordArg)
+ return Sema::TDK_NonDeducedMismatch;
+
+ ClassTemplateSpecializationDecl *SpecArg
+ = dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl());
+ if (!SpecArg)
+ return Sema::TDK_NonDeducedMismatch;
+
+ // Perform template argument deduction for the template name.
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context,
+ SpecParam->getTemplateName(),
+ TemplateName(SpecArg->getSpecializedTemplate()),
+ Info, Deduced))
+ return Result;
+
+ // FIXME: Can the # of arguments in the parameter and the argument differ?
+ unsigned NumArgs = SpecParam->getNumArgs();
+ const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs();
+ if (NumArgs != ArgArgs.size())
+ return Sema::TDK_NonDeducedMismatch;
+
+ for (unsigned I = 0; I != NumArgs; ++I)
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ SpecParam->getArg(I),
+ ArgArgs.get(I),
+ Info, Deduced))
+ return Result;
+ return Sema::TDK_Success;
+ }
+
+ // T type::*
+ // T T::*
+ // T (type::*)()
+ // type (T::*)()
+ // type (type::*)(T)
+ // type (T::*)(T)
+ // T (type::*)(T)
+ // T (T::*)()
+ // T (T::*)(T)
+ case Type::MemberPointer: {
+ const MemberPointerType *MemPtrParam = cast<MemberPointerType>(Param);
+ const MemberPointerType *MemPtrArg = dyn_cast<MemberPointerType>(Arg);
+ if (!MemPtrArg)
+ return Sema::TDK_NonDeducedMismatch;
+
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ MemPtrParam->getPointeeType(),
+ MemPtrArg->getPointeeType(),
+ Info, Deduced))
+ return Result;
+
+ return DeduceTemplateArguments(Context, TemplateParams,
+ QualType(MemPtrParam->getClass(), 0),
+ QualType(MemPtrArg->getClass(), 0),
+ Info, Deduced);
+ }
+
+ // (clang extension)
+ //
+ // type(^)(T)
+ // T(^)()
+ // T(^)(T)
+ case Type::BlockPointer: {
+ const BlockPointerType *BlockPtrParam = cast<BlockPointerType>(Param);
+ const BlockPointerType *BlockPtrArg = dyn_cast<BlockPointerType>(Arg);
+
+ if (!BlockPtrArg)
+ return Sema::TDK_NonDeducedMismatch;
+
+ return DeduceTemplateArguments(Context, TemplateParams,
+ BlockPtrParam->getPointeeType(),
+ BlockPtrArg->getPointeeType(), Info,
+ Deduced);
+ }
+
+ case Type::TypeOfExpr:
+ case Type::TypeOf:
+ case Type::Typename:
+ // No template argument deduction for these types
+ return Sema::TDK_Success;
+
default:
break;
}
// FIXME: Many more cases to go (to go).
- return false;
+ return Sema::TDK_NonDeducedMismatch;
}
-static bool
-DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(ASTContext &Context,
+ TemplateParameterList *TemplateParams,
+ const TemplateArgument &Param,
const TemplateArgument &Arg,
+ Sema::TemplateDeductionInfo &Info,
llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
switch (Param.getKind()) {
case TemplateArgument::Null:
@@ -315,24 +543,38 @@ DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
case TemplateArgument::Type:
assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch");
- return DeduceTemplateArguments(Context, Param.getAsType(),
- Arg.getAsType(), Deduced);
+ return DeduceTemplateArguments(Context, TemplateParams,
+ Param.getAsType(),
+ Arg.getAsType(), Info, Deduced);
case TemplateArgument::Declaration:
// FIXME: Implement this check
assert(false && "Unimplemented template argument deduction case");
- return false;
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::Integral:
if (Arg.getKind() == TemplateArgument::Integral) {
// FIXME: Zero extension + sign checking here?
- return *Param.getAsIntegral() == *Arg.getAsIntegral();
+ if (*Param.getAsIntegral() == *Arg.getAsIntegral())
+ return Sema::TDK_Success;
+
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
+ if (Arg.getKind() == TemplateArgument::Expression) {
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
}
- if (Arg.getKind() == TemplateArgument::Expression)
- return false;
assert(false && "Type/value mismatch");
- return false;
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::Expression: {
if (NonTypeTemplateParmDecl *NTTP
@@ -340,70 +582,114 @@ DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
if (Arg.getKind() == TemplateArgument::Integral)
// FIXME: Sign problems here
return DeduceNonTypeTemplateArgument(Context, NTTP,
- *Arg.getAsIntegral(), Deduced);
+ *Arg.getAsIntegral(),
+ Info, Deduced);
if (Arg.getKind() == TemplateArgument::Expression)
return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(),
- Deduced);
+ Info, Deduced);
assert(false && "Type/value mismatch");
- return false;
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
}
// Can't deduce anything, but that's okay.
- return true;
+ return Sema::TDK_Success;
}
}
- return true;
+ return Sema::TDK_Success;
}
-static bool
+static Sema::TemplateDeductionResult
DeduceTemplateArguments(ASTContext &Context,
+ TemplateParameterList *TemplateParams,
const TemplateArgumentList &ParamList,
const TemplateArgumentList &ArgList,
+ Sema::TemplateDeductionInfo &Info,
llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
assert(ParamList.size() == ArgList.size());
for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
- if (!DeduceTemplateArguments(Context, ParamList[I], ArgList[I], Deduced))
- return false;
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ ParamList[I], ArgList[I],
+ Info, Deduced))
+ return Result;
}
- return true;
+ return Sema::TDK_Success;
}
-
-TemplateArgumentList *
+/// \brief Perform template argument deduction to determine whether
+/// the given template arguments match the given class template
+/// partial specialization per C++ [temp.class.spec.match].
+Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
- const TemplateArgumentList &TemplateArgs) {
- // Deduce the template arguments for the partial specialization
+ const TemplateArgumentList &TemplateArgs,
+ TemplateDeductionInfo &Info) {
+ // C++ [temp.class.spec.match]p2:
+ // A partial specialization matches a given actual template
+ // argument list if the template arguments of the partial
+ // specialization can be deduced from the actual template argument
+ // list (14.8.2).
+ SFINAETrap Trap(*this);
llvm::SmallVector<TemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
- if (! ::DeduceTemplateArguments(Context, Partial->getTemplateArgs(),
- TemplateArgs, Deduced))
- return 0;
-
- // FIXME: Substitute the deduced template arguments into the template
- // arguments of the class template partial specialization; the resulting
- // template arguments should match TemplateArgs exactly.
-
+ if (TemplateDeductionResult Result
+ = ::DeduceTemplateArguments(Context,
+ Partial->getTemplateParameters(),
+ Partial->getTemplateArgs(),
+ TemplateArgs, Info, Deduced))
+ return Result;
+
+ InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
+ Deduced.data(), Deduced.size());
+ if (Inst)
+ return TDK_InstantiationDepth;
+
+ // C++ [temp.deduct.type]p2:
+ // [...] or if any template argument remains neither deduced nor
+ // explicitly specified, template argument deduction fails.
+ TemplateArgumentListBuilder Builder(Context);
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
- TemplateArgument &Arg = Deduced[I];
+ if (Deduced[I].isNull()) {
+ Decl *Param
+ = const_cast<Decl *>(Partial->getTemplateParameters()->getParam(I));
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+ Info.Param = TTP;
+ else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param))
+ Info.Param = NTTP;
+ else
+ Info.Param = cast<TemplateTemplateParmDecl>(Param);
+ return TDK_Incomplete;
+ }
- // FIXME: If this template argument was not deduced, but the corresponding
- // template parameter has a default argument, instantiate the default
- // argument.
- if (Arg.isNull()) // FIXME: Result->Destroy(Context);
- return 0;
-
+ Builder.push_back(Deduced[I]);
+ }
+
+ // Form the template argument list from the deduced template arguments.
+ TemplateArgumentList *DeducedArgumentList
+ = new (Context) TemplateArgumentList(Context, Builder, /*CopyArgs=*/true,
+ /*FlattenArgs=*/true);
+ Info.reset(DeducedArgumentList);
+
+ // Now that we have all of the deduced template arguments, take
+ // another pass through them to convert any integral template
+ // arguments to the appropriate type.
+ for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
+ TemplateArgument &Arg = Deduced[I];
if (Arg.getKind() == TemplateArgument::Integral) {
- // FIXME: Instantiate the type, but we need some context!
const NonTypeTemplateParmDecl *Parm
= cast<NonTypeTemplateParmDecl>(Partial->getTemplateParameters()
->getParam(I));
- // QualType T = InstantiateType(Parm->getType(), *Result,
- // Parm->getLocation(), Parm->getDeclName());
- // if (T.isNull()) // FIXME: Result->Destroy(Context);
- // return 0;
- QualType T = Parm->getType();
+ QualType T = InstantiateType(Parm->getType(), *DeducedArgumentList,
+ Parm->getLocation(), Parm->getDeclName());
+ if (T.isNull()) {
+ Info.Param = const_cast<NonTypeTemplateParmDecl*>(Parm);
+ Info.FirstArg = TemplateArgument(Parm->getLocation(), Parm->getType());
+ return TDK_SubstitutionFailure;
+ }
// FIXME: Make sure we didn't overflow our data type!
llvm::APSInt &Value = *Arg.getAsIntegral();
@@ -413,14 +699,220 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
Value.setIsSigned(T->isSignedIntegerType());
Arg.setIntegralType(T);
}
+
+ (*DeducedArgumentList)[I] = Arg;
}
-
- // FIXME: This is terrible. DeduceTemplateArguments should use a
- // TemplateArgumentListBuilder directly.
- TemplateArgumentListBuilder Builder(Context);
- for (unsigned I = 0, N = Deduced.size(); I != N; ++I)
- Builder.push_back(Deduced[I]);
-
- return new (Context) TemplateArgumentList(Context, Builder, /*CopyArgs=*/true,
- /*FlattenArgs=*/true);
+
+ // Substitute the deduced template arguments into the template
+ // arguments of the class template partial specialization, and
+ // verify that the instantiated template arguments are both valid
+ // and are equivalent to the template arguments originally provided
+ // to the class template.
+ ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate();
+ const TemplateArgumentList &PartialTemplateArgs = Partial->getTemplateArgs();
+ for (unsigned I = 0, N = PartialTemplateArgs.flat_size(); I != N; ++I) {
+ Decl *Param = const_cast<Decl *>(
+ ClassTemplate->getTemplateParameters()->getParam(I));
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
+ TemplateArgument InstArg = Instantiate(PartialTemplateArgs[I],
+ *DeducedArgumentList);
+ if (InstArg.getKind() != TemplateArgument::Type) {
+ Info.Param = TTP;
+ Info.FirstArg = PartialTemplateArgs[I];
+ return TDK_SubstitutionFailure;
+ }
+
+ if (Context.getCanonicalType(InstArg.getAsType())
+ != Context.getCanonicalType(TemplateArgs[I].getAsType())) {
+ Info.Param = TTP;
+ Info.FirstArg = TemplateArgs[I];
+ Info.SecondArg = InstArg;
+ return TDK_NonDeducedMismatch;
+ }
+
+ continue;
+ }
+
+ // FIXME: Check template template arguments?
+ }
+
+ if (Trap.hasErrorOccurred())
+ return TDK_SubstitutionFailure;
+
+ return TDK_Success;
+}
+
+static void
+MarkDeducedTemplateParameters(Sema &SemaRef,
+ const TemplateArgument &TemplateArg,
+ llvm::SmallVectorImpl<bool> &Deduced);
+
+/// \brief Mark the template arguments that are deduced by the given
+/// expression.
+static void
+MarkDeducedTemplateParameters(Expr *E, llvm::SmallVectorImpl<bool> &Deduced) {
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
+ if (!E)
+ return;
+
+ NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl());
+ if (!NTTP)
+ return;
+
+ Deduced[NTTP->getIndex()] = true;
+}
+
+/// \brief Mark the template parameters that are deduced by the given
+/// type.
+static void
+MarkDeducedTemplateParameters(Sema &SemaRef, QualType T,
+ llvm::SmallVectorImpl<bool> &Deduced) {
+ // Non-dependent types have nothing deducible
+ if (!T->isDependentType())
+ return;
+
+ T = SemaRef.Context.getCanonicalType(T);
+ switch (T->getTypeClass()) {
+ case Type::ExtQual:
+ MarkDeducedTemplateParameters(SemaRef,
+ QualType(cast<ExtQualType>(T.getTypePtr())->getBaseType(), 0),
+ Deduced);
+ break;
+
+ case Type::Pointer:
+ MarkDeducedTemplateParameters(SemaRef,
+ cast<PointerType>(T.getTypePtr())->getPointeeType(),
+ Deduced);
+ break;
+
+ case Type::BlockPointer:
+ MarkDeducedTemplateParameters(SemaRef,
+ cast<BlockPointerType>(T.getTypePtr())->getPointeeType(),
+ Deduced);
+ break;
+
+ case Type::LValueReference:
+ case Type::RValueReference:
+ MarkDeducedTemplateParameters(SemaRef,
+ cast<ReferenceType>(T.getTypePtr())->getPointeeType(),
+ Deduced);
+ break;
+
+ case Type::MemberPointer: {
+ const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr());
+ MarkDeducedTemplateParameters(SemaRef, MemPtr->getPointeeType(), Deduced);
+ MarkDeducedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0),
+ Deduced);
+ break;
+ }
+
+ case Type::DependentSizedArray:
+ MarkDeducedTemplateParameters(
+ cast<DependentSizedArrayType>(T.getTypePtr())->getSizeExpr(),
+ Deduced);
+ // Fall through to check the element type
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ MarkDeducedTemplateParameters(SemaRef,
+ cast<ArrayType>(T.getTypePtr())->getElementType(),
+ Deduced);
+ break;
+
+ case Type::Vector:
+ case Type::ExtVector:
+ MarkDeducedTemplateParameters(SemaRef,
+ cast<VectorType>(T.getTypePtr())->getElementType(),
+ Deduced);
+ break;
+
+ case Type::FunctionProto: {
+ const FunctionProtoType *Proto = cast<FunctionProtoType>(T.getTypePtr());
+ MarkDeducedTemplateParameters(SemaRef, Proto->getResultType(), Deduced);
+ for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I)
+ MarkDeducedTemplateParameters(SemaRef, Proto->getArgType(I), Deduced);
+ break;
+ }
+
+ case Type::TemplateTypeParm:
+ Deduced[cast<TemplateTypeParmType>(T.getTypePtr())->getIndex()] = true;
+ break;
+
+ case Type::TemplateSpecialization: {
+ const TemplateSpecializationType *Spec
+ = cast<TemplateSpecializationType>(T.getTypePtr());
+ if (TemplateDecl *Template = Spec->getTemplateName().getAsTemplateDecl())
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(Template))
+ Deduced[TTP->getIndex()] = true;
+
+ for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
+ MarkDeducedTemplateParameters(SemaRef, Spec->getArg(I), Deduced);
+
+ break;
+ }
+
+ // None of these types have any deducible parts.
+ case Type::Builtin:
+ case Type::FixedWidthInt:
+ case Type::Complex:
+ case Type::VariableArray:
+ case Type::FunctionNoProto:
+ case Type::Record:
+ case Type::Enum:
+ case Type::Typename:
+ case Type::ObjCInterface:
+ case Type::ObjCQualifiedInterface:
+ case Type::ObjCQualifiedId:
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base)
+#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ break;
+ }
+}
+
+/// \brief Mark the template parameters that are deduced by this
+/// template argument.
+static void
+MarkDeducedTemplateParameters(Sema &SemaRef,
+ const TemplateArgument &TemplateArg,
+ llvm::SmallVectorImpl<bool> &Deduced) {
+ switch (TemplateArg.getKind()) {
+ case TemplateArgument::Null:
+ case TemplateArgument::Integral:
+ break;
+
+ case TemplateArgument::Type:
+ MarkDeducedTemplateParameters(SemaRef, TemplateArg.getAsType(), Deduced);
+ break;
+
+ case TemplateArgument::Declaration:
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl()))
+ Deduced[TTP->getIndex()] = true;
+ break;
+
+ case TemplateArgument::Expression:
+ MarkDeducedTemplateParameters(TemplateArg.getAsExpr(), Deduced);
+ break;
+ }
+}
+
+/// \brief Mark the template parameters can be deduced by the given
+/// template argument list.
+///
+/// \param TemplateArgs the template argument list from which template
+/// parameters will be deduced.
+///
+/// \param Deduced a bit vector whose elements will be set to \c true
+/// to indicate when the corresponding template parameter will be
+/// deduced.
+void
+Sema::MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
+ llvm::SmallVectorImpl<bool> &Deduced) {
+ for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
+ ::MarkDeducedTemplateParameters(*this, TemplateArgs[I], Deduced);
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 562749e18fef..18b2d75accbc 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -90,6 +90,30 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
}
}
+Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
+ SourceLocation PointOfInstantiation,
+ ClassTemplatePartialSpecializationDecl *PartialSpec,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange)
+ : SemaRef(SemaRef) {
+
+ Invalid = CheckInstantiationDepth(PointOfInstantiation,
+ InstantiationRange);
+ if (!Invalid) {
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind
+ = ActiveTemplateInstantiation::PartialSpecDeductionInstantiation;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
+ Inst.TemplateArgs = TemplateArgs;
+ Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+ Invalid = false;
+ }
+}
+
void Sema::InstantiatingTemplate::Clear() {
if (!Invalid) {
SemaRef.ActiveTemplateInstantiations.pop_back();
@@ -157,8 +181,50 @@ void Sema::PrintInstantiationStack() {
<< Active->InstantiationRange;
break;
}
+
+ case ActiveTemplateInstantiation::PartialSpecDeductionInstantiation: {
+ ClassTemplatePartialSpecializationDecl *PartialSpec
+ = cast<ClassTemplatePartialSpecializationDecl>((Decl *)Active->Entity);
+ // FIXME: The active template instantiation's template arguments
+ // are interesting, too. We should add something like [with T =
+ // foo, U = bar, etc.] to the string.
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ diag::note_partial_spec_deduct_instantiation_here)
+ << Context.getTypeDeclType(PartialSpec)
+ << Active->InstantiationRange;
+ break;
+ }
+
+ }
+ }
+}
+
+bool Sema::isSFINAEContext() const {
+ using llvm::SmallVector;
+ for (SmallVector<ActiveTemplateInstantiation, 16>::const_reverse_iterator
+ Active = ActiveTemplateInstantiations.rbegin(),
+ ActiveEnd = ActiveTemplateInstantiations.rend();
+ Active != ActiveEnd;
+ ++Active) {
+
+ switch(Active->Kind) {
+ case ActiveTemplateInstantiation::PartialSpecDeductionInstantiation:
+ // We're in a template argument deduction context, so SFINAE
+ // applies.
+ return true;
+
+ case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation:
+ // A default template argument instantiation may or may not be a
+ // SFINAE context; look further up the stack.
+ break;
+
+ case ActiveTemplateInstantiation::TemplateInstantiation:
+ // This is a template instantiation, so there is no SFINAE.
+ return false;
}
}
+
+ return false;
}
//===----------------------------------------------------------------------===/
@@ -236,9 +302,11 @@ TemplateTypeInstantiator::InstantiatePointerType(const PointerType *T,
QualType
TemplateTypeInstantiator::InstantiateBlockPointerType(const BlockPointerType *T,
unsigned Quals) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate BlockPointerType yet");
- return QualType();
+ QualType PointeeType = Instantiate(T->getPointeeType());
+ if (PointeeType.isNull())
+ return QualType();
+
+ return SemaRef.BuildBlockPointerType(PointeeType, Quals, Loc, Entity);
}
QualType
@@ -265,9 +333,16 @@ QualType
TemplateTypeInstantiator::
InstantiateMemberPointerType(const MemberPointerType *T,
unsigned Quals) const {
- // FIXME: Implement this
- assert(false && "Cannot instantiate MemberPointerType yet");
- return QualType();
+ QualType PointeeType = Instantiate(T->getPointeeType());
+ if (PointeeType.isNull())
+ return QualType();
+
+ QualType ClassType = Instantiate(QualType(T->getClass(), 0));
+ if (ClassType.isNull())
+ return QualType();
+
+ return SemaRef.BuildMemberPointerType(PointeeType, ClassType, Quals, Loc,
+ Entity);
}
QualType
@@ -390,7 +465,7 @@ InstantiateFunctionProtoType(const FunctionProtoType *T,
ParamTypes.push_back(P);
}
- return SemaRef.BuildFunctionType(ResultType, &ParamTypes[0],
+ return SemaRef.BuildFunctionType(ResultType, ParamTypes.data(),
ParamTypes.size(),
T->isVariadic(), T->getTypeQuals(),
Loc, Entity);
@@ -502,37 +577,11 @@ InstantiateTemplateSpecializationType(
InstantiatedTemplateArgs.reserve(T->getNumArgs());
for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end();
Arg != ArgEnd; ++Arg) {
- switch (Arg->getKind()) {
- case TemplateArgument::Null:
- assert(false && "Should never have a NULL template argument");
- break;
-
- case TemplateArgument::Type: {
- QualType T = SemaRef.InstantiateType(Arg->getAsType(),
- TemplateArgs,
- 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;
+ TemplateArgument InstArg = SemaRef.Instantiate(*Arg, TemplateArgs);
+ if (InstArg.isNull())
+ return QualType();
- case TemplateArgument::Expression:
- Sema::OwningExprResult E
- = SemaRef.InstantiateExpr(Arg->getAsExpr(), TemplateArgs);
- if (E.isInvalid())
- return QualType();
- InstantiatedTemplateArgs.push_back(E.takeAs<Expr>());
- break;
- }
+ InstantiatedTemplateArgs.push_back(InstArg);
}
// FIXME: We're missing the locations of the template name, '<', and '>'.
@@ -542,7 +591,7 @@ InstantiateTemplateSpecializationType(
TemplateArgs);
return SemaRef.CheckTemplateIdType(Name, Loc, SourceLocation(),
- &InstantiatedTemplateArgs[0],
+ InstantiatedTemplateArgs.data(),
InstantiatedTemplateArgs.size(),
SourceLocation());
}
@@ -831,8 +880,14 @@ Sema::InstantiateClassTemplateSpecialization(
const TemplateArgumentList *TemplateArgs
= &ClassTemplateSpec->getTemplateArgs();
- // Determine whether any class template partial specializations
- // match the given template arguments.
+ // C++ [temp.class.spec.match]p1:
+ // When a class template is used in a context that requires an
+ // instantiation of the class, it is necessary to determine
+ // whether the instantiation is to be generated using the primary
+ // template or one of the partial specializations. This is done by
+ // matching the template arguments of the class template
+ // specialization with the template argument lists of the partial
+ // specializations.
typedef std::pair<ClassTemplatePartialSpecializationDecl *,
TemplateArgumentList *> MatchResult;
llvm::SmallVector<MatchResult, 4> Matched;
@@ -841,20 +896,42 @@ Sema::InstantiateClassTemplateSpecialization(
PartialEnd = Template->getPartialSpecializations().end();
Partial != PartialEnd;
++Partial) {
- if (TemplateArgumentList *Deduced
+ TemplateDeductionInfo Info(Context);
+ if (TemplateDeductionResult Result
= DeduceTemplateArguments(&*Partial,
- ClassTemplateSpec->getTemplateArgs()))
- Matched.push_back(std::make_pair(&*Partial, Deduced));
+ ClassTemplateSpec->getTemplateArgs(),
+ Info)) {
+ // FIXME: Store the failed-deduction information for use in
+ // diagnostics, later.
+ (void)Result;
+ } else {
+ Matched.push_back(std::make_pair(&*Partial, Info.take()));
+ }
}
if (Matched.size() == 1) {
+ // -- If exactly one matching specialization is found, the
+ // instantiation is generated from that specialization.
Pattern = Matched[0].first;
TemplateArgs = Matched[0].second;
} else if (Matched.size() > 1) {
+ // -- If more than one matching specialization is found, the
+ // partial order rules (14.5.4.2) are used to determine
+ // whether one of the specializations is more specialized
+ // than the others. If none of the specializations is more
+ // specialized than all of the other matching
+ // specializations, then the use of the class template is
+ // ambiguous and the program is ill-formed.
// FIXME: Implement partial ordering of class template partial
// specializations.
Diag(ClassTemplateSpec->getLocation(),
diag::unsup_template_partial_spec_ordering);
+ } else {
+ // -- If no matches are found, the instantiation is generated
+ // from the primary template.
+
+ // Since we initialized the pattern and template arguments from
+ // the primary template, there is nothing more we need to do here.
}
// Note that this is an instantiation.
@@ -965,7 +1042,7 @@ Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
if (T.isNull())
return 0;
- if (T->isRecordType() ||
+ if (T->isDependentType() || T->isRecordType() ||
(getLangOptions().CPlusPlus0x && T->isEnumeralType())) {
assert(T.getCVRQualifiers() == 0 && "Can't get cv-qualifiers here");
return NestedNameSpecifier::Create(Context, Prefix,
@@ -1046,3 +1123,38 @@ Sema::InstantiateTemplateName(TemplateName Name, SourceLocation Loc,
// Decl. However, this won't be needed until we implement member templates.
return Name;
}
+
+TemplateArgument Sema::Instantiate(TemplateArgument Arg,
+ const TemplateArgumentList &TemplateArgs) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ assert(false && "Should never have a NULL template argument");
+ break;
+
+ case TemplateArgument::Type: {
+ QualType T = InstantiateType(Arg.getAsType(), TemplateArgs,
+ Arg.getLocation(), DeclarationName());
+ if (T.isNull())
+ return TemplateArgument();
+
+ return TemplateArgument(Arg.getLocation(), T);
+ }
+
+ case TemplateArgument::Declaration:
+ // FIXME: Template instantiation for template template parameters.
+ return Arg;
+
+ case TemplateArgument::Integral:
+ return Arg;
+
+ case TemplateArgument::Expression: {
+ Sema::OwningExprResult E = InstantiateExpr(Arg.getAsExpr(), TemplateArgs);
+ if (E.isInvalid())
+ return TemplateArgument();
+ return TemplateArgument(E.takeAs<Expr>());
+ }
+ }
+
+ assert(false && "Unhandled template argument kind");
+ return TemplateArgument();
+}
diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp
index fa5fdee2c13c..3c67f2ad0d30 100644
--- a/lib/Sema/SemaTemplateInstantiateExpr.cpp
+++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp
@@ -112,6 +112,14 @@ TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) {
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
assert(NTTP->getDepth() == 0 && "No nested templates yet");
const TemplateArgument &Arg = TemplateArgs[NTTP->getPosition()];
+
+ // The template argument itself might be an expression, in which
+ // case we just return that expression.
+ if (Arg.getKind() == TemplateArgument::Expression)
+ // FIXME: Clone the expression!
+ return SemaRef.Owned(Arg.getAsExpr());
+
+ assert(Arg.getKind() == TemplateArgument::Integral);
QualType T = Arg.getIntegralType();
if (T->isCharType() || T->isWideCharType())
return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral(
diff --git a/lib/Sema/SemaTemplateInstantiateStmt.cpp b/lib/Sema/SemaTemplateInstantiateStmt.cpp
index fd349df27edd..efdcec81afff 100644
--- a/lib/Sema/SemaTemplateInstantiateStmt.cpp
+++ b/lib/Sema/SemaTemplateInstantiateStmt.cpp
@@ -260,7 +260,7 @@ Sema::OwningStmtResult TemplateStmtInstantiator::VisitDoStmt(DoStmt *S) {
return SemaRef.StmtError();
return SemaRef.ActOnDoStmt(S->getDoLoc(), move(Body), S->getWhileLoc(),
- move(Cond));
+ SourceLocation(), move(Cond), S->getRParenLoc());
}
Sema::OwningStmtResult TemplateStmtInstantiator::VisitForStmt(ForStmt *S) {
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index cd19d97c5be9..70a92706071d 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -600,7 +600,93 @@ QualType Sema::BuildFunctionType(QualType T,
return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic,
Quals);
}
-
+
+/// \brief Build a member pointer type \c T Class::*.
+///
+/// \param T the type to which the member pointer refers.
+/// \param Class the class type into which the member pointer points.
+/// \param Quals Qualifiers applied to the member pointer type
+/// \param Loc the location where this type begins
+/// \param Entity the name of the entity that will have this member pointer type
+///
+/// \returns a member pointer type, if successful, or a NULL type if there was
+/// an error.
+QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
+ unsigned Quals, SourceLocation Loc,
+ DeclarationName Entity) {
+ // Verify that we're not building a pointer to pointer to function with
+ // exception specification.
+ if (CheckDistantExceptionSpec(T)) {
+ Diag(Loc, diag::err_distant_exception_spec);
+
+ // FIXME: If we're doing this as part of template instantiation,
+ // we should return immediately.
+
+ // Build the type anyway, but use the canonical type so that the
+ // exception specifiers are stripped off.
+ T = Context.getCanonicalType(T);
+ }
+
+ // C++ 8.3.3p3: A pointer to member shall not pointer to ... a member
+ // with reference type, or "cv void."
+ if (T->isReferenceType()) {
+ Diag(Loc, diag::err_illegal_decl_pointer_to_reference)
+ << (Entity? Entity.getAsString() : "type name");
+ return QualType();
+ }
+
+ if (T->isVoidType()) {
+ Diag(Loc, diag::err_illegal_decl_mempointer_to_void)
+ << (Entity? Entity.getAsString() : "type name");
+ return QualType();
+ }
+
+ // Enforce C99 6.7.3p2: "Types other than pointer types derived from
+ // object or incomplete types shall not be restrict-qualified."
+ if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) {
+ Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
+ << T;
+
+ // FIXME: If we're doing this as part of template instantiation,
+ // we should return immediately.
+ Quals &= ~QualType::Restrict;
+ }
+
+ if (!Class->isDependentType() && !Class->isRecordType()) {
+ Diag(Loc, diag::err_mempointer_in_nonclass_type) << Class;
+ return QualType();
+ }
+
+ return Context.getMemberPointerType(T, Class.getTypePtr())
+ .getQualifiedType(Quals);
+}
+
+/// \brief Build a block pointer type.
+///
+/// \param T The type to which we'll be building a block pointer.
+///
+/// \param Quals The cvr-qualifiers to be applied to the block pointer type.
+///
+/// \param Loc The location of the entity whose type involves this
+/// block pointer type or, if there is no such entity, the location of the
+/// type that will have block pointer type.
+///
+/// \param Entity The name of the entity that involves the block pointer
+/// type, if known.
+///
+/// \returns A suitable block pointer type, if there are no
+/// errors. Otherwise, returns a NULL type.
+QualType Sema::BuildBlockPointerType(QualType T, unsigned Quals,
+ SourceLocation Loc,
+ DeclarationName Entity) {
+ if (!T.getTypePtr()->isFunctionType()) {
+ Diag(Loc, diag::err_nonfunction_block_type);
+ return QualType();
+ }
+
+ return Context.getBlockPointerType(T).getQualifiedType(Quals);
+}
+
/// GetTypeForDeclarator - Convert the type for the specified
/// declarator to Type instances. Skip the outermost Skip type
/// objects.
@@ -675,11 +761,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
if (!LangOpts.Blocks)
Diag(DeclType.Loc, diag::err_blocks_disable);
- if (!T.getTypePtr()->isFunctionType())
- Diag(D.getIdentifierLoc(), diag::err_nonfunction_block_type);
- else
- T = (Context.getBlockPointerType(T)
- .getQualifiedType(DeclType.Cls.TypeQuals));
+ T = BuildBlockPointerType(T, DeclType.Cls.TypeQuals, D.getIdentifierLoc(),
+ Name);
break;
case DeclaratorChunk::Pointer:
// Verify that we're not building a pointer to pointer to function with
@@ -870,57 +953,32 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
break;
}
case DeclaratorChunk::MemberPointer:
- // Verify that we're not building a pointer to pointer to function with
- // exception specification.
- if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
- Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
- D.setInvalidType(true);
- // Build the type anyway.
- }
// The scope spec must refer to a class, or be dependent.
- DeclContext *DC = computeDeclContext(DeclType.Mem.Scope());
QualType ClsType;
- // FIXME: Extend for dependent types when it's actually supported.
- // See ActOnCXXNestedNameSpecifier.
- if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC)) {
+ if (isDependentScopeSpecifier(DeclType.Mem.Scope())) {
+ NestedNameSpecifier *NNS
+ = (NestedNameSpecifier *)DeclType.Mem.Scope().getScopeRep();
+ assert(NNS->getAsType() && "Nested-name-specifier must name a type");
+ ClsType = QualType(NNS->getAsType(), 0);
+ } else if (CXXRecordDecl *RD
+ = dyn_cast_or_null<CXXRecordDecl>(
+ computeDeclContext(DeclType.Mem.Scope()))) {
ClsType = Context.getTagDeclType(RD);
} else {
- if (DC) {
- Diag(DeclType.Mem.Scope().getBeginLoc(),
- diag::err_illegal_decl_mempointer_in_nonclass)
- << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name")
- << DeclType.Mem.Scope().getRange();
- }
+ Diag(DeclType.Mem.Scope().getBeginLoc(),
+ diag::err_illegal_decl_mempointer_in_nonclass)
+ << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name")
+ << DeclType.Mem.Scope().getRange();
D.setInvalidType(true);
- ClsType = Context.IntTy;
}
- // C++ 8.3.3p3: A pointer to member shall not pointer to ... a member
- // with reference type, or "cv void."
- if (T->isReferenceType()) {
- Diag(DeclType.Loc, diag::err_illegal_decl_pointer_to_reference)
- << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
- D.setInvalidType(true);
+ if (!ClsType.isNull())
+ T = BuildMemberPointerType(T, ClsType, DeclType.Mem.TypeQuals,
+ DeclType.Loc, D.getIdentifier());
+ if (T.isNull()) {
T = Context.IntTy;
+ D.setInvalidType(true);
}
- if (T->isVoidType()) {
- Diag(DeclType.Loc, diag::err_illegal_decl_mempointer_to_void)
- << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
- T = Context.IntTy;
- }
-
- // Enforce C99 6.7.3p2: "Types other than pointer types derived from
- // object or incomplete types shall not be restrict-qualified."
- if ((DeclType.Mem.TypeQuals & QualType::Restrict) &&
- !T->isIncompleteOrObjectType()) {
- Diag(DeclType.Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
- << T;
- DeclType.Mem.TypeQuals &= ~QualType::Restrict;
- }
-
- T = Context.getMemberPointerType(T, ClsType.getTypePtr()).
- getQualifiedType(DeclType.Mem.TypeQuals);
-
break;
}