From b7edc4f372f1abe6c422ea711a99f9906a7464da Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 17 Jun 2011 05:18:17 +0000 Subject: [PATCH] Factor the checking of the deduced argument type against the actual argument type for C++ [temp.deduct.call]p4 out of Sema::FinishTemplateArgumentDeduction(). No functionality change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133237 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaTemplateDeduction.cpp | 157 +++++++++++++++-------------- 1 file changed, 84 insertions(+), 73 deletions(-) diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 014c582779..9612ea777a 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2314,6 +2314,88 @@ Sema::SubstituteExplicitTemplateArguments( return TDK_Success; } +/// \brief Check whether the deduced argument type for a call to a function +/// template matches the actual argument type per C++ [temp.deduct.call]p4. +static bool +CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, + QualType DeducedA) { + ASTContext &Context = S.Context; + + QualType A = OriginalArg.OriginalArgType; + QualType OriginalParamType = OriginalArg.OriginalParamType; + + // Check for type equality (top-level cv-qualifiers are ignored). + if (Context.hasSameUnqualifiedType(A, DeducedA)) + return false; + + // Strip off references on the argument types; they aren't needed for + // the following checks. + if (const ReferenceType *DeducedARef = DeducedA->getAs()) + DeducedA = DeducedARef->getPointeeType(); + if (const ReferenceType *ARef = A->getAs()) + A = ARef->getPointeeType(); + + // C++ [temp.deduct.call]p4: + // [...] However, there are three cases that allow a difference: + // - 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 (const ReferenceType *OriginalParamRef + = OriginalParamType->getAs()) { + // We don't want to keep the reference around any more. + OriginalParamType = OriginalParamRef->getPointeeType(); + + Qualifiers AQuals = A.getQualifiers(); + Qualifiers DeducedAQuals = DeducedA.getQualifiers(); + if (AQuals == DeducedAQuals) { + // Qualifiers match; there's nothing to do. + } else if (!DeducedAQuals.compatiblyIncludes(AQuals)) { + return Sema::TDK_SubstitutionFailure; + } else { + // Qualifiers are compatible, so have the argument type adopt the + // deduced argument type's qualifiers as if we had performed the + // qualification conversion. + A = Context.getQualifiedType(A.getUnqualifiedType(), DeducedAQuals); + } + } + + // - The transformed A can be another pointer or pointer to member + // type that can be converted to the deduced A via a qualification + // conversion. + bool ObjCLifetimeConversion = false; + if ((A->isAnyPointerType() || A->isMemberPointerType()) && + S.IsQualificationConversion(A, DeducedA, false, ObjCLifetimeConversion)) + return false; + + + // - If P is a class and P has the form simple-template-id, then the + // transformed A can be a derived class of the deduced A. [...] + // [...] Likewise, if P is a pointer to a class of the form + // simple-template-id, the transformed A can be a pointer to a + // derived class pointed to by the deduced A. + if (const PointerType *OriginalParamPtr + = OriginalParamType->getAs()) { + if (const PointerType *DeducedAPtr = DeducedA->getAs()) { + if (const PointerType *APtr = A->getAs()) { + if (A->getPointeeType()->isRecordType()) { + OriginalParamType = OriginalParamPtr->getPointeeType(); + DeducedA = DeducedAPtr->getPointeeType(); + A = APtr->getPointeeType(); + } + } + } + } + + if (Context.hasSameUnqualifiedType(A, DeducedA)) + return false; + + if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) && + S.IsDerivedFrom(A, DeducedA)) + return false; + + return true; +} + /// \brief Finish template argument deduction for a function template, /// checking the deduced template arguments for completeness and forming /// the function template specialization. @@ -2487,85 +2569,14 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // is transformed as described above). [...] for (unsigned I = 0, N = OriginalCallArgs->size(); I != N; ++I) { OriginalCallArg OriginalArg = (*OriginalCallArgs)[I]; - QualType A = OriginalArg.OriginalArgType; unsigned ParamIdx = OriginalArg.ArgIdx; if (ParamIdx >= Specialization->getNumParams()) continue; QualType DeducedA = Specialization->getParamDecl(ParamIdx)->getType(); - QualType OriginalParamType = OriginalArg.OriginalParamType; - - // Check for type equality (top-level cv-qualifiers are ignored). - if (Context.hasSameUnqualifiedType(A, DeducedA)) - continue; - - // Strip off references on the argument types; they aren't needed for - // the following checks. - if (const ReferenceType *DeducedARef = DeducedA->getAs()) - DeducedA = DeducedARef->getPointeeType(); - if (const ReferenceType *ARef = A->getAs()) - A = ARef->getPointeeType(); - - // C++ [temp.deduct.call]p4: - // [...] However, there are three cases that allow a difference: - // - 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 (const ReferenceType *OriginalParamRef - = OriginalParamType->getAs()) { - // We don't want to keep the reference around any more. - OriginalParamType = OriginalParamRef->getPointeeType(); - - Qualifiers AQuals = A.getQualifiers(); - Qualifiers DeducedAQuals = DeducedA.getQualifiers(); - if (AQuals == DeducedAQuals) { - // Qualifiers match; there's nothing to do. - } else if (!DeducedAQuals.compatiblyIncludes(AQuals)) { - return Sema::TDK_SubstitutionFailure; - } else { - // Qualifiers are compatible, so have the argument type adopt the - // deduced argument type's qualifiers as if we had performed the - // qualification conversion. - A = Context.getQualifiedType(A.getUnqualifiedType(), DeducedAQuals); - } - } - - // - The transformed A can be another pointer or pointer to member - // type that can be converted to the deduced A via a qualification - // conversion. - bool ObjCLifetimeConversion = false; - if ((A->isAnyPointerType() || A->isMemberPointerType()) && - IsQualificationConversion(A, DeducedA, false, ObjCLifetimeConversion)) - continue; - - - // - If P is a class and P has the form simple-template-id, then the - // transformed A can be a derived class of the deduced A. [...] - // [...] Likewise, if P is a pointer to a class of the form - // simple-template-id, the transformed A can be a pointer to a - // derived class pointed to by the deduced A. - if (const PointerType *OriginalParamPtr - = OriginalParamType->getAs()) { - if (const PointerType *DeducedAPtr = DeducedA->getAs()) { - if (const PointerType *APtr = A->getAs()) { - if (A->getPointeeType()->isRecordType()) { - OriginalParamType = OriginalParamPtr->getPointeeType(); - DeducedA = DeducedAPtr->getPointeeType(); - A = APtr->getPointeeType(); - } - } - } - } - - if (Context.hasSameUnqualifiedType(A, DeducedA)) - continue; - - if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) && - IsDerivedFrom(A, DeducedA)) - continue; - - return Sema::TDK_SubstitutionFailure; + if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) + return Sema::TDK_SubstitutionFailure; } }