[cfe-commits] r99647 - in /cfe/trunk: lib/Sema/SemaExprCXX.cpp lib/Sema/SemaInit.cpp lib/Sema/SemaInit.h test/SemaCXX/conditional-expr.cpp
Douglas Gregor
dgregor at apple.com
Fri Mar 26 13:14:36 PDT 2010
Author: dgregor
Date: Fri Mar 26 15:14:36 2010
New Revision: 99647
URL: http://llvm.org/viewvc/llvm-project?rev=99647&view=rev
Log:
Switch semantic analysis of the conditional operator from using
CheckReferenceInit to using the new initialization sequence code.
Modified:
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaInit.h
cfe/trunk/test/SemaCXX/conditional-expr.cpp
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=99647&r1=99646&r2=99647&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Mar 26 15:14:36 2010
@@ -1913,11 +1913,17 @@
/// This is part of the parameter validation for the ? operator. If either
/// value operand is a class type, the two operands are attempted to be
/// converted to each other. This function does the conversion in one direction.
-/// It emits a diagnostic and returns true only if it finds an ambiguous
-/// conversion.
+/// It returns true if the program is ill-formed and has already been diagnosed
+/// as such.
static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
SourceLocation QuestionLoc,
- ImplicitConversionSequence &ICS) {
+ bool &HaveConversion,
+ QualType &ToType) {
+ HaveConversion = false;
+ ToType = To->getType();
+
+ InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(),
+ SourceLocation());
// C++0x 5.16p3
// The process for determining whether an operand expression E1 of type T1
// can be converted to match an operand expression E2 of type T2 is defined
@@ -1927,22 +1933,18 @@
// E1 can be converted to match E2 if E1 can be implicitly converted to
// type "lvalue reference to T2", subject to the constraint that in the
// conversion the reference must bind directly to E1.
- if (!Self.CheckReferenceInit(From,
- Self.Context.getLValueReferenceType(To->getType()),
- To->getLocStart(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- &ICS))
- {
- assert((ICS.isStandard() || ICS.isUserDefined()) &&
- "expected a definite conversion");
- bool DirectBinding =
- ICS.isStandard() ? ICS.Standard.DirectBinding
- : ICS.UserDefined.After.DirectBinding;
- if (DirectBinding)
- return false;
+ QualType T = Self.Context.getLValueReferenceType(ToType);
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(T);
+
+ InitializationSequence InitSeq(Self, Entity, Kind, &From, 1);
+ if (InitSeq.isDirectReferenceBinding()) {
+ ToType = T;
+ HaveConversion = true;
+ return false;
}
+
+ if (InitSeq.isAmbiguous())
+ return InitSeq.Diagnose(Self, Entity, Kind, &From, 1);
}
// -- If E2 is an rvalue, or if the conversion above cannot be done:
@@ -1952,47 +1954,46 @@
QualType TTy = To->getType();
const RecordType *FRec = FTy->getAs<RecordType>();
const RecordType *TRec = TTy->getAs<RecordType>();
- bool FDerivedFromT = FRec && TRec && Self.IsDerivedFrom(FTy, TTy);
- if (FRec && TRec && (FRec == TRec ||
- FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) {
+ bool FDerivedFromT = FRec && TRec && FRec != TRec &&
+ Self.IsDerivedFrom(FTy, TTy);
+ if (FRec && TRec &&
+ (FRec == TRec || FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) {
// E1 can be converted to match E2 if the class of T2 is the
// same type as, or a base class of, the class of T1, and
// [cv2 > cv1].
if (FRec == TRec || FDerivedFromT) {
if (TTy.isAtLeastAsQualifiedAs(FTy)) {
- // Could still fail if there's no copy constructor.
- // FIXME: Is this a hard error then, or just a conversion failure? The
- // standard doesn't say.
- ICS = Self.TryCopyInitialization(From, TTy,
- /*SuppressUserConversions=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
- } else {
- ICS.setBad(BadConversionSequence::bad_qualifiers, From, TTy);
- }
- } else {
- // Can't implicitly convert FTy to a derived class TTy.
- // TODO: more specific error for this.
- ICS.setBad(BadConversionSequence::no_conversion, From, TTy);
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy);
+ InitializationSequence InitSeq(Self, Entity, Kind, &From, 1);
+ if (InitSeq.getKind() != InitializationSequence::FailedSequence) {
+ HaveConversion = true;
+ return false;
+ }
+
+ if (InitSeq.isAmbiguous())
+ return InitSeq.Diagnose(Self, Entity, Kind, &From, 1);
+ }
}
- } else {
- // -- Otherwise: E1 can be converted to match E2 if E1 can be
- // implicitly converted to the type that expression E2 would have
- // if E2 were converted to an rvalue.
- // First find the decayed type.
- if (TTy->isFunctionType())
- TTy = Self.Context.getPointerType(TTy);
- else if (TTy->isArrayType())
- TTy = Self.Context.getArrayDecayedType(TTy);
-
- // Now try the implicit conversion.
- // FIXME: This doesn't detect ambiguities.
- ICS = Self.TryImplicitConversion(From, TTy,
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
+
+ return false;
}
+
+ // -- Otherwise: E1 can be converted to match E2 if E1 can be
+ // implicitly converted to the type that expression E2 would have
+ // if E2 were converted to an rvalue.
+ // First find the decayed type.
+ if (TTy->isFunctionType())
+ TTy = Self.Context.getPointerType(TTy);
+ else if (TTy->isArrayType())
+ TTy = Self.Context.getArrayDecayedType(TTy);
+
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy);
+ InitializationSequence InitSeq(Self, Entity, Kind, &From, 1);
+ HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence;
+ ToType = TTy;
+ if (InitSeq.isAmbiguous())
+ return InitSeq.Diagnose(Self, Entity, Kind, &From, 1);
+
return false;
}
@@ -2041,35 +2042,17 @@
/// \brief Perform an "extended" implicit conversion as returned by
/// TryClassUnification.
-///
-/// TryClassUnification generates ICSs that include reference bindings.
-/// PerformImplicitConversion is not suitable for this; it chokes if the
-/// second part of a standard conversion is ICK_DerivedToBase. This function
-/// handles the reference binding specially.
-static bool ConvertForConditional(Sema &Self, Expr *&E,
- const ImplicitConversionSequence &ICS) {
- if ((ICS.isStandard() && ICS.Standard.ReferenceBinding) ||
- (ICS.isUserDefined() && ICS.UserDefined.After.ReferenceBinding)) {
- assert(((ICS.isStandard() && ICS.Standard.DirectBinding) ||
- (ICS.isUserDefined() && ICS.UserDefined.After.DirectBinding)) &&
- "TryClassUnification should never generate indirect ref bindings");
- InitializedEntity Entity
- = InitializedEntity::InitializeTemporary(
- Self.Context.getLValueReferenceType(TargetType(ICS)));
- InitializationKind Kind = InitializationKind::CreateCopy(E->getLocStart(),
- SourceLocation());
- InitializationSequence InitSeq(Self, Entity, Kind, &E, 1);
- Sema::OwningExprResult Result = InitSeq.Perform(Self, Entity, Kind,
- Sema::MultiExprArg(Self, (void **)&E, 1));
- if (Result.isInvalid())
- return true;
-
- E = Result.takeAs<Expr>();
- return false;
- }
-
- if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, Sema::AA_Converting))
+static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) {
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(T);
+ InitializationKind Kind = InitializationKind::CreateCopy(E->getLocStart(),
+ SourceLocation());
+ InitializationSequence InitSeq(Self, Entity, Kind, &E, 1);
+ Sema::OwningExprResult Result = InitSeq.Perform(Self, Entity, Kind,
+ Sema::MultiExprArg(Self, (void **)&E, 1));
+ if (Result.isInvalid())
return true;
+
+ E = Result.takeAs<Expr>();
return false;
}
@@ -2137,17 +2120,17 @@
// Otherwise, if the second and third operand have different types, and
// either has (cv) class type, and attempt is made to convert each of those
// operands to the other.
- if (Context.getCanonicalType(LTy) != Context.getCanonicalType(RTy) &&
+ if (!Context.hasSameType(LTy, RTy) &&
(LTy->isRecordType() || RTy->isRecordType())) {
ImplicitConversionSequence ICSLeftToRight, ICSRightToLeft;
// These return true if a single direction is already ambiguous.
- if (TryClassUnification(*this, LHS, RHS, QuestionLoc, ICSLeftToRight))
+ QualType L2RType, R2LType;
+ bool HaveL2R, HaveR2L;
+ if (TryClassUnification(*this, LHS, RHS, QuestionLoc, HaveL2R, L2RType))
return QualType();
- if (TryClassUnification(*this, RHS, LHS, QuestionLoc, ICSRightToLeft))
+ if (TryClassUnification(*this, RHS, LHS, QuestionLoc, HaveR2L, R2LType))
return QualType();
-
- bool HaveL2R = !ICSLeftToRight.isBad();
- bool HaveR2L = !ICSRightToLeft.isBad();
+
// If both can be converted, [...] the program is ill-formed.
if (HaveL2R && HaveR2L) {
Diag(QuestionLoc, diag::err_conditional_ambiguous)
@@ -2159,11 +2142,11 @@
// the chosen operand and the converted operands are used in place of the
// original operands for the remainder of this section.
if (HaveL2R) {
- if (ConvertForConditional(*this, LHS, ICSLeftToRight))
+ if (ConvertForConditional(*this, LHS, L2RType))
return QualType();
LTy = LHS->getType();
} else if (HaveR2L) {
- if (ConvertForConditional(*this, RHS, ICSRightToLeft))
+ if (ConvertForConditional(*this, RHS, R2LType))
return QualType();
RTy = RHS->getType();
}
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=99647&r1=99646&r2=99647&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Fri Mar 26 15:14:36 2010
@@ -2001,6 +2001,40 @@
}
}
+bool InitializationSequence::isDirectReferenceBinding() const {
+ return getKind() == ReferenceBinding && Steps.back().Kind == SK_BindReference;
+}
+
+bool InitializationSequence::isAmbiguous() const {
+ if (getKind() != FailedSequence)
+ return false;
+
+ switch (getFailureKind()) {
+ case FK_TooManyInitsForReference:
+ case FK_ArrayNeedsInitList:
+ case FK_ArrayNeedsInitListOrStringLiteral:
+ case FK_AddressOfOverloadFailed: // FIXME: Could do better
+ case FK_NonConstLValueReferenceBindingToTemporary:
+ case FK_NonConstLValueReferenceBindingToUnrelated:
+ case FK_RValueReferenceBindingToLValue:
+ case FK_ReferenceInitDropsQualifiers:
+ case FK_ReferenceInitFailed:
+ case FK_ConversionFailed:
+ case FK_TooManyInitsForScalar:
+ case FK_ReferenceBindingToInitList:
+ case FK_InitListBadDestinationType:
+ case FK_DefaultInitOfConst:
+ return false;
+
+ case FK_ReferenceInitOverloadFailed:
+ case FK_UserConversionOverloadFailed:
+ case FK_ConstructorOverloadFailed:
+ return FailedOverloadResult == OR_Ambiguous;
+ }
+
+ return false;
+}
+
void InitializationSequence::AddAddressOverloadResolutionStep(
FunctionDecl *Function) {
Step S;
Modified: cfe/trunk/lib/Sema/SemaInit.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.h?rev=99647&r1=99646&r2=99647&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.h (original)
+++ cfe/trunk/lib/Sema/SemaInit.h Fri Mar 26 15:14:36 2010
@@ -599,6 +599,13 @@
step_iterator step_begin() const { return Steps.begin(); }
step_iterator step_end() const { return Steps.end(); }
+ /// \brief Determine whether this initialization is a direct reference
+ /// binding (C++ [dcl.init.ref]).
+ bool isDirectReferenceBinding() const;
+
+ /// \brief Determine whether this initialization failed due to an ambiguity.
+ bool isAmbiguous() const;
+
/// \brief Add a new step in the initialization that resolves the address
/// of an overloaded function to a specific function declaration.
///
Modified: cfe/trunk/test/SemaCXX/conditional-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conditional-expr.cpp?rev=99647&r1=99646&r2=99647&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/conditional-expr.cpp (original)
+++ cfe/trunk/test/SemaCXX/conditional-expr.cpp Fri Mar 26 15:14:36 2010
@@ -7,7 +7,8 @@
struct ToBool { explicit operator bool(); };
struct B;
-struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}}
+struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}} \
+ // expected-note 2 {{candidate is the implicit copy constructor}}
struct B { operator A() const; }; // expected-note 2 {{candidate function}}
struct I { operator int(); };
struct J { operator I(); };
More information about the cfe-commits
mailing list