diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-07-01 22:01:06 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-07-01 22:01:06 +0000 |
commit | ff6cbdf806da9fb5a62ebf7721660940d4bbb838 (patch) | |
tree | 32f70cd644e774775cdb7a83630a2e531dc769ad /clang/lib | |
parent | affb68bd08a2cd0f1e4dbeacfbdc1acc14c589ba (diff) | |
download | bcm5719-llvm-ff6cbdf806da9fb5a62ebf7721660940d4bbb838.tar.gz bcm5719-llvm-ff6cbdf806da9fb5a62ebf7721660940d4bbb838.zip |
Keep track of more information within the template instantiation stack, e.g.,
by distinguishing between substitution that occurs for template
argument deduction vs. explicitly-specifiad template arguments. This
is used both to improve diagnostics and to make sure we only provide
SFINAE in those cases where SFINAE should apply.
In addition, deal with the sticky issue where SFINAE only considers
substitution of template arguments into the *type* of a function
template; we need to issue hard errors beyond this point, as
test/SemaTemplate/operator-template.cpp illustrates.
llvm-svn: 74651
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/Sema.h | 31 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 79 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 22 |
4 files changed, 107 insertions, 31 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 338221e4d41..a6c34e88857 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2359,7 +2359,7 @@ public: /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { /// \brief The kind of template instantiation we are performing - enum { + enum InstantiationKind { /// We are instantiating a template declaration. The entity is /// the declaration we're instantiating (e.g., a CXXRecordDecl). TemplateInstantiation, @@ -2371,13 +2371,16 @@ public: /// 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 + /// We are substituting explicit template arguments provided for + /// a function template. The entity is a FunctionTemplateDecl. + ExplicitTemplateArgumentSubstitution, + + /// We are substituting template argument determined as part of + /// template argument deduction for either a class template + /// partial specialization or a function template. The + /// Entity is either a ClassTemplatePartialSpecializationDecl or + /// a FunctionTemplateDecl. + DeducedTemplateArgumentSubstitution } Kind; /// \brief The point of instantiation within the source code. @@ -2411,7 +2414,8 @@ public: return true; case DefaultTemplateArgumentInstantiation: - case PartialSpecDeductionInstantiation: + case ExplicitTemplateArgumentSubstitution: + case DeducedTemplateArgumentSubstitution: return X.TemplateArgs == Y.TemplateArgs; } @@ -2468,6 +2472,15 @@ public: unsigned NumTemplateArgs, SourceRange InstantiationRange = SourceRange()); + /// \brief Note that we are instantiating a default argument in a + /// template-id. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + FunctionTemplateDecl *FunctionTemplate, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + ActiveTemplateInstantiation::InstantiationKind Kind, + SourceRange InstantiationRange = SourceRange()); + /// \brief Note that we are instantiating as part of template /// argument deduction for a class template partial /// specialization. diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index ae0e7040654..5a0578f6bcb 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -939,7 +939,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // explicitly-specified template arguments against this function template, // and then substitute them into the function parameter types. InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), - FunctionTemplate, Deduced.data(), Deduced.size()); + FunctionTemplate, Deduced.data(), Deduced.size(), + ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution); if (Inst) return TDK_InstantiationDepth; @@ -1106,7 +1107,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // Enter a new template instantiation context while we instantiate the // actual function declaration. InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), - FunctionTemplate, Deduced.data(), Deduced.size()); + FunctionTemplate, Deduced.data(), Deduced.size(), + ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); if (Inst) return TDK_InstantiationDepth; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 3bc1cf9504b..6c2dc77b4cc 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -100,6 +100,30 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + FunctionTemplateDecl *FunctionTemplate, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + ActiveTemplateInstantiation::InstantiationKind Kind, + SourceRange InstantiationRange) +: SemaRef(SemaRef) { + + Invalid = CheckInstantiationDepth(PointOfInstantiation, + InstantiationRange); + if (!Invalid) { + ActiveTemplateInstantiation Inst; + Inst.Kind = Kind; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Entity = reinterpret_cast<uintptr_t>(FunctionTemplate); + Inst.TemplateArgs = TemplateArgs; + Inst.NumTemplateArgs = NumTemplateArgs; + Inst.InstantiationRange = InstantiationRange; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + Invalid = false; + } +} + +Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, + SourceLocation PointOfInstantiation, ClassTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, @@ -111,7 +135,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, if (!Invalid) { ActiveTemplateInstantiation Inst; Inst.Kind - = ActiveTemplateInstantiation::PartialSpecDeductionInstantiation; + = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution; Inst.PointOfInstantiation = PointOfInstantiation; Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec); Inst.TemplateArgs = TemplateArgs; @@ -148,6 +172,7 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth( /// \brief Prints the current instantiation stack through a series of /// notes. void Sema::PrintInstantiationStack() { + // FIXME: In all of these cases, we need to show the template arguments for (llvm::SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator Active = ActiveTemplateInstantiations.rbegin(), ActiveEnd = ActiveTemplateInstantiations.rend(); @@ -183,7 +208,7 @@ void Sema::PrintInstantiationStack() { TemplateDecl *Template = cast<TemplateDecl>((Decl *)Active->Entity); std::string TemplateArgsStr = TemplateSpecializationType::PrintTemplateArgumentList( - Active->TemplateArgs, + Active->TemplateArgs, Active->NumTemplateArgs, Context.PrintingPolicy); Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), @@ -193,18 +218,31 @@ void Sema::PrintInstantiationStack() { 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. + case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: { + FunctionTemplateDecl *FnTmpl + = cast<FunctionTemplateDecl>((Decl *)Active->Entity); Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), - diag::note_partial_spec_deduct_instantiation_here) - << Context.getTypeDeclType(PartialSpec) - << Active->InstantiationRange; + diag::note_explicit_template_arg_substitution_here) + << FnTmpl << Active->InstantiationRange; break; } + + case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution: + if (ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<ClassTemplatePartialSpecializationDecl>( + (Decl *)Active->Entity)) { + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + diag::note_partial_spec_deduct_instantiation_here) + << Context.getTypeDeclType(PartialSpec) + << Active->InstantiationRange; + } else { + FunctionTemplateDecl *FnTmpl + = cast<FunctionTemplateDecl>((Decl *)Active->Entity); + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + diag::note_function_template_deduction_instantiation_here) + << FnTmpl << Active->InstantiationRange; + } + break; } } @@ -219,19 +257,20 @@ bool Sema::isSFINAEContext() const { ++Active) { switch(Active->Kind) { - case ActiveTemplateInstantiation::PartialSpecDeductionInstantiation: - // We're in a template argument deduction context, so SFINAE - // applies. - return true; - + case ActiveTemplateInstantiation::TemplateInstantiation: + // This is a template instantiation, so there is no SFINAE. + return false; + 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; + + case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: + case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution: + // We're either substitution explicitly-specified template arguments + // or deduced template arguments, so SFINAE applies. + return true; } } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 769e0d222ae..f5971999206 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -628,6 +628,28 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl) { if (Tmpl->isDeleted()) New->setDeleted(); + + // If we are performing substituting explicitly-specified template arguments + // or deduced template arguments into a function template and we reach this + // point, we are now past the point where SFINAE applies and have committed + // to keeping the new function template specialization. We therefore + // convert the active template instantiation for the function template + // into a template instantiation for this specific function template + // specialization, which is not a SFINAE context, so that we diagnose any + // further errors in the declaration itself. + typedef Sema::ActiveTemplateInstantiation ActiveInstType; + ActiveInstType &ActiveInst = SemaRef.ActiveTemplateInstantiations.back(); + if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution || + ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) { + if (FunctionTemplateDecl *FunTmpl + = dyn_cast<FunctionTemplateDecl>((Decl *)ActiveInst.Entity)) { + assert(FunTmpl->getTemplatedDecl() == Tmpl && + "Deduction from the wrong function template?"); + ActiveInst.Kind = ActiveInstType::TemplateInstantiation; + ActiveInst.Entity = reinterpret_cast<uintptr_t>(New); + } + } + return false; } |