diff --git a/src/share/classes/com/sun/source/tree/DisjointTypeTree.java b/src/share/classes/com/sun/source/tree/DisjointTypeTree.java new file mode 100644 index 0000000000000000000000000000000000000000..513a70a2294d8d384484b076be489c5563df8584 --- /dev/null +++ b/src/share/classes/com/sun/source/tree/DisjointTypeTree.java @@ -0,0 +1,40 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.source.tree; + +import java.util.List; + +/** + * A tree node for a disjoint type expression in a multicatch var declaration. + * + * + * @author Maurizio Cimadamore + * + * @since 1.7 + */ +public interface DisjointTypeTree extends Tree { + List getTypeComponents(); +} \ No newline at end of file diff --git a/src/share/classes/com/sun/source/tree/Tree.java b/src/share/classes/com/sun/source/tree/Tree.java index d2d2d5a1d580257597ada211fd9b9ba0d24462bb..c5f46904dfa3704790efbdfef24f102319939a94 100644 --- a/src/share/classes/com/sun/source/tree/Tree.java +++ b/src/share/classes/com/sun/source/tree/Tree.java @@ -233,6 +233,11 @@ public interface Tree { */ PARAMETERIZED_TYPE(ParameterizedTypeTree.class), + /** + * Used for instances of {@link DisjointTypeTree}. + */ + DISJOINT_TYPE(DisjointTypeTree.class), + /** * Used for instances of {@link TypeCastTree}. */ diff --git a/src/share/classes/com/sun/source/tree/TreeVisitor.java b/src/share/classes/com/sun/source/tree/TreeVisitor.java index 99e7063d2048d6c7f93b27852b657e94bd5256ea..117b716f708494ad1fbc5a24ad62e3030fa58fee 100644 --- a/src/share/classes/com/sun/source/tree/TreeVisitor.java +++ b/src/share/classes/com/sun/source/tree/TreeVisitor.java @@ -96,6 +96,7 @@ public interface TreeVisitor { R visitCompilationUnit(CompilationUnitTree node, P p); R visitTry(TryTree node, P p); R visitParameterizedType(ParameterizedTypeTree node, P p); + R visitDisjointType(DisjointTypeTree node, P p); R visitArrayType(ArrayTypeTree node, P p); R visitTypeCast(TypeCastTree node, P p); R visitPrimitiveType(PrimitiveTypeTree node, P p); diff --git a/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java b/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java index e6c384bef4cb988bbc59335b4284df0dcdaa9ec2..c96416f99848277a562a9c4ec805ebbbb205c9dd 100644 --- a/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java +++ b/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java @@ -228,6 +228,10 @@ public class SimpleTreeVisitor implements TreeVisitor { return defaultAction(node, p); } + public R visitDisjointType(DisjointTypeTree node, P p) { + return defaultAction(node, p); + } + public R visitTypeParameter(TypeParameterTree node, P p) { return defaultAction(node, p); } diff --git a/src/share/classes/com/sun/source/util/TreeScanner.java b/src/share/classes/com/sun/source/util/TreeScanner.java index a1d2a2d881f90e15ed7dbb3b7bf52912bdbdc2a4..9253aa90da8914c4a518e5241a84e2bfcba6a62a 100644 --- a/src/share/classes/com/sun/source/util/TreeScanner.java +++ b/src/share/classes/com/sun/source/util/TreeScanner.java @@ -354,6 +354,10 @@ public class TreeScanner implements TreeVisitor { return r; } + public R visitDisjointType(DisjointTypeTree node, P p) { + return scan(node.getTypeComponents(), p); + } + public R visitTypeParameter(TypeParameterTree node, P p) { R r = scan(node.getAnnotations(), p); r = scanAndReduce(node.getBounds(), p, r); diff --git a/src/share/classes/com/sun/tools/javac/code/Flags.java b/src/share/classes/com/sun/tools/javac/code/Flags.java index 88f0bde43da3083c94dc5cb5b00f7a97b649c00c..5ecbcf9c1a2c06b19a09ae4202b26189f932fbf1 100644 --- a/src/share/classes/com/sun/tools/javac/code/Flags.java +++ b/src/share/classes/com/sun/tools/javac/code/Flags.java @@ -230,6 +230,11 @@ public class Flags { */ public static final long PROPRIETARY = 1L<<38; + /** + * Flag that marks a disjoint var in a multi-catch clause + */ + public static final long DISJOINT = 1L<<39; + /** Modifier masks. */ public static final int diff --git a/src/share/classes/com/sun/tools/javac/code/Source.java b/src/share/classes/com/sun/tools/javac/code/Source.java index 4809565d855bc4f1ec9a4449c7230ea4505d6f82..98b8365bc747fe404223c502a13fb17fcbfc6dcb 100644 --- a/src/share/classes/com/sun/tools/javac/code/Source.java +++ b/src/share/classes/com/sun/tools/javac/code/Source.java @@ -125,6 +125,9 @@ public enum Source { public boolean allowDiamond() { return compareTo(JDK1_7) >= 0; } + public boolean allowMulticatch() { + return compareTo(JDK1_7) >= 0; + } public boolean allowEnums() { return compareTo(JDK1_5) >= 0; } diff --git a/src/share/classes/com/sun/tools/javac/comp/Attr.java b/src/share/classes/com/sun/tools/javac/comp/Attr.java index 0d3df466c64422b15e50f670c1c576fde1fe31fb..cf1cf2c7f053ab5149c11fd968f3bc36236ebeb4 100644 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java @@ -988,6 +988,13 @@ public class Attr extends JCTree.Visitor { Env catchEnv = env.dup(c, env.info.dup(env.info.scope.dup())); Type ctype = attribStat(c.param, catchEnv); + if (TreeInfo.isMultiCatch(c)) { + //check that multi-catch parameter is marked as final + if ((c.param.sym.flags() & FINAL) == 0) { + log.error(c.param.pos(), "multicatch.param.must.be.final", c.param.sym); + } + c.param.sym.flags_field = c.param.sym.flags() | DISJOINT; + } if (c.param.type.tsym.kind == Kinds.VAR) { c.param.sym.setData(ElementKind.EXCEPTION_PARAMETER); } @@ -2735,6 +2742,11 @@ public class Attr extends JCTree.Visitor { result = check(tree, owntype, TYP, pkind, pt); } + public void visitTypeDisjoint(JCTypeDisjoint tree) { + List componentTypes = attribTypes(tree.components, env); + tree.type = result = check(tree, types.lub(componentTypes), TYP, pkind, pt); + } + public void visitTypeParameter(JCTypeParameter tree) { TypeVar a = (TypeVar)tree.type; Set boundSet = new HashSet(); diff --git a/src/share/classes/com/sun/tools/javac/comp/Flow.java b/src/share/classes/com/sun/tools/javac/comp/Flow.java index 626deeed78f3b81cde643ab6ef607d7d32ceeaa3..9de6950909a3febfb507009bffc53c1e4a29df70 100644 --- a/src/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java @@ -27,6 +27,8 @@ package com.sun.tools.javac.comp; +import java.util.HashMap; + import com.sun.tools.javac.code.*; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.util.*; @@ -184,6 +186,7 @@ public class Flow extends TreeScanner { private final Check chk; private TreeMaker make; private Lint lint; + private final boolean allowRethrowAnalysis; public static Flow instance(Context context) { Flow instance = context.get(flowKey); @@ -194,13 +197,14 @@ public class Flow extends TreeScanner { protected Flow(Context context) { context.put(flowKey, this); - names = Names.instance(context); log = Log.instance(context); syms = Symtab.instance(context); types = Types.instance(context); chk = Check.instance(context); lint = Lint.instance(context); + Source source = Source.instance(context); + allowRethrowAnalysis = source.allowMulticatch(); } /** A flag that indicates whether the last statement could @@ -216,6 +220,8 @@ public class Flow extends TreeScanner { */ Bits uninits; + HashMap> multicatchTypes; + /** The set of variables that are definitely unassigned everywhere * in current try block. This variable is maintained lazily; it is * updated only when something gets removed from uninits, @@ -355,8 +361,14 @@ public class Flow extends TreeScanner { if (sym.adr >= firstadr && trackable(sym)) { if ((sym.flags() & FINAL) != 0) { if ((sym.flags() & PARAMETER) != 0) { - log.error(pos, "final.parameter.may.not.be.assigned", + if ((sym.flags() & DISJOINT) != 0) { //multi-catch parameter + log.error(pos, "multicatch.parameter.may.not.be.assigned", + sym); + } + else { + log.error(pos, "final.parameter.may.not.be.assigned", sym); + } } else if (!uninits.isMember(sym.adr)) { log.error(pos, loopPassTwo @@ -952,8 +964,14 @@ public class Flow extends TreeScanner { List caughtPrev = caught; List thrownPrev = thrown; thrown = List.nil(); - for (List l = tree.catchers; l.nonEmpty(); l = l.tail) - caught = chk.incl(l.head.param.type, caught); + for (List l = tree.catchers; l.nonEmpty(); l = l.tail) { + List subClauses = TreeInfo.isMultiCatch(l.head) ? + ((JCTypeDisjoint)l.head.param.vartype).components : + List.of(l.head.param.vartype); + for (JCExpression ct : subClauses) { + caught = chk.incl(ct.type, caught); + } + } Bits uninitsTryPrev = uninitsTry; ListBuffer prevPendingExits = pendingExits; pendingExits = new ListBuffer(); @@ -973,27 +991,39 @@ public class Flow extends TreeScanner { for (List l = tree.catchers; l.nonEmpty(); l = l.tail) { alive = true; JCVariableDecl param = l.head.param; - Type exc = param.type; - if (chk.subset(exc, caughtInTry)) { - log.error(l.head.pos(), - "except.already.caught", exc); - } else if (!chk.isUnchecked(l.head.pos(), exc) && - exc.tsym != syms.throwableType.tsym && - exc.tsym != syms.exceptionType.tsym && - !chk.intersects(exc, thrownInTry)) { - log.error(l.head.pos(), - "except.never.thrown.in.try", exc); + List subClauses = TreeInfo.isMultiCatch(l.head) ? + ((JCTypeDisjoint)l.head.param.vartype).components : + List.of(l.head.param.vartype); + List ctypes = List.nil(); + List rethrownTypes = chk.diff(thrownInTry, caughtInTry); + for (JCExpression ct : subClauses) { + Type exc = ct.type; + ctypes = ctypes.append(exc); + if (types.isSameType(exc, syms.objectType)) + continue; + if (chk.subset(exc, caughtInTry)) { + log.error(l.head.pos(), + "except.already.caught", exc); + } else if (!chk.isUnchecked(l.head.pos(), exc) && + exc.tsym != syms.throwableType.tsym && + exc.tsym != syms.exceptionType.tsym && + !chk.intersects(exc, thrownInTry)) { + log.error(l.head.pos(), + "except.never.thrown.in.try", exc); + } + caughtInTry = chk.incl(exc, caughtInTry); } - caughtInTry = chk.incl(exc, caughtInTry); inits = initsTry.dup(); uninits = uninitsTry.dup(); scan(param); inits.incl(param.sym.adr); uninits.excl(param.sym.adr); + multicatchTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes)); scanStat(l.head.body); initsEnd.andSet(inits); uninitsEnd.andSet(uninits); nextadr = nextadrCatch; + multicatchTypes.remove(param.sym); aliveEnd |= alive; } if (tree.finalizer != null) { @@ -1121,7 +1151,19 @@ public class Flow extends TreeScanner { public void visitThrow(JCThrow tree) { scanExpr(tree.expr); - markThrown(tree, tree.expr.type); + Symbol sym = TreeInfo.symbol(tree.expr); + if (sym != null && + sym.kind == VAR && + (sym.flags() & FINAL) != 0 && + multicatchTypes.get(sym) != null && + allowRethrowAnalysis) { + for (Type t : multicatchTypes.get(sym)) { + markThrown(tree, t); + } + } + else { + markThrown(tree, tree.expr.type); + } markDead(); } @@ -1308,6 +1350,7 @@ public class Flow extends TreeScanner { firstadr = 0; nextadr = 0; pendingExits = new ListBuffer(); + multicatchTypes = new HashMap>(); alive = true; this.thrown = this.caught = null; this.classDef = null; diff --git a/src/share/classes/com/sun/tools/javac/jvm/Gen.java b/src/share/classes/com/sun/tools/javac/jvm/Gen.java index e39115c7af85f25fe080f809adca6b2de2758792..41bbbdcbb0bffe7acd9a1f5ff20c34f057b3a296 100644 --- a/src/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/src/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -1454,20 +1454,26 @@ public class Gen extends JCTree.Visitor { int startpc, int endpc, List gaps) { if (startpc != endpc) { - int catchType = makeRef(tree.pos(), tree.param.type); - while (gaps.nonEmpty()) { - int end = gaps.head.intValue(); - registerCatch(tree.pos(), - startpc, end, code.curPc(), - catchType); - gaps = gaps.tail; - startpc = gaps.head.intValue(); - gaps = gaps.tail; + List subClauses = TreeInfo.isMultiCatch(tree) ? + ((JCTypeDisjoint)tree.param.vartype).components : + List.of(tree.param.vartype); + for (JCExpression subCatch : subClauses) { + int catchType = makeRef(tree.pos(), subCatch.type); + List lGaps = gaps; + while (lGaps.nonEmpty()) { + int end = lGaps.head.intValue(); + registerCatch(tree.pos(), + startpc, end, code.curPc(), + catchType); + lGaps = lGaps.tail; + startpc = lGaps.head.intValue(); + lGaps = lGaps.tail; + } + if (startpc < endpc) + registerCatch(tree.pos(), + startpc, endpc, code.curPc(), + catchType); } - if (startpc < endpc) - registerCatch(tree.pos(), - startpc, endpc, code.curPc(), - catchType); VarSymbol exparam = tree.param.sym; code.statBegin(tree.pos); code.markStatBegin(); diff --git a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java index 63914e315e6b481ba7647e3984fa4c2ec2fcba7c..19d5b2ceff7807382a851c97711a108ba56ee49c 100644 --- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -132,6 +132,7 @@ public class JavacParser implements Parser { this.allowStaticImport = source.allowStaticImport(); this.allowAnnotations = source.allowAnnotations(); this.allowDiamond = source.allowDiamond(); + this.allowMulticatch = source.allowMulticatch(); this.allowTypeAnnotations = source.allowTypeAnnotations(); this.keepDocComments = keepDocComments; if (keepDocComments) @@ -153,6 +154,10 @@ public class JavacParser implements Parser { */ boolean allowDiamond; + /** Switch: Should multicatch clause be accepted? + */ + boolean allowMulticatch; + /** Switch: Should varargs be recognized? */ boolean allowVarargs; @@ -2011,14 +2016,28 @@ public class JavacParser implements Parser { int pos = S.pos(); accept(CATCH); accept(LPAREN); - JCVariableDecl formal = - variableDeclaratorId(optFinal(Flags.PARAMETER), - qualident()); + JCModifiers mods = optFinal(Flags.PARAMETER); + List catchTypes = catchTypes(); + JCExpression paramType = catchTypes.size() > 1 ? + toP(F.at(catchTypes.head.getStartPosition()).TypeDisjoint(catchTypes)) : + catchTypes.head; + JCVariableDecl formal = variableDeclaratorId(mods, paramType); accept(RPAREN); JCBlock body = block(); return F.at(pos).Catch(formal, body); } + List catchTypes() { + ListBuffer catchTypes = ListBuffer.lb(); + catchTypes.add(parseType()); + while (S.token() == BAR) { + checkMulticatch(); + S.nextToken(); + catchTypes.add(qualident()); + } + return catchTypes.toList(); + } + /** SwitchBlockStatementGroups = { SwitchBlockStatementGroup } * SwitchBlockStatementGroup = SwitchLabel BlockStatements * SwitchLabel = CASE ConstantExpression ":" | DEFAULT ":" @@ -3193,4 +3212,10 @@ public class JavacParser implements Parser { allowDiamond = true; } } + void checkMulticatch() { + if (!allowMulticatch) { + log.error(S.pos(), "multicatch.not.supported.in.source", source.name); + allowMulticatch = true; + } + } } diff --git a/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/share/classes/com/sun/tools/javac/resources/compiler.properties index 9de7466722993ee0afc830526032a6da71d1844d..b695e5c78702b9644653ae06b962f56b12abf14f 100644 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -172,6 +172,10 @@ compiler.err.except.never.thrown.in.try=\ compiler.err.final.parameter.may.not.be.assigned=\ final parameter {0} may not be assigned +compiler.err.multicatch.parameter.may.not.be.assigned=\ + multi-catch parameter {0} may not be assigned +compiler.err.multicatch.param.must.be.final=\ + multi-catch parameter {0} must be final compiler.err.finally.without.try=\ ''finally'' without ''try'' compiler.err.foreach.not.applicable.to.type=\ @@ -1235,6 +1239,10 @@ compiler.err.enums.not.supported.in.source=\ enums are not supported in -source {0}\n\ (use -source 5 or higher to enable enums) +compiler.err.multicatch.not.supported.in.source=\ + multi-catch statement is not supported in -source {0}\n\ +(use -source 7 or higher to enable multi-catch statement) + compiler.err.string.switch.not.supported.in.source=\ strings in switch are not supported in -source {0}\n\ (use -source 7 or higher to enable strings in switch) diff --git a/src/share/classes/com/sun/tools/javac/tree/JCTree.java b/src/share/classes/com/sun/tools/javac/tree/JCTree.java index 4344961a36b7b1d6f0ac563423c68b836c2c926f..20352f5b843724766fda56ba3d9766caa52c14a1 100644 --- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -236,9 +236,13 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { */ public static final int TYPEAPPLY = TYPEARRAY + 1; + /** Disjunctive types, of type TypeDisjoint. + */ + public static final int TYPEDISJOINT = TYPEAPPLY + 1; + /** Formal type parameters, of type TypeParameter. */ - public static final int TYPEPARAMETER = TYPEAPPLY + 1; + public static final int TYPEPARAMETER = TYPEDISJOINT + 1; /** Type argument. */ @@ -1862,6 +1866,34 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } } + /** + * A disjoint type, T1 | T2 | ... Tn (used in multicatch statements) + */ + public static class JCTypeDisjoint extends JCExpression implements DisjointTypeTree { + + public List components; + + protected JCTypeDisjoint(List components) { + this.components = components; + } + @Override + public void accept(Visitor v) { v.visitTypeDisjoint(this); } + + public Kind getKind() { return Kind.DISJOINT_TYPE; } + + public List getTypeComponents() { + return components; + } + @Override + public R accept(TreeVisitor v, D d) { + return v.visitDisjointType(this, d); + } + @Override + public int getTag() { + return TYPEDISJOINT; + } + } + /** * A formal class parameter. * @param name name @@ -2220,6 +2252,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { public void visitTypeIdent(JCPrimitiveTypeTree that) { visitTree(that); } public void visitTypeArray(JCArrayTypeTree that) { visitTree(that); } public void visitTypeApply(JCTypeApply that) { visitTree(that); } + public void visitTypeDisjoint(JCTypeDisjoint that) { visitTree(that); } public void visitTypeParameter(JCTypeParameter that) { visitTree(that); } public void visitWildcard(JCWildcard that) { visitTree(that); } public void visitTypeBoundKind(TypeBoundKind that) { visitTree(that); } diff --git a/src/share/classes/com/sun/tools/javac/tree/Pretty.java b/src/share/classes/com/sun/tools/javac/tree/Pretty.java index ef4d4dc02dc1ffdb7cf54f9b65fa9ea922b7e42f..578d745d0506c9e2721e215897abe4ff6ace2a36 100644 --- a/src/share/classes/com/sun/tools/javac/tree/Pretty.java +++ b/src/share/classes/com/sun/tools/javac/tree/Pretty.java @@ -1182,6 +1182,14 @@ public class Pretty extends JCTree.Visitor { } } + public void visitTypeDisjoint(JCTypeDisjoint tree) { + try { + printExprs(tree.components, " | "); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + public void visitTypeParameter(JCTypeParameter tree) { try { print(tree.name); diff --git a/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java b/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java index 9e3a9ba761fa4418da152b91ee79856b9dd786dd..c1e8835541b9ccd2e9b4eef5a0f3ed94a4023539 100644 --- a/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java +++ b/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java @@ -345,6 +345,12 @@ public class TreeCopier

implements TreeVisitor { return M.at(t.pos).TypeApply(clazz, arguments); } + public JCTree visitDisjointType(DisjointTypeTree node, P p) { + JCTypeDisjoint t = (JCTypeDisjoint) node; + List components = copy(t.components, p); + return M.at(t.pos).TypeDisjoint(components); + } + public JCTree visitArrayType(ArrayTypeTree node, P p) { JCArrayTypeTree t = (JCArrayTypeTree) node; JCExpression elemtype = copy(t.elemtype, p); diff --git a/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java index 12f25312e6eb4ff5972dd50229c731f2b8f6c01f..d70b609b13c0b4d54aa5230bc7d737ce67435252 100644 --- a/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java +++ b/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java @@ -118,6 +118,10 @@ public class TreeInfo { return false; } + public static boolean isMultiCatch(JCCatch catchClause) { + return catchClause.param.vartype.getTag() == JCTree.TYPEDISJOINT; + } + /** Is statement an initializer for a synthetic field? */ public static boolean isSyntheticInit(JCTree stat) { diff --git a/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java b/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java index 84229f60fbbc799e8af382bdfad5c72adb282457..250672d764fc8321886e8aea6ed74781d9b83266 100644 --- a/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java +++ b/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java @@ -444,6 +444,12 @@ public class TreeMaker implements JCTree.Factory { return tree; } + public JCTypeDisjoint TypeDisjoint(List components) { + JCTypeDisjoint tree = new JCTypeDisjoint(components); + tree.pos = pos; + return tree; + } + public JCTypeParameter TypeParameter(Name name, List bounds) { return TypeParameter(name, bounds, List.nil()); } diff --git a/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java b/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java index 5721d5d207841abc5fdf496b588c41afee91f6e8..421c0ce51f234dd836cc90da85f7ce49554668f0 100644 --- a/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java +++ b/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java @@ -275,6 +275,10 @@ public class TreeScanner extends Visitor { scan(tree.arguments); } + public void visitTypeDisjoint(JCTypeDisjoint tree) { + scan(tree.components); + } + public void visitTypeParameter(JCTypeParameter tree) { scan(tree.annotations); scan(tree.bounds); diff --git a/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java b/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java index 98f5250b4b913154fffa7b3a73c0a33be75b867d..9a95ceb094fba08652abedf736cf69fb22bfb535 100644 --- a/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java +++ b/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java @@ -367,6 +367,11 @@ public class TreeTranslator extends JCTree.Visitor { result = tree; } + public void visitTypeDisjoint(JCTypeDisjoint tree) { + tree.components = translate(tree.components); + result = tree; + } + public void visitTypeParameter(JCTypeParameter tree) { tree.annotations = translate(tree.annotations); tree.bounds = translate(tree.bounds); diff --git a/test/tools/javac/multicatch/Neg01.java b/test/tools/javac/multicatch/Neg01.java new file mode 100644 index 0000000000000000000000000000000000000000..dd0bc5cfe7bd4e16b968c31a036ae52a2a769321 --- /dev/null +++ b/test/tools/javac/multicatch/Neg01.java @@ -0,0 +1,28 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6943289 + * + * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch') + * @author darcy + * @compile/fail/ref=Neg01.out -XDrawDiagnostics Neg01.java + * @compile -source 6 -XDrawDiagnostics Neg01.java + * + */ + +class Neg01 { + static class A extends Exception {} + static class B1 extends A {} + static class B2 extends A {} + + class Test { + void m() throws A { + try { + throw new B1(); + } catch (final A ex1) { + try { + throw ex1; // used to throw A, now throws B1! + } catch (B2 ex2) { }//unreachable + } + } + } +} diff --git a/test/tools/javac/multicatch/Neg01.out b/test/tools/javac/multicatch/Neg01.out new file mode 100644 index 0000000000000000000000000000000000000000..328be8c7d487462a5c107f03deafa657797acc34 --- /dev/null +++ b/test/tools/javac/multicatch/Neg01.out @@ -0,0 +1,2 @@ +Neg01.java:24:19: compiler.err.except.never.thrown.in.try: Neg01.B2 +1 error diff --git a/test/tools/javac/multicatch/Neg02.java b/test/tools/javac/multicatch/Neg02.java new file mode 100644 index 0000000000000000000000000000000000000000..6312447eb53156e04d367b505cf85c2446345262 --- /dev/null +++ b/test/tools/javac/multicatch/Neg02.java @@ -0,0 +1,25 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6943289 + * + * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch') + * @author mcimadamore + * @compile/fail/ref=Neg02.out -XDrawDiagnostics Neg02.java + * + */ + +class Neg02 { + static class A extends Exception {} + static class B extends Exception {} + + void m() { + try { + if (true) { + throw new A(); + } + else { + throw new B(); + } + } catch (A | B ex) { } + } +} diff --git a/test/tools/javac/multicatch/Neg02.out b/test/tools/javac/multicatch/Neg02.out new file mode 100644 index 0000000000000000000000000000000000000000..f14045784427650e879310214b33da6d60f9f776 --- /dev/null +++ b/test/tools/javac/multicatch/Neg02.out @@ -0,0 +1,2 @@ +Neg02.java:23:24: compiler.err.multicatch.param.must.be.final: ex +1 error diff --git a/test/tools/javac/multicatch/Neg03.java b/test/tools/javac/multicatch/Neg03.java new file mode 100644 index 0000000000000000000000000000000000000000..c9e0b202c547e9b840b40a4f51cf29c2d83f6c1f --- /dev/null +++ b/test/tools/javac/multicatch/Neg03.java @@ -0,0 +1,27 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6943289 + * + * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch') + * @author mcimadamore + * @compile/fail/ref=Neg03.out -XDrawDiagnostics Neg03.java + * + */ + +class Neg03 { + static class A extends Exception {} + static class B extends Exception {} + + void m() { + try { + if (true) { + throw new A(); + } + else { + throw new B(); + } + } catch (final A | B ex) { + ex = new B(); + } + } +} diff --git a/test/tools/javac/multicatch/Neg03.out b/test/tools/javac/multicatch/Neg03.out new file mode 100644 index 0000000000000000000000000000000000000000..c854ee991ff295515308dc5811e37586e432d24c --- /dev/null +++ b/test/tools/javac/multicatch/Neg03.out @@ -0,0 +1,2 @@ +Neg03.java:24:13: compiler.err.multicatch.parameter.may.not.be.assigned: ex +1 error diff --git a/test/tools/javac/multicatch/Neg04.java b/test/tools/javac/multicatch/Neg04.java new file mode 100644 index 0000000000000000000000000000000000000000..d17de52b15775bde65de06cef95023ee742feb5a --- /dev/null +++ b/test/tools/javac/multicatch/Neg04.java @@ -0,0 +1,31 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6943289 + * + * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch') + * @author mcimadamore + * @compile/fail/ref=Neg04.out -XDrawDiagnostics Neg04.java + * + */ + +class Neg04 { + static class A extends Exception {} + static class B extends Exception {} + + void test() throws B { + try { + if (true) { + throw new A(); + } else if (false) { + throw new B(); + } else { + throw (Throwable)new Exception(); + } + } + catch (A e) {} + catch (final Exception e) { + throw e; + } + catch (Throwable t) {} + } +} diff --git a/test/tools/javac/multicatch/Neg04.out b/test/tools/javac/multicatch/Neg04.out new file mode 100644 index 0000000000000000000000000000000000000000..e2e2e3f4493f270fd1569c4a1b9e772c47e67ab6 --- /dev/null +++ b/test/tools/javac/multicatch/Neg04.out @@ -0,0 +1,2 @@ +Neg04.java:27:13: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception +1 error diff --git a/test/tools/javac/multicatch/Pos01.java b/test/tools/javac/multicatch/Pos01.java new file mode 100644 index 0000000000000000000000000000000000000000..e48322e4662d743761687621d128627e0498a0a8 --- /dev/null +++ b/test/tools/javac/multicatch/Pos01.java @@ -0,0 +1,59 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6943289 + * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch') + * + */ + +public class Pos01 { + + static class A extends Exception {} + static class B extends Exception {} + + static int caughtExceptions = 0; + + static void test(boolean b) { + try { + if (b) { + throw new A(); + } + else { + throw new B(); + } + } + catch (final A | B ex) { + caughtExceptions++; + } + } + + public static void main(String[] args) { + test(true); + test(false); + if (caughtExceptions != 2) { + throw new AssertionError("Exception handler called " + caughtExceptions + "times"); + } + } +} diff --git a/test/tools/javac/multicatch/Pos02.java b/test/tools/javac/multicatch/Pos02.java new file mode 100644 index 0000000000000000000000000000000000000000..156919c0df50c605af4d068765df7f678d0ab779 --- /dev/null +++ b/test/tools/javac/multicatch/Pos02.java @@ -0,0 +1,81 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6943289 + * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch') + * + */ + +public class Pos02 { + + static class A extends Exception {} + static class B extends Exception {} + static class C extends Exception {} + static class C1 extends C {} + static class C2 extends C {} + + enum ExceptionKind { + A, + B, + C1, + C2 + } + + static int caughtExceptions = 0; + static int caughtRethrownExceptions = 0; + + static void test(ExceptionKind ekind) throws A, C1 { + try { + switch (ekind) { + case A : throw new A(); + case B : throw new B(); + case C1: throw new C1(); + case C2 : throw new C2(); + } + } + catch (final C2 | B ex) { + caughtExceptions++; + } + catch (final C | A ex) { + caughtExceptions++; + throw ex; + } + } + + public static void main(String[] args) { + for (ExceptionKind ekind : ExceptionKind.values()) { + try { + test(ekind); + } + catch (final C1 | A ex) { + caughtRethrownExceptions++; + } + } + if (caughtExceptions != 4 && caughtRethrownExceptions == 2) { + throw new AssertionError("Exception handler called " + caughtExceptions + "times" + + " rethrown handler called " + caughtRethrownExceptions + "times"); + } + } +} diff --git a/test/tools/javac/multicatch/Pos03.java b/test/tools/javac/multicatch/Pos03.java new file mode 100644 index 0000000000000000000000000000000000000000..d0438abe7462d7f3749ae1d30aa857b7231e6558 --- /dev/null +++ b/test/tools/javac/multicatch/Pos03.java @@ -0,0 +1,50 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6943289 + * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch') + * @compile Pos03.java + */ + +class Pos03 { + + static class A extends Exception { public void m() {}; public Object f;} + static class B1 extends A {} + static class B2 extends A {} + + void m() { + try { + if (true) { + throw new B1(); + } + else { + throw new B2(); + } + } catch (final B1 | B2 ex) { + ex.m(); + System.out.println(ex.f); + } + } +} diff --git a/test/tools/javac/multicatch/Pos04.java b/test/tools/javac/multicatch/Pos04.java new file mode 100644 index 0000000000000000000000000000000000000000..05b7bb463fa3376150f6aa2304c0d911cacdb805 --- /dev/null +++ b/test/tools/javac/multicatch/Pos04.java @@ -0,0 +1,92 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6943289 + * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch') + */ + +import java.lang.annotation.*; + +public class Pos04 { + + enum ExceptionKind { + A(1), + B(2), + C(1); + + int expectedValue; + + ExceptionKind(int expectedValue) { + this.expectedValue = expectedValue; + } + } + + @Retention(RetentionPolicy.RUNTIME) + @interface CatchNumber { + int value(); + } + + @CatchNumber(1) + static class A extends Exception { } + + @CatchNumber(2) + static class B extends Exception { } + + @CatchNumber(1) + static class C extends Exception { } + + static int sum = 0; + + public static void main(String[] args) { + for (ExceptionKind ekind : ExceptionKind.values()) { + test(ekind); + } + if (sum != 4) { + throw new Error("bad checksum - expected:4, found:" + sum); + } + } + + public static void test(ExceptionKind ekind) { + try { + switch(ekind) { + case A: throw new A(); + case B: throw new B(); + case C: throw new C(); + } + } catch(final A | C ex) {// Catch number 1 + CatchNumber catchNumber = ex.getClass().getAnnotation(CatchNumber.class); + if (catchNumber == null || catchNumber.value() != ekind.expectedValue) { + throw new Error("was expecting 1 - got " + catchNumber); + } + sum += catchNumber.value(); + } catch (final B ex) { // Catch number 2 + CatchNumber catchNumber = ex.getClass().getAnnotation(CatchNumber.class); + if (catchNumber == null || catchNumber.value() != ekind.expectedValue) { + throw new Error("was expecting 2 - got " + catchNumber); + } + sum += catchNumber.value(); + } + } +} diff --git a/test/tools/javac/multicatch/Pos05.java b/test/tools/javac/multicatch/Pos05.java new file mode 100644 index 0000000000000000000000000000000000000000..128450d11bda3c7a7d9eaaee439759a732ea99da --- /dev/null +++ b/test/tools/javac/multicatch/Pos05.java @@ -0,0 +1,117 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6943289 + * @summary Project Coin: Improved Exception Handling for Java (aka 'multicatch') + * @run main Pos05 + */ + +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.Code_attribute; +import com.sun.tools.classfile.Code_attribute.Exception_data; +import com.sun.tools.classfile.Method; +import java.io.*; + +public class Pos05 { + + static class Pos05sub { + + class A extends Exception {} + class B extends Exception {} + class C extends Exception {} + + void test(boolean b1, boolean b2) { + try { + if (b1) { + throw new A(); + } + else if (b2) { + throw new B(); + } + else { + throw new C(); + } + } + catch (final A | B | C ex) { + System.out.println("Exception caught"); + } + } + } + + static final int TYPES_IN_MULTICATCH = 3; + static final String SUBTEST_NAME = Pos05sub.class.getName() + ".class"; + static final String TEST_METHOD_NAME = "test"; + + public static void main(String... args) throws Exception { + new Pos05().run(); + } + + public void run() throws Exception { + String workDir = System.getProperty("test.classes"); + File compiledTest = new File(workDir, SUBTEST_NAME); + verifyMulticatchExceptionRanges(compiledTest); + } + + void verifyMulticatchExceptionRanges(File f) { + System.err.println("verify: " + f); + try { + int count = 0; + ClassFile cf = ClassFile.read(f); + Method testMethod = null; + for (Method m : cf.methods) { + if (m.getName(cf.constant_pool).equals(TEST_METHOD_NAME)) { + testMethod = m; + break; + } + } + if (testMethod == null) { + throw new Error("Test method not found"); + } + Code_attribute ea = (Code_attribute)testMethod.attributes.get(Attribute.Code); + if (testMethod == null) { + throw new Error("Code attribute for test() method not found"); + } + Exception_data firstExceptionTable = null; + for (int i = 0 ; i < ea.exception_table_langth; i++) { + if (firstExceptionTable == null) { + firstExceptionTable = ea.exception_table[i]; + } + if (ea.exception_table[i].handler_pc != firstExceptionTable.handler_pc || + ea.exception_table[i].start_pc != firstExceptionTable.start_pc || + ea.exception_table[i].end_pc != firstExceptionTable.end_pc) { + throw new Error("Multiple overlapping catch clause found in generated code"); + } + count++; + } + if (count != TYPES_IN_MULTICATCH) { + throw new Error("Wrong number of exception data found: " + count); + } + } catch (Exception e) { + e.printStackTrace(); + throw new Error("error reading " + f +": " + e); + } + } +}