Merge
authorlana
Thu, 06 Oct 2016 23:12:58 +0000
changeset 41445 1a8e5abf305f
parent 41437 589fd293bb4f (current diff)
parent 41444 b61c805c6173 (diff)
child 41446 ecd0b488293c
Merge
--- a/langtools/make/tools/crules/MutableFieldsAnalyzer.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/make/tools/crules/MutableFieldsAnalyzer.java	Thu Oct 06 23:12:58 2016 +0000
@@ -111,6 +111,8 @@
                 "loadMethod");
         ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$VMHelper",
                 "vmClass", "getRuntimeArgumentsMethod");
+        ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$JmodFile",
+                "jmodFileClass", "checkMagicMethod");
     }
 
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Oct 06 23:12:58 2016 +0000
@@ -4415,6 +4415,7 @@
                 chk.checkDeprecatedAnnotation(env.tree.pos(), c);
                 chk.checkClassOverrideEqualsAndHashIfNeeded(env.tree.pos(), c);
                 chk.checkFunctionalInterface((JCClassDecl) env.tree, c);
+                chk.checkLeaksNotAccessible(env, (JCClassDecl) env.tree);
             } finally {
                 env.info.returnResult = prevReturnRes;
                 log.useSource(prev);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Thu Oct 06 23:12:58 2016 +0000
@@ -31,10 +31,13 @@
 
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Attribute.Compound;
+import com.sun.tools.javac.code.Directive.ExportsDirective;
+import com.sun.tools.javac.code.Directive.RequiresDirective;
 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
+import com.sun.tools.javac.resources.CompilerProperties.Warnings;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
@@ -3661,4 +3664,178 @@
         }
     }
 
+    public void checkLeaksNotAccessible(Env<AttrContext> env, JCClassDecl check) {
+        JCCompilationUnit toplevel = env.toplevel;
+
+        if (   toplevel.modle == syms.unnamedModule
+            || toplevel.modle == syms.noModule
+            || (check.sym.flags() & COMPOUND) != 0) {
+            return ;
+        }
+
+        ExportsDirective currentExport = findExport(toplevel.packge);
+
+        if (   currentExport == null //not exported
+            || currentExport.modules != null) //don't check classes in qualified export
+            return ;
+
+        new TreeScanner() {
+            Lint lint = env.info.lint;
+            boolean inSuperType;
+
+            @Override
+            public void visitBlock(JCBlock tree) {
+            }
+            @Override
+            public void visitMethodDef(JCMethodDecl tree) {
+                if (!isAPISymbol(tree.sym))
+                    return;
+                Lint prevLint = lint;
+                try {
+                    lint = lint.augment(tree.sym);
+                    if (lint.isEnabled(LintCategory.EXPORTS)) {
+                        super.visitMethodDef(tree);
+                    }
+                } finally {
+                    lint = prevLint;
+                }
+            }
+            @Override
+            public void visitVarDef(JCVariableDecl tree) {
+                if (!isAPISymbol(tree.sym) && tree.sym.owner.kind != MTH)
+                    return;
+                Lint prevLint = lint;
+                try {
+                    lint = lint.augment(tree.sym);
+                    if (lint.isEnabled(LintCategory.EXPORTS)) {
+                        scan(tree.mods);
+                        scan(tree.vartype);
+                    }
+                } finally {
+                    lint = prevLint;
+                }
+            }
+            @Override
+            public void visitClassDef(JCClassDecl tree) {
+                if (tree != check)
+                    return ;
+
+                if (!isAPISymbol(tree.sym))
+                    return ;
+
+                Lint prevLint = lint;
+                try {
+                    lint = lint.augment(tree.sym);
+                    if (lint.isEnabled(LintCategory.EXPORTS)) {
+                        scan(tree.mods);
+                        scan(tree.typarams);
+                        try {
+                            inSuperType = true;
+                            scan(tree.extending);
+                            scan(tree.implementing);
+                        } finally {
+                            inSuperType = false;
+                        }
+                        scan(tree.defs);
+                    }
+                } finally {
+                    lint = prevLint;
+                }
+            }
+            @Override
+            public void visitTypeApply(JCTypeApply tree) {
+                scan(tree.clazz);
+                boolean oldInSuperType = inSuperType;
+                try {
+                    inSuperType = false;
+                    scan(tree.arguments);
+                } finally {
+                    inSuperType = oldInSuperType;
+                }
+            }
+            @Override
+            public void visitIdent(JCIdent tree) {
+                Symbol sym = TreeInfo.symbol(tree);
+                if (sym.kind == TYP && !sym.type.hasTag(TYPEVAR)) {
+                    checkVisible(tree.pos(), sym, toplevel.packge, inSuperType);
+                }
+            }
+
+            @Override
+            public void visitSelect(JCFieldAccess tree) {
+                Symbol sym = TreeInfo.symbol(tree);
+                Symbol sitesym = TreeInfo.symbol(tree.selected);
+                if (sym.kind == TYP && sitesym.kind == PCK) {
+                    checkVisible(tree.pos(), sym, toplevel.packge, inSuperType);
+                } else {
+                    super.visitSelect(tree);
+                }
+            }
+
+            @Override
+            public void visitAnnotation(JCAnnotation tree) {
+                if (tree.attribute.type.tsym.getAnnotation(java.lang.annotation.Documented.class) != null)
+                    super.visitAnnotation(tree);
+            }
+
+        }.scan(check);
+    }
+        //where:
+        private ExportsDirective findExport(PackageSymbol pack) {
+            for (ExportsDirective d : pack.modle.exports) {
+                if (d.packge == pack)
+                    return d;
+            }
+
+            return null;
+        }
+        private boolean isAPISymbol(Symbol sym) {
+            while (sym.kind != PCK) {
+                if ((sym.flags() & Flags.PUBLIC) == 0 && (sym.flags() & Flags.PROTECTED) == 0) {
+                    return false;
+                }
+                sym = sym.owner;
+            }
+            return true;
+        }
+        private void checkVisible(DiagnosticPosition pos, Symbol what, PackageSymbol inPackage, boolean inSuperType) {
+            if (!isAPISymbol(what) && !inSuperType) { //package private/private element
+                log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessible(kindName(what), what, what.packge().modle));
+                return ;
+            }
+
+            PackageSymbol whatPackage = what.packge();
+            ExportsDirective whatExport = findExport(whatPackage);
+            ExportsDirective inExport = findExport(inPackage);
+
+            if (whatExport == null) { //package not exported:
+                log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessibleUnexported(kindName(what), what, what.packge().modle));
+                return ;
+            }
+
+            if (whatExport.modules != null) {
+                if (inExport.modules == null || !whatExport.modules.containsAll(inExport.modules)) {
+                    log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessibleUnexportedQualified(kindName(what), what, what.packge().modle));
+                }
+            }
+
+            if (whatPackage.modle != inPackage.modle && whatPackage.modle != syms.java_base) {
+                //check that relativeTo.modle requires public what.modle, somehow:
+                List<ModuleSymbol> todo = List.of(inPackage.modle);
+
+                while (todo.nonEmpty()) {
+                    ModuleSymbol current = todo.head;
+                    todo = todo.tail;
+                    if (current == whatPackage.modle)
+                        return ; //OK
+                    for (RequiresDirective req : current.requires) {
+                        if (req.isPublic()) {
+                            todo = todo.prepend(req.module);
+                        }
+                    }
+                }
+
+                log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessibleNotRequiredPublic(kindName(what), what, what.packge().modle));
+            }
+        }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java	Thu Oct 06 23:12:58 2016 +0000
@@ -78,6 +78,7 @@
 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
