From: Fariborz Jahanian Date: Tue, 17 Jan 2012 23:39:50 +0000 (+0000) Subject: Folding away unreachable case statement. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=985df1c1f2d0666a09bc03f3593929286b0dea65;p=clang Folding away unreachable case statement. patch (slightly revised) by Aaron Ballman. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148359 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index ee4a272ea8..c7a8cf6a7d 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -883,10 +883,8 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) { // when we've constant-folded the switch, are emitting the constant case, // and part of the constant case includes another case statement. For // instance: switch (4) { case 4: do { case 5: } while (1); } - if (!SwitchInsn) { - EmitStmt(S.getSubStmt()); + if (!SwitchInsn) return; - } // Handle case ranges. if (S.getRHS()) { @@ -1162,6 +1160,10 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { if (S.getConditionVariable()) EmitAutoVarDecl(*S.getConditionVariable()); + // Handle nested switch statements. + llvm::SwitchInst *SavedSwitchInsn = SwitchInsn; + llvm::BasicBlock *SavedCRBlock = CaseRangeBlock; + // See if we can constant fold the condition of the switch and therefore only // emit the live case statement (if any) of the switch. llvm::APInt ConstantCondValue; @@ -1171,20 +1173,26 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { getContext())) { RunCleanupsScope ExecutedScope(*this); + // At this point, we are no longer "within" a switch instance, so + // we can temporarily enforce this to ensure that any embedded case + // statements are not emitted. + SwitchInsn = 0; + // Okay, we can dead code eliminate everything except this case. Emit the // specified series of statements and we're good. for (unsigned i = 0, e = CaseStmts.size(); i != e; ++i) EmitStmt(CaseStmts[i]); + + // Now we want to restore the saved switch instance so that nested switches + // continue to function properly + SwitchInsn = SavedSwitchInsn; + return; } } llvm::Value *CondV = EmitScalarExpr(S.getCond()); - // Handle nested switch statements. - llvm::SwitchInst *SavedSwitchInsn = SwitchInsn; - llvm::BasicBlock *SavedCRBlock = CaseRangeBlock; - // Create basic block to hold stuff that comes after switch // statement. We also need to create a default block now so that // explicit case ranges tests can have a place to jump to on diff --git a/test/CodeGenCXX/switch-case-folding-2.cpp b/test/CodeGenCXX/switch-case-folding-2.cpp new file mode 100644 index 0000000000..e1e66cfa3b --- /dev/null +++ b/test/CodeGenCXX/switch-case-folding-2.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s +// CHECK that we don't crash. + +extern int printf(const char*, ...); +int test(int val){ + switch (val) { + case 4: + do { + switch (6) { + case 6: do { case 5: printf("bad\n"); } while (0); + }; + } while (0); + } + return 0; +} + +int main(void) { + return test(5); +} + +// CHECK-NOT: call i32 (i8*, ...)* @printf(