From 692eafd2052fb6ca581530d6f3569eea9520a508 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 6 May 2013 06:51:17 +0000 Subject: C++1y: support range-based for loops in constant expressions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181184 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ExprConstant.cpp | 39 +++++++++++++++++++++ test/SemaCXX/constant-expression-cxx1y.cpp | 54 ++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 14503f4752..95bfd63f4d 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -2636,6 +2636,45 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, return ESR_Succeeded; } + case Stmt::CXXForRangeStmtClass: { + const CXXForRangeStmt *FS = cast(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; diff --git a/test/SemaCXX/constant-expression-cxx1y.cpp b/test/SemaCXX/constant-expression-cxx1y.cpp index d8cfb1c297..60ec82062d 100644 --- a/test/SemaCXX/constant-expression-cxx1y.cpp +++ b/test/SemaCXX/constant-expression-cxx1y.cpp @@ -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 struct ints {}; + template struct join_ints; + template struct join_ints, ints> { + using type = ints; + }; + template struct make_ints { + using type = typename join_ints::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 constexpr ignore(Ts &&...) {} }; + + template struct array { + constexpr array() : arr{} {} + template + constexpr array(X ...x) : arr{} { + init(typename make_ints::type{}, x...); + } + template constexpr void init(ints, 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 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, ""); } -- cgit v1.2.3-18-g5258