From 66d2c8e88681adffa2a392f563ad38451cadd02e Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 30 Aug 2010 21:04:23 +0000 Subject: [PATCH] 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 , a template argument deduction issue found by Boost.Filesystem. llvm-svn: 112523 --- clang/lib/Sema/SemaTemplateDeduction.cpp | 74 +++++++++++-------- .../temp.deduct/temp.deduct.call/p6.cpp | 18 +++++ 2 files changed, 61 insertions(+), 31 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 87d9febfb130..5c77ed61060b 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/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 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(); + 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(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() && + 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()) { - // [...] 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(ParamRefType) && - ParamRefType->getAs() && - 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 diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp index 1b240cc98fc7..16b5cd297d8b 100644 --- a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp +++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp @@ -93,3 +93,21 @@ namespace test1 { invoke(&temp2); // expected-error {{no matching function for call to 'invoke'}} } } + +namespace rdar8360106 { + template void f0(R (*)(T), T); + template void f1(R (&)(T) , T); // expected-note{{candidate template ignored: couldn't infer template argument 'R'}} + template void f2(R (* const&)(T), T); // expected-note{{candidate template ignored: couldn't infer template argument 'R'}} + + int g(int); + int g(int, int); + + void h() { + f0(g, 1); + f0(&g, 1); + f1(g, 1); + f1(&g, 1); // expected-error{{no matching function for call to 'f1'}} + f2(g, 1); // expected-error{{no matching function for call to 'f2'}} + f2(&g, 1); + } +}