IRGen for break/continue.

Swift SVN r2089
This commit is contained in:
Eli Friedman
2012-05-31 02:45:18 +00:00
parent c404598fcb
commit 26bebcfd61
13 changed files with 234 additions and 49 deletions

View File

@@ -21,7 +21,6 @@
namespace swift { namespace swift {
namespace irgen { namespace irgen {
class IRGenFunction;
// These classes are private to GenCleanup.cpp. // These classes are private to GenCleanup.cpp.
class CleanupControl; class CleanupControl;

View File

@@ -33,13 +33,13 @@ namespace irgen {
/// cleanup. /// cleanup.
class ManagedValue { class ManagedValue {
llvm::Value *Value; llvm::Value *Value;
IRGenFunction::CleanupsDepth Cleanup; CleanupsDepth Cleanup;
public: public:
ManagedValue() = default; ManagedValue() = default;
explicit ManagedValue(llvm::Value *value) explicit ManagedValue(llvm::Value *value)
: Value(value), Cleanup(IRGenFunction::CleanupsDepth::invalid()) {} : Value(value), Cleanup(CleanupsDepth::invalid()) {}
ManagedValue(llvm::Value *value, IRGenFunction::CleanupsDepth cleanup) ManagedValue(llvm::Value *value, CleanupsDepth cleanup)
: Value(value), Cleanup(cleanup) {} : Value(value), Cleanup(cleanup) {}
llvm::Value *getUnmanagedValue() const { llvm::Value *getUnmanagedValue() const {
@@ -49,7 +49,7 @@ public:
llvm::Value *getValue() const { return Value; } llvm::Value *getValue() const { return Value; }
bool hasCleanup() const { return Cleanup.isValid(); } bool hasCleanup() const { return Cleanup.isValid(); }
IRGenFunction::CleanupsDepth getCleanup() const { return Cleanup; } CleanupsDepth getCleanup() const { return Cleanup; }
/// Forward this value, deactivating the cleanup and returning the /// Forward this value, deactivating the cleanup and returning the
/// underlying value. /// underlying value.
@@ -60,8 +60,7 @@ public:
} }
/// Split this value into its underlying value and, if present, its cleanup. /// Split this value into its underlying value and, if present, its cleanup.
llvm::Value *split(llvm::SmallVectorImpl<IRGenFunction::CleanupsDepth> llvm::Value *split(llvm::SmallVectorImpl<CleanupsDepth> &cleanups) {
&cleanups) {
if (hasCleanup()) cleanups.push_back(getCleanup()); if (hasCleanup()) cleanups.push_back(getCleanup());
return getValue(); return getValue();
} }

View File

@@ -663,7 +663,7 @@ static void popAndEmitTopCleanup(IRGenFunction &IGF,
/// Remove all the dead cleanups on the top of the cleanup stack. /// Remove all the dead cleanups on the top of the cleanup stack.
static void popAndEmitTopDeadCleanups(IRGenFunction &IGF, static void popAndEmitTopDeadCleanups(IRGenFunction &IGF,
DiverseStackImpl<Cleanup> &stack, DiverseStackImpl<Cleanup> &stack,
IRGenFunction::CleanupsDepth end) { CleanupsDepth end) {
stack.checkIterator(end); stack.checkIterator(end);
while (stack.stable_begin() != end && stack.begin()->isDead()) { while (stack.stable_begin() != end && stack.begin()->isDead()) {

View File

@@ -1040,7 +1040,7 @@ namespace {
unsigned LastArgWritten; unsigned LastArgWritten;
SmallVector<llvm::Value*, 16> Args; SmallVector<llvm::Value*, 16> Args;
SmallVector<IRGenFunction::CleanupsDepth, 16> ArgCleanups; SmallVector<CleanupsDepth, 16> ArgCleanups;
protected: protected:
CallEmitter(IRGenFunction &IGF, const Callee &callee, CallEmitter(IRGenFunction &IGF, const Callee &callee,

View File

@@ -591,7 +591,7 @@ namespace {
/// Enter a cleanup to call swift_dealloc on the given pointer. /// Enter a cleanup to call swift_dealloc on the given pointer.
/// This cleanup will usually be deactivated as soon as the /// This cleanup will usually be deactivated as soon as the
/// initializer completes. /// initializer completes.
IRGenFunction::CleanupsDepth CleanupsDepth
IRGenFunction::pushDeallocCleanup(llvm::Value *allocation, IRGenFunction::pushDeallocCleanup(llvm::Value *allocation,
llvm::Value *size) { llvm::Value *size) {
pushFullExprCleanup<CallDealloc>(allocation, size); pushFullExprCleanup<CallDealloc>(allocation, size);

View File

@@ -70,7 +70,7 @@ static OnHeap_t isOnHeap(VarDecl *var) {
void Initialization::registerObject(IRGenFunction &IGF, Object object, void Initialization::registerObject(IRGenFunction &IGF, Object object,
OnHeap_t onHeap, const TypeInfo &objectTI) { OnHeap_t onHeap, const TypeInfo &objectTI) {
// Create the appropriate destroy cleanup. // Create the appropriate destroy cleanup.
IRGenFunction::CleanupsDepth destroy; CleanupsDepth destroy;
// We need a destroy cleanup if the object is on the heap or non-POD. // We need a destroy cleanup if the object is on the heap or non-POD.
if (onHeap || !objectTI.isPOD(ResilienceScope::Local)) { if (onHeap || !objectTI.isPOD(ResilienceScope::Local)) {
@@ -78,24 +78,24 @@ void Initialization::registerObject(IRGenFunction &IGF, Object object,
objectTI); objectTI);
destroy = IGF.getCleanupsDepth(); destroy = IGF.getCleanupsDepth();
} else { } else {
destroy = IRGenFunction::CleanupsDepth::invalid(); destroy = CleanupsDepth::invalid();
} }
registerObject(object, destroy); registerObject(object, destroy);
} }
void Initialization::registerObjectWithoutDestroy(Object object) { void Initialization::registerObjectWithoutDestroy(Object object) {
registerObject(object, IRGenFunction::CleanupsDepth::invalid()); registerObject(object, CleanupsDepth::invalid());
} }
/// Register an object with the initialization process. /// Register an object with the initialization process.
void Initialization::registerObject(Object object, void Initialization::registerObject(Object object,
IRGenFunction::CleanupsDepth destroy) { CleanupsDepth destroy) {
// The invariant is that the cleanup has to be an // The invariant is that the cleanup has to be an
// UnboundDestroy if it's valid. // UnboundDestroy if it's valid.
ValueRecord record = { ValueRecord record = {
IRGenFunction::CleanupsDepth::invalid(), destroy CleanupsDepth::invalid(), destroy
}; };
Records.insert(std::make_pair(object.Opaque, record)); Records.insert(std::make_pair(object.Opaque, record));
} }
@@ -103,7 +103,7 @@ void Initialization::registerObject(Object object,
/// Mark that an object has been allocated. /// Mark that an object has been allocated.
void Initialization::markAllocated(IRGenFunction &IGF, Object object, void Initialization::markAllocated(IRGenFunction &IGF, Object object,
OwnedAddress address, OwnedAddress address,
IRGenFunction::CleanupsDepth dealloc) { CleanupsDepth dealloc) {
ValueRecord &record = Records.find(object.Opaque)->second; ValueRecord &record = Records.find(object.Opaque)->second;
record.DeallocCleanup = dealloc; record.DeallocCleanup = dealloc;
@@ -161,7 +161,7 @@ Initialization::emitLocalAllocation(IRGenFunction &IGF, Object object,
// If the type is known to be empty, don't actually allocate anything. // If the type is known to be empty, don't actually allocate anything.
if (type.isEmpty(ResilienceScope::Local)) { if (type.isEmpty(ResilienceScope::Local)) {
OwnedAddress addr = createEmptyAlloca(IGF.IGM, type); OwnedAddress addr = createEmptyAlloca(IGF.IGM, type);
markAllocated(IGF, object, addr, IRGenFunction::CleanupsDepth::invalid()); markAllocated(IGF, object, addr, CleanupsDepth::invalid());
return addr; return addr;
} }
@@ -173,7 +173,7 @@ Initialization::emitLocalAllocation(IRGenFunction &IGF, Object object,
// TODO: lifetime intrinsics? // TODO: lifetime intrinsics?
OwnedAddress addr(rawAddr, IGF.IGM.RefCountedNull); OwnedAddress addr(rawAddr, IGF.IGM.RefCountedNull);
markAllocated(IGF, object, addr, IRGenFunction::CleanupsDepth::invalid()); markAllocated(IGF, object, addr, CleanupsDepth::invalid());
return addr; return addr;
} }
@@ -192,7 +192,7 @@ Initialization::emitLocalAllocation(IRGenFunction &IGF, Object object,
// Push a cleanup to dealloc the allocation. // Push a cleanup to dealloc the allocation.
// FIXME: don't emit the size twice! // FIXME: don't emit the size twice!
IRGenFunction::CleanupsDepth deallocCleanup CleanupsDepth deallocCleanup
= IGF.pushDeallocCleanup(allocation, layout.emitSize(IGF)); = IGF.pushDeallocCleanup(allocation, layout.emitSize(IGF));
OwnedAddress addr(rawAddr, allocation); OwnedAddress addr(rawAddr, allocation);
@@ -201,7 +201,7 @@ Initialization::emitLocalAllocation(IRGenFunction &IGF, Object object,
} }
static void maybeSetCleanupState(IRGenFunction &IGF, static void maybeSetCleanupState(IRGenFunction &IGF,
IRGenFunction::CleanupsDepth maybeCleanup, CleanupsDepth maybeCleanup,
CleanupState newState) { CleanupState newState) {
if (maybeCleanup.isValid()) if (maybeCleanup.isValid())
IGF.setCleanupState(maybeCleanup, newState); IGF.setCleanupState(maybeCleanup, newState);

View File

@@ -46,8 +46,8 @@ namespace irgen {
/// variable initialization. /// variable initialization.
class Initialization { class Initialization {
struct ValueRecord { struct ValueRecord {
IRGenFunction::CleanupsDepth DeallocCleanup; CleanupsDepth DeallocCleanup;
IRGenFunction::CleanupsDepth DestroyCleanup; CleanupsDepth DestroyCleanup;
}; };
llvm::DenseMap<void *, ValueRecord> Records; llvm::DenseMap<void *, ValueRecord> Records;
@@ -108,14 +108,14 @@ public:
/// trivial and there isn't a dealloc cleanup. /// trivial and there isn't a dealloc cleanup.
void markAllocated(IRGenFunction &IGF, Object object, void markAllocated(IRGenFunction &IGF, Object object,
OwnedAddress address, OwnedAddress address,
IRGenFunction::CleanupsDepth dealloc); CleanupsDepth dealloc);
/// Mark that the value has reached its instant of initialization. /// Mark that the value has reached its instant of initialization.
void markInitialized(IRGenFunction &IGF, Object object); void markInitialized(IRGenFunction &IGF, Object object);
private: private:
/// Add an object that is going to be initialized. /// Add an object that is going to be initialized.
void registerObject(Object object, IRGenFunction::CleanupsDepth destroy); void registerObject(Object object, CleanupsDepth destroy);
}; };
} // end namespace irgen } // end namespace irgen

View File

@@ -1828,8 +1828,7 @@ namespace {
// Pull off the outer result. // Pull off the outer result.
FixedPacking innerResultPacking; FixedPacking innerResultPacking;
IRGenFunction::CleanupsDepth outerResultCleanup CleanupsDepth outerResultCleanup = CleanupsDepth::invalid();
= IRGenFunction::CleanupsDepth::invalid();
if (HasAbstractedResult) { if (HasAbstractedResult) {
outerResult = Address(outerArgs.claimUnmanagedNext(), outerResult = Address(outerArgs.claimUnmanagedNext(),
getFixedBufferAlignment(IGM)); getFixedBufferAlignment(IGM));
@@ -2182,7 +2181,7 @@ void irgen::emitErasureAsInit(IRGenFunction &IGF, ErasureExpr *E,
Address object = emitAllocateBuffer(IGF, buffer, packing, concreteTI); Address object = emitAllocateBuffer(IGF, buffer, packing, concreteTI);
// Push a cleanup to destroy that. // Push a cleanup to destroy that.
IRGenFunction::CleanupsDepth deallocCleanup; CleanupsDepth deallocCleanup;
bool needsDeallocCleanup = !isNeverAllocated(packing); bool needsDeallocCleanup = !isNeverAllocated(packing);
if (needsDeallocCleanup) { if (needsDeallocCleanup) {
IGF.pushFullExprCleanup<DeallocateBuffer>(buffer, packing, concreteTI); IGF.pushFullExprCleanup<DeallocateBuffer>(buffer, packing, concreteTI);

View File

@@ -57,12 +57,10 @@ void IRGenFunction::emitStmt(Stmt *S) {
return emitForEachStmt(cast<ForEachStmt>(S)); return emitForEachStmt(cast<ForEachStmt>(S));
case StmtKind::Break: case StmtKind::Break:
unimplemented(cast<BreakStmt>(S)->getLoc(), "break statement"); return emitBreakStmt(cast<BreakStmt>(S));
return;
case StmtKind::Continue: case StmtKind::Continue:
unimplemented(cast<ContinueStmt>(S)->getLoc(), "continue statement"); return emitContinueStmt(cast<ContinueStmt>(S));
return;
} }
llvm_unreachable("bad statement kind!"); llvm_unreachable("bad statement kind!");
} }
@@ -136,12 +134,29 @@ void IRGenFunction::emitReturnStmt(ReturnStmt *S) {
Builder.ClearInsertionPoint(); Builder.ClearInsertionPoint();
} }
static void emitOrDeleteBlock(IRGenFunction &IGF, llvm::BasicBlock *BB) {
if (BB->use_empty()) {
// If the block is unused, we don't need it; just delete it.
delete BB;
} else {
// Otherwise, continue emitting code in BB.
if (IGF.Builder.hasValidIP())
IGF.Builder.CreateBr(BB);
IGF.Builder.emitBlockAnywhere(BB);
}
}
void IRGenFunction::emitWhileStmt(WhileStmt *S) { void IRGenFunction::emitWhileStmt(WhileStmt *S) {
// Create a new basic block and jump into it. // Create a new basic block and jump into it.
llvm::BasicBlock *loopBB = createBasicBlock("while"); llvm::BasicBlock *loopBB = createBasicBlock("while");
Builder.CreateBr(loopBB); Builder.CreateBr(loopBB);
Builder.emitBlock(loopBB); Builder.emitBlock(loopBB);
// Set the destinations for 'break' and 'continue'
llvm::BasicBlock *endBB = createBasicBlock("while.end");
BreakDestStack.emplace_back(endBB, getCleanupsDepth());
ContinueDestStack.emplace_back(loopBB, getCleanupsDepth());
// Evaluate the condition with the false edge leading directly // Evaluate the condition with the false edge leading directly
// to the continuation block. // to the continuation block.
Condition cond = emitCondition(S->getCond(), /*hasFalseCode*/ false); Condition cond = emitCondition(S->getCond(), /*hasFalseCode*/ false);
@@ -159,6 +174,10 @@ void IRGenFunction::emitWhileStmt(WhileStmt *S) {
// Complete the conditional execution. // Complete the conditional execution.
cond.complete(*this); cond.complete(*this);
emitOrDeleteBlock(*this, endBB);
BreakDestStack.pop_back();
ContinueDestStack.pop_back();
} }
void IRGenFunction::emitForStmt(ForStmt *S) { void IRGenFunction::emitForStmt(ForStmt *S) {
@@ -184,7 +203,13 @@ void IRGenFunction::emitForStmt(ForStmt *S) {
llvm::BasicBlock *loopBB = createBasicBlock("for.condition"); llvm::BasicBlock *loopBB = createBasicBlock("for.condition");
Builder.CreateBr(loopBB); Builder.CreateBr(loopBB);
Builder.emitBlock(loopBB); Builder.emitBlock(loopBB);
// Set the destinations for 'break' and 'continue'
llvm::BasicBlock *incBB = createBasicBlock("for.inc");
llvm::BasicBlock *endBB = createBasicBlock("for.end");
BreakDestStack.emplace_back(endBB, getCleanupsDepth());
ContinueDestStack.emplace_back(incBB, getCleanupsDepth());
// Evaluate the condition with the false edge leading directly // Evaluate the condition with the false edge leading directly
// to the continuation block. // to the continuation block.
Condition cond = S->getCond().isNonNull() ? Condition cond = S->getCond().isNonNull() ?
@@ -195,7 +220,9 @@ void IRGenFunction::emitForStmt(ForStmt *S) {
if (cond.hasTrue()) { if (cond.hasTrue()) {
cond.enterTrue(*this); cond.enterTrue(*this);
emitStmt(S->getBody()); emitStmt(S->getBody());
emitOrDeleteBlock(*this, incBB);
if (Builder.hasValidIP() && !S->getIncrement().isNull()) { if (Builder.hasValidIP() && !S->getIncrement().isNull()) {
if (Expr *E = S->getIncrement().dyn_cast<Expr*>()) { if (Expr *E = S->getIncrement().dyn_cast<Expr*>()) {
FullExpr scope(*this); FullExpr scope(*this);
@@ -215,6 +242,9 @@ void IRGenFunction::emitForStmt(ForStmt *S) {
// Complete the conditional execution. // Complete the conditional execution.
cond.complete(*this); cond.complete(*this);
emitOrDeleteBlock(*this, endBB);
BreakDestStack.pop_back();
ContinueDestStack.pop_back();
} }
void IRGenFunction::emitForEachStmt(ForEachStmt *S) { void IRGenFunction::emitForEachStmt(ForEachStmt *S) {
@@ -227,9 +257,14 @@ void IRGenFunction::emitForEachStmt(ForEachStmt *S) {
if (!Builder.hasValidIP()) return; if (!Builder.hasValidIP()) return;
// Create a new basic block and jump into it. // Create a new basic block and jump into it.
llvm::BasicBlock *LoopBB = createBasicBlock("foreach.cond"); llvm::BasicBlock *loopBB = createBasicBlock("foreach.cond");
Builder.CreateBr(LoopBB); Builder.CreateBr(loopBB);
Builder.emitBlock(LoopBB); Builder.emitBlock(loopBB);
// Set the destinations for 'break' and 'continue'
llvm::BasicBlock *endBB = createBasicBlock("foreach.end");
BreakDestStack.emplace_back(endBB, getCleanupsDepth());
ContinueDestStack.emplace_back(loopBB, getCleanupsDepth());
Condition Cond = emitCondition(S->getRangeEmpty(), /*hasFalseCode=*/false, Condition Cond = emitCondition(S->getRangeEmpty(), /*hasFalseCode=*/false,
/*invertValue=*/true); /*invertValue=*/true);
@@ -247,13 +282,26 @@ void IRGenFunction::emitForEachStmt(ForEachStmt *S) {
// Loop back to the header. // Loop back to the header.
if (Builder.hasValidIP()) { if (Builder.hasValidIP()) {
Builder.CreateBr(LoopBB); Builder.CreateBr(loopBB);
Builder.ClearInsertionPoint(); Builder.ClearInsertionPoint();
} }
Cond.exitTrue(*this); Cond.exitTrue(*this);
} }
// Complete the conditional execution. // Complete the conditional execution.
Cond.complete(*this); Cond.complete(*this);
emitOrDeleteBlock(*this, endBB);
BreakDestStack.pop_back();
ContinueDestStack.pop_back();
} }
void IRGenFunction::emitBreakStmt(BreakStmt *S) {
emitBranch(BreakDestStack.back());
Builder.ClearInsertionPoint();
}
void IRGenFunction::emitContinueStmt(ContinueStmt *S) {
emitBranch(ContinueDestStack.back());
Builder.ClearInsertionPoint();
}

View File

@@ -23,6 +23,7 @@
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "DiverseStack.h" #include "DiverseStack.h"
#include "IRBuilder.h" #include "IRBuilder.h"
#include "JumpDest.h"
namespace llvm { namespace llvm {
class AllocaInst; class AllocaInst;
@@ -33,7 +34,9 @@ namespace llvm {
namespace swift { namespace swift {
class AssignStmt; class AssignStmt;
class BraceStmt; class BraceStmt;
class BreakStmt;
class ClassType; class ClassType;
class ContinueStmt;
class Decl; class Decl;
class Expr; class Expr;
class ExtensionDecl; class ExtensionDecl;
@@ -56,13 +59,11 @@ namespace swift {
class WhileStmt; class WhileStmt;
namespace irgen { namespace irgen {
class Cleanup;
class Condition; class Condition;
class Explosion; class Explosion;
enum class ExplosionKind : unsigned; enum class ExplosionKind : unsigned;
class HeapLayout; class HeapLayout;
class IRGenModule; class IRGenModule;
class JumpDest;
class LinkEntity; class LinkEntity;
class LValue; class LValue;
class ManagedValue; class ManagedValue;
@@ -175,8 +176,6 @@ public:
return pushCleanupInState<T, A...>(state, ::std::forward<A>(args)...); return pushCleanupInState<T, A...>(state, ::std::forward<A>(args)...);
} }
typedef DiverseStackImpl<Cleanup>::stable_iterator CleanupsDepth;
/// Retun a stable reference to the current cleanup. /// Retun a stable reference to the current cleanup.
CleanupsDepth getCleanupsDepth() const { CleanupsDepth getCleanupsDepth() const {
return Cleanups.stable_begin(); return Cleanups.stable_begin();
@@ -208,6 +207,8 @@ private:
llvm::BasicBlock *UnreachableBB; llvm::BasicBlock *UnreachableBB;
llvm::Instruction *JumpDestSlot; llvm::Instruction *JumpDestSlot;
CleanupsDepth InnermostScope; CleanupsDepth InnermostScope;
std::vector<JumpDest> BreakDestStack;
std::vector<JumpDest> ContinueDestStack;
friend class Scope; friend class Scope;
Cleanup &initCleanup(Cleanup &cleanup, size_t allocSize, CleanupState state); Cleanup &initCleanup(Cleanup &cleanup, size_t allocSize, CleanupState state);
@@ -276,6 +277,8 @@ private:
void emitWhileStmt(WhileStmt *S); void emitWhileStmt(WhileStmt *S);
void emitForStmt(ForStmt *S); void emitForStmt(ForStmt *S);
void emitForEachStmt(ForEachStmt *S); void emitForEachStmt(ForEachStmt *S);
void emitBreakStmt(BreakStmt *S);
void emitContinueStmt(ContinueStmt *S);
//--- Expression emission ------------------------------------------------------ //--- Expression emission ------------------------------------------------------
public: public:

View File

@@ -17,7 +17,7 @@
#ifndef SWIFT_IRGEN_JUMPDEST_H #ifndef SWIFT_IRGEN_JUMPDEST_H
#define SWIFT_IRGEN_JUMPDEST_H #define SWIFT_IRGEN_JUMPDEST_H
#include "IRGenFunction.h" #include "DiverseStack.h"
namespace llvm { namespace llvm {
class BasicBlock; class BasicBlock;
@@ -26,18 +26,21 @@ namespace llvm {
namespace swift { namespace swift {
namespace irgen { namespace irgen {
class Cleanup;
typedef DiverseStackImpl<Cleanup>::stable_iterator CleanupsDepth;
/// The destination of a direct jump. Swift currently does not /// The destination of a direct jump. Swift currently does not
/// support indirect branches or goto, so the jump mechanism only /// support indirect branches or goto, so the jump mechanism only
/// needs to worry about branches into scopes, not out of them. /// needs to worry about branches into scopes, not out of them.
class JumpDest { class JumpDest {
llvm::BasicBlock *Block; llvm::BasicBlock *Block;
IRGenFunction::CleanupsDepth Depth; CleanupsDepth Depth;
public: public:
JumpDest(llvm::BasicBlock *block, IRGenFunction::CleanupsDepth depth) JumpDest(llvm::BasicBlock *block, CleanupsDepth depth)
: Block(block), Depth(depth) {} : Block(block), Depth(depth) {}
llvm::BasicBlock *getBlock() const { return Block; } llvm::BasicBlock *getBlock() const { return Block; }
IRGenFunction::CleanupsDepth getDepth() const { return Depth; } CleanupsDepth getDepth() const { return Depth; }
}; };
} // end namespace irgen } // end namespace irgen

View File

@@ -26,8 +26,8 @@ namespace irgen {
/// statement) has been entered. /// statement) has been entered.
class Scope { class Scope {
IRGenFunction &IGF; IRGenFunction &IGF;
IRGenFunction::CleanupsDepth Depth; CleanupsDepth Depth;
IRGenFunction::CleanupsDepth SavedInnermostScope; CleanupsDepth SavedInnermostScope;
void popImpl() { void popImpl() {
IGF.Cleanups.checkIterator(Depth); IGF.Cleanups.checkIterator(Depth);
@@ -51,7 +51,7 @@ public:
void pop() { void pop() {
assert(Depth.isValid() && "popping a scope twice!"); assert(Depth.isValid() && "popping a scope twice!");
popImpl(); popImpl();
Depth = IRGenFunction::CleanupsDepth::invalid(); Depth = CleanupsDepth::invalid();
} }
~Scope() { ~Scope() {

View File

@@ -0,0 +1,134 @@
// RUN: %swift -i %s | FileCheck %s
func test1() {
println("test1")
var i : Int
for i=0;;++i {
if i > 2 {
break
}
println(i)
continue
}
}
func test2() {
println("test2")
var i : Int
for i=0;i<10;++i {
if i > 2 {
continue
}
println(i)
}
}
func test3() {
println("test3")
var i : Int
for i=0;i<10;++i {
if i > 2 {
break
}
println(i)
}
}
func test4() {
println("test4")
for i in 0..10 {
if i > 2 {
break
}
println(i)
}
}
func test5() {
println("test5")
for i in 0..10 {
if i < 2 {
println(i)
continue
}
return
}
}
func test6() {
println("test6")
var i = 0
while (i < 10) {
if i < 2 {
println(i)
++i
continue
}
return
}
}
func test7() {
println("test7")
var i = 0
while (i < 10) {
if i < 2 {
println(i)
break
}
return
}
println("foo")
}
func test8() {
println("test8")
var i : Int
for i=0;;++i {
for j in 0..10 {
if j > 1 {
break
}
println(j)
}
if i > 2 {
break
}
println(i)
continue
}
}
println("start")
test1()
// CHECK: test1
// CHECK-NEXT: 0
// CHECK-NEXT: 1
// CHECK-NEXT: 2
test2()
// CHECK: test2
// CHECK-NEXT: 0
// CHECK-NEXT: 1
// CHECK-NEXT: 2
test3()
// CHECK: test3
// CHECK-NEXT: 0
// CHECK-NEXT: 1
// CHECK-NEXT: 2
test4()
// CHECK: test4
// CHECK-NEXT: 0
// CHECK-NEXT: 1
// CHECK-NEXT: 2
test5()
// CHECK: test5
// CHECK-NEXT: 0
// CHECK-NEXT: 1
test6()
// CHECK: test6
// CHECK-NEXT: 0
// CHECK-NEXT: 1
test7()
// CHECK: test7
// CHECK-NEXT: 0
// CHECK-NEXT: foo
test8()
// CHECK: test8
// CHECK-NEXT: 0
// CHECK-NEXT: 1
// CHECK-NEXT: 0
// CHECK-NEXT: 0
// CHECK-NEXT: 1
// CHECK-NEXT: 1