Summary
For a specific code, javac is producing illegal bytecode. This change is proposing adjustments to the flow scoping rules in the JLS to avoid this problem.
Problem
Consider code like:
X: if (!(o instanceof String s)) {
break X;
}
System.err.println(s);
Obviously, the System.err.println
statement is executed whether or not o
is matching String s
. So, s
may or may not have a meaning at this place. But the flow scoping rules allow this code to compile, leading to an invalid bytecode.
As an interrelated problem, consider this loop example:
X: {
while (!(o instanceof String s)) {
break X;
}
System.err.println(s);
}
The JLS rules are not completely clear on whether this code is allowed or not. javac will reject this code, as it contains a break outside of the while, which may be overly strict.
Solution
The JLS and javac will be adjusted to:
- prevent the first problem with breaking immediately out of the statement declaring the bindings variable by explicitly disallowing this case
- allow the second example, by only disallowing breaks that immediately break of the loop declaring the binding variable.
Specification
The proposed JLS change is as follows:
diff --git a/src/jls/06-names.xml b/src/jls/06-names.xml
index cebcb21702a0bc6ce6c466fc2480a2d08fe228e8..a892a97457589b3ace4bc1e89e0e43c1b26cb19f 100644
--- a/src/jls/06-names.xml
+++ b/src/jls/06-names.xml
@@ -2185,11 +2185,12 @@ The following rules apply to a statement &while; &lparen;&e;&rparen;
<!-- External flow -->
<listitem>
- <para role="norm" condition="static" xml:id="jls-6.3.2.3-100-B">
+ <para role="norm" condition="static" xml:id="jls-6.3.2.3-100-B"
+ revisionflag="changed" revision="21" conformance="8305701">
A pattern variable is introduced by &while; &lparen;&e;&rparen; &S;
iff (i) it is introduced by &e; when false and (ii) &S; does not
- contain a reachable &break; statement whose break target contains
- &S; (<xref linkend="jls-14.15"/>).</para>
+ contain a reachable &break; statement for which the &while; statement is
+ the break target (<xref linkend="jls-14.15"/>).</para>
<para revisionflag="deleted" revision="21" conformance="8309459" xml:id="jls-6.3.2.3-100-B.1z">
<info role="norm" condition="error" />
@@ -2214,12 +2215,13 @@ The following rule applies to a statement &do; &S; &while;
<!-- External flow -->
<listitem>
- <para role="norm" condition="static" xml:id="jls-6.3.2.4-100-A">
+ <para role="norm" condition="static" xml:id="jls-6.3.2.4-100-A"
+ revisionflag="changed" revision="21" conformance="8305701">
A pattern variable is introduced by &do; &S; &while;
&lparen;&e;&rparen; iff (i) it is introduced by &e; when
false and (ii) &S; does not contain a reachable &break;
- statement whose break target contains &S; (<xref
- linkend="jls-14.15"/>).</para>
+ statement for which the &do; statement is the break target
+ (<xref linkend="jls-14.15"/>).</para>
<para revisionflag="deleted" revision="21" conformance="8309459" xml:id="jls-6.3.2.4-100-A.1z">
<info role="norm" condition="error" />
@@ -2259,11 +2261,12 @@ linkend="jls-14.14.1"/>):</para>
<!-- External flow -->
<listitem>
- <para role="norm" condition="static" xml:id="jls-6.3.2.5-100-B">
+ <para role="norm" condition="static" xml:id="jls-6.3.2.5-100-B"
+ revisionflag="changed" revision="21" conformance="8305701">
A pattern variable is introduced by a basic &for; statement iff
(i) it is introduced by the condition expression when false and
(ii) the contained statement, &S;, does not contain a reachable
- &break; statement whose break target contains &S;
+ &break; for which the basic &for; statement is the break target
(<xref linkend="jls-14.15"/>).</para>
<para revisionflag="deleted" revision="21" conformance="8309459" xml:id="jls-6.3.2.5-100-B.1z">
@@ -2317,7 +2320,15 @@ The following rule applies to a labeled statement
<!-- External flow -->
<listitem>
- <para role="norm" condition="static" xml:id="jls-6.3.2.7-100-A">
+ <para role="norm" condition="static" xml:id="jls-6.3.2.7-100-A"
+ revisionflag="added" revision="21" conformance="8305701">
+ A pattern variable is introduced by a labeled statement &L;: &S;
+ (where &L; is a label) iff (i) it is introduced by the statement &S;, and
+ (ii) &S; does not contain a reachable &break; statement for which the
+ labeled statement is the break target (<xref linkend="jls-14.15"/>).
+ </para>
+ <para role="norm" condition="static" xml:id="jls-6.3.2.7-100-Az"
+ revisionflag="deleted" revision="21" conformance="8305701">
A pattern variable is introduced by a labeled statement iff it
is introduced by the labeled statement's immediately contained
&Statement;.</para>
javac will be adjusted to follow this new specification.
Please note this change is independent from JEPs 440 and 441. The problems above apply even to JDK 17, with preview features disabled.
- csr of
-
JDK-8302865 Illegal bytecode for break from if with instanceof pattern matching condition
- Resolved