]> granicus.if.org Git - clang/commitdiff
Although we currently have explicit lvalue-to-rvalue conversions, they're
authorJohn McCall <rjmccall@apple.com>
Sat, 4 Dec 2010 03:47:34 +0000 (03:47 +0000)
committerJohn McCall <rjmccall@apple.com>
Sat, 4 Dec 2010 03:47:34 +0000 (03:47 +0000)
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

30 files changed:
include/clang/AST/Expr.h
include/clang/AST/OperationKinds.h
include/clang/Sema/Sema.h
lib/AST/Expr.cpp
lib/AST/ExprClassification.cpp
lib/Analysis/CFG.cpp
lib/Checker/CheckSecuritySyntaxOnly.cpp
lib/Checker/DereferenceChecker.cpp
lib/Checker/Environment.cpp
lib/Checker/GRExprEngine.cpp
lib/Checker/IdempotentOperationChecker.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprComplex.cpp
lib/CodeGen/CGExprScalar.cpp
lib/Parse/ParseStmt.cpp
lib/Sema/SemaCXXCast.cpp
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaExprObjC.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaStmt.cpp
test/CodeGen/volatile-1.c
test/CodeGenObjCXX/property-dot-reference.mm
test/Rewriter/properties.m
test/Rewriter/rewrite-nested-property-in-blocks.mm
test/Sema/rdr6094103-unordered-compare-promote.c
test/SemaCXX/decl-expr-ambiguity.cpp
test/SemaTemplate/enum-argument.cpp

index 4babbc476b20b1bf170d22bddd7b6725d2f4baf0..217e99ee560a7f8e5619e007577ac22505100a2c 100644 (file)
@@ -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<Expr*>(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<Expr*>(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<Expr*>(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:
index 2ced0c9c719e00242021d9bba5b78c0daff8c314..35c72c45ce7c21ecdefec59c48e4ed1a121779d0 100644 (file)
@@ -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.
index 93b5884d91f1c5de423ca28f78d391a4e7e6d52e..65ba72e3b1e25e84dc223e4e14e40a3d8998c1ff 100644 (file)
@@ -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,
index 265788a0817fec4f3540a8c25b5de37e68989cf4..fbc5a67af1f097325047be8bc22d9e1018006eb5 100644 (file)
@@ -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<ParenExpr>(E)) {
+      E = P->getSubExpr();
+      continue;
+    }
+    if (CastExpr *P = dyn_cast<CastExpr>(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<BinaryOperator>(E)) {
+      if (BO->getOpcode() == BO_Comma) {
+        E = BO->getRHS();
+        continue;
+      }
+    }
+
+    break;
+  }
+
+  return cast<ObjCPropertyRefExpr>(E);
+}
+
 FieldDecl *Expr::getBitField() {
   Expr *E = this->IgnoreParens();
 
   while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(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;
index e55545e69365790d69f2d4562384e874dd7aee5e..1afc7602fb9ef4d9ee8e7cc25ada6fbe364b5fb1 100644 (file)
@@ -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<CStyleCastExpr>(E->IgnoreParens())){
-      if (CE->getSubExpr()->Classify(Ctx).isLValue()) {
-        Loc = CE->getLParenLoc();
+    if (const ExplicitCastExpr *CE =
+          dyn_cast<ExplicitCastExpr>(E->IgnoreParens())) {
+      if (CE->getSubExpr()->IgnoreParenImpCasts()->isLValue()) {
+        Loc = CE->getExprLoc();
         return Cl::CM_LValueCast;
       }
     }
index 57e67e4268af698d67d7f5a1d378eb7ff9c75136..b382d9be5800386c525a4507f1f4c80961498b75 100644 (file)
@@ -825,6 +825,16 @@ tryAgain:
 
     case Stmt::ContinueStmtClass:
       return VisitContinueStmt(cast<ContinueStmt>(S));
+    
+    case Stmt::CStyleCastExprClass: {
+      CastExpr *castExpr = cast<CastExpr>(S);
+      if (castExpr->getCastKind() == CK_LValueToRValue) {
+        // temporary workaround
+        S = castExpr->getSubExpr();
+        goto tryAgain;
+      }
+      return VisitStmt(S, asc);
+    }
 
     case Stmt::CXXCatchStmtClass:
       return VisitCXXCatchStmt(cast<CXXCatchStmt>(S));
@@ -871,8 +881,15 @@ tryAgain:
     case Stmt::IfStmtClass:
       return VisitIfStmt(cast<IfStmt>(S));
 
-    case Stmt::ImplicitCastExprClass:
-      return VisitImplicitCastExpr(cast<ImplicitCastExpr>(S), asc);
+    case Stmt::ImplicitCastExprClass: {
+      ImplicitCastExpr *castExpr = cast<ImplicitCastExpr>(S);
+      if (castExpr->getCastKind() == CK_LValueToRValue) {
+        // temporary workaround
+        S = castExpr->getSubExpr();
+        goto tryAgain;
+      }
+      return VisitImplicitCastExpr(castExpr, asc);
+    }
 
     case Stmt::IndirectGotoStmtClass:
       return VisitIndirectGotoStmt(cast<IndirectGotoStmt>(S));
index 9a2ac45fa2e1e2d0aa992216d99eb399c854aebe..0223240ce6e4d8c9457ace9df75ba1ce2940731b 100644 (file)
@@ -187,8 +187,10 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
     return;
 
   // Are we comparing variables?
-  const DeclRefExpr *drLHS = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParens());
-  const DeclRefExpr *drRHS = dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParens());
+  const DeclRefExpr *drLHS =
+    dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
+  const DeclRefExpr *drRHS =
+    dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
 
   // Does at least one of the variables have a floating point type?
   drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : NULL;
index 747fcbe311f888f6c24974f746b8f06e37c4748c..af929a7af721ab2e8968250d6d33f34f90ccd260 100644 (file)
@@ -59,6 +59,7 @@ void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os,
                                      llvm::SmallVectorImpl<SourceRange> &Ranges,
                                         const Expr *Ex,
                                         bool loadedFrom) {
+  Ex = Ex->IgnoreParenLValueCasts();
   switch (Ex->getStmtClass()) {
     default:
       return;
index aac4afaafba9b48e2ae603ca9a8befa61ed6a5be..4b67bda9132c4e4da1f094c330a4038cbf77d237 100644 (file)
@@ -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;
         }
index a43d36aaeb4b392627c4e79da2ed5474e92e9894..e737eed8d15eff84ccb5e55adeec383c89cb1167 100644 (file)
@@ -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<Expr>(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<ParenExpr>(S)->getSubExpr()->IgnoreParens(), Pred, Dst);
-      break;
-
     case Stmt::ReturnStmtClass:
       VisitReturnStmt(cast<ReturnStmt>(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:
index 0e23c2a03138c946690b7b9876cac1e1c76109af..245caef48532528ee29597e0dfc5f63ea429c58a 100644 (file)
@@ -543,7 +543,7 @@ bool IdempotentOperationChecker::isTruncationExtensionAssignment(
   if (VD != RHS_DR->getDecl())
      return false;
 
-  return dyn_cast<DeclRefExpr>(RHS->IgnoreParens()) == NULL;
+  return dyn_cast<DeclRefExpr>(RHS->IgnoreParenLValueCasts()) == NULL;
 }
 
 // Returns false if a path to this block was not completely analyzed, or true
index c98ee1784201b7f55afd990d45809f9403364f4b..78605ba8b1e8db4ad50d3384cb8b7500c983c88a 100644 (file)
@@ -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());
index 9e4e7dcc534a5a4979c1b37bc2ae6c4721911279..b2679a3106f69c1488a9901f26d2d1ab40d72f23 100644 (file)
@@ -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) {
index e1d042ba9a4457409ffac877f3216e1a38e183c3..fbb3d4860a8eb367928cd65f5c8c191d8c1382e7 100644 (file)
@@ -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())
index 86d7216bbe1365fd35fcaf0811068900835dbc76..8ed8cb38db2713ac335109a206d7d435b36e166a 100644 (file)
@@ -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<Expr*>(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;
index 4d737b737045b67a4476ddbf48fc3007a110e39d..29779070bee34c5b0cbfd302b6e6caa8cf3c038e 100644 (file)
@@ -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)) {
index 214d1f6175585ddff376aff1aa0608c8d1df71c3..ac679f70096153690c0c6afe2b37aa139093cfa3 100644 (file)
@@ -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;
   }
index 46c5967e5b2bc5c926722c41f60e0887ee2b0ce4..d6aa4ce88527296353a82c494e1c30df11cdb413 100644 (file)
@@ -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.
index 177d61cc822aaf75725fa02903471a9f2a0afc8e..8b29667bae11afd0eb3fdb7816a98e5e77728e9a 100644 (file)
@@ -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;
index fceb542c793c3e53be491912cf44fcdd679a5a1b..965328615dfe24fd6c75b8ee93866acf58cff2d9 100644 (file)
@@ -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);
 }
