diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java index 6af766effa5..5e9a75a0b6b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java @@ -208,7 +208,7 @@ public class Preview { public boolean isPreview(Feature feature) { return switch (feature) { case IMPLICIT_CLASSES -> true; - case SUPER_INIT -> true; + case FLEXIBLE_CONSTRUCTORS -> true; case PRIMITIVE_PATTERNS -> true; case MODULE_IMPORTS -> true; //Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing). diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java index f1cc1e89272..6288cbfb01b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java @@ -254,7 +254,7 @@ public enum Source { WARN_ON_ILLEGAL_UTF8(MIN, JDK21), UNNAMED_VARIABLES(JDK22, Fragments.FeatureUnnamedVariables, DiagKind.PLURAL), PRIMITIVE_PATTERNS(JDK23, Fragments.FeaturePrimitivePatterns, DiagKind.PLURAL), - SUPER_INIT(JDK22, Fragments.FeatureSuperInit, DiagKind.NORMAL), + FLEXIBLE_CONSTRUCTORS(JDK22, Fragments.FeatureFlexibleConstructors, DiagKind.NORMAL), MODULE_IMPORTS(JDK23, Fragments.FeatureModuleImports, DiagKind.PLURAL), ; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index d0f3ae7464a..8a67d9f8870 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -293,7 +293,9 @@ public class Attr extends JCTree.Visitor { void checkAssignable(DiagnosticPosition pos, VarSymbol v, JCTree base, Env env) { if (v.name == names._this) { log.error(pos, Errors.CantAssignValToThis); - } else if ((v.flags() & FINAL) != 0 && + return; + } + if ((v.flags() & FINAL) != 0 && ((v.flags() & HASINIT) != 0 || !((base == null || @@ -304,6 +306,23 @@ public class Attr extends JCTree.Visitor { } else { log.error(pos, Errors.CantAssignValToVar(Flags.toSource(v.flags() & (STATIC | FINAL)), v)); } + return; + } + + // Check instance field assignments that appear in constructor prologues + if (rs.isEarlyReference(env, base, v)) { + + // Field may not be inherited from a superclass + if (v.owner != env.enclClass.sym) { + log.error(pos, Errors.CantRefBeforeCtorCalled(v)); + return; + } + + // Field may not have an initializer + if ((v.flags() & HASINIT) != 0) { + log.error(pos, Errors.CantAssignInitializedBeforeCtorCalled(v)); + return; + } } } @@ -2779,6 +2798,7 @@ public class Attr extends JCTree.Visitor { } } } else if (!clazztype.tsym.isInterface() && + (clazztype.tsym.flags_field & NOOUTERTHIS) == 0 && clazztype.getEnclosingType().hasTag(CLASS)) { // Check for the existence of an apropos outer instance rs.resolveImplicitThis(tree.pos(), env, clazztype); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java index 4d9f0012733..5a442bac302 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java @@ -4060,9 +4060,9 @@ public class Check { break; } - // If super()/this() isn't first, require "statements before super()" feature + // If super()/this() isn't first, require flexible constructors feature if (!firstStatement) - preview.checkSourceLevel(apply.pos(), Feature.SUPER_INIT); + preview.checkSourceLevel(apply.pos(), Feature.FLEXIBLE_CONSTRUCTORS); // We found a legitimate super()/this() call; remember it initCall = methodName; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index 3980f03713d..ac8374a9a55 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -1508,7 +1508,7 @@ public class Resolve { (sym.flags() & STATIC) == 0) { if (staticOnly) return new StaticError(sym); - if (env1.info.ctorPrologue && (sym.flags_field & SYNTHETIC) == 0) + if (env1.info.ctorPrologue && !isAllowedEarlyReference(env1, (VarSymbol)sym)) return new RefBeforeCtorCalledError(sym); } return sym; @@ -3766,6 +3766,7 @@ public class Resolve { Env env, TypeSymbol c, Name name) { + Assert.check(name == names._this || name == names._super); Env env1 = env; boolean staticOnly = false; while (env1.outer != null) { @@ -3775,7 +3776,7 @@ public class Resolve { if (sym != null) { if (staticOnly) sym = new StaticError(sym); - else if (env1.info.ctorPrologue) + else if (env1.info.ctorPrologue && !isAllowedEarlyReference(env1, (VarSymbol)sym)) sym = new RefBeforeCtorCalledError(sym); return accessBase(sym, pos, env.enclClass.sym.type, name, true); @@ -3828,6 +3829,70 @@ public class Resolve { return result.toList(); } + /** + * Determine if an early instance field reference may appear in a constructor prologue. + * + *

+ * This is only allowed when: + * - The field is being assigned a value (i.e., written but not read) + * - The field is not inherited from a superclass + * - The assignment is not within a lambda, because that would require + * capturing 'this' which is not allowed prior to super(). + * + *

+ * Note, this method doesn't catch all such scenarios, because this method + * is invoked for symbol "x" only for "x = 42" but not for "this.x = 42". + * We also don't verify that the field has no initializer, which is required. + * To catch those cases, we rely on similar logic in Attr.checkAssignable(). + */ + private boolean isAllowedEarlyReference(Env env, VarSymbol v) { + + // Check assumptions + Assert.check(env.info.ctorPrologue); + Assert.check((v.flags_field & STATIC) == 0); + + // The symbol must appear in the LHS of an assignment statement + if (!(env.tree instanceof JCAssign assign)) + return false; + + // The assignment statement must not be within a lambda + if (env.info.isLambda) + return false; + + // Get the symbol's qualifier, if any + JCExpression lhs = TreeInfo.skipParens(assign.lhs); + JCExpression base = lhs instanceof JCFieldAccess select ? select.selected : null; + + // If an early reference, the field must not be declared in a superclass + if (isEarlyReference(env, base, v) && v.owner != env.enclClass.sym) + return false; + + // OK + return true; + } + + /** + * Determine if the variable appearance constitutes an early reference to the current class. + * + *

+ * This means the variable is an instance field of the current class and it appears + * in an early initialization context of it (i.e., one of its constructor prologues). + * + *

+ * Such a reference is only allowed for assignments to non-initialized fields that are + * not inherited from a superclass, though that is not enforced by this method. + * + * @param env The current environment + * @param base Variable qualifier, if any, otherwise null + * @param v The variable + */ + public boolean isEarlyReference(Env env, JCTree base, VarSymbol v) { + return env.info.ctorPrologue && + (v.flags() & STATIC) == 0 && + v.owner.kind == TYP && + types.isSubtype(env.enclClass.type, v.owner.type) && + (base == null || TreeInfo.isExplicitThisReference(types, (ClassType)env.enclClass.type, base)); + } /** * Resolve `c.this' for an enclosing class c that contains the diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index a37d9041f43..74281b4ea0d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -399,6 +399,10 @@ compiler.err.cant.inherit.from.final=\ compiler.err.cant.ref.before.ctor.called=\ cannot reference {0} before supertype constructor has been called +# 0: symbol or name +compiler.err.cant.assign.initialized.before.ctor.called=\ + cannot assign initialized field ''{0}'' before supertype constructor has been called + compiler.err.cant.select.static.class.from.param.type=\ cannot select a static class from a parameterized type @@ -3215,8 +3219,8 @@ compiler.misc.feature.unconditional.patterns.in.instanceof=\ compiler.misc.feature.implicit.classes=\ implicitly declared classes -compiler.misc.feature.super.init=\ - statements before super() +compiler.misc.feature.flexible.constructors=\ + flexible constructors compiler.misc.feature.module.imports=\ module imports diff --git a/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.java b/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.java new file mode 100644 index 00000000000..7947b69b830 --- /dev/null +++ b/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.java @@ -0,0 +1,51 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8325805 + * @summary Permit non-superclass instance field assignments before this/super in constructors + * @compile/fail/ref=DA_DUConstructors.out -XDrawDiagnostics DA_DUConstructors.java + * @enablePreview + */ + +public class DA_DUConstructors { + // identity + class C1 { + final int x; + final int y = x + 1; + C1() { + x = 12; + super(); + } + } + + class C2 { + final int x; + C2() { + this(x = 3); // error + } + C2(int i) { + x = 4; + } + } + + class C3 { + C3(int i) {} + } + class C4 extends C3 { + final int x; + C4() { + super(x = 3); // ok + } + } + + class C5 { + final int x; + final int y = x + 1; // x is not DA + C5() { + x = 12; super(); + } + C5(int i) { + /* no prologue */ + x = i; + } + } +} diff --git a/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.out b/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.out new file mode 100644 index 00000000000..78cd3d314a8 --- /dev/null +++ b/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.out @@ -0,0 +1,5 @@ +DA_DUConstructors.java:23:17: compiler.err.var.might.already.be.assigned: x +DA_DUConstructors.java:42:23: compiler.err.var.might.not.have.been.initialized: x +- compiler.note.preview.filename: DA_DUConstructors.java, DEFAULT +- compiler.note.preview.recompile +2 errors diff --git a/test/langtools/tools/javac/SuperInit/EarlyAssignments.java b/test/langtools/tools/javac/SuperInit/EarlyAssignments.java new file mode 100644 index 00000000000..89a13ccf0ff --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/EarlyAssignments.java @@ -0,0 +1,161 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8325805 + * @summary Permit non-superclass instance field assignments before this/super in constructors + * @compile/fail/ref=EarlyAssignments.out -XDrawDiagnostics EarlyAssignments.java + * @enablePreview + */ +public class EarlyAssignments { + + public static class Inner1 { + public int x; + + public Inner1() { + x = 123; // OK - "x" belongs to this class + this.x = 123; // OK - "x" belongs to this class + Inner1.this.x = 123; // OK - "x" belongs to this class + super(); + } + + public Inner1(int y) { + y = x; // FAIL - early 'this' reference + y = this.x; // FAIL - early 'this' reference + y = Inner1.this.x; // FAIL - early 'this' reference + super(); + } + + public class Inner1a extends Inner1 { + public int z; + public Inner1a(byte value) { + Inner1.this.x = value; // OK - "x" belongs to outer class + z = super.x; // FAIL - "x" belongs to superclass + z = x; // FAIL - "x" belongs to superclass + this.z = x; // FAIL - "x" belongs to superclass + Inner1a.this.z = x; // FAIL - "x" belongs to superclass + Object o1 = Inner1.this; // OK - Inner1 is an outer class + Object o2 = Inner1a.this; // FAIL - Inner1a is this class + super(); + } + public Inner1a(short value) { + x = value; // FAIL - "x" belongs to superclass + super(); + } + public Inner1a(char value) { + this.x = value; // FAIL - "x" belongs to superclass + super(); + } + public Inner1a(int value) { + super.x = value; // FAIL - "x" belongs to superclass + super(); + } + } + + public class Inner1b { + public Inner1b(int value) { + Inner1.this.x = value; // OK - "x" belongs to outer class + super(); + } + } + } + + public static class Inner2 extends Inner1 { + int y; + public Inner2(int value) { + y = value; // OK - "y" belongs to this class + this.y = value; // OK - "y" belongs to this class + x = value; // FAIL - "x" belongs to superclass + this.x = value; // FAIL - "x" belongs to superclass + Object o1 = this; // FAIL - can't acces 'this' yet + Object o2 = Inner2.this; // FAIL - can't acces 'this' yet + super(); + } + } + + public static class Inner3 { + + public int e; + + public class Inner3a { + + public static int x; + + public Inner3a(int val) { + x = val; // OK - "x" is a static field + val = x; // OK - "x" is a static field + e = val; // OK - "e" belongs to outer class + val = e; // OK - "e" belongs to outer class + Inner3.this.e = val; // OK - "e" belongs to outer class + super(); + } + } + } + + public static class Inner4 { + public int x; + + public Inner4() { + x = 0; // OK + x = x + 1; // FAIL - illegal early access + super(); + } + + public Inner4(int a) { + this.x = 0; // OK + this.x = this.x + 1; // FAIL - illegal early access + super(); + } + + public Inner4(char a) { + Inner4.this.x = 0; // OK + Inner4.this.x = Inner4.this.x + 1; // FAIL - illegal early access + super(); + } + } + + public static class Inner5 extends Inner4 { + public int y; + + public Inner5() { + y = x + 1; // FAIL - illegal early access + super(); + } + + public Inner5(int a) { + this.y = x + 1; // FAIL - illegal early access + super(); + } + + public Inner5(char a) { + Inner5.this.y = x + 1; // FAIL - illegal early access + super(); + } + + public Inner5(short a) { + y = super.x + 1; // FAIL - illegal early access + super(); + } + + public Inner5(float a) { + y = Inner5.this.x + 1; // FAIL - illegal early access + super(); + } + } + + public static class Inner6 { + public int x = 1; + + public Inner6() { + x = 2; // FAIL - illegal early access + super(); + } + } + + public static class Inner7 { + public final int x = 1; + + public Inner7() { + x = 2; // FAIL - illegal early access + super(); + } + } +} diff --git a/test/langtools/tools/javac/SuperInit/EarlyAssignments.out b/test/langtools/tools/javac/SuperInit/EarlyAssignments.out new file mode 100644 index 00000000000..81b4f20b505 --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/EarlyAssignments.out @@ -0,0 +1,28 @@ +EarlyAssignments.java:21:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:22:17: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:23:23: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:31:21: compiler.err.cant.ref.before.ctor.called: super +EarlyAssignments.java:32:21: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:33:26: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:34:34: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:36:36: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:40:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:44:21: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:48:22: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:66:13: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:67:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:68:25: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:69:31: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:98:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:104:22: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:110:35: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:119:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:124:22: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:129:29: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:134:17: compiler.err.cant.ref.before.ctor.called: super +EarlyAssignments.java:139:23: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:148:13: compiler.err.cant.assign.initialized.before.ctor.called: x +EarlyAssignments.java:157:13: compiler.err.cant.assign.val.to.var: final, x +- compiler.note.preview.filename: EarlyAssignments.java, DEFAULT +- compiler.note.preview.recompile +25 errors diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalClass.java b/test/langtools/tools/javac/SuperInit/EarlyLocalClass.java new file mode 100644 index 00000000000..1c68de603fb --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalClass.java @@ -0,0 +1,19 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8325805 + * @summary Verify local class in early construction context has no outer instance + * @compile/fail/ref=EarlyLocalClass.out -XDrawDiagnostics EarlyLocalClass.java + * @enablePreview + */ +public class EarlyLocalClass { + EarlyLocalClass() { + class Local { + void foo() { + EarlyLocalClass.this.hashCode(); // this should FAIL + } + } + new Local(); // this is OK + super(); + new Local(); // this is OK + } +} diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalClass.out b/test/langtools/tools/javac/SuperInit/EarlyLocalClass.out new file mode 100644 index 00000000000..390b68ea2c9 --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalClass.out @@ -0,0 +1,4 @@ +EarlyLocalClass.java:12:32: compiler.err.no.encl.instance.of.type.in.scope: EarlyLocalClass +- compiler.note.preview.filename: EarlyLocalClass.java, DEFAULT +- compiler.note.preview.recompile +1 error diff --git a/test/langtools/tools/javac/SuperInit/SuperInitFails.java b/test/langtools/tools/javac/SuperInit/SuperInitFails.java index cd0fc3fd903..b3dd88fc242 100644 --- a/test/langtools/tools/javac/SuperInit/SuperInitFails.java +++ b/test/langtools/tools/javac/SuperInit/SuperInitFails.java @@ -91,7 +91,7 @@ public class SuperInitFails extends AtomicReference implements Iterable< } public SuperInitFails(short[] x) { - this.x = x.length; // this should FAIL + this.x++; // this should FAIL super(); } @@ -145,16 +145,6 @@ public class SuperInitFails extends AtomicReference implements Iterable< return null; } - public SuperInitFails(short[][] x) { - class Foo { - Foo() { - SuperInitFails.this.hashCode(); - } - }; - new Foo(); // this should FAIL - super(); - } - public SuperInitFails(float[][] x) { Runnable r = () -> { super(); // this should FAIL @@ -168,4 +158,32 @@ public class SuperInitFails extends AtomicReference implements Iterable< public SuperInitFails(long[][] z) { super(new Inner1()); // this should FAIL } + + public static class Inner2 { + int x; + } + public static class Inner3 extends Inner2 { + int y; + Inner3(byte z) { + x = z; // this should FAIL + super(); + } + Inner3(short z) { + this.x = z; // this should FAIL + super(); + } + Inner3(char z) { + Inner3.this.x = z; // this should FAIL + super(); + } + Inner3(int z) { + super.x = z; // this should FAIL + super(); + } + } + + public SuperInitFails(double[][] x) { + Runnable r = () -> this.x = 7; // this should FAIL + super(); + } } diff --git a/test/langtools/tools/javac/SuperInit/SuperInitFails.out b/test/langtools/tools/javac/SuperInit/SuperInitFails.out index 60bbd83dcc0..c6b726ab173 100644 --- a/test/langtools/tools/javac/SuperInit/SuperInitFails.out +++ b/test/langtools/tools/javac/SuperInit/SuperInitFails.out @@ -12,9 +12,13 @@ SuperInitFails.java:119:22: compiler.err.call.must.only.appear.in.ctor SuperInitFails.java:125:9: compiler.err.cant.ref.before.ctor.called: this SuperInitFails.java:133:9: compiler.err.non.canonical.constructor.invoke.another.constructor: SuperInitFails.Record1 SuperInitFails.java:138:9: compiler.err.non.canonical.constructor.invoke.another.constructor: SuperInitFails.Record2 -SuperInitFails.java:154:9: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:165:31: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:169:15: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:155:31: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:159:15: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:168:13: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:172:17: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:176:24: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:180:18: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:186:28: compiler.err.cant.ref.before.ctor.called: this SuperInitFails.java:33:13: compiler.err.call.must.only.appear.in.ctor SuperInitFails.java:37:14: compiler.err.call.must.only.appear.in.ctor SuperInitFails.java:41:14: compiler.err.call.must.only.appear.in.ctor @@ -23,7 +27,7 @@ SuperInitFails.java:49:33: compiler.err.call.must.only.appear.in.ctor SuperInitFails.java:53:32: compiler.err.call.must.only.appear.in.ctor SuperInitFails.java:83:18: compiler.err.ctor.calls.not.allowed.here SuperInitFails.java:89:13: compiler.err.return.before.superclass.initialized -SuperInitFails.java:160:18: compiler.err.ctor.calls.not.allowed.here +SuperInitFails.java:150:18: compiler.err.ctor.calls.not.allowed.here - compiler.note.preview.filename: SuperInitFails.java, DEFAULT - compiler.note.preview.recompile -26 errors +30 errors diff --git a/test/langtools/tools/javac/SuperInit/SuperInitGood.java b/test/langtools/tools/javac/SuperInit/SuperInitGood.java index f82ee6188f1..68002e8d37e 100644 --- a/test/langtools/tools/javac/SuperInit/SuperInitGood.java +++ b/test/langtools/tools/javac/SuperInit/SuperInitGood.java @@ -407,6 +407,54 @@ public class SuperInitGood { } } + // we allow 'this' reference prior to super() for field assignments only + public static class Test20 { + private int x; + public Test20(short x) { + x = x; + super(); + } + public Test20(int x) { + this.x = x; + super(); + } + public Test20(char x) { + Test20.this.x = x; + super(); + } + public Test20(byte y) { + x = y; + this((int)y); + this.x++; + } + } + + // allow creating and using local and anonymous classes before super() + // they will not have enclosing instances though + public static class Test21 { + public Test21(int x) { + Runnable r = new Runnable() { + public void run() { + this.hashCode(); + } + }; + r.run(); + super(); + r.run(); + } + public Test21(float x) { + class Foo { + public void bar() { + this.hashCode(); + } + }; + new Foo().bar(); + super(); + new Foo().bar(); + } + } + + public static void main(String[] args) { new Test0(); new Test1(); @@ -448,5 +496,8 @@ public class SuperInitGood { assert false : "unexpected exception: " + e; } new Test19(123); + new Test20(123); + new Test21((int)123); + new Test21((float)123); } } diff --git a/test/langtools/tools/javac/diags/examples/CantAssignInitializedBeforeCtorCalled.java b/test/langtools/tools/javac/diags/examples/CantAssignInitializedBeforeCtorCalled.java new file mode 100644 index 00000000000..55f5d19451d --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/CantAssignInitializedBeforeCtorCalled.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + // key: compiler.note.preview.filename + // key: compiler.note.preview.recompile + // key: compiler.err.cant.assign.initialized.before.ctor.called + // options: --enable-preview -source ${jdk.version} + +class CantAssignInitializedBeforeCtorCalled { + int x = 1; + CantAssignInitializedBeforeCtorCalled() { + x = 2; + super(); + } +} diff --git a/test/langtools/tools/javac/diags/examples/FeatureStatementsBeforeSuper.java b/test/langtools/tools/javac/diags/examples/FeatureFlexibleConstructors.java similarity index 85% rename from test/langtools/tools/javac/diags/examples/FeatureStatementsBeforeSuper.java rename to test/langtools/tools/javac/diags/examples/FeatureFlexibleConstructors.java index f0e44836850..6bdff09e96f 100644 --- a/test/langtools/tools/javac/diags/examples/FeatureStatementsBeforeSuper.java +++ b/test/langtools/tools/javac/diags/examples/FeatureFlexibleConstructors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,12 +21,12 @@ * questions. */ - // key: compiler.misc.feature.super.init + // key: compiler.misc.feature.flexible.constructors // key: compiler.warn.preview.feature.use // options: --enable-preview -source ${jdk.version} -Xlint:preview -class FeatureStatementsBeforeSuper { - FeatureStatementsBeforeSuper() { +class FeatureFlexibleConstructors { + FeatureFlexibleConstructors() { System.out.println(); super(); }