From: Douglas Gregor Date: Tue, 11 Jan 2011 17:34:58 +0000 (+0000) Subject: Implement C++ [temp.func.order]p5 more directly, by passing down the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5c7bf42ef16dc767615bed10f3b7b3c1265314e1;p=clang Implement C++ [temp.func.order]p5 more directly, by passing down the number of explicit call arguments. This actually fixes an erroneous test for [temp.deduct.partial]p11, where we were considering parameters corresponding to arguments beyond those that were explicitly provided. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123244 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index d4ffd37bca..df4e4dc48c 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3510,10 +3510,12 @@ public: FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, - TemplatePartialOrderingContext TPOC); + TemplatePartialOrderingContext TPOC, + unsigned NumCallArguments); UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd, TemplatePartialOrderingContext TPOC, + unsigned NumCallArguments, SourceLocation Loc, const PartialDiagnostic &NoneDiag, const PartialDiagnostic &AmbigDiag, diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 62e60a1459..80ef65e433 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -5897,7 +5897,8 @@ isBetterOverloadCandidate(Sema &S, Cand2.Function->getPrimaryTemplate(), Loc, isa(Cand1.Function)? TPOC_Conversion - : TPOC_Call)) + : TPOC_Call, + NumArgs)) return BetterTemplate == Cand1.Function->getPrimaryTemplate(); // -- the context is an initialization by user-defined conversion @@ -6926,7 +6927,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, UnresolvedSetIterator Result = getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(), - TPOC_Other, From->getLocStart(), + TPOC_Other, 0, From->getLocStart(), PDiag(), PDiag(diag::err_addr_ovl_ambiguous) << Matches[0].second->getDeclName(), diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f540c7b935..d0899c89f0 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -4846,7 +4846,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Find the most specialized function template. UnresolvedSetIterator Result = getMostSpecialized(Candidates.begin(), Candidates.end(), - TPOC_Other, FD->getLocation(), + TPOC_Other, 0, FD->getLocation(), PDiag(diag::err_function_template_spec_no_match) << FD->getDeclName(), PDiag(diag::err_function_template_spec_ambiguous) @@ -5668,7 +5668,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // Find the most specialized function template specialization. UnresolvedSetIterator Result - = getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other, + = getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other, 0, D.getIdentifierLoc(), PDiag(diag::err_explicit_instantiation_not_known) << Name, PDiag(diag::err_explicit_instantiation_ambiguous) << Name, diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 1bc24db27a..6d0db4a541 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -84,6 +84,15 @@ DeduceTemplateArguments(Sema &S, TemplateDeductionInfo &Info, llvm::SmallVectorImpl &Deduced); +/// \brief Stores the result of comparing the qualifiers of two types, used +/// when +enum DeductionQualifierComparison { + NeitherMoreQualified = 0, + ParamMoreQualified, + ArgMoreQualified +}; + + static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, @@ -91,7 +100,10 @@ DeduceTemplateArguments(Sema &S, QualType Arg, TemplateDeductionInfo &Info, llvm::SmallVectorImpl &Deduced, - unsigned TDF); + unsigned TDF, + bool PartialOrdering = false, + llvm::SmallVectorImpl * + QualifierComparisons = 0); static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, @@ -621,6 +633,13 @@ FinishArgumentPackDeduction(Sema &S, /// \param TDF bitwise OR of the TemplateDeductionFlags bits that describe /// how template argument deduction is performed. /// +/// \param PartialOrdering If true, we are performing template argument +/// deduction for during partial ordering for a call +/// (C++0x [temp.deduct.partial]). +/// +/// \param QualifierComparisons If we're performing template argument deduction +/// in the context of partial ordering, the set of qualifier comparisons. +/// /// \returns the result of template argument deduction so far. Note that a /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. @@ -631,7 +650,10 @@ DeduceTemplateArguments(Sema &S, const QualType *Args, unsigned NumArgs, TemplateDeductionInfo &Info, llvm::SmallVectorImpl &Deduced, - unsigned TDF) { + unsigned TDF, + bool PartialOrdering = false, + llvm::SmallVectorImpl * + QualifierComparisons = 0) { // Fast-path check to see if we have too many/too few arguments. if (NumParams != NumArgs && !(NumParams && isa(Params[NumParams - 1])) && @@ -655,11 +677,14 @@ DeduceTemplateArguments(Sema &S, if (ArgIdx >= NumArgs) return Sema::TDK_NonDeducedMismatch; + if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, - Params[ParamIdx], - Args[ArgIdx], - Info, Deduced, TDF)) + = DeduceTemplateArguments(S, TemplateParams, + Params[ParamIdx], + Args[ArgIdx], + Info, Deduced, TDF, + PartialOrdering, + QualifierComparisons)) return Result; ++ArgIdx; @@ -716,7 +741,8 @@ DeduceTemplateArguments(Sema &S, // Deduce template arguments from the pattern. if (Sema::TemplateDeductionResult Result = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], - Info, Deduced)) + Info, Deduced, PartialOrdering, + QualifierComparisons)) return Result; // Capture the deduced template arguments for each parameter pack expanded @@ -765,6 +791,12 @@ DeduceTemplateArguments(Sema &S, /// \param TDF bitwise OR of the TemplateDeductionFlags bits that describe /// how template argument deduction is performed. /// +/// \param PartialOrdering Whether we're performing template argument deduction +/// in the context of partial ordering (C++0x [temp.deduct.partial]). +/// +/// \param QualifierComparisons If we're performing template argument deduction +/// in the context of partial ordering, the set of qualifier comparisons. +/// /// \returns the result of template argument deduction so far. Note that a /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. @@ -774,24 +806,68 @@ DeduceTemplateArguments(Sema &S, QualType ParamIn, QualType ArgIn, TemplateDeductionInfo &Info, llvm::SmallVectorImpl &Deduced, - unsigned TDF) { + unsigned TDF, + bool PartialOrdering, + llvm::SmallVectorImpl *QualifierComparisons) { // We only want to look at the canonical types, since typedefs and // sugar are not part of template argument deduction. QualType Param = S.Context.getCanonicalType(ParamIn); QualType Arg = S.Context.getCanonicalType(ArgIn); - // C++0x [temp.deduct.call]p4 bullet 1: - // - If the original P is a reference type, the deduced A (i.e., the type - // referred to by the reference) can be more cv-qualified than the - // transformed A. - if (TDF & TDF_ParamWithReferenceType) { - Qualifiers Quals; - QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals); - Quals.setCVRQualifiers(Quals.getCVRQualifiers() & - Arg.getCVRQualifiersThroughArrayTypes()); - Param = S.Context.getQualifiedType(UnqualParam, Quals); + if (PartialOrdering) { + // C++0x [temp.deduct.partial]p5: + // Before the partial ordering is done, certain transformations are + // performed on the types used for partial ordering: + // - If P is a reference type, P is replaced by the type referred to. + const ReferenceType *ParamRef = Param->getAs(); + if (ParamRef) + Param = ParamRef->getPointeeType(); + + // - If A is a reference type, A is replaced by the type referred to. + const ReferenceType *ArgRef = Arg->getAs(); + if (ArgRef) + Arg = ArgRef->getPointeeType(); + + if (QualifierComparisons && ParamRef && ArgRef) { + // C++0x [temp.deduct.partial]p6: + // If both P and A were reference types (before being replaced with the + // type referred to above), determine which of the two types (if any) is + // more cv-qualified than the other; otherwise the types are considered + // to be equally cv-qualified for partial ordering purposes. The result + // of this determination will be used below. + // + // We save this information for later, using it only when deduction + // succeeds in both directions. + DeductionQualifierComparison QualifierResult = NeitherMoreQualified; + if (Param.isMoreQualifiedThan(Arg)) + QualifierResult = ParamMoreQualified; + else if (Arg.isMoreQualifiedThan(Param)) + QualifierResult = ArgMoreQualified; + QualifierComparisons->push_back(QualifierResult); + } + + // C++0x [temp.deduct.partial]p7: + // Remove any top-level cv-qualifiers: + // - If P is a cv-qualified type, P is replaced by the cv-unqualified + // version of P. + Param = Param.getUnqualifiedType(); + // - If A is a cv-qualified type, A is replaced by the cv-unqualified + // version of A. + Arg = Arg.getUnqualifiedType(); + } else { + // C++0x [temp.deduct.call]p4 bullet 1: + // - If the original P is a reference type, the deduced A (i.e., the type + // referred to by the reference) can be more cv-qualified than the + // transformed A. + if (TDF & TDF_ParamWithReferenceType) { + Qualifiers Quals; + QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals); + Quals.setCVRQualifiers(Quals.getCVRQualifiers() & + Arg.getCVRQualifiersThroughArrayTypes()); + Param = S.Context.getQualifiedType(UnqualParam, Quals); + } } - + // If the parameter type is not dependent, there is nothing to deduce. if (!Param->isDependentType()) { if (!(TDF & TDF_SkipNonDependent) && Param != Arg) @@ -2300,7 +2376,7 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S, // for type deduction. ParamType = ParamRefType->getPointeeType(); } - + // Overload sets usually make this parameter an undeduced // context, but there are sometimes special circumstances. if (ArgType == S.Context.OverloadTy) { @@ -2786,90 +2862,6 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType(), Specialization, Info); } -/// \brief Stores the result of comparing the qualifiers of two types. -enum DeductionQualifierComparison { - NeitherMoreQualified = 0, - ParamMoreQualified, - ArgMoreQualified -}; - -/// \brief Deduce the template arguments during partial ordering by comparing -/// the parameter type and the argument type (C++0x [temp.deduct.partial]). -/// -/// \param S the semantic analysis object within which we are deducing -/// -/// \param TemplateParams the template parameters that we are deducing -/// -/// \param ParamIn the parameter type -/// -/// \param ArgIn the argument type -/// -/// \param Info information about the template argument deduction itself -/// -/// \param Deduced the deduced template arguments -/// -/// \returns the result of template argument deduction so far. Note that a -/// "success" result means that template argument deduction has not yet failed, -/// but it may still fail, later, for other reasons. -static Sema::TemplateDeductionResult -DeduceTemplateArgumentsDuringPartialOrdering(Sema &S, - TemplateParameterList *TemplateParams, - QualType ParamIn, QualType ArgIn, - TemplateDeductionInfo &Info, - llvm::SmallVectorImpl &Deduced, - llvm::SmallVectorImpl *QualifierComparisons) { - CanQualType Param = S.Context.getCanonicalType(ParamIn); - CanQualType Arg = S.Context.getCanonicalType(ArgIn); - - // C++0x [temp.deduct.partial]p5: - // Before the partial ordering is done, certain transformations are - // performed on the types used for partial ordering: - // - If P is a reference type, P is replaced by the type referred to. - CanQual ParamRef = Param->getAs(); - if (!ParamRef.isNull()) - Param = ParamRef->getPointeeType(); - - // - If A is a reference type, A is replaced by the type referred to. - CanQual ArgRef = Arg->getAs(); - if (!ArgRef.isNull()) - Arg = ArgRef->getPointeeType(); - - if (QualifierComparisons && !ParamRef.isNull() && !ArgRef.isNull()) { - // C++0x [temp.deduct.partial]p6: - // If both P and A were reference types (before being replaced with the - // type referred to above), determine which of the two types (if any) is - // more cv-qualified than the other; otherwise the types are considered to - // be equally cv-qualified for partial ordering purposes. The result of this - // determination will be used below. - // - // We save this information for later, using it only when deduction - // succeeds in both directions. - DeductionQualifierComparison QualifierResult = NeitherMoreQualified; - if (Param.isMoreQualifiedThan(Arg)) - QualifierResult = ParamMoreQualified; - else if (Arg.isMoreQualifiedThan(Param)) - QualifierResult = ArgMoreQualified; - QualifierComparisons->push_back(QualifierResult); - } - - // C++0x [temp.deduct.partial]p7: - // Remove any top-level cv-qualifiers: - // - If P is a cv-qualified type, P is replaced by the cv-unqualified - // version of P. - Param = Param.getUnqualifiedType(); - // - If A is a cv-qualified type, A is replaced by the cv-unqualified - // version of A. - Arg = Arg.getUnqualifiedType(); - - // C++0x [temp.deduct.partial]p8: - // Using the resulting types P and A the deduction is then done as - // described in 14.9.2.5. If deduction succeeds for a given type, the type - // from the argument template is considered to be at least as specialized - // as the type from the parameter template. - return DeduceTemplateArguments(S, TemplateParams, Param, Arg, Info, - Deduced, TDF_None); -} - static void MarkUsedTemplateParameters(Sema &SemaRef, QualType T, bool OnlyDeduced, @@ -2907,6 +2899,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, TemplatePartialOrderingContext TPOC, + unsigned NumCallArguments, llvm::SmallVectorImpl *QualifierComparisons) { FunctionDecl *FD1 = FT1->getTemplatedDecl(); FunctionDecl *FD2 = FT2->getTemplatedDecl(); @@ -2951,7 +2944,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, unsigned Skip1 = !S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1; if (S.getLangOptions().CPlusPlus0x && IsNonStatic1 && !IsNonStatic2) - MaybeAddImplicitObjectParameterType(S.Context, Method1, Args1); + MaybeAddImplicitObjectParameterType(S.Context, Method1, Args1); Args1.insert(Args1.end(), Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end()); @@ -2962,16 +2955,18 @@ static bool isAtLeastAsSpecializedAs(Sema &S, MaybeAddImplicitObjectParameterType(S.Context, Method2, Args2); Args2.insert(Args2.end(), Proto2->arg_type_begin() + Skip2, Proto2->arg_type_end()); - - unsigned NumParams = std::min(Args1.size(), Args2.size()); - for (unsigned I = 0; I != NumParams; ++I) - if (DeduceTemplateArgumentsDuringPartialOrdering(S, - TemplateParams, - Args2[I], - Args1[I], - Info, - Deduced, - QualifierComparisons)) + + // C++ [temp.func.order]p5: + // The presence of unused ellipsis and default arguments has no effect on + // the partial ordering of function templates. + if (Args1.size() > NumCallArguments) + Args1.resize(NumCallArguments); + if (Args2.size() > NumCallArguments) + Args2.resize(NumCallArguments); + if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(), + Args1.data(), Args1.size(), Info, Deduced, + TDF_None, /*PartialOrdering=*/true, + QualifierComparisons)) return false; break; @@ -2980,26 +2975,21 @@ static bool isAtLeastAsSpecializedAs(Sema &S, case TPOC_Conversion: // - In the context of a call to a conversion operator, the return types // of the conversion function templates are used. - if (DeduceTemplateArgumentsDuringPartialOrdering(S, - TemplateParams, - Proto2->getResultType(), - Proto1->getResultType(), - Info, - Deduced, - QualifierComparisons)) + if (DeduceTemplateArguments(S, TemplateParams, Proto2->getResultType(), + Proto1->getResultType(), Info, Deduced, + TDF_None, /*PartialOrdering=*/true, + QualifierComparisons)) return false; break; case TPOC_Other: // - In other contexts (14.6.6.2) the function template’s function type // is used. - if (DeduceTemplateArgumentsDuringPartialOrdering(S, - TemplateParams, - FD2->getType(), - FD1->getType(), - Info, - Deduced, - QualifierComparisons)) + // FIXME: Don't we actually want to perform the adjustments on the parameter + // types? + if (DeduceTemplateArguments(S, TemplateParams, FD2->getType(), + FD1->getType(), Info, Deduced, TDF_None, + /*PartialOrdering=*/true, QualifierComparisons)) return false; break; } @@ -3026,7 +3016,9 @@ static bool isAtLeastAsSpecializedAs(Sema &S, UsedParameters.resize(TemplateParams->size()); switch (TPOC) { case TPOC_Call: { - unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs()); + unsigned NumParams = std::min(NumCallArguments, + std::min(Proto1->getNumArgs(), + Proto2->getNumArgs())); if (S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1) ::MarkUsedTemplateParameters(S, Method2->getThisType(S.Context), false, TemplateParams->getDepth(), UsedParameters); @@ -3070,16 +3062,22 @@ static bool isAtLeastAsSpecializedAs(Sema &S, /// \param TPOC the context in which we are performing partial ordering of /// function templates. /// +/// \param NumCallArguments The number of arguments in a call, used only +/// when \c TPOC is \c TPOC_Call. +/// /// \returns the more specialized function template. If neither /// template is more specialized, returns NULL. FunctionTemplateDecl * Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, - TemplatePartialOrderingContext TPOC) { + TemplatePartialOrderingContext TPOC, + unsigned NumCallArguments) { llvm::SmallVector QualifierComparisons; - bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, 0); + bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, + NumCallArguments, 0); bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, + NumCallArguments, &QualifierComparisons); if (Better1 != Better2) // We have a clear winner @@ -3156,6 +3154,9 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) { /// \param TPOC the partial ordering context to use to compare the function /// template specializations. /// +/// \param NumCallArguments The number of arguments in a call, used only +/// when \c TPOC is \c TPOC_Call. +/// /// \param Loc the location where the ambiguity or no-specializations /// diagnostic should occur. /// @@ -3181,8 +3182,9 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) { /// template argument deduction. UnresolvedSetIterator Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, - UnresolvedSetIterator SpecEnd, + UnresolvedSetIterator SpecEnd, TemplatePartialOrderingContext TPOC, + unsigned NumCallArguments, SourceLocation Loc, const PartialDiagnostic &NoneDiag, const PartialDiagnostic &AmbigDiag, @@ -3206,7 +3208,7 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, = cast(*I)->getPrimaryTemplate(); assert(Challenger && "Not a function template specialization?"); if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, - Loc, TPOC), + Loc, TPOC, NumCallArguments), Challenger)) { Best = I; BestTemplate = Challenger; @@ -3221,7 +3223,7 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, = cast(*I)->getPrimaryTemplate(); if (I != Best && !isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, - Loc, TPOC), + Loc, TPOC, NumCallArguments), BestTemplate)) { Ambiguous = true; break; @@ -3293,13 +3295,10 @@ Sema::getMoreSpecializedPartialSpecialization( // Determine whether PS1 is at least as specialized as PS2 Deduced.resize(PS2->getTemplateParameters()->size()); - bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(*this, - PS2->getTemplateParameters(), - PT2, - PT1, - Info, - Deduced, - 0); + bool Better1 = !::DeduceTemplateArguments(*this, PS2->getTemplateParameters(), + PT2, PT1, Info, Deduced, TDF_None, + /*PartialOrdering=*/true, + /*QualifierComparisons=*/0); if (Better1) { InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2, Deduced.data(), Deduced.size(), Info); @@ -3311,13 +3310,10 @@ Sema::getMoreSpecializedPartialSpecialization( // Determine whether PS2 is at least as specialized as PS1 Deduced.clear(); Deduced.resize(PS1->getTemplateParameters()->size()); - bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(*this, - PS1->getTemplateParameters(), - PT1, - PT2, - Info, - Deduced, - 0); + bool Better2 = !::DeduceTemplateArguments(*this, PS1->getTemplateParameters(), + PT1, PT2, Info, Deduced, TDF_None, + /*PartialOrdering=*/true, + /*QualifierComparisons=*/0); if (Better2) { InstantiatingTemplate Inst(*this, PS1->getLocation(), PS1, Deduced.data(), Deduced.size(), Info); diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p11.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p11.cpp index 99ade4bc99..ae9c083112 100644 --- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p11.cpp +++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p11.cpp @@ -13,10 +13,10 @@ struct identity { }; template - T* f2(int, typename identity::type = 0); // expected-note{{candidate}} + T* f2(int, typename identity::type = 0); template - T& f2(U, typename identity::type = 0); // expected-note{{candidate}} + T& f2(U, typename identity::type = 0); void g2() { - f2(1); // expected-error{{ambiguous}} + int* ip = f2(1); }