C++ PATCH for cp_finish_decl
Mark Mitchell
mark@codesourcery.com
Sat Aug 28 18:38:00 GMT 1999
This patch just splits cp_finish_decl (which was imposing at 800
lines) into more manageable chunks. I also removed some dead code,
replacing it with assertions of deadness.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
1999-08-28 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (strip_array_types): New function.
* decl.c (maybe_deduce_size_from_array_init): New function, split
out from cp_finish_decl.
(layout_var_decl): Likewise.
(maybe_commonize_var): Likewise.
(maybe_inject_for_scope_var): Likewise.
(initialize_local_var): Likewise.
(build_cleanup_on_safe_obstack): Likewise.
(check_initializer): Likewise.
(make_rtl_for_nonlocal_decl): Likewise.
(cp_finish_decl): Use them.
* typeck.c (strip_array_types): New function.
Index: cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.274
diff -c -p -r1.274 cp-tree.h
*** cp-tree.h 1999/08/29 00:51:31 1.274
--- cp-tree.h 1999/08/29 01:32:16
*************** extern tree c_expand_start_case PROTO(
*** 3574,3579 ****
--- 3574,3580 ----
extern int comp_ptr_ttypes PROTO((tree, tree));
extern int ptr_reasonably_similar PROTO((tree, tree));
extern tree build_ptrmemfunc PROTO((tree, tree, int));
+ extern tree strip_array_types PROTO((tree));
extern int cp_type_quals PROTO((tree));
extern int cp_has_mutable_p PROTO((tree));
extern int at_least_as_qualified_p PROTO((tree, tree));
Index: decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.419
diff -c -p -r1.419 decl.c
*** decl.c 1999/08/28 21:45:27 1.419
--- decl.c 1999/08/29 01:32:25
*************** static void add_decl_to_level PROTO((tre
*** 193,198 ****
--- 193,206 ----
static tree make_label_decl PROTO((tree, int));
static void pop_label PROTO((tree));
static void pop_labels PROTO((tree));
+ static void maybe_deduce_size_from_array_init PROTO((tree, tree));
+ static void layout_var_decl PROTO((tree, tree *));
+ static void maybe_commonize_var PROTO((tree));
+ static void maybe_inject_for_scope_var PROTO((tree));
+ static void initialize_local_var PROTO((tree, tree, tree, int));
+ static tree build_cleanup_on_safe_obstack PROTO((tree));
+ static void check_initializer PROTO((tree, tree *));
+ static void make_rtl_for_nonlocal_decl PROTO((tree, tree, const char *));
#if defined (DEBUG_CP_BINDING_LEVELS)
static void indent PROTO((void));
*************** obscure_complex_init (decl, init)
*** 7315,7320 ****
--- 7323,7529 ----
return init;
}
+ /* When parsing `int a[] = {1, 2};' we don't know the size of the
+ array until we finish parsing the initializer. If that's the
+ situation we're in, update DECL accordingly. */
+
+ static void
+ maybe_deduce_size_from_array_init (decl, init)
+ tree decl;
+ tree init;
+ {
+ tree type = TREE_TYPE (decl);
+
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && TYPE_DOMAIN (type) == NULL_TREE
+ && TREE_CODE (decl) != TYPE_DECL)
+ {
+ int do_default
+ = (TREE_STATIC (decl)
+ /* Even if pedantic, an external linkage array
+ may have incomplete type at first. */
+ ? pedantic && ! DECL_EXTERNAL (decl)
+ : !DECL_EXTERNAL (decl));
+ tree initializer = init ? init : DECL_INITIAL (decl);
+ int failure = complete_array_type (type, initializer, do_default);
+
+ if (failure == 1)
+ cp_error ("initializer fails to determine size of `%D'", decl);
+
+ if (failure == 2)
+ {
+ if (do_default)
+ cp_error ("array size missing in `%D'", decl);
+ /* If a `static' var's size isn't known, make it extern as
+ well as static, so it does not get allocated. If it's not
+ `static', then don't mark it extern; finish_incomplete_decl
+ will give it a default size and it will get allocated. */
+ else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (decl))
+ DECL_EXTERNAL (decl) = 1;
+ }
+
+ if (pedantic && TYPE_DOMAIN (type) != NULL_TREE
+ && tree_int_cst_lt (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
+ integer_zero_node))
+ cp_error ("zero-size array `%D'", decl);
+
+ layout_decl (decl, 0);
+ }
+ }
+
+ /* Set DECL_SIZE, DECL_ALIGN, etc. for DECL (a VAR_DECL), and issue
+ any appropriate error messages regarding the layout. INITP is a
+ pointer to the initializer for DECL; the initializer may be
+ modified by this function. */
+
+ static void
+ layout_var_decl (decl, initp)
+ tree decl;
+ tree *initp;
+ {
+ tree ttype = target_type (TREE_TYPE (decl));
+
+ if (DECL_SIZE (decl) == NULL_TREE
+ && TYPE_SIZE (complete_type (TREE_TYPE (decl))) != NULL_TREE)
+ layout_decl (decl, 0);
+
+ if (TREE_STATIC (decl) && DECL_SIZE (decl) == NULL_TREE)
+ {
+ /* A static variable with an incomplete type:
+ that is an error if it is initialized.
+ Otherwise, let it through, but if it is not `extern'
+ then it may cause an error message later. */
+ if (DECL_INITIAL (decl) != NULL_TREE)
+ cp_error ("storage size of `%D' isn't known", decl);
+ *initp = NULL_TREE;
+ }
+ else if (!DECL_EXTERNAL (decl) && DECL_SIZE (decl) == NULL_TREE)
+ {
+ /* An automatic variable with an incomplete type: that is an error.
+ Don't talk about array types here, since we took care of that
+ message in grokdeclarator. */
+ cp_error ("storage size of `%D' isn't known", decl);
+ TREE_TYPE (decl) = error_mark_node;
+ }
+ else if (!DECL_EXTERNAL (decl) && IS_AGGR_TYPE (ttype))
+ /* Let debugger know it should output info for this type. */
+ note_debug_info_needed (ttype);
+
+ if (TREE_STATIC (decl) && DECL_CLASS_SCOPE_P (decl))
+ note_debug_info_needed (DECL_CONTEXT (decl));
+
+ if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl))
+ && DECL_SIZE (decl) != NULL_TREE
+ && ! TREE_CONSTANT (DECL_SIZE (decl)))
+ {
+ if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST)
+ constant_expression_warning (DECL_SIZE (decl));
+ else
+ cp_error ("storage size of `%D' isn't constant", decl);
+ }
+ }
+
+ /* Return a cleanup for DECL, created on whatever obstack is
+ appropriate. */
+
+ static tree
+ build_cleanup_on_safe_obstack (decl)
+ tree decl;
+ {
+ tree cleanup;
+ tree type;
+ int need_pop;
+
+ type = TREE_TYPE (decl);
+
+ /* Only variables get cleaned up. */
+ if (TREE_CODE (decl) != VAR_DECL)
+ return NULL_TREE;
+
+ /* And only things with destructors need cleaning up. */
+ if (!TYPE_NEEDS_DESTRUCTOR (type))
+ return NULL_TREE;
+
+ if (TREE_CODE (decl) == VAR_DECL &&
+ (DECL_EXTERNAL (decl) || TREE_STATIC (decl)))
+ /* We don't clean up things that aren't defined in this
+ translation unit, or that need a static cleanup. The latter
+ are handled by finish_file. */
+ return NULL_TREE;
+
+ /* Switch to an obstack that will live until the point where the
+ cleanup code is actually expanded. */
+ need_pop = suspend_momentary ();
+
+ /* Compute the cleanup. */
+ cleanup = maybe_build_cleanup (decl);
+
+ /* Pop back to the obstack we were on before. */
+ resume_momentary (need_pop);
+
+ return cleanup;
+ }
+
+ /* If a local static variable is declared in an inline function, or if
+ we have a weak definition, we must endeavor to create only one
+ instance of the variable at link-time. */
+
+ static void
+ maybe_commonize_var (decl)
+ tree decl;
+ {
+ /* Static data in a function with comdat linkage also has comdat
+ linkage. */
+ if (TREE_STATIC (decl)
+ /* Don't mess with __FUNCTION__. */
+ && ! TREE_ASM_WRITTEN (decl)
+ && current_function_decl
+ && DECL_CONTEXT (decl) == current_function_decl
+ && (DECL_THIS_INLINE (current_function_decl)
+ || DECL_TEMPLATE_INSTANTIATION (current_function_decl))
+ && TREE_PUBLIC (current_function_decl))
+ {
+ /* Rather than try to get this right with inlining, we suppress
+ inlining of such functions. */
+ current_function_cannot_inline
+ = "function with static variable cannot be inline";
+
+ /* If flag_weak, we don't need to mess with this, as we can just
+ make the function weak, and let it refer to its unique local
+ copy. This works because we don't allow the function to be
+ inlined. */
+ if (! flag_weak)
+ {
+ if (DECL_INTERFACE_KNOWN (current_function_decl))
+ {
+ TREE_PUBLIC (decl) = 1;
+ DECL_EXTERNAL (decl) = DECL_EXTERNAL (current_function_decl);
+ }
+ else if (DECL_INITIAL (decl) == NULL_TREE
+ || DECL_INITIAL (decl) == error_mark_node)
+ {
+ TREE_PUBLIC (decl) = 1;
+ DECL_COMMON (decl) = 1;
+ }
+ /* else we lose. We can only do this if we can use common,
+ which we can't if it has been initialized. */
+
+ if (TREE_PUBLIC (decl))
+ DECL_ASSEMBLER_NAME (decl)
+ = build_static_name (current_function_decl, DECL_NAME (decl));
+ else if (! DECL_ARTIFICIAL (decl))
+ {
+ cp_warning_at ("sorry: semantics of inline function static data `%#D' are wrong (you'll wind up with multiple copies)", decl);
+ cp_warning_at (" you can work around this by removing the initializer", decl);
+ }
+ }
+ }
+ else if (DECL_LANG_SPECIFIC (decl) && DECL_COMDAT (decl))
+ /* Set it up again; we might have set DECL_INITIAL since the last
+ time. */
+ comdat_linkage (decl);
+ }
+
/* Issue an error message if DECL is an uninitialized const variable. */
static void
*************** check_for_uninitialized_const_var (decl)
*** 7334,7339 ****
--- 7543,7869 ----
cp_error ("uninitialized const `%D'", decl);
}
+ /* Verify INITP (the initializer for DECL), and record the
+ initialization in DECL_INITIAL, if appropriate. The initializer
+ may be modified by this function. */
+
+ static void
+ check_initializer (decl, initp)
+ tree decl;
+ tree *initp;
+ {
+ tree init;
+ tree type;
+
+ if (TREE_CODE (decl) == FIELD_DECL)
+ return;
+
+ type = TREE_TYPE (decl);
+ init = *initp;
+
+ /* If `start_decl' didn't like having an initialization, ignore it now. */
+ if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE)
+ init = NULL_TREE;
+ else if (DECL_EXTERNAL (decl))
+ ;
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ if (TREE_STATIC (decl))
+ make_decl_rtl (decl, NULL_PTR, toplevel_bindings_p ());
+ grok_reference_init (decl, type, init);
+ init = NULL_TREE;
+ }
+
+ /* Check for certain invalid initializations. */
+ if (init)
+ {
+ if (TYPE_SIZE (type) && !TREE_CONSTANT (TYPE_SIZE (type)))
+ {
+ cp_error ("variable-sized object `%D' may not be initialized", decl);
+ init = NULL_TREE;
+ }
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && !TYPE_SIZE (complete_type (TREE_TYPE (type))))
+ {
+ cp_error ("elements of array `%#D' have incomplete type", decl);
+ init = NULL_TREE;
+ }
+ }
+
+ if (TREE_CODE (decl) == CONST_DECL)
+ {
+ my_friendly_assert (TREE_CODE (decl) != REFERENCE_TYPE, 148);
+
+ DECL_INITIAL (decl) = init;
+
+ /* This will keep us from needing to worry about our obstacks. */
+ my_friendly_assert (init != NULL_TREE, 149);
+ init = NULL_TREE;
+ }
+ else if (init)
+ {
+ if (TYPE_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type))
+ {
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ init = digest_init (type, init, (tree *) 0);
+ else if (TREE_CODE (init) == CONSTRUCTOR
+ && TREE_HAS_CONSTRUCTOR (init))
+ {
+ if (TYPE_NON_AGGREGATE_CLASS (type))
+ {
+ cp_error ("`%D' must be initialized by constructor, not by `{...}'",
+ decl);
+ init = error_mark_node;
+ }
+ else
+ goto dont_use_constructor;
+ }
+ }
+ else
+ {
+ dont_use_constructor:
+ if (TREE_CODE (init) != TREE_VEC)
+ init = store_init_value (decl, init);
+ }
+
+ if (init)
+ /* We must hide the initializer so that expand_decl
+ won't try to do something it does not understand. */
+ init = obscure_complex_init (decl, init);
+ }
+ else if (DECL_EXTERNAL (decl))
+ ;
+ else if (TREE_CODE_CLASS (TREE_CODE (type)) == 't'
+ && (IS_AGGR_TYPE (type) || TYPE_NEEDS_CONSTRUCTING (type)))
+ {
+ tree core_type = strip_array_types (type);
+
+ if (! TYPE_NEEDS_CONSTRUCTING (core_type))
+ {
+ if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type))
+ cp_error ("structure `%D' with uninitialized const members", decl);
+ if (CLASSTYPE_REF_FIELDS_NEED_INIT (core_type))
+ cp_error ("structure `%D' with uninitialized reference members",
+ decl);
+ }
+
+ check_for_uninitialized_const_var (decl);
+
+ if (TYPE_SIZE (type) != NULL_TREE
+ && TYPE_NEEDS_CONSTRUCTING (type))
+ init = obscure_complex_init (decl, NULL_TREE);
+
+ }
+ else
+ check_for_uninitialized_const_var (decl);
+
+ /* Store the modified initializer for our caller. */
+ *initp = init;
+ }
+
+ /* If DECL is not a local variable, give it RTL. */
+
+ static void
+ make_rtl_for_nonlocal_decl (decl, init, asmspec)
+ tree decl;
+ tree init;
+ const char *asmspec;
+ {
+ int was_temp;
+ int toplev;
+ tree type;
+
+ type = TREE_TYPE (decl);
+ toplev = toplevel_bindings_p ();
+ was_temp = (TREE_STATIC (decl) && TYPE_NEEDS_DESTRUCTOR (type)
+ && allocation_temporary_p ());
+ if (was_temp)
+ end_temporary_allocation ();
+
+ if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
+ make_decl_rtl (decl, NULL_PTR, toplev);
+ else if (TREE_CODE (decl) == VAR_DECL
+ && TREE_READONLY (decl)
+ && DECL_INITIAL (decl) != NULL_TREE
+ && DECL_INITIAL (decl) != error_mark_node
+ && ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl)))
+ {
+ DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl));
+
+ if (asmspec)
+ DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
+
+ if (! toplev
+ && TREE_STATIC (decl)
+ && ! TREE_SIDE_EFFECTS (decl)
+ && ! TREE_PUBLIC (decl)
+ && ! DECL_EXTERNAL (decl)
+ && ! TYPE_NEEDS_DESTRUCTOR (type)
+ && DECL_MODE (decl) != BLKmode)
+ {
+ /* If this variable is really a constant, then fill its DECL_RTL
+ slot with something which won't take up storage.
+ If something later should take its address, we can always give
+ it legitimate RTL at that time. */
+ DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl));
+ store_expr (DECL_INITIAL (decl), DECL_RTL (decl), 0);
+ TREE_ASM_WRITTEN (decl) = 1;
+ }
+ else if (toplev && ! TREE_PUBLIC (decl))
+ {
+ /* If this is a static const, change its apparent linkage
+ if it belongs to a #pragma interface. */
+ if (!interface_unknown)
+ {
+ TREE_PUBLIC (decl) = 1;
+ DECL_EXTERNAL (decl) = interface_only;
+ }
+ make_decl_rtl (decl, asmspec, toplev);
+ }
+ else
+ rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
+ }
+ else if (TREE_CODE (decl) == VAR_DECL
+ && DECL_LANG_SPECIFIC (decl)
+ && DECL_IN_AGGR_P (decl))
+ {
+ my_friendly_assert (TREE_STATIC (decl), 19990828);
+
+ if (init == NULL_TREE
+ #ifdef DEFAULT_STATIC_DEFS
+ /* If this code is dead, then users must
+ explicitly declare static member variables
+ outside the class def'n as well. */
+ && TYPE_NEEDS_CONSTRUCTING (type)
+ #endif
+ )
+ {
+ DECL_EXTERNAL (decl) = 1;
+ make_decl_rtl (decl, asmspec, 1);
+ }
+ else
+ rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
+ }
+ else
+ rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
+
+ if (was_temp)
+ resume_temporary_allocation ();
+ }
+
+ /* The old ARM scoping rules injected variables declared in the
+ initialization statement of a for-statement into the surrounding
+ scope. We support this usage, in order to be backward-compatible.
+ DECL is a just-declared VAR_DECL; if necessary inject its
+ declaration into the surrounding scope. */
+
+ static void
+ maybe_inject_for_scope_var (decl)
+ tree decl;
+ {
+ if (current_binding_level->is_for_scope)
+ {
+ struct binding_level *outer
+ = current_binding_level->level_chain;
+
+ /* Check to see if the same name is already bound at the outer
+ level, either because it was directly declared, or because a
+ dead for-decl got preserved. In either case, the code would
+ not have been valid under the ARM scope rules, so clear
+ is_for_scope for the current_binding_level.
+
+ Otherwise, we need to preserve the temp slot for decl to last
+ into the outer binding level. */
+
+ tree outer_binding
+ = TREE_CHAIN (IDENTIFIER_BINDING (DECL_NAME (decl)));
+
+ if (outer_binding && BINDING_LEVEL (outer_binding) == outer
+ && (TREE_CODE (BINDING_VALUE (outer_binding))
+ == VAR_DECL)
+ && DECL_DEAD_FOR_LOCAL (BINDING_VALUE (outer_binding)))
+ {
+ BINDING_VALUE (outer_binding)
+ = DECL_SHADOWED_FOR_VAR (BINDING_VALUE (outer_binding));
+ current_binding_level->is_for_scope = 0;
+ }
+ else if (DECL_IN_MEMORY_P (decl))
+ preserve_temp_slots (DECL_RTL (decl));
+ }
+ }
+
+ /* Generate code to initialized DECL (a local variable). */
+
+ static void
+ initialize_local_var (decl, init, cleanup, flags)
+ tree decl;
+ tree init;
+ tree cleanup;
+ int flags;
+ {
+ tree type;
+
+ type = TREE_TYPE (decl);
+ expand_start_target_temps ();
+
+ if (DECL_SIZE (decl) && type != error_mark_node)
+ {
+ int already_used;
+
+ /* Compute and store the initial value. */
+ expand_decl_init (decl);
+ already_used = TREE_USED (decl) || TREE_USED (type);
+
+ if (init || TYPE_NEEDS_CONSTRUCTING (type))
+ {
+ emit_line_note (DECL_SOURCE_FILE (decl),
+ DECL_SOURCE_LINE (decl));
+ /* We call push_momentary here so that when
+ finish_expr_stmt clears the momentary obstack it
+ doesn't destory any momentary expressions we may
+ have lying around. Although cp_finish_decl is
+ usually called at the end of a declaration
+ statement, it may also be called for a temporary
+ object in the middle of an expression. */
+ push_momentary ();
+ finish_expr_stmt (build_aggr_init (decl, init, flags));
+ pop_momentary ();
+ }
+
+ /* Set this to 0 so we can tell whether an aggregate which was
+ initialized was ever used. Don't do this if it has a
+ destructor, so we don't complain about the 'resource
+ allocation is initialization' idiom. */
+ /* Now set attribute((unused)) on types so decls of that type
+ will be marked used. (see TREE_USED, above.) This avoids the
+ warning problems this particular code tried to work
+ around. */
+
+ if (TYPE_NEEDS_CONSTRUCTING (type)
+ && ! already_used
+ && cleanup == NULL_TREE
+ && DECL_NAME (decl))
+ TREE_USED (decl) = 0;
+
+ if (already_used)
+ TREE_USED (decl) = 1;
+ }
+
+ /* Cleanup any temporaries needed for the initial value. */
+ expand_end_target_temps ();
+
+ if (DECL_SIZE (decl) && type != error_mark_node)
+ {
+ /* Store the cleanup, if there was one. */
+ if (cleanup)
+ {
+ if (! expand_decl_cleanup (decl, cleanup))
+ cp_error ("parser lost in parsing declaration of `%D'",
+ decl);
+ }
+ }
+ }
+
/* Finish processing of a declaration;
install its line number and initial value.
If the length of an array type is not known before,
*************** cp_finish_decl (decl, init, asmspec_tree
*** 7364,7376 ****
int flags;
{
register tree type;
! tree cleanup = NULL_TREE, ttype = NULL_TREE;
int was_incomplete;
int temporary = allocation_temporary_p ();
const char *asmspec = NULL;
int was_readonly = 0;
- int already_used = 0;
- tree core_type;
/* If this is 0, then we did not change obstacks. */
if (! decl)
--- 7894,7904 ----
int flags;
{
register tree type;
! tree ttype = NULL_TREE;
int was_incomplete;
int temporary = allocation_temporary_p ();
const char *asmspec = NULL;
int was_readonly = 0;
/* If this is 0, then we did not change obstacks. */
if (! decl)
*************** cp_finish_decl (decl, init, asmspec_tree
*** 7433,7438 ****
--- 7961,7969 ----
goto finish_end0;
}
+ /* Parameters are handled by store_parm_decls, not cp_finish_decl. */
+ my_friendly_assert (TREE_CODE (decl) != PARM_DECL, 19990828);
+
/* Take care of TYPE_DECLs up front. */
if (TREE_CODE (decl) == TYPE_DECL)
{
*************** cp_finish_decl (decl, init, asmspec_tree
*** 7478,7599 ****
TREE_READONLY (decl) = 0;
}
! if (TREE_CODE (decl) == FIELD_DECL)
{
! if (init && init != error_mark_node)
! my_friendly_assert (TREE_PERMANENT (init), 147);
!
! if (asmspec)
! {
! /* This must override the asm specifier which was placed
! by grokclassfn. Lay this out fresh. */
! DECL_RTL (TREE_TYPE (decl)) = NULL_RTX;
! DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
! make_decl_rtl (decl, asmspec, 0);
! }
}
- /* If `start_decl' didn't like having an initialization, ignore it now. */
- else if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE)
- init = NULL_TREE;
- else if (DECL_EXTERNAL (decl))
- ;
- else if (TREE_CODE (type) == REFERENCE_TYPE)
- {
- if (TREE_STATIC (decl))
- make_decl_rtl (decl, NULL_PTR, toplevel_bindings_p ());
- grok_reference_init (decl, type, init);
- init = NULL_TREE;
- }
! /* Check for certain invalid initializations. */
! if (init)
! {
! if (TYPE_SIZE (type) && !TREE_CONSTANT (TYPE_SIZE (type)))
! {
! cp_error ("variable-sized object `%D' may not be initialized", decl);
! init = NULL_TREE;
! }
! if (TREE_CODE (type) == ARRAY_TYPE
! && !TYPE_SIZE (complete_type (TREE_TYPE (type))))
! {
! cp_error ("elements of array `%#D' have incomplete type", decl);
! init = NULL_TREE;
! }
! }
GNU_xref_decl (current_function_decl, decl);
- core_type = type;
- while (TREE_CODE (core_type) == ARRAY_TYPE)
- core_type = TREE_TYPE (core_type);
-
- if (TREE_CODE (decl) == FIELD_DECL)
- ;
- else if (TREE_CODE (decl) == CONST_DECL)
- {
- my_friendly_assert (TREE_CODE (decl) != REFERENCE_TYPE, 148);
-
- DECL_INITIAL (decl) = init;
-
- /* This will keep us from needing to worry about our obstacks. */
- my_friendly_assert (init != NULL_TREE, 149);
- init = NULL_TREE;
- }
- else if (init)
- {
- if (TYPE_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type))
- {
- if (TREE_CODE (type) == ARRAY_TYPE)
- init = digest_init (type, init, (tree *) 0);
- else if (TREE_CODE (init) == CONSTRUCTOR
- && TREE_HAS_CONSTRUCTOR (init))
- {
- if (TYPE_NON_AGGREGATE_CLASS (type))
- {
- cp_error ("`%D' must be initialized by constructor, not by `{...}'",
- decl);
- init = error_mark_node;
- }
- else
- goto dont_use_constructor;
- }
- }
- else
- {
- dont_use_constructor:
- if (TREE_CODE (init) != TREE_VEC)
- init = store_init_value (decl, init);
- }
-
- if (init)
- /* We must hide the initializer so that expand_decl
- won't try to do something it does not understand. */
- init = obscure_complex_init (decl, init);
- }
- else if (DECL_EXTERNAL (decl))
- ;
- else if (TREE_CODE_CLASS (TREE_CODE (type)) == 't'
- && (IS_AGGR_TYPE (type) || TYPE_NEEDS_CONSTRUCTING (type)))
- {
- if (! TYPE_NEEDS_CONSTRUCTING (core_type))
- {
- if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type))
- cp_error ("structure `%D' with uninitialized const members", decl);
- if (CLASSTYPE_REF_FIELDS_NEED_INIT (core_type))
- cp_error ("structure `%D' with uninitialized reference members",
- decl);
- }
-
- check_for_uninitialized_const_var (decl);
-
- if (TYPE_SIZE (type) != NULL_TREE
- && TYPE_NEEDS_CONSTRUCTING (type))
- init = obscure_complex_init (decl, NULL_TREE);
-
- }
- else
- check_for_uninitialized_const_var (decl);
-
/* For top-level declaration, the initial value was read in
the temporary obstack. MAXINDEX, rtl, etc. to be made below
must go in the permanent obstack; but don't discard the
--- 8009,8027 ----
TREE_READONLY (decl) = 0;
}
! if (TREE_CODE (decl) == FIELD_DECL && asmspec)
{
! /* This must override the asm specifier which was placed by
! grokclassfn. Lay this out fresh. */
! DECL_RTL (TREE_TYPE (decl)) = NULL_RTX;
! DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
! make_decl_rtl (decl, asmspec, 0);
}
! check_initializer (decl, &init);
GNU_xref_decl (current_function_decl, decl);
/* For top-level declaration, the initial value was read in
the temporary obstack. MAXINDEX, rtl, etc. to be made below
must go in the permanent obstack; but don't discard the
*************** cp_finish_decl (decl, init, asmspec_tree
*** 7603,7704 ****
end_temporary_allocation ();
/* Deduce size of array from initialization, if not already known. */
- if (TREE_CODE (type) == ARRAY_TYPE
- && TYPE_DOMAIN (type) == NULL_TREE
- && TREE_CODE (decl) != TYPE_DECL)
- {
- int do_default
- = (TREE_STATIC (decl)
- /* Even if pedantic, an external linkage array
- may have incomplete type at first. */
- ? pedantic && ! DECL_EXTERNAL (decl)
- : !DECL_EXTERNAL (decl));
- tree initializer = init ? init : DECL_INITIAL (decl);
- int failure = complete_array_type (type, initializer, do_default);
-
- if (failure == 1)
- cp_error ("initializer fails to determine size of `%D'", decl);
-
- if (failure == 2)
- {
- if (do_default)
- cp_error ("array size missing in `%D'", decl);
- /* If a `static' var's size isn't known, make it extern as
- well as static, so it does not get allocated. If it's not
- `static', then don't mark it extern; finish_incomplete_decl
- will give it a default size and it will get allocated. */
- else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (decl))
- DECL_EXTERNAL (decl) = 1;
- }
-
- if (pedantic && TYPE_DOMAIN (type) != NULL_TREE
- && tree_int_cst_lt (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
- integer_zero_node))
- cp_error ("zero-size array `%D'", decl);
-
- layout_decl (decl, 0);
- }
-
if (TREE_CODE (decl) == VAR_DECL)
! {
! if (DECL_SIZE (decl) == NULL_TREE
! && TYPE_SIZE (complete_type (TREE_TYPE (decl))) != NULL_TREE)
! layout_decl (decl, 0);
!
! if (TREE_STATIC (decl) && DECL_SIZE (decl) == NULL_TREE)
! {
! /* A static variable with an incomplete type:
! that is an error if it is initialized.
! Otherwise, let it through, but if it is not `extern'
! then it may cause an error message later. */
! if (DECL_INITIAL (decl) != NULL_TREE)
! cp_error ("storage size of `%D' isn't known", decl);
! init = NULL_TREE;
! }
! else if (!DECL_EXTERNAL (decl) && DECL_SIZE (decl) == NULL_TREE)
! {
! /* An automatic variable with an incomplete type: that is an error.
! Don't talk about array types here, since we took care of that
! message in grokdeclarator. */
! cp_error ("storage size of `%D' isn't known", decl);
! TREE_TYPE (decl) = error_mark_node;
! }
! else if (!DECL_EXTERNAL (decl) && IS_AGGR_TYPE (ttype))
! /* Let debugger know it should output info for this type. */
! note_debug_info_needed (ttype);
!
! if (TREE_STATIC (decl) && DECL_CLASS_SCOPE_P (decl))
! note_debug_info_needed (DECL_CONTEXT (decl));
!
! if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl))
! && DECL_SIZE (decl) != NULL_TREE
! && ! TREE_CONSTANT (DECL_SIZE (decl)))
! {
! if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST)
! constant_expression_warning (DECL_SIZE (decl));
! else
! cp_error ("storage size of `%D' isn't constant", decl);
! }
!
! if (! DECL_EXTERNAL (decl) && TYPE_NEEDS_DESTRUCTOR (type)
! /* Cleanups for static variables are handled by `finish_file'. */
! && ! TREE_STATIC (decl))
! {
! int yes = suspend_momentary ();
! cleanup = maybe_build_cleanup (decl);
! resume_momentary (yes);
! }
! }
! /* PARM_DECLs get cleanups, too. */
! else if (TREE_CODE (decl) == PARM_DECL && TYPE_NEEDS_DESTRUCTOR (type))
! {
! if (temporary)
! end_temporary_allocation ();
! cleanup = maybe_build_cleanup (decl);
! if (temporary)
! resume_temporary_allocation ();
! }
/* Output the assembler code and/or RTL code for variables and functions,
unless the type is an undefined structure or union.
--- 8031,8040 ----
end_temporary_allocation ();
/* Deduce size of array from initialization, if not already known. */
+ maybe_deduce_size_from_array_init (decl, init);
if (TREE_CODE (decl) == VAR_DECL)
! layout_var_decl (decl, &init);
/* Output the assembler code and/or RTL code for variables and functions,
unless the type is an undefined structure or union.
*************** cp_finish_decl (decl, init, asmspec_tree
*** 7711,7856 ****
{
/* ??? FIXME: What about nested classes? */
int toplev = toplevel_bindings_p ();
- int was_temp
- = (TREE_STATIC (decl) && TYPE_NEEDS_DESTRUCTOR (type)
- && allocation_temporary_p ());
! if (was_temp)
! end_temporary_allocation ();
!
! /* Static data in a function with comdat linkage also has comdat
! linkage. */
! if (TREE_CODE (decl) == VAR_DECL
! && TREE_STATIC (decl)
! /* Don't mess with __FUNCTION__. */
! && ! TREE_ASM_WRITTEN (decl)
! && current_function_decl
! && DECL_CONTEXT (decl) == current_function_decl
! && (DECL_THIS_INLINE (current_function_decl)
! || DECL_TEMPLATE_INSTANTIATION (current_function_decl))
! && TREE_PUBLIC (current_function_decl))
! {
! /* Rather than try to get this right with inlining, we suppress
! inlining of such functions. */
! current_function_cannot_inline
! = "function with static variable cannot be inline";
!
! /* If flag_weak, we don't need to mess with this, as we can just
! make the function weak, and let it refer to its unique local
! copy. This works because we don't allow the function to be
! inlined. */
! if (! flag_weak)
! {
! if (DECL_INTERFACE_KNOWN (current_function_decl))
! {
! TREE_PUBLIC (decl) = 1;
! DECL_EXTERNAL (decl) = DECL_EXTERNAL (current_function_decl);
! }
! else if (DECL_INITIAL (decl) == NULL_TREE
! || DECL_INITIAL (decl) == error_mark_node)
! {
! TREE_PUBLIC (decl) = 1;
! DECL_COMMON (decl) = 1;
! }
! /* else we lose. We can only do this if we can use common,
! which we can't if it has been initialized. */
!
! if (TREE_PUBLIC (decl))
! DECL_ASSEMBLER_NAME (decl)
! = build_static_name (current_function_decl, DECL_NAME (decl));
! else if (! DECL_ARTIFICIAL (decl))
! {
! cp_warning_at ("sorry: semantics of inline function static data `%#D' are wrong (you'll wind up with multiple copies)", decl);
! cp_warning_at (" you can work around this by removing the initializer", decl);
! }
! }
! }
!
! else if (TREE_CODE (decl) == VAR_DECL
! && DECL_LANG_SPECIFIC (decl)
! && DECL_COMDAT (decl))
! /* Set it up again; we might have set DECL_INITIAL since the
! last time. */
! comdat_linkage (decl);
!
! if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
! make_decl_rtl (decl, NULL_PTR, toplev);
! else if (TREE_CODE (decl) == VAR_DECL
! && TREE_READONLY (decl)
! && DECL_INITIAL (decl) != NULL_TREE
! && DECL_INITIAL (decl) != error_mark_node
! && ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl)))
! {
! DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl));
!
! if (asmspec)
! DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
!
! if (! toplev
! && TREE_STATIC (decl)
! && ! TREE_SIDE_EFFECTS (decl)
! && ! TREE_PUBLIC (decl)
! && ! DECL_EXTERNAL (decl)
! && ! TYPE_NEEDS_DESTRUCTOR (type)
! && DECL_MODE (decl) != BLKmode)
! {
! /* If this variable is really a constant, then fill its DECL_RTL
! slot with something which won't take up storage.
! If something later should take its address, we can always give
! it legitimate RTL at that time. */
! DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl));
! store_expr (DECL_INITIAL (decl), DECL_RTL (decl), 0);
! TREE_ASM_WRITTEN (decl) = 1;
! }
! else if (toplev && ! TREE_PUBLIC (decl))
! {
! /* If this is a static const, change its apparent linkage
! if it belongs to a #pragma interface. */
! if (!interface_unknown)
! {
! TREE_PUBLIC (decl) = 1;
! DECL_EXTERNAL (decl) = interface_only;
! }
! make_decl_rtl (decl, asmspec, toplev);
! }
! else
! rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
! }
! else if (TREE_CODE (decl) == VAR_DECL
! && DECL_LANG_SPECIFIC (decl)
! && DECL_IN_AGGR_P (decl))
! {
! if (TREE_STATIC (decl))
! {
! if (init == NULL_TREE
! #ifdef DEFAULT_STATIC_DEFS
! /* If this code is dead, then users must
! explicitly declare static member variables
! outside the class def'n as well. */
! && TYPE_NEEDS_CONSTRUCTING (type)
! #endif
! )
! {
! DECL_EXTERNAL (decl) = 1;
! make_decl_rtl (decl, asmspec, 1);
! }
! else
! rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
! }
! else
! /* Just a constant field. Should not need any rtl. */
! goto finish_end0;
! }
! else
! rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
! if (was_temp)
! resume_temporary_allocation ();
! if (!abstract_virtuals_error (decl, core_type)
! && (TREE_CODE (type) == FUNCTION_TYPE
! || TREE_CODE (type) == METHOD_TYPE))
! abstract_virtuals_error (decl, TREE_TYPE (type));
if (TREE_CODE (decl) == FUNCTION_DECL)
;
--- 8047,8064 ----
{
/* ??? FIXME: What about nested classes? */
int toplev = toplevel_bindings_p ();
! if (TREE_CODE (decl) == VAR_DECL)
! maybe_commonize_var (decl);
! make_rtl_for_nonlocal_decl (decl, init, asmspec);
! if (TREE_CODE (type) == FUNCTION_TYPE
! || TREE_CODE (type) == METHOD_TYPE)
! abstract_virtuals_error (decl,
! strip_array_types (TREE_TYPE (type)));
! else
! abstract_virtuals_error (decl, strip_array_types (type));
if (TREE_CODE (decl) == FUNCTION_DECL)
;
*************** cp_finish_decl (decl, init, asmspec_tree
*** 7870,7875 ****
--- 8078,8085 ----
}
else if (! toplev)
{
+ tree cleanup = build_cleanup_on_safe_obstack (decl);
+
/* This is a declared decl which must live until the
end of the binding contour. It may need a cleanup. */
*************** cp_finish_decl (decl, init, asmspec_tree
*** 7903,7996 ****
cleanup = NULL_TREE;
}
}
-
- if (current_binding_level->is_for_scope)
- {
- struct binding_level *outer
- = current_binding_level->level_chain;
-
- /* Check to see if the same name is already bound at
- the outer level, either because it was directly declared,
- or because a dead for-decl got preserved. In either case,
- the code would not have been valid under the ARM
- scope rules, so clear is_for_scope for the
- current_binding_level.
! Otherwise, we need to preserve the temp slot for decl
! to last into the outer binding level. */
!
! tree outer_binding
! = TREE_CHAIN (IDENTIFIER_BINDING (DECL_NAME (decl)));
!
! if (outer_binding && BINDING_LEVEL (outer_binding) == outer
! && (TREE_CODE (BINDING_VALUE (outer_binding))
! == VAR_DECL)
! && DECL_DEAD_FOR_LOCAL (BINDING_VALUE (outer_binding)))
! {
! BINDING_VALUE (outer_binding)
! = DECL_SHADOWED_FOR_VAR (BINDING_VALUE (outer_binding));
! current_binding_level->is_for_scope = 0;
! }
! else if (DECL_IN_MEMORY_P (decl))
! preserve_temp_slots (DECL_RTL (decl));
! }
!
! expand_start_target_temps ();
!
! if (DECL_SIZE (decl) && type != error_mark_node)
! {
! /* Compute and store the initial value. */
! expand_decl_init (decl);
! already_used = TREE_USED (decl) || TREE_USED (type);
!
! if (init || TYPE_NEEDS_CONSTRUCTING (type))
! {
! emit_line_note (DECL_SOURCE_FILE (decl),
! DECL_SOURCE_LINE (decl));
! /* We call push_momentary here so that when
! finish_expr_stmt clears the momentary obstack it
! doesn't destory any momentary expressions we may
! have lying around. Although cp_finish_decl is
! usually called at the end of a declaration
! statement, it may also be called for a temporary
! object in the middle of an expression. */
! push_momentary ();
! finish_expr_stmt (build_aggr_init (decl, init, flags));
! pop_momentary ();
! }
!
! /* Set this to 0 so we can tell whether an aggregate which
! was initialized was ever used. Don't do this if it has a
! destructor, so we don't complain about the 'resource
! allocation is initialization' idiom. */
! /* Now set attribute((unused)) on types so decls of
! that type will be marked used. (see TREE_USED, above.)
! This avoids the warning problems this particular code
! tried to work around. */
!
! if (TYPE_NEEDS_CONSTRUCTING (type)
! && ! already_used
! && cleanup == NULL_TREE
! && DECL_NAME (decl))
! TREE_USED (decl) = 0;
!
! if (already_used)
! TREE_USED (decl) = 1;
! }
!
! /* Cleanup any temporaries needed for the initial value. */
! expand_end_target_temps ();
!
! if (DECL_SIZE (decl) && type != error_mark_node)
! {
! /* Store the cleanup, if there was one. */
! if (cleanup)
! {
! if (! expand_decl_cleanup (decl, cleanup))
! cp_error ("parser lost in parsing declaration of `%D'",
! decl);
! }
! }
}
finish_end0:
--- 8113,8121 ----
cleanup = NULL_TREE;
}
}
! maybe_inject_for_scope_var (decl);
! initialize_local_var (decl, init, cleanup, flags);
}
finish_end0:
*************** cp_finish_decl (decl, init, asmspec_tree
*** 8035,8046 ****
}
if (need_pop)
! {
! /* Resume permanent allocation, if not within a function. */
! /* The corresponding push_obstacks_nochange is in start_decl,
! start_method, groktypename, and in grokfield. */
! pop_obstacks ();
! }
if (was_readonly)
TREE_READONLY (decl) = 1;
--- 8160,8169 ----
}
if (need_pop)
! /* Resume permanent allocation, if not within a function. The
! corresponding push_obstacks_nochange is in start_decl,
! start_method, groktypename, and in grokfield. */
! pop_obstacks ();
if (was_readonly)
TREE_READONLY (decl) = 1;
Index: typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.198
diff -c -p -r1.198 typeck.c
*** typeck.c 1999/08/25 22:07:16 1.198
--- typeck.c 1999/08/29 01:32:29
*************** comp_ptr_ttypes_reinterpret (to, from)
*** 7167,7182 ****
}
}
! /* Returns the type-qualifier set corresponding to TYPE. */
! int
! cp_type_quals (type)
tree type;
{
while (TREE_CODE (type) == ARRAY_TYPE)
type = TREE_TYPE (type);
! return TYPE_QUALS (type);
}
/* Returns non-zero if the TYPE contains a mutable member */
--- 7167,7192 ----
}
}
! /* Recursively examines the array elements of TYPE, until a non-array
! element type is found. */
! tree
! strip_array_types (type)
tree type;
{
while (TREE_CODE (type) == ARRAY_TYPE)
type = TREE_TYPE (type);
+
+ return type;
+ }
+
+ /* Returns the type-qualifier set corresponding to TYPE. */
! int
! cp_type_quals (type)
! tree type;
! {
! return TYPE_QUALS (strip_array_types (type));
}
/* Returns non-zero if the TYPE contains a mutable member */
More information about the Gcc-patches
mailing list