<div dir="ltr">This results in a new gcc warning:<div><br></div>[ 633s] /home/abuild/rpmbuild/BUILD/llvm/tools/clang/lib/AST/ExprConstant.cpp: In function '{anonymous}::EvalStmtResult EvaluateSwitch(clang::APValue&, {anonymous}::EvalInfo&, const clang::SwitchStmt*)': [ 633s] /home/abuild/rpmbuild/BUILD/llvm/tools/clang/lib/AST/ExprConstant.cpp:2876:1: warning: control reaches end of non-void function [-Wreturn-type]
</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Sun, May 12, 2013 at 7:32 PM, Richard Smith <span dir="ltr"><<a href="mailto:richard-llvm@metafoo.co.uk" target="_blank">richard-llvm@metafoo.co.uk</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rsmith<br>
Date: Sun May 12 12:32:42 2013<br>
New Revision: 181671<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=181671&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=181671&view=rev</a><br>
Log:<br>
C++1y: support for 'switch' statements in constexpr functions. This is somewhat<br>
inefficient; we perform a linear scan of switch labels to find the one matching<br>
the condition, and then walk the body looking for that label. Both parts should<br>
be straightforward to optimize.<br>
<br>
Modified:<br>
    cfe/trunk/include/clang/AST/Stmt.h<br>
    cfe/trunk/lib/AST/ExprConstant.cpp<br>
    cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp<br>
<br>
Modified: cfe/trunk/include/clang/AST/Stmt.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=181671&r1=181670&r2=181671&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=181671&r1=181670&r2=181671&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/include/clang/AST/Stmt.h (original)<br>
+++ cfe/trunk/include/clang/AST/Stmt.h Sun May 12 12:32:42 2013<br>
@@ -967,9 +967,6 @@ public:<br>
   SwitchCase *getSwitchCaseList() { return FirstCase; }<br>
<br>
   /// \brief Set the case list for this switch statement.<br>
-  ///<br>
-  /// The caller is responsible for incrementing the retain counts on<br>
-  /// all of the SwitchCase statements in this list.<br>
   void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }<br>
<br>
   SourceLocation getSwitchLoc() const { return SwitchLoc; }<br>
<br>
Modified: cfe/trunk/lib/AST/ExprConstant.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=181671&r1=181670&r2=181671&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=181671&r1=181670&r2=181671&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)<br>
+++ cfe/trunk/lib/AST/ExprConstant.cpp Sun May 12 12:32:42 2013<br>
@@ -2769,7 +2769,9 @@ enum EvalStmtResult {<br>
   /// Hit a 'continue' statement.<br>
   ESR_Continue,<br>
   /// Hit a 'break' statement.<br>
-  ESR_Break<br>
+  ESR_Break,<br>
+  /// Still scanning for 'case' or 'default' statement.<br>
+  ESR_CaseNotFound<br>
 };<br>
 }<br>
<br>
@@ -2803,12 +2805,13 @@ static bool EvaluateCond(EvalInfo &Info,<br>
 }<br>
<br>
 static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,<br>
-                                   const Stmt *S);<br>
+                                   const Stmt *S, const SwitchCase *SC = 0);<br>
<br>
 /// Evaluate the body of a loop, and translate the result as appropriate.<br>
 static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info,<br>
-                                       const Stmt *Body) {<br>
-  switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body)) {<br>
+                                       const Stmt *Body,<br>
+                                       const SwitchCase *Case = 0) {<br>
+  switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case)) {<br>
   case ESR_Break:<br>
     return ESR_Succeeded;<br>
   case ESR_Succeeded:<br>
@@ -2816,17 +2819,128 @@ static EvalStmtResult EvaluateLoopBody(A<br>
     return ESR_Continue;<br>
   case ESR_Failed:<br>
   case ESR_Returned:<br>
+  case ESR_CaseNotFound:<br>
     return ESR;<br>
   }<br>
   llvm_unreachable("Invalid EvalStmtResult!");<br>
 }<br>
