]> granicus.if.org Git - clang/commitdiff
C++1y: support range-based for loops in constant expressions.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 6 May 2013 06:51:17 +0000 (06:51 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 6 May 2013 06:51:17 +0000 (06:51 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181184 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ExprConstant.cpp
test/SemaCXX/constant-expression-cxx1y.cpp

index 14503f47526d1330e9112db373553a95e2d40019..95bfd63f4dccf5e5386663a0cf6f22b4d6911dc8 100644 (file)
@@ -2636,6 +2636,45 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
     return ESR_Succeeded;
   }
 
+  case Stmt::CXXForRangeStmtClass: {
+    const CXXForRangeStmt *FS = cast<CXXForRangeStmt>(S);
+
+    // Initialize the __range variable.
+    EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getRangeStmt());
+    if (ESR != ESR_Succeeded)
+      return ESR;
+
+    // Create the __begin and __end iterators.
+    ESR = EvaluateStmt(Result, Info, FS->getBeginEndStmt());
+    if (ESR != ESR_Succeeded)
+      return ESR;
+
+    while (true) {
+      // Condition: __begin != __end.
+      bool Continue = true;
+      if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info))
+        return ESR_Failed;
+      if (!Continue)
+        break;
+
+      // User's variable declaration, initialized by *__begin.
+      ESR = EvaluateStmt(Result, Info, FS->getLoopVarStmt());
+      if (ESR != ESR_Succeeded)
+        return ESR;
+
+      // Loop body.
+      ESR = EvaluateLoopBody(Result, Info, FS->getBody());
+      if (ESR != ESR_Continue)
+        return ESR;
+
+      // Increment: ++__begin
+      if (!EvaluateIgnoredValue(Info, FS->getInc()))
+        return ESR_Failed;
+    }
+
+    return ESR_Succeeded;
+  }
+
   case Stmt::ContinueStmtClass:
     return ESR_Continue;
 
index d8cfb1c29749394291181af5224d86172d634ea8..60ec82062de5ae39af2a56f5551e08cbbc65fc52 100644 (file)
@@ -402,4 +402,58 @@ namespace loops {
     return true;
   }
   static_assert(cond(), "");
+
+  constexpr int range_for() {
+    int arr[] = { 1, 2, 3, 4, 5 };
+    int sum = 0;
+    for (int x : arr)
+      sum = sum + x;
+    return sum;
+  }
+  static_assert(range_for() == 15, "");
+
+  template<int...N> struct ints {};
+  template<typename A, typename B> struct join_ints;
+  template<int...As, int...Bs> struct join_ints<ints<As...>, ints<Bs...>> {
+    using type = ints<As..., sizeof...(As) + Bs...>;
+  };
+  template<unsigned N> struct make_ints {
+    using type = typename join_ints<typename make_ints<N/2>::type, typename make_ints<(N+1)/2>::type>::type;
+  };
+  template<> struct make_ints<0> { using type = ints<>; };
+  template<> struct make_ints<1> { using type = ints<0>; };
+
+  struct ignore { template<typename ...Ts> constexpr ignore(Ts &&...) {} };
+
+  template<typename T, unsigned N> struct array {
+    constexpr array() : arr{} {}
+    template<typename ...X>
+    constexpr array(X ...x) : arr{} {
+      init(typename make_ints<sizeof...(X)>::type{}, x...);
+    }
+    template<int ...I, typename ...X> constexpr void init(ints<I...>, X ...x) {
+      ignore{arr[I] = x ...};
+    }
+    T arr[N];
+    struct iterator {
+      T *p;
+      constexpr explicit iterator(T *p) : p(p) {}
+      constexpr bool operator!=(iterator o) { return p != o.p; }
+      constexpr iterator &operator++() { ++p; return *this; }
+      constexpr T &operator*() { return *p; }
+    };
+    constexpr iterator begin() { return iterator(arr); }
+    constexpr iterator end() { return iterator(arr + N); }
+  };
+
+  constexpr int range_for_2() {
+    array<int, 5> arr { 1, 2, 3, 4, 5 };
+    int sum = 0;
+    for (int k : arr) {
+      sum = sum + k;
+      if (sum > 8) break;
+    }
+    return sum;
+  }
+  static_assert(range_for_2() == 10, "");
 }