Skip to content
Permalink
Browse files
8267923: [lworld] Javac's implementation differs from JEP401 in a few…
… matters.

8267918: [lworld] Javac tolerates synchronizing on a primitive reference type
8267907: [lworld] Withdraw support for the experimental option -XDallowValueMemberCycles
8267843: [lworld] Double diagnostics when primitive class instance is passed around before being fully initialized
8267841: [lworld] A primitive class that implements Cloneable is tolerated by javac
8267835: [lworld] Javac tolerates vacuous chaining to super constructor from primitive class constructor
8267965: [lworld] Javac disallows calls to super.{hashCode(), equals(), toString()} on a primitive instance receiver
  • Loading branch information
Srikanth Adayapalam committed May 31, 2021
1 parent 44cb67e commit f1b32691431219c4d4861da296a1f33fb1bb8b01
Showing with 288 additions and 37 deletions.
  1. +1 −1 src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
  2. +9 −17 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
  3. +27 −2 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
  4. +4 −1 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java
  5. +9 −0 src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
  6. +27 −0 test/langtools/tools/javac/diags/examples/PrimitiveClassMustNotImplementCloneable.java
  7. +31 −0 test/langtools/tools/javac/diags/examples/SuperNotAllowedInPrimitiveCtor.java
  8. +29 −0 test/langtools/tools/javac/diags/examples/TypeReqIdentity.java
  9. +1 −1 test/langtools/tools/javac/valhalla/lworld-values/CheckCyclicMembership.java
  10. +1 −1 test/langtools/tools/javac/valhalla/lworld-values/CheckFlattenableCycles.java
  11. +1 −4 test/langtools/tools/javac/valhalla/lworld-values/CheckObjectMethodsUsage.out
  12. +22 −4 test/langtools/tools/javac/valhalla/lworld-values/CheckSynchronized.java
  13. +5 −3 test/langtools/tools/javac/valhalla/lworld-values/CheckSynchronized.out
  14. +24 −0 test/langtools/tools/javac/valhalla/lworld-values/DualNonDuplicateErrors.java
  15. +3 −0 test/langtools/tools/javac/valhalla/lworld-values/DualNonDuplicateErrors.out
  16. +1 −3 test/langtools/tools/javac/valhalla/lworld-values/SneakThroSuperCallTest.out
  17. +27 −0 test/langtools/tools/javac/valhalla/lworld-values/SuperCallInCtor.java
  18. +2 −0 test/langtools/tools/javac/valhalla/lworld-values/SuperCallInCtor.out
  19. +64 −0 test/langtools/tools/javac/valhalla/lworld-values/SuperHashCodeEqualsToStringTest.java
