JDK-4396402 : Spec bugs on compile-time constants
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Affected Version: 1.3.0
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2000-12-08
  • Updated: 2001-01-04
  • Resolved: 2001-01-04
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.0 merlinFixed
Related Reports
Relates :  
Description

Name: boT120536			Date: 12/08/2000


java version "1.3.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0_01)
Java HotSpot(TM) Client VM (build 1.3.0_01, mixed mode)


The specification for 15.28, Constant Expressions, has a number of bugs.

1. You have omitted the fact that ParenthesizedExpressions are valid constant
expressions.  This is obviously allowable, though, since you then list
(short)(1*2*3*4*5) as an example constant.

2. The last two bullets are misleading.  They should be amended to read:
"Simple names that refer to final primitives or Strings whose initializers are
constant expressions.
"Qualified names of the form TypeName . Identifier that refer to final
primitives or Strings whose initializers are constant expressions."

As they stand now, I could argue that the following should be legal Java (in
fact, I had submitted this as a bug to the compiler department, and was told I
was in error, and to refer the matter to specification):

class Bad {
  static final Object o = "This is a constant initializer";
  void foo(int i) {
    switch (i) {
      case (String)o != "This string is constant" ? 1 : 2: // case 1
    }
  }
}

As you can see, I used only a cast to String, a simple named reference to a
final variable whose initializer was a constant, the != operator, a string
literal, two integer literals, and the ?: operator, all valid by bullets in the
list of 15.28.  Without the addition of an explicit statement that all
subexpressions, such as the field accesses, must also be primitives or type
String, this class file meets all the written specs for compilation, even though
it violates the spirit of the section.

3. You need to specify how to handle integer division by constant 0.  1/0 is
composed solely of elements that form constants, but cannot be a constant itself
since it is undefined.  However, should it be a compile-time error to have a
constant 0 as the divisor to integer /, %, /=, and %=?  Or should compilers do
as javac 1.3 does, and compile it as a non-constant and generate the guaranteed
ArithmeticException?

Personally, I would prefer that any attempt to do integer division by a constant
0 should be flagged as a compile-time error.  If it is allowed to compile, then
you are violating the premise that all expressions can complete normally, since
you would be guaranteed an abrupt completion on that expression.

class Divide {
  void foo(int i) {
    int j = i / 0;
    System.out.print(j); // this statement is unreachable
  }
}

4. You should probably clarify the behavior of the short-circuiting logic
operators, when the condition is constant.  Must the unevaluated portion of the
expression be constant for the overall expression to be constant?  If bytecode
is generated for the unused side of the operator, it will never be called.

class ShortCircuit {
  void foo(int i) {
    boolean t = true, f = false;
    switch (i) {
      case (true || t) ? 0 : 1: // case 0
      case (false && f) ? 0 : 1: // case 1
      case true ? 2 : i: // case 2
      case false ? i : 3: // case 3
    }
  }
}

5. Presumably, constant expressions can alter what exceptions an expression may
throw.  I am assuming that this code should be illegal, as all the catch blocks
are provably unreachable.  However, I could not find any definitive mention in
the specs one way or another as to the correctness of my assumptions.  Javac 1.3
compiles this, but has other known bugs with not noticing unreachable catch
blocks.

class Question {
  void foo() {
    try {
      String s = "a" + "b"; // cannot throw OutOfMemoryError, as the class
                            // file only sees this as "ab"
    } catch(OutOfMemoryError e) {
    }
    try {
      int[] i = new int[1]; // cannot throw NegativeArraySizeException, as
                            // the size is positive
      char c = 'c';
      int[] j = new int[c]; // ditto
    } catch(NegativeArraySizeException e) {
    }
    try {
      int i = 1;
      int j = i / 1; // cannot throw ArithmeticException
    } catch (ArithmeticException e) {
    }
  }
}

Likewise, code such as new int[-1] should be a compile-time error, rather than
waiting until runtime to throw the NegativeArraySizeException.
(Review ID: 113476) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: generic FIXED IN: merlin INTEGRATED IN: merlin
14-06-2004

WORK AROUND Name: boT120536 Date: 12/08/2000 Make the assumptions that constant expressions may include ParenthesizedExpressions, may not reference variables that are not type String, that division by 0 is a compile-time error, that short-circuiting expressions require the unreached half to be constant if the whole expression is to be constant, and that constants inside an expression can reduce the exceptions it can throw. ======================================================================
11-06-2004

PUBLIC COMMENTS JLS 15.28 should explicitly state that parenthesized constant expressions are constant expressions. Also, the two last bullets apply to variables declared to be of type String or of a primitive type.
10-06-2004

EVALUATION Regarding (1) and (2): points taken. Regarding (3): that issue is handled in 4178182. Regarding (4): it is already clear from 15.28 that ALL subexpressions must be constant. Regarding (5): the compiler is permitted to assume all unchecked exceptions can be thrown anywhere; this is missing from the JLS and reported as 4046575. neal.gafter@Eng 2001-01-03 I agree with Neal. As for negative array indices, this is also a new semantic requirement, not a bug. See bug 4395572. Regarding issues 1 & 2: dealt with in the draft 3rd edition. gilad.bracha@eng 2001-01-03
03-01-2001