Fri, 08 Feb 2013 09:21:19 +0000
7167125: Two variables after the same operation in a inner class return different results
Reviewed-by: jjg, mcimadamore
1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Lower.java Fri Feb 08 09:15:27 2013 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java Fri Feb 08 09:21:19 2013 +0000 1.3 @@ -3066,55 +3066,38 @@ 1.4 } 1.5 1.6 public void visitAssignop(final JCAssignOp tree) { 1.7 - if (!tree.lhs.type.isPrimitive() && 1.8 - tree.operator.type.getReturnType().isPrimitive()) { 1.9 - // boxing required; need to rewrite as x = (unbox typeof x)(x op y); 1.10 - // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y) 1.11 - // (but without recomputing x) 1.12 - JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() { 1.13 - public JCTree build(final JCTree lhs) { 1.14 - JCTree.Tag newTag = tree.getTag().noAssignOp(); 1.15 - // Erasure (TransTypes) can change the type of 1.16 - // tree.lhs. However, we can still get the 1.17 - // unerased type of tree.lhs as it is stored 1.18 - // in tree.type in Attr. 1.19 - Symbol newOperator = rs.resolveBinaryOperator(tree.pos(), 1.20 - newTag, 1.21 - attrEnv, 1.22 - tree.type, 1.23 - tree.rhs.type); 1.24 - JCExpression expr = (JCExpression)lhs; 1.25 - if (expr.type != tree.type) 1.26 - expr = make.TypeCast(tree.type, expr); 1.27 - JCBinary opResult = make.Binary(newTag, expr, tree.rhs); 1.28 - opResult.operator = newOperator; 1.29 - opResult.type = newOperator.type.getReturnType(); 1.30 - JCTypeCast newRhs = make.TypeCast(types.unboxedType(tree.type), 1.31 - opResult); 1.32 - return make.Assign((JCExpression)lhs, newRhs).setType(tree.type); 1.33 - } 1.34 - }); 1.35 - result = translate(newTree); 1.36 - return; 1.37 - } 1.38 - tree.lhs = translate(tree.lhs, tree); 1.39 - tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head); 1.40 - 1.41 - // If translated left hand side is an Apply, we are 1.42 - // seeing an access method invocation. In this case, append 1.43 - // right hand side as last argument of the access method. 1.44 - if (tree.lhs.hasTag(APPLY)) { 1.45 - JCMethodInvocation app = (JCMethodInvocation)tree.lhs; 1.46 - // if operation is a += on strings, 1.47 - // make sure to convert argument to string 1.48 - JCExpression rhs = (((OperatorSymbol)tree.operator).opcode == string_add) 1.49 - ? makeString(tree.rhs) 1.50 - : tree.rhs; 1.51 - app.args = List.of(rhs).prependList(app.args); 1.52 - result = app; 1.53 - } else { 1.54 - result = tree; 1.55 - } 1.56 + final boolean boxingReq = !tree.lhs.type.isPrimitive() && 1.57 + tree.operator.type.getReturnType().isPrimitive(); 1.58 + 1.59 + // boxing required; need to rewrite as x = (unbox typeof x)(x op y); 1.60 + // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y) 1.61 + // (but without recomputing x) 1.62 + JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() { 1.63 + public JCTree build(final JCTree lhs) { 1.64 + JCTree.Tag newTag = tree.getTag().noAssignOp(); 1.65 + // Erasure (TransTypes) can change the type of 1.66 + // tree.lhs. However, we can still get the 1.67 + // unerased type of tree.lhs as it is stored 1.68 + // in tree.type in Attr. 1.69 + Symbol newOperator = rs.resolveBinaryOperator(tree.pos(), 1.70 + newTag, 1.71 + attrEnv, 1.72 + tree.type, 1.73 + tree.rhs.type); 1.74 + JCExpression expr = (JCExpression)lhs; 1.75 + if (expr.type != tree.type) 1.76 + expr = make.TypeCast(tree.type, expr); 1.77 + JCBinary opResult = make.Binary(newTag, expr, tree.rhs); 1.78 + opResult.operator = newOperator; 1.79 + opResult.type = newOperator.type.getReturnType(); 1.80 + JCExpression newRhs = boxingReq ? 1.81 + make.TypeCast(types.unboxedType(tree.type), 1.82 + opResult) : 1.83 + opResult; 1.84 + return make.Assign((JCExpression)lhs, newRhs).setType(tree.type); 1.85 + } 1.86 + }); 1.87 + result = translate(newTree); 1.88 } 1.89 1.90 /** Lower a tree of the form e++ or e-- where e is an object type */
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/test/tools/javac/7167125/DiffResultAfterSameOperationInnerClasses.java Fri Feb 08 09:21:19 2013 +0000 2.3 @@ -0,0 +1,61 @@ 2.4 +/* 2.5 + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. 2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.7 + * 2.8 + * This code is free software; you can redistribute it and/or modify it 2.9 + * under the terms of the GNU General Public License version 2 only, as 2.10 + * published by the Free Software Foundation. 2.11 + * 2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 2.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 2.15 + * version 2 for more details (a copy is included in the LICENSE file that 2.16 + * accompanied this code). 2.17 + * 2.18 + * You should have received a copy of the GNU General Public License version 2.19 + * 2 along with this work; if not, write to the Free Software Foundation, 2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2.21 + * 2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2.23 + * or visit www.oracle.com if you need additional information or have any 2.24 + * questions. 2.25 + */ 2.26 + 2.27 +/* 2.28 + * @test 2.29 + * @bug 7167125 2.30 + * @summary Two variables after the same operation in a inner class return 2.31 + * different results 2.32 + * @run main DiffResultAfterSameOperationInnerClasses 2.33 + */ 2.34 + 2.35 +public class DiffResultAfterSameOperationInnerClasses { 2.36 + public int i = 1; 2.37 + private int j = 1; 2.38 + public String s1 = "Hi, "; 2.39 + private String s2 = "Hi, "; 2.40 + 2.41 + public static void main(String[] args) { 2.42 + InnerClass inner = 2.43 + new DiffResultAfterSameOperationInnerClasses().new InnerClass(); 2.44 + if (!inner.test()) { 2.45 + throw new AssertionError("Different results after same calculation"); 2.46 + } 2.47 + } 2.48 + 2.49 + class InnerClass { 2.50 + public boolean test() { 2.51 + i += i += 1; 2.52 + j += j += 1; 2.53 + 2.54 + s1 += s1 += "dude"; 2.55 + s2 += s2 += "dude"; 2.56 + 2.57 + System.out.println("s1 = " + s1); 2.58 + System.out.println("s2 = " + s2); 2.59 + 2.60 + return (i == j && i == 3 && 2.61 + s1.equals(s2) && s1.endsWith("Hi, Hi, dude")); 2.62 + } 2.63 + } 2.64 +}