changeset 59551:59e74aa436b9

8236692: static final fields without initializer are accepted by javac Reviewed-by: mcimadamore
author vromero
date Wed, 08 Jan 2020 15:18:58 -0500
parents decd3d2953b6
children 2383b1a86007
files src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java test/langtools/tools/javac/records/RecordCompilationTests.java
diffstat 2 files changed, 36 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Wed Jan 08 19:12:20 2020 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Wed Jan 08 15:18:58 2020 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2020, 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
@@ -1855,21 +1855,17 @@
 
         /** Check that trackable variable is initialized.
          */
-        boolean checkInit(DiagnosticPosition pos, VarSymbol sym, boolean compactConstructor) {
-            return checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym), compactConstructor);
+        void checkInit(DiagnosticPosition pos, VarSymbol sym) {
+            checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
         }
 
-        boolean checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey, boolean compactConstructor) {
+        void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
                 trackable(sym) &&
                 !inits.isMember(sym.adr)) {
-                if (sym.owner.kind != TYP || !compactConstructor || !uninits.isMember(sym.adr)) {
                     log.error(pos, errkey);
-                }
                 inits.incl(sym.adr);
-                return false;
             }
-            return true;
         }
 
         /** Utility method to reset several Bits instances.
@@ -2099,15 +2095,27 @@
                                 // the ctor is default(synthesized) or not
                                 if (isSynthesized && !isCompactConstructor) {
                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
-                                        var, Errors.VarNotInitializedInDefaultConstructor(var), isCompactConstructor);
-                                } else {
-                                    boolean wasInitialized = checkInit(TreeInfo.diagEndPos(tree.body), var, isCompactConstructor && tree.completesNormally);
-                                    if (!wasInitialized && var.owner.kind == TYP && isCompactConstructor && uninits.isMember(var.adr) && tree.completesNormally) {
+                                            var, Errors.VarNotInitializedInDefaultConstructor(var));
+                                } else if (isCompactConstructor) {
+                                    boolean isInstanceRecordField = var.enclClass().isRecord() &&
+                                            (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
+                                            !var.isStatic() &&
+                                            var.owner.kind == TYP;
+                                    if (isInstanceRecordField) {
+                                        boolean notInitialized = !inits.isMember(var.adr);
+                                        if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
                                         /*  this way we indicate Lower that it should generate an initialization for this field
                                          *  in the compact constructor
                                          */
-                                        var.flags_field |= UNINITIALIZED_FIELD;
+                                            var.flags_field |= UNINITIALIZED_FIELD;
+                                        } else {
+                                            checkInit(TreeInfo.diagEndPos(tree.body), var);
+                                        }
+                                    } else {
+                                        checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
                                     }
+                                } else {
+                                    checkInit(TreeInfo.diagEndPos(tree.body), var);
                                 }
                             }
                         }
@@ -2124,7 +2132,7 @@
                             Assert.check(exit instanceof AssignPendingExit);
                             inits.assign(((AssignPendingExit) exit).exit_inits);
                             for (int i = firstadr; i < nextadr; i++) {
-                                checkInit(exit.tree.pos(), vardecls[i].sym, isCompactConstructor);
+                                checkInit(exit.tree.pos(), vardecls[i].sym);
                             }
                         }
                     }
@@ -2666,7 +2674,7 @@
             super.visitSelect(tree);
             if (TreeInfo.isThisQualifier(tree.selected) &&
                 tree.sym.kind == VAR) {
-                checkInit(tree.pos(), (VarSymbol)tree.sym, false);
+                checkInit(tree.pos(), (VarSymbol)tree.sym);
             }
         }
 
@@ -2727,7 +2735,7 @@
 
         public void visitIdent(JCIdent tree) {
             if (tree.sym.kind == VAR) {
-                checkInit(tree.pos(), (VarSymbol)tree.sym, false);
+                checkInit(tree.pos(), (VarSymbol)tree.sym);
                 referenced(tree.sym);
             }
         }
--- a/test/langtools/tools/javac/records/RecordCompilationTests.java	Wed Jan 08 19:12:20 2020 +0100
+++ b/test/langtools/tools/javac/records/RecordCompilationTests.java	Wed Jan 08 15:18:58 2020 -0500
@@ -406,6 +406,18 @@
         // x is not DA nor DU in the body of the constructor hence error
         assertFail("compiler.err.var.might.not.have.been.initialized", "record R(int x) { # }",
                 "public R { if (x < 0) { this.x = -x; } }");
+
+        // if static fields are not DA then error
+        assertFail("compiler.err.var.might.not.have.been.initialized",
+                "record R() { # }", "static final String x;");
+
+        // ditto
+        assertFail("compiler.err.var.might.not.have.been.initialized",
+                "record R() { # }", "static final String x; public R {}");
+
+        // ditto
+        assertFail("compiler.err.var.might.not.have.been.initialized",
+                "record R(int i) { # }", "static final String x; public R {}");
     }
 
     public void testReturnInCanonical_Compact() {