fix pr18645. Correct logic concerning 'T &&' deduction against lvalues.

llvm-svn: 225587
This commit is contained in:
Nathan Sidwell 2015-01-10 18:16:25 +00:00
parent a0040df38c
commit f9701c6e83
2 changed files with 22 additions and 30 deletions

View File

@ -3136,34 +3136,16 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
// are ignored for type deduction.
if (ParamType.hasQualifiers())
ParamType = ParamType.getUnqualifiedType();
// [...] If P is a reference type, the type referred to by P is
// used for type deduction.
const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>();
if (ParamRefType) {
QualType PointeeType = ParamRefType->getPointeeType();
if (ParamRefType)
ParamType = ParamRefType->getPointeeType();
// If the argument has incomplete array type, try to complete its type.
if (ArgType->isIncompleteArrayType() && !S.RequireCompleteExprType(Arg, 0))
ArgType = Arg->getType();
// [C++0x] If P is an rvalue reference to a cv-unqualified
// template parameter and the argument is an lvalue, the type
// "lvalue reference to A" is used in place of A for type
// deduction.
if (isa<RValueReferenceType>(ParamType)) {
if (!PointeeType.getQualifiers() &&
isa<TemplateTypeParmType>(PointeeType) &&
Arg->Classify(S.Context).isLValue() &&
Arg->getType() != S.Context.OverloadTy &&
Arg->getType() != S.Context.BoundMemberTy)
ArgType = S.Context.getLValueReferenceType(ArgType);
}
// [...] If P is a reference type, the type referred to by P is used
// for type deduction.
ParamType = PointeeType;
}
// Overload sets usually make this parameter an undeduced
// context, but there are sometimes special circumstances.
// Overload sets usually make this parameter an undeduced context,
// but there are sometimes special circumstances. Typically
// involving a template-id-expr.
if (ArgType == S.Context.OverloadTy) {
ArgType = ResolveOverloadForDeduction(S, TemplateParams,
Arg, ParamType,
@ -3173,12 +3155,17 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
}
if (ParamRefType) {
// If the argument has incomplete array type, try to complete its type.
if (ArgType->isIncompleteArrayType() && !S.RequireCompleteExprType(Arg, 0))
ArgType = Arg->getType();
// 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 P is an rvalue reference to a cv-unqualified template
// parameter and the argument is an lvalue, the type "lvalue
// reference to A" is used in place of A for type deduction.
if (ParamRefType->isRValueReferenceType() &&
ParamRefType->getAs<TemplateTypeParmType>() &&
!ParamType.getQualifiers() &&
isa<TemplateTypeParmType>(ParamType) &&
Arg->isLValue())
ArgType = S.Context.getLValueReferenceType(ArgType);
} else {

View File

@ -202,3 +202,8 @@ namespace PR19372 {
using T = S<int, int>;
}
}
namespace PR18645 {
template<typename F> F Quux(F &&f);
auto Baz = Quux(Quux<float>);
}