[gcjx] Patch: FYI: enum fixes
Tom Tromey
tromey@redhat.com
Fri Nov 11 16:54:00 GMT 2005
I'm checking this in on the gcjx branch.
This makes some correctness changes to enum handling. In particular,
the Enum constructor takes two arguments, so we have to go through and
add the appropriate arguments to each enum constructor. It also adds
a new subclass of model_new -- the enum's compiler-generated static
initializer is allowed to make instances of the enum class (it is the
only thing which can), and this new class lets us bypass the checking.
This patch snowballed a bit to some cleanups, a change to method
resolution handling, and a change to how assert members are added to a
class. In the assert case, I'm not sure how what was there ever
worked.
Tom
Index: ChangeLog
from Tom Tromey <tromey@redhat.com>
* model/method.cc (model_method): Initialize new field.
(resolve): Use 'state'.
(resolve_classes): Likewise.
* model/method.hh (model_method::resolution_state_value): New
enum.
(model_method::state): New field.
(model_method): Initialize new field.
* model/field.cc (model_field): Updated.
(type): Likewise.
(resolve_classes): Likewise.
(resolve): Likewise.
(require_resolution): Likewise.
* model/field.hh (model_field::resolution_state_value): New enum.
(model_field::state): Changed type.
* model/assert.cc (resolve): Don't call add_assert_members.
* source/parse.cc (assert_statement): Call add_assert_members.
* model/constructor.cc (add_parameter): Removed assert.
(resolve): Use 'state' field.
* model/invoke.cc (resolve): Added special case for 'enum'.
* model/wildcard.hh (model_wildcard::resolve_classes_hook):
Renamed.
* model/wildcard.cc (resolve_classes_hook): Renamed.
* model/typevar.hh (model_type_variable::resolve_classes_hook):
Renamed.
* model/typevar.cc (resolve_classes_hook): Renamed.
* model/enum.hh (model_enum::resolve_classes_hook): Renamed.
(model_enum::add_implicit_constructor): Declare.
(model_enum::resolve_member_hook): Declare.
* model/class.cc (do_resolve_classes): Updated.
(add_assert_members): Set location from class. Don't add to
static initializer.
(create_clinit_method): Add assertions to static initializer.
(resolve): Don't give an error about synthetic static fields.
* model/annotype.hh (model_annotation_type::resolve_classes_hook):
Renamed.
* model/annotype.cc (resolve_classes_hook): Renamed.
* model/class.hh (model_class::resolve_classes_hook): Renamed
from resolve_hook.
(model_class::add_implicit_constructor): Now virtual.
* model/new.cc (check_instantiation): New method.
(finish_search_class): Use it.
* model/new.hh (model_new::check_instantiation): Declare.
(class model_new_enum): New class.
* model/enum.cc (add_enum): Pass name and ordinal to
constructor. Create a model_new_enum.
(resolve_classes_hook): Renamed.
(resolve_member_hook): New method.
(add_enum_arguments): New method.
* model/enumconst.cc (model_enum_constant): New constructor.
* model/enumconst.hh (model_enum_constant): No longer inline.
Index: source/parse.cc
===================================================================
--- source/parse.cc (revision 106718)
+++ source/parse.cc (working copy)
@@ -1559,6 +1559,14 @@
}
require (TOKEN_SEMI);
+
+ // This is a somewhat ugly hack. We need to add some synthetic
+ // members to the class if an 'assert' is seen. However, if we wait
+ // until resolution, then there is not really a good time to do it.
+ // So, it is simplest to note the presence of an assert during
+ // parsing.
+ enclosing_class ()->add_assert_members ();
+
return result;
}
Index: model/enum.hh
===================================================================
--- model/enum.hh (revision 105944)
+++ model/enum.hh (working copy)
@@ -34,9 +34,15 @@
// All the enum constants that have been added.
std::list<ref_enum_constant> constants;
- void resolve_hook (resolution_scope *);
+ // Add enum-specific arguments to the constructor. See the Enum
+ // constructor; these are passed up to it by the super() call in the
+ // constructor.
+ void add_enum_arguments (model_constructor *);
+ void resolve_classes_hook (resolution_scope *);
+ void resolve_member_hook (resolution_scope *);
void massage_modifiers (const ref_modifier_list &mods);
+ ref_method add_implicit_constructor ();
public:
Index: model/typevar.cc
===================================================================
--- model/typevar.cc (revision 105944)
+++ model/typevar.cc (working copy)
@@ -22,7 +22,7 @@
#include "typedefs.hh"
void
-model_type_variable::resolve_hook (resolution_scope *scope)
+model_type_variable::resolve_classes_hook (resolution_scope *scope)
{
ref_forwarding_type bounds_class;
std::list<ref_forwarding_type> ifaces;
Index: model/field.hh
===================================================================
--- model/field.hh (revision 106607)
+++ model/field.hh (working copy)
@@ -38,8 +38,15 @@
class model_field : public model_field_base, public model_variable_decl,
public IDeprecatable, public IModifiable
{
+ enum resolution_state_value
+ {
+ NONE,
+ CLASSES,
+ RESOLVED
+ };
+
// Indicates our current resolution state.
- int state;
+ resolution_state_value state;
void massage_modifiers (const ref_modifier_list &)
{
Index: model/enumconst.cc
===================================================================
--- model/enumconst.cc (revision 105944)
+++ model/enumconst.cc (working copy)
@@ -21,6 +21,15 @@
#include "typedefs.hh"
+model_enum_constant::model_enum_constant (const location &w)
+ : model_class (w),
+ ordinal (-1),
+ body (false)
+{
+ // These classes are effectively anonymous.
+ set_anonymous ();
+}
+
void
model_enum_constant::visit (visitor *v)
{
Index: model/method.hh
===================================================================
--- model/method.hh (revision 106661)
+++ model/method.hh (working copy)
@@ -46,6 +46,13 @@
{
protected:
+ enum resolution_state_value
+ {
+ NONE,
+ CLASSES,
+ RESOLVED
+ };
+
// Name.
std::string name;
@@ -80,6 +87,11 @@
// True if this is an instance initializer method, aka 'finit$'.
bool is_instance_initializer;
+ // The resolution state. We might be resolved multiple times, as
+ // static methods are copied between different instantiations of a
+ // class.
+ resolution_state_value state;
+
// We keep track of the end of the method as well as the beginning;
// this is used by GCC for debugging information.
location method_end;
@@ -116,6 +128,7 @@
used (false),
overrides (false),
is_instance_initializer (false),
+ state (NONE),
// By default we set the end location to the start location.
method_end (w)
{
Index: model/enum.cc
===================================================================
--- model/enum.cc (revision 105944)
+++ model/enum.cc (working copy)
@@ -64,8 +64,9 @@
}
}
- if (! has_body)
- implicit_modifier (ACC_FINAL);
+ // FIXME
+// if (! has_body)
+// implicit_modifier (ACC_FINAL);
mods->access_check (this, "class declared %1 also declared %2");
}
@@ -90,10 +91,25 @@
this);
field->set_modifiers (ACC_PUBLIC | ACC_STATIC | ACC_FINAL);
- ref_new init = new model_new (new_constant->get_location (),
- new_constant.get ());
- init->set_anonymous (new_constant);
- init->set_arguments (new_constant->get_arguments ());
+ ref_expression name
+ = new model_string_literal (new_constant->get_location (),
+ new_constant->get_name ());
+ ref_expression ord
+ = new model_int_literal (new_constant->get_location (),
+ jint (new_constant->get_ordinal ()));
+
+ model_class *what = (new_constant->has_body_p () ?
+ (model_class *) new_constant.get ()
+ : (model_class *) this);
+ ref_new init = new model_new_enum (new_constant->get_location (), what);
+ if (new_constant->has_body_p ())
+ init->set_anonymous (new_constant);
+
+ std::list<ref_expression> init_args = new_constant->get_arguments ();
+ init_args.push_front (ord);
+ init_args.push_front (name);
+ init->set_arguments (init_args);
+
field->set_initializer (init);
add (field);
@@ -107,7 +123,7 @@
}
void
-model_enum::resolve_hook (resolution_scope *scope)
+model_enum::resolve_classes_hook (resolution_scope *scope)
{
if (declaring_class && declaring_class->inner_p ())
std::cerr << error ("enum invalid in inner class %1")
@@ -131,6 +147,55 @@
}
void
+model_enum::add_enum_arguments (model_constructor *cons)
+{
+ location where = get_location ();
+ // FIXME: name of synthetic variable should not clash.
+ ref_variable_decl name
+ = new model_parameter_decl (where, "$name",
+ new model_forwarding_resolved (where,
+ global->get_compiler ()->java_lang_String ()),
+ this);
+ // FIXME: name of synthetic variable should not clash.
+ ref_variable_decl ordinal
+ = new model_parameter_decl (where, "$ordinal",
+ new model_forwarding_resolved (where,
+ primitive_int_type),
+ this);
+
+ cons->add_parameter (ordinal);
+ cons->add_parameter (name);
+}
+
+ref_method
+model_enum::add_implicit_constructor ()
+{
+ ref_method result = model_class::add_implicit_constructor ();
+
+ // For an enum, the implicit constructor is always private.
+ modifier_t mods = result->get_modifiers ();
+ mods &= ~ACC_ACCESS;
+ mods |= ACC_PRIVATE;
+ result->set_modifiers (mods);
+
+ add_enum_arguments (assert_cast<model_constructor *> (result.get ()));
+ return result;
+}
+
+void
+model_enum::resolve_member_hook (resolution_scope *scope)
+{
+ // Add the special arguments to each constructor in the class.
+ for (std::list<ref_method>::const_iterator i = methods.begin ();
+ i != methods.end ();
+ ++i)
+ {
+ if ((*i)->constructor_p ())
+ add_enum_arguments (assert_cast<model_constructor *> ((*i).get ()));
+ }
+}
+
+void
model_enum::visit (visitor *v)
{
v->visit_enum (this, descriptor, name, constants);
Index: model/class.hh
===================================================================
--- model/class.hh (revision 106607)
+++ model/class.hh (working copy)
@@ -210,7 +210,7 @@
std::string get_assigned_name () const;
// Add an implicit constructor if one wasn't found.
- ref_method add_implicit_constructor ();
+ virtual ref_method add_implicit_constructor ();
// Add 'finit$' if it is required.
void create_finit_method ();
// Add '<clinit>' if it is required. Return true if it was created.
@@ -257,8 +257,8 @@
bool check_init_list (const std::list<ref_stmt> &);
// An ad hoc method for subclasses to override. Called during
- // resolution.
- virtual void resolve_hook (resolution_scope *)
+ // class ("envelope") resolution.
+ virtual void resolve_classes_hook (resolution_scope *)
{
}
Index: model/field.cc
===================================================================
--- model/field.cc (revision 106607)
+++ model/field.cc (working copy)
@@ -28,7 +28,7 @@
vardecl->get_declared_type (),
vardecl->get_declaring_class ()),
IModifiable (),
- state (0)
+ state (NONE)
{
set_initializer (vardecl->get_initializer ());
}
@@ -38,7 +38,7 @@
model_class *decl)
: model_variable_decl (w, n, t, decl),
IModifiable (),
- state (0)
+ state (NONE)
{
}
@@ -62,7 +62,7 @@
model_type *
model_field::type () const
{
- if (state < 1
+ if (state < CLASSES
&& ! declaring_class->local_p ()
&& declaring_class->get_compilation_unit ())
{
@@ -79,9 +79,9 @@
void
model_field::resolve_classes (resolution_scope *scope)
{
- if (state < 1)
+ if (state < CLASSES)
{
- state = 1;
+ state = CLASSES;
resolution_scope::push_warnings warn_holder (scope, this);
model_variable_decl::resolve_classes (scope);
}
@@ -90,20 +90,20 @@
void
model_field::check_serialization_fields ()
{
- warning_state state
+ warning_state wstate
= global->get_compiler ()->warn_bad_serialization_field ();
- assert (state);
+ assert (wstate);
if (name == "serialPersistentFields")
{
model_type *io
= global->get_compiler ()->java_io_ObjectStreamField ()->array ();
if (type () != io)
- std::cerr << warn (state, "field %1 should be of type %2")
+ std::cerr << warn (wstate, "field %1 should be of type %2")
% this % io;
if ((modifiers & (ACC_PRIVATE | ACC_STATIC | ACC_FINAL))
!= (ACC_PRIVATE | ACC_STATIC | ACC_FINAL))
- std::cerr << warn (state,
+ std::cerr << warn (wstate,
"field %1 should be %<private static final%>")
% this;
}
@@ -111,19 +111,19 @@
if (name == "serialVersionUID")
{
if (type () != primitive_long_type)
- std::cerr << warn (state, "field %1 should be of type %<long%>")
+ std::cerr << warn (wstate, "field %1 should be of type %<long%>")
% this;
if (! declaring_class->interface_p ()
&& ((modifiers & (ACC_PRIVATE | ACC_STATIC | ACC_FINAL))
!= (ACC_PRIVATE | ACC_STATIC | ACC_FINAL)))
- std::cerr << warn (state,
+ std::cerr << warn (wstate,
"field %1 should be %<private static final%>")
% this;
}
if ((name == "serialPersistentFields" || name == "serialVersionUID")
&& ! global->get_compiler ()->java_io_Serializable ()->assignable_from_p (declaring_class))
- std::cerr << warn (state, "field %1 declared in class which "
+ std::cerr << warn (wstate, "field %1 declared in class which "
"is not serializable")
% this;
}
@@ -131,9 +131,9 @@
void
model_field::resolve (resolution_scope *scope)
{
- if (state < 2)
+ if (state < RESOLVED)
{
- state = 2;
+ state = RESOLVED;
resolution_scope::push_warnings warn_holder (scope, this);
model_variable_decl::resolve (scope);
@@ -208,7 +208,7 @@
void
model_field::require_resolution ()
{
- if (state < 2)
+ if (state < RESOLVED)
{
resolution_scope scope;
declaring_class->push_on_scope (&scope);
Index: model/wildcard.hh
===================================================================
--- model/wildcard.hh (revision 106309)
+++ model/wildcard.hh (working copy)
@@ -34,7 +34,7 @@
// The type bound. If there is no bound, this is NULL.
ref_forwarding_type bound;
- void resolve_hook (resolution_scope *);
+ void resolve_classes_hook (resolution_scope *);
public:
Index: model/annotype.hh
===================================================================
--- model/annotype.hh (revision 105944)
+++ model/annotype.hh (working copy)
@@ -38,7 +38,7 @@
watch<annotation_retention> policy;
- void resolve_hook (resolution_scope *);
+ void resolve_classes_hook (resolution_scope *);
annotation_kind get_annotation_kind () const
{
Index: model/new.hh
===================================================================
--- model/new.hh (revision 105944)
+++ model/new.hh (working copy)
@@ -42,6 +42,9 @@
void finish_search_class (resolution_scope *, model_class **,
model_class **);
+ // Called to perform the instantiation check of the target class.
+ virtual void check_instantiation (model_class *);
+
public:
model_new (const location &w)
@@ -121,8 +124,32 @@
void visit (visitor *);
};
+/// This is just like 'new', but it is only used when creating an
+/// Enum's static initializer, and it bypasses the instantiation
+/// check. These cannot be created by user code, only by the
+/// internal enum handling.
+class model_new_enum : public model_new
+{
+protected:
+
+ void check_instantiation (model_class *)
+ {
+ // Nothing.
+ }
+
+public:
+
+ model_new_enum (const location &w, model_type *t)
+ : model_new (w, t)
+ {
+ }
+};
+
/// These typedefs are used to represent 'new' expressions with
/// explicit actual type parameters for their generic constructors.
+/// Note that we do not need a generic variant of model_new_enum, as
+/// these constructor calls are generated internally and never specify
+/// type arguments.
typedef class model_generic_invocation<model_new> model_generic_new;
typedef class model_generic_invocation<model_new_primary> model_generic_new_primary;
Index: model/method.cc
===================================================================
--- model/method.cc (revision 106708)
+++ model/method.cc (working copy)
@@ -45,6 +45,7 @@
IAnnotatable (other),
IModifiable (other),
IMember (enclosing),
+ state (other->state),
method_end (other->method_end)
{
set_name (other->name);
@@ -86,6 +87,7 @@
IAnnotatable (other),
IModifiable (other),
IMember (enclosing),
+ state (other->state),
method_end (other->method_end)
{
set_name (other->name);
@@ -663,6 +665,10 @@
void
model_method::resolve (resolution_scope *scope)
{
+ if (state == RESOLVED)
+ return;
+ state = RESOLVED;
+
resolve_annotations (scope);
resolution_scope::push_warnings warn_holder (scope, this);
@@ -745,6 +751,10 @@
void
model_method::resolve_classes (resolution_scope *scope)
{
+ if (state >= CLASSES)
+ return;
+ state = CLASSES;
+
// Resolve annotations here since they seem like part of the
// envelope.
resolve_annotation_classes (scope);
Index: model/typevar.hh
===================================================================
--- model/typevar.hh (revision 105944)
+++ model/typevar.hh (working copy)
@@ -31,7 +31,7 @@
// The bounds before resolution.
std::list<ref_forwarding_type> bounds;
- void resolve_hook (resolution_scope *);
+ void resolve_classes_hook (resolution_scope *);
void compute_descriptor ()
{
Index: model/class.cc
===================================================================
--- model/class.cc (revision 106760)
+++ model/class.cc (working copy)
@@ -796,16 +796,16 @@
{
if (! dollar_assertionsDisabled)
{
- // This can only be called for the first time when resolving a
- // method body of a method declared in this class.
- assert (resolution_state == POST_MEMBERS);
+ // This can only be called for the first time during parsing.
+ assert (resolution_state == NONE);
+ location where = get_location ();
std::string name = generate_synthetic_field_name ("$assertionsDisabled");
// Create a new '$assertionsDisabled' field.
ref_field result
- = new model_field (LOCATION_UNKNOWN, name,
- new model_forwarding_resolved (LOCATION_UNKNOWN,
+ = new model_field (where, name,
+ new model_forwarding_resolved (where,
primitive_boolean_type),
this);
result->set_modifiers (ACC_PRIVATE | ACC_STATIC | ACC_FINAL);
@@ -816,28 +816,21 @@
// this differently.
// Call '<this class>.desiredAssertionStatus()'.
ref_method_invocation call
- = new model_method_invocation (LOCATION_UNKNOWN);
- call->set_expression (new model_class_ref (LOCATION_UNKNOWN, this));
+ = new model_method_invocation (where);
+ call->set_expression (new model_class_ref (where, this));
call->set_method ("desiredAssertionStatus");
// Now invert the value.
- ref_unary expr = new model_logical_not (LOCATION_UNKNOWN);
+ ref_unary expr = new model_logical_not (where);
expr->set_expression (call);
result->set_initializer (expr);
// Put in various places it might be needed.
// FIXME: clean up these internal adds.
- ambiguous_field_map[name] = result.get ();
field_map.insert (std::make_pair (name, result.get ()));
fields.push_back (result);
- // Set up static initializer.
- add (static_inits, result);
-
+
dollar_assertionsDisabled = result;
-
- // Now make sure the field is resolved. This works by side
- // effect. FIXME: just have a real method on model_field.
- result->constant_p ();
}
return dollar_assertionsDisabled.get ();
}
@@ -1178,7 +1171,7 @@
if (compilation_unit)
compilation_unit->resolve (scope);
- resolve_hook (scope);
+ resolve_classes_hook (scope);
resolve_annotation_classes (scope);
@@ -1534,6 +1527,10 @@
bool
model_class::create_clinit_method ()
{
+ // Handle assertion-related things after other initializations.
+ if (dollar_assertionsDisabled)
+ add (static_inits, dollar_assertionsDisabled);
+
if (static_inits.empty () || ! check_init_list (static_inits))
return false;
@@ -1865,7 +1862,10 @@
f->resolve (scope);
}
- if (inner_p () && f->static_p () && ! f->constant_p ())
+ // Note that we skip synthetic fields, for instance the fields
+ // added for assertions.
+ if (inner_p () && f->static_p () && ! f->constant_p ()
+ && ! f->synthetic_p ())
std::cerr << f->error ("%<static%> field of inner class must "
"be a compile-time constant");
}
Index: model/constructor.cc
===================================================================
--- model/constructor.cc (revision 106607)
+++ model/constructor.cc (working copy)
@@ -102,6 +102,9 @@
void
model_constructor::resolve (resolution_scope *scope)
{
+ if (state == RESOLVED)
+ return;
+
model_method::resolve (scope);
if (this0 && other_this == NULL)
@@ -168,7 +171,6 @@
void
model_constructor::add_parameter (const ref_variable_decl ¶m)
{
- assert (constructor_p ());
parameters.push_front (param);
// Must reset this in case it was used before.
descriptor = "";
Index: model/wildcard.cc
===================================================================
--- model/wildcard.cc (revision 106616)
+++ model/wildcard.cc (working copy)
@@ -62,7 +62,7 @@
}
void
-model_wildcard::resolve_hook (resolution_scope *scope)
+model_wildcard::resolve_classes_hook (resolution_scope *scope)
{
if (bound)
{
Index: model/invoke.cc
===================================================================
--- model/invoke.cc (revision 106661)
+++ model/invoke.cc (working copy)
@@ -543,6 +543,38 @@
void
model_super_invocation::resolve (resolution_scope *scope)
{
+ model_class *current = scope->get_current_class ();
+
+ // Special case for a 'super' in an enum.
+ if (current->enum_p ())
+ {
+ // An explicit 'super' in an enum class is invalid.
+ if (! synthetic)
+ throw error ("explicit %<super%> invocation is invalid "
+ "in %<enum%> class");
+
+ // A 'super' call in an enum will alway be implicit and thus
+ // will always have no arguments. We add two arguments, namely
+ // the special arguments added to the enum's constructor, which
+ // are passed to the Enum constructor.
+ assert (arguments.empty ());
+ model_constructor *cons
+ = assert_cast<model_constructor *> (scope->get_current_method ());
+
+ std::list<ref_variable_decl> params = cons->get_parameters ();
+ assert (params.size () >= 2);
+ std::list<ref_variable_decl>::const_iterator p_it = params.begin ();
+
+ ref_simple_variable_ref ref;
+
+ ref = new model_simple_variable_ref (get_location (), (*p_it).get ());
+ arguments.push_back (ref);
+
+ ++p_it;
+ ref = new model_simple_variable_ref (get_location (), (*p_it).get ());
+ arguments.push_back (ref);
+ }
+
{
// The 'super' call is a static context.
model_static_context_scope static_holder (true);
@@ -550,11 +582,6 @@
model_invocation_base::resolve (scope);
}
- // An explicit 'super' in an enum class is invalid.
- model_class *current = scope->get_current_class ();
- if (! synthetic && current->enum_p ())
- throw error ("explicit %<super%> invocation is invalid in %<enum%> class");
-
// An explicit 'super' is invalid in Object.
if (current == global->get_compiler ()->java_lang_Object ())
throw error ("%<super%> invocation invalid in %<java.lang.Object%>");
Index: model/annotype.cc
===================================================================
--- model/annotype.cc (revision 105944)
+++ model/annotype.cc (working copy)
@@ -49,7 +49,7 @@
}
void
-model_annotation_type::resolve_hook (resolution_scope *scope)
+model_annotation_type::resolve_classes_hook (resolution_scope *scope)
{
model_class *annot
= global->get_compiler ()->java_lang_annotation_Annotation ();
Index: model/assert.cc
===================================================================
--- model/assert.cc (revision 105944)
+++ model/assert.cc (working copy)
@@ -1,6 +1,6 @@
// Assert statement.
-// Copyright (C) 2004 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -47,9 +47,6 @@
fold (result);
}
-
- // Make sure the required members are added to the class.
- scope->get_current_class ()->add_assert_members ();
}
void
Index: model/enumconst.hh
===================================================================
--- model/enumconst.hh (revision 105944)
+++ model/enumconst.hh (working copy)
@@ -42,14 +42,7 @@
public:
- model_enum_constant (const location &w)
- : model_class (w),
- ordinal (-1),
- body (false)
- {
- // These classes are effectively anonymous.
- set_anonymous ();
- }
+ model_enum_constant (const location &);
void set_arguments (const std::list<ref_expression> &args)
{
Index: model/new.cc
===================================================================
--- model/new.cc (revision 105944)
+++ model/new.cc (working copy)
@@ -99,11 +99,17 @@
}
void
+model_new::check_instantiation (model_class *target)
+{
+ target->check_instantiation (this);
+}
+
+void
model_new::finish_search_class (resolution_scope *scope,
model_class **result,
model_class **qualifier)
{
- (*result)->check_instantiation (this);
+ check_instantiation (*result);
if ((*result)->anonymous_p ())
{
More information about the Java-patches
mailing list