mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
IRGen for break/continue.
Swift SVN r2089
This commit is contained in:
@@ -21,7 +21,6 @@
|
||||
|
||||
namespace swift {
|
||||
namespace irgen {
|
||||
class IRGenFunction;
|
||||
|
||||
// These classes are private to GenCleanup.cpp.
|
||||
class CleanupControl;
|
||||
|
||||
@@ -33,13 +33,13 @@ namespace irgen {
|
||||
/// cleanup.
|
||||
class ManagedValue {
|
||||
llvm::Value *Value;
|
||||
IRGenFunction::CleanupsDepth Cleanup;
|
||||
CleanupsDepth Cleanup;
|
||||
|
||||
public:
|
||||
ManagedValue() = default;
|
||||
explicit ManagedValue(llvm::Value *value)
|
||||
: Value(value), Cleanup(IRGenFunction::CleanupsDepth::invalid()) {}
|
||||
ManagedValue(llvm::Value *value, IRGenFunction::CleanupsDepth cleanup)
|
||||
: Value(value), Cleanup(CleanupsDepth::invalid()) {}
|
||||
ManagedValue(llvm::Value *value, CleanupsDepth cleanup)
|
||||
: Value(value), Cleanup(cleanup) {}
|
||||
|
||||
llvm::Value *getUnmanagedValue() const {
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
llvm::Value *getValue() const { return Value; }
|
||||
|
||||
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
|
||||
/// underlying value.
|
||||
@@ -60,8 +60,7 @@ public:
|
||||
}
|
||||
|
||||
/// Split this value into its underlying value and, if present, its cleanup.
|
||||
llvm::Value *split(llvm::SmallVectorImpl<IRGenFunction::CleanupsDepth>
|
||||
&cleanups) {
|
||||
llvm::Value *split(llvm::SmallVectorImpl<CleanupsDepth> &cleanups) {
|
||||
if (hasCleanup()) cleanups.push_back(getCleanup());
|
||||
return getValue();
|
||||
}
|
||||
|
||||
@@ -663,7 +663,7 @@ static void popAndEmitTopCleanup(IRGenFunction &IGF,
|
||||
/// Remove all the dead cleanups on the top of the cleanup stack.
|
||||
static void popAndEmitTopDeadCleanups(IRGenFunction &IGF,
|
||||
DiverseStackImpl<Cleanup> &stack,
|
||||
IRGenFunction::CleanupsDepth end) {
|
||||
CleanupsDepth end) {
|
||||
stack.checkIterator(end);
|
||||
|
||||
while (stack.stable_begin() != end && stack.begin()->isDead()) {
|
||||
|
||||
@@ -1040,7 +1040,7 @@ namespace {
|
||||
|
||||
unsigned LastArgWritten;
|
||||
SmallVector<llvm::Value*, 16> Args;
|
||||
SmallVector<IRGenFunction::CleanupsDepth, 16> ArgCleanups;
|
||||
SmallVector<CleanupsDepth, 16> ArgCleanups;
|
||||
|
||||
protected:
|
||||
CallEmitter(IRGenFunction &IGF, const Callee &callee,
|
||||
|
||||
@@ -591,7 +591,7 @@ namespace {
|
||||
/// Enter a cleanup to call swift_dealloc on the given pointer.
|
||||
/// This cleanup will usually be deactivated as soon as the
|
||||
/// initializer completes.
|
||||
IRGenFunction::CleanupsDepth
|
||||
CleanupsDepth
|
||||
IRGenFunction::pushDeallocCleanup(llvm::Value *allocation,
|
||||
llvm::Value *size) {
|
||||
pushFullExprCleanup<CallDealloc>(allocation, size);
|
||||
|
||||
@@ -70,7 +70,7 @@ static OnHeap_t isOnHeap(VarDecl *var) {
|
||||
void Initialization::registerObject(IRGenFunction &IGF, Object object,
|
||||
OnHeap_t onHeap, const TypeInfo &objectTI) {
|
||||
// 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.
|
||||
if (onHeap || !objectTI.isPOD(ResilienceScope::Local)) {
|
||||
@@ -78,24 +78,24 @@ void Initialization::registerObject(IRGenFunction &IGF, Object object,
|
||||
objectTI);
|
||||
destroy = IGF.getCleanupsDepth();
|
||||
} else {
|
||||
destroy = IRGenFunction::CleanupsDepth::invalid();
|
||||
destroy = CleanupsDepth::invalid();
|
||||
}
|
||||
|
||||
registerObject(object, destroy);
|
||||
}
|
||||
|
||||
void Initialization::registerObjectWithoutDestroy(Object object) {
|
||||
registerObject(object, IRGenFunction::CleanupsDepth::invalid());
|
||||
registerObject(object, CleanupsDepth::invalid());
|
||||
}
|
||||
|
||||
/// Register an object with the initialization process.
|
||||
void Initialization::registerObject(Object object,
|
||||
IRGenFunction::CleanupsDepth destroy) {
|
||||
CleanupsDepth destroy) {
|
||||
// The invariant is that the cleanup has to be an
|
||||
// UnboundDestroy if it's valid.
|
||||
|
||||
ValueRecord record = {
|
||||
IRGenFunction::CleanupsDepth::invalid(), destroy
|
||||
CleanupsDepth::invalid(), destroy
|
||||
};
|
||||
Records.insert(std::make_pair(object.Opaque, record));
|
||||
}
|
||||
@@ -103,7 +103,7 @@ void Initialization::registerObject(Object object,
|
||||
/// Mark that an object has been allocated.
|
||||
void Initialization::markAllocated(IRGenFunction &IGF, Object object,
|
||||
OwnedAddress address,
|
||||
IRGenFunction::CleanupsDepth dealloc) {
|
||||
CleanupsDepth dealloc) {
|
||||
ValueRecord &record = Records.find(object.Opaque)->second;
|
||||
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 (type.isEmpty(ResilienceScope::Local)) {
|
||||
OwnedAddress addr = createEmptyAlloca(IGF.IGM, type);
|
||||
markAllocated(IGF, object, addr, IRGenFunction::CleanupsDepth::invalid());
|
||||
markAllocated(IGF, object, addr, CleanupsDepth::invalid());
|
||||
return addr;
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ Initialization::emitLocalAllocation(IRGenFunction &IGF, Object object,
|
||||
// TODO: lifetime intrinsics?
|
||||
|
||||
OwnedAddress addr(rawAddr, IGF.IGM.RefCountedNull);
|
||||
markAllocated(IGF, object, addr, IRGenFunction::CleanupsDepth::invalid());
|
||||
markAllocated(IGF, object, addr, CleanupsDepth::invalid());
|
||||
return addr;
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ Initialization::emitLocalAllocation(IRGenFunction &IGF, Object object,
|
||||
|
||||
// Push a cleanup to dealloc the allocation.
|
||||
// FIXME: don't emit the size twice!
|
||||
IRGenFunction::CleanupsDepth deallocCleanup
|
||||
CleanupsDepth deallocCleanup
|
||||
= IGF.pushDeallocCleanup(allocation, layout.emitSize(IGF));
|
||||
|
||||
OwnedAddress addr(rawAddr, allocation);
|
||||
@@ -201,7 +201,7 @@ Initialization::emitLocalAllocation(IRGenFunction &IGF, Object object,
|
||||
}
|
||||
|
||||
static void maybeSetCleanupState(IRGenFunction &IGF,
|
||||
IRGenFunction::CleanupsDepth maybeCleanup,
|
||||
CleanupsDepth maybeCleanup,
|
||||
CleanupState newState) {
|
||||
if (maybeCleanup.isValid())
|
||||
IGF.setCleanupState(maybeCleanup, newState);
|
||||
|
||||
@@ -46,8 +46,8 @@ namespace irgen {
|
||||
/// variable initialization.
|
||||
class Initialization {
|
||||
struct ValueRecord {
|
||||
IRGenFunction::CleanupsDepth DeallocCleanup;
|
||||
IRGenFunction::CleanupsDepth DestroyCleanup;
|
||||
CleanupsDepth DeallocCleanup;
|
||||
CleanupsDepth DestroyCleanup;
|
||||
};
|
||||
|
||||
llvm::DenseMap<void *, ValueRecord> Records;
|
||||
@@ -108,14 +108,14 @@ public:
|
||||
/// trivial and there isn't a dealloc cleanup.
|
||||
void markAllocated(IRGenFunction &IGF, Object object,
|
||||
OwnedAddress address,
|
||||
IRGenFunction::CleanupsDepth dealloc);
|
||||
CleanupsDepth dealloc);
|
||||
|
||||
/// Mark that the value has reached its instant of initialization.
|
||||
void markInitialized(IRGenFunction &IGF, Object object);
|
||||
|
||||
private:
|
||||
/// 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
|
||||
|
||||
@@ -1828,8 +1828,7 @@ namespace {
|
||||
|
||||
// Pull off the outer result.
|
||||
FixedPacking innerResultPacking;
|
||||
IRGenFunction::CleanupsDepth outerResultCleanup
|
||||
= IRGenFunction::CleanupsDepth::invalid();
|
||||
CleanupsDepth outerResultCleanup = CleanupsDepth::invalid();
|
||||
if (HasAbstractedResult) {
|
||||
outerResult = Address(outerArgs.claimUnmanagedNext(),
|
||||
getFixedBufferAlignment(IGM));
|
||||
@@ -2182,7 +2181,7 @@ void irgen::emitErasureAsInit(IRGenFunction &IGF, ErasureExpr *E,
|
||||
Address object = emitAllocateBuffer(IGF, buffer, packing, concreteTI);
|
||||
|
||||
// Push a cleanup to destroy that.
|
||||
IRGenFunction::CleanupsDepth deallocCleanup;
|
||||
CleanupsDepth deallocCleanup;
|
||||
bool needsDeallocCleanup = !isNeverAllocated(packing);
|
||||
if (needsDeallocCleanup) {
|
||||
IGF.pushFullExprCleanup<DeallocateBuffer>(buffer, packing, concreteTI);
|
||||
|
||||
@@ -57,12 +57,10 @@ void IRGenFunction::emitStmt(Stmt *S) {
|
||||
return emitForEachStmt(cast<ForEachStmt>(S));
|
||||
|
||||
case StmtKind::Break:
|
||||
unimplemented(cast<BreakStmt>(S)->getLoc(), "break statement");
|
||||
return;
|
||||
return emitBreakStmt(cast<BreakStmt>(S));
|
||||
|
||||
case StmtKind::Continue:
|
||||
unimplemented(cast<ContinueStmt>(S)->getLoc(), "continue statement");
|
||||
return;
|
||||
return emitContinueStmt(cast<ContinueStmt>(S));
|
||||
}
|
||||
llvm_unreachable("bad statement kind!");
|
||||
}
|
||||
@@ -136,12 +134,29 @@ void IRGenFunction::emitReturnStmt(ReturnStmt *S) {
|
||||
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) {
|
||||
// Create a new basic block and jump into it.
|
||||
llvm::BasicBlock *loopBB = createBasicBlock("while");
|
||||
Builder.CreateBr(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
|
||||
// to the continuation block.
|
||||
Condition cond = emitCondition(S->getCond(), /*hasFalseCode*/ false);
|
||||
@@ -159,6 +174,10 @@ void IRGenFunction::emitWhileStmt(WhileStmt *S) {
|
||||
|
||||
// Complete the conditional execution.
|
||||
cond.complete(*this);
|
||||
|
||||
emitOrDeleteBlock(*this, endBB);
|
||||
BreakDestStack.pop_back();
|
||||
ContinueDestStack.pop_back();
|
||||
}
|
||||
|
||||
void IRGenFunction::emitForStmt(ForStmt *S) {
|
||||
@@ -185,6 +204,12 @@ void IRGenFunction::emitForStmt(ForStmt *S) {
|
||||
Builder.CreateBr(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
|
||||
// to the continuation block.
|
||||
Condition cond = S->getCond().isNonNull() ?
|
||||
@@ -196,6 +221,8 @@ void IRGenFunction::emitForStmt(ForStmt *S) {
|
||||
cond.enterTrue(*this);
|
||||
emitStmt(S->getBody());
|
||||
|
||||
emitOrDeleteBlock(*this, incBB);
|
||||
|
||||
if (Builder.hasValidIP() && !S->getIncrement().isNull()) {
|
||||
if (Expr *E = S->getIncrement().dyn_cast<Expr*>()) {
|
||||
FullExpr scope(*this);
|
||||
@@ -215,6 +242,9 @@ void IRGenFunction::emitForStmt(ForStmt *S) {
|
||||
// Complete the conditional execution.
|
||||
cond.complete(*this);
|
||||
|
||||
emitOrDeleteBlock(*this, endBB);
|
||||
BreakDestStack.pop_back();
|
||||
ContinueDestStack.pop_back();
|
||||
}
|
||||
|
||||
void IRGenFunction::emitForEachStmt(ForEachStmt *S) {
|
||||
@@ -227,9 +257,14 @@ void IRGenFunction::emitForEachStmt(ForEachStmt *S) {
|
||||
if (!Builder.hasValidIP()) return;
|
||||
|
||||
// Create a new basic block and jump into it.
|
||||
llvm::BasicBlock *LoopBB = createBasicBlock("foreach.cond");
|
||||
Builder.CreateBr(LoopBB);
|
||||
Builder.emitBlock(LoopBB);
|
||||
llvm::BasicBlock *loopBB = createBasicBlock("foreach.cond");
|
||||
Builder.CreateBr(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,
|
||||
/*invertValue=*/true);
|
||||
@@ -247,7 +282,7 @@ void IRGenFunction::emitForEachStmt(ForEachStmt *S) {
|
||||
|
||||
// Loop back to the header.
|
||||
if (Builder.hasValidIP()) {
|
||||
Builder.CreateBr(LoopBB);
|
||||
Builder.CreateBr(loopBB);
|
||||
Builder.ClearInsertionPoint();
|
||||
}
|
||||
Cond.exitTrue(*this);
|
||||
@@ -255,5 +290,18 @@ void IRGenFunction::emitForEachStmt(ForEachStmt *S) {
|
||||
|
||||
// Complete the conditional execution.
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "DiverseStack.h"
|
||||
#include "IRBuilder.h"
|
||||
#include "JumpDest.h"
|
||||
|
||||
namespace llvm {
|
||||
class AllocaInst;
|
||||
@@ -33,7 +34,9 @@ namespace llvm {
|
||||
namespace swift {
|
||||
class AssignStmt;
|
||||
class BraceStmt;
|
||||
class BreakStmt;
|
||||
class ClassType;
|
||||
class ContinueStmt;
|
||||
class Decl;
|
||||
class Expr;
|
||||
class ExtensionDecl;
|
||||
@@ -56,13 +59,11 @@ namespace swift {
|
||||
class WhileStmt;
|
||||
|
||||
namespace irgen {
|
||||
class Cleanup;
|
||||
class Condition;
|
||||
class Explosion;
|
||||
enum class ExplosionKind : unsigned;
|
||||
class HeapLayout;
|
||||
class IRGenModule;
|
||||
class JumpDest;
|
||||
class LinkEntity;
|
||||
class LValue;
|
||||
class ManagedValue;
|
||||
@@ -175,8 +176,6 @@ public:
|
||||
return pushCleanupInState<T, A...>(state, ::std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
typedef DiverseStackImpl<Cleanup>::stable_iterator CleanupsDepth;
|
||||
|
||||
/// Retun a stable reference to the current cleanup.
|
||||
CleanupsDepth getCleanupsDepth() const {
|
||||
return Cleanups.stable_begin();
|
||||
@@ -208,6 +207,8 @@ private:
|
||||
llvm::BasicBlock *UnreachableBB;
|
||||
llvm::Instruction *JumpDestSlot;
|
||||
CleanupsDepth InnermostScope;
|
||||
std::vector<JumpDest> BreakDestStack;
|
||||
std::vector<JumpDest> ContinueDestStack;
|
||||
|
||||
friend class Scope;
|
||||
Cleanup &initCleanup(Cleanup &cleanup, size_t allocSize, CleanupState state);
|
||||
@@ -276,6 +277,8 @@ private:
|
||||
void emitWhileStmt(WhileStmt *S);
|
||||
void emitForStmt(ForStmt *S);
|
||||
void emitForEachStmt(ForEachStmt *S);
|
||||
void emitBreakStmt(BreakStmt *S);
|
||||
void emitContinueStmt(ContinueStmt *S);
|
||||
|
||||
//--- Expression emission ------------------------------------------------------
|
||||
public:
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#ifndef SWIFT_IRGEN_JUMPDEST_H
|
||||
#define SWIFT_IRGEN_JUMPDEST_H
|
||||
|
||||
#include "IRGenFunction.h"
|
||||
#include "DiverseStack.h"
|
||||
|
||||
namespace llvm {
|
||||
class BasicBlock;
|
||||
@@ -26,18 +26,21 @@ namespace llvm {
|
||||
namespace swift {
|
||||
namespace irgen {
|
||||
|
||||
class Cleanup;
|
||||
typedef DiverseStackImpl<Cleanup>::stable_iterator CleanupsDepth;
|
||||
|
||||
/// The destination of a direct jump. Swift currently does not
|
||||
/// support indirect branches or goto, so the jump mechanism only
|
||||
/// needs to worry about branches into scopes, not out of them.
|
||||
class JumpDest {
|
||||
llvm::BasicBlock *Block;
|
||||
IRGenFunction::CleanupsDepth Depth;
|
||||
CleanupsDepth Depth;
|
||||
public:
|
||||
JumpDest(llvm::BasicBlock *block, IRGenFunction::CleanupsDepth depth)
|
||||
JumpDest(llvm::BasicBlock *block, CleanupsDepth depth)
|
||||
: Block(block), Depth(depth) {}
|
||||
|
||||
llvm::BasicBlock *getBlock() const { return Block; }
|
||||
IRGenFunction::CleanupsDepth getDepth() const { return Depth; }
|
||||
CleanupsDepth getDepth() const { return Depth; }
|
||||
};
|
||||
|
||||
} // end namespace irgen
|
||||
|
||||
@@ -26,8 +26,8 @@ namespace irgen {
|
||||
/// statement) has been entered.
|
||||
class Scope {
|
||||
IRGenFunction &IGF;
|
||||
IRGenFunction::CleanupsDepth Depth;
|
||||
IRGenFunction::CleanupsDepth SavedInnermostScope;
|
||||
CleanupsDepth Depth;
|
||||
CleanupsDepth SavedInnermostScope;
|
||||
|
||||
void popImpl() {
|
||||
IGF.Cleanups.checkIterator(Depth);
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
void pop() {
|
||||
assert(Depth.isValid() && "popping a scope twice!");
|
||||
popImpl();
|
||||
Depth = IRGenFunction::CleanupsDepth::invalid();
|
||||
Depth = CleanupsDepth::invalid();
|
||||
}
|
||||
|
||||
~Scope() {
|
||||
|
||||
134
test/Interpreter/break_continue.swift
Normal file
134
test/Interpreter/break_continue.swift
Normal 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
|
||||
Reference in New Issue
Block a user