diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 6 | ||||
-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 | ||||
-rw-r--r-- | clang/test/CXX/temp/temp.fct.spec/temp.deduct/sfinae-1.cpp | 17 | ||||
-rw-r--r-- | clang/test/SemaTemplate/operator-template.cpp | 4 |
7 files changed, 132 insertions, 33 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5847945a4f8..af8999e305e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -839,6 +839,12 @@ def note_function_template_spec_here : Note< def note_default_arg_instantiation_here : Note< "in instantiation of default argument for '%0' required here">; +def note_explicit_template_arg_substitution_here : Note< + "while substituting explicitly-specified template arguments into function " + "template %f, here">; +def note_function_template_deduction_instantiation_here : Note< + "while substituting deduced template arguments into function template %0, " + "here">; def note_partial_spec_deduct_instantiation_here : Note< "during template argument deduction for class template partial " "specialization %0, here">; 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; } diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/sfinae-1.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/sfinae-1.cpp new file mode 100644 index 00000000000..b9057b94aa7 --- /dev/null +++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/sfinae-1.cpp @@ -0,0 +1,17 @@ +// RUN: clang-cc + +typedef char one_byte; +struct two_bytes { char data[2]; }; + +template<typename T> one_byte __is_class_check(int T::*); +template<typename T> two_bytes __is_class_check(...); + +template<typename T> struct is_class { + static const bool value = sizeof(__is_class_check<T>(0)) == 1; +}; + +struct X { }; + +int array0[is_class<X>::value? 1 : -1]; +int array1[is_class<int>::value? -1 : 1]; +int array2[is_class<char[3]>::value? -1 : 1]; diff --git a/clang/test/SemaTemplate/operator-template.cpp b/clang/test/SemaTemplate/operator-template.cpp index d65a2781c87..7039e0ec83d 100644 --- a/clang/test/SemaTemplate/operator-template.cpp +++ b/clang/test/SemaTemplate/operator-template.cpp @@ -7,10 +7,10 @@ int a(A<int> x) { return operator==(x,1); } int a0(A<int> x) { return x == 1; } -// FIXME: The diagnostic here is a bit messed up +// FIXME: the location information for the note isn't very good template<class X>struct B{typedef X Y;}; template<class X>bool operator==(B<X>*,typename B<X>::Y); // \ expected-error{{overloaded 'operator==' must have at least one parameter of class or enumeration type}} \ -expected-note{{in instantiation of default argument for 'operator==<int>' required here}} +expected-note{{in instantiation of member function}} int a(B<int> x) { return operator==(&x,1); } |