From 185b5013fe2154c2c8f9a0f2a2f044b49d14cfb9 Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Fri, 16 Aug 2013 13:03:14 +0400 Subject: [PATCH] Properly process nested try and loop blocks KT-3894: Loops and finally: finally block executed twice when break and return exists in try/finally block KT-3874: Compilation error on try catch block contains break and continue KT-3869: Loops and finally: outer finally block not run #KT-3869 Fixed #KT-3894 Fixed #KT-3874 Fixed --- .../jet/codegen/ExpressionCodegen.java | 74 +++++++++++-------- .../codegen/box/finally/finallyAndFinally.kt | 39 ++++++++++ .../testData/codegen/box/finally/kt3874.kt | 35 +++++++++ .../testData/codegen/box/finally/kt3894.kt | 36 +++++++++ .../codegen/box/finally/loopAndFinally.kt | 69 +++++++++++++++++ .../codegen/box/finally/tryLoopTry.kt | 36 +++++++++ .../BlackBoxCodegenTestGenerated.java | 25 +++++++ 7 files changed, 284 insertions(+), 30 deletions(-) create mode 100644 compiler/testData/codegen/box/finally/finallyAndFinally.kt create mode 100644 compiler/testData/codegen/box/finally/kt3874.kt create mode 100644 compiler/testData/codegen/box/finally/kt3894.kt create mode 100644 compiler/testData/codegen/box/finally/loopAndFinally.kt create mode 100644 compiler/testData/codegen/box/finally/tryLoopTry.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index f7c0fc961c8..e7e5969e585 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1156,17 +1156,17 @@ public class ExpressionCodegen extends JetVisitor implem private StackValue visitBreakOrContinueExpression(@NotNull JetLabelQualifiedExpression expression, StackValue receiver, boolean isBreak) { assert expression instanceof JetContinueExpression || expression instanceof JetBreakExpression; - JetSimpleNameExpression labelElement = expression.getTargetLabel(); + if (!blockStackElements.isEmpty()) { + BlockStackElement stackElement = blockStackElements.peek(); - for (int i = blockStackElements.size() - 1; i >= 0; --i) { - BlockStackElement stackElement = blockStackElements.get(i); if (stackElement instanceof FinallyBlockStackElement) { FinallyBlockStackElement finallyBlockStackElement = (FinallyBlockStackElement) stackElement; //noinspection ConstantConditions - genFinallyBlockOrGoto(finallyBlockStackElement, false, null); + genFinallyBlockOrGoto(finallyBlockStackElement, null); } else if (stackElement instanceof LoopBlockStackElement) { LoopBlockStackElement loopBlockStackElement = (LoopBlockStackElement) stackElement; + JetSimpleNameExpression labelElement = expression.getTargetLabel(); //noinspection ConstantConditions if (labelElement == null || loopBlockStackElement.targetLabel != null && @@ -1176,11 +1176,18 @@ public class ExpressionCodegen extends JetVisitor implem } } else { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Wrong BlockStackElement in processing stack"); } + + blockStackElements.pop(); + StackValue result = visitBreakOrContinueExpression(expression, receiver, isBreak); + blockStackElements.push(stackElement); + return result; + + } - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Target label for break/continue not found"); } private StackValue generateSingleBranchIf( @@ -1510,32 +1517,36 @@ public class ExpressionCodegen extends JetVisitor implem } private void doFinallyOnReturn() { - for (int i = blockStackElements.size() - 1; i >= 0; --i) { - BlockStackElement stackElement = blockStackElements.get(i); + if(!blockStackElements.isEmpty()) { + BlockStackElement stackElement = blockStackElements.peek(); if (stackElement instanceof FinallyBlockStackElement) { FinallyBlockStackElement finallyBlockStackElement = (FinallyBlockStackElement) stackElement; - genFinallyBlockOrGoto(finallyBlockStackElement, true, null); + genFinallyBlockOrGoto(finallyBlockStackElement, null); } else if (stackElement instanceof LoopBlockStackElement) { - break; + } else { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Wrong BlockStackElement in processing stack"); } + + blockStackElements.pop(); + doFinallyOnReturn(); + blockStackElements.push(stackElement); } } private void genFinallyBlockOrGoto( @Nullable FinallyBlockStackElement finallyBlockStackElement, - boolean doPop, @Nullable Label tryCatchBlockEnd ) { - if (finallyBlockStackElement != null) { - assert finallyBlockStackElement.gaps.size() % 2 == 0; - JetTryExpression jetTryExpression = finallyBlockStackElement.expression; - if (doPop) { - blockStackElements.pop(); - } + if (finallyBlockStackElement != null) { + assert finallyBlockStackElement.gaps.size() % 2 == 0 : "Finally block gaps are inconsistent"; + + BlockStackElement topOfStack = blockStackElements.pop(); + assert topOfStack == finallyBlockStackElement : "Top element of stack doesn't equals processing finally block"; + + JetTryExpression jetTryExpression = finallyBlockStackElement.expression; Label finallyStart = new Label(); v.mark(finallyStart); finallyBlockStackElement.addGapLabel(finallyStart); @@ -1553,9 +1564,7 @@ public class ExpressionCodegen extends JetVisitor implem v.mark(finallyEnd); finallyBlockStackElement.addGapLabel(finallyEnd); - if (doPop) { - blockStackElements.push(finallyBlockStackElement); - } + blockStackElements.push(finallyBlockStackElement); } } @@ -3473,11 +3482,11 @@ The "returned" value of try expression with no finally is either the last expres v.mark(tryEnd); //do it before finally block generation - List