From: Douglas Gregor Date: Wed, 11 Nov 2009 21:54:23 +0000 (+0000) Subject: Improve diagnostics when a default template argument does not match X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f35f828f9883123772a9731af190a608f3236ef4;p=clang Improve diagnostics when a default template argument does not match with its corresponding template parameter. This can happen when we performed some substitution into the default template argument and what we had doesn't match any more, e.g., template struct A; template class X = A> class B; B b; Previously, we'd emit a pretty but disembodied diagnostic showing how the default argument didn't match the template parameter. The diagnostic was good, but nothing tied it to the *use* of the default argument in "B". This commit fixes that. Also, tweak the counting of active template instantiations to avoid counting non-instantiation records, such as those we create for (surprise!) checking default arguments, instantiating default arguments, and performing substitutions as part of template argument deduction. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86884 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index e0ac0ada8b..f0e1be82a7 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/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/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 38063ac018..5c92b65f82 100644 --- a/lib/Sema/Sema.cpp +++ b/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/lib/Sema/Sema.h b/lib/Sema/Sema.h index b9cacafc4c..2fea5539a8 100644 --- a/lib/Sema/Sema.h +++ b/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 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/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index aace983441..ee928bccaf 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/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(*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(*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(*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(*Param)) { + if (!NTTP->hasDefaultArgument()) { + assert((Invalid || PartialTemplateArgs) && "Missing default argument"); + break; + } - Expr *Ex = E.takeAs(); - Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex); - } else { - TemplateTemplateParmDecl *TempParm - = cast(*Param); + Sema::OwningExprResult E = SubstDefaultTemplateArgument(*this, Template, + TemplateLoc, + RAngleLoc, + NTTP, + Converted); + if (E.isInvalid()) + return true; - if (!TempParm->hasDefaultArgument()) - break; + Expr *Ex = E.takeAs(); + Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex); + } else { + TemplateTemplateParmDecl *TempParm + = cast(*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/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index b1e0481932..b303dce06f 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/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(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(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(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(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(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(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(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/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index ab712946dc..47d2701bcd 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1285,6 +1285,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, (void) FunTmpl; ActiveInst.Kind = ActiveInstType::TemplateInstantiation; ActiveInst.Entity = reinterpret_cast(New); + --SemaRef.NonInstantiationEntries; } } diff --git a/test/CXX/temp/temp.param/p12.cpp b/test/CXX/temp/temp.param/p12.cpp index 10bdb65664..3864fbeaa1 100644 --- a/test/CXX/temp/temp.param/p12.cpp +++ b/test/CXX/temp/temp.param/p12.cpp @@ -36,4 +36,4 @@ template 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/test/SemaTemplate/default-arguments.cpp b/test/SemaTemplate/default-arguments.cpp index e1999218dd..e082693aa5 100644 --- a/test/SemaTemplate/default-arguments.cpp +++ b/test/SemaTemplate/default-arguments.cpp @@ -116,5 +116,5 @@ template x6a; -X6 x6b; +X6 x6b; // expected-note{{while checking a default template argument}} X6 x6c;