[cfe-commits] r107301 - in /cfe/trunk: lib/Sema/SemaInit.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/rval-references.cpp
Sebastian Redl
sebastian.redl at getdesigned.at
Wed Jun 30 11:13:39 PDT 2010
Author: cornedbee
Date: Wed Jun 30 13:13:39 2010
New Revision: 107301
URL: http://llvm.org/viewvc/llvm-project?rev=107301&view=rev
Log:
Make both old and new versions of reference binding use the new classification functions, and updated them for N3092.
Modified:
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/SemaCXX/rval-references.cpp
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=107301&r1=107300&r2=107301&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Wed Jun 30 13:13:39 2010
@@ -2239,8 +2239,6 @@
/// \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 @@
if (ConvTemplate)
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
- Conv = cast<CXXConversionDecl>(*I);
+ Conv = cast<CXXConversionDecl>(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 @@
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<ReferenceType>()->getPointeeType();
Qualifiers T1Quals;
@@ -2417,7 +2415,7 @@
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 @@
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 @@
// 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 @@
}
}
}
-
+
// - 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 @@
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 @@
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
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=107301&r1=107300&r2=107301&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jun 30 13:13:39 2010
@@ -2622,6 +2622,93 @@
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<CXXRecordDecl>(T2->getAs<RecordType>()->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<CXXRecordDecl>(D->getDeclContext());
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ FunctionTemplateDecl *ConvTemplate
+ = dyn_cast<FunctionTemplateDecl>(D);
+ CXXConversionDecl *Conv;
+ if (ConvTemplate)
+ Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ Conv = cast<CXXConversionDecl>(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<ReferenceType>();
+ 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 @@
// 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<CXXRecordDecl>(T2->getAs<RecordType>()->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<CXXRecordDecl>(D->getDeclContext());
- if (isa<UsingShadowDecl>(D))
- D = cast<UsingShadowDecl>(D)->getTargetDecl();
-
- FunctionTemplateDecl *ConvTemplate
- = dyn_cast<FunctionTemplateDecl>(D);
- CXXConversionDecl *Conv;
- if (ConvTemplate)
- Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
- else
- Conv = cast<CXXConversionDecl>(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;
-
- 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 ICS;
-
- case OR_Ambiguous:
- ICS.setAmbiguous();
- for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
- Cand != CandidateSet.end(); ++Cand)
- if (Cand->Viable)
- ICS.Ambiguous.addConversion(Cand->Function);
+ // 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;
+
+ // 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_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 @@
// 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 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;
- // -- if T2 is a class type and
+ // -- 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 @@
//
// 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;
Modified: cfe/trunk/test/SemaCXX/rval-references.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/rval-references.cpp?rev=107301&r1=107300&r2=107301&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/rval-references.cpp (original)
+++ cfe/trunk/test/SemaCXX/rval-references.cpp Wed Jun 30 13:13:39 2010
@@ -21,6 +21,10 @@
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 @@
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}}
More information about the cfe-commits
mailing list