+import com.sun.tools.javac.util.JDK9Wrappers;
 import com.sun.tools.javac.util.ListBuffer;
 import com.sun.tools.javac.util.Log;
 import com.sun.tools.javac.jvm.ModuleNameReader;
@@ -1103,6 +1104,11 @@
 
                 if (p.getFileName().toString().endsWith(".jmod")) {
                     try {
+                        // check if the JMOD file is valid
+                        JDK9Wrappers.JmodFile.checkMagic(p);
+
+                        // No JMOD file system.  Use JarFileSystem to
+                        // workaround for now
                         FileSystem fs = fileSystems.get(p);
                         if (fs == null) {
                             URI uri = URI.create("jar:" + p.toUri());
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/CommandLine.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/CommandLine.java	Thu Oct 06 23:12:58 2016 +0000
@@ -27,7 +27,6 @@
 
 import java.io.IOException;
 import java.io.Reader;
-import java.io.StreamTokenizer;
 import java.nio.file.Files;
 import java.nio.file.Paths;
 
@@ -51,10 +50,11 @@
      * '@file' argument replaced with the resulting tokens. Recursive command
      * files are not supported. The '@' character itself can be quoted with
      * the sequence '@@'.
+     * @param args the arguments that may contain @files
+     * @return the arguments, with @files expanded
+     * @throws IOException if there is a problem reading any of the @files
      */
-    public static String[] parse(String[] args)
-        throws IOException
-    {
+    public static String[] parse(String[] args) throws IOException {
         ListBuffer<String> newArgs = new ListBuffer<>();
         for (String arg : args) {
             if (arg.length() > 1 && arg.charAt(0) == '@') {
@@ -71,19 +71,120 @@
         return newArgs.toList().toArray(new String[newArgs.length()]);
     }
 
-    private static void loadCmdFile(String name, ListBuffer<String> args)
-        throws IOException
-    {
+    private static void loadCmdFile(String name, ListBuffer<String> args) throws IOException {
         try (Reader r = Files.newBufferedReader(Paths.get(name))) {
-            StreamTokenizer st = new StreamTokenizer(r);
-            st.resetSyntax();
-            st.wordChars(' ', 255);
-            st.whitespaceChars(0, ' ');
-            st.commentChar('#');
-            st.quoteChar('"');
-            st.quoteChar('\'');
-            while (st.nextToken() != StreamTokenizer.TT_EOF) {
-                args.append(st.sval);
+            Tokenizer t = new Tokenizer(r);
+            String s;
+            while ((s = t.nextToken()) != null) {
+                args.append(s);
+            }
+        }
+    }
+
+    public static class Tokenizer {
+        private final Reader in;
+        private int ch;
+
+        public Tokenizer(Reader in) throws IOException {
+            this.in = in;
+            ch = in.read();
+        }
+
+        public String nextToken() throws IOException {
+            skipWhite();
+            if (ch == -1) {
+                return null;
+            }
+
+            StringBuilder sb = new StringBuilder();
+            char quoteChar = 0;
+
+            while (ch != -1) {
+                switch (ch) {
+                    case ' ':
+                    case '\t':
+                    case '\f':
+                        if (quoteChar == 0) {
+                            return sb.toString();
+                        }
+                        sb.append((char) ch);
+                        break;
+
+                    case '\n':
+                    case '\r':
+                        return sb.toString();
+
+                    case '\'':
+                    case '"':
+                        if (quoteChar == 0) {
+                            quoteChar = (char) ch;
+                        } else if (quoteChar == ch) {
+                            quoteChar = 0;
+                        } else {
+                            sb.append((char) ch);
+                        }
+                        break;
+
+                    case '\\':
+                        if (quoteChar != 0) {
+                            ch = in.read();
+                            switch (ch) {
+                                case '\n':
+                                case '\r':
+                                    while (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f') {
+                                        ch = in.read();
+                                    }
+                                    continue;
+
+                                case 'n':
+                                    ch = '\n';
+                                    break;
+                                case 'r':
+                                    ch = '\r';
+                                    break;
+                                case 't':
+                                    ch = '\t';
+                                    break;
+                                case 'f':
+                                    ch = '\f';
+                                    break;
+                            }
+                        }
+                        sb.append((char) ch);
+                        break;
+
+                    default:
+                        sb.append((char) ch);
+                }
+
+                ch = in.read();
+            }
+
+            return sb.toString();
+        }
+
+        void skipWhite() throws IOException {
+            while (ch != -1) {
+                switch (ch) {
+                    case ' ':
+                    case '\t':
+                    case '\n':
+                    case '\r':
+                    case '\f':
+                        break;
+
+                    case '#':
+                        ch = in.read();
+                        while (ch != '\n' && ch != '\r' && ch != -1) {
+                            ch = in.read();
+                        }
+                        break;
+
+                    default:
+                        return;
+                }
+
+                ch = in.read();
             }
         }
     }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Oct 06 23:12:58 2016 +0000
@@ -2865,6 +2865,19 @@
 compiler.warn.service.provided.but.not.exported.or.used=\
     service interface provided but not exported or used
 
+# 0: kind name, 1: symbol, 2: symbol
+compiler.warn.leaks.not.accessible=\
+    {0} {1} in module {2} is not accessible to clients that require this module
+# 0: kind name, 1: symbol, 2: symbol
+compiler.warn.leaks.not.accessible.unexported=\
+    {0} {1} in module {2} is not exported
+# 0: kind name, 1: symbol, 2: symbol
+compiler.warn.leaks.not.accessible.not.required.public=\
+    {0} {1} in module {2} is not indirectly exported using 'requires public'
+# 0: kind name, 1: symbol, 2: symbol
+compiler.warn.leaks.not.accessible.unexported.qualified=\
+    {0} {1} in module {2} may not be visible to all clients that require this module
+
 ###
 # errors related to options
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Iterators.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Iterators.java	Thu Oct 06 23:12:58 2016 +0000
@@ -46,7 +46,8 @@
 
         private final Iterator<I> inputs;
         private final Function<I, Iterator<O>> convertor;
-        private Iterator<O> currentIterator;
+        @SuppressWarnings("unchecked")
+        private Iterator<O> currentIterator = EMPTY;
 
         public CompoundIterator(Iterable<I> inputs, Function<I, Iterator<O>> convertor) {
             this.inputs = inputs.iterator();
@@ -54,10 +55,10 @@
         }
 
         public boolean hasNext() {
-            while (inputs.hasNext() && (currentIterator == null || !currentIterator.hasNext())) {
-                currentIterator = convertor.apply(inputs.next());
+            if (currentIterator != null && !currentIterator.hasNext()) {
+                update();
             }
-            return currentIterator != null && currentIterator.hasNext();
+            return currentIterator != null;
         }
 
         public O next() {
@@ -70,5 +71,25 @@
         public void remove() {
             throw new UnsupportedOperationException();
         }
+
+        private void update() {
+            while (inputs.hasNext()) {
+                currentIterator = convertor.apply(inputs.next());
+                if (currentIterator.hasNext()) return;
+            }
+            currentIterator = null;
+        }
     }
+
+    @SuppressWarnings("rawtypes")
+    private final static Iterator EMPTY = new Iterator() {
+        public boolean hasNext() {
+            return false;
+        }
+
+        @Override
+        public Object next() {
+            return null;
+        }
+    };
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JDK9Wrappers.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JDK9Wrappers.java	Thu Oct 06 23:12:58 2016 +0000
@@ -25,6 +25,7 @@
 
 package com.sun.tools.javac.util;
 
+import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.nio.file.Path;
@@ -367,4 +368,41 @@
             }
         }
     }
+
+    /**
+     * Helper class for new method in jdk.internal.jmod.JmodFile
+     */
+    public static final class JmodFile {
+        public static final String JMOD_FILE_CLASSNAME = "jdk.internal.jmod.JmodFile";
+
+        public static void checkMagic(Path file) throws IOException {
+            try {
+                init();
+                checkMagicMethod.invoke(null, file);
+            } catch (InvocationTargetException ex) {
+                if (ex.getCause() instanceof IOException) {
+                    throw IOException.class.cast(ex.getCause());
+                }
+                throw new Abort(ex);
+            } catch (IllegalAccessException | IllegalArgumentException | SecurityException ex) {
+                throw new Abort(ex);
+            }
+        }
+
+        // -----------------------------------------------------------------------------------------
+
+        private static Class<?> jmodFileClass = null;
+        private static Method checkMagicMethod = null;
+
+        private static void init() {
+            if (jmodFileClass == null) {
+                try {
+                    jmodFileClass = Class.forName(JMOD_FILE_CLASSNAME, false, null);
+                    checkMagicMethod = jmodFileClass.getDeclaredMethod("checkMagic", Path.class);
+                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
+                    throw new Abort(ex);
+                }
+            }
+        }
+    }
 }
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java	Thu Oct 06 23:12:58 2016 +0000
@@ -89,8 +89,6 @@
  *  - multi-version jar
  */
 public class Main implements DiagnosticListener<JavaFileObject> {
-    public static Main instance;
-
     final PrintStream out;
     final PrintStream err;
     final List<File> bootClassPath = new ArrayList<>();
@@ -415,13 +413,6 @@
     }
 
     /**
-     * Prints a usage message to the err stream.
-     */
-    void usage() {
-
-    }
-
-    /**
      * An enum denoting the mode in which the tool is running.
      * Different modes correspond to the different process* methods.
      * The exception is UNKNOWN, which indicates that a mode wasn't
@@ -504,7 +495,6 @@
                     args.remove();
                     switch (a) {
                         case "--class-path":
-                        case "-cp":
                             classPath.clear();
                             Arrays.stream(args.remove().split(File.pathSeparator))
                                   .map(File::new)
@@ -699,12 +689,7 @@
      * @return true on success, false otherwise
      */
     public static boolean call(PrintStream out, PrintStream err, String... args) {
-        try {
-            instance = new Main(out, err);
-            return instance.run(args);
-        } finally {
-            instance = null;
-        }
+        return new Main(out, err).run(args);
     }
 
     /**
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md	Thu Oct 06 23:12:58 2016 +0000
@@ -39,7 +39,6 @@
 
 **OPTIONS**
 
-        -cp PATH
         --class-path PATH
 
             Sets the classpath to PATH.
@@ -103,7 +102,7 @@
 
         java.lang.Thread$State
 
-The `--class-path` and `-cp` options specify the classpath used for
+The `--class-path` option specifies the classpath used for
 class searching. The classpath is used for classes named on the
 command line, as well as for dependencies of the classes in jar file
 or directory hierarchy to be scanned.
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties	Thu Oct 06 23:12:58 2016 +0000
@@ -2,7 +2,7 @@
 Usage: jdeprscan [options] '{dir|jar|class}' ...\n\
 \n\
 options:\n\
-\  -cp  --class-path PATH\n\
+\       --class-path PATH\n\
 \       --for-removal\n\
 \       --full-version\n\
 \  -h   --help\n\
@@ -20,7 +20,7 @@
 \n\
 \    java.lang.Thread$State\n\
 \n\
-The --class-path (-cp) option provides a search path for resolution\n\
+The --class-path option provides a search path for resolution\n\
 of dependent classes.\n\
 \n\
 The --for-removal option limits scanning or listing to APIs that are\n\
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Thu Oct 06 23:12:58 2016 +0000
@@ -63,7 +63,7 @@
      * Returns a ClassFileReader instance of a given path.
      */
     public static ClassFileReader newInstance(Path path) throws IOException {
-        return newInstance(path, JarFile.baseVersion());
+        return newInstance(path, null);
     }
 
     /**
@@ -438,7 +438,10 @@
                     cf = reader.readClassFile(jf, nextEntry);
                     return true;
                 } catch (ClassFileError | IOException ex) {
-                    skippedEntries.add(nextEntry.getName());
+                    skippedEntries.add(String.format("%s: %s (%s)",
+                                                     ex.getMessage(),
+                                                     nextEntry.getName(),
+                                                     jf.getName()));
                 }
                 nextEntry = nextEntry();
             }
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java	Thu Oct 06 23:12:58 2016 +0000
@@ -483,6 +483,7 @@
             }
             if (options.checkModuleDeps != null && !inputArgs.isEmpty()) {
                 reportError("err.invalid.module.option", inputArgs, "--check");
+                return EXIT_CMDERR;
             }
 
             boolean ok = run();
@@ -604,11 +605,12 @@
         boolean ok = analyzer.run(options.compileTimeView, options.depth);
 
         // print skipped entries, if any
-        analyzer.archives()
-            .forEach(archive -> archive.reader()
-                .skippedEntries().stream()
-                .forEach(name -> warning("warn.skipped.entry",
-                                         name, archive.getPathName())));
+        if (!options.nowarning) {
+            analyzer.archives()
+                .forEach(archive -> archive.reader()
+                    .skippedEntries().stream()
+                    .forEach(name -> warning("warn.skipped.entry", name)));
+        }
 
         if (options.findJDKInternals && !options.nowarning) {
             Map<String, String> jdkInternals = new TreeMap<>();
@@ -676,17 +678,29 @@
     }
 
     private boolean genModuleInfo(JdepsConfiguration config) throws IOException {
+        // check if any JAR file contains unnamed package
+        for (String arg : inputArgs) {
+            Optional<String> classInUnnamedPackage =
+                ClassFileReader.newInstance(Paths.get(arg))
+                    .entries().stream()
+                    .filter(n -> n.endsWith(".class"))
+                    .filter(cn -> toPackageName(cn).isEmpty())
+                    .findFirst();
+
+            if (classInUnnamedPackage.isPresent()) {
+                if (classInUnnamedPackage.get().equals("module-info.class")) {
+                    reportError("err.genmoduleinfo.not.jarfile", arg);
+                } else {
+                    reportError("err.genmoduleinfo.unnamed.package", arg);
+                }
+                return false;
+            }
+        }
+
         ModuleInfoBuilder builder
             = new ModuleInfoBuilder(config, inputArgs, options.genModuleInfo);
         boolean ok = builder.run();
 
-        builder.modules().forEach(module -> {
-            if (module.packages().contains("")) {
-                reportError("ERROR: %s contains unnamed package.  " +
-                    "module-info.java not generated%n", module.getPathName());
-            }
-        });
-
         if (!ok && !options.nowarning) {
             log.println("ERROR: missing dependencies");
             builder.visitMissingDeps(
@@ -703,6 +717,11 @@
         return ok;
     }
 
+    private String toPackageName(String name) {
+        int i = name.lastIndexOf('/');
+        return i > 0 ? name.replace('/', '.').substring(0, i) : "";
+    }
+
     /**
      * Returns a filter used during dependency analysis
      */
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Thu Oct 06 23:12:58 2016 +0000
@@ -166,7 +166,8 @@
 err.missing.arg=no value given for {0}
 err.invalid.arg.for.option=invalid argument for option: {0}
 err.option.after.class=option must be specified before classes: {0}
-err.genmoduleinfo.not.jarfile={0} not valid for --generate-module-info option (must be non-modular JAR file)
+err.genmoduleinfo.not.jarfile={0} is a modular JAR file that cannot be specified with the --generate-module-info option
+err.genmoduleinfo.unnamed.package={0} contains an unnamed package that is not allowed in a module
 err.profiles.msg=No profile information
 err.exception.message={0}
 err.invalid.path=invalid path: {0}
@@ -180,6 +181,7 @@
 err.multirelease.version.associated=class {0} already associated with version {1}, trying to add version {2}
 err.multirelease.jar.malformed=malformed multi-release jar, {0}, bad entry: {1}
 warn.invalid.arg=Path does not exist: {0}
+warn.skipped.entry={0}
 warn.split.package=package {0} defined in {1} {2}
 warn.replace.useJDKInternals=\
 JDK internal APIs are unsupported and private to JDK implementation that are\n\
--- a/langtools/test/tools/javac/T8003967/DetectMutableStaticFields.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/test/tools/javac/T8003967/DetectMutableStaticFields.java	Thu Oct 06 23:12:58 2016 +0000
@@ -118,6 +118,8 @@
                 "loadMethod");
         ignore("com/sun/tools/javac/util/JDK9Wrappers$VMHelper",
                 "vmClass", "getRuntimeArgumentsMethod");
+        ignore("com/sun/tools/javac/util/JDK9Wrappers$JmodFile",
+                "jmodFileClass", "checkMagicMethod");
     }
 
     private final List<String> errors = new ArrayList<>();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessible/LeaksNotAccessible.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016, 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.warn.leaks.not.accessible
+// options: -Xlint:exports
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessible/modulesourcepath/m1/api/Api.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+package api;
+
+public class Api {
+     public Impl getImpl() {
+         return null;
+     }
+}
+
+class Impl {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessible/modulesourcepath/m1/module-info.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+module m1 {
+     exports api;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/LeaksNotAccessibleNotRequiredPublic.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016, 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.warn.leaks.not.accessible.not.required.public
+// options: -Xlint:exports
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m1/api1/Api1.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+package api1;
+
+public class Api1 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m1/module-info.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+module m1 {
+     exports api1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m2/api2/Api2.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+package api2;
+
+public class Api2 {
+     public api1.Api1 getApi1() {
+         return null;
+     }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m2/module-info.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+module m2 {
+     requires m1;
+     exports api2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/LeaksNotAccessibleUnexported.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016, 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.warn.leaks.not.accessible.unexported
+// options: -Xlint:exports
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/api/Api.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+package api;
+
+public class Api {
+     public impl.Impl getImpl() {
+         return null;
+     }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/impl/Impl.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+package impl;
+
+public class Impl {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/module-info.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+module m1 {
+     exports api;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/LeaksNotAccessibleUnexportedQualified.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016, 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.warn.leaks.not.accessible.unexported.qualified
+// options: -Xlint:exports
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/api/Api.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+package api;
+
+public class Api {
+     public qapi.QApi get() {
+         return null;
+     }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/module-info.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+module m1 {
+     exports api;
+     exports qapi to m2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/qapi/QApi.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+package qapi;
+
+public class QApi {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m2/module-info.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+module m2 {
+     requires m1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/main/AtFileTest.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016, 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 8166472 8162810
+ * @summary Align javac support for at-files with launcher support
+ * @modules jdk.compiler/com.sun.tools.javac.main
+ */
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.sun.tools.javac.main.CommandLine.Tokenizer;
+
+public class AtFileTest {
+
+    public static void main(String... args) throws IOException {
+        AtFileTest t = new AtFileTest();
+        if (args.length > 0) {
+            System.out.println(String.join(" ", args));
+        } else {
+            t.run();
+        }
+    }
+
+    void run() throws IOException {
+        test("-version -cp \"c:\\\\java libs\\\\one.jar\" \n",
+                "-version", "-cp", "c:\\java libs\\one.jar");
+
+        // note the open quote at the end
+        test("com.foo.Panda \"Furious 5\"\fand\t'Shi Fu' \"escape\tprison",
+                "com.foo.Panda", "Furious 5", "and", "Shi Fu", "escape\tprison");
+
+        test("escaped chars testing \"\\a\\b\\c\\f\\n\\r\\t\\v\\9\\6\\23\\82\\28\\377\\477\\278\\287\"",
+                "escaped", "chars", "testing", "abc\f\n\r\tv96238228377477278287");
+
+        test("\"mix 'single quote' in double\" 'mix \"double quote\" in single' partial\"quote me\"this",
+                "mix 'single quote' in double", "mix \"double quote\" in single", "partialquote methis");
+
+        test("line one #comment\n'line #2' #rest are comment\r\n#comment on line 3\nline 4 #comment to eof",
+                "line", "one", "line #2", "line", "4");
+
+        test("This is an \"open quote \n    across line\n\t, note for WS.",
+                "This", "is", "an", "open quote ", "across", "line", ",", "note", "for", "WS.");
+
+        test("Try \"this \\\\\\\\ escape\\n double quote \\\" in open quote",
+                "Try", "this \\\\ escape\n double quote \" in open quote");
+
+        test("'-Dmy.quote.single'='Property in single quote. Here a double quote\" Add some slashes \\\\/'",
+                "-Dmy.quote.single=Property in single quote. Here a double quote\" Add some slashes \\/");
+
+        test("\"Open quote to \n  new \"line \\\n\r   third\\\n\r\\\tand\ffourth\"",
+                "Open quote to ", "new", "line third\tand\ffourth");
+
+        test("c:\\\"partial quote\"\\lib",
+                "c:\\partial quote\\lib");
+    }
+
+    void test(String full, String... expect) throws IOException {
+        System.out.println("test: >>>" + full + "<<<");
+        List<String> found = expand(full);
+        if (found.equals(Arrays.asList(expect))) {
+            System.out.println("OK");
+        } else {
+            for (int i = 0; i < Math.max(found.size(), expect.length); i++) {
+                if (i < found.size()) {
+                    System.out.println("found[" + i + "]:  >>>" + found.get(i) + "<<<");
+                }
+                if (i < expect.length) {
+                    System.out.println("expect[" + i + "]: >>>" + expect[i] + "<<<");
+                }
+            }
+        }
+        System.out.println();
+    }
+
+    List<String> expand(String full) throws IOException {
+        Tokenizer t = new Tokenizer(new StringReader(full));
+        List<String> result = new ArrayList<>();
+        String s;
+        while ((s = t.nextToken()) != null) {
+//            System.err.println("token: " + s);
+            result.add(s);
+        }
+        return result;
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/modules/ExportsUnexported.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2016, 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
+ * @summary tests for module declarations
+ * @library /tools/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.main
+ * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase
+ * @run main ExportsUnexported
+ */
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import toolbox.JavacTask;
+import toolbox.Task;
+
+public class ExportsUnexported extends ModuleTestBase {
+
+    public static void main(String... args) throws Exception {
+        ExportsUnexported t = new ExportsUnexported();
+        t.runTests();
+    }
+
+    @Test
+    public void testLocations(Path base) throws Exception {
+        String warningsTest = "package api;\n" +
+                      "import impl.impl.*;\n" +
+                      "@impl.impl^.DocAnn\n" +
+                      "public abstract class Api<T extends impl.impl^.Cls&impl.impl^.Intf> extends impl.impl^.Cls implements impl.impl^.Intf, impl.impl^.NonDocAnn, impl.impl^.DocAnn {\n" +
+                      "    public static <E extends impl.impl^.Cls&impl.impl^.Intf> impl.impl^.Cls m(impl.impl^.Intf i, impl.impl^.Cls c) throws impl.impl^.Exc { return null; }\n" +
+                      "    public static impl.impl^.Cls f;\n" +
+                      "}";
+        String noWarningsTest = "package api;\n" +
+                      "import impl.impl.*;\n" +
+                      "@impl.impl.NonDocAnn\n" +
+                      "public abstract class Api {\n" +
+                      "    private static abstract class I <T extends impl.impl.Cls&impl.impl.Intf> extends impl.impl.Cls implements impl.impl.Intf, impl.impl.NonDocAnn, impl.impl.DocAnn {\n" +
+                      "        public static abstract class II <T extends impl.impl.Cls&impl.impl.Intf> extends impl.impl.Cls implements impl.impl.Intf, impl.impl.NonDocAnn, impl.impl.DocAnn { }\n" +
+                      "        public static <E extends impl.impl.Cls&impl.impl.Intf> impl.impl.Cls m(impl.impl.Intf i, impl.impl.Cls c) throws impl.impl.Exc { return null; }\n" +
+                      "        public static impl.impl.Cls f;\n" +
+                      "    }\n" +
+                      "    private static <E extends impl.impl.Cls&impl.impl.Intf> impl.impl.Cls m(impl.impl.Intf i, impl.impl.Cls c) throws impl.impl.Exc { return null; }\n" +
+                      "    private static impl.impl.Cls f1;\n" +
+                      "    public static void m() { new impl.impl.Cls(); }\n" +
+                      "    public static Object f2 = new impl.impl.Cls();\n" +
+                      "}";
+        for (String genericTest : new String[] {warningsTest, noWarningsTest}) {
+            for (String test : new String[] {genericTest, genericTest.replaceAll("impl\\.impl\\^.([A-Za-z])", "^$1").replaceAll("impl\\.impl\\.([A-Za-z])", "$1")}) {
+                System.err.println("testing: " + test);
+
+                Path src = base.resolve("src");
+                Path src_m1 = src.resolve("m1");
+                StringBuilder testCode = new StringBuilder();
+                List<String> expectedLog = new ArrayList<>();
+                int line = 1;
+                int col  = 1;
+
+                for (int i = 0; i < test.length(); i++) {
+                    char c = test.charAt(i);
+
+                    if (c == '^') {
+                        StringBuilder typeName = new StringBuilder();
+                        for (int j = i + 1 + (test.charAt(i + 1) == '.' ? 1 : 0);
+                             j < test.length() && Character.isJavaIdentifierPart(test.charAt(j));
+                             j++) {
+                            typeName.append(test.charAt(j));
+                        }
+                        String kindName;
+                        switch (typeName.toString()) {
+                            case "Exc": case "DocAnn": case "NonDocAnn":
+                            case "Cls": kindName = "kindname.class"; break;
+                            case "Intf": kindName = "kindname.interface"; break;
+                            default:
+                                throw new AssertionError(typeName.toString());
+                        }
+                        expectedLog.add("Api.java:" + line + ":" + col + ": compiler.warn.leaks.not.accessible.unexported: " + kindName + ", impl.impl." + typeName + ", m1");
+                        continue;
+                    }
+
+                    if (c == '\n') {
+                        line++;
+                        col = 0;
+                    }
+
+                    testCode.append(c);
+                    col++;
+                }
+
+                if (!expectedLog.isEmpty()) {
+                    expectedLog.add("" + expectedLog.size() + " warning" + (expectedLog.size() == 1 ? "" : "s"));
+                    expectedLog.add("- compiler.err.warnings.and.werror");
+                    expectedLog.add("1 error");
+                }
+
+                Collections.sort(expectedLog);
+
+                tb.writeJavaFiles(src_m1,
+                                  "module m1 { exports api; }",
+                                  testCode.toString(),
+                                  "package impl.impl; public class Cls { }",
+                                  "package impl.impl; public class Exc extends Exception { }",
+                                  "package impl.impl; public interface Intf { }",
+                                  "package impl.impl; @java.lang.annotation.Documented public @interface DocAnn { }",
+                                  "package impl.impl; public @interface NonDocAnn { }");
+                Path classes = base.resolve("classes");
+                tb.createDirectories(classes);
+
+                List<String> log = new JavacTask(tb)
+                        .options("-XDrawDiagnostics",
+                                 "-Werror",
+                                 "--module-source-path", src.toString(),
+                                 "-Xlint:exports")
+                        .outdir(classes)
+                        .files(findJavaFiles(src))
+                        .run(expectedLog.isEmpty() ? Task.Expect.SUCCESS : Task.Expect.FAIL)
+                        .writeAll()
+                        .getOutputLines(Task.OutputKind.DIRECT);
+
+                log = new ArrayList<>(log);
+                Collections.sort(log);
+
+                if (expectedLog.isEmpty() ? !log.equals(Arrays.asList("")) : !log.equals(expectedLog)) {
+                    throw new Exception("expected output not found in: " + log + "; " + expectedLog);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testAccessibleToSpecificOrAll(Path base) throws Exception {
+        Path src = base.resolve("src");
+        Path src_lib1 = src.resolve("lib1");
+        tb.writeJavaFiles(src_lib1,
+                          "module lib1 { exports lib1; }",
+                          "package lib1; public class Lib1 {}");
+        Path src_lib2 = src.resolve("lib2");
+        tb.writeJavaFiles(src_lib2,
+                          "module lib2 { exports lib2; }",
+                          "package lib2; public class Lib2 {}");
+        Path src_api = src.resolve("api");
+        tb.writeJavaFiles(src_api,
+                          "module api {\n" +
+                          "    exports api;\n" +
+                          "    exports qapi1 to qual1;\n" +
+                          "    exports qapi2 to qual1, qual2;\n" +
+                          "    requires public lib1;\n" +
+                          "    requires lib2;\n" +
+                          "}\n",
+                          "package api;\n" +
+                          "public class Api {\n" +
+                          "    public lib1.Lib1 lib1;\n" +
+                          "    public lib2.Lib2 lib2;\n" +
+                          "    public qapi1.QApi1 qapi1;\n" +
+                          "    public impl.Impl impl;\n" +
+                          "}",
+                          "package qapi1;\n" +
+                          "public class QApi1 {\n" +
+                          "    public qapi2.QApi2 qapi2;\n" +
+                          "}",
+                          "package qapi2;\n" +
+                          "public class QApi2 {\n" +
+                          "    public qapi1.QApi1 qapi1;\n" +
+                          "}",
+                          "package impl;\n" +
+                          "public class Impl {\n" +
+                          "}");
+        Path src_qual1 = src.resolve("qual1");
+        tb.writeJavaFiles(src_qual1, "module qual1 { }");
+        Path src_qual2 = src.resolve("qual2");
+        tb.writeJavaFiles(src_qual2, "module qual2 { }");
+        Path classes = base.resolve("classes");
+        tb.createDirectories(classes);
+
+        List<String> log = new JavacTask(tb)
+                .options("-XDrawDiagnostics",
+                         "-Werror",
+                         "--module-source-path", src.toString(),
+                         "-Xlint:exports")
+                .outdir(classes)
+                .files(findJavaFiles(src))
+                .run(Task.Expect.FAIL)
+                .writeAll()
+                .getOutputLines(Task.OutputKind.DIRECT);
+
+        List<String> expected = Arrays.asList(
+            "Api.java:4:16: compiler.warn.leaks.not.accessible.not.required.public: kindname.class, lib2.Lib2, lib2",
+            "Api.java:5:17: compiler.warn.leaks.not.accessible.unexported.qualified: kindname.class, qapi1.QApi1, api",
+            "Api.java:6:16: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl, api",
+            "- compiler.err.warnings.and.werror",
+            "1 error",
+            "3 warnings"
+        );
+
+        if (!log.equals(expected))
+            throw new Exception("expected output not found");
+    }
+
+    @Test
+    public void testNestedClasses(Path base) throws Exception {
+        Path src = base.resolve("src");
+        Path src_api = src.resolve("api");
+        tb.writeJavaFiles(src_api,
+                          "module api {\n" +
+                          "    exports api;\n" +
+                          "}\n",
+                          "package api;\n" +
+                          "import impl.Impl.Nested;\n" +
+                          "public class Api {\n" +
+                          "    public impl.Impl impl1;\n" +
+                          "    public impl.Impl.Nested impl2;\n" +
+                          "    public Nested impl3;\n" +
+                          "}",
+                          "package impl;\n" +
+                          "public class Impl {\n" +
+                          "    public static class Nested {\n" +
+                          "    }\n" +
+                          "}");
+        Path classes = base.resolve("classes");
+        tb.createDirectories(classes);
+
+        List<String> log = new JavacTask(tb)
+                .options("-XDrawDiagnostics",
+                         "-Werror",
+                         "--module-source-path", src.toString(),
+                         "-Xlint:exports")
+                .outdir(classes)
+                .files(findJavaFiles(src))
+                .run(Task.Expect.FAIL)
+                .writeAll()
+                .getOutputLines(Task.OutputKind.DIRECT);
+
+        List<String> expected = Arrays.asList(
+            "Api.java:4:16: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl, api",
+            "Api.java:5:16: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl, api",
+            "Api.java:6:12: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl.Nested, api",
+            "- compiler.err.warnings.and.werror",
+            "1 error",
+            "3 warnings"
+        );
+
+        if (!log.equals(expected))
+            throw new Exception("expected output not found");
+    }
+
+    @Test
+    public void testProtectedAndInaccessible(Path base) throws Exception {
+        Path src = base.resolve("src");
+        Path src_api = src.resolve("api");
+        tb.writeJavaFiles(src_api,
+                          "module api {\n" +
+                          "    exports api;\n" +
+                          "}\n",
+                          "package api;\n" +
+                          "public class Api extends PackagePrivateClass<PackagePrivateInterface> implements PackagePrivateInterface<PackagePrivateClass> {\n" +
+                          "    protected PackagePrivateClass<?> f1;\n" +
+                          "    protected PackagePrivateInterface<?> f2;\n" +
+                          "    protected Inner f3;\n" +
+                          "    protected PrivateInner f4;\n" +
+                          "    protected impl.Impl f5;\n" +
+                          "    public static class InnerClass extends PrivateInner {}\n" +
+                          "    protected static class Inner {}\n" +
+                          "    private static class PrivateInner {}\n" +
+                          "}\n" +
+                          "class PackagePrivateClass<T> {}\n" +
+                          "interface PackagePrivateInterface<T> {}",
+                          "package impl;\n" +
+                          "public class Impl {\n" +
+                          "}");
+        Path classes = base.resolve("classes");
+        tb.createDirectories(classes);
+
+        List<String> log = new JavacTask(tb)
+                .options("-XDrawDiagnostics",
+                         "-Werror",
+                         "--module-source-path", src.toString(),
+                         "-Xlint:exports")
+                .outdir(classes)
+                .files(findJavaFiles(src))
+                .run(Task.Expect.FAIL)
+                .writeAll()
+                .getOutputLines(Task.OutputKind.DIRECT);
+
+        List<String> expected = Arrays.asList(
+            "Api.java:2:46: compiler.warn.leaks.not.accessible: kindname.interface, api.PackagePrivateInterface, api",
+            "Api.java:2:106: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api",
+            "Api.java:3:15: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api",
+            "Api.java:4:15: compiler.warn.leaks.not.accessible: kindname.interface, api.PackagePrivateInterface, api",
+            "Api.java:6:15: compiler.warn.leaks.not.accessible: kindname.class, api.Api.PrivateInner, api",
+            "Api.java:7:19: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl, api",
+            "- compiler.err.warnings.and.werror",
+            "1 error",
+            "6 warnings"
+        );
+
+        if (!log.equals(expected))
+            throw new Exception("expected output not found");
+    }
+
+    @Test
+    public void testSuppressResetProperly(Path base) throws Exception {
+        Path src = base.resolve("src");
+        Path src_api = src.resolve("api");
+        tb.writeJavaFiles(src_api,
+                          "module api {\n" +
+                          "    exports api;\n" +
+                          "}\n",
+                          "package api;\n" +
+                          "public class Api {\n" +
+                          "    @SuppressWarnings(\"exports\")\n" +
+                          "    public PackagePrivateClass f1;\n" +
+                          "    public PackagePrivateClass f2;\n" +
+                          "    @SuppressWarnings(\"exports\")\n" +
+                          "    public void t() {}\n" +
+                          "    public PackagePrivateClass f3;\n" +
+                          "    @SuppressWarnings(\"exports\")\n" +
+                          "    public static class C {\n" +
+                          "        public PackagePrivateClass f4;\n" +
+                          "    }\n" +
+                          "    public PackagePrivateClass f5;\n" +
+                          "}\n" +
+                          "class PackagePrivateClass<T> {}\n");
+        Path classes = base.resolve("classes");
+        tb.createDirectories(classes);
+
+        List<String> log = new JavacTask(tb)
+                .options("-XDrawDiagnostics",
+                         "-Werror",
+                         "--module-source-path", src.toString(),
+                         "-Xlint:exports")
+                .outdir(classes)
+                .files(findJavaFiles(src))
+                .run(Task.Expect.FAIL)
+                .writeAll()
+                .getOutputLines(Task.OutputKind.DIRECT);
+
+        List<String> expected = Arrays.asList(
+            "Api.java:5:12: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api",
+            "Api.java:8:12: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api",
+            "Api.java:13:12: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api",
+            "- compiler.err.warnings.and.werror",
+            "1 error",
+            "3 warnings"
+        );
+
+        if (!log.equals(expected))
+            throw new Exception("expected output not found");
+    }
+
+}
--- a/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java	Thu Oct 06 23:12:58 2016 +0000
@@ -74,7 +74,7 @@
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         try (PrintStream out = new PrintStream(baos, false, "UTF-8")) {
             boolean r = Main.call(out, System.err,
-                "-cp", deprcases, "--Xload-dir", deprcases, deprusage);
+                "--class-path", deprcases, "--Xload-dir", deprcases, deprusage);
             assertTrue(r);
         }
         byte[] bytes = baos.toByteArray();
--- a/langtools/test/tools/jdeps/jdkinternals/RemovedJDKInternals.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/test/tools/jdeps/jdkinternals/RemovedJDKInternals.java	Thu Oct 06 23:12:58 2016 +0000
@@ -26,7 +26,7 @@
  * @bug 8153042
  * @summary Tests JDK internal APIs that have been removed.
  * @library ../lib
- * @build CompilerUtils JdepsUtil ModuleMetaData
+ * @build CompilerUtils JdepsRunner JdepsUtil ModuleMetaData
  * @modules jdk.jdeps/com.sun.tools.jdeps
  * @run testng RemovedJDKInternals
  */
@@ -123,7 +123,8 @@
 
     @Test
     public void checkReplacement() {
-        String[] output = JdepsUtil.jdeps("-jdkinternals", CLASSES_DIR.toString());
+        JdepsRunner jdeps = JdepsRunner.run("-jdkinternals", CLASSES_DIR.toString());
+        String[] output = jdeps.output();
         int i = 0;
         while (!output[i].contains("Suggested Replacement")) {
             i++;
--- a/langtools/test/tools/jdeps/jdkinternals/ShowReplacement.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/test/tools/jdeps/jdkinternals/ShowReplacement.java	Thu Oct 06 23:12:58 2016 +0000
@@ -70,7 +70,8 @@
     @Test
     public void withReplacement() {
         Path file = Paths.get("q", "WithRepl.class");
-        String[] output = JdepsUtil.jdeps("-jdkinternals", CLASSES_DIR.resolve(file).toString());
+        JdepsRunner jdeps = JdepsRunner.run("-jdkinternals", CLASSES_DIR.resolve(file).toString());
+        String[] output = jdeps.output();
         int i = 0;
         while (!output[i].contains("Suggested Replacement")) {
             i++;
@@ -99,7 +100,8 @@
     @Test
     public void noReplacement() {
         Path file = Paths.get("q", "NoRepl.class");
-        String[] output = JdepsUtil.jdeps("-jdkinternals", CLASSES_DIR.resolve(file).toString());
+        JdepsRunner jdeps = JdepsRunner.run("-jdkinternals", CLASSES_DIR.resolve(file).toString());
+        String[] output = jdeps.output();
         int i = 0;
         // expect no replacement
         while (i < output.length && !output[i].contains("Suggested Replacement")) {
@@ -116,7 +118,8 @@
     @Test
     public void removedPackage() {
         Path file = Paths.get("q", "RemovedPackage.class");
-        String[] output = JdepsUtil.jdeps("--jdk-internals", CLASSES_DIR.resolve(file).toString());
+        JdepsRunner jdeps = JdepsRunner.run("--jdk-internals", CLASSES_DIR.resolve(file).toString());
+        String[] output = jdeps.output();
         int i = 0;
         // expect no replacement
         while (i < output.length && !output[i].contains("Suggested Replacement")) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/lib/JdepsRunner.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * JdepsRunner class to invoke jdeps with the given command line argument
+ */
+public class JdepsRunner {
+    public static JdepsRunner run(String... args) {
+        JdepsRunner jdeps = new JdepsRunner(args);
+        int rc = jdeps.run();
+        jdeps.printStdout(System.err);
+        if (rc != 0)
+           throw new Error("jdeps failed: rc=" + rc);
+        return jdeps;
+    }
+
+    final StringWriter stdout = new StringWriter();
+    final StringWriter stderr = new StringWriter();
+    final String[] args;
+    public JdepsRunner(String... args) {
+        System.err.println("jdeps " + Arrays.stream(args)
+                                            .collect(Collectors.joining(" ")));
+        this.args = args;
+    }
+
+    public JdepsRunner(List<String> args) {
+        this(args.toArray(new String[0]));
+    }
+
+    public int run() {
+        return run(false);
+    }
+
+    public int run(boolean showOutput) {
+        try (PrintWriter pw = new PrintWriter(stdout)) {
+            int rc = com.sun.tools.jdeps.Main.run(args, pw);
+            if (showOutput) {
+                System.err.println(stdout.toString());
+            }
+            return rc;
+        }
+    }
+
+    public boolean outputContains(String s) {
+        return stdout.toString().contains(s);
+    }
+
+    public void printStdout(PrintStream stream) {
+        stream.println(stdout.toString());
+    }
+
+    public void printStderr(PrintStream stream) {
+        stream.println(stderr.toString());
+    }
+
+    public String[] output() {
+        String lineSep = System.getProperty("line.separator");
+        return stdout.toString().split(lineSep);
+    }
+}
--- a/langtools/test/tools/jdeps/lib/JdepsUtil.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/test/tools/jdeps/lib/JdepsUtil.java	Thu Oct 06 23:12:58 2016 +0000
@@ -39,37 +39,17 @@
 import java.lang.module.ModuleDescriptor;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.jar.JarEntry;
 import java.util.jar.JarOutputStream;
 import java.util.regex.Pattern;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 /**
  * Utilities to run jdeps command
  */
 public final class JdepsUtil {
-    /*
-     * Runs jdeps with the given arguments
-     */
-    public static String[] jdeps(String... args) {
-        String lineSep =     System.getProperty("line.separator");
-        StringWriter sw = new StringWriter();
-        PrintWriter pw = new PrintWriter(sw);
-        System.err.println("jdeps " + Arrays.stream(args).collect(Collectors.joining(" ")));
-        int rc = com.sun.tools.jdeps.Main.run(args, pw);
-        pw.close();
-        String out = sw.toString();
-        if (!out.isEmpty())
-            System.err.println(out);
-        if (rc != 0)
-            throw new Error("jdeps failed: rc=" + rc);
-        return out.split(lineSep);
-    }
-
     public static Command newCommand(String cmd) {
         return new Command(cmd);
     }
--- a/langtools/test/tools/jdeps/modules/GenModuleInfo.java	Thu Oct 06 20:56:13 2016 +0000
+++ b/langtools/test/tools/jdeps/modules/GenModuleInfo.java	Thu Oct 06 23:12:58 2016 +0000
@@ -25,7 +25,7 @@
  * @test
  * @summary Tests jdeps --generate-module-info option
  * @library ../lib
- * @build CompilerUtils JdepsUtil
+ * @build CompilerUtils JdepsUtil JdepsRunner
  * @modules jdk.jdeps/com.sun.tools.jdeps
  * @run testng GenModuleInfo
  */
@@ -97,7 +97,7 @@
         Stream<String> files = Arrays.stream(modules)
                 .map(mn -> LIBS_DIR.resolve(mn + ".jar"))
                 .map(Path::toString);
-        JdepsUtil.jdeps(Stream.concat(Stream.of("-cp"), files).toArray(String[]::new));
+        JdepsRunner.run(Stream.concat(Stream.of("-cp"), files).toArray(String[]::new));
     }
 
     @Test
@@ -106,7 +106,7 @@
                 .map(mn -> LIBS_DIR.resolve(mn + ".jar"))
                 .map(Path::toString);
 
-        JdepsUtil.jdeps(Stream.concat(Stream.of("--generate-module-info", DEST_DIR.toString()),
+        JdepsRunner.run(Stream.concat(Stream.of("--generate-module-info", DEST_DIR.toString()),
                                       files).toArray(String[]::new));
 
         // check file exists
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/modules/UnnamedPackage.java	Thu Oct 06 23:12:58 2016 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, 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 8166846
+ * @summary Tests --generate-module-info on invalid JAR file
+ * @modules jdk.jdeps/com.sun.tools.jdeps
+ * @library ../lib
+ * @build JdepsRunner JdepsUtil
+ * @run main UnnamedPackage
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Stream;
+
+public class UnnamedPackage {
+    private static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes"));
+    private static final Path FOO_JAR_FILE = Paths.get("foo.jar");
+
+    public static void main(String... args) throws Exception {
+        // create foo.jar with unnamed package
+        Path name = TEST_CLASSES.resolve("UnnamedPackage.class");
+        JdepsUtil.createJar(FOO_JAR_FILE, TEST_CLASSES, Stream.of(name));
+
+        // run jdeps --generate-module-info
+        JdepsRunner jdeps = new JdepsRunner("--generate-module-info",
+                                            "tmp", FOO_JAR_FILE.toString());
+        // should fail to generate module-info.java
+        int exitValue = jdeps.run();
+        if (exitValue == 0) {
+            throw new RuntimeException("expected non-zero exitValue");
+        }
+        if (!jdeps.outputContains("foo.jar contains an unnamed package")) {
+            jdeps.printStdout(System.out);
+            throw new RuntimeException("expected error message not found");
+        }
+    }
+}