# HG changeset patch # User michaelm # Date 1325755631 0 # Node ID c864786394dc3d78c1d155d8cd62faf3385a7bc0 # Parent 004d487ac88698e67991f090be7cb8c12c0c2cac# Parent c66bb51b9aa74550f8719c5292fe09cda800f800 Merge diff -r 004d487ac886 -r c864786394dc .hgtags --- a/.hgtags Thu Dec 29 09:21:35 2011 -0800 +++ b/.hgtags Thu Jan 05 09:27:11 2012 +0000 @@ -142,3 +142,6 @@ f474527e77e4797d78bd6c3b31923fddcfd9d5c6 jdk7u2-b13 fc0769df8cd03fffc38c7a1ab6b2e2e7cc2506a8 jdk7u2-b21 8851e7f3721f8f756cc9f5731600a152506542db jdk7u4-b200 +358c42289352a2288084039e7c9d3f134c9c29e9 jdk7u4-b04 +8556ecc20a5b32ae7f336ecf3c420d7feb88d323 jdk7u4-b02 +62ee502a464924d68d398899570c1ad27fbe6cc4 jdk7u4-b05 \ No newline at end of file diff -r 004d487ac886 -r c864786394dc src/share/classes/com/sun/tools/javac/code/Symbol.java --- a/src/share/classes/com/sun/tools/javac/code/Symbol.java Thu Dec 29 09:21:35 2011 -0800 +++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java Thu Jan 05 09:27:11 2012 +0000 @@ -726,6 +726,11 @@ */ public JavaFileObject classfile; + /** the list of translated local classes (used for generating + * InnerClasses attribute) + */ + public List trans_local; + /** the constant pool of the class */ public Pool pool; diff -r 004d487ac886 -r c864786394dc src/share/classes/com/sun/tools/javac/comp/Lower.java --- a/src/share/classes/com/sun/tools/javac/comp/Lower.java Thu Dec 29 09:21:35 2011 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java Thu Jan 05 09:27:11 2012 +0000 @@ -2271,6 +2271,14 @@ tree.extending = translate(tree.extending); tree.implementing = translate(tree.implementing); + if (currentClass.isLocal()) { + ClassSymbol encl = currentClass.owner.enclClass(); + if (encl.trans_local == null) { + encl.trans_local = List.nil(); + } + encl.trans_local = encl.trans_local.prepend(currentClass); + } + // Recursively translate members, taking into account that new members // might be created during the translation and prepended to the member // list `tree.defs'. diff -r 004d487ac886 -r c864786394dc src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java --- a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Thu Dec 29 09:21:35 2011 -0800 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Thu Jan 05 09:27:11 2012 +0000 @@ -863,10 +863,10 @@ } if (c.type.tag != CLASS) return; // arrays if (pool != null && // pool might be null if called from xClassName - c.owner.kind != PCK && + c.owner.enclClass() != null && (innerClasses == null || !innerClasses.contains(c))) { // log.errWriter.println("enter inner " + c);//DEBUG - if (c.owner.kind == TYP) enterInner((ClassSymbol)c.owner); + enterInner(c.owner.enclClass()); pool.put(c); pool.put(c.name); if (innerClasses == null) { @@ -1505,6 +1505,13 @@ default : Assert.error(); } } + + if (c.trans_local != null) { + for (ClassSymbol local : c.trans_local) { + enterInner(local); + } + } + databuf.appendChar(fieldsCount); writeFields(c.members().elems); databuf.appendChar(methodsCount); diff -r 004d487ac886 -r c864786394dc test/tools/javac/7003595/T7003595.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/7003595/T7003595.java Thu Jan 05 09:27:11 2012 +0000 @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2011, 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 7003595 + * @summary IncompatibleClassChangeError with unreferenced local class with subclass + */ + +import com.sun.source.util.JavacTask; +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.InnerClasses_attribute; +import com.sun.tools.classfile.ConstantPool.*; +import com.sun.tools.javac.api.JavacTool; + +import java.io.File; +import java.net.URI; +import java.util.Arrays; +import java.util.ArrayList; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + + +public class T7003595 { + + /** global decls ***/ + + // Create a single file manager and reuse it for each compile to save time. + static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null); + + //statistics + static int checkCount = 0; + + enum ClassKind { + NESTED("static class #N { #B }", "$", true), + INNER("class #N { #B }", "$", false), + LOCAL_REF("void test() { class #N { #B }; new #N(); }", "$1", false), + LOCAL_NOREF("void test() { class #N { #B }; }", "$1", false), + ANON("void test() { new Object() { #B }; }", "$1", false), + NONE("", "", false); + + String memberInnerStr; + String sep; + boolean staticAllowed; + + private ClassKind(String memberInnerStr, String sep, boolean staticAllowed) { + this.memberInnerStr = memberInnerStr; + this.sep = sep; + this.staticAllowed = staticAllowed; + } + + String getSource(String className, String outerName, String nested) { + return memberInnerStr.replaceAll("#O", outerName). + replaceAll("#N", className).replaceAll("#B", nested); + } + + static String getClassfileName(String[] names, ClassKind[] outerKinds, int pos) { + System.out.println(" pos = " + pos + " kind = " + outerKinds[pos] + " sep = " + outerKinds[pos].sep); + String name = outerKinds[pos] != ANON ? + names[pos] : ""; + if (pos == 0) { + return "Test" + outerKinds[pos].sep + name; + } else { + String outerStr = getClassfileName(names, outerKinds, pos - 1); + return outerStr + outerKinds[pos].sep + name; + } + } + + boolean isAllowed(ClassKind nestedKind) { + return nestedKind != NESTED || + staticAllowed; + } + } + + enum LocalInnerClass { + LOCAL_REF("class L {}; new L();", "Test$1L"), + LOCAL_NOREF("class L {};", "Test$1L"), + ANON("new Object() {};", "Test$1"), + NONE("", ""); + + String localInnerStr; + String canonicalInnerStr; + + private LocalInnerClass(String localInnerStr, String canonicalInnerStr) { + this.localInnerStr = localInnerStr; + this.canonicalInnerStr = canonicalInnerStr; + } + } + + public static void main(String... args) throws Exception { + for (ClassKind ck1 : ClassKind.values()) { + String cname1 = "C1"; + for (ClassKind ck2 : ClassKind.values()) { + if (!ck1.isAllowed(ck2)) continue; + String cname2 = "C2"; + for (ClassKind ck3 : ClassKind.values()) { + if (!ck2.isAllowed(ck3)) continue; + String cname3 = "C3"; + new T7003595(new ClassKind[] {ck1, ck2, ck3}, new String[] { cname1, cname2, cname3 }).compileAndCheck(); + } + } + } + + System.out.println("Total checks made: " + checkCount); + } + + /** instance decls **/ + + ClassKind[] cks; + String[] cnames; + + T7003595(ClassKind[] cks, String[] cnames) { + this.cks = cks; + this.cnames = cnames; + } + + void compileAndCheck() throws Exception { + final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); + JavaSource source = new JavaSource(); + JavacTask ct = (JavacTask)tool.getTask(null, fm, null, + null, null, Arrays.asList(source)); + ct.call(); + verifyBytecode(source); + } + + void verifyBytecode(JavaSource source) { + for (int i = 0; i < 3 ; i ++) { + if (cks[i] == ClassKind.NONE) break; + checkCount++; + String filename = cks[i].getClassfileName(cnames, cks, i); + File compiledTest = new File(filename + ".class"); + try { + ClassFile cf = ClassFile.read(compiledTest); + if (cf == null) { + throw new Error("Classfile not found: " + filename); + } + + InnerClasses_attribute innerClasses = (InnerClasses_attribute)cf.getAttribute(Attribute.InnerClasses); + + ArrayList foundInnerSig = new ArrayList<>(); + if (innerClasses != null) { + for (InnerClasses_attribute.Info info : innerClasses.classes) { + String foundSig = info.getInnerClassInfo(cf.constant_pool).getName(); + foundInnerSig.add(foundSig); + } + } + + ArrayList expectedInnerSig = new ArrayList<>(); + //add inner class (if any) + if (i < 2 && cks[i + 1] != ClassKind.NONE) { + expectedInnerSig.add(cks[i + 1].getClassfileName(cnames, cks, i + 1)); + } + //add inner classes + for (int j = 0 ; j != i + 1 && j < 3; j++) { + expectedInnerSig.add(cks[j].getClassfileName(cnames, cks, j)); + } + + if (expectedInnerSig.size() != foundInnerSig.size()) { + throw new Error("InnerClasses attribute for " + cnames[i] + " has wrong size\n" + + "expected " + expectedInnerSig.size() + "\n" + + "found " + innerClasses.number_of_classes + "\n" + + source); + } + + for (String foundSig : foundInnerSig) { + if (!expectedInnerSig.contains(foundSig)) { + throw new Error("InnerClasses attribute for " + cnames[i] + " has unexpected signature: " + + foundSig + "\n" + source + "\n" + expectedInnerSig); + } + } + + for (String expectedSig : expectedInnerSig) { + if (!foundInnerSig.contains(expectedSig)) { + throw new Error("InnerClasses attribute for " + cnames[i] + " does not contain expected signature: " + + expectedSig + "\n" + source); + } + } + } catch (Exception e) { + e.printStackTrace(); + throw new Error("error reading " + compiledTest +": " + e); + } + } + } + + class JavaSource extends SimpleJavaFileObject { + + static final String source_template = "class Test { #C }"; + + String source; + + public JavaSource() { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + String c3 = cks[2].getSource(cnames[2], cnames[1], ""); + String c2 = cks[1].getSource(cnames[1], cnames[0], c3); + String c1 = cks[0].getSource(cnames[0], "Test", c2); + source = source_template.replace("#C", c1); + } + + @Override + public String toString() { + return source; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + } +} diff -r 004d487ac886 -r c864786394dc test/tools/javac/7003595/T7003595b.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/7003595/T7003595b.java Thu Jan 05 09:27:11 2012 +0000 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011, 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 7003595 + * @summary IncompatibleClassChangeError with unreferenced local class with subclass + */ + +public class T7003595b { + public static void main(String... args) throws Exception { + class A {} + class B extends A {} + B.class.getSuperclass().getDeclaringClass(); + } +}