diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-08-30 21:04:23 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-08-30 21:04:23 +0000 |
commit | 75f21af57f3dce1577d6c27bbe7bb45b49ced732 (patch) | |
tree | ac6ad9625097e721f4a6de5ab1f7263cc18b448c /lib/Sema/SemaTemplateDeduction.cpp | |
parent | 3b6081bf49b7506cb96131247f209d1e03610df8 (diff) |
Perform the function-to-pointer adjustment during template argument
deduction where the parameter is a function reference, function
pointer, or member function pointer and the argument is an overloaded
function. Fixes <rdar://problem/8360106>, a template argument
deduction issue found by Boost.Filesystem.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112523 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaTemplateDeduction.cpp')
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 74 |
1 files changed, 43 insertions, 31 deletions
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 87d9febfb1..5c77ed6106 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -1542,12 +1542,20 @@ static QualType GetTypeOfFunction(ASTContext &Context, /// undeduced context static QualType ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, - Expr *Arg, QualType ParamType) { + Expr *Arg, QualType ParamType, + bool ParamWasReference) { OverloadExpr::FindResult R = OverloadExpr::find(Arg); OverloadExpr *Ovl = R.Expression; + // C++0x [temp.deduct.call]p4 + unsigned TDF = 0; + if (ParamWasReference) + TDF |= TDF_ParamWithReferenceType; + if (R.IsAddressOfOperand) + TDF |= TDF_IgnoreQualifiers; + // If there were explicit template arguments, we can only find // something via C++ [temp.arg.explicit]p3, i.e. if the arguments // unambiguously name a full specialization. @@ -1583,6 +1591,11 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, QualType ArgType = GetTypeOfFunction(S.Context, R, Fn); if (ArgType.isNull()) continue; + // Function-to-pointer conversion. + if (!ParamWasReference && ParamType->isPointerType() && + ArgType->isFunctionType()) + ArgType = S.Context.getPointerType(ArgType); + // - If the argument is an overload set (not containing function // templates), trial argument deduction is attempted using each // of the members of the set. If deduction succeeds for only one @@ -1598,8 +1611,6 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, llvm::SmallVector<DeducedTemplateArgument, 8> Deduced(TemplateParams->size()); TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc()); - unsigned TDF = 0; - Sema::TemplateDeductionResult Result = DeduceTemplateArguments(S, TemplateParams, ParamType, ArgType, @@ -1694,20 +1705,40 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType ParamType = ParamTypes[I]; QualType ArgType = Args[I]->getType(); + // C++0x [temp.deduct.call]p3: + // If P is a cv-qualified type, the top level cv-qualifiers of P’s type + // are ignored for type deduction. + if (ParamType.getCVRQualifiers()) + ParamType = ParamType.getLocalUnqualifiedType(); + const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>(); + if (ParamRefType) { + // [...] If P is a reference type, the type referred to by P is used + // for type deduction. + ParamType = ParamRefType->getPointeeType(); + } + // Overload sets usually make this parameter an undeduced // context, but there are sometimes special circumstances. if (ArgType == Context.OverloadTy) { ArgType = ResolveOverloadForDeduction(*this, TemplateParams, - Args[I], ParamType); + Args[I], ParamType, + ParamRefType != 0); if (ArgType.isNull()) continue; } - // C++ [temp.deduct.call]p2: - // If P is not a reference type: - QualType CanonParamType = Context.getCanonicalType(ParamType); - bool ParamWasReference = isa<ReferenceType>(CanonParamType); - if (!ParamWasReference) { + if (ParamRefType) { + // C++0x [temp.deduct.call]p3: + // [...] If P is of the form T&&, where T is a template parameter, and + // the argument is an lvalue, the type A& is used in place of A for + // type deduction. + if (ParamRefType->isRValueReferenceType() && + ParamRefType->getAs<TemplateTypeParmType>() && + Args[I]->isLvalue(Context) == Expr::LV_Valid) + ArgType = Context.getLValueReferenceType(ArgType); + } else { + // C++ [temp.deduct.call]p2: + // If P is not a reference type: // - If A is an array type, the pointer type produced by the // array-to-pointer standard conversion (4.2) is used in place of // A for type deduction; otherwise, @@ -1722,30 +1753,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // - If A is a cv-qualified type, the top level cv-qualifiers of A’s // type are ignored for type deduction. QualType CanonArgType = Context.getCanonicalType(ArgType); - if (CanonArgType.getLocalCVRQualifiers()) - ArgType = CanonArgType.getLocalUnqualifiedType(); + if (ArgType.getCVRQualifiers()) + ArgType = ArgType.getUnqualifiedType(); } } - // C++0x [temp.deduct.call]p3: - // If P is a cv-qualified type, the top level cv-qualifiers of P’s type - // are ignored for type deduction. - if (CanonParamType.getLocalCVRQualifiers()) - ParamType = CanonParamType.getLocalUnqualifiedType(); - if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) { - // [...] If P is a reference type, the type referred to by P is used - // for type deduction. - ParamType = ParamRefType->getPointeeType(); - - // [...] If P is of the form T&&, where T is a template parameter, and - // the argument is an lvalue, the type A& is used in place of A for - // type deduction. - if (isa<RValueReferenceType>(ParamRefType) && - ParamRefType->getAs<TemplateTypeParmType>() && - Args[I]->isLvalue(Context) == Expr::LV_Valid) - ArgType = Context.getLValueReferenceType(ArgType); - } - // C++0x [temp.deduct.call]p4: // In general, the deduction process attempts to find template argument // values that will make the deduced A identical to A (after the type A @@ -1755,7 +1767,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // - 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 (ParamWasReference) + if (ParamRefType) TDF |= TDF_ParamWithReferenceType; // - The transformed A can be another pointer or pointer to member // type that can be converted to the deduced A via a qualification |