index e60aa071e2d3c34eaf9320a9b1ccdb343da24ff8..d63b228f36c08249f52a7225e41dae2035c86354 100644 (file)
@@ -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;
index 26826aa87b51a56f64a8063269b7e4b07c2369f0..d7048a129f1540baa5018fc897c16b1be82b5549 100644 (file)
@@ -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) {
index 7fa555e4f9017a7766011888b5ec9fa45b861009..7ab30d16214b567fe95efccde6c3265fe6fee7a7 100644 (file)
@@ -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 ||
index e4c6c679bd2558a508383bde2a09ec6074244bc5..d8ce39acd9f1d2a0ae0ee51fbbd609646a9fe2c8 100644 (file)
@@ -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;
+}
index 0d455c6ca81cf1cf0d5c466a09f08193bc904f75..a6a243e660ca7fdc04664f74fac695233ee61e71 100644 (file)
@@ -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<void>(obj.myProperty);
+    static_cast<void>(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
index 44c55b1b69c4ac40b0ed04afdd31e6b1ca11569a..68ff982db5abb23432582797a3d8599ed18aeb38 100644 (file)
@@ -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;
index 2dffe66ab326bf6f1af82e7f01a6df02a818e7e1..348858ccc1d9f77f40ffce4eb675aaa18848ce25 100755 (executable)
@@ -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);
index 9991982a20b27fcc7385c56a1b5a68f08d1a596e..7bb363e797c86e29c07a94733895f76cb4f1644d 100644 (file)
@@ -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.
index 9595faece29966478327d61227ab4e1cef67dd6e..1ddff8058a3b4422bc4e03b24d6e7bd6d8231677 100644 (file)
@@ -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)<<a; // expected-error {{excess elements in scalar initializer}}
   void(a), ++a;
   if (int(a)+1) {}
index 7d237570678f23409bcb6c1382483039eb863e0a..a79ed8403e9f43b949c7b545c50a165a73effe77 100644 (file)
@@ -30,7 +30,7 @@ namespace rdar8020920 {
     unsigned long long bitfield : e0;
 
     void f(int j) {
-      bitfield + j;
+      bitfield + j; // expected-warning {{expression result unused}}
     }
   };
 }