T_CPPFLAGS =
CC = cc
-# CYGNUS LOCAL: we use byacc instead of bison, DO NOT SEND TO RMS
-BISON = `if [ -f ../../byacc/byacc ] ; then echo ../../byacc/byacc ; else echo byacc ; fi`
+BISON = bison
BISONFLAGS =
-LEX = `if [ -f ../../flex/flex ] ; then echo ../../flex/flex ; else echo flex ; fi`
+LEX = flex
LEXFLAGS=
AR = ar
OLDAR_FLAGS = qc
`echo $(srcdir)/parse.c | sed 's,^\./,,'`
$(srcdir)/parse.c $(srcdir)/parse.h : $(srcdir)/parse.y
- @echo expect 28 shift/reduce conflicts, 14 reduce/reduce conflicts.
+ @echo expect 24 reduce/reduce conflicts.
cd $(srcdir); $(BISON) $(BISONFLAGS) -d -o parse.c parse.y
cd $(srcdir); grep '^#define[ ]*YYEMPTY' parse.c >>parse.h
extern int flag_assume_nonnull_objects;
extern tree ctor_label, dtor_label;
-/* From cp-typeck.c: */
+/* From typeck.c: */
extern tree unary_complex_lvalue ();
/* Compute the ease with which a conversion can be performed
cp_error ("call to destructor for non-type `%D'", name);
return void_zero_node;
}
+ if (basetype != TREE_TYPE(instance))
+ basetype = TREE_TYPE(instance);
if (! TYPE_HAS_DESTRUCTOR (basetype))
return void_zero_node;
instance = default_conversion (instance);
TREE_VALUE (parm) = resolve_offset_ref (TREE_VALUE (parm));
t = TREE_TYPE (TREE_VALUE (parm));
}
+ if (TREE_CODE (TREE_VALUE (parm)) == OFFSET_REF
+ && TREE_CODE (t) == METHOD_TYPE)
+ {
+ TREE_VALUE (parm) = build_unary_op (ADDR_EXPR, TREE_VALUE (parm), 0);
+ }
if (TREE_CODE (t) == ARRAY_TYPE)
{
/* Perform the conversion from ARRAY_TYPE to POINTER_TYPE in place.
/* Way of stacking language names. */
tree *current_lang_base, *current_lang_stack;
-static int current_lang_stacksize;
+int current_lang_stacksize;
/* Names of languages we recognize. */
tree lang_name_c, lang_name_cplusplus;
via this node. */
static tree base_layout_decl;
-/* Variables shared between cp-class.c and cp-call.c. */
+/* Variables shared between class.c and call.c. */
int n_vtables = 0;
int n_vtable_entries = 0;
vtbl = build_indirect_ref (build_vfield_ref (instance, basetype),
NULL_PTR);
}
- assemble_external (vtbl);
+ if (!flag_vtable_hack)
+ assemble_external (vtbl);
aref = build_array_ref (vtbl, idx);
/* Save the intermediate result in a SAVE_EXPR so we don't have to
/* Access the virtual function table entry that logically
contains BASE_FNDECL. VIRTUALS is the virtual function table's
- initializer. */
+ initializer. We can run off the end, when dealing with virtual
+ destructors in MI situations, return NULL_TREE in that case. */
static tree
get_vtable_entry (virtuals, base_fndecl)
tree virtuals, base_fndecl;
n_vtable_searches += i;
#endif
- while (i > 0)
+ while (i > 0 && virtuals)
{
virtuals = TREE_CHAIN (virtuals);
i -= 1;
prepare_fresh_vtable (binfo, base, t);
}
- saved_pfn = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (get_vtable_entry (BINFO_VIRTUALS (binfo), base_fndecl))), 0);
+ saved_pfn = get_vtable_entry (BINFO_VIRTUALS (binfo), base_fndecl);
+ if (saved_pfn)
+ saved_pfn = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (saved_pfn)), 0);
#ifdef NOTQUITE
cp_warning ("in %D", DECL_NAME (BINFO_VTABLE (binfo)));
#endif
/* The this_offset can be wrong, if we try and modify an entry
that had been modified once before. */
- if (! SAME_FN (saved_pfn, fndecl))
+ if (saved_pfn && ! SAME_FN (saved_pfn, fndecl))
{
modify_vtable_entry (get_vtable_entry (BINFO_VIRTUALS (binfo), base_fndecl),
build_vtable_entry (this_offset, pfn),
return 0;
}
-static tree
+/* Return the offset to the main vtable for a given base BINFO. */
+tree
get_vfield_offset (binfo)
tree binfo;
{
return size_binop (PLUS_EXPR,
- DECL_FIELD_BITPOS (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))),
+ size_binop (FLOOR_DIV_EXPR,
+ DECL_FIELD_BITPOS (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))),
+ size_int (BITS_PER_UNIT)),
BINFO_OFFSET (binfo));
}
b->cant_synth_copy_ctor = 1;
}
}
+ {
+ tree v = get_vbase_types (t_binfo);
+
+ for (; v; v = TREE_CHAIN (v))
+ {
+ tree basetype = BINFO_TYPE (v);
+ if (get_base_distance (basetype, t_binfo, 0, (tree*)0) == -2)
+ {
+ if (extra_warnings)
+ cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
+ basetype, t);
+ b->cant_synth_asn_ref = 1;
+ b->cant_synth_copy_ctor = 1;
+ }
+ }
+ }
{
tree vfields;
enum tree_code code = TREE_CODE (t);
register tree x, last_x, method_vec;
int needs_virtual_dtor;
- tree name = TYPE_NAME (t), fields, fn_fields, tail;
+ tree name = TYPE_NAME (t), fields, fn_fields, *tail;
+ tree *tail_user_methods = &CLASSTYPE_METHODS (t);
enum access_type access;
int all_virtual;
int has_virtual;
CLASSTYPE_VFIELDS (t) = vfields;
CLASSTYPE_VFIELD (t) = vfield;
- fn_fields = NULL_TREE;
- tail = NULL_TREE;
+ tail = &fn_fields;
if (last_x && list_of_fieldlists)
TREE_CHAIN (last_x) = TREE_VALUE (list_of_fieldlists);
if (last_x)
TREE_CHAIN (last_x) = TREE_CHAIN (x);
- if (! fn_fields)
- fn_fields = x;
- else
- TREE_CHAIN (tail) = x;
- tail = x;
+ /* Link x onto end of fn_fields and CLASSTYPE_METHODS. */
+ *tail = x;
+ tail = &TREE_CHAIN (x);
+ *tail_user_methods = x;
+ tail_user_methods = &DECL_NEXT_METHOD (x);
#if 0
/* ??? What if we have duplicate declarations
}
}
- if (tail) TREE_CHAIN (tail) = NULL_TREE;
-
/* If this type has any constant members which did not come
with their own initialization, mark that fact here. It is
not an error here, since such types can be saved either by their
TYPE_NEEDS_DESTRUCTOR (t) = 0;
else
{
- if (! fn_fields)
- fn_fields = dtor;
- else
- TREE_CHAIN (tail) = dtor;
- tail = dtor;
+ /* Link dtor onto end of fn_fields. */
+ *tail = dtor;
+ tail = &TREE_CHAIN (dtor);
if (DECL_VINDEX (dtor) == NULL_TREE
&& ! CLASSTYPE_DECLARED_EXCEPTION (t)
}
}
+ *tail = NULL_TREE;
+ *tail_user_methods = NULL_TREE;
+
TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_HAS_DESTRUCTOR (t);
/* Synthesize any needed methods. Note that methods will be synthesized
};
int rank_for_overload ();
-/* Variables shared between cp-class.c and cp-call.c. */
+/* Variables shared between class.c and call.c. */
extern int n_vtables;
extern int n_vtable_entries;
extern int write_virtuals;
+/* True if we want output of vtables to be controlled by whether
+ we seen the class's first non-inline virtual function.
+ 0 is old behavior; 1 is new behavior. */
+extern flag_vtable_hack;
+
/* INTERFACE_ONLY nonzero means that we are in an "interface"
section of the compiler. INTERFACE_UNKNOWN nonzero means
we cannot trust the value of INTERFACE_ONLY. If INTERFACE_UNKNOWN
union tree_node *dossier;
+ union tree_node *methods;
+
union tree_node *signature;
union tree_node *signature_pointer_to;
union tree_node *signature_reference_to;
/* The is the VAR_DECL that contains NODE's dossier. */
#define CLASSTYPE_DOSSIER(NODE) (TYPE_LANG_SPECIFIC(NODE)->dossier)
+/* List of all explicit methods (chained using DECL_NEXT_METHOD),
+ in order they were parsed. */
+#define CLASSTYPE_METHODS(NODE) (TYPE_LANG_SPECIFIC(NODE)->methods)
+
/* Nonzero means that this _CLASSTYPE node overloads operator(). */
#define TYPE_OVERLOADS_CALL_EXPR(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_call_overloaded)
struct template_info *template_info;
tree main_decl_variant;
struct pending_inline *pending_inline_info;
- tree vbase_init_list;
+ tree next_method;
tree chain;
};
#define DECL_CHAIN(NODE) (TREE_CHAIN (NODE))
#endif
+/* Next method in CLASSTYPE_METHODS list. */
+#define DECL_NEXT_METHOD(NODE) (DECL_LANG_SPECIFIC(NODE)->next_method)
+
/* Points back to the decl which caused this lang_decl to be allocated. */
#define DECL_MAIN_VARIANT(NODE) (DECL_LANG_SPECIFIC(NODE)->main_decl_variant)
which this signature member function pointer was created. */
#define DECL_MEMFUNC_POINTING_TO(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.memfunc_pointer_to)
-/* Holds information about how virtual base classes should be initialized
- by this constructor *if* this constructor is the one to perform
- such initialization. */
-#define DECL_VBASE_INIT_LIST(NODE) (DECL_LANG_SPECIFIC(NODE)->vbase_init_list)
-
/* For a TEMPLATE_DECL: template-specific information. */
#define DECL_TEMPLATE_INFO(NODE) (DECL_LANG_SPECIFIC(NODE)->template_info)
#define DECL_TEMPLATE_IS_CLASS(NODE) (DECL_RESULT(NODE) == NULL_TREE)
#define DECL_TEMPLATE_PARMS(NODE) DECL_ARGUMENTS(NODE)
/* For class templates. */
-#define DECL_TEMPLATE_MEMBERS(NODE) DECL_INITIAL(NODE)
+#define DECL_TEMPLATE_MEMBERS(NODE) DECL_SIZE(NODE)
/* For function, method, class-data templates. */
#define DECL_TEMPLATE_RESULT(NODE) DECL_RESULT(NODE)
#define DECL_TEMPLATE_INSTANTIATIONS(NODE) DECL_VINDEX(NODE)
extern tree type_for_mode PROTO((enum machine_mode, int));
extern tree type_for_size PROTO((unsigned, int));
-/* in cp-decl{2}.c */
+/* in decl{2}.c */
extern tree void_list_node;
extern tree void_zero_node;
extern tree default_function_type;
/* For building calls to `delete'. */
extern tree integer_two_node, integer_three_node;
-/* in cp-except.c */
+/* in except.c */
extern tree current_exception_type;
extern tree current_exception_decl;
extern tree current_exception_object;
-/* in cp-pt.c */
+/* in pt.c */
/* PARM_VEC is a vector of template parameters, either IDENTIFIER_NODEs or
PARM_DECLs. BINDINGS, if non-null, is a vector of bindings for those
parameters. */
extern struct tinst_level *current_tinst_level;
-/* in cp-class.c */
+/* in class.c */
extern tree current_class_name;
extern tree current_class_type;
extern tree previous_class_type;
extern tree current_class_name, current_class_type, current_class_decl, C_C_D;
extern tree current_vtable_decl;
-/* in cp-init.c */
+/* in init.c */
extern tree global_base_init_list;
extern tree current_base_init_list, current_member_init_list;
access_private_virtual
};
-/* in cp-lex.c */
+/* in lex.c */
extern tree current_unit_name, current_unit_language;
/* Things for handling inline functions. */
unsigned int interface : 2; /* 0=interface 1=unknown 2=implementation */
};
-/* in cp-method.c */
+/* in method.c */
extern struct pending_inline *pending_inlines;
/* 1 for -fall-virtual: make every member function (except
(TEMPLATE_CONST_TPARMLIST (NODE) = saved_parmlist, \
TEMPLATE_CONST_IDX (NODE) = I)
-/* in cp-lex.c */
+/* in lex.c */
/* Indexed by TREE_CODE, these tables give C-looking names to
operators represented by TREE_CODES. For example,
opname_tab[(int) MINUS_EXPR] == "-". */
extern void overflow_warning PROTO((tree));
extern void unsigned_conversion_warning PROTO((tree, tree));
-/* in cp-call.c */
+/* in call.c */
extern struct candidate *ansi_c_bullshit;
extern int rank_for_overload PROTO((struct candidate *, struct candidate *));
extern tree build_overload_call PROTO((tree, tree, int, struct candidate *));
extern tree build_overload_call_maybe PROTO((tree, tree, int, struct candidate *));
-/* in cp-class.c */
+/* in class.c */
extern tree build_vbase_pointer PROTO((tree, tree));
extern tree build_vbase_path PROTO((enum tree_code, tree, tree, tree, int));
extern tree build_vtable_entry PROTO((tree, tree));
extern tree build_vfn_ref PROTO((tree *, tree, tree));
extern void add_method PROTO((tree, tree *, tree));
+extern tree get_vfield_offset PROTO((tree));
extern void duplicate_tag_error PROTO((tree));
extern tree finish_struct PROTO((tree, tree, int));
extern int resolves_to_fixed_type_p PROTO((tree, int *));
extern void print_class_statistics PROTO((void));
extern void maybe_push_cache_obstack PROTO((void));
-/* in cp-cvt.c */
+/* in cvt.c */
extern tree convert_to_reference PROTO((tree, tree, tree, tree, int, char *, int, int));
extern tree convert_from_reference PROTO((tree));
extern tree convert_to_aggr PROTO((tree, tree, char **, int));
extern int build_default_binary_type_conversion PROTO((enum tree_code, tree *, tree *));
extern int build_default_unary_type_conversion PROTO((enum tree_code, tree *));
-/* cp-decl.c */
+/* decl.c */
extern int global_bindings_p PROTO((void));
extern void keep_next_level PROTO((void));
extern int kept_level_p PROTO((void));
extern void push_exception_cleanup PROTO((tree));
extern void revert_static_member_fn PROTO((tree *, tree *, tree *));
-/* in cp-decl2.c */
+/* in decl2.c */
extern int lang_decode_option PROTO((char *));
extern tree grok_method_quals PROTO((tree, tree, tree));
extern void grokclassfn PROTO((tree, tree, tree, enum overload_flags, tree));
extern tree grokfield PROTO((tree, tree, tree, tree, tree));
extern tree grokbitfield PROTO((tree, tree, tree));
extern tree groktypefield PROTO((tree, tree));
-extern tree grokoptypename PROTO((tree, int));
+extern tree grokoptypename PROTO((tree, tree));
extern tree build_push_scope PROTO((tree, tree));
extern tree constructor_name_full PROTO((tree));
extern tree constructor_name PROTO((tree));
extern void finish_file PROTO((void));
extern void warn_if_unknown_interface PROTO((void));
extern tree grok_x_components PROTO((tree, tree));
+extern tree reparse_absdcl_as_expr PROTO((tree, tree));
+extern tree reparse_absdcl_as_casts PROTO((tree, tree));
+extern tree reparse_decl_as_expr PROTO((tree, tree));
+extern tree finish_decl_parsing PROTO((tree));
-/* in cp-edsel.c */
+/* in edsel.c */
-/* in cp-except.c */
+/* in except.c */
extern tree lookup_exception_cname PROTO((tree, tree, tree));
extern tree lookup_exception_tname PROTO((tree));
extern tree lookup_exception_object PROTO((tree, tree, int));
extern void init_exception_processing PROTO((void));
extern void init_exception_processing_1 PROTO((void));
-/* in cp-expr.c */
+/* in expr.c */
/* skip cplus_expand_expr */
extern void init_cplus_expand PROTO((void));
extern void fixup_result_decl PROTO((tree, struct rtx_def *));
extern int decl_in_memory_p PROTO((tree));
-/* in cp-gc.c */
+/* in gc.c */
extern int type_needs_gc_entry PROTO((tree));
extern int value_safe_from_gc PROTO((tree, tree));
extern void build_static_gc_entry PROTO((tree, tree));
extern tree get_typeid PROTO((tree));
extern tree build_dynamic_cast PROTO((tree, tree));
-/* in cp-init.c */
+/* in init.c */
extern void emit_base_init PROTO((tree, int));
extern void check_base_init PROTO((tree));
extern tree build_virtual_init PROTO((tree, tree, tree));
extern tree build_vbase_delete PROTO((tree, tree));
extern tree build_vec_delete PROTO((tree, tree, tree, tree, tree, tree));
-/* in cp-input.c */
+/* in input.c */
-/* in cp-lex.c */
+/* in lex.c */
extern tree make_pointer_declarator PROTO((tree, tree));
extern tree make_reference_declarator PROTO((tree, tree));
extern char *operator_name_string PROTO((tree));
extern void compiler_error_with_decl PROTO((tree, char *));
extern void yyerror PROTO((char *));
-/* in cp-error.c */
+/* in error.c */
extern void init_error PROTO((void));
extern char *fndecl_as_string PROTO((tree, tree, int));
extern char *type_as_string PROTO((tree, int));
extern char *parm_as_string PROTO((int, int));
extern char *op_as_string PROTO((enum tree_code, int));
-/* in cp-method.c */
+/* in method.c */
extern void init_method PROTO((void));
extern tree make_anon_parm_name PROTO((void));
extern void clear_anon_parm_name PROTO((void));
extern tree hack_identifier PROTO((tree, tree, int));
extern tree build_component_type_expr PROTO((tree, tree, tree, int));
-/* in cp-pt.c */
+/* in pt.c */
extern void begin_template_parm_list PROTO((void));
extern tree process_template_parm PROTO((tree, tree));
extern tree end_template_parm_list PROTO((tree));
-extern void end_template_decl PROTO((tree, tree, tree));
+extern void end_template_decl PROTO((tree, tree, tree, int));
extern tree lookup_template_class PROTO((tree, tree, tree));
extern void push_template_decls PROTO((tree, tree, int));
extern void pop_template_decls PROTO((tree, tree, int));
struct tinst_level *tinst_for_decl PROTO((void));
extern void do_function_instantiation PROTO((tree, tree));
-/* in cp-search.c */
+/* in search.c */
extern tree make_memoized_table_entry PROTO((tree, tree, int));
extern void push_memoized_context PROTO((tree, int));
extern void pop_memoized_context PROTO((int));
extern void reinit_search_statistics PROTO((void));
extern tree current_scope PROTO((void));
-/* in cp-sig.c */
+/* in sig.c */
extern tree build_signature_pointer_type PROTO((tree, int, int));
extern tree build_signature_reference_type PROTO((tree, int, int));
extern tree build_signature_pointer_constructor PROTO((tree, tree));
extern tree build_sptr_ref PROTO((tree));
extern tree build_vptr_ref PROTO((tree));
-/* in cp-spew.c */
+/* in spew.c */
extern void init_spew PROTO((void));
extern int yylex PROTO((void));
extern tree arbitrate_lookup PROTO((tree, tree, tree));
-/* in cp-tree.c */
+/* in tree.c */
extern int lvalue_p PROTO((tree));
extern int lvalue_or_else PROTO((tree, char *));
extern tree build_cplus_new PROTO((tree, tree, int));
extern tree array_type_nelts_total PROTO((tree));
extern tree array_type_nelts_top PROTO((tree));
-/* in cp-typeck.c */
+/* in typeck.c */
extern tree target_type PROTO((tree));
extern tree require_complete_type PROTO((tree));
extern int type_unknown_p PROTO((tree));
extern tree build_component_ref PROTO((tree, tree, tree, int));
extern tree build_ptrmemfunc PROTO((tree, tree, int));
-/* in cp-type2.c */
+/* in typeck2.c */
extern tree error_not_base_type PROTO((tree, tree));
extern tree binfo_or_else PROTO((tree, tree));
extern void error_with_aggr_type (); /* PROTO((tree, char *, HOST_WIDE_INT)); */
extern char *enum_name_string PROTO((tree, tree));
extern void report_case_error PROTO((int, tree, tree, tree));
-/* in cp-xref.c */
+/* in xref.c */
extern void GNU_xref_begin PROTO((char *));
extern void GNU_xref_end PROTO((int));
extern void GNU_xref_file PROTO((char *));
if (TYPE_USES_COMPLEX_INHERITANCE (argtype))
{
TREE_TYPE (rval) = TYPE_POINTER_TO (argtype);
- rval = convert_pointer_to (target_type, rval);
+ if (flags & LOOKUP_PROTECT)
+ rval = convert_pointer_to (target_type, rval);
+ else
+ rval
+ = convert_to_pointer_force (build_pointer_type (target_type), rval);
TREE_TYPE (rval) = type;
}
TREE_CONSTANT (rval) = literal_flag;
if (code == POINTER_TYPE)
return fold (convert_to_pointer_force (type, e));
- /* From cp-typeck.c convert_for_assignment */
+ /* From typeck.c convert_for_assignment */
if (((TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE && TREE_CODE (e) == ADDR_EXPR
&& TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (TREE_TYPE (e))) == METHOD_TYPE)
- || integer_zerop (e))
+ || integer_zerop (e)
+ || TYPE_PTRMEMFUNC_P (TREE_TYPE (e)))
&& TYPE_PTRMEMFUNC_P (type))
{
/* compatible pointer to member functions. */
- e = build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), e, 1);
- if (e == 0)
- return error_mark_node;
- return digest_init (type, e, (tree *)0);
+ return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), e, 1);
}
{
int old_equiv = flag_int_enum_equivalence;
extern tree *current_lang_base, *current_lang_stack;
\f
-/* C and C++ flags are in cp-decl2.c. */
+/* C and C++ flags are in decl2.c. */
/* Set to 0 at beginning of a constructor, set to 1
if that function does an allocation before referencing its
int current_function_obstack_usage;
-/* Flag used when debugging cp-spew.c */
+/* Flag used when debugging spew.c */
extern int spew_debug;
tree class_name, class_type, class_decl, function_decl;
struct binding_level *class_bindings;
tree previous_class_type;
+ tree *lang_base, *lang_stack, lang_name;
+ int lang_stacksize;
+ tree named_labels;
};
static struct saved_scope *current_saved_scope;
extern tree prev_class_type;
void
push_to_top_level ()
{
+ extern int current_lang_stacksize;
struct saved_scope *s =
(struct saved_scope *) xmalloc (sizeof (struct saved_scope));
struct binding_level *b = current_binding_level;
s->function_decl = current_function_decl;
s->class_bindings = class_binding_level;
s->previous_class_type = previous_class_type;
+ s->lang_stack = current_lang_stack;
+ s->lang_base = current_lang_base;
+ s->lang_stacksize = current_lang_stacksize;
+ s->lang_name = current_lang_name;
+ s->named_labels = named_labels;
current_class_name = current_class_type = current_class_decl = NULL_TREE;
current_function_decl = NULL_TREE;
class_binding_level = (struct binding_level *)0;
previous_class_type = NULL_TREE;
+ current_lang_stacksize = 10;
+ current_lang_stack = current_lang_base
+ = (tree *) xmalloc (current_lang_stacksize * sizeof (tree));
+ current_lang_name = lang_name_cplusplus;
+ strict_prototype = strict_prototypes_lang_cplusplus;
+ named_labels = NULL_TREE;
s->prev = current_saved_scope;
s->old_bindings = old_bindings;
void
pop_from_top_level ()
{
+ extern int current_lang_stacksize;
struct saved_scope *s = current_saved_scope;
tree t;
current_function_decl = s->function_decl;
class_binding_level = s->class_bindings;
previous_class_type = s->previous_class_type;
+ free (current_lang_base);
+ current_lang_base = s->lang_base;
+ current_lang_stack = s->lang_stack;
+ current_lang_name = s->lang_name;
+ current_lang_stacksize = s->lang_stacksize;
+ if (current_lang_name == lang_name_cplusplus)
+ strict_prototype = strict_prototypes_lang_cplusplus;
+ else if (current_lang_name == lang_name_c)
+ strict_prototype = strict_prototypes_lang_c;
+ named_labels = s->named_labels;
+
free (s);
}
\f
incorrect results with `-g' unless they duplicate this code.
This is currently needed mainly for dbxout.c, but we can make
- use of it in cp-method.c later as well. */
+ use of it in method.c later as well. */
tree
make_type_decl (name, type)
tree name, type;
else
types_match = 0;
}
+ else if (TREE_CODE (newdecl) == TEMPLATE_DECL
+ && TREE_CODE (olddecl) == TEMPLATE_DECL)
+ {
+ tree newargs = DECL_TEMPLATE_PARMS (newdecl);
+ tree oldargs = DECL_TEMPLATE_PARMS (olddecl);
+ int i, len = TREE_VEC_LENGTH (newargs);
+
+ if (TREE_VEC_LENGTH (oldargs) != len)
+ return 0;
+
+ for (i = 0; i < len; i++)
+ {
+ tree newarg = TREE_VEC_ELT (newargs, i);
+ tree oldarg = TREE_VEC_ELT (oldargs, i);
+ if (TREE_CODE (newarg) != TREE_CODE (oldarg))
+ return 0;
+ else if (TREE_CODE (newarg) == IDENTIFIER_NODE)
+ /* continue */;
+ else if (! comptypes (TREE_TYPE (newarg), TREE_TYPE (oldarg), 1))
+ return 0;
+ }
+
+ if (DECL_TEMPLATE_IS_CLASS (newdecl)
+ != DECL_TEMPLATE_IS_CLASS (olddecl))
+ types_match = 0;
+ else if (DECL_TEMPLATE_IS_CLASS (newdecl))
+ types_match = 1;
+ else
+ types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl),
+ DECL_TEMPLATE_RESULT (newdecl));
+ }
else
{
if (TREE_TYPE (newdecl) == error_mark_node)
If safely possible, alter OLDDECL to look like NEWDECL, and return 1.
Otherwise, return 0. */
-static int
+int
duplicate_decls (newdecl, olddecl)
register tree newdecl, olddecl;
{
int new_defines_function;
tree previous_c_decl = NULL_TREE;
- if (TREE_CODE (newdecl) == FUNCTION_DECL
- && is_overloaded_fn (olddecl))
+ if (TREE_CODE (newdecl) == FUNCTION_DECL && is_overloaded_fn (olddecl))
{
olddecl = get_first_fn (olddecl);
cp_error ("declaration of C function `%#D' conflicts with", newdecl);
cp_error_at ("previous declaration `%#D' here", previous_c_decl);
}
+ else if (!types_match && TREE_CODE (newdecl) == TEMPLATE_DECL)
+ return 0;
else if (!types_match)
{
tree oldtype = TREE_TYPE (olddecl);
char *errmsg = redeclaration_error_message (newdecl, olddecl);
if (errmsg)
{
- error_with_decl (newdecl, errmsg);
+ cp_error (errmsg, newdecl);
if (DECL_NAME (olddecl) != NULL_TREE)
cp_error_at ((DECL_INITIAL (olddecl)
&& current_binding_level == global_binding_level)
DECL_CLASS_CONTEXT (newdecl) = DECL_CLASS_CONTEXT (olddecl);
if (DECL_CHAIN (newdecl) == NULL_TREE)
DECL_CHAIN (newdecl) = DECL_CHAIN (olddecl);
+ if (DECL_NEXT_METHOD (newdecl) == NULL_TREE)
+ DECL_NEXT_METHOD (newdecl) = DECL_NEXT_METHOD (olddecl);
if (DECL_PENDING_INLINE_INFO (newdecl) == (struct pending_inline *)0)
DECL_PENDING_INLINE_INFO (newdecl) = DECL_PENDING_INLINE_INFO (olddecl);
}
#endif
}
+ if (TREE_CODE (olddecl) == TEMPLATE_DECL
+ && DECL_TEMPLATE_INFO (olddecl)->length)
+ DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
+
/* Special handling ensues if new decl is a function definition. */
new_defines_function = (TREE_CODE (newdecl) == FUNCTION_DECL
&& DECL_INITIAL (newdecl) != NULL_TREE);
layout_type (TREE_TYPE (newdecl));
if (TREE_CODE (newdecl) != FUNCTION_DECL
&& TREE_CODE (newdecl) != TYPE_DECL
- && TREE_CODE (newdecl) != CONST_DECL)
+ && TREE_CODE (newdecl) != CONST_DECL
+ && TREE_CODE (newdecl) != TEMPLATE_DECL)
layout_decl (newdecl, 0);
}
else
cp_error_at ("`%#D' used prior to declaration", x);
}
- if (t != NULL_TREE)
+ else if (t != NULL_TREE)
{
if (TREE_CODE (t) == PARM_DECL)
{
}
file = DECL_SOURCE_FILE (t);
line = DECL_SOURCE_LINE (t);
- }
- if (t != NULL_TREE
- && (TREE_CODE (t) != TREE_CODE (x) || is_overloaded_fn (t)))
- {
- if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (x) == TYPE_DECL)
+ if (TREE_CODE (t) != TREE_CODE (x))
{
- /* We do nothing special here, because C++ does such nasty
- things with TYPE_DECLs. Instead, just let the TYPE_DECL
- get shadowed, and know that if we need to find a TYPE_DECL
- for a given name, we can look in the IDENTIFIER_TYPE_VALUE
- slot of the identifier. */
- ;
+ if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (x) == TYPE_DECL)
+ {
+ /* We do nothing special here, because C++ does such nasty
+ things with TYPE_DECLs. Instead, just let the TYPE_DECL
+ get shadowed, and know that if we need to find a TYPE_DECL
+ for a given name, we can look in the IDENTIFIER_TYPE_VALUE
+ slot of the identifier. */
+ ;
+ }
+ else if (duplicate_decls (x, t))
+ return t;
}
else if (duplicate_decls (x, t))
- return t;
- }
- else if (t != NULL_TREE && duplicate_decls (x, t))
- {
+ {
#if 0
/* This is turned off until I have time to do it right (bpk). */
}
#endif
- /* Due to interference in memory reclamation (X may be
- obstack-deallocated at this point), we must guard against
- one really special case. */
- if (current_function_decl == x)
- current_function_decl = t;
-
- return t;
+ /* Due to interference in memory reclamation (X may be
+ obstack-deallocated at this point), we must guard against
+ one really special case. */
+ if (current_function_decl == x)
+ current_function_decl = t;
+
+ return t;
+ }
}
+
/* If declaring a type as a typedef, and the type has no known
typedef name, install this TYPE_DECL as its typedef name. */
if (comptypes (newdecl, olddecl, 0))
return 0;
else
- return "redefinition of `%s'";
+ return "redefinition of `%#D'";
}
else if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
&& !(DECL_INLINE (newdecl) && DECL_EXTERNAL (newdecl))))
{
if (DECL_NAME (olddecl) == NULL_TREE)
- return "`%s' not declared in class";
+ return "`%#D' not declared in class";
else
- return "redefinition of `%s'";
+ return "redefinition of `%#D'";
}
return 0;
}
+ else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
+ {
+ if (DECL_INITIAL (olddecl) && DECL_INITIAL (newdecl))
+ return "redefinition of `%#D'";
+ return 0;
+ }
else if (current_binding_level == global_binding_level)
{
/* Objects declared at top level: */
/* Reject two definitions. */
if (DECL_INITIAL (olddecl) != NULL_TREE
&& DECL_INITIAL (newdecl) != NULL_TREE)
- return "redefinition of `%s'";
+ return "redefinition of `%#D'";
/* Now we have two tentative defs, or one tentative and one real def. */
/* Insist that the linkage match. */
if (TREE_PUBLIC (olddecl) != TREE_PUBLIC (newdecl))
- return "conflicting declarations of `%s'";
+ return "conflicting declarations of `%#D'";
return 0;
}
else
/* Reject two definitions, and reject a definition
together with an external reference. */
if (!(DECL_EXTERNAL (newdecl) && DECL_EXTERNAL (olddecl)))
- return "redeclaration of `%s'";
+ return "redeclaration of `%#D'";
return 0;
}
}
definitions if there are many, or return 0 if it is undefined.
If PREFER_TYPE is > 0, we prefer TYPE_DECLs.
- If PREFER_TYPE is = 0, we prefer non-TYPE_DECLs.
- If PREFER_TYPE is < 0, we arbitrate according to lexical context. */
+ Otherwise we prefer non-TYPE_DECLs. */
tree
lookup_name (name, prefer_type)
if (val == val_as_type || prefer_type > 0
|| looking_for_typename > 0)
return val_as_type;
- if (prefer_type == 0)
- return val;
- return arbitrate_lookup (name, val, val_as_type);
+
+ return val;
}
if (TREE_TYPE (val) == error_mark_node)
return error_mark_node;
my_friendly_abort (13);
}
else if (TREE_CODE (result) == FUNCTION_DECL)
- tem = push_overloaded_decl (tem, 0);
+ /*tem = push_overloaded_decl (tem, 0)*/;
else if (TREE_CODE (result) == VAR_DECL
|| TREE_CODE (result) == TYPE_DECL)
{
if (maxindex)
{
+ tree itype;
+
TYPE_DOMAIN (type) = build_index_type (maxindex);
if (!TREE_TYPE (maxindex))
TREE_TYPE (maxindex) = TYPE_DOMAIN (type);
+ if (initial_value)
+ itype = TREE_TYPE (initial_value);
+ else
+ itype = NULL;
+ if (itype && !TYPE_DOMAIN (itype))
+ TYPE_DOMAIN (itype) = TYPE_DOMAIN (type);
}
/* Lay out the type now that we can get the real answer. */
case IDENTIFIER_NODE:
dname = decl;
- name = IDENTIFIER_POINTER (decl);
decl = NULL_TREE;
+
+ if (IDENTIFIER_TYPENAME_P (dname))
+ {
+ my_friendly_assert (flags == NO_SPECIAL, 154);
+ flags = TYPENAME_FLAG;
+ ctor_return_type = TREE_TYPE (dname);
+ return_type = return_conversion;
+ }
+
+ if (IDENTIFIER_OPNAME_P (dname))
+ name = operator_name_string (dname);
+ else
+ name = IDENTIFIER_POINTER (dname);
break;
case RECORD_TYPE:
decl = NULL_TREE;
break;
- case TYPE_EXPR:
- my_friendly_assert (flags == NO_SPECIAL, 154);
- flags = TYPENAME_FLAG;
- name = "operator <typename>"; /* We don't know the type yet. */
- /* Go to the absdcl. */
- decl = TREE_OPERAND (decl, 0);
- return_type = return_conversion;
- break;
-
/* C++ extension */
case SCOPE_REF:
/*
type = void_type_node;
else if (return_type == return_ctor)
type = TYPE_POINTER_TO (ctor_return_type);
+ else if (return_type == return_conversion)
+ type = ctor_return_type;
else if (current_class_type
&& IS_SIGNATURE (current_class_type)
&& (RIDBIT_SETP (RID_TYPEDEF, specbits)
error ("return type specification for constructor invalid");
type = TYPE_POINTER_TO (ctor_return_type);
}
+ else if (return_type == return_conversion)
+ {
+ if (comp_target_types (type, ctor_return_type, 1) == 0)
+ cp_error ("operator `%T' declared to return `%T'",
+ ctor_return_type, type);
+ else
+ cp_pedwarn ("return type specified for `operator %T'",
+ ctor_return_type);
+
+ type = ctor_return_type;
+ }
ctype = NULL_TREE;
error ("typedef declaration includes an initializer");
/* To process a class-local typedef declaration, we descend down
- the chain of declspecs looking for the `typedef' spec. When we
- find it, we splice it out of the chain of declspecs, and then
- recursively call `grokdeclarator' with the original declarator
- and with the newly adjusted declspecs. This call should return
- a FIELD_DECL node with the TREE_TYPE (and other parts) set
+ the chain of declspecs looking for the `typedef' spec. When
+ we find it, we replace it with `static', and then recursively
+ call `grokdeclarator' with the original declarator and with
+ the newly adjusted declspecs. This call should return a
+ FIELD_DECL node with the TREE_TYPE (and other parts) set
appropriately. We can then just change the TREE_CODE on that
from FIELD_DECL to TYPE_DECL and we're done. */
if (TREE_VALUE (scanner) == ridpointers[(int) RID_TYPEDEF])
break;
}
- if (previous_declspec)
- TREE_CHAIN (previous_declspec) = TREE_CHAIN (scanner);
+
+ if (scanner == IDENTIFIER_AS_LIST (ridpointers [(int) RID_TYPEDEF]))
+ {
+ if (previous_declspec)
+ TREE_CHAIN (previous_declspec)
+ = IDENTIFIER_AS_LIST (ridpointers [(int) RID_STATIC]);
+ else
+ declspecs
+ = IDENTIFIER_AS_LIST (ridpointers [(int) RID_STATIC]);
+ }
else
- declspecs = TREE_CHAIN (scanner);
-
+ TREE_VALUE (scanner) = ridpointers[(int) RID_STATIC];
+
/* In the recursive call to grokdeclarator we need to know
whether we are working on a signature-local typedef. */
if (IS_SIGNATURE (current_class_type))
qualify the member name.
an ADDR_EXPR (for &...),
a BIT_NOT_EXPR (for destructors)
- a TYPE_EXPR (for operator typenames)
At this point, TYPE is the type of elements of an array,
or for a function to return, or for a pointer to point to.
&& (friendp == 0 || dname == current_class_name))
ctype = current_class_type;
- if (ctype && flags == TYPENAME_FLAG)
+ if (ctype && return_type == return_conversion)
TYPE_HAS_CONVERSION (ctype) = 1;
if (ctype && constructor_name (ctype) == dname)
{
return void_type_node;
}
{
- int inlinep, staticp;
- inlinep = RIDBIT_SETP (RID_INLINE, specbits);
- staticp = RIDBIT_SETP (RID_STATIC, specbits);
- RIDBIT_RESET (RID_INLINE, specbits);
- RIDBIT_RESET (RID_STATIC, specbits);
- if (RIDBIT_ANY_SET (specbits))
+ RID_BIT_TYPE tmp_bits;
+ bcopy ((void*)&specbits, (void*)&tmp_bits, sizeof(RID_BIT_TYPE));
+ RIDBIT_RESET (RID_INLINE, tmp_bits);
+ RIDBIT_RESET (RID_STATIC, tmp_bits);
+ if (RIDBIT_ANY_SET (tmp_bits))
error ("return value type specifier for constructor ignored");
- if (inlinep)
- RIDBIT_SET (RID_INLINE, specbits);
- if (staticp)
- RIDBIT_SET (RID_STATIC, specbits);
}
type = TYPE_POINTER_TO (ctype);
if (decl_context == FIELD &&
/* Say it's a definition only for the CALL_EXPR
closest to the identifier. */
funcdef_p =
- (inner_decl &&
- (TREE_CODE (inner_decl) == IDENTIFIER_NODE
- || TREE_CODE (inner_decl) == TYPE_EXPR)) ? funcdef_flag : 0;
+ (inner_decl && TREE_CODE (inner_decl) == IDENTIFIER_NODE)
+ ? funcdef_flag : 0;
/* FIXME: This is where default args should be fully
processed. */
return t;
}
- if (flags == TYPENAME_FLAG)
- cp_error ("type conversion is not a member of structure `%T'", ctype);
- else
- cp_error
- ("field `%D' is not a member of structure `%T'",
- sname, ctype);
+ cp_error
+ ("field `%D' is not a member of structure `%T'",
+ sname, ctype);
}
if (current_class_type)
declarator = sname;
}
- else if (TREE_CODE (sname) == TYPE_EXPR)
- {
- /* A TYPE_EXPR will change types out from under us.
- So do the TYPE_EXPR now, and make this SCOPE_REF
- inner to the TYPE_EXPR's CALL_EXPR.
-
- This does not work if we don't get a CALL_EXPR back.
- I did not think about error recovery, hence the
- my_friendly_abort. */
-
- /* Get the CALL_EXPR. */
- sname = grokoptypename (sname, 0);
- my_friendly_assert (TREE_CODE (sname) == CALL_EXPR, 157);
- type = TREE_TYPE (TREE_OPERAND (sname, 0));
- /* Scope the CALL_EXPR's name. */
- TREE_OPERAND (declarator, 1) = TREE_OPERAND (sname, 0);
- /* Put the SCOPE_EXPR in the CALL_EXPR's innermost position. */
- TREE_OPERAND (sname, 0) = declarator;
- /* Now work from the CALL_EXPR. */
- declarator = sname;
- continue;
- }
else if (TREE_CODE (sname) == SCOPE_REF)
my_friendly_abort (17);
else
declarator = TREE_OPERAND (declarator, 0);
break;
- case TYPE_EXPR:
- declarator = grokoptypename (declarator, 0);
- if (explicit_int != -1)
- {
- tree stype = TREE_TYPE (TREE_OPERAND (declarator, 0));
- if (comp_target_types (type, stype, 1) == 0)
- cp_error ("`operator %T' declared to return `%T'", stype,
- type);
- else
- cp_pedwarn ("return type specified for `operator %T'", type);
- }
- dname = declarator;
- type = TREE_TYPE (TREE_OPERAND (declarator, 0));
- break;
-
case RECORD_TYPE:
case UNION_TYPE:
case ENUMERAL_TYPE:
&& ! funcdef_flag
&& RIDBIT_NOTSETP (RID_STATIC, specbits)
&& RIDBIT_NOTSETP (RID_INLINE, specbits)));
+ if (TREE_CODE (type) == METHOD_TYPE)
+ publicp
+ |= (ctype && CLASSTYPE_INTERFACE_KNOWN (ctype))
+ || (!funcdef_flag && RIDBIT_NOTSETP (RID_INLINE, specbits));
decl = grokfndecl (ctype, type, declarator,
virtualp, flags, quals,
raises, friendp ? -1 : 0, publicp);
into some other file, so we don't clear TREE_PUBLIC for them. */
publicp
= ((ctype
- && CLASSTYPE_INTERFACE_KNOWN (ctype)
- && ! CLASSTYPE_INTERFACE_ONLY (ctype))
+ && CLASSTYPE_INTERFACE_KNOWN (ctype))
|| !(RIDBIT_SETP (RID_STATIC, specbits)
|| RIDBIT_SETP (RID_INLINE, specbits)));
if (value)
STRIP_TYPE_NOPS (value);
- /* Make up for hacks in cp-lex.c. */
+ /* Make up for hacks in lex.c. */
if (value == integer_zero_node)
value = build_int_2 (0, 0);
else if (value == integer_one_node)
else if (pre_parsed_p == 0)
{
current_function_decl = pushdecl (decl1);
- if (TREE_CODE (current_function_decl) == TREE_LIST)
+ if (TREE_CODE (current_function_decl) == TREE_LIST
+ || (DECL_ASSEMBLER_NAME (current_function_decl)
+ != DECL_ASSEMBLER_NAME (decl1)))
{
/* @@ revert to modified original declaration. */
decl1 = DECL_MAIN_VARIANT (decl1);
can have the same name. */
static int global_temp_name_counter;
-/* Flag used when debugging cp-spew.c */
+/* Flag used when debugging spew.c */
extern int spew_debug;
\f
int warn_ctor_dtor_privacy = 1;
+/* True if we want output of vtables to be controlled by whether
+ we seen the class's first non-inline virtual function. */
+int flag_vtable_hack = 0;
+
/* Nonzero means give string constants the type `const char *'
to get extra warnings from them. These warnings will be too numerous
to be useful, except in thoroughly ANSIfied programs. */
{"ansi-overloading", &flag_ansi_overloading, 1},
{"huge-objects", &flag_huge_objects, 1},
{"conserve-space", &flag_conserve_space, 1},
+ {"vtable-hack", &flag_vtable_hack, 1},
};
/* Decode the string P as a language-specific option.
return decl;
}
-/* The precedence rules of this grammar (or any other deterministic LALR
- grammar, for that matter), place the CALL_EXPR somewhere where we
- may not want it. The solution is to grab the first CALL_EXPR we see,
- pretend that that is the one that belongs to the parameter list of
- the type conversion function, and leave everything else alone.
- We pull it out in place.
-
- CALL_REQUIRED is non-zero if we should complain if a CALL_EXPR
- does not appear in DECL. */
tree
-grokoptypename (decl, call_required)
- tree decl;
- int call_required;
+grokoptypename (declspecs, declarator)
+ tree declspecs, declarator;
{
- tree tmp, last;
-
- my_friendly_assert (TREE_CODE (decl) == TYPE_EXPR, 195);
-
- tmp = TREE_OPERAND (decl, 0);
- last = NULL_TREE;
-
- while (tmp)
- {
- switch (TREE_CODE (tmp))
- {
- case CALL_EXPR:
- {
- tree parms = TREE_OPERAND (tmp, 1);
-
- if (last)
- TREE_OPERAND (last, 0) = TREE_OPERAND (tmp, 0);
- else
- TREE_OPERAND (decl, 0) = TREE_OPERAND (tmp, 0);
-
- last = grokdeclarator (TREE_OPERAND (decl, 0),
- TREE_TYPE (decl),
- TYPENAME, 0, NULL_TREE);
- TREE_OPERAND (tmp, 0) = build_typename_overload (last);
- TREE_TYPE (TREE_OPERAND (tmp, 0)) = last;
-
- if (parms
- && TREE_CODE (TREE_VALUE (parms)) == TREE_LIST)
- TREE_VALUE (parms)
- = grokdeclarator (TREE_VALUE (TREE_VALUE (parms)),
- TREE_PURPOSE (TREE_VALUE (parms)),
- TYPENAME, 0, NULL_TREE);
- if (parms)
- {
- if (TREE_VALUE (parms) != void_type_node)
- cp_error ("`operator %T' requires empty parameter list",
- last);
- else
- /* Canonicalize parameter lists. */
- TREE_OPERAND (tmp, 1) = void_list_node;
- }
-
- return tmp;
- }
-
- case INDIRECT_REF:
- case ADDR_EXPR:
- case ARRAY_REF:
- break;
-
- case SCOPE_REF:
- /* This is legal when declaring a conversion to
- something of type pointer-to-member. */
- if (TREE_CODE (TREE_OPERAND (tmp, 1)) == INDIRECT_REF)
- {
- tmp = TREE_OPERAND (tmp, 1);
- }
- else
- {
-#if 0
- /* We may need to do this if grokdeclarator cannot handle this. */
- error ("type `member of class %s' invalid return type",
- TYPE_NAME_STRING (TREE_OPERAND (tmp, 0)));
- TREE_OPERAND (tmp, 1) = build_parse_node (INDIRECT_REF, TREE_OPERAND (tmp, 1));
-#endif
- tmp = TREE_OPERAND (tmp, 1);
- }
- break;
-
- default:
- my_friendly_abort (196);
- }
- last = tmp;
- tmp = TREE_OPERAND (tmp, 0);
- }
-
- last = grokdeclarator (TREE_OPERAND (decl, 0),
- TREE_TYPE (decl),
- TYPENAME, 0, NULL_TREE);
-
- if (call_required)
- cp_error ("`operator %T' construct requires parameter list", last);
-
- tmp = build_parse_node (CALL_EXPR, build_typename_overload (last),
- void_list_node, NULL_TREE);
- TREE_TYPE (TREE_OPERAND (tmp, 0)) = last;
- return tmp;
+ tree t = grokdeclarator (declarator, declspecs, TYPENAME, 0, NULL_TREE);
+ return build_typename_overload (t);
}
/* When a function is declared with an initializer,
finish_vtable_vardecl (prev, vars)
tree prev, vars;
{
+ tree ctype = DECL_CONTEXT (vars);
+ if (flag_vtable_hack && !CLASSTYPE_INTERFACE_KNOWN (ctype))
+ {
+ tree method;
+ for (method = CLASSTYPE_METHODS (ctype); method != NULL_TREE;
+ method = DECL_NEXT_METHOD (method))
+ {
+ if (DECL_VINDEX (method) != NULL_TREE && !DECL_SAVED_INSNS (method))
+ {
+ TREE_PUBLIC (vars) = 1;
+ DECL_EXTERNAL (vars) = DECL_EXTERNAL (method);
+ break;
+ }
+ }
+ }
+
if (write_virtuals >= 0
&& ! DECL_EXTERNAL (vars) && (TREE_PUBLIC (vars) || TREE_USED (vars)))
{
rest_of_decl_compilation (vars, 0, 1, 1);
}
+ else if (TREE_USED (vars) && flag_vtable_hack)
+ assemble_external (vars);
/* We know that PREV must be non-zero here. */
TREE_CHAIN (prev) = TREE_CHAIN (vars);
}
There are several ways of getting the same effect, from changing the
way that iterators over the chain treat the elements that pertain to
virtual function tables, moving the implementation of this code to
- cp-decl.c (where we can manipulate global_binding_level directly),
+ decl.c (where we can manipulate global_binding_level directly),
popping the garbage after pushing it and slicing away the vtable
stuff, or just leaving it alone. */
if (flag_detailed_statistics)
dump_time_statistics ();
}
+
+/* This is something of the form 'A()()()()()+1' that has turned out to be an
+ expr. Since it was parsed like a type, we need to wade through and fix
+ that. Unfortunately, since operator() is left-associative, we can't use
+ tail recursion. In the above example, TYPE is `A', and DECL is
+ `()()()()()'.
+
+ Maybe this shouldn't be recursive, but how often will it actually be
+ used? (jason) */
+tree
+reparse_absdcl_as_expr (type, decl)
+ tree type, decl;
+{
+ /* do build_functional_cast (type, NULL_TREE) at bottom */
+ if (TREE_OPERAND (decl, 0) == NULL_TREE)
+ return build_functional_cast (type, NULL_TREE);
+
+ /* recurse */
+ decl = reparse_decl_as_expr (type, TREE_OPERAND (decl, 0));
+
+ decl = build_x_function_call (decl, NULL_TREE, current_class_decl);
+
+ if (TREE_CODE (decl) == CALL_EXPR && TREE_TYPE (decl) != void_type_node)
+ decl = require_complete_type (decl);
+
+ return decl;
+}
+
+/* This is something of the form `int ((int)(int)(int)1)' that has turned
+ out to be an expr. Since it was parsed like a type, we need to wade
+ through and fix that. Since casts are right-associative, we are
+ reversing the order, so we don't have to recurse.
+
+ In the above example, DECL is the `(int)(int)(int)', and EXPR is the
+ `1'. */
+tree
+reparse_absdcl_as_casts (decl, expr)
+ tree decl, expr;
+{
+ tree type;
+
+ if (TREE_CODE (expr) == CONSTRUCTOR)
+ {
+ type = groktypename (TREE_VALUE (TREE_OPERAND (decl, 1)));
+ decl = TREE_OPERAND (decl, 0);
+
+ if (IS_SIGNATURE (type))
+ {
+ error ("cast specifies signature type");
+ return error_mark_node;
+ }
+
+ expr = digest_init (type, expr, (tree *) 0);
+ if (TREE_CODE (type) == ARRAY_TYPE && TYPE_SIZE (type) == 0)
+ {
+ int failure = complete_array_type (type, expr, 1);
+ if (failure)
+ my_friendly_abort (78);
+ }
+ }
+
+ while (decl)
+ {
+ type = groktypename (TREE_VALUE (TREE_OPERAND (decl, 1)));
+ decl = TREE_OPERAND (decl, 0);
+ expr = build_c_cast (type, expr);
+ }
+
+ return expr;
+}
+
+/* Recursive helper function for reparse_decl_as_expr. It may be a good
+ idea to reimplement this using an explicit stack, rather than recursion. */
+static tree
+reparse_decl_as_expr1 (decl)
+ tree decl;
+{
+ switch (TREE_CODE (decl))
+ {
+ case IDENTIFIER_NODE:
+ return do_identifier (decl);
+ case INDIRECT_REF:
+ return build_x_indirect_ref
+ (reparse_decl_as_expr1 (TREE_OPERAND (decl, 0)), "unary *");
+ case ADDR_EXPR:
+ return build_x_unary_op (ADDR_EXPR,
+ reparse_decl_as_expr1 (TREE_OPERAND (decl, 0)));
+ case BIT_NOT_EXPR:
+ return build_x_unary_op (BIT_NOT_EXPR,
+ reparse_decl_as_expr1 (TREE_OPERAND (decl, 0)));
+ }
+ my_friendly_abort (5);
+}
+
+/* This is something of the form `int (*a)++' that has turned out to be an
+ expr. It was only converted into parse nodes, so we need to go through
+ and build up the semantics. Most of the work is done by
+ reparse_decl_as_expr1, above.
+
+ In the above example, TYPE is `int' and DECL is `*a'. */
+tree
+reparse_decl_as_expr (type, decl)
+ tree type, decl;
+{
+ decl = build_tree_list (NULL_TREE, reparse_decl_as_expr1 (decl));
+ return build_functional_cast (type, decl);
+}
+
+/* This is something of the form `int (*a)' that has turned out to be a
+ decl. It was only converted into parse nodes, so we need to do the
+ checking that make_{pointer,reference}_declarator do. */
+
+tree
+finish_decl_parsing (decl)
+ tree decl;
+{
+ switch (TREE_CODE (decl))
+ {
+ case IDENTIFIER_NODE:
+ return decl;
+ case INDIRECT_REF:
+ return make_pointer_declarator
+ (NULL_TREE, finish_decl_parsing (TREE_OPERAND (decl, 0)));
+ case ADDR_EXPR:
+ return make_reference_declarator
+ (NULL_TREE, finish_decl_parsing (TREE_OPERAND (decl, 0)));
+ case BIT_NOT_EXPR:
+ TREE_OPERAND (decl, 0) = finish_decl_parsing (TREE_OPERAND (decl, 0));
+ return decl;
+ }
+}
/* cp_printer is the type of a function which converts an argument into
a string for digestion by printf. The cp_printer function should deal
with all memory management; the functions in this file will not free
- the char*s returned. See cp-error.c for an example use of this code. */
+ the char*s returned. See error.c for an example use of this code. */
typedef char* cp_printer PROTO((HOST_WIDE_INT, int));
extern cp_printer * cp_printers[256];
# define OB_FINISH() (obstack_1grow (&scratch_obstack, '\0'))
# define OB_PUTI(CST) do { sprintf (digit_buffer, "%d", (CST)); \
OB_PUTCP (digit_buffer); } while (0)
+# define OB_UNPUT(N) obstack_blank (&scratch_obstack, - (N));
# define NEXT_CODE(t) (TREE_CODE (TREE_TYPE (t)))
switch (TREE_CODE (t))
{
case ERROR_MARK:
- OB_PUTS ("<error>");
+ OB_PUTS ("{error}");
break;
case UNKNOWN_TYPE:
- OB_PUTS ("<unknown type>");
+ OB_PUTS ("{unknown type}");
break;
case TREE_LIST:
break;
case TEMPLATE_TYPE_PARM:
- OB_PUTS ("<template type parm ");
OB_PUTID (TYPE_IDENTIFIER (t));
- OB_PUTC ('>');
break;
case UNINSTANTIATED_P_TYPE:
break;
default:
- my_friendly_abort (68);
-
+ sorry ("`%s' not supported by dump_type",
+ tree_code_name[(int) TREE_CODE (t)]);
}
}
-/* Print out a class declaration, in the form `class foo'. */
-static void
-dump_aggr_type (t, v)
+static char *
+aggr_variety (t)
tree t;
- int v; /* verbose? */
{
- tree name;
- char *variety;
-
if (TREE_CODE (t) == ENUMERAL_TYPE)
- variety = "enum";
+ return "enum";
else if (TREE_CODE (t) == UNION_TYPE)
- variety = "union";
+ return "union";
else if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t))
- variety = "class";
+ return "class";
else if (TYPE_LANG_SPECIFIC (t) && IS_SIGNATURE (t))
- variety = "signature";
+ return "signature";
else
- variety = "struct";
+ return "struct";
+}
+
+/* Print out a class declaration, in the form `class foo'. */
+static void
+dump_aggr_type (t, v)
+ tree t;
+ int v; /* verbose? */
+{
+ tree name;
+ char *variety = aggr_variety (t);
dump_readonly_or_volatile (t, after);
if (ANON_AGGRNAME_P (name))
{
- OB_PUTS ("<anonymous");
+ OB_PUTS ("{anonymous");
if (!v)
{
OB_PUTC (' ');
OB_PUTCP (variety);
}
- OB_PUTC ('>');
+ OB_PUTC ('}');
}
else
OB_PUTID (name);
case OFFSET_TYPE:
offset_type:
dump_type_prefix (TREE_TYPE (t), v);
- if (NEXT_CODE (t) != FUNCTION_TYPE && NEXT_CODE (t) != METHOD_TYPE)
- OB_PUTC (' ');
- if (TREE_CODE (t) == OFFSET_TYPE)
- dump_type (TYPE_OFFSET_BASETYPE (t), 0);
- else /* pointer to member function */
- dump_type (TYPE_METHOD_BASETYPE (TREE_TYPE (t)), 0);
- OB_PUTC2 (':', ':');
+ if (TREE_CODE (t) == OFFSET_TYPE) /* pmfs deal with this in d_t_p */
+ {
+ OB_PUTC (' ');
+ dump_type (TYPE_OFFSET_BASETYPE (t), 0);
+ OB_PUTC2 (':', ':');
+ }
OB_PUTC ('*');
dump_readonly_or_volatile (t, none);
break;
break;
default:
- my_friendly_abort (65);
+ sorry ("`%s' not supported by dump_type_prefix",
+ tree_code_name[(int) TREE_CODE (t)]);
}
}
break;
default:
- my_friendly_abort (67);
+ sorry ("`%s' not supported by dump_type_suffix",
+ tree_code_name[(int) TREE_CODE (t)]);
}
}
if (DECL_NAME (t))
dump_decl (DECL_NAME (t), v);
else
- OB_PUTS ("<anon>");
+ OB_PUTS ("{anon}");
if (v > 0) dump_type_suffix (TREE_TYPE (t), v);
break;
break;
case TEMPLATE_DECL:
- switch (NEXT_CODE (t))
- {
- case METHOD_TYPE:
- case FUNCTION_TYPE:
- dump_function_decl (t, v);
- break;
+ {
+ tree args = DECL_TEMPLATE_PARMS (t);
+ int i, len = TREE_VEC_LENGTH (args);
+ OB_PUTS ("template <");
+ for (i = 0; i < len; i++)
+ {
+ tree arg = TREE_VEC_ELT (args, i);
+ if (TREE_CODE (arg) == IDENTIFIER_NODE)
+ {
+ OB_PUTS ("class ");
+ OB_PUTID (arg);
+ }
+ else
+ dump_decl (arg, 1);
+ OB_PUTC2 (',', ' ');
+ }
+ OB_UNPUT (2);
+ OB_PUTC2 ('>', ' ');
- default:
- my_friendly_abort (353);
- }
+ if (DECL_TEMPLATE_IS_CLASS (t))
+ {
+ OB_PUTS ("class ");
+ OB_PUTID (DECL_NAME (t));
+ }
+ else switch (NEXT_CODE (t))
+ {
+ case METHOD_TYPE:
+ case FUNCTION_TYPE:
+ dump_function_decl (t, v);
+ break;
+
+ default:
+ my_friendly_abort (353);
+ }
+ }
break;
case LABEL_DECL:
break;
default:
- my_friendly_abort (70);
+ sorry ("`%s' not supported by dump_decl",
+ tree_code_name[(int) TREE_CODE (t)]);
}
}
OB_PUTC ('}');
break;
+ case OFFSET_REF:
+ {
+ tree ob = TREE_OPERAND (t, 0);
+ if (TREE_CODE (ob) == NOP_EXPR
+ && TREE_OPERAND (ob, 0) == error_mark_node
+ && TREE_CODE (TREE_OPERAND (t, 1)) == FUNCTION_DECL)
+ /* A::f */
+ dump_expr (TREE_OPERAND (t, 1), 0);
+ else
+ {
+ sorry ("operand of OFFSET_REF not understood");
+ goto error;
+ }
+ break;
+ }
+
/* This list is incomplete, but should suffice for now.
It is very important that `sorry' does not call
`report_error_function'. That could cause an infinite loop. */
/* fall through to ERROR_MARK... */
case ERROR_MARK:
error:
- OB_PUTCP ("/* error */");
+ OB_PUTCP ("{error}");
break;
}
}
static char buf[] = "operator ";
if (p == 0)
- return "<unknown>";
+ return "{unknown}";
strcpy (buf + 9, opname_tab [p]);
return buf;
finish_exception_decl (cname, decl)
tree cname, decl;
{
- /* In cp-decl.h. */
+ /* In decl.h. */
extern tree last_function_parms;
/* An exception declaration. */
* Templates::
* Access Control::
* Error Reporting::
+* Parser::
+* Copying Objects::
* Concept Index::
@end menu
@example
extern "C" int printf(const char*, ...);
-struct A { virtual void f() { } };
-struct B : virtual A { int b; B() : b(0) {} void f() { b++; } };
-struct C : B {};
-struct D : B {};
-struct E : C, D {};
+struct A @{ virtual void f() @{ @} @};
+struct B : virtual A @{ int b; B() : b(0) @{@} void f() @{ b++; @} @};
+struct C : B @{@};
+struct D : B @{@};
+struct E : C, D @{@};
int main()
-{
+@{
E e;
C& c = e; D& d = e;
c.f(); d.f();
printf ("C::b = %d, D::b = %d\n", e.C::b, e.D::b);
return 0;
-}
+@}
@end example
This will print out 2, 0, instead of 1,1.
granted by the containing class. BEWARE: TREE_PUBLIC means something
completely unrelated to access control!
-@node Error Reporting, Concept Index, Access Control, Top
+@node Error Reporting, Parser, Access Control, Top
@section Error Reporting
The C++ frontend uses a call-back mechanism to allow functions to print
DECL, use @code{cp_error_at} and its ilk; to indicate which argument you want,
use @code{%+D}, or it will default to the first.
-@node Concept Index, , Error Reporting, Top
+@node Parser, Copying Objects, Error Reporting, Top
+@section Parser
+
+Some comments on the parser:
+
+The @code{after_type_declarator} / @code{notype_declarator} hack is
+necessary in order to allow redeclarations of @code{TYPENAME}s, for
+instance
+
+@example
+typedef int foo;
+class A @{
+ char *foo;
+@};
+@end example
+
+In the above, the first @code{foo} is parsed as a @code{notype_declarator},
+and the second as a @code{after_type_declarator}.
+
+Ambiguities:
+
+There are currently four reduce/reduce ambiguities in the parser. They are:
+
+1) Between @code{template_parm} and
+@code{named_class_head_sans_basetype}, for the tokens @code{aggr
+identifier}. This situation occurs in code looking like
+
+@example
+template <class T> class A @{ @};
+@end example
+
+It is ambiguous whether @code{class T} should be parsed as the
+declaration of a template type parameter named @code{T} or an unnamed
+constant parameter of type @code{class T}. Section 14.6, paragraph 3 of
+the January '94 working paper states that the first interpretation is
+the correct one. This ambiguity results in four reduce/reduce conflicts.
+
+2) Between @code{primary} and @code{typename} for code like @samp{int()}
+in places where both can be accepted, such as the argument to
+@code{sizeof}. Section 8.1 of the pre-San Diego working paper specifies
+that these ambiguous constructs will be interpreted as @code{typename}s.
+This ambiguity results in six reduce/reduce conflicts.
+
+3) Between @code{primary}/@code{functional_cast} and
+@code{expr_or_declarator}/@code{complex_direct_notype_declarator}, for
+various token strings. This situation occurs in code looking like
+
+@example
+int (*a);
+@end example
+
+This code is ambiguous; it could be a declaration of the variable
+@samp{a} as a pointer to @samp{int}, or it could be a functional cast of
+@samp{*a} to @samp{int}. Section 6.8 specifies that the former
+interpretation is correct. This ambiguity results in 12 reduce/reduce
+conflicts. Ack.
+
+4) Between @code{after_type_declarator} and @code{parm}, for the token
+@code{TYPENAME}. This occurs in (as one example) code like
+
+@example
+typedef int foo, bar;
+class A @{
+ foo (bar);
+@};
+@end example
+
+What is @code{bar} inside the class definition? We currently interpret
+it as a @code{parm}, as does Cfront, but IBM xlC interprets it as an
+@code{after_type_declarator}. I suspect that xlC is correct, in light
+of 7.1p2, which says "The longest sequence of @i{decl-specifiers} that
+could possibly be a type name is taken as the @i{decl-specifier-seq} of
+a @i{declaration}." However, it seems clear that this rule must be
+violated in the case of constructors, so...
+
+Unlike the others, this ambiguity is not recognized by the Working Paper.
+
+@node Copying Objects, Concept Index, Parser, Top
+@section Copying Objects
+
+The generated copy assignment operator in g++ does not currently do the
+right thing for multiple inheritance involving virtual bases; it just
+calls the copy assignment operators for its direct bases. What it
+should probably do is:
+
+1) Split up the copy assignment operator for all classes that have
+vbases into "copy my vbases" and "copy everything else" parts. Or do
+the trickiness that the constructors do to ensure that vbases don't get
+initialized by intermediate bases.
+
+2) Wander through the class lattice, find all vbases for which no
+intermediate base has a user-defined copy assignment operator, and call
+their "copy everything else" routines. If not all of my vbases satisfy
+this criterion, warn, because this may be surprising behavior.
+
+3) Call the "copy everything else" routine for my direct bases.
+
+If we only have one direct base, we can just foist everything off onto
+them.
+
+This issue is currently under discussion in the core reflector
+(2/28/94).
+
+@node Concept Index, , Copying Objects, Top
@section Concept Index
@printindex cp
}
\f
-/* This code could just as well go in `cp-class.c', but is placed here for
+/* This code could just as well go in `class.c', but is placed here for
modularity. */
/* For an expression of the form CNAME :: NAME (PARMLIST), build
@@ Prints out lousy diagnostics for operator <typename>
@@ fields.
- @@ This function should be rewritten and placed in cp-search.c. */
+ @@ This function should be rewritten and placed in search.c. */
tree
build_offset_ref (cname, name)
tree cname, name;
name);
return error_mark_node;
}
- if (TREE_CODE (t) == TYPE_DECL)
- {
- cp_error ("member `%D' is just a type declaration", t);
- return error_mark_node;
- }
- if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == CONST_DECL)
+ if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (t) == VAR_DECL
+ || TREE_CODE (t) == CONST_DECL)
{
TREE_USED (t) = 1;
return t;
if (TREE_CODE (t) == TYPE_DECL)
{
- cp_error ("member `%D' is just a type declaration", t);
- return error_mark_node;
+ TREE_USED (t) = 1;
+ return t;
}
/* static class members and class-specific enum
values can be returned without further ado. */
/* probably meant to be a vec new */
tree this_nelts;
+ while (TREE_OPERAND (absdcl, 0)
+ && TREE_CODE (TREE_OPERAND (absdcl, 0)) == ARRAY_REF)
+ {
+ last_absdcl = absdcl;
+ absdcl = TREE_OPERAND (absdcl, 0);
+ }
+
has_array = 1;
this_nelts = TREE_OPERAND (absdcl, 1);
if (this_nelts != error_mark_node)
}
}
done:
+ if (rval && TREE_TYPE (rval) != build_pointer_type (type))
+ {
+ /* The type of new int [3][3] is not int *, but int [3] * */
+ rval = build_c_cast (build_pointer_type (type), rval);
+ }
+
if (pending_sizes)
rval = build_compound_expr (chainon (pending_sizes,
build_tree_list (NULL_TREE, rval)));
the GNU library available, so FILE objects just don't cut it.
This file is written as a separate module, but can be included by
- cp-lex.c for very minor efficiency gains (primarily in function
+ lex.c for very minor efficiency gains (primarily in function
inlining). */
#include <stdio.h>
static int putback_char = -1;
/* Some of these external functions are declared inline in case this file
- is included in cp-lex.c. */
+ is included in lex.c. */
inline
void
\f
/* Table indexed by tree code giving a string containing a character
classifying the tree code. Possibilities are
- t, d, s, c, r, <, 1 and 2. See cp-tree.def for details. */
+ t, d, s, c, r, <, 1 and 2. See cp/tree.def for details. */
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
interface_unknown = TREE_INT_CST_HIGH (fileinfo);
}
-/* Return nonzero if S and T are not considered part of an
+/* Return nonzero if S is not considered part of an
INTERFACE/IMPLEMENTATION pair. Otherwise, return 0. */
static int
interface_strcmp (s)
struct impl_files *ifiles;
char *s1;
- s = FILE_NAME_NONDIRECTORY (s);
-
for (ifiles = impl_file_chain; ifiles; ifiles = ifiles->next)
{
char *t1 = ifiles->filename;
tree type = TREE_TYPE (vars);
CLASSTYPE_INTERFACE_ONLY (type) = TREE_INT_CST_LOW (fileinfo)
- = interface_strcmp (DECL_SOURCE_FILE (vars));
+ = interface_strcmp (FILE_NAME_NONDIRECTORY (DECL_SOURCE_FILE (vars)));
}
void
\f
/* Called from the top level: if there are any pending inlines to
do, set up to process them now. This function sets up the first function
- to be parsed; after it has been, the rule for fndef in cp-parse.y will
+ to be parsed; after it has been, the rule for fndef in parse.y will
call process_next_inline to start working on the next one. */
void
do_pending_inlines ()
&& getch () == 'e'
&& ((c = getch ()) == ' ' || c == '\t' || c == '\n'))
{
- int warned_interface = 0;
+ int warned_already = 0;
+ char *main_filename = input_filename;
- /* Read to newline. */
+ main_filename = FILE_NAME_NONDIRECTORY (main_filename);
+ while (c == ' ' || c == '\t')
+ c = getch ();
+ if (c != '\n')
+ {
+ put_back (c);
+ token = real_yylex ();
+ if (token != STRING
+ || TREE_CODE (yylval.ttype) != STRING_CST)
+ {
+ error ("invalid `#pragma interface'");
+ goto skipline;
+ }
+ main_filename = TREE_STRING_POINTER (yylval.ttype);
+ c = getch();
+ put_back (c);
+ }
+
+ while (c == ' ' || c == '\t')
+ c = getch ();
while (c != '\n')
{
- c = getch ();
- if (!warned_interface && extra_warnings
+ if (!warned_already && extra_warnings
&& c != ' ' && c != '\t' && c != '\n')
{
warning ("garbage after `#pragma interface' ignored");
- warned_interface = 1;
+ warned_already = 1;
}
+ c = getch ();
}
write_virtuals = 3;
if (main_input_filename == 0)
main_input_filename = input_filename;
+#ifdef AUTO_IMPLEMENT
filename = FILE_NAME_NONDIRECTORY (main_input_filename);
fi = get_time_identifier (filename);
fi = IDENTIFIER_CLASS_VALUE (fi);
impl_file_chain = (struct impl_files *)permalloc (sizeof (struct impl_files));
impl_file_chain->filename = filename;
impl_file_chain->next = 0;
+#endif
}
- interface_only = interface_strcmp (input_filename);
+ interface_only = interface_strcmp (main_filename);
interface_unknown = 0;
TREE_INT_CST_LOW (fileinfo) = interface_only;
TREE_INT_CST_HIGH (fileinfo) = interface_unknown;
&& getch () == 'n'
&& ((c = getch ()) == ' ' || c == '\t' || c == '\n'))
{
+ int warned_already = 0;
char *main_filename = main_input_filename ? main_input_filename : input_filename;
+ main_filename = FILE_NAME_NONDIRECTORY (main_filename);
while (c == ' ' || c == '\t')
c = getch ();
if (c != '\n')
goto skipline;
}
main_filename = TREE_STRING_POINTER (yylval.ttype);
+ c = getch();
+ put_back (c);
}
- main_filename = FILE_NAME_NONDIRECTORY (main_filename);
- /* read to newline. */
- while (c != '\n')
+ while (c == ' ' || c == '\t')
c = getch ();
+ while (c != '\n')
+ {
+ if (!warned_already && extra_warnings
+ && c != ' ' && c != '\t' && c != '\n')
+ {
+ warning ("garbage after `#pragma implementation' ignored");
+ warned_already = 1;
+ }
+ c = getch ();
+ }
+
if (write_virtuals == 3)
{
struct impl_files *ifiles = impl_file_chain;
-/* Define constants and variables for communication with cp-parse.y.
+/* Define constants and variables for communication with parse.y.
Copyright (C) 1987, 1992, 1993 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
and by Brendan Kehoe (brendan@cygnus.com).
build_overload_name (type, 0, 1);
id = get_identifier (obstack_base (&scratch_obstack));
IDENTIFIER_OPNAME_P (id) = 1;
+ IDENTIFIER_GLOBAL_VALUE (id) = TYPE_NAME (type);
+ TREE_TYPE (id) = type;
return id;
}
%nonassoc IF
%nonassoc ELSE
-%left IDENTIFIER TYPENAME PTYPENAME TYPENAME_COLON SCSPEC TYPESPEC TYPE_QUAL ENUM AGGR ELLIPSIS
+%left IDENTIFIER TYPENAME PTYPENAME TYPENAME_COLON SCSPEC TYPESPEC TYPE_QUAL ENUM AGGR ELLIPSIS SCOPED_TYPENAME TYPEOF SIGOF START_DECLARATOR OPERATOR
%left '{' ',' ';'
%left <code> LSHIFT RSHIFT
%left <code> '+' '-'
%left <code> '*' '/' '%'
-%right <code> UNARY PLUSPLUS MINUSMINUS
+%left <code> POINTSAT_STAR DOT_STAR
+%right <code> UNARY PLUSPLUS MINUSMINUS '~'
%left HYPERUNARY
%left <ttype> PAREN_STAR_PAREN LEFT_RIGHT
-%left <code> POINTSAT POINTSAT_STAR '.' DOT_STAR '(' '['
+%left <code> POINTSAT '.' '(' '['
%right SCOPE /* C++ extension */
%nonassoc NEW DELETE RAISE RAISES RERAISE TRY EXCEPT CATCH THROW
%type <code> unop
%type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist
-%type <ttype> optional_identifier paren_expr_or_null
+%type <ttype> optional_identifier paren_expr_or_null nontrivial_exprlist
%type <ttype> expr_no_commas cast_expr unary_expr primary string STRING
%type <ttype> typed_declspecs reserved_declspecs
%type <ttype> typed_typespecs reserved_typespecquals
%type <ttype> init initlist maybeasm
%type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers
%type <ttype> maybe_attribute attribute_list attrib
-%type <ttype> abs_member_declarator after_type_member_declarator
%type <ttype> compstmt except_stmts ansi_except_stmts implicitly_scoped_stmt
%type <ttype> declarator notype_declarator after_type_declarator
+%type <ttype> notype_declarator1 after_type_declarator1
+%type <ttype> direct_notype_declarator direct_after_type_declarator
%type <ttype> structsp opt.component_decl_list component_decl_list
%type <ttype> component_decl components component_declarator
+%type <ttype> notype_components notype_component_declarator
+%type <ttype> after_type_component_declarator after_type_component_declarator0
+%type <ttype> notype_component_declarator0
%type <ttype> enumlist enumerator
-%type <ttype> typename absdcl absdcl1 type_quals abs_or_notype_decl
-%type <ttype> xexpr see_typename parmlist parms parm bad_parm
+%type <ttype> type_id absdcl absdcl1 type_quals
+%type <ttype> direct_abstract_declarator conversion_declarator
+%type <ttype> new_type_id new_declarator direct_new_declarator
+%type <ttype> xexpr parmlist parms parm bad_parm
%type <ttype> identifiers_or_typenames
+%type <ttype> fcast_or_absdcl regcast_or_absdcl sub_cast_expr
+%type <ttype> expr_or_declarator complex_notype_declarator1
+%type <ttype> notype_unqualified_id
+%type <ttype> complex_direct_notype_declarator functional_cast
+%type <ttype> named_parm complex_parmlist typed_declspecs1 parms_comma
/* C++ extensions */
%type <ttype> typename_scope
%type <ttype> class_head base_class_list
%type <itype> base_class_access_list
%type <ttype> base_class maybe_base_class_list base_class.1
-%type <ttype> after_type_declarator_no_typename
%type <ttype> maybe_raises raise_identifier raise_identifiers ansi_raise_identifier ansi_raise_identifiers
%type <ttype> component_declarator0 id_scope scoped_typename scoped_base_class
%type <ttype> forhead.1 identifier_or_opname operator_name
-%type <ttype> new delete object object_star aggr
+%type <ttype> new delete object aggr
/* %type <ttype> primary_no_id */
%type <ttype> nonmomentary_expr
%type <itype> forhead.2 initdcl0 notype_initdcl0 member_init_list
%type <strtype> .pushlevel
-/* cp-spew.c depends on this being the last token. Define
+/* spew.c depends on this being the last token. Define
any new tokens before this one! */
%token END_OF_SAVED_INPUT
\f
template_parm:
/* The following rules introduce a new reduce/reduce
- conflict: they are valid prefixes for a `structsp',
- which means they could match a nameless parameter.
+ conflict on the ',' and '>' input tokens: they are valid
+ prefixes for a `structsp', which means they could match a
+ nameless parameter. See 14.6, paragraph 3.
By putting them before the `parm' rule, we get
their match before considering them nameless parameter
declarations. */
sorry ("template type defining a signature");
/* Maybe pedantic warning for union?
How about an enum? :-) */
- end_template_decl ($1, $2, current_aggr);
+ end_template_decl ($1, $2, current_aggr, 1);
reinit_parse_for_template (yychar, $1, $2);
yychar = YYEMPTY;
}
';'
| template_header named_class_head_sans_basetype ';'
{
- end_template_decl ($1, $2, current_aggr);
+ end_template_decl ($1, $2, current_aggr, 0);
/* declare $2 as template name with $1 parm list */
}
| template_header named_class_head_sans_basetype_defn ';'
{
- end_template_decl ($1, $2, current_aggr);
+ end_template_decl ($1, $2, current_aggr, 0);
/* declare $2 as template name with $1 parm list */
}
| template_header /* notype_initdcl0 ';' */
{
tree d;
int momentary;
+ int def = ($6 != ';');
momentary = suspend_momentary ();
- d = start_decl ($<ttype>2, /*current_declspecs*/NULL_TREE, 0, $3);
+ d = start_decl ($<ttype>2, /*current_declspecs*/NULL_TREE, 0,
+ $3);
cplus_decl_attributes (d, $5);
finish_decl (d, NULL_TREE, $4, 0);
- end_template_decl ($1, d, 0);
- if ($6 != ';')
+ end_template_decl ($1, d, 0, def);
+ if (def)
reinit_parse_for_template ((int) $6, $1, d);
resume_momentary (momentary);
}
{
tree d;
int momentary;
+ int def = ($7 != ';');
current_declspecs = $2;
momentary = suspend_momentary ();
cplus_decl_attributes (d, $6);
finish_decl (d, NULL_TREE, $5, 0);
end_exception_decls ();
- end_template_decl ($1, d, 0);
- if ($7 != ';')
+ end_template_decl ($1, d, 0, def);
+ if (def)
{
reinit_parse_for_template ((int) $7, $1, d);
yychar = YYEMPTY;
note_list_got_semicolon ($<ttype>2);
resume_momentary (momentary);
}
- | template_header declmods declarator fn_tmpl_end
+ | template_header declmods notype_declarator fn_tmpl_end
{
+ int def = ($4 != ';');
tree d = start_decl ($<ttype>3, $<ttype>2, 0, NULL_TREE);
finish_decl (d, NULL_TREE, NULL_TREE, 0);
- end_template_decl ($1, d, 0);
- if ($4 != ';')
+ end_template_decl ($1, d, 0, def);
+ if (def)
reinit_parse_for_template ((int) $4, $1, d);
}
/* Try to recover from syntax errors in templates. */
- | template_header error '}' { end_template_decl ($1, 0, 0); }
- | template_header error ';' { end_template_decl ($1, 0, 0); }
+ | template_header error '}' { end_template_decl ($1, 0, 0, 0); }
+ | template_header error ';' { end_template_decl ($1, 0, 0, 0); }
;
fn_tmpl_end: '{' { $$ = '{'; }
warning ("data definition has no type or storage class"); }
| declmods notype_initdecls ';'
{}
- /* Normal case to make fast: "int i;". */
- | declmods declarator ';'
+ /* Normal case to make fast: "const i;". */
+ | declmods notype_declarator ';'
{ tree d;
d = start_decl ($<ttype>2, $<ttype>$, 0, NULL_TREE);
finish_decl (d, NULL_TREE, NULL_TREE, 0);
reinit_parse_for_function (); }
;
-/* more C++ complexity */
+/* more C++ complexity. See component_decl for a comment on the
+ reduce/reduce conflict introduced by these rules. */
fn.def2:
typed_declspecs '(' parmlist ')' type_quals maybe_raises
{
if (yychar == YYEMPTY)
yychar = YYLEX;
reinit_parse_for_method (yychar, $$); }
- | declmods declarator maybe_raises
+ | declmods notype_declarator maybe_raises
{ $$ = start_method ($$, $2, $3);
if (! $$)
YYERROR1;
;
template_arg:
- typename
+ type_id
{ $$ = groktypename ($$); }
| expr_no_commas %prec UNARY
;
{ $$ = TRUTH_NOT_EXPR; }
;
-expr: nonnull_exprlist
+expr: nontrivial_exprlist
{ $$ = build_x_compound_expr ($$); }
- /* Ugly, but faster. */
| expr_no_commas
;
| simple_stmt
;
+nontrivial_exprlist:
+ expr_no_commas ',' expr_no_commas
+ { $$ = tree_cons (NULL_TREE, $$,
+ build_tree_list (NULL_TREE, $3)); }
+ | expr_no_commas ',' error
+ { $$ = tree_cons (NULL_TREE, $$,
+ build_tree_list (NULL_TREE, error_mark_node)); }
+ | nontrivial_exprlist ',' expr_no_commas
+ { chainon ($$, build_tree_list (NULL_TREE, $3)); }
+ | nontrivial_exprlist ',' error
+ { chainon ($$, build_tree_list (NULL_TREE, error_mark_node)); }
+ ;
+
nonnull_exprlist:
expr_no_commas
{ $$ = build_tree_list (NULL_TREE, $$); }
- | nonnull_exprlist ',' expr_no_commas
- { chainon ($$, build_tree_list (NULL_TREE, $3)); }
- | nonnull_exprlist ',' error
- { chainon ($$, build_tree_list (NULL_TREE, error_mark_node)); }
+ | nontrivial_exprlist
;
unary_expr:
{ $$ = build_x_indirect_ref ($2, "unary *"); }
| '&' cast_expr %prec UNARY
{ $$ = build_x_unary_op (ADDR_EXPR, $2); }
- | '~' cast_expr %prec UNARY
+ | '~' cast_expr
{ $$ = build_x_unary_op (BIT_NOT_EXPR, $2); }
| unop cast_expr %prec UNARY
{ $$ = build_x_unary_op ((enum tree_code) $$, $2);
pedwarn ("ANSI C++ forbids using sizeof() on a function");
}
$$ = c_sizeof (TREE_TYPE ($2)); }
- | SIZEOF '(' typename ')' %prec HYPERUNARY
+ | SIZEOF '(' type_id ')' %prec HYPERUNARY
{ $$ = c_sizeof (groktypename ($3)); }
| ALIGNOF unary_expr %prec UNARY
{ $$ = grok_alignof ($2); }
- | ALIGNOF '(' typename ')' %prec HYPERUNARY
+ | ALIGNOF '(' type_id ')' %prec HYPERUNARY
{ $$ = c_alignof (groktypename ($3)); }
- | .scope new typename %prec '='
+ | .scope new new_type_id %prec '='
{ $$ = build_new ($2, $3, NULL_TREE, $$ != NULL_TREE); }
- | .scope new '(' nonnull_exprlist ')' typename %prec '='
+ | .scope new '(' nonnull_exprlist ')' new_type_id %prec '='
{ $$ = build_new ($4, $6, NULL_TREE, $$ != NULL_TREE); }
| .scope new typespec '(' nonnull_exprlist ')'
{ $$ = build_new ($2, $3, $5, $$ != NULL_TREE); }
{ $$ = build_new ($2, $3, NULL_TREE, $$ != NULL_TREE); }
| .scope new '(' nonnull_exprlist ')' typespec LEFT_RIGHT
{ $$ = build_new ($4, $6, NULL_TREE, $$ != NULL_TREE); }
- | .scope new typename '=' init %prec '='
+ | .scope new new_type_id '=' init %prec '='
{ $$ = build_new ($2, $3, $5, $$ != NULL_TREE); }
- | .scope new '(' nonnull_exprlist ')' typename '=' init %prec '='
+ | .scope new '(' nonnull_exprlist ')' new_type_id '=' init %prec '='
{ $$ = build_new ($4, $6, $8, $$ != NULL_TREE); }
-
- /* I am not going to add placement syntax to the below complex rules
- because Ken says the syntax is illegal. (mrs) */
- /* I'm not sure why this is disallowed. But since it is, and it
- doesn't seem difficult to catch it, let's give a message, so
- the programmer can fix it. --Ken Raeburn */
- | .scope new '(' typed_typespecs absdcl ')' '[' nonmomentary_expr ']'
- {
+ /* If you don't understand why this is illegal, read 5.3.4. (jason) */
+ | .scope new '(' type_id ')' '[' nonmomentary_expr ']'
+ {
tree absdcl, typename;
- illegal_new_array:
- absdcl = build_parse_node (ARRAY_REF, $5, $8);
- typename = build_decl_list ($4, absdcl);
+ absdcl = build_parse_node (ARRAY_REF, TREE_VALUE ($4), $7);
+ typename = build_decl_list (TREE_PURPOSE ($4), absdcl);
pedwarn ("ANSI C++ forbids array dimensions with parenthesized type");
$$ = build_new ($2, typename, NULL_TREE, $$ != NULL_TREE);
}
- | .scope new '(' nonempty_type_quals absdcl ')' '[' nonmomentary_expr ']'
- { goto illegal_new_array; }
-
- | .scope new '(' typed_typespecs absdcl ')'
- { $$ = build_new ($2, build_decl_list ($4, $5), NULL_TREE, $$ != NULL_TREE); }
- | .scope new '(' nonnull_exprlist ')' '(' typed_typespecs absdcl ')'
- { $$ = build_new ($4, build_decl_list ($7, $8), NULL_TREE, $$ != NULL_TREE); }
- | .scope new '(' nonempty_type_quals absdcl ')'
- { $$ = build_new ($2, build_decl_list ($4, $5), NULL_TREE, $$ != NULL_TREE); }
- | .scope new '(' nonnull_exprlist ')' '(' nonempty_type_quals absdcl ')'
- { $$ = build_new ($4, build_decl_list ($7, $8), NULL_TREE, $$ != NULL_TREE); }
+ | .scope new '(' type_id ')'
+ { $$ = build_new ($2, $4, NULL_TREE, $$ != NULL_TREE); }
+ | .scope new '(' nonnull_exprlist ')' '(' type_id ')'
+ { $$ = build_new ($4, $7, NULL_TREE, $$ != NULL_TREE); }
/* Unswallow a ':' which is probably meant for ?: expression. */
| .scope new TYPENAME_COLON
{ yyungetc (':', 1); $$ = build_new ($2, $3, NULL_TREE, $$ != NULL_TREE); }
yychar = YYLEX; }
;
+/* This is necessary to postpone reduction of `int ((int)(int)(int))'. */
+regcast_or_absdcl:
+ '(' type_id ')' %prec EMPTY
+ { $2 = tree_cons (NULL_TREE, $2, void_list_node);
+ TREE_PARMLIST ($2) = 1;
+ $$ = build_parse_node (CALL_EXPR, NULL_TREE, $2,
+ NULL_TREE); }
+ | regcast_or_absdcl '(' type_id ')' %prec EMPTY
+ { $3 = tree_cons (NULL_TREE, $3, void_list_node);
+ TREE_PARMLIST ($3) = 1;
+ $$ = build_parse_node (CALL_EXPR, $$, $3, NULL_TREE); }
+ ;
+
cast_expr:
- unary_expr
- | '(' typename ')' expr_no_commas %prec UNARY
- { tree type = groktypename ($2);
- $$ = build_c_cast (type, $4); }
- | '(' typename ')' '{' initlist maybecomma '}' %prec UNARY
- { tree type = groktypename ($2);
+ sub_cast_expr
+ | regcast_or_absdcl sub_cast_expr %prec UNARY
+ { $$ = reparse_absdcl_as_casts ($$, $2); }
+ | regcast_or_absdcl '{' initlist maybecomma '}' %prec UNARY
+ {
+ tree init = build_nt (CONSTRUCTOR, NULL_TREE,
+ nreverse ($3));
+ if (pedantic)
+ pedwarn ("ANSI C++ forbids constructor-expressions");
+ /* Indicate that this was a GNU C constructor expression. */
+ TREE_HAS_CONSTRUCTOR (init) = 1;
- if (IS_SIGNATURE (type))
- {
- error ("cast specifies signature type");
- $$ = error_mark_node;
- }
- else
- {
- tree init;
- init = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($5));
- if (pedantic)
- pedwarn ("ANSI C++ forbids constructor-expressions");
- /* Indicate that this was a GNU C constructor expression. */
- TREE_HAS_CONSTRUCTOR (init) = 1;
- $$ = digest_init (type, init, (tree *) 0);
- if (TREE_CODE (type) == ARRAY_TYPE
- && TYPE_SIZE (type) == 0)
- {
- int failure = complete_array_type (type, $$, 1);
- if (failure)
- my_friendly_abort (78);
- }
- }
+ $$ = reparse_absdcl_as_casts ($$, init);
}
+ ;
+
+sub_cast_expr:
+ unary_expr
| HEADOF '(' expr ')'
{ $$ = build_headof ($3); }
| CLASSOF '(' expr ')'
expr_no_commas:
cast_expr
+ /* Handle general members. */
+ | expr_no_commas POINTSAT_STAR expr_no_commas
+ { $$ = build_x_binary_op (MEMBER_REF, $$, $3); }
+ | expr_no_commas DOT_STAR expr_no_commas
+ { $$ = build_m_component_ref ($$, $3); }
| expr_no_commas '+' expr_no_commas
{ $$ = build_x_binary_op ($2, $$, $3); }
| expr_no_commas '-' expr_no_commas
$$ = rval;
else
$$ = build_modify_expr ($$, $2, $3); }
- | primary DOT_STAR expr_no_commas %prec UNARY
- { $$ = build_m_component_ref ($$, $3); }
- /* Handle general members. */
- | object_star expr_no_commas %prec UNARY
- { $$ = build_x_binary_op (MEMBER_REF, $$, $2); }
/* These extensions are not defined. The second arg to build_m_component_ref
is old, build_m_component_ref now does an implicit
build_indirect_ref (x, NULL_PTR) on the second argument.
{ $$ = build_m_component_ref ($$, build_x_unary_op (ADDR_EXPR, $3)); }
| object unop expr_no_commas %prec UNARY
{ $$ = build_m_component_ref ($$, build_x_unary_op ($2, $3)); }
- | object '(' typename ')' expr_no_commas %prec UNARY
+ | object '(' type_id ')' expr_no_commas %prec UNARY
{ tree type = groktypename ($3);
$$ = build_m_component_ref ($$, build_c_cast (type, $5)); }
| object primary_no_id %prec UNARY
*/
;
-primary:
- IDENTIFIER
- { $$ = do_identifier ($$); }
+notype_unqualified_id:
+ '~' see_typename TYPENAME
+ {
+ destructor_name:
+ $$ = build_parse_node (BIT_NOT_EXPR, $3);
+ }
+ | '~' see_typename IDENTIFIER
+ { goto destructor_name; }
+ | '~' see_typename PTYPENAME
+ { goto destructor_name; }
| operator_name
+ | IDENTIFIER
+ | PTYPENAME %prec EMPTY
+ ;
+
+expr_or_declarator:
+ '*' expr_or_declarator %prec UNARY
+ { $$ = build_parse_node (INDIRECT_REF, $2); }
+ | '&' expr_or_declarator %prec UNARY
+ { $$ = build_parse_node (ADDR_EXPR, $2); }
+ | notype_unqualified_id
+ { see_typename (); }
+ ;
+
+direct_notype_declarator:
+ complex_direct_notype_declarator
+ | notype_unqualified_id
+ { see_typename (); }
+ ;
+
+primary:
+ notype_unqualified_id
{
- tree op = $$;
- if (TREE_CODE (op) != IDENTIFIER_NODE)
- $$ = op;
- else
+ if (TREE_CODE ($$) == BIT_NOT_EXPR)
+ $$ = build_x_unary_op (BIT_NOT_EXPR, TREE_OPERAND ($$, 0));
+ else if (IDENTIFIER_OPNAME_P ($$))
{
+ tree op = $$;
$$ = lookup_name (op, 0);
if ($$ == NULL_TREE)
{
$$ = error_mark_node;
}
}
- }
+ else
+ $$ = do_identifier ($$);
+ }
| CONSTANT
| string
{ $$ = combine_strings ($$); }
$$ = build_c_cast (type, build_compound_expr ($3));
}
}
- | typespec '(' nonnull_exprlist ')'
- { $$ = build_functional_cast ($$, $3); }
- | typespec LEFT_RIGHT
- { $$ = build_functional_cast ($$, NULL_TREE); }
+ | functional_cast
/* Stroustrup RTTI */
- | DYNAMIC_CAST '<' typename '>' '(' expr ')'
+ | DYNAMIC_CAST '<' type_id '>' '(' expr ')'
{ tree type = groktypename ($3);
$$ = build_dynamic_cast (type, $6); }
| TYPEID '(' expr ')'
{ $$ = build_typeid ($3); }
- | TYPEID '(' typename ')'
+ | TYPEID '(' type_id ')'
{ tree type = groktypename ($3);
$$ = get_typeid (type); }
| SCOPE typespec '(' nonnull_exprlist ')'
}
;
-object_star: primary POINTSAT_STAR
- ;
-
decl:
typed_declspecs initdecls ';'
{
resume_momentary ($2);
- note_list_got_semicolon ($<ttype>$);
+ note_list_got_semicolon ($1);
+ }
+ | typespec initdecls ';'
+ {
+ resume_momentary ($2);
+ if (IS_AGGR_TYPE_CODE (TREE_CODE ($1)))
+ note_got_semicolon ($1);
}
/* Normal case: make this fast. */
| typed_declspecs declarator ';'
- { tree d;
+ { tree d = $1;
int yes = suspend_momentary ();
- d = start_decl ($<ttype>2, $<ttype>$, 0, NULL_TREE);
+ d = start_decl ($2, d, 0, NULL_TREE);
finish_decl (d, NULL_TREE, NULL_TREE, 0);
resume_momentary (yes);
- note_list_got_semicolon ($<ttype>$);
+ note_list_got_semicolon ($1);
+ }
+ | typespec declarator ';'
+ { tree d = get_decl_list ($1);
+ int yes = suspend_momentary ();
+ d = start_decl ($2, d, 0, NULL_TREE);
+ finish_decl (d, NULL_TREE, NULL_TREE, 0);
+ resume_momentary (yes);
+ if (IS_AGGR_TYPE_CODE (TREE_CODE ($1)))
+ note_got_semicolon ($1);
}
| declmods notype_initdecls ';'
{ resume_momentary ((int) $<itype>2); }
/* Normal case: make this fast. */
- | declmods declarator ';'
+ | declmods notype_declarator ';'
{ tree d;
int yes = suspend_momentary ();
d = start_decl ($<ttype>2, $<ttype>$, 0, NULL_TREE);
after an explicit typespec). */
declarator:
- after_type_declarator
- | notype_declarator
- | START_DECLARATOR after_type_declarator
- { $$ = $2; }
- | START_DECLARATOR notype_declarator
- { $$ = $2; }
+ after_type_declarator %prec EMPTY
+ | notype_declarator %prec EMPTY
+ ;
+
+/* This is necessary to postpone reduction of `int()()()()'. */
+fcast_or_absdcl:
+ LEFT_RIGHT %prec EMPTY
+ { $$ = build_parse_node (CALL_EXPR, NULL_TREE, empty_parms (),
+ NULL_TREE); }
+ | fcast_or_absdcl LEFT_RIGHT %prec EMPTY
+ { $$ = build_parse_node (CALL_EXPR, $$, empty_parms (),
+ NULL_TREE); }
+ ;
+
+/* ANSI type-id (8.1) */
+type_id:
+ typed_typespecs absdcl
+ { $$ = build_decl_list ($$, $2); }
+ | nonempty_type_quals absdcl
+ { $$ = build_decl_list ($$, $2); }
+ | typespec absdcl
+ { $$ = build_decl_list (get_decl_list ($$), $2); }
+ | typed_typespecs %prec EMPTY
+ { $$ = build_decl_list ($$, NULL_TREE); }
+ | nonempty_type_quals %prec EMPTY
+ { $$ = build_decl_list ($$, NULL_TREE); }
;
/* Declspecs which contain at least one type specifier or typedef name.
A typedef'd name following these is taken as a name to be declared. */
typed_declspecs:
- typespec %prec HYPERUNARY
- { if ($$) $$ = list_hash_lookup_or_cons ($$); }
- | declmods typespec
- { $$ = hash_tree_chain ($2, $$); }
+ typed_typespecs %prec EMPTY
+ | typed_declspecs1
+
+typed_declspecs1:
+ declmods typespec
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
| typespec reserved_declspecs %prec HYPERUNARY
- { $$ = hash_tree_chain ($$, $2); }
+ { $$ = decl_tree_cons (NULL_TREE, $$, $2); }
| declmods typespec reserved_declspecs
- { $$ = hash_tree_chain ($2, hash_chainon ($3, $$)); }
+ { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
+ | declmods typespec reserved_typespecquals
+ { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
+ | declmods typespec reserved_typespecquals reserved_declspecs
+ { $$ = decl_tree_cons (NULL_TREE, $2,
+ chainon ($3, chainon ($4, $$))); }
;
-reserved_declspecs: /* empty
- { $$ = NULL_TREE; } */
- typespecqual_reserved
- { $$ = build_decl_list (NULL_TREE, $$); }
- | SCSPEC
+reserved_declspecs:
+ SCSPEC
{ if (extra_warnings)
warning ("`%s' is not at beginning of declaration",
IDENTIFIER_POINTER ($$));
to redeclare a typedef-name. */
declmods:
- TYPE_QUAL
- { $$ = IDENTIFIER_AS_LIST ($$);
- TREE_STATIC ($$) = 1; }
+ nonempty_type_quals %prec EMPTY
+ { TREE_STATIC ($$) = 1; }
| SCSPEC
{ $$ = IDENTIFIER_AS_LIST ($$); }
| declmods TYPE_QUAL
- { $$ = hash_tree_chain ($2, $$);
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$);
TREE_STATIC ($$) = 1; }
| declmods SCSPEC
{ if (extra_warnings && TREE_STATIC ($$))
warning ("`%s' is not at beginning of declaration",
IDENTIFIER_POINTER ($2));
- $$ = hash_tree_chain ($2, $$);
+ $$ = decl_tree_cons (NULL_TREE, $2, $$);
TREE_STATIC ($$) = TREE_STATIC ($1); }
;
| typespec reserved_typespecquals
{ $$ = decl_tree_cons (NULL_TREE, $$, $2); }
| nonempty_type_quals typespec reserved_typespecquals
- { $$ = decl_tree_cons (NULL_TREE, $2, hash_chainon ($3, $$)); }
+ { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
;
reserved_typespecquals:
typespecqual_reserved
- { $$ = get_decl_list ($$); }
+ { $$ = build_decl_list (NULL_TREE, $$); }
| reserved_typespecquals typespecqual_reserved
{ $$ = decl_tree_cons (NULL_TREE, $2, $$); }
;
typespec: structsp
| TYPESPEC %prec EMPTY
| TYPENAME %prec EMPTY
- | scoped_typename
+ | scoped_typename %prec EMPTY
+ | SCOPE TYPENAME %prec EMPTY
+ { $$ = IDENTIFIER_GLOBAL_VALUE ($2);
+ if (!$$)
+ {
+ error ("undeclared variable `%s' (first use here)",
+ IDENTIFIER_POINTER ($2));
+ $$ = error_mark_node;
+ IDENTIFIER_GLOBAL_VALUE ($2) = error_mark_node;
+ }
+ else
+ {
+ $$ = TREE_TYPE($$);
+ }
+ }
| TYPEOF '(' expr ')'
{ $$ = TREE_TYPE ($3);
if (pedantic)
pedwarn ("ANSI C++ forbids `typeof'"); }
- | TYPEOF '(' typename ')'
+ | TYPEOF '(' type_id ')'
{ $$ = groktypename ($3);
if (pedantic)
pedwarn ("ANSI C++ forbids `typeof'"); }
$$ = error_mark_node;
}
}
- | SIGOF '(' typename ')'
+ | SIGOF '(' type_id ')'
{ tree type = groktypename ($3);
if (IS_AGGR_TYPE (type))
initdcl0:
declarator maybe_raises maybeasm maybe_attribute '='
{ current_declspecs = $<ttype>0;
+ if (TREE_CODE (current_declspecs) != TREE_LIST)
+ current_declspecs = get_decl_list (current_declspecs);
$<itype>5 = suspend_momentary ();
$<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1, $2);
cplus_decl_attributes ($<ttype>$, $4); }
| declarator maybe_raises maybeasm maybe_attribute
{ tree d;
current_declspecs = $<ttype>0;
+ if (TREE_CODE (current_declspecs) != TREE_LIST)
+ current_declspecs = get_decl_list (current_declspecs);
$$ = suspend_momentary ();
d = start_decl ($<ttype>1, current_declspecs, 0, $2);
cplus_decl_attributes (d, $4);
;
named_class_head_sans_basetype_defn:
- aggr identifier_defn
+ aggr identifier_defn %prec EMPTY
{ current_aggr = $$; $$ = $2; }
;
+do_xref: /* empty */ %prec EMPTY
+ { $<ttype>$ = xref_tag (current_aggr, $<ttype>0, NULL_TREE, 1); }
+
+do_xref_defn: /* empty */ %prec EMPTY
+ { $<ttype>$ = xref_defn_tag (current_aggr, $<ttype>0, NULL_TREE); }
+
named_class_head:
- named_class_head_sans_basetype
- {
- $<ttype>$ = xref_tag (current_aggr, $1, NULL_TREE, 1);
- }
+ named_class_head_sans_basetype do_xref
maybe_base_class_list %prec EMPTY
{
if ($3)
$$ = $<ttype>2;
}
|
- named_class_head_sans_basetype_defn
- {
- $<ttype>$ = xref_defn_tag (current_aggr, $1, NULL_TREE);
- }
+ named_class_head_sans_basetype_defn do_xref_defn
maybe_base_class_list %prec EMPTY
{
if ($3)
$$ = error_mark_node;
}
}
- | SIGOF '(' typename ')'
+ | SIGOF '(' type_id ')'
{
if (current_aggr == signature_type_node)
{
;
component_decl:
+ /* Do not add a "typed_declspecs declarator ';'" rule here for
+ speed; we need to call grok_x_components for enums, so the
+ speedup would be insignificant. */
typed_declspecs components ';'
{
$$ = grok_x_components ($$, $2);
end_exception_decls ();
}
+ /* These rules introduce a reduce/reduce conflict; in
+ typedef int foo, bar;
+ class A {
+ foo (bar);
+ };
+ should "A::foo" be declared as a function or data member?
+ In other words, is "bar" an after_type_declarator or a parmlist? */
| typed_declspecs '(' parmlist ')' ';'
{ $$ = groktypefield ($$, $3); }
| typed_declspecs '(' parmlist ')' '}'
{ error ("missing ';' before right brace");
yyungetc ('}', 0);
$$ = groktypefield ($$, empty_parms ()); }
- | declmods components ';'
+ | declmods notype_components ';'
{
$$ = grok_x_components ($$, $2);
end_exception_decls ();
}
/* Normal case: make this fast. */
- | declmods declarator ';'
+ | declmods notype_declarator ';'
{ $$ = grokfield ($<ttype>2, $<ttype>$,
NULL_TREE, NULL_TREE, NULL_TREE); }
- | declmods components '}'
+ | declmods notype_components '}'
{ error ("missing ';' before right brace");
yyungetc ('}', 0);
$$ = grok_x_components ($$, $2);
$$ = grokfield ($$, NULL_TREE, $2, NULL_TREE, NULL_TREE); }
;
+/* The case of exactly one component is handled directly by component_decl. */
components:
/* empty: possibly anonymous */
{ $$ = NULL_TREE; }
}
;
+notype_components:
+ /* empty: possibly anonymous */
+ { $$ = NULL_TREE; }
+ | notype_component_declarator0
+ | notype_components ',' notype_component_declarator
+ {
+ /* In this context, void_type_node encodes
+ friends. They have been recorded elsewhere. */
+ if ($$ == void_type_node)
+ $$ = $3;
+ else
+ $$ = chainon ($$, $3);
+ }
+ ;
+
component_declarator0:
- declarator maybe_raises maybeasm maybe_attribute
+ after_type_component_declarator0
+ | notype_component_declarator0
+ ;
+
+component_declarator:
+ after_type_component_declarator
+ | notype_component_declarator
+ ;
+
+after_type_component_declarator0:
+ after_type_declarator maybe_raises maybeasm maybe_attribute
{ current_declspecs = $<ttype>0;
$$ = grokfield ($$, current_declspecs, $2, NULL_TREE, $3);
cplus_decl_attributes ($$, $4); }
- | declarator maybe_raises maybeasm maybe_attribute '=' init
+ | after_type_declarator maybe_raises maybeasm maybe_attribute '=' init
{ current_declspecs = $<ttype>0;
$$ = grokfield ($$, current_declspecs, $2, $6, $3);
cplus_decl_attributes ($$, $4); }
- | IDENTIFIER ':' expr_no_commas maybe_attribute
+ | TYPENAME ':' expr_no_commas maybe_attribute
{ current_declspecs = $<ttype>0;
$$ = grokbitfield ($$, current_declspecs, $3);
cplus_decl_attributes ($$, $4); }
- | TYPENAME ':' expr_no_commas maybe_attribute
+ ;
+
+notype_component_declarator0:
+ notype_declarator maybe_raises maybeasm maybe_attribute
+ { current_declspecs = $<ttype>0;
+ $$ = grokfield ($$, current_declspecs, $2, NULL_TREE, $3);
+ cplus_decl_attributes ($$, $4); }
+ | notype_declarator maybe_raises maybeasm maybe_attribute '=' init
+ { current_declspecs = $<ttype>0;
+ $$ = grokfield ($$, current_declspecs, $2, $6, $3);
+ cplus_decl_attributes ($$, $4); }
+ | IDENTIFIER ':' expr_no_commas maybe_attribute
{ current_declspecs = $<ttype>0;
$$ = grokbitfield ($$, current_declspecs, $3);
cplus_decl_attributes ($$, $4); }
cplus_decl_attributes ($$, $3); }
;
-component_declarator:
- declarator maybe_raises maybeasm maybe_attribute
+after_type_component_declarator:
+ after_type_declarator maybe_raises maybeasm maybe_attribute
{ $$ = grokfield ($$, current_declspecs, $2, NULL_TREE, $3);
cplus_decl_attributes ($$, $4); }
- | declarator maybe_raises maybeasm maybe_attribute '=' init
+ | after_type_declarator maybe_raises maybeasm maybe_attribute '=' init
{ $$ = grokfield ($$, current_declspecs, $2, $6, $3);
cplus_decl_attributes ($$, $4); }
- | IDENTIFIER ':' expr_no_commas maybe_attribute
+ | TYPENAME ':' expr_no_commas maybe_attribute
{ $$ = grokbitfield ($$, current_declspecs, $3);
cplus_decl_attributes ($$, $4); }
- | TYPENAME ':' expr_no_commas maybe_attribute
+ ;
+
+notype_component_declarator:
+ notype_declarator maybe_raises maybeasm maybe_attribute
+ { $$ = grokfield ($$, current_declspecs, $2, NULL_TREE, $3);
+ cplus_decl_attributes ($$, $4); }
+ | notype_declarator maybe_raises maybeasm maybe_attribute '=' init
+ { $$ = grokfield ($$, current_declspecs, $2, $6, $3);
+ cplus_decl_attributes ($$, $4); }
+ | IDENTIFIER ':' expr_no_commas maybe_attribute
{ $$ = grokbitfield ($$, current_declspecs, $3);
cplus_decl_attributes ($$, $4); }
| ':' expr_no_commas maybe_attribute
{ $$ = build_enumerator ($$, $3); }
;
-/* ANSI type-id (8.1) */
-typename:
- typed_typespecs absdcl
+/* ANSI new-type-id (5.3.4) */
+new_type_id:
+ typed_typespecs new_declarator
{ $$ = build_decl_list ($$, $2); }
- | nonempty_type_quals absdcl
+ | nonempty_type_quals new_declarator
{ $$ = build_decl_list ($$, $2); }
+ | typed_typespecs %prec EMPTY
+ { $$ = build_decl_list ($$, NULL_TREE); }
+ | nonempty_type_quals %prec EMPTY
+ { $$ = build_decl_list ($$, NULL_TREE); }
;
/* ANSI abstract-declarator (8.1) */
-absdcl: /* an abstract declarator */
- /* empty */ %prec EMPTY
- { $$ = NULL_TREE; }
- | absdcl1 %prec EMPTY
+absdcl:
+ absdcl1 %prec EMPTY
| START_DECLARATOR absdcl1 %prec EMPTY
{ $$ = $2; }
;
+type_quals:
+ /* empty */ %prec EMPTY
+ { $$ = NULL_TREE; }
+ | type_quals TYPE_QUAL
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ ;
+
nonempty_type_quals:
TYPE_QUAL
{ $$ = IDENTIFIER_AS_LIST ($$); }
{ $$ = decl_tree_cons (NULL_TREE, $2, $$); }
;
-type_quals:
- /* empty */
- { $$ = NULL_TREE; }
- | type_quals TYPE_QUAL
- { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
- ;
-
/* These rules must follow the rules for function declarations
and component declarations. That way, longer rules are preferred. */
nonmomentary_expr:
{ $<itype>$ = suspend_momentary (); } expr
{ resume_momentary ((int) $<itype>1); $$ = $2; }
+ ;
/* A declarator that is allowed only after an explicit typespec. */
/* may all be followed by prec '.' */
after_type_declarator:
- after_type_declarator '(' nonnull_exprlist ')' type_quals %prec '.'
- { $$ = build_parse_node (CALL_EXPR, $$, $3, $5); }
- | after_type_declarator '(' parmlist ')' type_quals %prec '.'
- { $$ = build_parse_node (CALL_EXPR, $$, $3, $5); }
- | after_type_declarator LEFT_RIGHT type_quals %prec '.'
- { $$ = build_parse_node (CALL_EXPR, $$, empty_parms (), $3); }
- | after_type_declarator '(' error ')' type_quals %prec '.'
- { $$ = build_parse_node (CALL_EXPR, $$, NULL_TREE, NULL_TREE); }
- | after_type_declarator '[' nonmomentary_expr ']'
- { $$ = build_parse_node (ARRAY_REF, $$, $3); }
- | after_type_declarator '[' ']'
- { $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
- | '(' after_type_declarator_no_typename ')'
+ after_type_declarator1
+ | START_DECLARATOR after_type_declarator1
{ $$ = $2; }
- | '(' '*' type_quals after_type_declarator ')'
- { $$ = make_pointer_declarator ($3, $4); }
- | PAREN_STAR_PAREN
- { see_typename (); }
- | after_type_member_declarator
- | '(' '&' type_quals after_type_declarator ')'
- { $$ = make_reference_declarator ($3, $4); }
- | '*' type_quals after_type_declarator %prec UNARY
+ ;
+
+after_type_declarator1:
+ '*' nonempty_type_quals after_type_declarator1 %prec UNARY
{ $$ = make_pointer_declarator ($2, $3); }
- | '&' type_quals after_type_declarator %prec UNARY
+ | '&' nonempty_type_quals after_type_declarator1 %prec UNARY
{ $$ = make_reference_declarator ($2, $3); }
- | TYPENAME %prec EMPTY
+ | '*' after_type_declarator1 %prec UNARY
+ { $$ = make_pointer_declarator (NULL_TREE, $2); }
+ | '&' after_type_declarator1 %prec UNARY
+ { $$ = make_reference_declarator (NULL_TREE, $2); }
+ | id_scope '*' type_quals after_type_declarator1
+ { tree arg = make_pointer_declarator ($3, $4);
+ if (TREE_CODE ($$) != SCOPE_REF)
+ $$ = build_push_scope ($$, arg);
+ else if (TREE_OPERAND ($$, 1) == NULL_TREE)
+ TREE_OPERAND ($$, 1) = arg;
+ else
+ $$ = build_parse_node (SCOPE_REF, $$, arg);
+ }
+ | direct_after_type_declarator
;
-after_type_declarator_no_typename:
- after_type_declarator_no_typename '(' nonnull_exprlist ')' type_quals %prec '.'
+direct_after_type_declarator:
+ direct_after_type_declarator '(' nonnull_exprlist ')' type_quals %prec '.'
{ $$ = build_parse_node (CALL_EXPR, $$, $3, $5); }
- | after_type_declarator_no_typename '(' parmlist ')' type_quals %prec '.'
+ | direct_after_type_declarator '(' parmlist ')' type_quals %prec '.'
{ $$ = build_parse_node (CALL_EXPR, $$, $3, $5); }
- | after_type_declarator_no_typename LEFT_RIGHT type_quals %prec '.'
+ | direct_after_type_declarator LEFT_RIGHT type_quals %prec '.'
{ $$ = build_parse_node (CALL_EXPR, $$, empty_parms (), $3); }
- | after_type_declarator_no_typename '(' error ')' type_quals %prec '.'
+ | direct_after_type_declarator '(' error ')' type_quals %prec '.'
{ $$ = build_parse_node (CALL_EXPR, $$, NULL_TREE, NULL_TREE); }
- | after_type_declarator_no_typename '[' nonmomentary_expr ']'
+ | direct_after_type_declarator '[' nonmomentary_expr ']'
{ $$ = build_parse_node (ARRAY_REF, $$, $3); }
- | after_type_declarator_no_typename '[' ']'
+ | direct_after_type_declarator '[' ']'
{ $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
- | '(' after_type_declarator_no_typename ')'
+ | '(' after_type_declarator1 ')'
{ $$ = $2; }
- | PAREN_STAR_PAREN
- { see_typename (); }
- | after_type_member_declarator
- | '*' type_quals after_type_declarator %prec UNARY
- { $$ = make_pointer_declarator ($2, $3); }
- | '&' type_quals after_type_declarator %prec UNARY
- { $$ = make_reference_declarator ($2, $3); }
+ | TYPENAME %prec EMPTY
;
/* A declarator allowed whether or not there has been
an explicit typespec. These cannot redeclare a typedef-name. */
notype_declarator:
- notype_declarator '(' nonnull_exprlist ')' type_quals %prec '.'
+ notype_declarator1
+ | START_DECLARATOR notype_declarator1
+ { $$ = $2; }
+ ;
+
+notype_declarator1:
+ '*' nonempty_type_quals notype_declarator1 %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '&' nonempty_type_quals notype_declarator1 %prec UNARY
+ { $$ = make_reference_declarator ($2, $3); }
+ | '*' notype_declarator1 %prec UNARY
+ { $$ = make_pointer_declarator (NULL_TREE, $2); }
+ | '&' notype_declarator1 %prec UNARY
+ { $$ = make_reference_declarator (NULL_TREE, $2); }
+ | id_scope '*' type_quals notype_declarator1
+ { tree arg = make_pointer_declarator ($3, $4);
+ if (TREE_CODE ($$) != SCOPE_REF)
+ $$ = build_push_scope ($$, arg);
+ else if (TREE_OPERAND ($$, 1) == NULL_TREE)
+ TREE_OPERAND ($$, 1) = arg;
+ else
+ $$ = build_parse_node (SCOPE_REF, $$, arg);
+ }
+ | direct_notype_declarator
+ ;
+
+complex_notype_declarator1:
+ '*' nonempty_type_quals notype_declarator1 %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '&' nonempty_type_quals notype_declarator1 %prec UNARY
+ { $$ = make_reference_declarator ($2, $3); }
+ | '*' complex_notype_declarator1 %prec UNARY
+ { $$ = make_pointer_declarator (NULL_TREE, $2); }
+ | '&' complex_notype_declarator1 %prec UNARY
+ { $$ = make_reference_declarator (NULL_TREE, $2); }
+ | id_scope '*' type_quals notype_declarator1
+ { tree arg = make_pointer_declarator ($3, $4);
+ if (TREE_CODE ($$) != SCOPE_REF)
+ $$ = build_push_scope ($$, arg);
+ else if (TREE_OPERAND ($$, 1) == NULL_TREE)
+ TREE_OPERAND ($$, 1) = arg;
+ else
+ $$ = build_parse_node (SCOPE_REF, $$, arg);
+ }
+ | complex_direct_notype_declarator
+ ;
+
+complex_direct_notype_declarator:
+ direct_notype_declarator '(' nonnull_exprlist ')' type_quals %prec '.'
{ $$ = build_parse_node (CALL_EXPR, $$, $3, $5); }
- | notype_declarator '(' parmlist ')' type_quals %prec '.'
+ | direct_notype_declarator '(' parmlist ')' type_quals %prec '.'
{ $$ = build_parse_node (CALL_EXPR, $$, $3, $5); }
- | notype_declarator LEFT_RIGHT type_quals %prec '.'
+ | direct_notype_declarator LEFT_RIGHT type_quals %prec '.'
{ $$ = build_parse_node (CALL_EXPR, $$, empty_parms (), $3); }
- | notype_declarator '(' error ')' type_quals %prec '.'
+ | direct_notype_declarator '(' error ')' type_quals %prec '.'
{ $$ = build_parse_node (CALL_EXPR, $$, NULL_TREE, NULL_TREE); }
- | '(' notype_declarator ')'
+ | '(' expr_or_declarator ')'
+ { $$ = finish_decl_parsing ($2); }
+ | '(' complex_notype_declarator1 ')'
{ $$ = $2; }
- | '*' type_quals notype_declarator %prec UNARY
- { $$ = make_pointer_declarator ($2, $3); }
- | '&' type_quals notype_declarator %prec UNARY
- { $$ = make_reference_declarator ($2, $3); }
- | notype_declarator '[' nonmomentary_expr ']'
+ | direct_notype_declarator '[' nonmomentary_expr ']'
{ $$ = build_parse_node (ARRAY_REF, $$, $3); }
- | notype_declarator '[' ']'
+ | direct_notype_declarator '[' ']'
{ $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
- | IDENTIFIER
- { see_typename (); }
/* C++ extensions. */
- | operator_name
- { see_typename (); }
-
- | '~' TYPENAME
- {
- destructor_name:
- see_typename ();
- $$ = build_parse_node (BIT_NOT_EXPR, $2);
- }
- | '~' IDENTIFIER
- { goto destructor_name; }
- | '~' PTYPENAME
- { goto destructor_name; }
- | id_scope see_typename notype_declarator %prec '('
+ | id_scope see_typename notype_unqualified_id
{ see_typename ();
if (TREE_CODE ($$) != SCOPE_REF)
$$ = build_push_scope ($$, $3);
else
$$ = build_parse_node (SCOPE_REF, $$, $3);
}
- | id_scope see_typename TYPENAME %prec '('
- { $$ = build_push_scope ($$, $3); }
- | id_scope see_typename TYPENAME '(' nonnull_exprlist ')' type_quals %prec '.'
- { $$ = build_push_scope ($$, build_parse_node (CALL_EXPR, $3, $5, $7)); }
- | id_scope see_typename TYPENAME '(' parmlist ')' type_quals %prec '.'
- { $$ = build_push_scope ($$, build_parse_node (CALL_EXPR, $3, $5, $7)); }
- | id_scope see_typename TYPENAME LEFT_RIGHT type_quals %prec '.'
- { $$ = build_push_scope ($$, build_parse_node (CALL_EXPR, $3, empty_parms (), $5)); }
- | id_scope see_typename TYPENAME '(' error ')' type_quals %prec '.'
- { $$ = build_push_scope ($$, build_parse_node (CALL_EXPR, $3, NULL_TREE, NULL_TREE)); }
- /* For constructor templates. */
- | id_scope see_typename PTYPENAME %prec '('
+ | id_scope see_typename TYPENAME
{ $$ = build_push_scope ($$, $3); }
- | id_scope see_typename PTYPENAME '(' nonnull_exprlist ')' type_quals %prec '.'
- { $$ = build_push_scope ($$, build_parse_node (CALL_EXPR, $3, $5, $7)); }
- | id_scope see_typename PTYPENAME '(' parmlist ')' type_quals %prec '.'
- { $$ = build_push_scope ($$, build_parse_node (CALL_EXPR, $3, $5, $7)); }
- | id_scope see_typename PTYPENAME LEFT_RIGHT type_quals %prec '.'
- { $$ = build_push_scope ($$, build_parse_node (CALL_EXPR, $3, empty_parms (), $5)); }
- | id_scope see_typename PTYPENAME '(' error ')' type_quals %prec '.'
- { $$ = build_push_scope ($$, build_parse_node (CALL_EXPR, $3, NULL_TREE, NULL_TREE)); }
- | SCOPE see_typename notype_declarator
+ | SCOPE see_typename direct_notype_declarator
{ $$ = build_parse_node (SCOPE_REF, NULL_TREE, $3); }
| template_type SCOPED_NAME
- { $$ = $2; }
+ { tree t;
+ extern int current_class_depth;
+
+ t = TREE_TYPE(TREE_OPERAND($2, 0));
+ if (t != current_class_type &&
+ TREE_CODE(t) != TEMPLATE_TYPE_PARM)
+ {
+ push_nested_class(t, 3);
+ TREE_COMPLEXITY ($2) = current_class_depth;
+ }
+ $$ = $2;
+ }
+ ;
+
+functional_cast:
+ typespec '(' nonnull_exprlist ')'
+ { $$ = build_functional_cast ($$, $3); }
+ | typespec '(' expr_or_declarator ')'
+ { $$ = reparse_decl_as_expr ($$, $3); }
+ | typespec fcast_or_absdcl %prec EMPTY
+ { $$ = reparse_absdcl_as_expr ($$, $2); }
;
-id_scope: typename_scope
+id_scope: typename_scope
{ tree t;
do_id_scope:
} */
;
-absdcl1: /* a nonempty abstract declarator */
- '(' absdcl1 ')'
- { see_typename ();
- $$ = $2; }
- /* `(typedef)1' is `int'. */
- | '*' type_quals absdcl1 %prec EMPTY
+/* ANSI new-declarator (5.3.4) */
+new_declarator:
+ '*' type_quals new_declarator
{ $$ = make_pointer_declarator ($2, $3); }
| '*' type_quals %prec EMPTY
{ $$ = make_pointer_declarator ($2, NULL_TREE); }
-/*
- | id_scope '*' type_quals absdcl1 %prec EMPTY
- { $3 = make_pointer_declarator ($3, $4);
- $$ = build_parse_node (SCOPE_REF, $$, $3); }
+ | '&' type_quals new_declarator %prec EMPTY
+ { $$ = make_reference_declarator ($2, $3); }
+ | '&' type_quals %prec EMPTY
+ { $$ = make_reference_declarator ($2, NULL_TREE); }
| id_scope '*' type_quals %prec EMPTY
- { $3 = make_pointer_declarator ($3, NULL_TREE);
- $$ = build_parse_node (SCOPE_REF, $$, $3); }
-*/
- | PAREN_STAR_PAREN
- { see_typename (); }
- | '(' abs_member_declarator ')'
- { $$ = $2; }
- | '&' type_quals absdcl1 %prec EMPTY
+ { tree arg = make_pointer_declarator ($3, NULL_TREE);
+ if (TREE_CODE ($$) != SCOPE_REF)
+ $$ = build_push_scope ($$, arg);
+ else if (TREE_OPERAND ($$, 1) == NULL_TREE)
+ TREE_OPERAND ($$, 1) = arg;
+ else
+ $$ = build_parse_node (SCOPE_REF, $$, arg);
+ }
+ | id_scope '*' type_quals new_declarator
+ { tree arg = make_pointer_declarator ($3, $4);
+ if (TREE_CODE ($$) != SCOPE_REF)
+ $$ = build_push_scope ($$, arg);
+ else if (TREE_OPERAND ($$, 1) == NULL_TREE)
+ TREE_OPERAND ($$, 1) = arg;
+ else
+ $$ = build_parse_node (SCOPE_REF, $$, arg);
+ }
+ | direct_new_declarator %prec EMPTY
+ ;
+
+/* ANSI direct-new-declarator (5.3.4) */
+direct_new_declarator:
+ '[' expr ']'
+ { $$ = build_parse_node (ARRAY_REF, NULL_TREE, $2); }
+ | direct_new_declarator '[' nonmomentary_expr ']'
+ { $$ = build_parse_node (ARRAY_REF, $$, $3); }
+ ;
+
+/* ANSI abstract-declarator (8.1) */
+absdcl1:
+ '*' nonempty_type_quals absdcl1
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '*' absdcl1
+ { $$ = make_pointer_declarator (NULL_TREE, $2); }
+ | '*' type_quals %prec EMPTY
+ { $$ = make_pointer_declarator ($2, NULL_TREE); }
+ | '&' nonempty_type_quals absdcl1
{ $$ = make_reference_declarator ($2, $3); }
+ | '&' absdcl1
+ { $$ = make_reference_declarator (NULL_TREE, $2); }
| '&' type_quals %prec EMPTY
{ $$ = make_reference_declarator ($2, NULL_TREE); }
- | absdcl1 '(' parmlist ')' type_quals %prec '.'
+ | id_scope '*' type_quals %prec EMPTY
+ { tree arg = make_pointer_declarator ($3, NULL_TREE);
+ if (TREE_CODE ($$) != SCOPE_REF)
+ $$ = build_push_scope ($$, arg);
+ else if (TREE_OPERAND ($$, 1) == NULL_TREE)
+ TREE_OPERAND ($$, 1) = arg;
+ else
+ $$ = build_parse_node (SCOPE_REF, $$, arg);
+ }
+ | id_scope '*' type_quals absdcl1
+ { tree arg = make_pointer_declarator ($3, $4);
+ if (TREE_CODE ($$) != SCOPE_REF)
+ $$ = build_push_scope ($$, arg);
+ else if (TREE_OPERAND ($$, 1) == NULL_TREE)
+ TREE_OPERAND ($$, 1) = arg;
+ else
+ $$ = build_parse_node (SCOPE_REF, $$, arg);
+ }
+ | direct_abstract_declarator %prec EMPTY
+ ;
+
+/* ANSI direct-abstract-declarator (8.1) */
+direct_abstract_declarator:
+ '(' absdcl1 ')'
+ { see_typename ();
+ $$ = $2; }
+ /* `(typedef)1' is `int'. */
+ | PAREN_STAR_PAREN
+ { see_typename (); }
+ | direct_abstract_declarator '(' parmlist ')' type_quals %prec '.'
{ $$ = build_parse_node (CALL_EXPR, $$, $3, $5); }
- | absdcl1 LEFT_RIGHT type_quals %prec '.'
+ | direct_abstract_declarator LEFT_RIGHT type_quals %prec '.'
{ $$ = build_parse_node (CALL_EXPR, $$, empty_parms (), $3); }
- | absdcl1 '[' nonmomentary_expr ']' %prec '.'
+ | direct_abstract_declarator '[' nonmomentary_expr ']' %prec '.'
{ $$ = build_parse_node (ARRAY_REF, $$, $3); }
- | absdcl1 '[' ']' %prec '.'
+ | direct_abstract_declarator '[' ']' %prec '.'
{ $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
- | '(' parmlist ')' type_quals %prec '.'
+ | '(' complex_parmlist ')' type_quals %prec '.'
{ $$ = build_parse_node (CALL_EXPR, NULL_TREE, $2, $4); }
- | LEFT_RIGHT type_quals %prec '.'
- { $$ = build_parse_node (CALL_EXPR, NULL_TREE, empty_parms (), $2); }
+ | regcast_or_absdcl type_quals %prec '.'
+ { TREE_OPERAND ($$, 2) = $2; }
+ | fcast_or_absdcl type_quals %prec '.'
+ { TREE_OPERAND ($$, 2) = $2; }
| '[' nonmomentary_expr ']' %prec '.'
{ $$ = build_parse_node (ARRAY_REF, NULL_TREE, $2); }
| '[' ']' %prec '.'
{ $$ = build_parse_node (ARRAY_REF, NULL_TREE, NULL_TREE); }
;
-abs_member_declarator:
- id_scope see_typename '*' type_quals
- { tree t;
- t = $$;
- while (TREE_OPERAND (t, 1))
- t = TREE_OPERAND (t, 1);
- TREE_OPERAND (t, 1) = build_parse_node (INDIRECT_REF, 0);
- }
- | id_scope see_typename '*' type_quals absdcl1
- { tree t;
- t = $$;
- while (TREE_OPERAND (t, 1))
- t = TREE_OPERAND (t, 1);
- TREE_OPERAND (t, 1) = build_parse_node (INDIRECT_REF, $5);
- }
- | id_scope see_typename '&' type_quals
- { tree t;
- t = $$;
- while (TREE_OPERAND (t, 1))
- t = TREE_OPERAND (t, 1);
- TREE_OPERAND (t, 1) = build_parse_node (ADDR_EXPR, 0);
- }
- | id_scope see_typename '&' type_quals absdcl1
- { tree t;
- t = $$;
- while (TREE_OPERAND (t, 1))
- t = TREE_OPERAND (t, 1);
- TREE_OPERAND (t, 1) = build_parse_node (ADDR_EXPR, $5);
- }
- ;
-
-after_type_member_declarator:
- id_scope see_typename '*' type_quals after_type_declarator
- { tree t;
- t = $$;
- while (TREE_OPERAND (t, 1))
- t = TREE_OPERAND (t, 1);
- TREE_OPERAND (t, 1) = build_parse_node (INDIRECT_REF, $5);
- }
- | id_scope see_typename '&' type_quals after_type_declarator
- { tree t;
- t = $$;
- while (TREE_OPERAND (t, 1))
- t = TREE_OPERAND (t, 1);
- TREE_OPERAND (t, 1) = build_parse_node (ADDR_EXPR, $5);
- }
- ;
-
/* For C++, decls and stmts can be intermixed, so we don't need to
have a special rule that won't start parsing the stmt section
until we have a stmt that parses without errors. */
ansi_except_stmts:
/* empty */
{ $$ = NULL_TREE; }
- | ansi_except_stmts CATCH '(' typename optional_identifier ')'
+ | ansi_except_stmts CATCH '(' type_id optional_identifier ')'
{
tree type = groktypename ($4);
if (IS_SIGNATURE (type))
In C++, declaring a function with no parameters
means that that function takes *no* parameters. */
+
parmlist: /* empty */
{
if (strict_prototype)
else
$$ = NULL_TREE;
}
- | parms
+ | complex_parmlist
+ | type_id
+ { $$ = tree_cons (NULL_TREE, $$, void_list_node);
+ TREE_PARMLIST ($$) = 1; }
+ ;
+
+/* This nonterminal does not include the common sequence '(' type_id ')',
+ as it is ambiguous and must be disambiguated elsewhere. */
+complex_parmlist:
+ parms
{
$$ = chainon ($$, void_list_node);
TREE_PARMLIST ($$) = 1;
}
- | parms ',' ELLIPSIS
+ | parms_comma ELLIPSIS
{
TREE_PARMLIST ($$) = 1;
}
{
TREE_PARMLIST ($$) = 1;
}
+ | type_id ELLIPSIS
+ {
+ $$ = build_tree_list (NULL_TREE, $$);
+ TREE_PARMLIST ($$) = 1;
+ }
| ELLIPSIS
{
/* ARM $8.2.5 has this as a boxed-off comment. */
{
TREE_PARMLIST ($$) = 1;
}
+ | type_id TYPENAME_ELLIPSIS
+ {
+ $$ = build_tree_list (NULL_TREE, $$);
+ TREE_PARMLIST ($$) = 1;
+ }
| parms ':'
{
/* This helps us recover from really nasty
yyungetc (':', 0);
yychar = ')';
}
+ | type_id ':'
+ {
+ /* This helps us recover from really nasty
+ parse errors, for example, a missing right
+ parenthesis. */
+ yyerror ("possibly missing ')'");
+ $$ = tree_cons (NULL_TREE, $$, void_list_node);
+ TREE_PARMLIST ($$) = 1;
+ yyungetc (':', 0);
+ yychar = ')';
+ }
;
/* A nonempty list of parameter declarations or type names. */
parms:
- parm
+ named_parm
{ $$ = build_tree_list (NULL_TREE, $$); }
| parm '=' init
{ $$ = build_tree_list ($3, $$); }
- | parms ',' parm
- { $$ = chainon ($$, build_tree_list (NULL_TREE, $3)); }
- | parms ',' parm '=' init
- { $$ = chainon ($$, build_tree_list ($5, $3)); }
- | parms ',' bad_parm
- { $$ = chainon ($$, build_tree_list (NULL_TREE, $3)); }
- | parms ',' bad_parm '=' init
- { $$ = chainon ($$, build_tree_list ($5, $3)); }
+ | parms_comma parm
+ { $$ = chainon ($$, build_tree_list (NULL_TREE, $2)); }
+ | parms_comma parm '=' init
+ { $$ = chainon ($$, build_tree_list ($4, $2)); }
+ | parms_comma bad_parm
+ { $$ = chainon ($$, build_tree_list (NULL_TREE, $2)); }
+ | parms_comma bad_parm '=' init
+ { $$ = chainon ($$, build_tree_list ($4, $2)); }
+ ;
+
+parms_comma:
+ parms ','
+ | type_id ','
+ { $$ = build_tree_list (NULL_TREE, $$); }
;
/* A single parameter declaration or parameter type name,
as found in a parmlist. The first four cases make up for 10%
of the time spent parsing C++. We cannot use them because
of `int id[]' which won't get parsed properly. */
-parm:
+named_parm:
/*
typed_declspecs dont_see_typename '*' IDENTIFIER
{ $$ = build_tree_list ($$, build_parse_node (INDIRECT_REF, $4));
{ $$ = build_tree_list ($$, build_parse_node (ADDR_EXPR, $4));
see_typename (); }
| TYPENAME IDENTIFIER
- { $$ = build_tree_list (list_hash_lookup_or_cons ($$), $2); }
+ { $$ = build_tree_list (get_decl_list ($$), $2); }
| TYPESPEC IDENTIFIER
- { $$ = build_tree_list (list_hash_lookup_or_cons ($$), $2); }
+ { $$ = build_tree_list (get_decl_list ($$), $2); }
| */
- typed_declspecs dont_see_typename abs_or_notype_decl
- { $$ = build_tree_list ($$, $3);
+ /* Here we expand typed_declspecs inline to avoid mis-parsing of
+ TYPESPEC IDENTIFIER. */
+ typed_declspecs1 declarator
+ { $$ = build_tree_list ($$, $2);
+ see_typename (); }
+ | typed_typespecs declarator
+ { $$ = build_tree_list ($$, $2);
+ see_typename (); }
+ | typespec declarator
+ { $$ = build_tree_list (get_decl_list ($$), $2);
+ see_typename (); }
+ | typed_declspecs1 absdcl
+ { $$ = build_tree_list ($$, $2);
+ see_typename (); }
+ | typed_declspecs1 %prec EMPTY
+ { $$ = build_tree_list ($$, NULL_TREE);
see_typename (); }
- | declmods dont_see_typename abs_or_notype_decl
- { $$ = build_tree_list ($$, $3);
+ | declmods notype_declarator
+ { $$ = build_tree_list ($$, $2);
see_typename (); }
;
-abs_or_notype_decl: absdcl
- | notype_declarator
- | START_DECLARATOR notype_declarator
- { $$ = $2; }
+parm:
+ named_parm
+ | type_id
;
-see_typename: type_quals
+see_typename: %prec EMPTY
{ see_typename (); }
;
-dont_see_typename: %prec EMPTY /* empty */
+/*
+dont_see_typename: %prec EMPTY
{ dont_see_typename (); }
- ;
+ ;
-/*
try_for_typename:
{
if ($<ttype>-1 == error_mark_node)
*/
bad_parm:
- abs_or_notype_decl
+ /* empty */ %prec EMPTY
+ {
+ warning ("type specifier omitted for parameter");
+ $$ = build_tree_list (TREE_PURPOSE (TREE_VALUE ($<ttype>-1)), NULL_TREE);
+ }
+ | notype_declarator
{
warning ("type specifier omitted for parameter");
$$ = build_tree_list (TREE_PURPOSE (TREE_VALUE ($<ttype>-1)), $$);
;
ansi_raise_identifier:
- typename
+ type_id
{ $$ = build_decl_list (NULL_TREE, $$); }
;
}
;
+conversion_declarator:
+ /* empty */ %prec EMPTY
+ { $$ = NULL_TREE; }
+ | '*' type_quals conversion_declarator
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '&' type_quals conversion_declarator
+ { $$ = make_reference_declarator ($2, $3); }
+ | id_scope '*' type_quals conversion_declarator
+ { tree arg = make_pointer_declarator ($3, $4);
+ if (TREE_CODE ($$) != SCOPE_REF)
+ $$ = build_push_scope ($$, arg);
+ else if (TREE_OPERAND ($$, 1) == NULL_TREE)
+ TREE_OPERAND ($$, 1) = arg;
+ else
+ $$ = build_parse_node (SCOPE_REF, $$, arg);
+ }
+ ;
+
operator_name:
OPERATOR '*'
{ $$ = ansi_opname[MULT_EXPR]; }
{ $$ = ansi_opname[ARRAY_REF]; }
| OPERATOR NEW
{ $$ = ansi_opname[NEW_EXPR]; }
-/*
- | OPERATOR NEW '[' ']'
- { $$ = ansi_opname[VEC_NEW_EXPR]; }
-*/
| OPERATOR DELETE
{ $$ = ansi_opname[DELETE_EXPR]; }
-/*
+/* | OPERATOR NEW '[' ']'
+ { $$ = ansi_opname[VEC_NEW_EXPR]; }
| OPERATOR DELETE '[' ']'
- { $$ = ansi_opname[VEC_DELETE_EXPR]; }
-*/
-
- /* These should do `groktypename' and set up TREE_HAS_X_CONVERSION
- here, rather than doing it in class.c . */
- | OPERATOR typed_typespecs absdcl
- { $$ = build1 (TYPE_EXPR, $2, $3); }
+ { $$ = ansi_opname[VEC_DELETE_EXPR]; } */
+ | OPERATOR typed_typespecs conversion_declarator
+ { $$ = grokoptypename ($2, $3); }
| OPERATOR error
{ $$ = ansi_opname[ERROR_MARK]; }
;
D1 is template header; D2 is class_head_sans_basetype or a
TEMPLATE_DECL with its DECL_RESULT field set. */
void
-end_template_decl (d1, d2, is_class)
+end_template_decl (d1, d2, is_class, defn)
tree d1, d2, is_class;
+ int defn;
{
tree decl;
struct template_info *tmpl;
}
DECL_TEMPLATE_INFO (decl) = tmpl;
DECL_TEMPLATE_PARMS (decl) = d1;
-lose:
- if (decl)
+
+ /* So that duplicate_decls can do the right thing. */
+ if (defn)
+ DECL_INITIAL (decl) = error_mark_node;
+
+ /* If context of decl is non-null (i.e., method template), add it
+ to the appropriate class template, and pop the binding levels. */
+ if (! DECL_TEMPLATE_IS_CLASS (decl)
+ && DECL_CONTEXT (DECL_TEMPLATE_RESULT (decl)) != NULL_TREE)
{
- /* If context of decl is non-null (i.e., method template), add it
- to the appropriate class template, and pop the binding levels. */
- if (! DECL_TEMPLATE_IS_CLASS (decl)
- && DECL_CONTEXT (DECL_TEMPLATE_RESULT (decl)) != NULL_TREE)
+ tree ctx = DECL_CONTEXT (DECL_TEMPLATE_RESULT (decl));
+ tree tmpl;
+ my_friendly_assert (TREE_CODE (ctx) == UNINSTANTIATED_P_TYPE, 266);
+ tmpl = UPT_TEMPLATE (ctx);
+ DECL_TEMPLATE_MEMBERS (tmpl) =
+ perm_tree_cons (DECL_NAME (decl), decl,
+ DECL_TEMPLATE_MEMBERS (tmpl));
+ poplevel (0, 0, 0);
+ poplevel (0, 0, 0);
+ }
+ /* Otherwise, go back to top level first, and push the template decl
+ again there. */
+ else
+ {
+ poplevel (0, 0, 0);
+ poplevel (0, 0, 0);
+ if (TREE_TYPE (decl))
{
- tree ctx = DECL_CONTEXT (DECL_TEMPLATE_RESULT (decl));
- tree tmpl;
- my_friendly_assert (TREE_CODE (ctx) == UNINSTANTIATED_P_TYPE, 266);
- tmpl = UPT_TEMPLATE (ctx);
- DECL_TEMPLATE_MEMBERS (tmpl) =
- perm_tree_cons (DECL_NAME (decl), decl,
- DECL_TEMPLATE_MEMBERS (tmpl));
- poplevel (0, 0, 0);
- poplevel (0, 0, 0);
+ /* Function template */
+ tree t = IDENTIFIER_GLOBAL_VALUE (DECL_NAME (decl));
+ if (t && is_overloaded_fn (t))
+ for (t = get_first_fn (t); t; t = DECL_CHAIN (t))
+ if (TREE_CODE (t) == TEMPLATE_DECL
+ && duplicate_decls (decl, t))
+ decl = t;
+ push_overloaded_decl (decl, 0);
}
- /* Otherwise, go back to top level first, and push the template decl
- again there. */
else
- {
- poplevel (0, 0, 0);
- poplevel (0, 0, 0);
- if (TREE_TYPE (decl)
- && IDENTIFIER_GLOBAL_VALUE (DECL_NAME (decl)) != NULL_TREE)
- push_overloaded_decl (decl, 0);
- else
- pushdecl (decl);
- }
+ pushdecl (decl);
}
+ lose:
#if 0 /* It happens sometimes, with syntactic or semantic errors.
One specific case:
poplevel (0, 0, 0);
}
\f
-/* Should be defined in cp-parse.h. */
+/* Should be defined in parse.h. */
extern int yychar;
int
extract_interface_info ();
}
\f
-/* Store away the text of an inline template function. No rtl is
- generated for this function until it is actually needed. */
+/* Store away the text of an template. */
void
reinit_parse_for_template (yychar, d1, d2)
tree d1, d2;
{
struct template_info *template_info;
- extern struct obstack inline_text_obstack; /* see comment in cp-lex.c */
+ extern struct obstack inline_text_obstack; /* see comment in lex.c */
if (d2 == NULL_TREE || d2 == error_mark_node)
{
my_friendly_assert (TREE_CODE (tparms) == TREE_VEC, 289);
my_friendly_assert (TREE_CODE (parms) == TREE_LIST, 290);
- /* ARGS could be NULL (via a call from cp-parse.y to
+ /* ARGS could be NULL (via a call from parse.y to
build_x_function_call). */
if (args)
my_friendly_assert (TREE_CODE (args) == TREE_LIST, 291);
type = BINFO_TYPE (binfo);
else if (TREE_CODE (binfo) == RECORD_TYPE)
type = binfo;
+ else if (TREE_CODE (binfo) == UNION_TYPE)
+ return NULL_TREE;
else
my_friendly_abort (90);
}
else
{
- int same_object = tree_int_cst_equal (BINFO_OFFSET (*new_binfo_ptr),
- BINFO_OFFSET (binfo));
-
+ int same_object = (tree_int_cst_equal (BINFO_OFFSET (*new_binfo_ptr),
+ BINFO_OFFSET (binfo))
+ && *via_virtual_ptr && via_virtual);
+
if (*via_virtual_ptr && via_virtual==0)
{
*rval_private_ptr = is_private;
tree addr;
tree vtbl = BINFO_VTABLE (vbases);
tree init = build_unary_op (ADDR_EXPR, vtbl, 0);
- assemble_external (vtbl);
+ if (!flag_vtable_hack)
+ assemble_external (vtbl);
TREE_USED (vtbl) = 1;
if (use_computed_offsets)
dfs_get_vbase_types (binfo)
tree binfo;
{
- tree binfos = BINFO_BASETYPES (binfo);
- tree type = BINFO_TYPE (binfo);
- tree these_vbase_types = CLASSTYPE_VBASECLASSES (type);
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
- if (these_vbase_types)
- {
- while (these_vbase_types)
- {
- tree this_type = BINFO_TYPE (these_vbase_types);
-
- /* We really need to start from a fresh copy of this
- virtual basetype! CLASSTYPE_MARKED2 is the shortcut
- for BINFO_VBASE_MARKED. */
- if (! CLASSTYPE_MARKED2 (this_type))
- {
- vbase_types = make_binfo (integer_zero_node,
- this_type,
- TYPE_BINFO_VTABLE (this_type),
- TYPE_BINFO_VIRTUALS (this_type),
- vbase_types);
- TREE_VIA_VIRTUAL (vbase_types) = 1;
- SET_CLASSTYPE_MARKED2 (this_type);
- }
- these_vbase_types = TREE_CHAIN (these_vbase_types);
- }
- }
- else for (i = 0; i < n_baselinks; i++)
+ if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo))
{
- tree base_binfo = TREE_VEC_ELT (binfos, i);
- if (TREE_VIA_VIRTUAL (base_binfo) && ! BINFO_VBASE_MARKED (base_binfo))
- {
- vbase_types = make_binfo (integer_zero_node, BINFO_TYPE (base_binfo),
- BINFO_VTABLE (base_binfo),
- BINFO_VIRTUALS (base_binfo), vbase_types);
- TREE_VIA_VIRTUAL (vbase_types) = 1;
- SET_BINFO_VBASE_MARKED (base_binfo);
- }
+ vbase_types = make_binfo (integer_zero_node, BINFO_TYPE (binfo),
+ BINFO_VTABLE (binfo),
+ BINFO_VIRTUALS (binfo), vbase_types);
+ TREE_VIA_VIRTUAL (vbase_types) = 1;
+ SET_BINFO_VBASE_MARKED (binfo);
}
SET_BINFO_MARKED (binfo);
}
-/* Some virtual baseclasses might be virtual baseclasses for
- other virtual baseclasses. We sort the virtual baseclasses
- topologically: in the list returned, the first virtual base
- classes have no virtual baseclasses themselves, and any entry
- on the list has no dependency on virtual base classes later in the
- list. */
+/* get a list of virtual base classes in dfs order. */
tree
get_vbase_types (type)
tree type;
{
- tree ordered_vbase_types = NULL_TREE, prev, next;
tree vbases;
+ tree binfo;
+
+ if (TREE_CODE (type) == TREE_VEC)
+ binfo = type;
+ else
+ binfo = TYPE_BINFO (type);
vbase_types = NULL_TREE;
- dfs_walk (TYPE_BINFO (type), dfs_get_vbase_types, unmarkedp);
- dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp);
+ dfs_walk (binfo, dfs_get_vbase_types, unmarkedp);
+ dfs_walk (binfo, dfs_unmark, markedp);
/* Rely upon the reverse dfs ordering from dfs_get_vbase_types, and now
reverse it so that we get normal dfs ordering. */
vbase_types = nreverse (vbase_types);
- /* Almost all of the below is not needed now. We should be able to just
- return vbase_types directly... (mrs) */
- while (vbase_types)
- {
- /* Now sort these types. This is essentially a bubble merge. */
-
- /* Farm out virtual baseclasses which have no marked ancestors. */
- for (vbases = vbase_types, prev = NULL_TREE;
- vbases; vbases = next)
- {
- next = TREE_CHAIN (vbases);
- /* If VBASES does not have any vbases itself, or it's
- topologically safe, it goes into the sorted list. */
- if (1 /* ANSI C++ specifies dfs ordering now. */
- || ! CLASSTYPE_VBASECLASSES (BINFO_TYPE (vbases))
- || BINFO_VBASE_MARKED (vbases) == 0)
- {
- if (prev)
- TREE_CHAIN (prev) = TREE_CHAIN (vbases);
- else
- vbase_types = TREE_CHAIN (vbases);
- TREE_CHAIN (vbases) = NULL_TREE;
- ordered_vbase_types = chainon (ordered_vbase_types, vbases);
- CLEAR_BINFO_VBASE_MARKED (vbases);
- }
- else
- prev = vbases;
- }
-
- /* Now unmark types all of whose ancestors are now on the
- `ordered_vbase_types' list. */
- for (vbases = vbase_types; vbases; vbases = TREE_CHAIN (vbases))
- {
- /* If all our virtual baseclasses are unmarked, ok. */
- tree t = CLASSTYPE_VBASECLASSES (BINFO_TYPE (vbases));
- while (t && (BINFO_VBASE_MARKED (t) == 0
- || ! CLASSTYPE_VBASECLASSES (BINFO_TYPE (t))))
- t = TREE_CHAIN (t);
- if (t == NULL_TREE)
- CLEAR_BINFO_VBASE_MARKED (vbases);
- }
- }
+ /* unmark marked vbases */
+ for (vbases = vbase_types; vbases; vbases = TREE_CHAIN (vbases))
+ CLEAR_BINFO_VBASE_MARKED (vbases);
- return ordered_vbase_types;
+ return vbase_types;
}
\f
static void
/* This file is the type analyzer for GNU C++. To debug it, define SPEW_DEBUG
- when compiling cp-parse.c and cp-spew.c. */
+ when compiling parse.c and spew.c. */
#include "config.h"
#include <stdio.h>
static tree hack_ptype ();
static tree hack_more_ids ();
-/* From cp-lex.c: */
+/* From lex.c: */
/* the declaration found for the last IDENTIFIER token read in.
yylex must look this up to detect typedefs, which get token type TYPENAME,
so it is left around in case the identifier is not a typedef but is
static char follows_identifier[END_OF_SAVED_INPUT+1];
/* This is a hack!!! TEMPLATE_TYPE_SEEN_BEFORE_SCOPE consists of the name
- * of the last template_type parsed in cp-parse.y if it is followed by a
+ * of the last template_type parsed in parse.y if it is followed by a
* scope operator. It will be reset inside the next invocation of yylex().
* This is used for recognizing nested types inside templates.
* - niklas@appli.se */
return nlevels != 0 && lp != 0;
}
-/* from cp-lex.c: */
+/* from lex.c: */
/* Value is 1 if we should try to make the next identifier look like a
typename (when it may be a local variable or a class variable).
Value is 0 if we treat this name in a default fashion.
{
/* Sync back again, leaving SCOPE on the token stream, because we
* failed to substitute the original SCOPE token with a
- * SCOPED_TYPENAME. See rule "template_type" in cp-parse.y */
+ * SCOPED_TYPENAME. See rule "template_type" in parse.y */
consume_token ();
}
else
goto retry;
case IDENTIFIER:
- /* Note: this calls arbitrate_lookup. */
trrr = lookup_name (tmp_token.yylval.ttype, -2);
if (trrr)
{
case TYPESPEC:
consume_token ();
finish_typename_processing:
+#if 0
/* Now see if we should insert a START_DECLARATOR token.
Here are the cases caught:
nth_token (0)->yychar = START_DECLARATOR;
}
}
+#endif
break;
#if 0
return rt;
}
+#if 0
/* When this function is called, nth_token(0) is the current
token we are scanning. This means that the next token we'll
scan is nth_token (1). Usually the next token we'll scan
return t;
}
}
+#endif
/* now returns decl_node */
debug_yychar (yy)
int yy;
{
- /* In cp-parse.y: */
+ /* In parse.y: */
extern char *debug_yytranslate ();
int i;
case OFFSET_REF:
if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
return 1;
- if (TREE_CODE (TREE_OPERAND (ref, 1)) == VAR_DECL)
- if (TREE_READONLY (ref) && ! TREE_STATIC (ref)
- && DECL_LANG_SPECIFIC (ref)
- && DECL_IN_AGGR_P (ref))
- return 0;
- else
- return 1;
+ return lvalue_p (TREE_OPERAND (ref, 0))
+ && lvalue_p (TREE_OPERAND (ref, 1));
break;
case ADDR_EXPR:
hash_chainon (TREE_CHAIN (list1), list2));
}
-tree
-get_decl_list (value)
+static tree
+get_identifier_list (value)
tree value;
{
- tree list = NULL_TREE;
-
- if (TREE_CODE (value) == IDENTIFIER_NODE)
+ tree list = IDENTIFIER_AS_LIST (value);
+ if (list != NULL_TREE
+ && (TREE_CODE (list) != TREE_LIST
+ || TREE_VALUE (list) != value))
+ list = NULL_TREE;
+ else if (IDENTIFIER_HAS_TYPE_VALUE (value)
+ && TREE_CODE (IDENTIFIER_TYPE_VALUE (value)) == RECORD_TYPE)
{
- list = IDENTIFIER_AS_LIST (value);
- if (list != NULL_TREE
- && (TREE_CODE (list) != TREE_LIST
- || TREE_VALUE (list) != value))
+ tree type = IDENTIFIER_TYPE_VALUE (value);
+
+ if (TYPE_PTRMEMFUNC_P (type))
list = NULL_TREE;
- else if (IDENTIFIER_HAS_TYPE_VALUE (value)
- && TREE_CODE (IDENTIFIER_TYPE_VALUE (value)) == RECORD_TYPE)
+ else if (type == current_class_type)
+ /* Don't mess up the constructor name. */
+ list = tree_cons (NULL_TREE, value, NULL_TREE);
+ else
{
register tree id;
- tree type = IDENTIFIER_TYPE_VALUE (value);
-
- if (TYPE_PTRMEMFUNC_P (type))
- list = NULL_TREE;
+ /* This will return the correct thing for regular types,
+ nested types, and templates. Yay! */
+ if (TYPE_NESTED_NAME (type))
+ id = TYPE_NESTED_NAME (type);
else
- {
- /* This will return the correct thing for regular types,
- nested types, and templates. Yay! */
- if (DECL_NESTED_TYPENAME (TYPE_NAME (type)))
- value = DECL_NESTED_TYPENAME (TYPE_NAME (type));
- id = value;
-
- if (CLASSTYPE_ID_AS_LIST (type) == NULL_TREE)
- CLASSTYPE_ID_AS_LIST (type) = perm_tree_cons (NULL_TREE,
- id, NULL_TREE);
- list = CLASSTYPE_ID_AS_LIST (type);
- }
+ id = TYPE_IDENTIFIER (type);
+
+ if (CLASSTYPE_ID_AS_LIST (type) == NULL_TREE)
+ CLASSTYPE_ID_AS_LIST (type)
+ = perm_tree_cons (NULL_TREE, id, NULL_TREE);
+ list = CLASSTYPE_ID_AS_LIST (type);
}
}
+ return list;
+}
+
+tree
+get_decl_list (value)
+ tree value;
+{
+ tree list = NULL_TREE;
+
+ if (TREE_CODE (value) == IDENTIFIER_NODE)
+ list = get_identifier_list (value);
else if (TREE_CODE (value) == RECORD_TYPE
&& TYPE_LANG_SPECIFIC (value))
list = CLASSTYPE_AS_LIST (value);
tree list = NULL_TREE;
if (TREE_CODE (value) == IDENTIFIER_NODE)
- {
- list = IDENTIFIER_AS_LIST (value);
- if (list != NULL_TREE
- && (TREE_CODE (list) != TREE_LIST
- || TREE_VALUE (list) != value))
- list = NULL_TREE;
- else if (IDENTIFIER_HAS_TYPE_VALUE (value)
- && TREE_CODE (IDENTIFIER_TYPE_VALUE (value)) == RECORD_TYPE)
- {
- /* If the type name and constructor name are different, don't
- write constructor name into type. */
- if (identifier_typedecl_value (value)
- && identifier_typedecl_value (value) != constructor_name (value))
- list = tree_cons (NULL_TREE, value, NULL_TREE);
- else
- {
- tree type = IDENTIFIER_TYPE_VALUE (value);
- if (TYPE_PTRMEMFUNC_P (type))
- list = NULL_TREE;
- else
- {
- if (CLASSTYPE_ID_AS_LIST (type) == NULL_TREE)
- {
- /* Not just `value', which could be a template parm. */
- tree id = DECL_NAME (TYPE_NAME (type));
- CLASSTYPE_ID_AS_LIST (type) =
- perm_tree_cons (NULL_TREE, id, NULL_TREE);
- }
- list = CLASSTYPE_ID_AS_LIST (type);
- }
- }
- }
- }
+ list = get_identifier_list (value);
else if (TREE_CODE (value) == TYPE_DECL
&& TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE
&& TYPE_LANG_SPECIFIC (TREE_TYPE (value)))
t1 = type_for_size (TYPE_PRECISION (t1), 1);
if (TREE_CODE (t2) == ENUMERAL_TYPE)
t2 = type_for_size (TYPE_PRECISION (t2), 1);
- }
- if (t1 == t2)
- return 1;
+ if (t1 == t2)
+ return 1;
+ }
/* Different classes of types can't be compatible. */
/* Target types must match incl. qualifiers. */
return comp_array_types (comptypes, t1, t2, strict);
+ case TEMPLATE_TYPE_PARM:
+ return 1;
}
return 0;
}
tree e2;
tree e3;
tree aref, vtbl;
+ tree aux_delta;
- vtbl = build1 (ADDR_EXPR, ptr_type_node, instance);
+ /* convert down to the right base, before using the instance. */
+ instance = convert_pointer_to_real (TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)),
+ build_unary_op (ADDR_EXPR, instance, 0));
+ if (instance == error_mark_node)
+ return instance;
+
+ vtbl = convert_pointer_to (ptr_type_node, instance);
vtbl = build (PLUS_EXPR,
build_pointer_type (build_pointer_type (vtable_entry_type)),
vtbl, convert (sizetype, delta2));
val = integer_zero_node;
}
}
+ else if (TREE_CODE (val) == OFFSET_REF
+ && TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)
+ {
+ /* This is unclean. Should be handled elsewhere. */
+ val = build_unary_op (ADDR_EXPR, val, 0);
+ }
else if (TREE_CODE (val) == OFFSET_REF)
val = resolve_offset_ref (val);
}
else
index1 = integer_neg_one_node;
- op1 = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type0), op1);
+ {
+ tree nop1 = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type0), op1);
+ TREE_CONSTANT (nop1) = TREE_CONSTANT (op1);
+ op1 = nop1;
+ }
e1 = build_binary_op (EQ_EXPR, index0, index1, 1);
e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node, 1);
e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2, build_binary_op (EQ_EXPR, delta20, delta21, 1), 1);
if (TREE_CODE (field) == FIELD_DECL
&& TYPE_USES_COMPLEX_INHERITANCE (basetype))
- /* Can't convert directly to ARGTYPE, since that
- may have the same pointer type as one of our
- baseclasses. */
- rval = build1 (NOP_EXPR, argtype,
- convert_pointer_to (basetype, rval));
+ {
+ /* Can't convert directly to ARGTYPE, since that
+ may have the same pointer type as one of our
+ baseclasses. */
+ rval = build1 (NOP_EXPR, argtype,
+ convert_pointer_to (basetype, rval));
+ TREE_CONSTANT (rval) == TREE_CONSTANT (TREE_OPERAND (rval, 0));
+ }
else
/* This conversion is harmless. */
rval = convert (argtype, rval);
}
}
- /* When converting into a reference type, just convert into a pointer to
- the new type and deference it. While this is not exactly what ARM 5.4
- calls for [why not? -jason], it is pretty close for now.
- (int &)ri ---> *(int*)&ri */
- if (TREE_CODE (type) == REFERENCE_TYPE)
- {
- value = build_unary_op (ADDR_EXPR, value, 0);
- if (value != error_mark_node)
- value = convert (build_pointer_type (TREE_TYPE (type)), value);
- if (value != error_mark_node)
- value = build_indirect_ref (value, "reference conversion");
- return value;
- }
-
if (IS_SIGNATURE (type))
{
error ("cast specifies signature type");
return 1;
}
\f
+/* Get differnce in deltas for different pointer to member function
+ types. Return inetger_zero_node, if FROM cannot be converted to a
+ TO type. If FORCE is true, then allow reverse conversions as well. */
+static tree
+get_delta_difference (from, to, force)
+ tree from, to;
+{
+ tree delta = integer_zero_node;
+ tree binfo;
+
+ if (to == from)
+ return delta;
+
+ binfo = get_binfo (from, to, 1);
+ if (binfo == error_mark_node)
+ {
+ error (" in pointer to member function conversion");
+ return delta;
+ }
+ if (binfo == 0)
+ {
+ if (!force)
+ {
+ error_not_base_type (from, to);
+ error (" in pointer to member function conversion");
+ return delta;
+ }
+ binfo = get_binfo (to, from, 1);
+ if (binfo == error_mark_node)
+ {
+ error (" in pointer to member function conversion");
+ return delta;
+ }
+ if (binfo == 0)
+ {
+ error ("cannot convert pointer to member of type %T to unrelated pointer to member of type %T", from, to);
+ return delta;
+ }
+ if (TREE_VIA_VIRTUAL (binfo))
+ {
+ warning ("pointer to member conversion from virtual base class will only work if your very careful");
+ }
+ return fold (size_binop (MINUS_EXPR,
+ integer_zero_node,
+ BINFO_OFFSET (binfo)));
+ }
+ if (TREE_VIA_VIRTUAL (binfo))
+ {
+ warning ("pointer to member conversion from virtual base class will only work if your very careful");
+ }
+ return BINFO_OFFSET (binfo);
+}
+
/* Build a constructor for a pointer to member function. It can be
used to initialize global variables, local variable, or used
as a value in expressions. TYPE is the POINTER to METHOD_TYPE we
If FORCE is non-zero, then force this conversion, even if
we would rather not do it. Usually set when using an explicit
- cast. */
+ cast.
+
+ Return error_mark_node, if something goes wrong. */
tree
build_ptrmemfunc (type, pfn, force)
tree type, pfn;
int force;
{
- tree index;
+ tree index = integer_zero_node;
tree delta = integer_zero_node;
tree delta2 = integer_zero_node;
tree vfield_offset;
tree npfn;
tree u;
- /* Handle null pointer to member function conversions. */
- if (integer_zerop (pfn))
- {
- pfn = build_c_cast (type, integer_zero_node);
- u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, pfn, NULL_TREE));
- return build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, integer_zero_node,
- tree_cons (NULL_TREE, integer_zero_node,
- tree_cons (NULL_TREE, u, NULL_TREE))));
- }
-
- /* Allow pointer to member conversions here. */
- if (type != TREE_TYPE (pfn))
+ /* Handle multiple conversions of pointer to member fucntions. */
+ if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
{
- tree binfo
- = get_binfo (TYPE_METHOD_BASETYPE (TREE_TYPE (TREE_TYPE (pfn))),
- TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
- 1);
- if (binfo == error_mark_node)
- {
- error (" in pointer to member function conversion");
- return NULL_TREE;
- }
- if (binfo == 0)
+ tree ndelta, ndelta2, nindex;
+ /* Is is already the right type? */
+#if 0
+ /* Sorry, can't do this, the backend is too stupid. */
+ if (TYPE_METHOD_BASETYPE (TREE_TYPE (type))
+ == TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))))
{
- if (!force)
+ if (type != TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))
{
- error_not_base_type (TYPE_METHOD_BASETYPE (TREE_TYPE (TREE_TYPE (pfn))),
- TYPE_METHOD_BASETYPE (TREE_TYPE (type)));
- error (" in pointer to member function conversion");
- return NULL_TREE;
+ npfn = build1 (NOP_EXPR, TYPE_GET_PTRMEMFUNC_TYPE (type), pfn);
+ TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
}
- /* Just something handy with an offset of zero. */
- binfo = TYPE_BINFO (TYPE_METHOD_BASETYPE (TREE_TYPE (type)));
+ return pfn;
}
- if (TREE_VIA_VIRTUAL (binfo))
+#else
+ if (type == TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))
+ return pfn;
+#endif
+
+ if (TREE_CODE (pfn) != CONSTRUCTOR)
{
- sorry ("pointer to member conversion from virtual base class");
+ tree e1, e2, e3;
+ ndelta = convert (sizetype, build_component_ref (pfn, delta_identifier, 0, 0));
+ ndelta2 = convert (sizetype, DELTA2_FROM_PTRMEMFUNC (pfn));
+ index = build_component_ref (pfn, index_identifier, 0, 0);
+ delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))),
+ TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
+ force);
+ delta = fold (size_binop (PLUS_EXPR, delta, ndelta));
+ delta2 = fold (size_binop (PLUS_EXPR, ndelta2, delta2));
+ e1 = fold (build (GT_EXPR, integer_type_node, index, integer_zero_node));
+
+ u = build_nt (CONSTRUCTOR, 0, tree_cons (delta2_identifier, delta2, NULL_TREE));
+ u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
+ tree_cons (NULL_TREE, index,
+ tree_cons (NULL_TREE, u, NULL_TREE))));
+ e2 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+
+ pfn = PFN_FROM_PTRMEMFUNC (pfn);
+ npfn = build1 (NOP_EXPR, type, pfn);
+ TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+
+ u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, npfn, NULL_TREE));
+ u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
+ tree_cons (NULL_TREE, index,
+ tree_cons (NULL_TREE, u, NULL_TREE))));
+ e3 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+ return build_conditional_expr (e1, e2, e3);
+ }
+
+ ndelta = TREE_VALUE (CONSTRUCTOR_ELTS (pfn));
+ nindex = TREE_VALUE (TREE_CHAIN (CONSTRUCTOR_ELTS (pfn)));
+ npfn = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CONSTRUCTOR_ELTS (pfn))));
+ npfn = TREE_VALUE (CONSTRUCTOR_ELTS (npfn));
+ if (integer_zerop (nindex))
+ pfn = integer_zero_node;
+ else
+ {
+ sorry ("value casting of varible nonnull pointer to member functions not supported");
+ return error_mark_node;
}
- delta = BINFO_OFFSET (binfo);
- delta2 = size_binop (PLUS_EXPR, delta2, delta);
}
-
+
+ /* Handle null pointer to member function conversions. */
+ if (integer_zerop (pfn))
+ {
+ pfn = build_c_cast (type, integer_zero_node);
+ u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, pfn, NULL_TREE));
+ u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, integer_zero_node,
+ tree_cons (NULL_TREE, integer_zero_node,
+ tree_cons (NULL_TREE, u, NULL_TREE))));
+ return digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+ }
+
+ /* Allow pointer to member conversions here. */
+ delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TREE_TYPE (pfn))),
+ TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
+ force);
+ delta2 = fold (size_binop (PLUS_EXPR, delta2, delta));
if (TREE_CODE (TREE_OPERAND (pfn, 0)) != FUNCTION_DECL)
warning ("assuming pointer to member function is non-virtual");
&& DECL_VINDEX (TREE_OPERAND (pfn, 0)))
{
/* Find the offset to the vfield pointer in the object. */
- vfield_offset = TYPE_METHOD_BASETYPE (TREE_TYPE (TREE_TYPE (pfn)));
- vfield_offset = CLASSTYPE_VFIELD (vfield_offset);
- vfield_offset = DECL_FIELD_BITPOS (vfield_offset);
- vfield_offset = size_binop (FLOOR_DIV_EXPR, vfield_offset, size_int (BITS_PER_UNIT));
+ vfield_offset = get_binfo (DECL_CONTEXT (TREE_OPERAND (pfn, 0)),
+ DECL_CLASS_CONTEXT (TREE_OPERAND (pfn, 0)),
+ 0);
+ vfield_offset = get_vfield_offset (vfield_offset);
delta2 = size_binop (PLUS_EXPR, vfield_offset, delta2);
/* Map everything down one to make room for the null pointer to member. */
DECL_VINDEX (TREE_OPERAND (pfn, 0)),
integer_one_node);
u = build_nt (CONSTRUCTOR, 0, tree_cons (delta2_identifier, delta2, NULL_TREE));
-
- return build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
- tree_cons (NULL_TREE, index,
- tree_cons (NULL_TREE, u, NULL_TREE))));
}
else
- index = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
+ {
+ index = fold (size_binop (MINUS_EXPR, integer_zero_node, integer_one_node));
- npfn = build1 (NOP_EXPR, type, pfn);
- TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+ npfn = build1 (NOP_EXPR, type, pfn);
+ TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
- u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, npfn, NULL_TREE));
+ u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, npfn, NULL_TREE));
+ }
- return build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
- tree_cons (NULL_TREE, index,
- tree_cons (NULL_TREE, u, NULL_TREE))));
+ u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
+ tree_cons (NULL_TREE, index,
+ tree_cons (NULL_TREE, u, NULL_TREE))));
+ return digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
}
/* Convert value RHS to type TYPE as preparation for an assignment
else
pedwarn ("ANSI C++ forbids implicit conversion from `void *' in %s",
errtype);
- else if (pedantic
- && ((TYPE_MAIN_VARIANT (ttl) == void_type_node
- && (TREE_CODE (ttr) == FUNCTION_TYPE
- || TREE_CODE (ttr) == METHOD_TYPE))
- ||
- (TYPE_MAIN_VARIANT (ttr) == void_type_node
- && (TREE_CODE (ttl) == FUNCTION_TYPE
- || TREE_CODE (ttl) == METHOD_TYPE))))
- {
- if (fndecl)
- cp_pedwarn ("passing `%T' as argument %P of `%D'",
- rhstype, parmnum, fndecl);
- else
- cp_pedwarn ("%s to `void *' from `%T'", errtype, rhstype);
- }
/* Const and volatile mean something different for function types,
so the usual warnings are not appropriate. */
else if ((TREE_CODE (ttr) != FUNCTION_TYPE && TREE_CODE (ttr) != METHOD_TYPE)
else if (((coder == POINTER_TYPE && TREE_CODE (rhs) == ADDR_EXPR
&& TREE_CODE (rhstype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (rhstype)) == METHOD_TYPE)
- || integer_zerop (rhs))
+ || integer_zerop (rhs)
+ || TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
&& TYPE_PTRMEMFUNC_P (type))
{
/* compatible pointer to member functions. */
- rhs = build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), rhs, 0);
- if (rhs == 0)
- return error_mark_node;
- return digest_init (type, rhs, (tree *)0);
+ return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), rhs, 0);
}
else if (codel == ERROR_MARK || coder == ERROR_MARK)
return error_mark_node;
/* Force an abort. */
my_friendly_assert (codel != REFERENCE_TYPE, 317);
else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (rhs)))
- return build1 (NOP_EXPR, type, rhs);
+ {
+ tree nrhs = build1 (NOP_EXPR, type, rhs);
+ TREE_CONSTANT (nrhs) = TREE_CONSTANT (rhs);
+ return nrhs;
+ }
else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs)))
return convert (type, rhs);
if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE)
rhs = convert_from_reference (rhs);
if (type != rhstype)
- return build1 (NOP_EXPR, type, rhs);
+ {
+ tree nrhs = build1 (NOP_EXPR, type, rhs);
+ TREE_CONSTANT (nrhs) = TREE_CONSTANT (rhs);
+ rhs = nrhs;
+ }
return rhs;
}
silly. So instead, we just do the equivalent of a call to fatal in the
same situation (call exit). */
-/* First used: 0 (reserved), Last used: 355. Free: 5. */
+/* First used: 0 (reserved), Last used: 355. */
static int abortcount = 0;
if (TREE_CODE (init) == NON_LVALUE_EXPR)
init = TREE_OPERAND (init, 0);
+ if (init && TREE_TYPE (init) && TYPE_PTRMEMFUNC_P (type))
+ init = default_conversion (init);
+
if (init && TYPE_PTRMEMFUNC_P (type)
&& ((TREE_CODE (init) == ADDR_EXPR
&& TREE_CODE (TREE_TYPE (init)) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (TREE_TYPE (init))) == METHOD_TYPE)
- || integer_zerop (init)))
+ || integer_zerop (init)
+ || (TREE_TYPE (init) && TYPE_PTRMEMFUNC_P (TREE_TYPE (init)))))
{
- init = build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), init, 0);
+ return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), init, 0);
}
raw_constructor = TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == 0;
{
tree tail1 = tail;
- if (TYPE_PTRMEMFUNC_P (TREE_TYPE (field)))
- {
- tree t
- = build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (field)),
- default_conversion (TREE_VALUE (tail)),
- 0);
- if (t == NULL_TREE)
- return error_mark_node;
- next1 = digest_init (TREE_TYPE (field), t, &tail1);
- }
- else
- next1 = digest_init (TREE_TYPE (field),
- TREE_VALUE (tail), &tail1);
+ next1 = digest_init (TREE_TYPE (field),
+ TREE_VALUE (tail), &tail1);
my_friendly_assert (tail1 == 0
|| TREE_CODE (tail1) == TREE_LIST, 320);
tail = tail1;
if (datum == error_mark_node || component == error_mark_node)
return error_mark_node;
- if (! IS_AGGR_TYPE (objtype))
- {
- cp_error ("cannot apply member pointer `%D' to `%E'", component, datum);
- cp_error ("which is of non-aggregate type `%T'", objtype);
- return error_mark_node;
- }
-
if (TREE_CODE (type) != OFFSET_TYPE && TREE_CODE (type) != METHOD_TYPE)
{
- error ("non-member type composed with object");
+ cp_error ("`%E' cannot be used as a member pointer, since it is of type `%T'", component, type);
return error_mark_node;
}
if (TREE_CODE (objtype) == REFERENCE_TYPE)
objtype = TREE_TYPE (objtype);
+ if (! IS_AGGR_TYPE (objtype))
+ {
+ cp_error ("cannot apply member pointer `%E' to `%E'", component, datum);
+ cp_error ("which is of non-aggregate type `%T'", objtype);
+ return error_mark_node;
+ }
+
if (! comptypes (TYPE_METHOD_BASETYPE (type), objtype, 0))
{
cp_error ("member type `%T::' incompatible with object type `%T'",