r181671 - C++1y: support for 'switch' statements in constexpr functions. This is somewhat
İsmail Dönmez
ismail at donmez.ws
Mon May 13 13:22:01 PDT 2013
This results in a new gcc warning:
[ 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]
On Sun, May 12, 2013 at 7:32 PM, Richard Smith
<richard-llvm at metafoo.co.uk>wrote:
> Author: rsmith
> Date: Sun May 12 12:32:42 2013
> New Revision: 181671
>
> URL: http://llvm.org/viewvc/llvm-project?rev=181671&view=rev
> Log:
> C++1y: support for 'switch' statements in constexpr functions. This is
> somewhat
> inefficient; we perform a linear scan of switch labels to find the one
> matching
> the condition, and then walk the body looking for that label. Both parts
> should
> be straightforward to optimize.
>
> Modified:
> cfe/trunk/include/clang/AST/Stmt.h
> cfe/trunk/lib/AST/ExprConstant.cpp
> cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
>
> Modified: cfe/trunk/include/clang/AST/Stmt.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=181671&r1=181670&r2=181671&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Stmt.h (original)
> +++ cfe/trunk/include/clang/AST/Stmt.h Sun May 12 12:32:42 2013
> @@ -967,9 +967,6 @@ public:
> SwitchCase *getSwitchCaseList() { return FirstCase; }
>
> /// \brief Set the case list for this switch statement.
> - ///
> - /// The caller is responsible for incrementing the retain counts on
> - /// all of the SwitchCase statements in this list.
> void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }
>
> SourceLocation getSwitchLoc() const { return SwitchLoc; }
>
> Modified: cfe/trunk/lib/AST/ExprConstant.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=181671&r1=181670&r2=181671&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Sun May 12 12:32:42 2013
> @@ -2769,7 +2769,9 @@ enum EvalStmtResult {
> /// Hit a 'continue' statement.
> ESR_Continue,
> /// Hit a 'break' statement.
> - ESR_Break
> + ESR_Break,
> + /// Still scanning for 'case' or 'default' statement.
> + ESR_CaseNotFound
> };
> }
>
> @@ -2803,12 +2805,13 @@ static bool EvaluateCond(EvalInfo &Info,
> }
>
> static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
> - const Stmt *S);
> + const Stmt *S, const SwitchCase *SC =
> 0);
>
> /// Evaluate the body of a loop, and translate the result as appropriate.
> static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info,
> - const Stmt *Body) {
> - switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body)) {
> + const Stmt *Body,
> + const SwitchCase *Case = 0) {
> + switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case)) {
> case ESR_Break:
> return ESR_Succeeded;
> case ESR_Succeeded:
> @@ -2816,17 +2819,128 @@ static EvalStmtResult EvaluateLoopBody(A
> return ESR_Continue;
> case ESR_Failed:
> case ESR_Returned:
> + case ESR_CaseNotFound:
> return ESR;
> }
> llvm_unreachable("Invalid EvalStmtResult!");
> }
>
> +/// Evaluate a switch statement.
> +static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info,
> + const SwitchStmt *SS) {
> + // Evaluate the switch condition.
> + if (SS->getConditionVariable() &&
> + !EvaluateDecl(Info, SS->getConditionVariable()))
> + return ESR_Failed;
> + APSInt Value;
> + if (!EvaluateInteger(SS->getCond(), Value, Info))
> + return ESR_Failed;
> +
> + // Find the switch case corresponding to the value of the condition.
> + // FIXME: Cache this lookup.
> + const SwitchCase *Found = 0;
> + for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;
> + SC = SC->getNextSwitchCase()) {
> + if (isa<DefaultStmt>(SC)) {
> + Found = SC;
> + continue;
> + }
> +
> + const CaseStmt *CS = cast<CaseStmt>(SC);
> + APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx);
> + APSInt RHS = CS->getRHS() ?
> CS->getRHS()->EvaluateKnownConstInt(Info.Ctx)
> + : LHS;
> + if (LHS <= Value && Value <= RHS) {
> + Found = SC;
> + break;
> + }
> + }
> +
> + if (!Found)
> + return ESR_Succeeded;
> +
> + // Search the switch body for the switch case and evaluate it from
> there.
> + switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(),
> Found)) {
> + case ESR_Break:
> + return ESR_Succeeded;
> + case ESR_Succeeded:
> + case ESR_Continue:
> + case ESR_Failed:
> + case ESR_Returned:
> + return ESR;
> + case ESR_CaseNotFound:
> + Found->dump();
> + SS->getBody()->dump();
> + llvm_unreachable("couldn't find switch case");
> + }
> +}
> +
> // Evaluate a statement.
> static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
> - const Stmt *S) {
> + const Stmt *S, const SwitchCase *Case)
> {
> if (!Info.nextStep(S))
> return ESR_Failed;
>
> + // If we're hunting down a 'case' or 'default' label, recurse through
> + // substatements until we hit the label.
> + if (Case) {
> + // FIXME: We don't start the lifetime of objects whose initialization
> we
> + // jump over. However, such objects must be of class type with a
> trivial
> + // default constructor that initialize all subobjects, so must be
> empty,
> + // so this almost never matters.
> + switch (S->getStmtClass()) {
> + case Stmt::CompoundStmtClass:
> + // FIXME: Precompute which substatement of a compound statement we
> + // would jump to, and go straight there rather than performing a
> + // linear scan each time.
> + case Stmt::LabelStmtClass:
> + case Stmt::AttributedStmtClass:
> + case Stmt::DoStmtClass:
> + break;
> +
> + case Stmt::CaseStmtClass:
> + case Stmt::DefaultStmtClass:
> + if (Case == S)
> + Case = 0;
> + break;
> +
> + case Stmt::IfStmtClass: {
> + // FIXME: Precompute which side of an 'if' we would jump to, and go
> + // straight there rather than scanning both sides.
> + const IfStmt *IS = cast<IfStmt>(S);
> + EvalStmtResult ESR = EvaluateStmt(Result, Info, IS->getThen(),
> Case);
> + if (ESR != ESR_CaseNotFound || !IS->getElse())
> + return ESR;
> + return EvaluateStmt(Result, Info, IS->getElse(), Case);
> + }
> +
> + case Stmt::WhileStmtClass: {
> + EvalStmtResult ESR =
> + EvaluateLoopBody(Result, Info, cast<WhileStmt>(S)->getBody(),
> Case);
> + if (ESR != ESR_Continue)
> + return ESR;
> + break;
> + }
> +
> + case Stmt::ForStmtClass: {
> + const ForStmt *FS = cast<ForStmt>(S);
> + EvalStmtResult ESR =
> + EvaluateLoopBody(Result, Info, FS->getBody(), Case);
> + if (ESR != ESR_Continue)
> + return ESR;
> + if (FS->getInc() && !EvaluateIgnoredValue(Info, FS->getInc()))
> + return ESR_Failed;
> + break;
> + }
> +
> + case Stmt::DeclStmtClass:
> + // FIXME: If the variable has initialization that can't be jumped
> over,
> + // bail out of any immediately-surrounding compound-statement too.
> + default:
> + return ESR_CaseNotFound;
> + }
> + }
> +
> // FIXME: Mark all temporaries in the current frame as destroyed at
> // the end of each full-expression.
> switch (S->getStmtClass()) {
> @@ -2865,11 +2979,13 @@ static EvalStmtResult EvaluateStmt(APVal
> const CompoundStmt *CS = cast<CompoundStmt>(S);
> for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
> BE = CS->body_end(); BI != BE; ++BI) {
> - EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI);
> - if (ESR != ESR_Succeeded)
> + EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI, Case);
> + if (ESR == ESR_Succeeded)
> + Case = 0;
> + else if (ESR != ESR_CaseNotFound)
> return ESR;
> }
> - return ESR_Succeeded;
> + return Case ? ESR_CaseNotFound : ESR_Succeeded;
> }
>
> case Stmt::IfStmtClass: {
> @@ -2909,9 +3025,10 @@ static EvalStmtResult EvaluateStmt(APVal
> const DoStmt *DS = cast<DoStmt>(S);
> bool Continue;
> do {
> - EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody());
> + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody(),
> Case);
> if (ESR != ESR_Continue)
> return ESR;
> + Case = 0;
>
> if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info))
> return ESR_Failed;
> @@ -2983,11 +3100,27 @@ static EvalStmtResult EvaluateStmt(APVal
> return ESR_Succeeded;
> }
>
> + case Stmt::SwitchStmtClass:
> + return EvaluateSwitch(Result, Info, cast<SwitchStmt>(S));
> +
> case Stmt::ContinueStmtClass:
> return ESR_Continue;
>
> case Stmt::BreakStmtClass:
> return ESR_Break;
> +
> + case Stmt::LabelStmtClass:
> + return EvaluateStmt(Result, Info, cast<LabelStmt>(S)->getSubStmt(),
> Case);
> +
> + case Stmt::AttributedStmtClass:
> + // As a general principle, C++11 attributes can be ignored without
> + // any semantic impact.
> + return EvaluateStmt(Result, Info,
> cast<AttributedStmt>(S)->getSubStmt(),
> + Case);
> +
> + case Stmt::CaseStmtClass:
> + case Stmt::DefaultStmtClass:
> + return EvaluateStmt(Result, Info, cast<SwitchCase>(S)->getSubStmt(),
> Case);
> }
> }
>
>
> Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp?rev=181671&r1=181670&r2=181671&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp (original)
> +++ cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp Sun May 12
> 12:32:42 2013
> @@ -593,3 +593,117 @@ namespace assignment_op {
> }
> static_assert(testC(), "");
> }
> +
> +namespace switch_stmt {
> + constexpr int f(char k) {
> + bool b = false;
> + int z = 6;
> + switch (k) {
> + return -1;
> + case 0:
> + if (false) {
> + case 1:
> + z = 1;
> + for (; b;) {
> + return 5;
> + while (0)
> + case 2: return 2;
> + case 7: z = 7;
> + do case 6: {
> + return z;
> + if (false)
> + case 3: return 3;
> + case 4: z = 4;
> + } while (1);
> + case 5: b = true;
> + case 9: z = 9;
> + }
> + return z;
> + } else if (false) case 8: z = 8;
> + else if (false) {
> + case 10:
> + z = -10;
> + break;
> + }
> + else z = 0;
> + return z;
> + default:
> + return -1;
> + }
> + return -z;
> + }
> + static_assert(f(0) == 0, "");
> + static_assert(f(1) == 1, "");
> + static_assert(f(2) == 2, "");
> + static_assert(f(3) == 3, "");
> + static_assert(f(4) == 4, "");
> + static_assert(f(5) == 5, "");
> + static_assert(f(6) == 6, "");
> + static_assert(f(7) == 7, "");
> + static_assert(f(8) == 8, "");
> + static_assert(f(9) == 9, "");
> + static_assert(f(10) == 10, "");
> +
> + // Check that we can continue an outer loop from within a switch.
> + constexpr bool contin() {
> + for (int n = 0; n != 10; ++n) {
> + switch (n) {
> + case 0:
> + ++n;
> + continue;
> + case 1:
> + return false;
> + case 2:
> + return true;
> + }
> + }
> + return false;
> + }
> + static_assert(contin(), "");
> +
> + constexpr bool switch_into_for() {
> + int n = 0;
> + switch (n) {
> + for (; n == 1; ++n) {
> + return n == 1;
> + case 0: ;
> + }
> + }
> + return false;
> + }
> + static_assert(switch_into_for(), "");
> +
> + constexpr void duff_copy(char *a, const char *b, int n) {
> + switch ((n - 1) % 8 + 1) {
> + for ( ; n; n = (n - 1) & ~7) {
> + case 8: a[n-8] = b[n-8];
> + case 7: a[n-7] = b[n-7];
> + case 6: a[n-6] = b[n-6];
> + case 5: a[n-5] = b[n-5];
> + case 4: a[n-4] = b[n-4];
> + case 3: a[n-3] = b[n-3];
> + case 2: a[n-2] = b[n-2];
> + case 1: a[n-1] = b[n-1];
> + }
> + case 0: ;
> + }
> + }
> +
> + constexpr bool test_copy(const char *str, int n) {
> + char buffer[16] = {};
> + duff_copy(buffer, str, n);
> + for (int i = 0; i != sizeof(buffer); ++i)
> + if (buffer[i] != (i < n ? str[i] : 0))
> + return false;
> + return true;
> + }
> + static_assert(test_copy("foo", 0), "");
> + static_assert(test_copy("foo", 1), "");
> + static_assert(test_copy("foo", 2), "");
> + static_assert(test_copy("hello world", 0), "");
> + static_assert(test_copy("hello world", 7), "");
> + static_assert(test_copy("hello world", 8), "");
> + static_assert(test_copy("hello world", 9), "");
> + static_assert(test_copy("hello world", 10), "");
> + static_assert(test_copy("hello world", 10), "");
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130513/5b12c66b/attachment.html>
More information about the cfe-commits
mailing list