From f6a1648197562e0b133440d612d9af297d0a86cc Mon Sep 17 00:00:00 2001 From: John McCall Date: Sat, 4 Dec 2010 03:47:34 +0000 Subject: [PATCH] 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 --- include/clang/AST/Expr.h | 14 ++ include/clang/AST/OperationKinds.h | 7 + include/clang/Sema/Sema.h | 9 +- lib/AST/Expr.cpp | 46 ++++- lib/AST/ExprClassification.cpp | 11 +- lib/Analysis/CFG.cpp | 21 ++- lib/Checker/CheckSecuritySyntaxOnly.cpp | 6 +- lib/Checker/DereferenceChecker.cpp | 1 + lib/Checker/Environment.cpp | 3 +- lib/Checker/GRExprEngine.cpp | 17 +- lib/Checker/IdempotentOperationChecker.cpp | 2 +- lib/CodeGen/CGExpr.cpp | 15 ++ lib/CodeGen/CGExprAgg.cpp | 15 +- lib/CodeGen/CGExprComplex.cpp | 17 +- lib/CodeGen/CGExprScalar.cpp | 18 +- lib/Parse/ParseStmt.cpp | 12 +- lib/Sema/SemaCXXCast.cpp | 2 + lib/Sema/SemaChecking.cpp | 4 +- lib/Sema/SemaExpr.cpp | 163 ++++++++++++------ lib/Sema/SemaExprCXX.cpp | 62 +++++-- lib/Sema/SemaExprObjC.cpp | 3 + lib/Sema/SemaInit.cpp | 16 +- lib/Sema/SemaStmt.cpp | 17 +- test/CodeGen/volatile-1.c | 12 +- test/CodeGenObjCXX/property-dot-reference.mm | 21 +++ test/Rewriter/properties.m | 4 + .../rewrite-nested-property-in-blocks.mm | 4 + .../rdr6094103-unordered-compare-promote.c | 2 +- test/SemaCXX/decl-expr-ambiguity.cpp | 4 +- test/SemaTemplate/enum-argument.cpp | 2 +- 30 files changed, 419 insertions(+), 111 deletions(-) diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 4babbc476b..217e99ee56 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -39,6 +39,7 @@ namespace clang { class CXXBaseSpecifier; class CXXOperatorCallExpr; class CXXMemberCallExpr; + class ObjCPropertyRefExpr; class TemplateArgumentLoc; class TemplateArgumentListInfo; @@ -312,6 +313,10 @@ public: return const_cast(this)->getBitField(); } + /// \brief If this expression is an l-value for an Objective C + /// property, find the underlying property reference expression. + const ObjCPropertyRefExpr *getObjCProperty() const; + /// \brief Returns whether this expression refers to a vector element. bool refersToVectorElement() const; @@ -456,6 +461,14 @@ public: const Expr *IgnoreParenImpCasts() const { return const_cast(this)->IgnoreParenImpCasts(); } + + /// Ignore parentheses and lvalue casts. Strip off any ParenExpr and + /// CastExprs that represent lvalue casts, returning their operand. + Expr *IgnoreParenLValueCasts(); + + const Expr *IgnoreParenLValueCasts() const { + return const_cast(this)->IgnoreParenLValueCasts(); + } /// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the /// value (including ptr->int casts of the same size). Strip off any @@ -2056,6 +2069,7 @@ private: case CK_Dependent: case CK_LValueToRValue: + case CK_GetObjCProperty: case CK_NoOp: case CK_PointerToBoolean: case CK_IntegralToBoolean: diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h index 2ced0c9c71..35c72c45ce 100644 --- a/include/clang/AST/OperationKinds.h +++ b/include/clang/AST/OperationKinds.h @@ -48,6 +48,13 @@ enum CastKind { /// an r-value from the operand gl-value. The result of an r-value /// conversion is always unqualified. CK_LValueToRValue, + + /// CK_GetObjCProperty - A conversion which calls an Objective-C + /// property getter. The operand is an OK_ObjCProperty l-value; the + /// result will generally be an r-value, but could be an ordinary + /// gl-value if the property reference is to an implicit property + /// for a method that returns a reference type. + CK_GetObjCProperty, /// CK_NoOp - A conversion which does not affect the type other than /// (possibly) adding qualifiers. diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 93b5884d91..65ba72e3b1 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1579,6 +1579,7 @@ public: SourceLocation StartLoc, SourceLocation EndLoc); void ActOnForEachDeclStmt(DeclGroupPtrTy Decl); + StmtResult ActOnForEachLValueExpr(Expr *E); StmtResult ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, SourceLocation DotDotDotLoc, Expr *RHSVal, SourceLocation ColonLoc); @@ -3984,6 +3985,11 @@ public: ExprValueKind VK = VK_RValue, const CXXCastPath *BasePath = 0); + /// IgnoredValueConversions - Given that an expression's result is + /// syntactically ignored, perform any conversions that are + /// required. + void IgnoredValueConversions(Expr *&expr); + // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts // functions and arrays to their respective pointers (C99 6.3.2.1). Expr *UsualUnaryConversions(Expr *&expr); @@ -4190,7 +4196,8 @@ public: QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] Expr *lex, Expr *&rex, SourceLocation OpLoc, QualType convertedType); - void ConvertPropertyAssignment(Expr *LHS, Expr *&RHS, QualType& LHSTy); + void ConvertPropertyForRValue(Expr *&E); + void ConvertPropertyForLValue(Expr *&LHS, Expr *&RHS, QualType& LHSTy); QualType CheckConditionalOperands( // C99 6.5.15 Expr *&cond, Expr *&lhs, Expr *&rhs, Expr *&save, diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 265788a081..fbc5a67af1 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -824,6 +824,8 @@ const char *CastExpr::getCastKindName() const { return "LValueBitCast"; case CK_LValueToRValue: return "LValueToRValue"; + case CK_GetObjCProperty: + return "GetObjCProperty"; case CK_NoOp: return "NoOp"; case CK_BaseToDerived: @@ -1722,6 +1724,24 @@ Expr *Expr::IgnoreParenCasts() { } } +Expr *Expr::IgnoreParenLValueCasts() { + Expr *E = this; + while (E) { + if (ParenExpr *P = dyn_cast(E)) { + E = P->getSubExpr(); + continue; + } + if (CastExpr *P = dyn_cast(E)) { + if (P->getCastKind() == CK_LValueToRValue) { + E = P->getSubExpr(); + continue; + } + } + break; + } + return E; +} + Expr *Expr::IgnoreParenImpCasts() { Expr *E = this; while (true) { @@ -2043,12 +2063,34 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx, return isIntegerConstantExpr(Result, Ctx) && Result == 0; } +/// \brief If this expression is an l-value for an Objective C +/// property, find the underlying property reference expression. +const ObjCPropertyRefExpr *Expr::getObjCProperty() const { + const Expr *E = this; + while (true) { + assert((E->getValueKind() == VK_LValue && + E->getObjectKind() == OK_ObjCProperty) && + "expression is not a property reference"); + E = E->IgnoreParenCasts(); + if (const BinaryOperator *BO = dyn_cast(E)) { + if (BO->getOpcode() == BO_Comma) { + E = BO->getRHS(); + continue; + } + } + + break; + } + + return cast(E); +} + FieldDecl *Expr::getBitField() { Expr *E = this->IgnoreParens(); while (ImplicitCastExpr *ICE = dyn_cast(E)) { - if (ICE->getValueKind() != VK_RValue && - ICE->getCastKind() == CK_NoOp) + if (ICE->getCastKind() == CK_LValueToRValue || + (ICE->getValueKind() != VK_RValue && ICE->getCastKind() == CK_NoOp)) E = ICE->getSubExpr()->IgnoreParens(); else break; diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index e55545e693..1afc7602fb 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -413,8 +413,10 @@ static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) { assert(Ctx.getLangOptions().CPlusPlus && "This is only relevant for C++."); // C++ [expr.ass]p1: All [...] return an lvalue referring to the left operand. + // Except we override this for writes to ObjC properties. if (E->isAssignmentOp()) - return Cl::CL_LValue; + return (E->getLHS()->getObjectKind() == OK_ObjCProperty + ? Cl::CL_PRValue : Cl::CL_LValue); // C++ [expr.comma]p1: the result is of the same value category as its right // operand, [...]. @@ -468,9 +470,10 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, if (Kind == Cl::CL_PRValue) { // For the sake of better diagnostics, we want to specifically recognize // use of the GCC cast-as-lvalue extension. - if (const CStyleCastExpr *CE = dyn_cast(E->IgnoreParens())){ - if (CE->getSubExpr()->Classify(Ctx).isLValue()) { - Loc = CE->getLParenLoc(); + if (const ExplicitCastExpr *CE = + dyn_cast(E->IgnoreParens())) { + if (CE->getSubExpr()->IgnoreParenImpCasts()->isLValue()) { + Loc = CE->getExprLoc(); return Cl::CM_LValueCast; } } diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 57e67e4268..b382d9be58 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -825,6 +825,16 @@ tryAgain: case Stmt::ContinueStmtClass: return VisitContinueStmt(cast(S)); + + case Stmt::CStyleCastExprClass: { + CastExpr *castExpr = cast(S); + if (castExpr->getCastKind() == CK_LValueToRValue) { + // temporary workaround + S = castExpr->getSubExpr(); + goto tryAgain; + } + return VisitStmt(S, asc); + } case Stmt::CXXCatchStmtClass: return VisitCXXCatchStmt(cast(S)); @@ -871,8 +881,15 @@ tryAgain: case Stmt::IfStmtClass: return VisitIfStmt(cast(S)); - case Stmt::ImplicitCastExprClass: - return VisitImplicitCastExpr(cast(S), asc); + case Stmt::ImplicitCastExprClass: { + ImplicitCastExpr *castExpr = cast(S); + if (castExpr->getCastKind() == CK_LValueToRValue) { + // temporary workaround + S = castExpr->getSubExpr(); + goto tryAgain; + } + return VisitImplicitCastExpr(castExpr, asc); + } case Stmt::IndirectGotoStmtClass: return VisitIndirectGotoStmt(cast(S)); diff --git a/lib/Checker/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp index 9a2ac45fa2..0223240ce6 100644 --- a/lib/Checker/CheckSecuritySyntaxOnly.cpp +++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp @@ -187,8 +187,10 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) { return; // Are we comparing variables? - const DeclRefExpr *drLHS = dyn_cast(B->getLHS()->IgnoreParens()); - const DeclRefExpr *drRHS = dyn_cast(B->getRHS()->IgnoreParens()); + const DeclRefExpr *drLHS = + dyn_cast(B->getLHS()->IgnoreParenLValueCasts()); + const DeclRefExpr *drRHS = + dyn_cast(B->getRHS()->IgnoreParenLValueCasts()); // Does at least one of the variables have a floating point type? drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : NULL; diff --git a/lib/Checker/DereferenceChecker.cpp b/lib/Checker/DereferenceChecker.cpp index 747fcbe311..af929a7af7 100644 --- a/lib/Checker/DereferenceChecker.cpp +++ b/lib/Checker/DereferenceChecker.cpp @@ -59,6 +59,7 @@ void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os, llvm::SmallVectorImpl &Ranges, const Expr *Ex, bool loadedFrom) { + Ex = Ex->IgnoreParenLValueCasts(); switch (Ex->getStmtClass()) { default: return; diff --git a/lib/Checker/Environment.cpp b/lib/Checker/Environment.cpp index aac4afaafb..4b67bda913 100644 --- a/lib/Checker/Environment.cpp +++ b/lib/Checker/Environment.cpp @@ -53,7 +53,8 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder) const { QualType CT = C->getType(); if (CT->isVoidType()) return UnknownVal(); - if (C->getCastKind() == CK_NoOp) { + if (C->getCastKind() == CK_NoOp || + C->getCastKind() == CK_LValueToRValue) { // temporary workaround E = C->getSubExpr(); continue; } diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index a43d36aaeb..e737eed8d1 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -778,6 +778,10 @@ void GRExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, S->getLocStart(), "Error evaluating statement"); + // Expressions to ignore. + if (const Expr *Ex = dyn_cast(S)) + S = Ex->IgnoreParenLValueCasts(); + // FIXME: add metadata to the CFG so that we can disable // this check when we KNOW that there is no block-level subexpression. // The motivation is that this check requires a hashtable lookup. @@ -814,7 +818,9 @@ void GRExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, MakeNode(Dst, S, Pred, GetState(Pred)); break; } - + + case Stmt::ParenExprClass: + llvm_unreachable("ParenExprs already handled."); // Cases that should never be evaluated simply because they shouldn't // appear in the CFG. case Stmt::BreakStmtClass: @@ -1039,10 +1045,6 @@ void GRExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, break; } - case Stmt::ParenExprClass: - Visit(cast(S)->getSubExpr()->IgnoreParens(), Pred, Dst); - break; - case Stmt::ReturnStmtClass: VisitReturnStmt(cast(S), Pred, Dst); break; @@ -1113,8 +1115,8 @@ void GRExprEngine::VisitLValue(const Expr* Ex, ExplodedNode* Pred, Ex->getLocStart(), "Error evaluating statement"); - - Ex = Ex->IgnoreParens(); + // Expressions to ignore. + Ex = Ex->IgnoreParenLValueCasts(); if (Ex != CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)){ Dst.Add(Pred); @@ -2661,6 +2663,7 @@ void GRExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, } return; + case CK_GetObjCProperty: case CK_Dependent: case CK_ArrayToPointerDecay: case CK_BitCast: diff --git a/lib/Checker/IdempotentOperationChecker.cpp b/lib/Checker/IdempotentOperationChecker.cpp index 0e23c2a031..245caef485 100644 --- a/lib/Checker/IdempotentOperationChecker.cpp +++ b/lib/Checker/IdempotentOperationChecker.cpp @@ -543,7 +543,7 @@ bool IdempotentOperationChecker::isTruncationExtensionAssignment( if (VD != RHS_DR->getDecl()) return false; - return dyn_cast(RHS->IgnoreParens()) == NULL; + return dyn_cast(RHS->IgnoreParenLValueCasts()) == NULL; } // Returns false if a path to this block was not completely analyzed, or true diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index c98ee17842..78605ba8b1 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1755,6 +1755,21 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!"); + case CK_GetObjCProperty: { + LValue LV = EmitLValue(E->getSubExpr()); + assert(LV.isPropertyRef()); + RValue RV = EmitLoadOfPropertyRefLValue(LV); + + // Property is an aggregate r-value. + if (RV.isAggregate()) { + return MakeAddrLValue(RV.getAggregateAddr(), E->getType()); + } + + // Implicit property returns an l-value. + assert(RV.isScalar()); + return MakeAddrLValue(RV.getScalarVal(), E->getSubExpr()->getType()); + } + case CK_NoOp: if (!E->getSubExpr()->isRValue() || E->getType()->isRecordType()) { LValue LV = EmitLValue(E->getSubExpr()); diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 9e4e7dcc53..b2679a3106 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -282,8 +282,16 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { break; } + case CK_GetObjCProperty: { + LValue LV = CGF.EmitLValue(E->getSubExpr()); + assert(LV.isPropertyRef()); + RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV, getReturnValueSlot()); + EmitGCMove(E, RV); + break; + } + + case CK_LValueToRValue: // hope for downstream optimization case CK_NoOp: - case CK_LValueToRValue: case CK_UserDefinedConversion: case CK_ConstructorConversion: assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(), @@ -349,9 +357,8 @@ void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) { } void AggExprEmitter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { - RValue RV = CGF.EmitLoadOfPropertyRefLValue(CGF.EmitObjCPropertyRefLValue(E), - getReturnValueSlot()); - EmitGCMove(E, RV); + llvm_unreachable("direct property access not surrounded by " + "lvalue-to-rvalue cast"); } void AggExprEmitter::VisitBinComma(const BinaryOperator *E) { diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index e1d042ba9a..fbb3d4860a 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -108,6 +108,7 @@ public: return EmitLoadOfLValue(E); } ComplexPairTy VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { + assert(E->getObjectKind() == OK_Ordinary); return EmitLoadOfLValue(E); } ComplexPairTy VisitObjCMessageExpr(ObjCMessageExpr *E) { @@ -333,7 +334,21 @@ ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val, ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op, QualType DestTy) { - // FIXME: this should be based off of the CastKind. + switch (CK) { + case CK_GetObjCProperty: { + LValue LV = CGF.EmitLValue(Op); + assert(LV.isPropertyRef() && "Unknown LValue type!"); + return CGF.EmitLoadOfPropertyRefLValue(LV).getComplexVal(); + } + + case CK_NoOp: + case CK_LValueToRValue: + return Visit(Op); + + // TODO: do all of these + default: + break; + } // Two cases here: cast from (complex to complex) and (scalar to complex). if (Op->getType()->isAnyComplexType()) diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 86d7216bbe..8ed8cb38db 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -237,6 +237,8 @@ public: return EmitLoadOfLValue(E); } Value *VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { + assert(E->getObjectKind() == OK_Ordinary && + "reached property reference without lvalue-to-rvalue"); return EmitLoadOfLValue(E); } Value *VisitObjCMessageExpr(ObjCMessageExpr *E) { @@ -1097,9 +1099,18 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { case CK_ToUnion: llvm_unreachable("scalar cast to non-scalar value"); break; + + case CK_GetObjCProperty: { + assert(CGF.getContext().hasSameUnqualifiedType(E->getType(), DestTy)); + assert(E->isLValue() && E->getObjectKind() == OK_ObjCProperty && + "CK_GetObjCProperty for non-lvalue or non-ObjCProperty"); + RValue RV = CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getType()); + return RV.getScalarVal(); + } case CK_LValueToRValue: assert(CGF.getContext().hasSameUnqualifiedType(E->getType(), DestTy)); + assert(E->isGLValue() && "lvalue-to-rvalue applied to r-value!"); return Visit(const_cast(E)); case CK_IntegralToPointer: { @@ -1124,11 +1135,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { return Builder.CreatePtrToInt(Src, ConvertType(DestTy)); } case CK_ToVoid: { - if (E->Classify(CGF.getContext()).isGLValue()) { - LValue LV = CGF.EmitLValue(E); - if (LV.isPropertyRef()) - CGF.EmitLoadOfPropertyRefLValue(LV); - } + if (!E->isRValue()) + CGF.EmitLValue(E); else CGF.EmitAnyExpr(E, AggValueSlot::ignored(), true); return 0; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 4d737b7370..29779070be 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1032,13 +1032,19 @@ StmtResult Parser::ParseForStatement(AttributeList *Attr) { } else { Value = ParseExpression(); + ForEach = isTokIdentifier_in(); + // Turn the expression into a stmt. - if (!Value.isInvalid()) - FirstPart = Actions.ActOnExprStmt(Actions.MakeFullExpr(Value.get())); + if (!Value.isInvalid()) { + if (ForEach) + FirstPart = Actions.ActOnForEachLValueExpr(Value.get()); + else + FirstPart = Actions.ActOnExprStmt(Actions.MakeFullExpr(Value.get())); + } if (Tok.is(tok::semi)) { ConsumeToken(); - } else if ((ForEach = isTokIdentifier_in())) { + } else if (ForEach) { ConsumeToken(); // consume 'in' if (Tok.is(tok::code_completion)) { 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()) 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(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(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(); 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(LHSStripped)) { if (DeclRefExpr* DRR = dyn_cast(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(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(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()) { + 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(RExpr)) + if (ICE->getCastKind() == CK_LValueToRValue) + RExpr = ICE->getSubExpr(); if (DeclRefExpr *DRE = dyn_cast(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(E)) E = Temps->getSubExpr(); - E = E->IgnoreParens(); + E = E->IgnoreParenImpCasts(); if (const CallExpr *CE = dyn_cast(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(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 || diff --git a/test/CodeGen/volatile-1.c b/test/CodeGen/volatile-1.c index e4c6c679bd..d8ce39acd9 100644 --- a/test/CodeGen/volatile-1.c +++ b/test/CodeGen/volatile-1.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -Wno-unused-value -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -Wno-return-type -Wno-unused-value -emit-llvm %s -o - | FileCheck %s // CHECK: @i = common global [[INT:i[0-9]+]] 0 volatile int i, j, k; @@ -301,3 +301,13 @@ void test() { printf("s.x is at %p\n", &((s = s1).x)); #endif } + +extern volatile enum X x; +// CHECK: define void @test1() +void test1() { + // CHECK-NEXT: : + // CHECK-NEXT: ret void + x; + (void) x; + return x; +} diff --git a/test/CodeGenObjCXX/property-dot-reference.mm b/test/CodeGenObjCXX/property-dot-reference.mm index 0d455c6ca8..a6a243e660 100644 --- a/test/CodeGenObjCXX/property-dot-reference.mm +++ b/test/CodeGenObjCXX/property-dot-reference.mm @@ -36,3 +36,24 @@ void f1(A *a) { f0([a target]); } +@interface Test2 +@property (readonly) int myProperty; +- (int) myProperty; +- (double) myGetter; +@end +void test2() { + Test2 *obj; + (void) obj.myProperty; + (void) obj.myGetter; + static_cast(obj.myProperty); + static_cast(obj.myGetter); + void(obj.myProperty); + void(obj.myGetter); +} +// CHECK: define void @_Z5test2v() +// CHECK: call i32 bitcast +// CHECK: call double bitcast +// CHECK: call i32 bitcast +// CHECK: call double bitcast +// CHECK: call i32 bitcast +// CHECK: call double bitcast diff --git a/test/Rewriter/properties.m b/test/Rewriter/properties.m index 44c55b1b69..68ff982db5 100644 --- a/test/Rewriter/properties.m +++ b/test/Rewriter/properties.m @@ -1,5 +1,9 @@ // RUN: %clang_cc1 -rewrite-objc %s -o - +// Fariborz approved this being xfail'ed during the addition +// of explicit lvalue-to-rvalue conversions. +// XFAIL: * + @interface Foo { int i; int rrrr; diff --git a/test/Rewriter/rewrite-nested-property-in-blocks.mm b/test/Rewriter/rewrite-nested-property-in-blocks.mm index 2dffe66ab3..348858ccc1 100755 --- a/test/Rewriter/rewrite-nested-property-in-blocks.mm +++ b/test/Rewriter/rewrite-nested-property-in-blocks.mm @@ -2,6 +2,10 @@ // RUN: %clang_cc1 -fsyntax-only -fms-extensions -Wno-address-of-temporary -Did="void *" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp // radar 8608293 +// Fariborz approved this being xfail'ed during the addition +// of explicit lvalue-to-rvalue conversions. +// XFAIL: * + void *sel_registerName(const char *); extern "C" void nowarn(id); diff --git a/test/Sema/rdr6094103-unordered-compare-promote.c b/test/Sema/rdr6094103-unordered-compare-promote.c index 9991982a20..7bb363e797 100644 --- a/test/Sema/rdr6094103-unordered-compare-promote.c +++ b/test/Sema/rdr6094103-unordered-compare-promote.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -ast-dump %s 2>&1 | grep ImplicitCastExpr | count 2 +// RUN: %clang_cc1 -ast-dump %s 2>&1 | grep ImplicitCastExpr | count 4 int foo (double x, long double y) { // There needs to be an implicit cast on x here. diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp index 9595faece2..1ddff8058a 100644 --- a/test/SemaCXX/decl-expr-ambiguity.cpp +++ b/test/SemaCXX/decl-expr-ambiguity.cpp @@ -7,8 +7,8 @@ void f() { // Expressions. T(a)->m = 7; - int(a)++; // expected-error {{expression is not assignable}} - __extension__ int(a)++; // expected-error {{expression is not assignable}} + int(a)++; // expected-error {{assignment to cast is illegal}} + __extension__ int(a)++; // expected-error {{assignment to cast is illegal}} __typeof(int)(a,5)<