diff options
author | Manoj Palat | 2020-07-19 07:35:10 +0000 |
---|---|---|
committer | Manoj Palat | 2020-07-19 07:36:25 +0000 |
commit | 12cac2354732e0b1e75a0ebb5e1df3f61743ea15 (patch) | |
tree | ac29393f77331caee00aa6d71cd72fde1ac78420 | |
parent | 55cd7fdcd2486170b7f6a341015cae5df037d88f (diff) | |
download | eclipse.jdt.core-12cac2354732e0b1e75a0ebb5e1df3f61743ea15.tar.gz eclipse.jdt.core-12cac2354732e0b1e75a0ebb5e1df3f61743ea15.tar.xz eclipse.jdt.core-12cac2354732e0b1e75a0ebb5e1df3f61743ea15.zip |
Bug 565156 - Compiler crash on switch expressions with try-catch andI20200719-2010
throw
Change-Id: Ib0531d06d0223758b8928397a4a2e3d8b36e2a37
Signed-off-by: Manoj Palat <manpalat@in.ibm.com>
5 files changed, 314 insertions, 44 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java index 0cb6f7e8fc..32df1d186f 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java @@ -26,7 +26,7 @@ public class SwitchExpressionsYieldTest extends AbstractRegressionTest { static { // TESTS_NUMBERS = new int [] { 40 }; // TESTS_RANGE = new int[] { 1, -1 }; -// TESTS_NAMES = new String[] { "testBug561766" }; +// TESTS_NAMES = new String[] { "testBug545567_14" }; } public static Class<?> testClass() { @@ -5192,4 +5192,229 @@ public class SwitchExpressionsYieldTest extends AbstractRegressionTest { "The target type of this expression must be a functional interface\n" + "----------\n"); } + public void testBug565156_001() { + runConformTest( + new String[] { + "X.java", + "public class X {\n"+ + " public int test() {\n"+ + " return switch (0) {\n"+ + " default -> {\n"+ + " try {\n"+ + " yield 0;\n"+ + " }\n"+ + " catch (RuntimeException e) {\n"+ + " throw e;\n"+ + " }\n"+ + " }\n"+ + " };\n"+ + " } \n"+ + " public static void main(String[] args) {\n"+ + " int i = new X().test();\n"+ + " System.out.println(i);\n"+ + " }\n"+ + "}\n" + }, + "0"); + } + public void testBug565156_002() { + runConformTest( + new String[] { + "X.java", + "public class X {\n"+ + " public int test() {\n"+ + " return switch (0) {\n"+ + " default -> {\n"+ + " try {\n"+ + " yield 0;\n"+ + " }\n"+ + " finally {\n"+ + " //do nothing\n"+ + " }\n"+ + " }\n"+ + " };\n"+ + " } \n"+ + " public static void main(String[] args) {\n"+ + " int i = new X().test();\n"+ + " System.out.println(i);\n"+ + " }\n"+ + "}\n" + }, + "0"); + } + public void testBug565156_003() { + runConformTest( + new String[] { + "X.java", + "public class X {\n"+ + " public int test() {\n"+ + " return switch (0) {\n"+ + " default -> {\n"+ + " try {\n"+ + " yield 0;\n"+ + " }\n"+ + " finally {\n"+ + " int i = 20;"+ + " yield 20;"+ + " }\n"+ + " }\n"+ + " };\n"+ + " } \n"+ + " public static void main(String[] args) {\n"+ + " int i = new X().test();\n"+ + " System.out.println(i);\n"+ + " }\n"+ + "}\n" + }, + "20"); + } + public void testBug565156_004() { + runConformTest( + new String[] { + "X.java", + "public class X {\n"+ + " public int test() {\n"+ + " return switch (0) {\n"+ + " default -> {\n"+ + " try {\n"+ + " yield switch (0) {\n"+ + " default -> {\n"+ + " try {\n"+ + " yield 100;\n"+ + " }\n"+ + " finally {\n"+ + " yield 200; \n"+ + " }\n"+ + " }\n"+ + " };\n"+ + " }\n"+ + " finally {\n"+ + " yield 20;\n"+ + " }\n"+ + " }\n"+ + " };\n"+ + " }\n"+ + " public static void main(String[] args){\n"+ + " int i = new X().test();\n"+ + " System.out.println(i);\n"+ + " }\n"+ + "}" + }, + "20"); + } + public void testBug565156_005() { + runConformTest( + new String[] { + "X.java", + "public class X {\n"+ + " public int test() {\n"+ + " return switch (0) {\n"+ + " default -> {\n"+ + " try {\n"+ + " yield switch (0) {\n"+ + " default -> {\n"+ + " try {\n"+ + " yield 100;\n"+ + " }\n"+ + " finally {\n"+ + " // do nothing\n"+ + " }\n"+ + " }\n"+ + " };\n"+ + " }\n"+ + " finally {\n"+ + " // do nothing\n"+ + " }\n"+ + " }\n"+ + " };\n"+ + " }\n"+ + " public static void main(String[] args){\n"+ + " int i = new X().test();\n"+ + " System.out.println(i);\n"+ + " }\n"+ + "}" + }, + "100"); + } + public void testBug565156_006() { + runConformTest( + new String[] { + "X.java", + "public class X {\n"+ + " public static void main(String[] args) {\n"+ + " new X().foo(args);\n"+ + " }\n"+ + "\n"+ + " @SuppressWarnings({ \"finally\" })\n"+ + " public void foo(String[] args) {\n"+ + " int t = switch (0) {\n"+ + " default -> {\n"+ + " try {\n"+ + " if (args == null)\n"+ + " yield 1;\n"+ + " else if (args.length ==2)\n"+ + " yield 2; \n"+ + " else if (args.length == 4)\n"+ + " yield 4;\n"+ + " else yield 5; \n"+ + " } finally {\n"+ + " yield 3; \n"+ + " }\n"+ + " }\n"+ + " }; \n"+ + " t = switch (100) {\n"+ + " default -> {\n"+ + " try {\n"+ + " yield 10;\n"+ + " } finally {\n"+ + " }\n"+ + " } \n"+ + " }; \n"+ + " System.out.println(t);\n"+ + " }\n"+ + "}" + }, + "10"); + } + public void testBug565156_007() { + runConformTest( + new String[] { + "X.java", + "public class X {\n"+ + " public static void main(String[] args) {\n"+ + " new X().foo(args);\n"+ + " }\n"+ + "\n"+ + " @SuppressWarnings({ \"finally\" })\n"+ + " public void foo(String[] args) {\n"+ + " int t = switch (0) {\n"+ + " case 101 -> {yield 101;}\n"+ + " default -> {\n"+ + " try {\n"+ + " if (args == null)\n"+ + " yield 1;\n"+ + " else if (args.length ==2)\n"+ + " yield 2; \n"+ + " else if (args.length == 4)\n"+ + " yield 4;\n"+ + " else yield 5; \n"+ + " } finally {\n"+ + " yield 3; \n"+ + " }\n"+ + " }\n"+ + " }; \n"+ + " t = switch (100) {\n"+ + " default -> {\n"+ + " try {\n"+ + " yield 10;\n"+ + " } finally {\n"+ + " }\n"+ + " } \n"+ + " }; \n"+ + " System.out.println(t);\n"+ + " }\n"+ + "}" + }, + "10"); + } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java index 62904f9308..59522dfa93 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java @@ -32,12 +32,6 @@ public BranchStatement(char[] label, int sourceStart,int sourceEnd) { this.sourceEnd = sourceEnd; } -protected void generateExpressionResultCode(BlockScope currentScope, CodeStream codeStream) { - // do nothing here -} -protected void adjustStackSize(BlockScope currentScope, CodeStream codeStream) { - // do nothing here -} protected void setSubroutineSwitchExpression(SubRoutineStatement sub) { // Do nothing } @@ -54,7 +48,6 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { if ((this.bits & ASTNode.IsReachable) == 0) { return; } - generateExpressionResultCode(currentScope, codeStream); int pc = codeStream.position; // generation of code responsible for invoking the finally @@ -80,7 +73,6 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { } // checkAndLoadSyntheticVars(codeStream); codeStream.goto_(this.targetLabel); - adjustStackSize(currentScope, codeStream); codeStream.recordPositionsFrom(pc, this.sourceStart); SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream); if (this.initStateIndex != -1) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java index e0c96327b4..3e258e3ebe 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java @@ -302,6 +302,7 @@ public class SwitchExpression extends SwitchStatement implements IPolyExpression public void loadStoredTypesAndKeep(CodeStream codeStream) { List<LocalVariableBinding> tos = this.typesOnStack; int sz = tos != null ? tos.size() : 0; + codeStream.clearTypeBindingStack(); int index = sz - 1; while (index >= 0) { LocalVariableBinding lvb = tos.get(index--); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java index 84a9106bc7..f626942837 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java @@ -127,44 +127,96 @@ protected void addSecretYieldResultValue(BlockScope scope1) { protected void restartExceptionLabels(CodeStream codeStream) { SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream); } -@Override -protected void generateExpressionResultCode(BlockScope currentScope, CodeStream codeStream) { +protected void generateExpressionResultCodeExpanded(BlockScope currentScope, CodeStream codeStream) { SwitchExpression se = this.switchExpression; - if (se != null && se.containsTry && se.resolvedType != null ) { - addSecretYieldResultValue(this.scope); - assert this.secretYieldResultValue != null; - codeStream.record(this.secretYieldResultValue); - SingleNameReference lhs = new SingleNameReference(this.secretYieldResultValue.name, 0); - lhs.binding = this.secretYieldResultValue; - lhs.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits - lhs.bits |= Binding.LOCAL; - lhs.bits |= ASTNode.IsSecretYieldValueUsage; - ((LocalVariableBinding) lhs.binding).markReferenced(); // TODO : Can be skipped? - Assignment assignment = new Assignment(lhs, this.expression, 0); - assignment.generateCode(this.scope, codeStream); - int l = this.subroutines == null ? 0 : this.subroutines.length; - boolean foundFinally = false; - if (l > 0) { - for (int i = 0; i < l; ++i) { - SubRoutineStatement srs = this.subroutines[i]; - srs.exitAnyExceptionHandler(); - srs.exitDeclaredExceptionHandlers(codeStream); - if (srs instanceof TryStatement) { - TryStatement ts = (TryStatement) srs; - if (ts.finallyBlock != null) { - foundFinally = true; + addSecretYieldResultValue(this.scope); + assert this.secretYieldResultValue != null; + codeStream.record(this.secretYieldResultValue); + SingleNameReference lhs = new SingleNameReference(this.secretYieldResultValue.name, 0); + lhs.binding = this.secretYieldResultValue; + lhs.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits + lhs.bits |= Binding.LOCAL; + lhs.bits |= ASTNode.IsSecretYieldValueUsage; + ((LocalVariableBinding) lhs.binding).markReferenced(); // TODO : Can be skipped? + Assignment assignment = new Assignment(lhs, this.expression, 0); + assignment.generateCode(this.scope, codeStream); + + int pc = codeStream.position; + // generation of code responsible for invoking the finally + // blocks in sequence + if (this.subroutines != null){ + for (int i = 0, max = this.subroutines.length; i < max; i++){ + SubRoutineStatement sub = this.subroutines[i]; + sub.exitAnyExceptionHandler(); + sub.exitDeclaredExceptionHandlers(codeStream); + SwitchExpression se1 = sub.getSwitchExpression(); + setSubroutineSwitchExpression(sub); + boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, this.targetLabel, this.initStateIndex, null); + sub.setSwitchExpression(se1); + if (didEscape) { + codeStream.removeVariable(this.secretYieldResultValue); + codeStream.recordPositionsFrom(pc, this.sourceStart); + SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream); + if (this.initStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); } - } + restartExceptionLabels(codeStream); + return; } } - if (!foundFinally) { - // no finally - TODO: Check for SynSta? - se.loadStoredTypesAndKeep(codeStream); - codeStream.load(this.secretYieldResultValue); + } + se.loadStoredTypesAndKeep(codeStream); + codeStream.load(this.secretYieldResultValue); + codeStream.removeVariable(this.secretYieldResultValue); + + codeStream.goto_(this.targetLabel); + codeStream.recordPositionsFrom(pc, this.sourceStart); + SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream); + if (this.initStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); + } +} +@Override +public void generateCode(BlockScope currentScope, CodeStream codeStream) { + if ((this.bits & ASTNode.IsReachable) == 0) { + return; + } + if (this.switchExpression != null && this.switchExpression.containsTry && this.switchExpression.resolvedType != null ) { + generateExpressionResultCodeExpanded(currentScope, codeStream); + return; + } + this.expression.generateCode(this.scope, codeStream, this.switchExpression != null); + int pc = codeStream.position; + + // generation of code responsible for invoking the finally + // blocks in sequence + if (this.subroutines != null){ + for (int i = 0, max = this.subroutines.length; i < max; i++){ + SubRoutineStatement sub = this.subroutines[i]; + SwitchExpression se = sub.getSwitchExpression(); + setSubroutineSwitchExpression(sub); + boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, this.targetLabel, this.initStateIndex, null); + sub.setSwitchExpression(se); + if (didEscape) { + codeStream.recordPositionsFrom(pc, this.sourceStart); + SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream); + if (this.initStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); + } + restartExceptionLabels(codeStream); + return; + } } - codeStream.removeVariable(this.secretYieldResultValue); - } else { - this.expression.generateCode(this.scope, codeStream, se != null); + } + codeStream.goto_(this.targetLabel); + codeStream.recordPositionsFrom(pc, this.sourceStart); + SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream); + if (this.initStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); } } private boolean isInsideTry() { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java index 393398afcf..ddf658f3a8 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java @@ -6823,7 +6823,7 @@ public void pop2() { public void pushExceptionOnStack(TypeBinding binding) { this.stackDepth = 1; - clearTypeBindingStack(); +// clearTypeBindingStack(); pushTypeBinding(binding); if (this.stackDepth > this.stackMax) this.stackMax = this.stackDepth; @@ -7689,7 +7689,7 @@ private void popTypeBinding(int nPop) { for (int i = 0; i< nPop; ++i) popTypeBinding(); } -private void clearTypeBindingStack() { +public void clearTypeBindingStack() { if (!isSwitchStackTrackingActive()) return; this.switchSaveTypeBindings.clear(); |