From 4680bf233caeebe89aa297eb5a25709dd15a4b11 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Wed, 30 Jun 2010 18:13:39 +0000 Subject: [PATCH] Make both old and new versions of reference binding use the new classification functions, and updated them for N3092. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107301 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaInit.cpp | 54 +++--- lib/Sema/SemaOverload.cpp | 290 +++++++++++++++++-------------- test/SemaCXX/rval-references.cpp | 7 + 3 files changed, 195 insertions(+), 156 deletions(-) diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index f30e80979c..c2d6de749b 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2239,8 +2239,6 @@ static void TryListInitialization(Sema &S, /// \brief Try a reference initialization that involves calling a conversion /// function. -/// -/// FIXME: look intos DRs 656, 896 static OverloadingResult TryRefInitWithConversionFunction(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -2331,7 +2329,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, if (ConvTemplate) Conv = cast(ConvTemplate->getTemplatedDecl()); else - Conv = cast(*I); + Conv = cast(D); // If the conversion function doesn't return a reference type, // it can't be considered for this conversion unless we're allowed to @@ -2401,14 +2399,14 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, return OR_Success; } -/// \brief Attempt reference initialization (C++0x [dcl.init.list]) +/// \brief Attempt reference initialization (C++0x [dcl.init.ref]) static void TryReferenceInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, Expr *Initializer, InitializationSequence &Sequence) { Sequence.setSequenceKind(InitializationSequence::ReferenceBinding); - + QualType DestType = Entity.getType(); QualType cv1T1 = DestType->getAs()->getPointeeType(); Qualifiers T1Quals; @@ -2417,7 +2415,7 @@ static void TryReferenceInitialization(Sema &S, Qualifiers T2Quals; QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals); SourceLocation DeclLoc = Initializer->getLocStart(); - + // If the initializer is the address of an overloaded function, try // to resolve the overloaded function. If all goes well, T2 is the // type of the resulting function. @@ -2431,29 +2429,33 @@ static void TryReferenceInitialization(Sema &S, Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); return; } - + Sequence.AddAddressOverloadResolutionStep(Fn, Found); cv2T2 = Fn->getType(); T2 = cv2T2.getUnqualifiedType(); } - + // Compute some basic properties of the types and the initializer. bool isLValueRef = DestType->isLValueReferenceType(); bool isRValueRef = !isLValueRef; bool DerivedToBase = false; - Expr::isLvalueResult InitLvalue = Initializer->isLvalue(S.Context); + Expr::Classification InitCategory = Initializer->Classify(S.Context); Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase); - + // C++0x [dcl.init.ref]p5: // A reference to type "cv1 T1" is initialized by an expression of type // "cv2 T2" as follows: // // - If the reference is an lvalue reference and the initializer // expression + // Note the analogous bullet points for rvlaue refs to functions. Because + // there are no function rvalues in C++, rvalue refs to functions are treated + // like lvalue refs. OverloadingResult ConvOvlResult = OR_Success; - if (isLValueRef) { - if (InitLvalue == Expr::LV_Valid && + bool T1Function = T1->isFunctionType(); + if (isLValueRef || T1Function) { + if (InitCategory.isLValue() && RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { // - is an lvalue (but is not a bit-field), and "cv1 T1" is // reference-compatible with "cv2 T2," or @@ -2481,10 +2483,13 @@ static void TryReferenceInitialization(Sema &S, // with "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 (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType()) { + // If we have an rvalue ref to function type here, the rhs must be + // an rvalue. + if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType() && + (isLValueRef || InitCategory.isRValue())) { ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, Kind, Initializer, - /*AllowRValues=*/false, + /*AllowRValues=*/isRValueRef, Sequence); if (ConvOvlResult == OR_Success) return; @@ -2495,19 +2500,20 @@ static void TryReferenceInitialization(Sema &S, } } } - + // - Otherwise, the reference shall be an lvalue reference to a // non-volatile const type (i.e., cv1 shall be const), or the reference // shall be an rvalue reference and the initializer expression shall - // be an rvalue. + // be an rvalue or have a function type. + // We handled the function type stuff above. if (!((isLValueRef && T1Quals.hasConst() && !T1Quals.hasVolatile()) || - (isRValueRef && InitLvalue != Expr::LV_Valid))) { + (isRValueRef && InitCategory.isRValue()))) { if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) Sequence.SetOverloadFailure( InitializationSequence::FK_ReferenceInitOverloadFailed, ConvOvlResult); else if (isLValueRef) - Sequence.SetFailed(InitLvalue == Expr::LV_Valid + Sequence.SetFailed(InitCategory.isLValue() ? (RefRelationship == Sema::Ref_Related ? InitializationSequence::FK_ReferenceInitDropsQualifiers : InitializationSequence::FK_NonConstLValueReferenceBindingToUnrelated) @@ -2515,15 +2521,15 @@ static void TryReferenceInitialization(Sema &S, else Sequence.SetFailed( InitializationSequence::FK_RValueReferenceBindingToLValue); - + return; } - - // - If T1 and T2 are class types and - if (T1->isRecordType() && T2->isRecordType()) { + + // - [If T1 is not a function type], if T2 is a class type and + if (!T1Function && T2->isRecordType()) { // - the initializer expression is an rvalue and "cv1 T1" is // reference-compatible with "cv2 T2", or - if (InitLvalue != Expr::LV_Valid && + if (InitCategory.isRValue() && RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { // The corresponding bullet in C++03 [dcl.init.ref]p5 gives the // compiler the freedom to perform a copy here or bind to the @@ -2546,7 +2552,7 @@ static void TryReferenceInitialization(Sema &S, Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); 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 diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 56e800539f..344fb92c25 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -2622,6 +2622,93 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, return Ref_Related; } +/// \brief Look for a user-defined conversion to an lvalue reference-compatible +/// with DeclType. Return true if something definite is found. +static bool +FindConversionToLValue(Sema &S, ImplicitConversionSequence &ICS, + QualType DeclType, SourceLocation DeclLoc, + Expr *Init, QualType T2, bool AllowExplicit) { + assert(T2->isRecordType() && "Can only find conversions of record types."); + CXXRecordDecl *T2RecordDecl + = dyn_cast(T2->getAs()->getDecl()); + + OverloadCandidateSet CandidateSet(DeclLoc); + const UnresolvedSetImpl *Conversions + = T2RecordDecl->getVisibleConversionFunctions(); + for (UnresolvedSetImpl::iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingDC = cast(D->getDeclContext()); + if (isa(D)) + D = cast(D)->getTargetDecl(); + + FunctionTemplateDecl *ConvTemplate + = dyn_cast(D); + CXXConversionDecl *Conv; + if (ConvTemplate) + Conv = cast(ConvTemplate->getTemplatedDecl()); + else + Conv = cast(D); + + // If the conversion function doesn't return a reference type, + // it can't be considered for this conversion. An rvalue reference + // is only acceptable if its referencee is a function type. + const ReferenceType *RefType = + Conv->getConversionType()->getAs(); + if (RefType && (RefType->isLValueReferenceType() || + RefType->getPointeeType()->isFunctionType()) && + (AllowExplicit || !Conv->isExplicit())) { + if (ConvTemplate) + S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, + Init, DeclType, CandidateSet); + else + S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init, + DeclType, CandidateSet); + } + } + + OverloadCandidateSet::iterator Best; + switch (S.BestViableFunction(CandidateSet, DeclLoc, Best)) { + case OR_Success: + // C++ [over.ics.ref]p1: + // + // [...] If the parameter binds directly to the result of + // applying a conversion function to the argument + // expression, the implicit conversion sequence is a + // user-defined conversion sequence (13.3.3.1.2), with the + // second standard conversion sequence either an identity + // conversion or, if the conversion function returns an + // entity of a type that is a derived class of the parameter + // type, a derived-to-base Conversion. + if (!Best->FinalConversion.DirectBinding) + return false; + + ICS.setUserDefined(); + ICS.UserDefined.Before = Best->Conversions[0].Standard; + ICS.UserDefined.After = Best->FinalConversion; + ICS.UserDefined.ConversionFunction = Best->Function; + ICS.UserDefined.EllipsisConversion = false; + assert(ICS.UserDefined.After.ReferenceBinding && + ICS.UserDefined.After.DirectBinding && + "Expected a direct reference binding!"); + return true; + + case OR_Ambiguous: + ICS.setAmbiguous(); + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); + Cand != CandidateSet.end(); ++Cand) + if (Cand->Viable) + ICS.Ambiguous.addConversion(Cand->Function); + return true; + + case OR_No_Viable_Function: + case OR_Deleted: + // There was no suitable conversion, or we found a deleted + // conversion; continue with other checks. + return false; + } +} + /// \brief Compute an implicit conversion sequence for reference /// initialization. static ImplicitConversionSequence @@ -2651,149 +2738,72 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // Compute some basic properties of the types and the initializer. bool isRValRef = DeclType->isRValueReferenceType(); bool DerivedToBase = false; - Expr::isLvalueResult InitLvalue = Init->isLvalue(S.Context); + Expr::Classification InitCategory = Init->Classify(S.Context); Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase); - // C++ [over.ics.ref]p3: - // Except for an implicit object parameter, for which see 13.3.1, - // a standard conversion sequence cannot be formed if it requires - // binding an lvalue reference to non-const to an rvalue or - // binding an rvalue reference to an lvalue. - // - // FIXME: DPG doesn't trust this code. It seems far too early to - // abort because of a binding of an rvalue reference to an lvalue. - if (isRValRef && InitLvalue == Expr::LV_Valid) - return ICS; - - // C++0x [dcl.init.ref]p16: + // C++0x [dcl.init.ref]p5: // A reference to type "cv1 T1" is initialized by an expression // of type "cv2 T2" as follows: - // -- If the initializer expression - // -- is an lvalue (but is not a bit-field), and "cv1 T1" is - // reference-compatible with "cv2 T2," or - // - // Per C++ [over.ics.ref]p4, we don't check the bit-field property here. - if (InitLvalue == Expr::LV_Valid && - RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { - // C++ [over.ics.ref]p1: - // When a parameter of reference type binds directly (8.5.3) - // to an argument expression, the implicit conversion sequence - // is the identity conversion, unless the argument expression - // has a type that is a derived class of the parameter type, - // in which case the implicit conversion sequence is a - // derived-to-base Conversion (13.3.3.1). - ICS.setStandard(); - ICS.Standard.First = ICK_Identity; - ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; - ICS.Standard.Third = ICK_Identity; - ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); - ICS.Standard.setToType(0, T2); - ICS.Standard.setToType(1, T1); - ICS.Standard.setToType(2, T1); - ICS.Standard.ReferenceBinding = true; - ICS.Standard.DirectBinding = true; - ICS.Standard.RRefBinding = false; - ICS.Standard.CopyConstructor = 0; - - // Nothing more to do: the inaccessibility/ambiguity check for - // derived-to-base conversions is suppressed when we're - // computing the implicit conversion sequence (C++ - // [over.best.ics]p2). - return ICS; - } - - // -- 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 lvalue of type "cv3 T3," where "cv1 T1" - // is reference-compatible with "cv3 T3" 92) (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 (!isRValRef && !SuppressUserConversions && T2->isRecordType() && - !S.RequireCompleteType(DeclLoc, T2, 0) && - RefRelationship == Sema::Ref_Incompatible) { - CXXRecordDecl *T2RecordDecl - = dyn_cast(T2->getAs()->getDecl()); - - OverloadCandidateSet CandidateSet(DeclLoc); - const UnresolvedSetImpl *Conversions - = T2RecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSetImpl::iterator I = Conversions->begin(), - E = Conversions->end(); I != E; ++I) { - NamedDecl *D = *I; - CXXRecordDecl *ActingDC = cast(D->getDeclContext()); - if (isa(D)) - D = cast(D)->getTargetDecl(); - - FunctionTemplateDecl *ConvTemplate - = dyn_cast(D); - CXXConversionDecl *Conv; - if (ConvTemplate) - Conv = cast(ConvTemplate->getTemplatedDecl()); - else - Conv = cast(D); - - // If the conversion function doesn't return a reference type, - // it can't be considered for this conversion. - if (Conv->getConversionType()->isLValueReferenceType() && - (AllowExplicit || !Conv->isExplicit())) { - if (ConvTemplate) - S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, - Init, DeclType, CandidateSet); - else - S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init, - DeclType, CandidateSet); - } - } - - OverloadCandidateSet::iterator Best; - switch (S.BestViableFunction(CandidateSet, DeclLoc, Best)) { - case OR_Success: + // -- If reference is an lvalue reference and the initializer expression + // The next bullet point (T1 is a function) is pretty much equivalent to this + // one, so it's handled here. + if (!isRValRef || T1->isFunctionType()) { + // -- is an lvalue (but is not a bit-field), and "cv1 T1" is + // reference-compatible with "cv2 T2," or + // + // Per C++ [over.ics.ref]p4, we don't check the bit-field property here. + if (InitCategory.isLValue() && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { // C++ [over.ics.ref]p1: - // - // [...] If the parameter binds directly to the result of - // applying a conversion function to the argument - // expression, the implicit conversion sequence is a - // user-defined conversion sequence (13.3.3.1.2), with the - // second standard conversion sequence either an identity - // conversion or, if the conversion function returns an - // entity of a type that is a derived class of the parameter - // type, a derived-to-base Conversion. - if (!Best->FinalConversion.DirectBinding) - break; + // When a parameter of reference type binds directly (8.5.3) + // to an argument expression, the implicit conversion sequence + // is the identity conversion, unless the argument expression + // has a type that is a derived class of the parameter type, + // in which case the implicit conversion sequence is a + // derived-to-base Conversion (13.3.3.1). + ICS.setStandard(); + ICS.Standard.First = ICK_Identity; + ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; + ICS.Standard.Third = ICK_Identity; + ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); + ICS.Standard.setToType(0, T2); + ICS.Standard.setToType(1, T1); + ICS.Standard.setToType(2, T1); + ICS.Standard.ReferenceBinding = true; + ICS.Standard.DirectBinding = true; + ICS.Standard.RRefBinding = isRValRef; + ICS.Standard.CopyConstructor = 0; - ICS.setUserDefined(); - ICS.UserDefined.Before = Best->Conversions[0].Standard; - ICS.UserDefined.After = Best->FinalConversion; - ICS.UserDefined.ConversionFunction = Best->Function; - ICS.UserDefined.EllipsisConversion = false; - assert(ICS.UserDefined.After.ReferenceBinding && - ICS.UserDefined.After.DirectBinding && - "Expected a direct reference binding!"); + // Nothing more to do: the inaccessibility/ambiguity check for + // derived-to-base conversions is suppressed when we're + // computing the implicit conversion sequence (C++ + // [over.best.ics]p2). return ICS; + } - case OR_Ambiguous: - ICS.setAmbiguous(); - for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); - Cand != CandidateSet.end(); ++Cand) - if (Cand->Viable) - ICS.Ambiguous.addConversion(Cand->Function); - return ICS; - - case OR_No_Viable_Function: - case OR_Deleted: - // There was no suitable conversion, or we found a deleted - // conversion; continue with other checks. - break; + // -- 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 lvalue of type "cv3 T3," where "cv1 T1" + // is reference-compatible with "cv3 T3" 92) (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 (!SuppressUserConversions && T2->isRecordType() && + !S.RequireCompleteType(DeclLoc, T2, 0) && + RefRelationship == Sema::Ref_Incompatible) { + if (FindConversionToLValue(S, ICS, DeclType, DeclLoc, + Init, T2, AllowExplicit)) + return ICS; } } - // -- Otherwise, the reference shall be to a non-volatile const - // type (i.e., cv1 shall be const), or the reference shall be an - // rvalue reference and the initializer expression shall be an rvalue. + // -- Otherwise, the reference shall be an lvalue reference to a + // non-volatile const type (i.e., cv1 shall be const), or the reference + // shall be an rvalue reference and the initializer expression shall be + // an rvalue or have a function type. // // We actually handle one oddity of C++ [over.ics.ref] at this // point, which is that, due to p2 (which short-circuits reference @@ -2802,10 +2812,26 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // reference to bind to an rvalue. Hence the check for the presence // of "const" rather than checking for "const" being the only // qualifier. - if (!isRValRef && !T1.isConstQualified()) + // This is also the point where rvalue references and lvalue inits no longer + // go together. + if ((!isRValRef && !T1.isConstQualified()) || + (isRValRef && InitCategory.isLValue())) return ICS; - // -- if T2 is a class type and + // -- If T1 is a function type, then + // -- if T2 is the same type as T1, the reference is bound to the + // initializer expression lvalue; + // -- if T2 is a class type and the initializer expression can be + // implicitly converted to an lvalue of type T1 [...], the + // reference is bound to the function lvalue that is the result + // of the conversion; + // This is the same as for the lvalue case above, so it was handled there. + // -- otherwise, the program is ill-formed. + // This is the one difference to the lvalue case. + if (T1->isFunctionType()) + return ICS; + + // -- Otherwise, if T2 is a class type and // -- the initializer expression is an rvalue and "cv1 T1" // is reference-compatible with "cv2 T2," or // @@ -2824,7 +2850,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // // We're only checking the first case here, which is a direct // binding in C++0x but not in C++03. - if (InitLvalue != Expr::LV_Valid && T2->isRecordType() && + if (InitCategory.isRValue() && T2->isRecordType() && RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { ICS.setStandard(); ICS.Standard.First = ICK_Identity; diff --git a/test/SemaCXX/rval-references.cpp b/test/SemaCXX/rval-references.cpp index d5b465f078..30622ccbfe 100644 --- a/test/SemaCXX/rval-references.cpp +++ b/test/SemaCXX/rval-references.cpp @@ -21,6 +21,10 @@ struct conv_to_not_int_rvalue { operator not_int &&(); }; +typedef void (fun_type)(); +void fun(); +fun_type &&make_fun(); + void f() { int &&virr1; // expected-error {{declaration of reference variable 'virr1' requires an initializer}} int &&virr2 = 0; @@ -47,6 +51,9 @@ void f() { not_int &ni5 = cnir; // expected-error{{non-const lvalue reference to type 'not_int' cannot bind to a value of unrelated type 'conv_to_not_int_rvalue'}} not_int &&ni6 = conv_to_not_int_rvalue(); + fun_type &&fun_ref = fun; // works because functions are special + fun_type &&fun_ref2 = make_fun(); // same + fun_type &fun_lref = make_fun(); // also special try { } catch(int&&) { // expected-error {{cannot catch exceptions by rvalue reference}}