diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index 3fdb206ef146..ffce99bf9f7d 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -551,15 +551,13 @@ public: OverloadsShown getShowOverloads() const { return ShowOverloads; } /// \brief Pretend that the last diagnostic issued was ignored, so any - /// subsequent notes will be suppressed, or restore a prior ignoring - /// state after ignoring some diagnostics and their notes, possibly in - /// the middle of another diagnostic. + /// subsequent notes will be suppressed. /// /// This can be used by clients who suppress diagnostics themselves. - void setLastDiagnosticIgnored(bool Ignored = true) { + void setLastDiagnosticIgnored() { if (LastDiagLevel == DiagnosticIDs::Fatal) FatalErrorOccurred = true; - LastDiagLevel = Ignored ? DiagnosticIDs::Ignored : DiagnosticIDs::Warning; + LastDiagLevel = DiagnosticIDs::Ignored; } /// \brief Determine whether the previous diagnostic was ignored. This can diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index b5e78bd01e7b..2d37ed2cdeaa 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7210,16 +7210,13 @@ public: unsigned PrevSFINAEErrors; bool PrevInNonInstantiationSFINAEContext; bool PrevAccessCheckingSFINAE; - bool PrevLastDiagnosticIgnored; public: explicit SFINAETrap(Sema &SemaRef, bool AccessCheckingSFINAE = false) : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors), PrevInNonInstantiationSFINAEContext( SemaRef.InNonInstantiationSFINAEContext), - PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE), - PrevLastDiagnosticIgnored( - SemaRef.getDiagnostics().isLastDiagnosticIgnored()) + PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE) { if (!SemaRef.isSFINAEContext()) SemaRef.InNonInstantiationSFINAEContext = true; @@ -7231,8 +7228,6 @@ public: SemaRef.InNonInstantiationSFINAEContext = PrevInNonInstantiationSFINAEContext; SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE; - SemaRef.getDiagnostics().setLastDiagnosticIgnored( - PrevLastDiagnosticIgnored); } /// \brief Determine whether any SFINAE errors have been trapped. diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index d9acc77c6d7c..5d78fd437e2a 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2242,7 +2242,7 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( SmallVectorImpl &Deduced, TemplateDeductionInfo &Info, SmallVectorImpl &Builder, LocalInstantiationScope *CurrentInstantiationScope = nullptr, - unsigned NumAlreadyConverted = 0, bool SkipNonDeduced = false) { + unsigned NumAlreadyConverted = 0, bool PartialOverloading = false) { TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { @@ -2330,14 +2330,11 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( // If there was no default argument, deduction is incomplete. if (DefArg.getArgument().isNull()) { - if (SkipNonDeduced) { - Builder.push_back(TemplateArgument()); - continue; - } - Info.Param = makeTemplateParameter( const_cast(TemplateParams->getParam(I))); Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); + if (PartialOverloading) break; + return HasDefaultArg ? Sema::TDK_SubstitutionFailure : Sema::TDK_Incomplete; } @@ -3298,9 +3295,9 @@ static bool AdjustFunctionParmAndArgTypesForDeduction( return false; } -static bool hasDeducibleTemplateParameters(Sema &S, - TemplateParameterList *Params, - QualType T); +static bool +hasDeducibleTemplateParameters(Sema &S, FunctionTemplateDecl *FunctionTemplate, + QualType T); static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( Sema &S, TemplateParameterList *TemplateParams, unsigned FirstInnerIndex, @@ -3489,7 +3486,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // Template argument deduction is done by comparing each function template // parameter that contains template-parameters that participate in // template argument deduction ... - if (!hasDeducibleTemplateParameters(*this, TemplateParams, ParamType)) + if (!hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) return Sema::TDK_Success; // ... with the type of the corresponding argument @@ -4368,7 +4365,6 @@ static bool isAtLeastAsSpecializedAs(Sema &S, // The types used to determine the ordering depend on the context in which // the partial ordering is done: TemplateDeductionInfo Info(Loc); - SmallVector Args1; SmallVector Args2; switch (TPOC) { case TPOC_Call: { @@ -4392,6 +4388,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, // // C++98/03 doesn't have this provision but we've extended DR532 to cover // it as wording was broken prior to it. + SmallVector Args1; + unsigned NumComparedArguments = NumCallArguments1; if (!Method2 && Method1 && !Method1->isStatic()) { @@ -4415,37 +4413,35 @@ static bool isAtLeastAsSpecializedAs(Sema &S, Args1.resize(NumComparedArguments); if (Args2.size() > NumComparedArguments) Args2.resize(NumComparedArguments); + if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(), + Args1.data(), Args1.size(), Info, Deduced, + TDF_None, /*PartialOrdering=*/true)) + return false; + break; } case TPOC_Conversion: // - In the context of a call to a conversion operator, the return types // of the conversion function templates are used. - Args1.push_back(Proto1->getReturnType()); - Args2.push_back(Proto2->getReturnType()); + if (DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, Proto2->getReturnType(), Proto1->getReturnType(), + Info, Deduced, TDF_None, + /*PartialOrdering=*/true)) + return false; break; case TPOC_Other: // - In other contexts (14.6.6.2) the function template's function type // is used. - Args1.push_back(FD1->getType()); - Args2.push_back(FD2->getType()); + if (DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + FD2->getType(), FD1->getType(), + Info, Deduced, TDF_None, + /*PartialOrdering=*/true)) + return false; break; } - // FIXME: C++1z [temp.deduct.partial]p4: - // If a particular P contains no template-parameters that participate in - // template argument deduction, that P is not used to determine the - // ordering. - // We do not implement this because it has highly undesirable consequences; - // for instance, it means a non-dependent template is never more specialized - // than any other. - - if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(), - Args1.data(), Args1.size(), Info, Deduced, - TDF_None, /*PartialOrdering=*/true)) - return false; - // C++0x [temp.deduct.partial]p11: // In most cases, all template parameters must have values in order for // deduction to succeed, but for partial ordering purposes a template @@ -4457,76 +4453,44 @@ static bool isAtLeastAsSpecializedAs(Sema &S, if (Deduced[ArgIdx].isNull()) break; - if (ArgIdx != NumArgs) { - // At least one template argument was not deduced. Check whether we deduced - // everything that was used in the types used for ordering. + // FIXME: We fail to implement [temp.deduct.type]p1 along this path. We need + // to substitute the deduced arguments back into the template and check that + // we get the right type. - // Figure out which template parameters were used. - llvm::SmallBitVector UsedParameters(TemplateParams->size()); - for (QualType T : Args2) - ::MarkUsedTemplateParameters(S.Context, T, false, - TemplateParams->getDepth(), UsedParameters); - - for (; ArgIdx != NumArgs; ++ArgIdx) - // If this argument had no value deduced but was used in one of the types - // used for partial ordering, then deduction fails. - if (Deduced[ArgIdx].isNull() && UsedParameters[ArgIdx]) - return false; + if (ArgIdx == NumArgs) { + // All template arguments were deduced. FT1 is at least as specialized + // as FT2. + return true; } - EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated); - Sema::SFINAETrap Trap(S); + // Figure out which template parameters were used. + llvm::SmallBitVector UsedParameters(TemplateParams->size()); + switch (TPOC) { + case TPOC_Call: + for (unsigned I = 0, N = Args2.size(); I != N; ++I) + ::MarkUsedTemplateParameters(S.Context, Args2[I], false, + TemplateParams->getDepth(), + UsedParameters); + break; - SmallVector DeducedArgs(Deduced.begin(), Deduced.end()); - Sema::InstantiatingTemplate Inst( - S, Info.getLocation(), FT2, DeducedArgs, - Sema::ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution, - Info); - if (Inst.isInvalid()) - return false; + case TPOC_Conversion: + ::MarkUsedTemplateParameters(S.Context, Proto2->getReturnType(), false, + TemplateParams->getDepth(), UsedParameters); + break; - SmallVector Builder; - if (ConvertDeducedTemplateArguments(S, FT2, true, Deduced, Info, Builder, - nullptr, 0, /*SkipNonDeduced*/true)) - return false; - - // C++1z [temp.deduct.type]p1: - // an attempt is made to find template argument values (a type for a type - // parameter, a value for a non-type parameter, or a template for a - // template parameter) that will make P, after substitution of the deduced - // values (call it the deduced A), compatible with A. - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Builder); - MultiLevelTemplateArgumentList Args(TemplateArgs); - auto *TrailingPack = - Args2.empty() ? nullptr : dyn_cast(Args2.back()); - unsigned PackIndex = Args2.size() - 1; - for (unsigned I = 0, N = Args1.size(); I != N; ++I) { - // Per C++ [temp.deduct.partial]p8, we're supposed to have formed separate - // P/A pairs for each parameter of template 1 for a trailing pack in - // template 2. Reconstruct those now if necessary. - QualType DeducedA; - if (TrailingPack && I >= PackIndex) { - Sema::ArgumentPackSubstitutionIndexRAII Index(S, I - PackIndex); - DeducedA = S.SubstType(TrailingPack->getPattern(), Args, - Info.getLocation(), FT2->getDeclName()); - } else { - DeducedA = S.SubstType(Args2[I], Args, Info.getLocation(), - FT2->getDeclName()); - } - if (DeducedA.isNull()) - return false; - - QualType A = Args1[I]; - if (auto *AsPack = dyn_cast(A)) - A = AsPack->getPattern(); - - // Per [temp.deduct.partial]p5-7, we strip off top-level references and - // cv-qualifications before this check. - if (!S.Context.hasSameUnqualifiedType(DeducedA.getNonReferenceType(), - A.getNonReferenceType())) - return false; + case TPOC_Other: + ::MarkUsedTemplateParameters(S.Context, FD2->getType(), false, + TemplateParams->getDepth(), + UsedParameters); + break; } + for (; ArgIdx != NumArgs; ++ArgIdx) + // If this argument had no value deduced but was used in one of the types + // used for partial ordering, then deduction fails. + if (Deduced[ArgIdx].isNull() && UsedParameters[ArgIdx]) + return false; + return true; } @@ -5339,13 +5303,17 @@ void Sema::MarkDeducedTemplateParameters( true, TemplateParams->getDepth(), Deduced); } -bool hasDeducibleTemplateParameters(Sema &S, TemplateParameterList *Params, +bool hasDeducibleTemplateParameters(Sema &S, + FunctionTemplateDecl *FunctionTemplate, QualType T) { if (!T->isDependentType()) return false; - llvm::SmallBitVector Deduced(Params->size()); - ::MarkUsedTemplateParameters(S.Context, T, true, Params->getDepth(), Deduced); + TemplateParameterList *TemplateParams + = FunctionTemplate->getTemplateParameters(); + llvm::SmallBitVector Deduced(TemplateParams->size()); + ::MarkUsedTemplateParameters(S.Context, T, true, TemplateParams->getDepth(), + Deduced); return Deduced.any(); } diff --git a/clang/test/CXX/drs/dr4xx.cpp b/clang/test/CXX/drs/dr4xx.cpp index 4a4865cf9795..6046c4afefd5 100644 --- a/clang/test/CXX/drs/dr4xx.cpp +++ b/clang/test/CXX/drs/dr4xx.cpp @@ -54,7 +54,7 @@ namespace dr401 { // dr401: yes void g(B b) { f(b); } #if __cplusplus < 201103L // expected-error@-3 0-1{{extension}} expected-error@-3 {{protected}} expected-note@-3 {{instantiation}} - // expected-note@-3 {{substituting}} expected-note@-33 {{declared protected here}} + // expected-note@-3 {{substituting}} #else // expected-error@-5 {{no matching}} expected-note@-6 {{protected}} #endif diff --git a/clang/test/SemaTemplate/deduction.cpp b/clang/test/SemaTemplate/deduction.cpp index f2d05057269c..16e01a934630 100644 --- a/clang/test/SemaTemplate/deduction.cpp +++ b/clang/test/SemaTemplate/deduction.cpp @@ -127,12 +127,12 @@ namespace test1 { namespace test2 { template struct Const { typedef void const type; }; - template void f(T, typename Const::type*); // expected-note {{candidate}} - template void f(T, void const *); // expected-note {{candidate}} + template void f(T, typename Const::type*); + template void f(T, void const *); void test() { void *p = 0; - f(0, p); // expected-error {{ambiguous}} + f(0, p); } } diff --git a/clang/test/SemaTemplate/partial-order.cpp b/clang/test/SemaTemplate/partial-order.cpp index bafede4750ad..0a151de39023 100644 --- a/clang/test/SemaTemplate/partial-order.cpp +++ b/clang/test/SemaTemplate/partial-order.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -std=c++1z %s -verify +// expected-no-diagnostics + namespace hana_enable_if_idiom { template struct A {}; template> struct B; @@ -10,21 +12,3 @@ namespace hana_enable_if_idiom { }; B b; } - -// Ensure that we implement the check that deduced A == A during function -// template partial ordering. -namespace check_substituted_type_matches { - struct X { typedef int type; }; - - // A specific but dependent type is neither better nor worse than a - // specific and non-dependent type. - template void f(T, typename T::type); // expected-note {{candidate}} - template void f(T, int); // expected-note {{candidate}} - void test_f() { f(X{}, 0); } // expected-error {{ambiguous}} - - // A specific but dependent type is more specialized than a - // deducible type. - template void g(T, typename T::type); - template void g(T, U); - void test_g() { g(X{}, 0); } -} diff --git a/clang/test/SemaTemplate/temp_arg_nontype.cpp b/clang/test/SemaTemplate/temp_arg_nontype.cpp index dacb7a7c4441..8658fb006060 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype.cpp @@ -442,13 +442,17 @@ namespace dependent_nested_partial_specialization { namespace nondependent_default_arg_ordering { int n, m; template struct X {}; - template void f(X); - template void f(X); - template void f(X) = delete; // expected-warning {{C++11}} - template class T, typename A, int *B> void f(T) = delete; // expected-warning {{C++11}} + template void f(X); // expected-note {{candidate}} + template void f(X); // expected-note {{candidate}} + template void f(X); // expected-note 2{{candidate}} + template class T, typename A, int *B> void f(T); // expected-note 2{{candidate}} void g() { - X x; f(x); - X y; f(y); + // FIXME: The first and second function templates above should be + // considered more specialized than the last two, but during partial + // ordering we fail to check that we actually deduced template arguments + // that make the deduced A identical to A. + X x; f(x); // expected-error {{ambiguous}} + X y; f(y); // expected-error {{ambiguous}} } } diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp index dfdc3285bb5b..c1fcedd58d13 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp @@ -328,23 +328,3 @@ namespace Nested { void g(int, int); using Int = A::B<&g>::param2; } - -namespace nondependent_default_arg_ordering { - int n, m; - template struct X {}; - template void f(X); // #1, expected-note {{candidate}} - template void f(X); // #2, expected-note {{candidate}} - template void f(X); // #3, expected-note 2{{candidate}} - template class T, typename A, int *B> void f(T); // #4, expected-note 2{{candidate}} - void g() { - // These become ill-formed in C++1z because we can now deduce the - // type A in #3 and #4 in two ways during partial ordering: - // * we can deduce #3's A = #1's A from the template-id - // * we can deduce #3's A = 'int *' from the type of the value - // deduced as #3's B - // FIXME: It seems unfortunate that we have to reject this; #1 and #2 are - // obviously more specialized than #3 and #4. - X x; f(x); // expected-error {{ambiguous}} - X y; f(y); // expected-error {{ambiguous}} - } -}