forked from OSchip/llvm-project
Implement the special template argument deduction rule for T&& in a
call (C++0x [temp.deduct.call]p3). As part of this, start improving the reference-binding implementation used in the computation of implicit conversion sequences (for overload resolution) to reflect C++0x semantics. It still needs more work and testing, of course. llvm-svn: 123966
This commit is contained in:
parent
f4ca47bda8
commit
cba72b1f62
|
@ -3013,8 +3013,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
|
|||
// qualifier.
|
||||
// This is also the point where rvalue references and lvalue inits no longer
|
||||
// go together.
|
||||
if ((!isRValRef && !T1.isConstQualified()) ||
|
||||
(isRValRef && InitCategory.isLValue()))
|
||||
if (!isRValRef && !T1.isConstQualified())
|
||||
return ICS;
|
||||
|
||||
// -- If T1 is a function type, then
|
||||
|
@ -3073,8 +3072,17 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
|
|||
!S.RequireCompleteType(DeclLoc, T2, 0) &&
|
||||
FindConversionForRefInit(S, ICS, DeclType, DeclLoc,
|
||||
Init, T2, /*AllowRvalues=*/true,
|
||||
AllowExplicit))
|
||||
AllowExplicit)) {
|
||||
// In the second case, if the reference is an rvalue reference
|
||||
// and the second standard conversion sequence of the
|
||||
// user-defined conversion sequence includes an lvalue-to-rvalue
|
||||
// conversion, the program is ill-formed.
|
||||
if (ICS.isUserDefined() && isRValRef &&
|
||||
ICS.UserDefined.After.First == ICK_Lvalue_To_Rvalue)
|
||||
ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType);
|
||||
|
||||
return ICS;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Otherwise, a temporary of type "cv1 T1" is created and
|
||||
|
@ -3101,6 +3109,12 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
|
|||
(T1->isRecordType() || T2->isRecordType()))
|
||||
return ICS;
|
||||
|
||||
// If T1 is reference-related to T2 and the reference is an rvalue
|
||||
// reference, the initializer expression shall not be an lvalue.
|
||||
if (RefRelationship >= Sema::Ref_Related &&
|
||||
isRValRef && Init->Classify(S.Context).isLValue())
|
||||
return ICS;
|
||||
|
||||
// C++ [over.ics.ref]p2:
|
||||
// When a parameter of reference type is not bound directly to
|
||||
// an argument expression, the conversion sequence is the one
|
||||
|
@ -3123,6 +3137,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
|
|||
ICS.UserDefined.After.ReferenceBinding = true;
|
||||
ICS.UserDefined.After.RRefBinding = isRValRef;
|
||||
}
|
||||
|
||||
return ICS;
|
||||
}
|
||||
|
||||
|
@ -4005,6 +4020,16 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
|
|||
Candidate.FailureKind = ovl_fail_final_conversion_not_exact;
|
||||
}
|
||||
|
||||
// C++0x [dcl.init.ref]p5:
|
||||
// In the second case, if the reference is an rvalue reference and
|
||||
// the second standard conversion sequence of the user-defined
|
||||
// conversion sequence includes an lvalue-to-rvalue conversion, the
|
||||
// program is ill-formed.
|
||||
if (ToType->isRValueReferenceType() &&
|
||||
ICS.Standard.First == ICK_Lvalue_To_Rvalue) {
|
||||
Candidate.Viable = false;
|
||||
Candidate.FailureKind = ovl_fail_bad_final_conversion;
|
||||
}
|
||||
break;
|
||||
|
||||
case ImplicitConversionSequence::BadConversion:
|
||||
|
|
|
@ -2399,6 +2399,18 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
|
|||
ParamType = ParamType.getLocalUnqualifiedType();
|
||||
const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>();
|
||||
if (ParamRefType) {
|
||||
// [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 (const RValueReferenceType *RValueRef
|
||||
= dyn_cast<RValueReferenceType>(ParamType)) {
|
||||
if (!RValueRef->getPointeeType().getQualifiers() &&
|
||||
isa<TemplateTypeParmType>(RValueRef->getPointeeType()) &&
|
||||
Arg->Classify(S.Context).isLValue())
|
||||
ArgType = S.Context.getLValueReferenceType(ArgType);
|
||||
}
|
||||
|
||||
// [...] If P is a reference type, the type referred to by P is used
|
||||
// for type deduction.
|
||||
ParamType = ParamRefType->getPointeeType();
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
|
||||
|
||||
|
||||
// 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.
|
||||
template<typename T> struct X { };
|
||||
|
||||
template<typename T> X<T> f0(T&&);
|
||||
|
||||
struct Y { };
|
||||
|
||||
template<typename T> T prvalue();
|
||||
template<typename T> T&& xvalue();
|
||||
template<typename T> T& lvalue();
|
||||
|
||||
void test_f0() {
|
||||
X<int> xi0 = f0(prvalue<int>());
|
||||
X<int> xi1 = f0(xvalue<int>());
|
||||
X<int&> xi2 = f0(lvalue<int>());
|
||||
X<Y> xy0 = f0(prvalue<Y>());
|
||||
X<Y> xy1 = f0(xvalue<Y>());
|
||||
X<Y&> xy2 = f0(lvalue<Y>());
|
||||
}
|
Loading…
Reference in New Issue