From: Douglas Gregor Date: Thu, 20 Jan 2011 16:44:54 +0000 (+0000) Subject: Start refactoring reference binding to more closely match the C++0x X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c5db24dfbc860a9fd1501c72f398bf6b6d5b6e0e;p=clang Start refactoring reference binding to more closely match the C++0x working paper's structure. The only functional change here is that we now handling binding to array rvalues, which we would previously reject. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123918 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 9593489b80..7360eca1e9 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2597,13 +2597,17 @@ static void TryReferenceInitialization(Sema &S, return; } - // - [If T1 is not a function type], if T2 is a class type and - if (!T1Function && T2->isRecordType()) { - bool isXValue = InitCategory.isXValue(); - // - the initializer expression is an rvalue and "cv1 T1" is - // reference-compatible with "cv2 T2", or - if (InitCategory.isRValue() && - RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + // - If the initializer expression + // - is an xvalue, class prvalue, array prvalue, or function lvalue and + // "cv1 T1" is reference-compatible with "cv2 T2" + // Note: functions are handled below. + if (!T1Function && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification && + (InitCategory.isXValue() || + (InitCategory.isPRValue() && T2->isRecordType()) || + (InitCategory.isPRValue() && T2->isArrayType()))) { + ExprValueKind ValueKind = InitCategory.isXValue()? VK_XValue : VK_RValue; + if (InitCategory.isPRValue() && T2->isRecordType()) { // The corresponding bullet in C++03 [dcl.init.ref]p5 gives the // compiler the freedom to perform a copy here or bind to the // object, while C++0x requires that we bind directly to the @@ -2615,27 +2619,30 @@ static void TryReferenceInitialization(Sema &S, // be callable whether or not the copy is actually done. if (!S.getLangOptions().CPlusPlus0x && !S.getLangOptions().Microsoft) Sequence.AddExtraneousCopyToTemporary(cv2T2); - - if (DerivedToBase) - Sequence.AddDerivedToBaseCastStep( - S.Context.getQualifiedType(T1, T2Quals), - isXValue ? VK_XValue : VK_RValue); - else if (ObjCConversion) - Sequence.AddObjCObjectConversionStep( - S.Context.getQualifiedType(T1, T2Quals)); - - if (T1Quals != T2Quals) - Sequence.AddQualificationConversionStep(cv1T1, - isXValue ? VK_XValue : VK_RValue); - Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/!isXValue); - return; } - - // - T1 is not reference-related to T2 and the initializer expression - // can be implicitly converted to an rvalue of type "cv3 T3" (this - // conversion is selected by enumerating the applicable conversion - // functions (13.3.1.6) and choosing the best one through overload - // resolution (13.3)), + + if (DerivedToBase) + Sequence.AddDerivedToBaseCastStep(S.Context.getQualifiedType(T1, T2Quals), + ValueKind); + else if (ObjCConversion) + Sequence.AddObjCObjectConversionStep( + S.Context.getQualifiedType(T1, T2Quals)); + + if (T1Quals != T2Quals) + Sequence.AddQualificationConversionStep(cv1T1, ValueKind); + Sequence.AddReferenceBindingStep(cv1T1, + /*bindingTemporary=*/(InitCategory.isPRValue() && !T2->isArrayType())); + return; + } + + // - has a class type (i.e., T2 is a class type), where T1 is not + // reference-related to T2, and can be implicitly converted to an + // xvalue, class prvalue, or function lvalue of type "cv3 T3", + // where "cv1 T1" is reference-compatible with "cv3 T3", + // + // FIXME: Need to handle xvalue, class prvalue, etc. cases in + // TryRefInitWithConversionFunction. + if (T2->isRecordType()) { if (RefRelationship == Sema::Ref_Incompatible) { ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, Kind, Initializer, @@ -2652,13 +2659,7 @@ static void TryReferenceInitialization(Sema &S, Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); return; } - - // - If the initializer expression is an rvalue, with T2 an array type, - // and "cv1 T1" is reference-compatible with "cv2 T2," the reference - // is bound to the object represented by the rvalue (see 3.10). - // FIXME: How can an array type be reference-compatible with anything? - // Don't we mean the element types of T1 and T2? - + // - Otherwise, a temporary of type “cv1 T1” is created and initialized // from the initializer expression using the rules for a non-reference // copy initialization (8.5). The reference is then bound to the diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp index ef230509b2..41741a98d8 100644 --- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp +++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify -pedantic %s // Test the C++0x-specific reference initialization rules, e.g., the // rules for rvalue references. @@ -30,9 +30,28 @@ void test_rvalue_refs() { Base&& base2 = prvalue(); Base&& base3 = prvalue(); - // FIXME: array prvalue case - // int (&&array0)[5] = HasArray().array; + // array prvalue case + int (&&array0)[5] = HasArray().array; // function lvalue case int (&&function0)(int) = f; } + +class NonCopyable { + NonCopyable(const NonCopyable&); +}; + +class NonCopyableDerived : public NonCopyable { + NonCopyableDerived(const NonCopyableDerived&); +}; + +void test_direct_binding() { + NonCopyable &&nc0 = prvalue(); + NonCopyable &&nc1 = prvalue(); + NonCopyable &&nc2 = xvalue(); + NonCopyable &&nc3 = xvalue(); + const NonCopyable &nc4 = prvalue(); + const NonCopyable &nc5 = prvalue(); + const NonCopyable &nc6 = xvalue(); + const NonCopyable &nc7 = xvalue(); +}