summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--clang/lib/Sema/Sema.cpp5
-rw-r--r--clang/lib/Sema/Sema.h26
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp132
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp151
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp1
-rw-r--r--clang/test/CXX/temp/temp.param/p12.cpp2
-rw-r--r--clang/test/SemaTemplate/default-arguments.cpp2
8 files changed, 211 insertions, 110 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e0ac0ada8bd..f0e1be82a72 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1102,6 +1102,8 @@ def note_partial_spec_deduct_instantiation_here : Note<
def note_prior_template_arg_substitution : Note<
"while substituting prior template arguments into %select{non-type|template}0"
" template parameter%1 %2">;
+def note_template_default_arg_checking : Note<
+ "while checking a default template argument used here">;
def err_field_instantiates_to_function : Error<
"data member instantiated with function type %0">;
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 38063ac0185..5c92b65f82c 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -355,8 +355,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0),
GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated),
CompleteTranslationUnit(CompleteTranslationUnit),
- NumSFINAEErrors(0), CurrentInstantiationScope(0) {
-
+ NumSFINAEErrors(0), NonInstantiationEntries(0),
+ CurrentInstantiationScope(0)
+{
TUScope = 0;
if (getLangOptions().CPlusPlus)
FieldCollector.reset(new CXXFieldCollector());
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index b9cacafc4ca..2fea5539a81 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -2889,7 +2889,11 @@ public:
/// We are substituting prior template arguments into a new
/// template parameter. The template parameter itself is either a
/// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl.
- PriorTemplateArgumentSubstitution
+ PriorTemplateArgumentSubstitution,
+
+ /// We are checking the validity of a default template argument that
+ /// has been used when naming a template-id.
+ DefaultTemplateArgumentChecking
} Kind;
/// \brief The point of instantiation within the source code.
@@ -2918,6 +2922,10 @@ public:
: Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0),
NumTemplateArgs(0) {}
+ /// \brief Determines whether this template is an actual instantiation
+ /// that should be counted toward the maximum instantiation depth.
+ bool isInstantiationRecord() const;
+
friend bool operator==(const ActiveTemplateInstantiation &X,
const ActiveTemplateInstantiation &Y) {
if (X.Kind != Y.Kind)
@@ -2931,6 +2939,7 @@ public:
return true;
case PriorTemplateArgumentSubstitution:
+ case DefaultTemplateArgumentChecking:
if (X.Template != Y.Template)
return false;
@@ -2962,6 +2971,11 @@ public:
llvm::SmallVector<ActiveTemplateInstantiation, 16>
ActiveTemplateInstantiations;
+ /// \brief The number of ActiveTemplateInstantiation entries in
+ /// \c ActiveTemplateInstantiations that are not actual instantiations and,
+ /// therefore, should not be counted as part of the instantiation depth.
+ unsigned NonInstantiationEntries;
+
/// \brief The last template from which a template instantiation
/// error or warning was produced.
///
@@ -3037,6 +3051,16 @@ public:
unsigned NumTemplateArgs,
SourceRange InstantiationRange);
+ /// \brief Note that we are checking the default template argument
+ /// against the template parameter for a given template-id.
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ NamedDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange);
+
+
/// \brief Note that we have finished instantiating this template.
void Clear();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index aace9834416..ee928bccaf9 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1856,73 +1856,87 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
continue;
}
- // Decode the template argument
+ if (ArgIdx < NumArgs) {
+ // Check the template argument we were given.
+ if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template,
+ TemplateLoc, RAngleLoc, Converted))
+ return true;
+
+ continue;
+ }
+
+ // We have a default template argument that we will use.
TemplateArgumentLoc Arg;
+
+ // Retrieve the default template argument from the template
+ // parameter. For each kind of template parameter, we substitute the
+ // template arguments provided thus far and any "outer" template arguments
+ // (when the template parameter was part of a nested template) into
+ // the default argument.
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+ if (!TTP->hasDefaultArgument()) {
+ assert((Invalid || PartialTemplateArgs) && "Missing default argument");
+ break;
+ }
- if (ArgIdx >= NumArgs) {
- // Retrieve the default template argument from the template
- // parameter.
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
- if (TTP->isParameterPack()) {
- // We have an empty argument pack.
- Converted.BeginPack();
- Converted.EndPack();
- break;
- }
-
- if (!TTP->hasDefaultArgument())
- break;
-
- DeclaratorInfo *ArgType = SubstDefaultTemplateArgument(*this,
- Template,
- TemplateLoc,
- RAngleLoc,
- TTP,
- Converted);
- if (!ArgType)
- return true;
-
- Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()),
- ArgType);
- } else if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- if (!NTTP->hasDefaultArgument())
- break;
-
- Sema::OwningExprResult E = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- NTTP,
- Converted);
- if (E.isInvalid())
- return true;
+ DeclaratorInfo *ArgType = SubstDefaultTemplateArgument(*this,
+ Template,
+ TemplateLoc,
+ RAngleLoc,
+ TTP,
+ Converted);
+ if (!ArgType)
+ return true;
+
+ Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()),
+ ArgType);
+ } else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
+ if (!NTTP->hasDefaultArgument()) {
+ assert((Invalid || PartialTemplateArgs) && "Missing default argument");
+ break;
+ }
- Expr *Ex = E.takeAs<Expr>();
- Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex);
- } else {
- TemplateTemplateParmDecl *TempParm
- = cast<TemplateTemplateParmDecl>(*Param);
+ Sema::OwningExprResult E = SubstDefaultTemplateArgument(*this, Template,
+ TemplateLoc,
+ RAngleLoc,
+ NTTP,
+ Converted);
+ if (E.isInvalid())
+ return true;
- if (!TempParm->hasDefaultArgument())
- break;
+ Expr *Ex = E.takeAs<Expr>();
+ Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex);
+ } else {
+ TemplateTemplateParmDecl *TempParm
+ = cast<TemplateTemplateParmDecl>(*Param);
- TemplateName Name = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- TempParm,
- Converted);
- if (Name.isNull())
- return true;
-
- Arg = TemplateArgumentLoc(TemplateArgument(Name),
- TempParm->getDefaultArgument().getTemplateQualifierRange(),
- TempParm->getDefaultArgument().getTemplateNameLoc());
+ if (!TempParm->hasDefaultArgument()) {
+ assert((Invalid || PartialTemplateArgs) && "Missing default argument");
+ break;
}
- } else {
- // Retrieve the template argument produced by the user.
- Arg = TemplateArgs[ArgIdx];
+
+ TemplateName Name = SubstDefaultTemplateArgument(*this, Template,
+ TemplateLoc,
+ RAngleLoc,
+ TempParm,
+ Converted);
+ if (Name.isNull())
+ return true;
+
+ Arg = TemplateArgumentLoc(TemplateArgument(Name),
+ TempParm->getDefaultArgument().getTemplateQualifierRange(),
+ TempParm->getDefaultArgument().getTemplateNameLoc());
}
+ // Introduce an instantiation record that describes where we are using
+ // the default template argument.
+ InstantiatingTemplate Instantiating(*this, RAngleLoc, Template, *Param,
+ Converted.getFlatArguments(),
+ Converted.flatSize(),
+ SourceRange(TemplateLoc, RAngleLoc));
+
+ // Check the default template argument.
if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc,
RAngleLoc, Converted))
return true;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index b1e0481932f..b303dce06ff 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -96,6 +96,23 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
return Result;
}
+bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const {
+ switch (Kind) {
+ case TemplateInstantiation:
+ case DefaultTemplateArgumentInstantiation:
+ case DefaultFunctionArgumentInstantiation:
+ return true;
+
+ case ExplicitTemplateArgumentSubstitution:
+ case DeducedTemplateArgumentSubstitution:
+ case PriorTemplateArgumentSubstitution:
+ case DefaultTemplateArgumentChecking:
+ return false;
+ }
+
+ return true;
+}
+
Sema::InstantiatingTemplate::
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Decl *Entity,
@@ -113,7 +130,6 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Inst.NumTemplateArgs = 0;
Inst.InstantiationRange = InstantiationRange;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- Invalid = false;
}
}
@@ -137,7 +153,6 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
Inst.NumTemplateArgs = NumTemplateArgs;
Inst.InstantiationRange = InstantiationRange;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- Invalid = false;
}
}
@@ -161,7 +176,9 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
Inst.NumTemplateArgs = NumTemplateArgs;
Inst.InstantiationRange = InstantiationRange;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- Invalid = false;
+
+ if (!Inst.isInstantiationRecord())
+ ++SemaRef.NonInstantiationEntries;
}
}
@@ -173,20 +190,19 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
SourceRange InstantiationRange)
: SemaRef(SemaRef) {
- Invalid = CheckInstantiationDepth(PointOfInstantiation,
- InstantiationRange);
- if (!Invalid) {
- ActiveTemplateInstantiation Inst;
- Inst.Kind
- = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
- 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;
- }
+ Invalid = false;
+
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
+ Inst.TemplateArgs = TemplateArgs;
+ Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+
+ assert(!Inst.isInstantiationRecord());
+ ++SemaRef.NonInstantiationEntries;
}
Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
@@ -219,19 +235,20 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceRange InstantiationRange) : SemaRef(SemaRef) {
- Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
+ Invalid = false;
- if (!Invalid) {
- ActiveTemplateInstantiation Inst;
- Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Template = Template;
- Inst.Entity = reinterpret_cast<uintptr_t>(Param);
- Inst.TemplateArgs = TemplateArgs;
- Inst.NumTemplateArgs = NumTemplateArgs;
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- }
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Template = Template;
+ Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.TemplateArgs = TemplateArgs;
+ Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+
+ assert(!Inst.isInstantiationRecord());
+ ++SemaRef.NonInstantiationEntries;
}
Sema::InstantiatingTemplate::
@@ -241,23 +258,51 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceRange InstantiationRange) : SemaRef(SemaRef) {
- Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
+ Invalid = false;
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Template = Template;
+ Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.TemplateArgs = TemplateArgs;
+ Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- if (!Invalid) {
- ActiveTemplateInstantiation Inst;
- Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Template = Template;
- Inst.Entity = reinterpret_cast<uintptr_t>(Param);
- Inst.TemplateArgs = TemplateArgs;
- Inst.NumTemplateArgs = NumTemplateArgs;
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- }
+ assert(!Inst.isInstantiationRecord());
+ ++SemaRef.NonInstantiationEntries;
+}
+
+Sema::InstantiatingTemplate::
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ NamedDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange) : SemaRef(SemaRef) {
+ Invalid = false;
+
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind = ActiveTemplateInstantiation::DefaultTemplateArgumentChecking;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Template = Template;
+ Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.TemplateArgs = TemplateArgs;
+ Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+
+ assert(!Inst.isInstantiationRecord());
+ ++SemaRef.NonInstantiationEntries;
}
void Sema::InstantiatingTemplate::Clear() {
if (!Invalid) {
+ if (!SemaRef.ActiveTemplateInstantiations.back().isInstantiationRecord()) {
+ assert(SemaRef.NonInstantiationEntries > 0);
+ --SemaRef.NonInstantiationEntries;
+ }
+
SemaRef.ActiveTemplateInstantiations.pop_back();
Invalid = true;
}
@@ -266,8 +311,11 @@ void Sema::InstantiatingTemplate::Clear() {
bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
SourceLocation PointOfInstantiation,
SourceRange InstantiationRange) {
- if (SemaRef.ActiveTemplateInstantiations.size()
- <= SemaRef.getLangOptions().InstantiationDepth)
+ assert(SemaRef.NonInstantiationEntries <=
+ SemaRef.ActiveTemplateInstantiations.size());
+ if ((SemaRef.ActiveTemplateInstantiations.size() -
+ SemaRef.NonInstantiationEntries)
+ <= SemaRef.getLangOptions().InstantiationDepth)
return false;
SemaRef.Diag(PointOfInstantiation,
@@ -391,6 +439,17 @@ void Sema::PrintInstantiationStack() {
<< Active->InstantiationRange;
break;
}
+
+ case ActiveTemplateInstantiation::DefaultTemplateArgumentChecking: {
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ diag::note_template_default_arg_checking)
+ << getTemplateArgumentBindingsText(
+ Active->Template->getTemplateParameters(),
+ Active->TemplateArgs,
+ Active->NumTemplateArgs)
+ << Active->InstantiationRange;
+ break;
+ }
}
}
}
@@ -401,17 +460,17 @@ bool Sema::isSFINAEContext() const {
Active = ActiveTemplateInstantiations.rbegin(),
ActiveEnd = ActiveTemplateInstantiations.rend();
Active != ActiveEnd;
- ++Active) {
-
+ ++Active)
+ {
switch(Active->Kind) {
case ActiveTemplateInstantiation::TemplateInstantiation:
case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
-
// This is a template instantiation, so there is no SFINAE.
return false;
case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation:
case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution:
+ case ActiveTemplateInstantiation::DefaultTemplateArgumentChecking:
// A default template argument instantiation and substitution into
// template parameters with arguments for prior parameters may or may
// not be a SFINAE context; look further up the stack.
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index ab712946dc5..47d2701bcd3 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1285,6 +1285,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
(void) FunTmpl;
ActiveInst.Kind = ActiveInstType::TemplateInstantiation;
ActiveInst.Entity = reinterpret_cast<uintptr_t>(New);
+ --SemaRef.NonInstantiationEntries;
}
}
diff --git a/clang/test/CXX/temp/temp.param/p12.cpp b/clang/test/CXX/temp/temp.param/p12.cpp
index 10bdb656649..3864fbeaa11 100644
--- a/clang/test/CXX/temp/temp.param/p12.cpp
+++ b/clang/test/CXX/temp/temp.param/p12.cpp
@@ -36,4 +36,4 @@ template<template<class, int> class // expected-note{{previous template template
= Y1> // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
class C1 {};
-C1<> c1;
+C1<> c1; // expected-note{{while checking a default template argument}}
diff --git a/clang/test/SemaTemplate/default-arguments.cpp b/clang/test/SemaTemplate/default-arguments.cpp
index e1999218dd0..e082693aa52 100644
--- a/clang/test/SemaTemplate/default-arguments.cpp
+++ b/clang/test/SemaTemplate/default-arguments.cpp
@@ -116,5 +116,5 @@ template<typename T,
struct X6 {};
X6<int> x6a;
-X6<long> x6b;
+X6<long> x6b; // expected-note{{while checking a default template argument}}
X6<long, X5b> x6c;
OpenPOWER on IntegriCloud