JDK-8361481 : Flexible Constructor Bodies generates a compilation error when compiling a user supplied java.lang.Object class
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 22
  • Priority: P4
  • Status: New
  • Resolution: Unresolved
  • Submitted: 2025-07-07
  • Updated: 2025-07-07
Related Reports
Relates :  
Description
The "Flexible Constructor Bodies" implementation generates an (incorrect) error for a rare case where a user supplied java.lang.Object class is compiled.

Consider the attached Object.java file. When compiling with `-source 8`, till Java 21, this compiles fine:

$JDK21_HOME/bin/javac -source 8 /tmp/Object.java
warning: [options] bootstrap class path not set in conjunction with -source 8
warning: [options] source value 8 is obsolete and will be removed in a future release
warning: [options] To suppress warnings about obsolete options, use -Xlint:-options.
3 warnings

echo $?
0

However, starting Java 22 (including Java 25 and current mainline) it generates the following (incorrect) error:

$JAVA25_HOME/bin/javac -source 8 /tmp/Object.java
...
/tmp/Object.java:9: error: flexible constructors is not supported in -source 8
        x = 0;
        ^
  (use -source 25 or higher to enable flexible constructors)
1 error
3 warnings

echo $?
1


Comments
A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/26158 Date: 2025-07-07 11:15:26 +0000
07-07-2025

I think the JLS does not require a fix. The text is quite subtle, but, I think, ultimately correct. Note that 8.8.7 says: "If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation "super();", an invocation of the constructor of its direct superclass that takes no arguments." Then, 8.8.7.1 says: "An expression occurs in the early construction context of a class C if it is contained in either the prologue of a constructor body of C, or it is nested in the explicit constructor invocation of a constructor body of C." What is a constructor prologue? 8.8.7 says: "If a constructor body contains an explicit constructor invocation, the BlockStatements preceding the explicit constructor invocation are called the prologue of the constructor body." Note the "IF a constructor body contains an explicit constructor invocation". In this case there's no explicit constructor invocation, so there's no prologue. Unfortunately, javac code makes this determination _after_ it appends an implicit super constructor call to constructors that are missing one -- and the special Object case creates a problem here.
07-07-2025

I believe the issue here is that javac does not emit an implicit super constructor call if the class in question is java.lang.Object -- the root of the hierarchy.: https://github.com/openjdk/jdk/blob/master/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java#L1202 Super calls in constructors are used by javac to detect the transition between early and late construction context: https://github.com/openjdk/jdk/blob/master/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java#L2565 (e.g. we start off as early, then we switch to late when we see a super call) But, since a constructor in Object has not super call, we remain in "early" mode -- meaning the field assignment in your code is understood to be an assignment in an early constructor context. A possible fix might be to add more nuance to this: https://github.com/openjdk/jdk/blob/master/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java#L1240 (edited) (e.g. only set the flag to true if we're not in a constructor of the Object class)
07-07-2025