Do l-value conversion, etc., on a switch condition expression in
ActOnStartOfSwitchStmt (i.e. before binding up a full-expression)
instead of ActOnFinishSwitchStmt.

Among other things, this means that property l-values are properly
converted inside the full-expression.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@137014 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 5803a76..cff9d6b 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -3448,10 +3448,11 @@
 void Sema::CodeCompleteCase(Scope *S) {
   if (getCurFunction()->SwitchStack.empty() || !CodeCompleter)
     return;
-  
+
   SwitchStmt *Switch = getCurFunction()->SwitchStack.back();
-  if (!Switch->getCond()->getType()->isEnumeralType()) {
-    CodeCompleteExpressionData Data(Switch->getCond()->getType());
+  QualType type = Switch->getCond()->IgnoreImplicit()->getType();
+  if (!type->isEnumeralType()) {
+    CodeCompleteExpressionData Data(type);
     Data.IntegralConstantExpression = true;
     CodeCompleteExpression(S, Data);
     return;
@@ -3459,7 +3460,7 @@
   
   // Code-complete the cases of a switch statement over an enumeration type
   // by providing the list of 
-  EnumDecl *Enum = Switch->getCond()->getType()->getAs<EnumType>()->getDecl();
+  EnumDecl *Enum = type->castAs<EnumType>()->getDecl();
   
   // Determine which enumerators we have already seen in the switch statement.
   // FIXME: Ideally, we would also be able to look *past* the code-completion
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 6b2935f..6e814e5 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -407,13 +407,12 @@
 
 /// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of
 /// potentially integral-promoted expression @p expr.
-static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) {
-  if (const CastExpr *ImplicitCast = dyn_cast<ImplicitCastExpr>(expr)) {
-    const Expr *ExprBeforePromotion = ImplicitCast->getSubExpr();
-    QualType TypeBeforePromotion = ExprBeforePromotion->getType();
-    if (TypeBeforePromotion->isIntegralOrEnumerationType()) {
-      return TypeBeforePromotion;
-    }
+static QualType GetTypeBeforeIntegralPromotion(Expr *&expr) {
+  if (ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(expr))
+    expr = cleanups->getSubExpr();
+  while (ImplicitCastExpr *impcast = dyn_cast<ImplicitCastExpr>(expr)) {
+    if (impcast->getCastKind() != CK_IntegralCast) break;
+    expr = impcast->getSubExpr();
   }
   return expr->getType();
 }
@@ -449,6 +448,11 @@
   if (CondResult.isInvalid()) return StmtError();
   Cond = CondResult.take();
 
+  // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
+  CondResult = UsualUnaryConversions(Cond);
+  if (CondResult.isInvalid()) return StmtError();
+  Cond = CondResult.take();
+
   if (!CondVar) {
     CheckImplicitConversions(Cond, SwitchLoc);
     CondResult = MaybeCreateExprWithCleanups(Cond);
@@ -482,21 +486,14 @@
   SS->setBody(BodyStmt, SwitchLoc);
   getCurFunction()->SwitchStack.pop_back();
 
-  if (SS->getCond() == 0)
-    return StmtError();
-
   Expr *CondExpr = SS->getCond();
+  if (!CondExpr) return StmtError();
+
+  QualType CondType = CondExpr->getType();
+
   Expr *CondExprBeforePromotion = CondExpr;
   QualType CondTypeBeforePromotion =
-      GetTypeBeforeIntegralPromotion(CondExpr);
-
-  // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
-  ExprResult CondResult = UsualUnaryConversions(CondExpr);
-  if (CondResult.isInvalid())
-    return StmtError();
-  CondExpr = CondResult.take();
-  QualType CondType = CondExpr->getType();
-  SS->setCond(CondExpr);
+      GetTypeBeforeIntegralPromotion(CondExprBeforePromotion);
 
   // C++ 6.4.2.p2:
   // Integral promotions are performed (on the switch condition).
diff --git a/test/SemaObjC/arc.m b/test/SemaObjC/arc.m
index 88d0818..83835eb 100644
--- a/test/SemaObjC/arc.m
+++ b/test/SemaObjC/arc.m
@@ -649,3 +649,16 @@
     (void) y;
   }
 }
+
+// rdar://problem/9887979
+@interface Test38
+@property int value;
+@end
+void test38() {
+  extern Test38 *test38_helper(void);
+  switch (test38_helper().value) {
+  case 0:
+  case 1:
+    ;
+  }
+}