Although we currently have explicit lvalue-to-rvalue conversions, they're
not actually frequently used, because ImpCastExprToType only creates a node
if the types differ. So explicitly create an ICE in the lvalue-to-rvalue
conversion code in DefaultFunctionArrayLvalueConversion() as well as several
other new places, and consistently deal with the consequences throughout the
compiler.
In addition, introduce a new cast kind for loading an ObjCProperty l-value,
and make sure we emit those nodes whenever an ObjCProperty l-value appears
that's not on the LHS of an assignment operator.
This breaks a couple of rewriter tests, which I've x-failed until future
development occurs on the rewriter.
Ted Kremenek kindly contributed the analyzer workarounds in this patch.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@120890 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 177d61c..8b29667 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -251,6 +251,24 @@
// A glvalue of a non-function, non-array type T can be
// converted to a prvalue.
if (E->isGLValue()) {
+ QualType T = E->getType();
+ assert(!T.isNull() && "r-value conversion on typeless expression?");
+
+ // Create a load out of an ObjCProperty l-value, if necessary.
+ if (E->getObjectKind() == OK_ObjCProperty) {
+ ConvertPropertyForRValue(E);
+ if (!E->isGLValue())
+ return;
+ }
+
+ // We don't want to throw lvalue-to-rvalue casts on top of
+ // expressions of certain types in C++.
+ if (getLangOptions().CPlusPlus &&
+ (E->getType() == Context.OverloadTy ||
+ T->isDependentType() ||
+ T->isRecordType()))
+ return;
+
// C++ [conv.lval]p1:
// [...] If T is a non-class type, the type of the prvalue is the
// cv-unqualified version of T. Otherwise, the type of the
@@ -259,15 +277,12 @@
// C99 6.3.2.1p2:
// If the lvalue has qualified type, the value has the unqualified
// version of the type of the lvalue; otherwise, the value has the
- // type of the lvalue.
- QualType T = E->getType();
- assert(!T.isNull() && "r-value conversion on typeless expression?");
-
- if (T.hasQualifiers() && !T->isDependentType() &&
- (!getLangOptions().CPlusPlus || !T->isRecordType()))
+ // type of the lvalue.
+ if (T.hasQualifiers())
T = T.getUnqualifiedType();
-
- ImpCastExprToType(E, T, CK_LValueToRValue);
+
+ E = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
+ E, 0, VK_RValue);
}
}
@@ -2649,6 +2664,10 @@
if (V->isTypeDependent())
return S.Context.DependentTy;
+ // _Real and _Imag are only l-values for normal l-values.
+ if (V->getObjectKind() != OK_Ordinary)
+ S.DefaultFunctionArrayLvalueConversion(V);
+
// These operators return the element type of a complex type.
if (const ComplexType *CT = V->getType()->getAs<ComplexType>())
return CT->getElementType();
@@ -3351,6 +3370,11 @@
return ExprError();
}
+ // Perform a property load on the base regardless of whether we
+ // actually need it for the declaration.
+ if (BaseExpr->getObjectKind() == OK_ObjCProperty)
+ ConvertPropertyForRValue(BaseExpr);
+
if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow,
SS, FD, FoundDecl, MemberNameInfo);
@@ -3359,7 +3383,7 @@
// We may have found a field within an anonymous union or struct
// (C++ [class.union]).
return BuildAnonymousStructUnionMemberReference(MemberLoc, FD,
- BaseExpr, OpLoc);
+ BaseExpr, OpLoc);
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, Var);
@@ -3694,6 +3718,10 @@
// Handle properties on 'id' and qualified "id".
if (!IsArrow && (BaseType->isObjCIdType() ||
BaseType->isObjCQualifiedIdType())) {
+ // This actually uses the base as an r-value.
+ DefaultFunctionArrayLvalueConversion(BaseExpr);
+ assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr->getType()));
+
const ObjCObjectPointerType *QIdTy = BaseType->getAs<ObjCObjectPointerType>();
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
@@ -3743,9 +3771,12 @@
// pointer to a (potentially qualified) interface type.
if (!IsArrow)
if (const ObjCObjectPointerType *OPT =
- BaseType->getAsObjCInterfacePointerType())
+ BaseType->getAsObjCInterfacePointerType()) {
+ // This actually uses the base as an r-value.
+ DefaultFunctionArrayLvalueConversion(BaseExpr);
return HandleExprPropertyRefExpr(OPT, BaseExpr, MemberName, MemberLoc,
SourceLocation(), QualType(), false);
+ }
// Handle the following exceptional case (*Obj).isa.
if (!IsArrow &&
@@ -4024,8 +4055,8 @@
Param? InitializedEntity::InitializeParameter(Context, Param)
: InitializedEntity::InitializeParameter(Context, ProtoArgType);
ExprResult ArgE = PerformCopyInitialization(Entity,
- SourceLocation(),
- Owned(Arg));
+ SourceLocation(),
+ Owned(Arg));
if (ArgE.isInvalid())
return true;
@@ -4532,16 +4563,19 @@
// We only support r-value casts in C.
VK = VK_RValue;
- DefaultFunctionArrayLvalueConversion(castExpr);
-
// C99 6.5.4p2: the cast type needs to be void or scalar and the expression
// type needs to be scalar.
if (castType->isVoidType()) {
+ // We don't necessarily do lvalue-to-rvalue conversions on this.
+ IgnoredValueConversions(castExpr);
+
// Cast to void allows any expr type.
Kind = CK_ToVoid;
return false;
}
+ DefaultFunctionArrayLvalueConversion(castExpr);
+
if (RequireCompleteType(TyR.getBegin(), castType,
diag::err_typecheck_cast_to_incomplete))
return true;
@@ -5713,7 +5747,7 @@
// FIXME: Currently, we fall through and treat C++ classes like C
// structures.
- }
+ }
// C99 6.5.16.1p1: the left operand is a pointer and the right is
// a null pointer constant.
@@ -6201,8 +6235,8 @@
// obvious cases in the definition of the template anyways. The idea is to
// warn when the typed comparison operator will always evaluate to the same
// result.
- Expr *LHSStripped = lex->IgnoreParens();
- Expr *RHSStripped = rex->IgnoreParens();
+ Expr *LHSStripped = lex->IgnoreParenImpCasts();
+ Expr *RHSStripped = rex->IgnoreParenImpCasts();
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHSStripped)) {
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped)) {
if (DRL->getDecl() == DRR->getDecl() &&
@@ -6782,7 +6816,8 @@
if (CompoundType.isNull()) {
QualType LHSTy(LHSType);
// Simple assignment "x = y".
- ConvertPropertyAssignment(LHS, RHS, LHSTy);
+ if (LHS->getObjectKind() == OK_ObjCProperty)
+ ConvertPropertyForLValue(LHS, RHS, LHSTy);
ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
// Special case of NSObject attributes on c-style pointer types.
if (ConvTy == IncompatiblePointer &&
@@ -6857,7 +6892,7 @@
}
// C99 6.5.17
-static QualType CheckCommaOperands(Sema &S, Expr *LHS, Expr *&RHS,
+static QualType CheckCommaOperands(Sema &S, Expr *&LHS, Expr *&RHS,
SourceLocation Loc) {
S.DiagnoseUnusedExprResult(LHS);
@@ -6873,11 +6908,12 @@
// C's comma performs lvalue conversion (C99 6.3.2.1) on both its
// operands, but not unary promotions.
// C++'s comma does not do any conversions at all (C++ [expr.comma]p1).
- if (!S.getLangOptions().CPlusPlus) {
- S.DefaultFunctionArrayLvalueConversion(LHS);
- if (!LHS->getType()->isVoidType())
- S.RequireCompleteType(Loc, LHS->getType(), diag::err_incomplete_type);
+ // So we treat the LHS as a ignored value, and in C++ we allow the
+ // containing site to determine what should be done with the RHS.
+ S.IgnoredValueConversions(LHS);
+
+ if (!S.getLangOptions().CPlusPlus) {
S.DefaultFunctionArrayLvalueConversion(RHS);
if (!RHS->getType()->isVoidType())
S.RequireCompleteType(Loc, RHS->getType(), diag::err_incomplete_type);
@@ -6971,21 +7007,47 @@
}
}
-void Sema::ConvertPropertyAssignment(Expr *LHS, Expr *&RHS, QualType& LHSTy) {
- bool copyInit = false;
- if (const ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
- if (PRE->isImplicitProperty()) {
- // If using property-dot syntax notation for assignment, and there is a
- // setter, RHS expression is being passed to the setter argument. So,
- // type conversion (and comparison) is RHS to setter's argument type.
- if (const ObjCMethodDecl *SetterMD = PRE->getImplicitPropertySetter()) {
- ObjCMethodDecl::param_iterator P = SetterMD->param_begin();
- LHSTy = (*P)->getType();
+void Sema::ConvertPropertyForRValue(Expr *&E) {
+ assert(E->getValueKind() == VK_LValue &&
+ E->getObjectKind() == OK_ObjCProperty);
+ const ObjCPropertyRefExpr *PRE = E->getObjCProperty();
+
+ ExprValueKind VK = VK_RValue;
+ if (PRE->isImplicitProperty()) {
+ QualType Result = PRE->getImplicitPropertyGetter()->getResultType();
+ VK = Expr::getValueKindForType(Result);
+ }
+
+ E = ImplicitCastExpr::Create(Context, E->getType(), CK_GetObjCProperty,
+ E, 0, VK);
+}
+
+void Sema::ConvertPropertyForLValue(Expr *&LHS, Expr *&RHS, QualType &LHSTy) {
+ assert(LHS->getValueKind() == VK_LValue &&
+ LHS->getObjectKind() == OK_ObjCProperty);
+ const ObjCPropertyRefExpr *PRE = LHS->getObjCProperty();
+
+ if (PRE->isImplicitProperty()) {
+ // If using property-dot syntax notation for assignment, and there is a
+ // setter, RHS expression is being passed to the setter argument. So,
+ // type conversion (and comparison) is RHS to setter's argument type.
+ if (const ObjCMethodDecl *SetterMD = PRE->getImplicitPropertySetter()) {
+ ObjCMethodDecl::param_iterator P = SetterMD->param_begin();
+ LHSTy = (*P)->getType();
+
+ // Otherwise, if the getter returns an l-value, just call that.
+ } else {
+ QualType Result = PRE->getImplicitPropertyGetter()->getResultType();
+ ExprValueKind VK = Expr::getValueKindForType(Result);
+ if (VK == VK_LValue) {
+ LHS = ImplicitCastExpr::Create(Context, LHS->getType(),
+ CK_GetObjCProperty, LHS, 0, VK);
+ return;
}
}
- copyInit = (getLangOptions().CPlusPlus && LHSTy->isRecordType());
- }
- if (copyInit) {
+ }
+
+ if (getLangOptions().CPlusPlus && LHSTy->isRecordType()) {
InitializedEntity Entity =
InitializedEntity::InitializeParameter(Context, LHSTy);
Expr *Arg = RHS;
@@ -7318,7 +7380,8 @@
switch (Opc) {
case BO_Assign:
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, QualType());
- if (getLangOptions().CPlusPlus) {
+ if (getLangOptions().CPlusPlus &&
+ lhs->getObjectKind() != OK_ObjCProperty) {
VK = lhs->getValueKind();
OK = lhs->getObjectKind();
}
@@ -7418,7 +7481,7 @@
return Owned(new (Context) BinaryOperator(lhs, rhs, Opc, ResultTy,
VK, OK, OpLoc));
- if (getLangOptions().CPlusPlus) {
+ if (getLangOptions().CPlusPlus && lhs->getObjectKind() != OK_ObjCProperty) {
VK = VK_LValue;
OK = lhs->getObjectKind();
}
@@ -7824,8 +7887,11 @@
LastStmt = Label->getSubStmt();
}
if (Expr *LastExpr = dyn_cast<Expr>(LastStmt)) {
- DefaultFunctionArrayLvalueConversion(LastExpr);
- Ty = LastExpr->getType();
+ // Do function/array conversion on the last expression, but not
+ // lvalue-to-rvalue. However, initialize an unqualified type.
+ DefaultFunctionArrayConversion(LastExpr);
+ Ty = LastExpr->getType().getUnqualifiedType();
+
if (!Ty->isDependentType() && !LastExpr->isTypeDependent()) {
ExprResult Res = PerformCopyInitialization(
InitializedEntity::InitializeResult(LPLoc,
@@ -8971,18 +9037,15 @@
return Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func)
<< E->getSourceRange();
- DefaultFunctionArrayLvalueConversion(E);
-
QualType T = E->getType();
- if (getLangOptions().CPlusPlus) {
- if (CheckCXXBooleanCondition(E)) // C++ 6.4p4
- return true;
- } else if (!T->isScalarType()) { // C99 6.8.4.1p1
- Diag(Loc, diag::err_typecheck_statement_requires_scalar)
- << T << E->getSourceRange();
- return true;
- }
+ if (getLangOptions().CPlusPlus)
+ return CheckCXXBooleanCondition(E); // C++ 6.4p4
+
+ DefaultFunctionArrayLvalueConversion(E);
+ if (!T->isScalarType()) // C99 6.8.4.1p1
+ return Diag(Loc, diag::err_typecheck_statement_requires_scalar)
+ << T << E->getSourceRange();
}
return false;