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