@@ -2277,7 +2277,7 @@ public Type asSuper(Type t, Symbol sym) {
} else if (sym == syms.primitiveObjectType.tsym) {
if (t.isPrimitiveClass() || t.isReferenceProjection())
return syms.primitiveObjectType;
if (t.hasTag(ARRAY) || t.tsym == syms.objectType.tsym)
if (t.hasTag(ARRAY) || t.tsym == syms.objectType.tsym || !t.hasTag(CLASS))
return null;
// else fall through and look for explicit coded super interface
}
@@ -175,7 +175,6 @@ protected Attr(Context context) {
allowRecords = Feature.RECORDS.allowedInSource(source);
sourceName = source.name;
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
allowValueMemberCycles = options.isSet("allowValueMemberCycles");

statInfo = new ResultInfo(KindSelector.NIL, Type.noType);
varAssignmentInfo = new ResultInfo(KindSelector.ASG, Type.noType);
@@ -224,11 +223,6 @@ protected Attr(Context context) {
*/
boolean useBeforeDeclarationWarning;

/**
* Switch: Allow value type member cycles?
*/
boolean allowValueMemberCycles;

/**
* Switch: name of source level; used for error reporting.
*/
@@ -1229,6 +1223,12 @@ public void visitMethodDef(JCMethodDecl tree) {
// generated one.
log.error(tree.body.stats.head.pos(),
Errors.CallToSuperNotAllowedInEnumCtor(env.enclClass.sym));
} else if ((env.enclClass.sym.flags() & PRIMITIVE_CLASS) != 0 &&
(tree.mods.flags & GENERATEDCONSTR) == 0 &&
TreeInfo.isSuperCall(body.stats.head)) {
// primitive constructors are not allowed to call super directly,
// but tolerate compiler generated ones
log.error(tree.body.stats.head.pos(), Errors.CallToSuperNotAllowedInPrimitiveCtor);
}
if (env.enclClass.sym.isRecord() && (tree.sym.flags_field & RECORD) != 0) { // we are seeing the canonical constructor
List<Name> recordComponentNames = TreeInfo.recordFields(env.enclClass).map(vd -> vd.sym.name);
@@ -1830,7 +1830,7 @@ private Symbol enumConstant(JCTree tree, Type enumType) {
}

public void visitSynchronized(JCSynchronized tree) {
chk.checkRefType(tree.pos(), attribExpr(tree.lock, env), false);
chk.checkIdentityType(tree.pos(), attribExpr(tree.lock, env));
if (env.info.lint.isEnabled(LintCategory.SYNCHRONIZATION) && isValueBased(tree.lock.type)) {
log.warning(LintCategory.SYNCHRONIZATION, tree.pos(), Warnings.AttemptToSynchronizeOnInstanceOfValueBasedClass);
}
@@ -2581,12 +2581,6 @@ public void visitApply(JCMethodInvocation tree) {
if (argSize == 0)
log.error(tree.pos(), Errors.PrimitiveClassDoesNotSupport(name));
break;
case "hashCode":
case "equals":
case "toString":
if (superCallOnValueReceiver)
log.error(tree.pos(), Errors.PrimitiveClassDoesNotSupport(names.fromString("invocation of super." + name)));
break;
}
}
}
@@ -5255,10 +5249,8 @@ public void attribClass(DiagnosticPosition pos, ClassSymbol c) {
attribClass(c);
if (types.isPrimitiveClass(c.type)) {
final Env<AttrContext> env = typeEnvs.get(c);
if (!allowValueMemberCycles) {
if (env != null && env.tree != null && env.tree.hasTag(CLASSDEF))
chk.checkNonCyclicMembership((JCClassDecl)env.tree);
}
if (env != null && env.tree != null && env.tree.hasTag(CLASSDEF))
chk.checkNonCyclicMembership((JCClassDecl)env.tree);
}
} catch (CompletionFailure ex) {
chk.completionError(pos, ex);
@@ -848,6 +848,32 @@ Type checkRefType(DiagnosticPosition pos, Type t, boolean valueOK) {
t);
}

/** Check that type is an identity type, i.e. not a primitive type
* nor its reference projection. When not discernible statically,
* give it the benefit of doubt and defer to runtime.
*
* @param pos Position to be used for error reporting.
* @param t The type to be checked.
*/
Type checkIdentityType(DiagnosticPosition pos, Type t) {

if (t.hasTag(ARRAY))
return t;

if (!t.hasTag(CLASS) || t.isPrimitiveClass() || t.isReferenceProjection())
return typeTagError(pos,
diags.fragment(Fragments.TypeReqIdentity),
t);

/* Not appropriate to check
* if (types.asSuper(t, syms.identityObjectType.tsym) != null)
* since jlO, interface types and abstract types may fail that check
* at compile time.
*/

return t;
}

/** Check that type is a reference type, i.e. a class, interface or array type
* or a type variable.
* @param pos Position to be used for error reporting.
@@ -2416,8 +2442,7 @@ void checkNonCyclicMembership(JCClassDecl tree) {
if (l.head.hasTag(VARDEF)) {
JCVariableDecl field = (JCVariableDecl) l.head;
if (cyclePossible(field.sym)) {
Type fieldType = field.sym.type;
checkNonCyclicMembership((ClassSymbol) fieldType.tsym, field.pos());
checkNonCyclicMembership((ClassSymbol) field.type.tsym, field.pos());
}
}
}
@@ -681,7 +681,7 @@ protected void attribSuperTypes(Env<AttrContext> env, Env<AttrContext> baseEnv)
// Determine supertype.
Type supertype;
JCExpression extending;
final boolean isValueType = (tree.mods.flags & Flags.PRIMITIVE_CLASS) != 0;
final boolean isPrimitiveClass = (tree.mods.flags & Flags.PRIMITIVE_CLASS) != 0;

if (tree.extending != null) {
extending = clearTypeParams(tree.extending);
@@ -708,6 +708,9 @@ protected void attribSuperTypes(Env<AttrContext> env, Env<AttrContext> baseEnv)
iface = clearTypeParams(iface);
Type it = attr.attribBase(iface, baseEnv, false, true, true);
if (it.hasTag(CLASS)) {
if (isPrimitiveClass && it.tsym == syms.cloneableType.tsym) {
log.error(tree, Errors.PrimitiveClassMustNotImplementCloneable(ct));
}
interfaces.append(it);
if (all_interfaces != null) all_interfaces.append(it);
} else {
@@ -2449,6 +2449,9 @@ compiler.misc.type.req.ref=\
compiler.misc.type.req.exact=\
class or interface without bounds

compiler.misc.type.req.identity=\
a type with identity

# 0: type
compiler.misc.type.parameter=\
type parameter {0}
@@ -3820,6 +3823,10 @@ compiler.err.generic.parameterization.with.primitive.class=\
compiler.err.primitive.class.must.not.implement.identity.object=\
The primitive class {0} attempts to implement the incompatible interface IdentityObject

# 0: type
compiler.err.primitive.class.must.not.implement.cloneable=\
The primitive class {0} attempts to implement the incompatible interface Cloneable

# 0: type
compiler.err.identity.class.must.not.implement.primitive.object=\
The identity class {0} attempts to implement the incompatible interface PrimitiveObject
@@ -3859,6 +3866,8 @@ compiler.err.super.class.cannot.be.inner=\
compiler.err.projection.cant.be.instantiated=\
Illegal attempt to instantiate a projection type

compiler.err.call.to.super.not.allowed.in.primitive.ctor=\
call to super not allowed in primitive class constructor

# 0: kind name, 1: symbol
compiler.warn.declared.using.preview=\
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2021, 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.err.primitive.class.must.not.implement.cloneable

primitive class Primitive implements Cloneable {
}
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2021, 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.err.call.to.super.not.allowed.in.primitive.ctor

primitive class SuperNotAllowedInPrimitiveCtor {

SuperNotAllowedInPrimitiveCtor() {
super();
}
}
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2021, 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.misc.type.req.identity
// key: compiler.err.type.found.req

primitive class TypeReqIdentity {
{ synchronized (this) {} }
}
@@ -1,7 +1,7 @@
/*
* @test /nodynamiccopyright/
* @summary Value types may not declare fields of its own type either directly or indirectly.
* @compile -XDallowValueMemberCycles -XDrawDiagnostics CheckCyclicMembership.java
*
* @compile/fail/ref=CheckCyclicMembership.out -XDrawDiagnostics CheckCyclicMembership.java
*/

@@ -1,7 +1,7 @@
/*
* @test /nodynamiccopyright/
* @summary Check for cycles through fields declared flattenable.
* @compile -XDallowValueMemberCycles -XDrawDiagnostics CheckFlattenableCycles.java
*
* @compile/fail/ref=CheckFlattenableCycles.out -XDrawDiagnostics CheckFlattenableCycles.java
*/

@@ -12,9 +12,6 @@ CheckObjectMethodsUsage.java:23:21: compiler.err.primitive.class.does.not.suppor
CheckObjectMethodsUsage.java:24:18: compiler.err.primitive.class.does.not.support: notifyAll
CheckObjectMethodsUsage.java:25:24: compiler.err.primitive.class.does.not.support: notifyAll
CheckObjectMethodsUsage.java:26:20: compiler.err.primitive.class.does.not.support: clone
CheckObjectMethodsUsage.java:27:23: compiler.err.primitive.class.does.not.support: invocation of super.hashCode
CheckObjectMethodsUsage.java:28:23: compiler.err.primitive.class.does.not.support: invocation of super.toString
CheckObjectMethodsUsage.java:29:21: compiler.err.primitive.class.does.not.support: invocation of super.equals
- compiler.note.deprecated.filename: CheckObjectMethodsUsage.java
- compiler.note.deprecated.recompile
17 errors
14 errors
@@ -1,19 +1,37 @@
/*
* @test /nodynamiccopyright/
* @summary Check behavior of synzhronized key word on value instances and methods.
* @summary Check behavior of synzhronized key word on primitive class instances and methods.
*
* @compile/fail/ref=CheckSynchronized.out -XDrawDiagnostics CheckSynchronized.java
*/

primitive final class CheckSynchronized {
primitive final class CheckSynchronized implements java.io.Serializable {
synchronized void foo() { // <<-- ERROR, no monitor associated with `this'
}
void goo() {
synchronized(this) {} // <<-- ERROR, no monitor associated with `this'
}
synchronized static void zoo(CheckSynchronized cs) { // OK, static method.
synchronized(cs) { // <<-- ERROR, no monitor associated with value instance.
synchronized(cs) { // <<-- ERROR, no monitor associated with primitive class instance.
}

CheckSynchronized.ref csr = cs;
synchronized(csr) {
// Error, no identity.
}

synchronized(x) {
// Error, no identity.
}

Object o = cs;
synchronized(o) {
// Error BUT not discernible at compile time
}
java.io.Serializable jis = cs;
synchronized(jis) {
// Error BUT not discernible at compile time
}
}
int x = 10;
static int x = 10;
}
@@ -1,4 +1,6 @@
CheckSynchronized.java:9:23: compiler.err.mod.not.allowed.here: synchronized
CheckSynchronized.java:12:9: compiler.err.type.found.req: CheckSynchronized, (compiler.misc.type.req.ref)
CheckSynchronized.java:15:9: compiler.err.type.found.req: CheckSynchronized, (compiler.misc.type.req.ref)
3 errors
CheckSynchronized.java:12:9: compiler.err.type.found.req: CheckSynchronized, (compiler.misc.type.req.identity)
CheckSynchronized.java:15:9: compiler.err.type.found.req: CheckSynchronized, (compiler.misc.type.req.identity)
CheckSynchronized.java:19:9: compiler.err.type.found.req: CheckSynchronized.ref, (compiler.misc.type.req.identity)
CheckSynchronized.java:23:9: compiler.err.type.found.req: int, (compiler.misc.type.req.identity)
5 errors
@@ -0,0 +1,24 @@
/*
* @test /nodynamiccopyright/
* @bug 8267843
* @summary Check that javac diagnoses `this` being passed around and instance method being invoked before primitive class instance is fully initialized.
* @compile/fail/ref=DualNonDuplicateErrors.out -XDrawDiagnostics DualNonDuplicateErrors.java
*/

public primitive class DualNonDuplicateErrors {

int x;

DualNonDuplicateErrors() {
// The call below should trigger two errors - they are not duplicates really.
// First one is for `this` being passed around ("exposed")
// Second is for instance method being invoked thereby allowing that method to
// observe the primitive class instance in a partially initialized state.
foo(this);
x = 10;
foo(this); // No error here.
}

void foo(DualNonDuplicateErrors x) {
}
}
@@ -0,0 +1,3 @@
DualNonDuplicateErrors.java:17:13: compiler.err.this.exposed.prematurely
DualNonDuplicateErrors.java:17:12: compiler.err.this.exposed.prematurely
2 errors
@@ -1,4 +1,2 @@
SneakThroSuperCallTest.java:13:21: compiler.err.primitive.class.does.not.support: notify
SneakThroSuperCallTest.java:17:30: compiler.err.primitive.class.does.not.support: invocation of super.hashCode
SneakThroSuperCallTest.java:21:30: compiler.err.primitive.class.does.not.support: invocation of super.toString
3 errors
1 error

0 comments on commit f1b3269

Please sign in to comment.