# HG changeset patch # User jjg # Date 1515006656 28800 # Node ID b08405cc467a8312355f4a4379cffcf18fddac23 # Parent c08f1067ef57894c3c48d68bbad2e879e1907a7c 8193125: javac should not compile a module if it requires java.base with modifiers Reviewed-by: vromero diff -r c08f1067ef57 -r b08405cc467a src/jdk.compiler/share/classes/com/sun/tools/javac/code/Directive.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Directive.java Wed Jan 03 15:37:35 2018 +0530 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Directive.java Wed Jan 03 11:10:56 2018 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2018, 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 @@ -27,11 +27,13 @@ import java.util.Collections; import java.util.EnumSet; +import java.util.Locale; import java.util.Set; import javax.lang.model.element.ModuleElement; import javax.lang.model.element.ModuleElement.DirectiveVisitor; +import com.sun.tools.javac.api.Messages; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.ModuleSymbol; import com.sun.tools.javac.code.Symbol.PackageSymbol; @@ -71,6 +73,11 @@ } public final int value; + + @Override + public String toString() { + return String.format("ACC_%s (0x%04x", name(), value); + } } /** Flags for ExportsDirective. */ diff -r c08f1067ef57 -r b08405cc467a src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java Wed Jan 03 15:37:35 2018 +0530 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java Wed Jan 03 11:10:56 2018 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2018, 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 @@ -63,6 +63,7 @@ import com.sun.tools.javac.code.Directive.RequiresFlag; import com.sun.tools.javac.code.Directive.UsesDirective; import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Flags.Flag; import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.ModuleFinder; import com.sun.tools.javac.code.Source; @@ -109,11 +110,15 @@ import static com.sun.tools.javac.code.Flags.ENUM; import static com.sun.tools.javac.code.Flags.PUBLIC; import static com.sun.tools.javac.code.Flags.UNATTRIBUTED; + import com.sun.tools.javac.code.Kinds; + import static com.sun.tools.javac.code.Kinds.Kind.ERR; import static com.sun.tools.javac.code.Kinds.Kind.MDL; import static com.sun.tools.javac.code.Kinds.Kind.MTH; + import com.sun.tools.javac.code.Symbol.ModuleResolutionFlags; + import static com.sun.tools.javac.code.TypeTag.CLASS; /** @@ -775,10 +780,20 @@ } else { allRequires.add(msym); Set flags = EnumSet.noneOf(RequiresFlag.class); - if (tree.isTransitive) - flags.add(RequiresFlag.TRANSITIVE); - if (tree.isStaticPhase) - flags.add(RequiresFlag.STATIC_PHASE); + if (tree.isTransitive) { + if (msym == syms.java_base && source.compareTo(Source.JDK10) >= 0) { + log.error(tree.pos(), Errors.ModifierNotAllowedHere(names.transitive)); + } else { + flags.add(RequiresFlag.TRANSITIVE); + } + } + if (tree.isStaticPhase) { + if (msym == syms.java_base && source.compareTo(Source.JDK10) >= 0) { + log.error(tree.pos(), Errors.ModNotAllowedHere(EnumSet.of(Flag.STATIC))); + } else { + flags.add(RequiresFlag.STATIC_PHASE); + } + } RequiresDirective d = new RequiresDirective(msym, flags); tree.directive = d; sym.requires = sym.requires.prepend(d); diff -r c08f1067ef57 -r b08405cc467a src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Wed Jan 03 15:37:35 2018 +0530 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Wed Jan 03 11:10:56 2018 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, 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 @@ -1315,7 +1315,8 @@ throw badClassFile("module.name.mismatch", moduleName, currentModule.name); } - msym.flags.addAll(readModuleFlags(nextChar())); + Set moduleFlags = readModuleFlags(nextChar()); + msym.flags.addAll(moduleFlags); msym.version = readName(nextChar()); ListBuffer requires = new ListBuffer<>(); @@ -1323,6 +1324,14 @@ for (int i = 0; i < nrequires; i++) { ModuleSymbol rsym = syms.enterModule(readModuleName(nextChar())); Set flags = readRequiresFlags(nextChar()); + if (rsym == syms.java_base && majorVersion >= V54.major) { + if (flags.contains(RequiresFlag.TRANSITIVE)) { + throw badClassFile("bad.requires.flag", RequiresFlag.TRANSITIVE); + } + if (flags.contains(RequiresFlag.STATIC_PHASE)) { + throw badClassFile("bad.requires.flag", RequiresFlag.STATIC_PHASE); + } + } nextChar(); // skip compiled version requires.add(new RequiresDirective(rsym, flags)); } diff -r c08f1067ef57 -r b08405cc467a src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Jan 03 15:37:35 2018 +0530 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Jan 03 11:10:56 2018 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2018, 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 @@ -753,6 +753,10 @@ compiler.err.mod.not.allowed.here=\ modifier {0} not allowed here +# 0: name +compiler.err.modifier.not.allowed.here=\ + modifier {0} not allowed here + compiler.err.intf.not.allowed.here=\ interface not allowed here @@ -3131,6 +3135,9 @@ compiler.misc.cant.resolve.modules=\ cannot resolve modules +compiler.misc.bad.requires.flag=\ + bad requires flag: {0} + # 0: string compiler.err.invalid.module.specifier=\ module specifier not allowed: {0} diff -r c08f1067ef57 -r b08405cc467a test/langtools/tools/javac/diags/examples.not-yet.txt --- a/test/langtools/tools/javac/diags/examples.not-yet.txt Wed Jan 03 15:37:35 2018 +0530 +++ b/test/langtools/tools/javac/diags/examples.not-yet.txt Wed Jan 03 11:10:56 2018 -0800 @@ -52,6 +52,7 @@ compiler.misc.bad.enclosing.method # bad class file compiler.misc.bad.runtime.invisible.param.annotations # bad class file compiler.misc.bad.signature # bad class file +compiler.misc.bad.requires.flag # bad class file compiler.misc.bad.type.annotation.value compiler.misc.base.membership # UNUSED compiler.misc.class.file.not.found # ClassReader diff -r c08f1067ef57 -r b08405cc467a test/langtools/tools/javac/diags/examples/ModifierNotAllowed/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/tools/javac/diags/examples/ModifierNotAllowed/module-info.java Wed Jan 03 11:10:56 2018 -0800 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018, 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.modifier.not.allowed.here + +module m { + requires transitive java.base; +} diff -r c08f1067ef57 -r b08405cc467a test/langtools/tools/javac/modules/JavaBaseTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/tools/javac/modules/JavaBaseTest.java Wed Jan 03 11:10:56 2018 -0800 @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2017, 2018, 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. + */ + +/** + * @test + * @bug 8193125 + * @summary test modifiers with java.base + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.jdeps/com.sun.tools.classfile + * @build toolbox.ToolBox toolbox.JavacTask + * @run main JavaBaseTest + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.Attributes; +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.ClassWriter; +import com.sun.tools.classfile.Module_attribute; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.Task.Expect; +import toolbox.ToolBox; + +public class JavaBaseTest { + + public static void main(String... args) throws Exception { + JavaBaseTest t = new JavaBaseTest(); + t.run(); + } + + final List> modifiers = List.of( + List.of("static"), + List.of("transitive"), + List.of("static", "transitive") + ); + + final String specVersion = System.getProperty("java.specification.version"); + final List targets = specVersion.equals("10") + ? List.of("9", "10") + : List.of("9", "10", specVersion); + + enum Mode { SOURCE, CLASS }; + + ToolBox tb = new ToolBox(); + int testCount = 0; + int errorCount = 0; + + void run() throws Exception { + for (List mods : modifiers) { + for (String target : targets) { + for (Mode mode : Mode.values()) { + test(mods, target, mode); + } + } + } + + System.err.println(testCount + " tests"); + if (errorCount > 0) { + throw new Exception(errorCount + " errors found"); + } + } + + void test(List mods, String target, Mode mode) { + System.err.println("Test " + mods + " " + target + " " + mode); + testCount++; + try { + Path base = Paths.get(String.join("-", mods)) + .resolve(target).resolve(mode.name().toLowerCase()); + Files.createDirectories(base); + switch (mode) { + case SOURCE: + testSource(base, mods, target); + break; + case CLASS: + testClass(base, mods, target); + break; + } + } catch (Exception e) { + error("Exception: " + e); + e.printStackTrace(); + } + System.err.println(); + } + + void testSource(Path base, List mods, String target) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + "module m { requires " + String.join(" ", mods) + " java.base; }"); + Path modules = Files.createDirectories(base.resolve("modules")); + boolean expectOK = target.equals("9"); + + String log = new JavacTask(tb) + .outdir(modules) + .options("-XDrawDiagnostics", "--release", target) + .files(tb.findJavaFiles(src)) + .run(expectOK ? Task.Expect.SUCCESS : Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + if (!expectOK) { + boolean foundErrorMessage = false; + for (String mod : mods) { + String key = mod.equals("static") + ? "compiler.err.mod.not.allowed.here" + : "compiler.err.modifier.not.allowed.here"; + String message = "module-info.java:1:12: " + key + ": " + mod; + if (log.contains(message)) { + foundErrorMessage = true; + } + } + if (!foundErrorMessage) { + throw new Exception("expected error message not found"); + } + } + } + + void testClass(Path base, List mods, String target) throws Exception { + createClass(base, mods, target); + + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + "module mx { requires m; }"); + Path modules = Files.createDirectories(base.resolve("modules")); + + boolean expectOK = target.equals("9"); + String log = new JavacTask(tb) + .outdir(modules) + .options("-XDrawDiagnostics", + "--module-path", base.resolve("test-modules").toString()) + .files(tb.findJavaFiles(src)) + .run(expectOK ? Task.Expect.SUCCESS : Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + if (!expectOK) { + boolean foundErrorMessage = false; + for (String mod : mods) { + String flag = mod.equals("static") + ? "ACC_STATIC_PHASE (0x0040)" + : "ACC_TRANSITIVE (0x0020)"; + String message = "- compiler.err.cant.access: m.module-info," + + " (compiler.misc.bad.class.file.header: module-info.class," + + " (compiler.misc.bad.requires.flag: " + flag + ")"; + if (log.contains(message)) { + foundErrorMessage = true; + } + } + if (!foundErrorMessage) { + throw new Exception("expected error message not found"); + } + } + } + + void createClass(Path base, List mods, String target) throws Exception { + Path src1 = base.resolve("interim-src"); + tb.writeJavaFiles(src1, + "module m { requires java.base; }"); + Path modules1 = Files.createDirectories(base.resolve("interim-modules")); + + new JavacTask(tb) + .outdir(modules1) + .options("--release", target) + .files(tb.findJavaFiles(src1)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + ClassFile cf1 = ClassFile.read(modules1.resolve("module-info.class")); + + Map attrMap = new LinkedHashMap<>(cf1.attributes.map); + Module_attribute modAttr1 = (Module_attribute) attrMap.get("Module"); + Module_attribute.RequiresEntry[] requires = + new Module_attribute.RequiresEntry[modAttr1.requires_count]; + for (int i = 0; i < modAttr1.requires_count; i++) { + Module_attribute.RequiresEntry e1 = modAttr1.requires[i]; + int flags = e1.requires_flags; + Module_attribute.RequiresEntry e2; + if (e1.getRequires(cf1.constant_pool).equals("java.base")) { + for (String mod : mods) { + switch (mod) { + case "static": + flags |= Module_attribute.ACC_STATIC_PHASE; + break; + case "transitive": + flags |= Module_attribute.ACC_TRANSITIVE; + break; + } + } + e2 = new Module_attribute.RequiresEntry( + e1.requires_index, + flags, + e1.requires_version_index); + } else { + e2 = e1; + } + requires[i] = e2; + } + Module_attribute modAttr2 = new Module_attribute( + modAttr1.attribute_name_index, + modAttr1.module_name, + modAttr1.module_flags, + modAttr1.module_version_index, + requires, + modAttr1.exports, + modAttr1.opens, + modAttr1.uses_index, + modAttr1.provides); + attrMap.put("Module", modAttr2); + Attributes attributes = new Attributes(attrMap); + + ClassFile cf2 = new ClassFile( + cf1.magic, cf1.minor_version, cf1.major_version, + cf1.constant_pool, cf1.access_flags, + cf1.this_class, cf1.super_class, cf1.interfaces, + cf1.fields, cf1.methods, attributes); + Path modInfo = base.resolve("test-modules").resolve("module-info.class"); + Files.createDirectories(modInfo.getParent()); + new ClassWriter().write(cf2, modInfo.toFile()); + } + + private void error(String message) { + System.err.println("Error: " + message); + errorCount++; + } +} + diff -r c08f1067ef57 -r b08405cc467a test/langtools/tools/javac/processing/model/util/printing/module-info.java --- a/test/langtools/tools/javac/processing/model/util/printing/module-info.java Wed Jan 03 15:37:35 2018 +0530 +++ b/test/langtools/tools/javac/processing/model/util/printing/module-info.java Wed Jan 03 11:10:56 2018 -0800 @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2017, 2018, 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. + */ + /* * @test * @bug 8173609 @@ -10,7 +33,7 @@ */ @Deprecated module printing { - requires static transitive java.base; + requires static transitive java.compiler; exports p to m.m1, m.m2; opens p to m.m1, m.m2; uses p.P; diff -r c08f1067ef57 -r b08405cc467a test/langtools/tools/javac/processing/model/util/printing/module-info.out --- a/test/langtools/tools/javac/processing/model/util/printing/module-info.out Wed Jan 03 15:37:35 2018 +0530 +++ b/test/langtools/tools/javac/processing/model/util/printing/module-info.out Wed Jan 03 11:10:56 2018 -0800 @@ -19,7 +19,8 @@ */ @java.lang.Deprecated module printing { - requires static transitive java.base; + requires java.base; + requires static transitive java.compiler; exports p to m.m1, m.m2; opens p to m.m1, m.m2; uses p.P;