diff options
author | John McCall <rjmccall@apple.com> | 2010-12-04 03:47:34 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-12-04 03:47:34 +0000 |
commit | f6a1648197562e0b133440d612d9af297d0a86cc (patch) | |
tree | 10c1ff179182b53e5f8eb356b7fe1ace0c7dab41 /lib/Sema | |
parent | e68b9842d2d6adc2c72c81c845a2c68e58d9d3a4 (diff) |
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
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaCXXCast.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 163 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 62 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 17 |
7 files changed, 194 insertions, 73 deletions
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 214d1f6175..ac679f7009 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -516,6 +516,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (DestType->isVoidType()) { + Self.IgnoredValueConversions(SrcExpr); Kind = CK_ToVoid; return; } @@ -1371,6 +1372,7 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (CastTy->isVoidType()) { + IgnoredValueConversions(CastExpr); Kind = CK_ToVoid; return false; } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 46c5967e5b..d6aa4ce885 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -2104,8 +2104,8 @@ do { void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) { bool EmitWarning = true; - Expr* LeftExprSansParen = lex->IgnoreParens(); - Expr* RightExprSansParen = rex->IgnoreParens(); + Expr* LeftExprSansParen = lex->IgnoreParenImpCasts(); + Expr* RightExprSansParen = rex->IgnoreParenImpCasts(); // Special case: check for x == x (which is OK). // Do not emit warnings for such cases. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 177d61cc82..8b29667bae 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -251,6 +251,24 @@ void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) { // 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 @@ void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) { // 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 @@ static QualType CheckRealImagOperand(Sema &S, Expr *&V, SourceLocation Loc, 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 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, 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 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, // 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 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // 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 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // 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 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, 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 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, // 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 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // 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 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, // 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 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, 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 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, } // 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 @@ static QualType CheckCommaOperands(Sema &S, Expr *LHS, Expr *&RHS, // 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 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, } } -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 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, 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 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, 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 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, 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 @@ bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { 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; diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index fceb542c79..965328615d 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1845,10 +1845,21 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // Perform the first implicit conversion. switch (SCS.First) { case ICK_Identity: - case ICK_Lvalue_To_Rvalue: // Nothing to do. break; + case ICK_Lvalue_To_Rvalue: + // Should this get its own ICK? + if (From->getObjectKind() == OK_ObjCProperty) { + ConvertPropertyForRValue(From); + if (!From->isRValue()) break; + } + + FromType = FromType.getUnqualifiedType(); + From = ImplicitCastExpr::Create(Context, FromType, CK_LValueToRValue, + From, 0, VK_RValue); + break; + case ICK_Array_To_Pointer: FromType = Context.getArrayDecayedType(FromType); ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay); @@ -2746,14 +2757,14 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // The operands have class type. Make a temporary copy. InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); ExprResult LHSCopy = PerformCopyInitialization(Entity, - SourceLocation(), - Owned(LHS)); + SourceLocation(), + Owned(LHS)); if (LHSCopy.isInvalid()) return QualType(); ExprResult RHSCopy = PerformCopyInitialization(Entity, - SourceLocation(), - Owned(RHS)); + SourceLocation(), + Owned(RHS)); if (RHSCopy.isInvalid()) return QualType(); @@ -3512,21 +3523,42 @@ ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation, return BuildCXXNoexceptExpr(KeyLoc, Operand, RParen); } -ExprResult Sema::ActOnFinishFullExpr(Expr *FullExpr) { - if (!FullExpr) return ExprError(); - +/// Perform the conversions required for an expression used in a +/// context that ignores the result. +void Sema::IgnoredValueConversions(Expr *&E) { // C99 6.3.2.1: // [Except in specific positions,] an lvalue that does not have // array type is converted to the value stored in the // designated object (and is no longer an lvalue). - // This rule does not apply in C++; however, in ObjC++, we do want - // to do lvalue-to-rvalue conversion on top-level ObjCProperty - // l-values. - if (!FullExpr->isRValue() && - (!getLangOptions().CPlusPlus || - FullExpr->getObjectKind() == OK_ObjCProperty)) - DefaultFunctionArrayLvalueConversion(FullExpr); + if (E->isRValue()) return; + + // We always want to do this on ObjC property references. + if (E->getObjectKind() == OK_ObjCProperty) { + ConvertPropertyForRValue(E); + if (E->isRValue()) return; + } + + // Otherwise, this rule does not apply in C++, at least not for the moment. + if (getLangOptions().CPlusPlus) return; + + // GCC seems to also exclude expressions of incomplete enum type. + if (const EnumType *T = E->getType()->getAs<EnumType>()) { + if (!T->getDecl()->isComplete()) { + // FIXME: stupid workaround for a codegen bug! + ImpCastExprToType(E, Context.VoidTy, CK_ToVoid); + return; + } + } + + DefaultFunctionArrayLvalueConversion(E); + RequireCompleteType(E->getExprLoc(), E->getType(), + diag::err_incomplete_type); +} + +ExprResult Sema::ActOnFinishFullExpr(Expr *FullExpr) { + if (!FullExpr) return ExprError(); + IgnoredValueConversions(FullExpr); CheckImplicitConversions(FullExpr); return MaybeCreateCXXExprWithTemporaries(FullExpr); } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index e60aa071e2..d63b228f36 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -284,6 +284,9 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, } bool Sema::isSelfExpr(Expr *RExpr) { + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RExpr)) + if (ICE->getCastKind() == CK_LValueToRValue) + RExpr = ICE->getSubExpr(); if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RExpr)) if (DRE->getDecl()->getIdentifier() == &Context.Idents.get("self")) return true; diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 26826aa87b..d7048a129f 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -3627,12 +3627,18 @@ InitializationSequence::Perform(Sema &S, case SK_ListInitialization: case SK_CAssignment: case SK_StringInit: - case SK_ObjCObjectConversion: + case SK_ObjCObjectConversion: { assert(Args.size() == 1); - CurInit = ExprResult(Args.get()[0]); - if (CurInit.isInvalid()) - return ExprError(); + Expr *CurInitExpr = Args.get()[0]; + if (!CurInitExpr) return ExprError(); + + // Read from a property when initializing something with it. + if (CurInitExpr->getObjectKind() == OK_ObjCProperty) + S.ConvertPropertyForRValue(CurInitExpr); + + CurInit = ExprResult(CurInitExpr); break; + } case SK_ConstructorInitialization: case SK_ZeroInitialization: @@ -3647,7 +3653,7 @@ InitializationSequence::Perform(Sema &S, if (CurInit.isInvalid()) return ExprError(); - Expr *CurInitExpr = (Expr *)CurInit.get(); + Expr *CurInitExpr = CurInit.get(); QualType SourceType = CurInitExpr? CurInitExpr->getType() : QualType(); switch (Step->Kind) { diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 7fa555e4f9..7ab30d1621 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -92,7 +92,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (const CXXExprWithTemporaries *Temps = dyn_cast<CXXExprWithTemporaries>(E)) E = Temps->getSubExpr(); - E = E->IgnoreParens(); + E = E->IgnoreParenImpCasts(); if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { if (E->getType()->isVoidType()) return; @@ -952,6 +952,17 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, RParenLoc)); } +/// In an Objective C collection iteration statement: +/// for (x in y) +/// x can be an arbitrary l-value expression. Bind it up as a +/// full-expression. +StmtResult Sema::ActOnForEachLValueExpr(Expr *E) { + CheckImplicitConversions(E); + ExprResult Result = MaybeCreateCXXExprWithTemporaries(E); + if (Result.isInvalid()) return StmtError(); + return Owned(static_cast<Stmt*>(Result.get())); +} + StmtResult Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, SourceLocation LParenLoc, @@ -1228,6 +1239,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { unsigned D = diag::ext_return_has_expr; if (RetValExp->getType()->isVoidType()) D = diag::ext_return_has_void_expr; + else { + IgnoredValueConversions(RetValExp); + ImpCastExprToType(RetValExp, Context.VoidTy, CK_ToVoid); + } // return (some void expression); is legal in C++. if (D != diag::ext_return_has_void_expr || |