<br>
+/// Evaluate a switch statement.<br>
+static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info,<br>
+                                     const SwitchStmt *SS) {<br>
+  // Evaluate the switch condition.<br>
+  if (SS->getConditionVariable() &&<br>
+      !EvaluateDecl(Info, SS->getConditionVariable()))<br>
+    return ESR_Failed;<br>
+  APSInt Value;<br>
+  if (!EvaluateInteger(SS->getCond(), Value, Info))<br>
+    return ESR_Failed;<br>
+<br>
+  // Find the switch case corresponding to the value of the condition.<br>
+  // FIXME: Cache this lookup.<br>
+  const SwitchCase *Found = 0;<br>
+  for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;<br>
+       SC = SC->getNextSwitchCase()) {<br>
+    if (isa<DefaultStmt>(SC)) {<br>
+      Found = SC;<br>
+      continue;<br>
+    }<br>
+<br>
+    const CaseStmt *CS = cast<CaseStmt>(SC);<br>
+    APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx);<br>
+    APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx)<br>
+                              : LHS;<br>
+    if (LHS <= Value && Value <= RHS) {<br>
+      Found = SC;<br>
+      break;<br>
+    }<br>
+  }<br>
+<br>
+  if (!Found)<br>
+    return ESR_Succeeded;<br>
+<br>
+  // Search the switch body for the switch case and evaluate it from there.<br>
+  switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found)) {<br>
+  case ESR_Break:<br>
+    return ESR_Succeeded;<br>
+  case ESR_Succeeded:<br>
+  case ESR_Continue:<br>
+  case ESR_Failed:<br>
+  case ESR_Returned:<br>
+    return ESR;<br>
+  case ESR_CaseNotFound:<br>
+    Found->dump();<br>
+    SS->getBody()->dump();<br>
+    llvm_unreachable("couldn't find switch case");<br>
+  }<br>
+}<br>
+<br>
 // Evaluate a statement.<br>
 static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,<br>
-                                   const Stmt *S) {<br>
+                                   const Stmt *S, const SwitchCase *Case) {<br>
   if (!Info.nextStep(S))<br>
     return ESR_Failed;<br>
<br>
+  // If we're hunting down a 'case' or 'default' label, recurse through<br>
+  // substatements until we hit the label.<br>
+  if (Case) {<br>
+    // FIXME: We don't start the lifetime of objects whose initialization we<br>
+    // jump over. However, such objects must be of class type with a trivial<br>
+    // default constructor that initialize all subobjects, so must be empty,<br>
+    // so this almost never matters.<br>
+    switch (S->getStmtClass()) {<br>
+    case Stmt::CompoundStmtClass:<br>
+      // FIXME: Precompute which substatement of a compound statement we<br>
+      // would jump to, and go straight there rather than performing a<br>
+      // linear scan each time.<br>
+    case Stmt::LabelStmtClass:<br>
+    case Stmt::AttributedStmtClass:<br>
+    case Stmt::DoStmtClass:<br>
+      break;<br>
+<br>
+    case Stmt::CaseStmtClass:<br>
+    case Stmt::DefaultStmtClass:<br>
+      if (Case == S)<br>
+        Case = 0;<br>
+      break;<br>
+<br>
+    case Stmt::IfStmtClass: {<br>
+      // FIXME: Precompute which side of an 'if' we would jump to, and go<br>
+      // straight there rather than scanning both sides.<br>
+      const IfStmt *IS = cast<IfStmt>(S);<br>
+      EvalStmtResult ESR = EvaluateStmt(Result, Info, IS->getThen(), Case);<br>
+      if (ESR != ESR_CaseNotFound || !IS->getElse())<br>
+        return ESR;<br>
+      return EvaluateStmt(Result, Info, IS->getElse(), Case);<br>
+    }<br>
+<br>
+    case Stmt::WhileStmtClass: {<br>
+      EvalStmtResult ESR =<br>
+          EvaluateLoopBody(Result, Info, cast<WhileStmt>(S)->getBody(), Case);<br>
+      if (ESR != ESR_Continue)<br>
+        return ESR;<br>
+      break;<br>
+    }<br>
+<br>
+    case Stmt::ForStmtClass: {<br>
+      const ForStmt *FS = cast<ForStmt>(S);<br>
+      EvalStmtResult ESR =<br>
+          EvaluateLoopBody(Result, Info, FS->getBody(), Case);<br>
+      if (ESR != ESR_Continue)<br>
+        return ESR;<br>
+      if (FS->getInc() && !EvaluateIgnoredValue(Info, FS->getInc()))<br>
+        return ESR_Failed;<br>
+      break;<br>
+    }<br>
+<br>
+    case Stmt::DeclStmtClass:<br>
+      // FIXME: If the variable has initialization that can't be jumped over,<br>
+      // bail out of any immediately-surrounding compound-statement too.<br>
+    default:<br>
+      return ESR_CaseNotFound;<br>
+    }<br>
+  }<br>
+<br>
   // FIXME: Mark all temporaries in the current frame as destroyed at<br>
   // the end of each full-expression.<br>
   switch (S->getStmtClass()) {<br>
@@ -2865,11 +2979,13 @@ static EvalStmtResult EvaluateStmt(APVal<br>
     const CompoundStmt *CS = cast<CompoundStmt>(S);<br>
     for (CompoundStmt::const_body_iterator BI = CS->body_begin(),<br>
            BE = CS->body_end(); BI != BE; ++BI) {<br>
-      EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI);<br>
-      if (ESR != ESR_Succeeded)<br>
+      EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI, Case);<br>
+      if (ESR == ESR_Succeeded)<br>
+        Case = 0;<br>
+      else if (ESR != ESR_CaseNotFound)<br>
         return ESR;<br>
     }<br>
-    return ESR_Succeeded;<br>
+    return Case ? ESR_CaseNotFound : ESR_Succeeded;<br>
   }<br>
