RFR: 8346751: Internal java compiler error with type annotations in constants expression in constant fields
Jan Lahoda
jlahoda at openjdk.org
Fri Jan 10 08:17:10 UTC 2025
Consider code like:
import java.lang.annotation.*;
public class Decl {
String VALUE = (@Nullable String) "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE_USE })
@interface Nullable {}
When processing this code, when `Attr.visitVarDef` is called for the field, it will first call `Annotate.queueScanTreeAndTypeAnnotate` on the initializer expression, which will find and attribute type annotations. Then the initializer is attributed, and eventually `Annotate.annotateTypeSecondStage` is called on the annotated type (`@Nullable String`). This second stage depends on the type annotations being already attributed. This works OK.
The problem appears when the code like changed to be like:
import java.lang.annotation.*;
@SuppressWarnings(Decl.VALUE)
public class Decl {
public static final @Nullable String VALUE = (@Nullable String) "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE_USE })
@interface Nullable {}
In this code, the field is a constant, and it is used from the annotation before `Attr.visitVarDef` is called on the constant. This will trigger attribution of the constant initializer (`Attr.attribLazyConstantValue`), which will trigger the `Annotate.annotateTypeSecondStage` on the annotated type, but `Annotate.queueScanTreeAndTypeAnnotate` was not yet called on the initializer, and so the type annotations are not attributed yet, and javac crashes with an exception like:
java.lang.AssertionError
at jdk.compiler/com.sun.tools.javac.util.Assert.error(Assert.java:155)
at jdk.compiler/com.sun.tools.javac.util.Assert.checkNonNull(Assert.java:62)
at jdk.compiler/com.sun.tools.javac.comp.Annotate.fromAnnotations(Annotate.java:167)
at jdk.compiler/com.sun.tools.javac.comp.Annotate.lambda$annotateTypeSecondStage$0(Annotate.java:1065)
at jdk.compiler/com.sun.tools.javac.comp.Annotate.flush(Annotate.java:194)
at jdk.compiler/com.sun.tools.javac.comp.Annotate.unblockAnnotations(Annotate.java:144)
at jdk.compiler/com.sun.tools.javac.comp.Annotate.enterDone(Annotate.java:157)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.enterDone(JavaCompiler.java:1820)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.enterTrees(JavaCompiler.java:1080)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:949)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:104)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.invocationHelper(JavacTaskImpl.java:152)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:100)
...
The proposed solution herein is to make sure `Annotate.queueScanTreeAndTypeAnnotate` is called before attributing field initializers in `Attr.attribLazyConstantValue`. A flag is used to make sure it is invoked at most once per field.
-------------
Commit messages:
- Using a safer marker bit for type annotations already handled for field inits.
- 8346751: Internal java compiler error with type annotations in constants expression in constant fields
Changes: https://git.openjdk.org/jdk/pull/23029/files
Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=23029&range=00
Issue: https://bugs.openjdk.org/browse/JDK-8346751
Stats: 111 lines in 5 files changed: 100 ins; 4 del; 7 mod
Patch: https://git.openjdk.org/jdk/pull/23029.diff
Fetch: git fetch https://git.openjdk.org/jdk.git pull/23029/head:pull/23029
PR: https://git.openjdk.org/jdk/pull/23029
More information about the compiler-dev
mailing list