From: Douglas Gregor Date: Tue, 25 Jan 2011 17:19:08 +0000 (+0000) Subject: Implement the rvalue-reference deduction transformation (from T&& -> X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=73b3cf6503f72f054288cf474e1a8c8ae56383c2;p=clang Implement the rvalue-reference deduction transformation (from T&& -> T) when taking the address of an overloaded function or matching a specialization to a template (C++0x [temp.deduct.type]p10). Fixes PR9044. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124197 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 5c899ebdea..00d92bc6b5 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -49,7 +49,10 @@ namespace clang { /// \brief Allow non-dependent types to differ, e.g., when performing /// template argument deduction from a function call where conversions /// may apply. - TDF_SkipNonDependent = 0x08 + TDF_SkipNonDependent = 0x08, + /// \brief Whether we are performing template argument deduction for + /// parameters and arguments in a top-level template argument + TDF_TopLevelParameterTypeList = 0x10 }; } @@ -763,9 +766,9 @@ DeduceTemplateArguments(Sema &S, // Deduce template arguments from the pattern. if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], - Info, Deduced, PartialOrdering, - RefParamComparisons)) + = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], + Info, Deduced, TDF, PartialOrdering, + RefParamComparisons)) return Result; // Capture the deduced template arguments for each parameter pack expanded @@ -898,6 +901,29 @@ DeduceTemplateArguments(Sema &S, Arg.getCVRQualifiers()); Param = S.Context.getQualifiedType(UnqualParam, Quals); } + + if ((TDF & TDF_TopLevelParameterTypeList) && !Param->isFunctionType()) { + // C++0x [temp.deduct.type]p10: + // If P and A are function types that originated from deduction when + // taking the address of a function template (14.8.2.2) or when deducing + // template arguments from a function declaration (14.8.2.6) and Pi and + // Ai are parameters of the top-level parameter-type-list of P and A, + // respectively, Pi is adjusted if it is an rvalue reference to a + // cv-unqualified template parameter and Ai is an lvalue reference, in + // which case the type of Pi is changed to be the template parameter + // type (i.e., T&& is changed to simply T). [ Note: As a result, when + // Pi is T&& and Ai is X&, the adjusted Pi will be T, causing T to be + // deduced as X&. — end note ] + TDF &= ~TDF_TopLevelParameterTypeList; + + if (const RValueReferenceType *ParamRef + = Param->getAs()) { + if (isa(ParamRef->getPointeeType()) && + !ParamRef->getPointeeType().getQualifiers()) + if (Arg->isLValueReferenceType()) + Param = ParamRef->getPointeeType(); + } + } } // If the parameter type is not dependent, there is nothing to deduce. @@ -1119,6 +1145,7 @@ DeduceTemplateArguments(Sema &S, // T(*)() // T(*)(T) case Type::FunctionProto: { + unsigned SubTDF = TDF & TDF_TopLevelParameterTypeList; const FunctionProtoType *FunctionProtoArg = dyn_cast(Arg); if (!FunctionProtoArg) @@ -1147,7 +1174,7 @@ DeduceTemplateArguments(Sema &S, FunctionProtoParam->getNumArgs(), FunctionProtoArg->arg_type_begin(), FunctionProtoArg->getNumArgs(), - Info, Deduced, 0); + Info, Deduced, SubTDF); } case Type::InjectedClassName: { @@ -2767,7 +2794,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, if (TemplateDeductionResult Result = ::DeduceTemplateArguments(*this, TemplateParams, FunctionType, ArgFunctionType, Info, - Deduced, 0)) + Deduced, TDF_TopLevelParameterTypeList)) return Result; } diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp new file mode 100644 index 0000000000..9d342c8f8e --- /dev/null +++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s +template void f(T&&); +template<> void f(int&) { } +void (*fp)(int&) = &f;