8334258: Compiler erronousely allows access to instance variable in argument expression of a constructor invocation

Reviewed-by: mcimadamore
This commit is contained in:
Archie Cobbs 2024-06-18 23:23:39 +00:00 committed by Maurizio Cimadamore
parent 2ce85d9635
commit e227c7e37d
7 changed files with 83 additions and 9 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -100,6 +100,7 @@ public class Resolve {
DeferredAttr deferredAttr; DeferredAttr deferredAttr;
Check chk; Check chk;
Infer infer; Infer infer;
Preview preview;
ClassFinder finder; ClassFinder finder;
ModuleFinder moduleFinder; ModuleFinder moduleFinder;
Types types; Types types;
@ -135,7 +136,7 @@ public class Resolve {
moduleFinder = ModuleFinder.instance(context); moduleFinder = ModuleFinder.instance(context);
types = Types.instance(context); types = Types.instance(context);
diags = JCDiagnostic.Factory.instance(context); diags = JCDiagnostic.Factory.instance(context);
Preview preview = Preview.instance(context); preview = Preview.instance(context);
Source source = Source.instance(context); Source source = Source.instance(context);
Options options = Options.instance(context); Options options = Options.instance(context);
compactMethodDiags = options.isSet(Option.XDIAGS, "compact") || compactMethodDiags = options.isSet(Option.XDIAGS, "compact") ||
@ -1480,10 +1481,11 @@ public class Resolve {
/** Find unqualified variable or field with given name. /** Find unqualified variable or field with given name.
* Synthetic fields always skipped. * Synthetic fields always skipped.
* @param pos The position to use for error reporting.
* @param env The current environment. * @param env The current environment.
* @param name The name of the variable or field. * @param name The name of the variable or field.
*/ */
Symbol findVar(Env<AttrContext> env, Name name) { Symbol findVar(DiagnosticPosition pos, Env<AttrContext> env, Name name) {
Symbol bestSoFar = varNotFound; Symbol bestSoFar = varNotFound;
Env<AttrContext> env1 = env; Env<AttrContext> env1 = env;
boolean staticOnly = false; boolean staticOnly = false;
@ -1508,7 +1510,7 @@ public class Resolve {
(sym.flags() & STATIC) == 0) { (sym.flags() & STATIC) == 0) {
if (staticOnly) if (staticOnly)
return new StaticError(sym); return new StaticError(sym);
if (env1.info.ctorPrologue && !isAllowedEarlyReference(env1, (VarSymbol)sym)) if (env1.info.ctorPrologue && !isAllowedEarlyReference(pos, env1, (VarSymbol)sym))
return new RefBeforeCtorCalledError(sym); return new RefBeforeCtorCalledError(sym);
} }
return sym; return sym;
@ -2421,15 +2423,15 @@ public class Resolve {
* (a subset of VAL, TYP, PCK). * (a subset of VAL, TYP, PCK).
*/ */
Symbol findIdent(DiagnosticPosition pos, Env<AttrContext> env, Name name, KindSelector kind) { Symbol findIdent(DiagnosticPosition pos, Env<AttrContext> env, Name name, KindSelector kind) {
return checkNonExistentType(checkRestrictedType(pos, findIdentInternal(env, name, kind), name)); return checkNonExistentType(checkRestrictedType(pos, findIdentInternal(pos, env, name, kind), name));
} }
Symbol findIdentInternal(Env<AttrContext> env, Name name, KindSelector kind) { Symbol findIdentInternal(DiagnosticPosition pos, Env<AttrContext> env, Name name, KindSelector kind) {
Symbol bestSoFar = typeNotFound; Symbol bestSoFar = typeNotFound;
Symbol sym; Symbol sym;
if (kind.contains(KindSelector.VAL)) { if (kind.contains(KindSelector.VAL)) {
sym = findVar(env, name); sym = findVar(pos, env, name);
if (sym.exists()) return sym; if (sym.exists()) return sym;
else bestSoFar = bestOf(bestSoFar, sym); else bestSoFar = bestOf(bestSoFar, sym);
} }
@ -3776,7 +3778,7 @@ public class Resolve {
if (sym != null) { if (sym != null) {
if (staticOnly) if (staticOnly)
sym = new StaticError(sym); sym = new StaticError(sym);
else if (env1.info.ctorPrologue && !isAllowedEarlyReference(env1, (VarSymbol)sym)) else if (env1.info.ctorPrologue && !isAllowedEarlyReference(pos, env1, (VarSymbol)sym))
sym = new RefBeforeCtorCalledError(sym); sym = new RefBeforeCtorCalledError(sym);
return accessBase(sym, pos, env.enclClass.sym.type, return accessBase(sym, pos, env.enclClass.sym.type,
name, true); name, true);
@ -3845,7 +3847,7 @@ public class Resolve {
* We also don't verify that the field has no initializer, which is required. * 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(). * To catch those cases, we rely on similar logic in Attr.checkAssignable().
*/ */
private boolean isAllowedEarlyReference(Env<AttrContext> env, VarSymbol v) { private boolean isAllowedEarlyReference(DiagnosticPosition pos, Env<AttrContext> env, VarSymbol v) {
// Check assumptions // Check assumptions
Assert.check(env.info.ctorPrologue); Assert.check(env.info.ctorPrologue);
@ -3880,6 +3882,9 @@ public class Resolve {
if (isEarlyReference(env, base, v) && v.owner != env.enclClass.sym) if (isEarlyReference(env, base, v) && v.owner != env.enclClass.sym)
return false; return false;
// The flexible constructors feature must be enabled
preview.checkSourceLevel(pos, Feature.FLEXIBLE_CONSTRUCTORS);
// OK // OK
return true; return true;
} }

View File

@ -0,0 +1,21 @@
/*
* @test /nodynamiccopyright/
* @bug 8334258
* @summary Disallow early assignment if FLEXIBLE_CONSTRUCTORS preview feature is not enabled
* @compile/fail/ref=EarlyAssignmentNoPreview1.out -XDrawDiagnostics EarlyAssignmentNoPreview1.java
*/
public class EarlyAssignmentNoPreview1 {
Runnable r;
public EarlyAssignmentNoPreview1() {
this(r = () -> System.out.println("hello"));
}
public EarlyAssignmentNoPreview1(Runnable r) {
}
public static void main(String[] args) {
new EarlyAssignmentNoPreview1();
}
}

View File

@ -0,0 +1,2 @@
EarlyAssignmentNoPreview1.java:12:14: compiler.err.preview.feature.disabled: (compiler.misc.feature.flexible.constructors)
1 error

View File

@ -0,0 +1,21 @@
/*
* @test /nodynamiccopyright/
* @bug 8334258
* @summary Disallow early assignment if FLEXIBLE_CONSTRUCTORS preview feature is not enabled
* @compile/fail/ref=EarlyAssignmentNoPreview2.out -XDrawDiagnostics EarlyAssignmentNoPreview2.java
*/
public class EarlyAssignmentNoPreview2 {
Runnable r;
public EarlyAssignmentNoPreview2() {
this(this.r = () -> System.out.println("hello"));
}
public EarlyAssignmentNoPreview2(Runnable r) {
}
public static void main(String[] args) {
new EarlyAssignmentNoPreview2();
}
}

View File

@ -0,0 +1,2 @@
EarlyAssignmentNoPreview2.java:12:14: compiler.err.preview.feature.disabled: (compiler.misc.feature.flexible.constructors)
1 error

View File

@ -0,0 +1,21 @@
/*
* @test /nodynamiccopyright/
* @bug 8334258
* @summary Disallow early assignment if FLEXIBLE_CONSTRUCTORS preview feature is not enabled
* @compile/fail/ref=EarlyAssignmentNoPreview3.out -XDrawDiagnostics EarlyAssignmentNoPreview3.java
*/
public class EarlyAssignmentNoPreview3 {
Runnable r;
public EarlyAssignmentNoPreview3() {
this(EarlyAssignmentNoPreview3.this.r = () -> System.out.println("hello"));
}
public EarlyAssignmentNoPreview3(Runnable r) {
}
public static void main(String[] args) {
new EarlyAssignmentNoPreview3();
}
}

View File

@ -0,0 +1,2 @@
EarlyAssignmentNoPreview3.java:12:39: compiler.err.preview.feature.disabled: (compiler.misc.feature.flexible.constructors)
1 error