Author: rsmith Date: Thu Jan 5 17:02:44 2017 New Revision: 291190 URL: http://llvm.org/viewvc/llvm-project?rev=291190&view=rev Log: Add missing "original call argument has same type as deduced parameter type" check for deductions from elements of a braced-init-list.
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=291190&r1=291189&r2=291190&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan 5 17:02:44 2017 @@ -3377,8 +3377,10 @@ def note_addrof_ovl_candidate_disabled_b "candidate function made ineligible by enable_if">; def note_ovl_candidate_deduced_mismatch : Note< "candidate template ignored: deduced type " - "%diff{$ of %ordinal0 parameter does not match adjusted type $ of argument" - "|of %ordinal0 parameter does not match adjusted type of argument}1,2%3">; + "%diff{$ of %select{|element of }4%ordinal0 parameter does not match " + "adjusted type $ of %select{|element of }4argument" + "|of %select{|element of }4%ordinal0 parameter does not match " + "adjusted type of %select{|element of }4argument}1,2%3">; def note_ovl_candidate_non_deduced_mismatch : Note< "candidate template ignored: could not match %diff{$ against $|types}0,1">; // This note is needed because the above note would sometimes print two Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=291190&r1=291189&r2=291190&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Thu Jan 5 17:02:44 2017 @@ -6564,6 +6564,10 @@ public: /// \brief After substituting deduced template arguments, a dependent /// parameter type did not match the corresponding argument. TDK_DeducedMismatch, + /// \brief After substituting deduced template arguments, an element of + /// a dependent parameter type did not match the corresponding element + /// of the corresponding argument (when deducing from an initializer list). + TDK_DeducedMismatchNested, /// \brief A non-depnedent component of the parameter did not match the /// corresponding component of the argument. TDK_NonDeducedMismatch, @@ -6602,13 +6606,14 @@ public: /// brief A function argument from which we performed template argument // deduction for a call. struct OriginalCallArg { - OriginalCallArg(QualType OriginalParamType, - unsigned ArgIdx, - QualType OriginalArgType) - : OriginalParamType(OriginalParamType), ArgIdx(ArgIdx), - OriginalArgType(OriginalArgType) { } + OriginalCallArg(QualType OriginalParamType, bool DecomposedParam, + unsigned ArgIdx, QualType OriginalArgType) + : OriginalParamType(OriginalParamType), + DecomposedParam(DecomposedParam), ArgIdx(ArgIdx), + OriginalArgType(OriginalArgType) {} QualType OriginalParamType; + bool DecomposedParam; unsigned ArgIdx; QualType OriginalArgType; }; Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=291190&r1=291189&r2=291190&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Jan 5 17:02:44 2017 @@ -604,7 +604,8 @@ clang::MakeDeductionFailureInfo(ASTConte Result.Data = Info.Param.getOpaqueValue(); break; - case Sema::TDK_DeducedMismatch: { + case Sema::TDK_DeducedMismatch: + case Sema::TDK_DeducedMismatchNested: { // FIXME: Should allocate from normal heap so that we can free this later. auto *Saved = new (Context) DFIDeducedMismatchArgs; Saved->FirstArg = Info.FirstArg; @@ -664,6 +665,7 @@ void DeductionFailureInfo::Destroy() { case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: case Sema::TDK_DeducedMismatch: + case Sema::TDK_DeducedMismatchNested: case Sema::TDK_NonDeducedMismatch: // FIXME: Destroy the data? Data = nullptr; @@ -699,6 +701,7 @@ TemplateParameter DeductionFailureInfo:: case Sema::TDK_TooFewArguments: case Sema::TDK_SubstitutionFailure: case Sema::TDK_DeducedMismatch: + case Sema::TDK_DeducedMismatchNested: case Sema::TDK_NonDeducedMismatch: case Sema::TDK_CUDATargetMismatch: return TemplateParameter(); @@ -735,6 +738,7 @@ TemplateArgumentList *DeductionFailureIn return nullptr; case Sema::TDK_DeducedMismatch: + case Sema::TDK_DeducedMismatchNested: return static_cast<DFIDeducedMismatchArgs*>(Data)->TemplateArgs; case Sema::TDK_SubstitutionFailure: @@ -764,6 +768,7 @@ const TemplateArgument *DeductionFailure case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: case Sema::TDK_DeducedMismatch: + case Sema::TDK_DeducedMismatchNested: case Sema::TDK_NonDeducedMismatch: return &static_cast<DFIArguments*>(Data)->FirstArg; @@ -791,6 +796,7 @@ const TemplateArgument *DeductionFailure case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: case Sema::TDK_DeducedMismatch: + case Sema::TDK_DeducedMismatchNested: case Sema::TDK_NonDeducedMismatch: return &static_cast<DFIArguments*>(Data)->SecondArg; @@ -803,11 +809,14 @@ const TemplateArgument *DeductionFailure } llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() { - if (static_cast<Sema::TemplateDeductionResult>(Result) == - Sema::TDK_DeducedMismatch) + switch (static_cast<Sema::TemplateDeductionResult>(Result)) { + case Sema::TDK_DeducedMismatch: + case Sema::TDK_DeducedMismatchNested: return static_cast<DFIDeducedMismatchArgs*>(Data)->CallArgIndex; - return llvm::None; + default: + return llvm::None; + } } void OverloadCandidateSet::destroyCandidates() { @@ -9682,7 +9691,8 @@ static void DiagnoseBadDeduction(Sema &S return; } - case Sema::TDK_DeducedMismatch: { + case Sema::TDK_DeducedMismatch: + case Sema::TDK_DeducedMismatchNested: { // Format the template argument list into the argument string. SmallString<128> TemplateArgString; if (TemplateArgumentList *Args = @@ -9695,7 +9705,8 @@ static void DiagnoseBadDeduction(Sema &S S.Diag(Templated->getLocation(), diag::note_ovl_candidate_deduced_mismatch) << (*DeductionFailure.getCallArgIndex() + 1) << *DeductionFailure.getFirstArg() << *DeductionFailure.getSecondArg() - << TemplateArgString; + << TemplateArgString + << (DeductionFailure.Result == Sema::TDK_DeducedMismatchNested); break; } @@ -10012,6 +10023,7 @@ static unsigned RankDeductionFailure(con case Sema::TDK_SubstitutionFailure: case Sema::TDK_DeducedMismatch: + case Sema::TDK_DeducedMismatchNested: case Sema::TDK_NonDeducedMismatch: case Sema::TDK_MiscellaneousDeductionFailure: case Sema::TDK_CUDATargetMismatch: Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=291190&r1=291189&r2=291190&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Thu Jan 5 17:02:44 2017 @@ -19,6 +19,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeOrdering.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Sema.h" #include "clang/Sema/Template.h" @@ -2856,6 +2857,36 @@ CheckOriginalCallArgDeduction(Sema &S, S return true; } +/// Find the pack index for a particular parameter index in an instantiation of +/// a function template with specific arguments. +/// +/// \return The pack index for whichever pack produced this parameter, or -1 +/// if this was not produced by a parameter. Intended to be used as the +/// ArgumentPackSubstitutionIndex for further substitutions. +// FIXME: We should track this in OriginalCallArgs so we don't need to +// reconstruct it here. +static unsigned getPackIndexForParam(Sema &S, + FunctionTemplateDecl *FunctionTemplate, + const MultiLevelTemplateArgumentList &Args, + unsigned ParamIdx) { + unsigned Idx = 0; + for (auto *PD : FunctionTemplate->getTemplatedDecl()->parameters()) { + if (PD->isParameterPack()) { + unsigned NumExpansions = + S.getNumArgumentsInExpansion(PD->getType(), Args).getValueOr(1); + if (Idx + NumExpansions > ParamIdx) + return ParamIdx - Idx; + Idx += NumExpansions; + } else { + if (Idx == ParamIdx) + return -1; // Not a pack expansion + ++Idx; + } + } + + llvm_unreachable("parameter index would not be produced from template"); +} + /// \brief Finish template argument deduction for a function template, /// checking the deduced template arguments for completeness and forming /// the function template specialization. @@ -2906,9 +2937,9 @@ Sema::FinishTemplateArgumentDeduction(Fu DeclContext *Owner = FunctionTemplate->getDeclContext(); if (FunctionTemplate->getFriendObjectKind()) Owner = FunctionTemplate->getLexicalDeclContext(); + MultiLevelTemplateArgumentList SubstArgs(*DeducedArgumentList); Specialization = cast_or_null<FunctionDecl>( - SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, - MultiLevelTemplateArgumentList(*DeducedArgumentList))); + SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs)); if (!Specialization || Specialization->isInvalidDecl()) return TDK_SubstitutionFailure; @@ -2934,19 +2965,46 @@ Sema::FinishTemplateArgumentDeduction(Fu // In general, the deduction process attempts to find template argument // values that will make the deduced A identical to A (after the type A // is transformed as described above). [...] + llvm::SmallDenseMap<std::pair<unsigned, QualType>, QualType> DeducedATypes; for (unsigned I = 0, N = OriginalCallArgs->size(); I != N; ++I) { OriginalCallArg OriginalArg = (*OriginalCallArgs)[I]; - unsigned ParamIdx = OriginalArg.ArgIdx; + auto ParamIdx = OriginalArg.ArgIdx; if (ParamIdx >= Specialization->getNumParams()) + // FIXME: This presumably means a pack ended up smaller than we + // expected while deducing. Should this not result in deduction + // failure? Can it even happen? continue; - QualType DeducedA = Specialization->getParamDecl(ParamIdx)->getType(); + QualType DeducedA; + if (!OriginalArg.DecomposedParam) { + // P is one of the function parameters, just look up its substituted + // type. + DeducedA = Specialization->getParamDecl(ParamIdx)->getType(); + } else { + // P is a decomposed element of a parameter corresponding to a + // braced-init-list argument. Substitute back into P to find the + // deduced A. + QualType &CacheEntry = + DeducedATypes[{ParamIdx, OriginalArg.OriginalParamType}]; + if (CacheEntry.isNull()) { + ArgumentPackSubstitutionIndexRAII PackIndex( + *this, getPackIndexForParam(*this, FunctionTemplate, SubstArgs, + ParamIdx)); + CacheEntry = + SubstType(OriginalArg.OriginalParamType, SubstArgs, + Specialization->getTypeSpecStartLoc(), + Specialization->getDeclName()); + } + DeducedA = CacheEntry; + } + if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) { Info.FirstArg = TemplateArgument(DeducedA); Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType); Info.CallArgIndex = OriginalArg.ArgIdx; - return TDK_DeducedMismatch; + return OriginalArg.DecomposedParam ? TDK_DeducedMismatchNested + : TDK_DeducedMismatch; } } } @@ -3203,7 +3261,7 @@ static Sema::TemplateDeductionResult Ded Expr *Arg, TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced, SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs, - Optional<unsigned> ArgIdx, unsigned TDF); + bool DecomposedParam, unsigned ArgIdx, unsigned TDF); /// \brief Attempt template argument deduction from an initializer list /// deemed to be an argument in a function call. @@ -3211,7 +3269,8 @@ static Sema::TemplateDeductionResult Ded Sema &S, TemplateParameterList *TemplateParams, QualType AdjustedParamType, InitListExpr *ILE, TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced, - SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs, unsigned TDF) { + SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs, unsigned ArgIdx, + unsigned TDF) { // C++ [temp.deduct.call]p1: (CWG 1591) // If removing references and cv-qualifiers from P gives // std::initializer_list<P0> or P0[N] for some P0 and N and the argument is @@ -3237,8 +3296,8 @@ static Sema::TemplateDeductionResult Ded if (ElTy->isDependentType()) { for (Expr *E : ILE->inits()) { if (auto Result = DeduceTemplateArgumentsFromCallArgument( - S, TemplateParams, ElTy, E, Info, Deduced, OriginalCallArgs, None, - TDF)) + S, TemplateParams, ElTy, E, Info, Deduced, OriginalCallArgs, true, + ArgIdx, TDF)) return Result; } } @@ -3270,7 +3329,7 @@ static Sema::TemplateDeductionResult Ded Expr *Arg, TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced, SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs, - Optional<unsigned> ArgIdx, unsigned TDF) { + bool DecomposedParam, unsigned ArgIdx, unsigned TDF) { QualType ArgType = Arg->getType(); QualType OrigParamType = ParamType; @@ -3283,19 +3342,15 @@ static Sema::TemplateDeductionResult Ded // If [...] the argument is a non-empty initializer list [...] if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg)) return DeduceFromInitializerList(S, TemplateParams, ParamType, ILE, Info, - Deduced, OriginalCallArgs, TDF); + Deduced, OriginalCallArgs, ArgIdx, TDF); // [...] the deduction process attempts to find template argument values // that will make the deduced A identical to A // // Keep track of the argument type and corresponding parameter index, // so we can check for compatibility between the deduced A and A. - // - // FIXME: We are supposed to perform this check for the P/A pairs we extract - // from the initializer list case too. - if (ArgIdx) - OriginalCallArgs.push_back( - Sema::OriginalCallArg(OrigParamType, *ArgIdx, ArgType)); + OriginalCallArgs.push_back( + Sema::OriginalCallArg(OrigParamType, DecomposedParam, ArgIdx, ArgType)); return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType, ArgType, Info, Deduced, TDF); } @@ -3388,7 +3443,7 @@ Sema::TemplateDeductionResult Sema::Dedu // ... with the type of the corresponding argument return DeduceTemplateArgumentsFromCallArgument( *this, TemplateParams, ParamType, Args[ArgIdx], Info, Deduced, - OriginalCallArgs, ArgIdx, /*TDF*/ 0); + OriginalCallArgs, /*Decomposed*/false, ArgIdx, /*TDF*/ 0); }; // Deduce template arguments from the function parameters. @@ -4075,7 +4130,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) { if (DeduceTemplateArgumentsFromCallArgument( *this, TemplateParamsSt.get(), TemplArg, InitList->getInit(i), - Info, Deduced, OriginalCallArgs, None, /*TDF*/0)) + Info, Deduced, OriginalCallArgs, /*Decomposed*/ true, + /*ArgIdx*/ 0, /*TDF*/ 0)) return DeductionFailed(); } } else { @@ -4086,7 +4142,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr if (DeduceTemplateArgumentsFromCallArgument( *this, TemplateParamsSt.get(), FuncParam, Init, Info, Deduced, - OriginalCallArgs, /*ArgIdx*/0, /*TDF*/0)) + OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0)) return DeductionFailed(); } @@ -4108,8 +4164,11 @@ Sema::DeduceAutoType(TypeLoc Type, Expr // Check that the deduced argument type is compatible with the original // argument type per C++ [temp.deduct.call]p4. + QualType DeducedA = InitList ? Deduced[0].getAsType() : Result; for (const OriginalCallArg &OriginalArg : OriginalCallArgs) { - if (CheckOriginalCallArgDeduction(*this, OriginalArg, Result)) { + assert((bool)InitList == OriginalArg.DecomposedParam && + "decomposed non-init-list in auto deduction?"); + if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) { Result = QualType(); return DeductionFailed(); } Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp?rev=291190&r1=291189&r2=291190&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp (original) +++ cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp Thu Jan 5 17:02:44 2017 @@ -105,6 +105,7 @@ T deduce_ref(const std::initializer_list template<typename T, typename U> struct pair { pair(...); }; template<typename T> void deduce_pairs(std::initializer_list<pair<T, typename T::type>>); +// expected-note@-1 {{deduced type 'pair<[...], typename WithIntType::type>' of element of 1st parameter does not match adjusted type 'pair<[...], float>' of element of argument [with T = WithIntType]}} struct WithIntType { typedef int type; }; template<typename ...T> void deduce_after_init_list_in_pack(void (*)(T...), T...); // expected-note {{<int, int> vs. <(no value), double>}} @@ -123,7 +124,7 @@ void argument_deduction() { pair<WithIntType, int> pi; pair<WithIntType, float> pf; deduce_pairs({pi, pi, pi}); // ok - deduce_pairs({pi, pf, pi}); // FIXME: This should be rejected, as we fail to produce a type that exactly matches the argument type. + deduce_pairs({pi, pf, pi}); // expected-error {{no matching function}} deduce_after_init_list_in_pack((void(*)(int,int))0, {}, 0); deduce_after_init_list_in_pack((void(*)(int,int))0, {}, 0.0); // expected-error {{no matching function}} @@ -298,9 +299,18 @@ namespace TemporaryInitListSourceRange_P namespace ParameterPackNestedInitializerLists_PR23904c3 { template <typename ...T> - void f(std::initializer_list<std::initializer_list<T>> ...tt); + void f(std::initializer_list<std::initializer_list<T>> ...tt); // expected-note 2{{conflicting}} expected-note {{incomplete pack}} - void foo() { f({{0}}, {{'\0'}}); } + void foo() { + f({{0}}, {{'\0'}}); // ok, T = <int, char> + f({{0}, {'\0'}}); // expected-error {{no match}} + f({{0, '\0'}}); // expected-error {{no match}} + + f({{0}}, {{{}}}); // expected-error {{no match}} + f({{0}}, {{{}, '\0'}}); // ok, T = <int, char> + f({{0}, {{}}}); // ok, T = <int> + f({{0, {}}}); // ok, T = <int> + } } namespace update_rbrace_loc_crash { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits