The following program compiles:
class Test {
static Object x = Test.x;
}
This is rejected by javac:
class Test {
static Object x = x;
}
Since Test.x and x represent the same variable should the compiler
reject both programs?
Comments
SUGGESTED FIX
Includes a fix for 6424491:
Index: j2se/src/share/classes/com/sun/tools/javac/comp/Attr.java
--- /tmp/geta5084 2006-05-15 00:26:23.343330144 -0700
+++ Attr.java 2006-05-14 13:44:46.000000000 -0700
@@ -1690,7 +1690,7 @@
// ..., evaluate its initializer, if it has one, and check for
// illegal forward reference.
- checkInit(tree, env, v);
+ checkInit(tree, env, v, false);
// If symbol is a local variable accessed from an embedded
// inner class check that it is final.
@@ -1791,9 +1791,11 @@
// If that symbol is a variable, ...
if (sym.kind == VAR) {
- // ..., evaluate its initializer, if it has one
VarSymbol v = (VarSymbol)sym;
- v.getConstValue(); // ensure initializer is evaluated
+
+ // ..., evaluate its initializer, if it has one, and check for
+ // illegal forward reference.
+ checkInit(tree, env, v, true);
// If we are expecting a variable (as opposed to a value), check
// that the variable is assignable in the current environment.
@@ -2079,11 +2081,10 @@
* @param env The current environment.
* @param v The variable's symbol.
*/
- private void checkInit(JCIdent tree, Env<AttrContext> env, VarSymbol v) {
-// System.err.println(v + " " + ((v.flags() & STATIC) != 0) + " " +
-// tree.pos + " " + v.pos + " " +
-// Resolve.isStatic(env));//DEBUG
-
+ private void checkInit(JCTree tree,
+ Env<AttrContext> env,
+ VarSymbol v,
+ boolean onlyWarning) {
// A forward reference is diagnosed if the declaration position
// of the variable is greater than the current tree position
// and the tree and variable definition occur in the same class
@@ -2097,8 +2098,14 @@
v.owner == env.info.scope.owner.enclClass() &&
((v.flags() & STATIC) != 0) == Resolve.isStatic(env) &&
(env.tree.tag != JCTree.ASSIGN ||
- TreeInfo.skipParens(((JCAssign) env.tree).lhs) != tree))
+ TreeInfo.skipParens(((JCAssign) env.tree).lhs) != tree)) {
+ if (onlyWarning &&
+ !Flags.isEnum(v.owner) || !Flags.isStatic(v) || Flags.isConstant(v))
+ // See issue 6425594 (javac accepts illegal forward references)
+ log.warning(tree.pos(), "forward.ref", v);
+ else
log.error(tree.pos(), "illegal.forward.ref");
+ }
v.getConstValue(); // ensure initializer is evaluated
@@ -2115,7 +2122,7 @@
* @param v The variable's symbol.
* @see JLS 3rd Ed. (8.9 Enums)
*/
- private void checkEnumInitializer(JCIdent tree, Env<AttrContext> env, VarSymbol v) {
+ private void checkEnumInitializer(JCTree tree, Env<AttrContext> env, VarSymbol v) {
// JLS 3rd Ed.:
//
// "It is a compile-time error to reference a static field
15-05-2006
EVALUATION
The JLS is a bit unclear:
http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.3.2.3
"The declaration of a member needs to appear textually before it is used only
if the member is an instance (respectively static) field of a class or interface
C and all of the following conditions hold:
* The usage occurs in an instance (respectively static) variable initializer
of C or in an instance (respectively static) initializer of C.
* The usage is not on the left hand side of an assignment.
* The usage is via a simple name.
* C is the innermost class or interface enclosing the usage.
A compile-time error occurs if any of the four requirements above are not met."
The last sentence should be something like: "If the declaration of a member
does not precede a use of that member, and the above conditions are met, a
compile-time error occurs."
So the program is valid since the third condition is not met.
However, the compiler should be able to issue a warning and I have changed
this issue to an RFE.