<br>
   case Stmt::IfStmtClass: {<br>
@@ -2909,9 +3025,10 @@ static EvalStmtResult EvaluateStmt(APVal<br>
     const DoStmt *DS = cast<DoStmt>(S);<br>
     bool Continue;<br>
     do {<br>
-      EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody());<br>
+      EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody(), Case);<br>
       if (ESR != ESR_Continue)<br>
         return ESR;<br>
+      Case = 0;<br>
<br>
       if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info))<br>
         return ESR_Failed;<br>
@@ -2983,11 +3100,27 @@ static EvalStmtResult EvaluateStmt(APVal<br>
     return ESR_Succeeded;<br>
   }<br>
<br>
+  case Stmt::SwitchStmtClass:<br>
+    return EvaluateSwitch(Result, Info, cast<SwitchStmt>(S));<br>
+<br>
   case Stmt::ContinueStmtClass:<br>
     return ESR_Continue;<br>
<br>
   case Stmt::BreakStmtClass:<br>
     return ESR_Break;<br>
+<br>
+  case Stmt::LabelStmtClass:<br>
+    return EvaluateStmt(Result, Info, cast<LabelStmt>(S)->getSubStmt(), Case);<br>
+<br>
+  case Stmt::AttributedStmtClass:<br>
+    // As a general principle, C++11 attributes can be ignored without<br>
+    // any semantic impact.<br>
+    return EvaluateStmt(Result, Info, cast<AttributedStmt>(S)->getSubStmt(),<br>
+                        Case);<br>
+<br>
+  case Stmt::CaseStmtClass:<br>
+  case Stmt::DefaultStmtClass:<br>
+    return EvaluateStmt(Result, Info, cast<SwitchCase>(S)->getSubStmt(), Case);<br>
   }<br>
 }<br>
<br>
<br>
Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp?rev=181671&r1=181670&r2=181671&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp?rev=181671&r1=181670&r2=181671&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp Sun May 12 12:32:42 2013<br>
@@ -593,3 +593,117 @@ namespace assignment_op {<br>
   }<br>
   static_assert(testC(), "");<br>
 }<br>
