/// - *e, the type of e cannot be a function type
/// - string-constant
/// - reference type [C++ [expr]]
+ /// - b ? x : y, where x and y are lvalues of suitable types [C++]
///
enum isLvalueResult {
LV_Valid,
case CXXTypeidExprClass:
// C++ 5.2.8p1: The result of a typeid expression is an lvalue of ...
return LV_Valid;
+ case ConditionalOperatorClass: {
+ // Complicated handling is only for C++.
+ if (!Ctx.getLangOptions().CPlusPlus)
+ return LV_InvalidExpression;
+
+ // Sema should have taken care to ensure that a CXXTemporaryObjectExpr is
+ // everywhere there's an object converted to an rvalue. Also, any other
+ // casts should be wrapped by ImplicitCastExprs. There's just the special
+ // case involving throws to work out.
+ const ConditionalOperator *Cond = cast<ConditionalOperator>(this);
+ Expr *LHS = Cond->getLHS();
+ Expr *RHS = Cond->getRHS();
+ // C++0x 5.16p2
+ // If either the second or the third operand has type (cv) void, [...]
+ // the result [...] is an rvalue.
+ if (LHS->getType()->isVoidType() || RHS->getType()->isVoidType())
+ return LV_InvalidExpression;
+
+ // Both sides must be lvalues for the result to be an lvalue.
+ if (LHS->isLvalue(Ctx) != LV_Valid || RHS->isLvalue(Ctx) != LV_Valid)
+ return LV_InvalidExpression;
+
+ // That's it.
+ return LV_Valid;
+ }
+
default:
break;
}
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
ICS->Standard.ReferenceBinding = true;
ICS->Standard.DirectBinding = false;
ICS->Standard.RRefBinding = isRValRef;
+ ICS->Standard.CopyConstructor = 0;
} else {
// FIXME: Binding to a subobject of the rvalue is going to require
// more AST annotation than this.
return true;
}
+/// \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.ConversionKind == ImplicitConversionSequence::StandardConversion &&
+ ICS.Standard.ReferenceBinding) {
+ assert(ICS.Standard.DirectBinding &&
+ "TryClassUnification should never generate indirect ref bindings");
+ Self.ImpCastExprToType(E, TargetType(ICS), true);
+ return false;
+ }
+ if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion &&
+ ICS.UserDefined.After.ReferenceBinding) {
+ assert(ICS.UserDefined.After.DirectBinding &&
+ "TryClassUnification should never generate indirect ref bindings");
+ Self.ImpCastExprToType(E, TargetType(ICS), true);
+ return false;
+ }
+ if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, "converting"))
+ return true;
+ return false;
+}
+
/// \brief Check the operands of ?: under C++ semantics.
///
/// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y
// the chosen operand and the converted operands are used in place of the
// original operands for the remainder of this section.
if (HaveL2R) {
- if (PerformImplicitConversion(LHS, TargetType(ICSLeftToRight),
- ICSLeftToRight, "converting"))
+ if (ConvertForConditional(*this, LHS, ICSLeftToRight))
return QualType();
LTy = LHS->getType();
} else if (HaveR2L) {
- if (PerformImplicitConversion(RHS, TargetType(ICSRightToLeft),
- ICSRightToLeft, "converting"))
+ if (ConvertForConditional(*this, RHS, ICSRightToLeft))
return QualType();
RTy = RHS->getType();
}
struct Base {
int trick();
A trick() const;
+ void fn1();
+};
+struct Derived : Base {
+ void fn2();
};
-struct Derived : Base {};
struct Convertible { operator Base&(); };
struct Priv : private Base {};
struct Mid : Base {};
struct Fin : Mid, Derived {};
+typedef void (Derived::*DFnPtr)();
+struct ToMemPtr { operator DFnPtr(); };
struct BadDerived;
struct BadBase { operator BadDerived&(); };
Base base;
Derived derived;
Convertible conv;
- // FIXME: lvalueness
- /*Base &bar1 =*/(void)( i1 ? base : derived);
- /*Base &bar2 =*/(void)( i1 ? derived : base);
- /*Base &bar3 =*/(void)( i1 ? base : conv);
- /*Base &bar4 =*/(void)( i1 ? conv : base);
+ Base &bar1 = i1 ? base : derived;
+ Base &bar2 = i1 ? derived : base;
+ Base &bar3 = i1 ? base : conv;
+ Base &bar4 = i1 ? conv : base;
// these are ambiguous
BadBase bb;
BadDerived bd;
// should fail: const lost
(void)(i1 ? Base() : constder()); // expected-error {{incompatible operand types ('struct Base' and 'struct Derived const')}}
(void)(i1 ? constder() : Base()); // expected-error {{incompatible operand types ('struct Derived const' and 'struct Base')}}
- // should fail: private or ambiguous base
+ // FIXME: should fail: private or ambiguous base
(void)(i1 ? Base() : Priv()); // xpected-error private base
(void)(i1 ? Priv() : Base()); // xpected-error private base
(void)(i1 ? Base() : Fin()); // xpected-error ambiguous base
(void)(i1 ? B() : A()); // expected-error {{incompatible operand types}}
(void)(i1 ? 1 : Ambig()); // expected-error {{incompatible operand types}}
(void)(i1 ? Ambig() : 1); // expected-error {{incompatible operand types}}
+ // By the way, this isn't an lvalue:
+ &(i1 ? i1 : i2); // expected-error {{address expression must be an lvalue or a function designator}}
// p4 (lvalue, same type)
- //Fields flds;
- int &ir1 = i1;
- //int &ir1 = i1 ? flds.i1 : flds.i2;
- //(i1 ? flds.b1 : flds.i2) = 0;
- //(i1 ? flds.i1 : flds.b2) = 0;
- //(i1 ? flds.b1 : flds.b2) = 0;
+ Fields flds;
+ int &ir1 = i1 ? flds.i1 : flds.i2;
+ (i1 ? flds.b1 : flds.i2) = 0;
+ (i1 ? flds.i1 : flds.b2) = 0;
+ (i1 ? flds.b1 : flds.b2) = 0;
// p5 (conversion to built-in types)
// GCC 4.3 fails these
double d1 = i1 ? I() : K();
pfn = i1 ? F() : G();
+ DFnPtr pfm;
+ // FIXME: Overload resolution won't choose the member pointer yet.
+ //pfm = i1 ? DFnPtr() : &Base::fn1;
+ //pfm = i1 ? &Base::fn1 : DFnPtr();
// p6 (final conversions)
i1 = i1 ? i1 : ir1;
i1 = i1 ? EVal : i1;
d1 = i1 ? 'c' : 4.0;
d1 = i1 ? 4.0 : 'c';
+ pfm = i1 ? &Derived::fn2 : 0;
+ pfm = i1 ? 0 : &Derived::fn2;
+ // FIXME: pointer conversions don't work yet.
+ //Base *pb = i1 ? (Base*)0 : (Derived*)0;
+ //Base *pb = i1 ? (Derived*)0 : (Base*)0;
+ //pfm = i1 ? &Base::fn1 : &Derived::fn2;
+ //pfm = i1 ? &Derived::fn2 : &Base::fn1;
+ // Conversion of primitives does not result in an lvalue.
+ &(i1 ? i1 : d1); // expected-error {{address expression must be an lvalue or a function designator}}
+
// Note the thing that this does not test: since DR446, various situations
// *must* create a separate temporary copy of class objects. This can only