+<br>
+namespace switch_stmt {<br>
+  constexpr int f(char k) {<br>
+    bool b = false;<br>
+    int z = 6;<br>
+    switch (k) {<br>
+      return -1;<br>
+    case 0:<br>
+      if (false) {<br>
+      case 1:<br>
+        z = 1;<br>
+        for (; b;) {<br>
+          return 5;<br>
+          while (0)<br>
+            case 2: return 2;<br>
+          case 7: z = 7;<br>
+          do case 6: {<br>
+            return z;<br>
+            if (false)<br>
+              case 3: return 3;<br>
+            case 4: z = 4;<br>
+          } while (1);<br>
+          case 5: b = true;<br>
+          case 9: z = 9;<br>
+        }<br>
+        return z;<br>
+      } else if (false) case 8: z = 8;<br>
+      else if (false) {<br>
+      case 10:<br>
+        z = -10;<br>
+        break;<br>
+      }<br>
+      else z = 0;<br>
+      return z;<br>
+    default:<br>
+      return -1;<br>
+    }<br>
+    return -z;<br>
+  }<br>
+  static_assert(f(0) == 0, "");<br>
+  static_assert(f(1) == 1, "");<br>
+  static_assert(f(2) == 2, "");<br>
+  static_assert(f(3) == 3, "");<br>
+  static_assert(f(4) == 4, "");<br>
+  static_assert(f(5) == 5, "");<br>
+  static_assert(f(6) == 6, "");<br>
+  static_assert(f(7) == 7, "");<br>
+  static_assert(f(8) == 8, "");<br>
+  static_assert(f(9) == 9, "");<br>
+  static_assert(f(10) == 10, "");<br>
+<br>
+  // Check that we can continue an outer loop from within a switch.<br>
+  constexpr bool contin() {<br>
+    for (int n = 0; n != 10; ++n) {<br>
+      switch (n) {<br>
+      case 0:<br>
+        ++n;<br>
+        continue;<br>
+      case 1:<br>
+        return false;<br>
+      case 2:<br>
+        return true;<br>
+      }<br>
+    }<br>
+    return false;<br>
+  }<br>
+  static_assert(contin(), "");<br>
+<br>
+  constexpr bool switch_into_for() {<br>
+    int n = 0;<br>
+    switch (n) {<br>
+      for (; n == 1; ++n) {<br>
+        return n == 1;<br>
+      case 0: ;<br>
+      }<br>
+    }<br>
+    return false;<br>
+  }<br>
+  static_assert(switch_into_for(), "");<br>
+<br>
+  constexpr void duff_copy(char *a, const char *b, int n) {<br>
+    switch ((n - 1) % 8 + 1) {<br>
+      for ( ; n; n = (n - 1) & ~7) {<br>
+      case 8: a[n-8] = b[n-8];<br>
+      case 7: a[n-7] = b[n-7];<br>
+      case 6: a[n-6] = b[n-6];<br>
+      case 5: a[n-5] = b[n-5];<br>
+      case 4: a[n-4] = b[n-4];<br>
+      case 3: a[n-3] = b[n-3];<br>
+      case 2: a[n-2] = b[n-2];<br>
+      case 1: a[n-1] = b[n-1];<br>
+      }<br>
+      case 0: ;<br>
+    }<br>
+  }<br>
+<br>
+  constexpr bool test_copy(const char *str, int n) {<br>
+    char buffer[16] = {};<br>
+    duff_copy(buffer, str, n);<br>
+    for (int i = 0; i != sizeof(buffer); ++i)<br>
+      if (buffer[i] != (i < n ? str[i] : 0))<br>
+        return false;<br>
+    return true;<br>
+  }<br>
+  static_assert(test_copy("foo", 0), "");<br>
+  static_assert(test_copy("foo", 1), "");<br>
+  static_assert(test_copy("foo", 2), "");<br>
+  static_assert(test_copy("hello world", 0), "");<br>
+  static_assert(test_copy("hello world", 7), "");<br>
+  static_assert(test_copy("hello world", 8), "");<br>
+  static_assert(test_copy("hello world", 9), "");<br>
+  static_assert(test_copy("hello world", 10), "");<br>
+  static_assert(test_copy("hello world", 10), "");<br>
+}<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>