This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for local-declaration processing
- To: gcc-patches at gcc dot gnu dot org
- Subject: C++ PATCH for local-declaration processing
- From: Mark Mitchell <mark at codesourcery dot com>
- Date: Sun, 29 Aug 1999 12:16:42 -0700
- Organization: CodeSourcery, LLC
This patch continues preparations for ordinary functions in
function-at-a-time mode by separating the semantic analysis required
for processing a local declaration from the process of generating RTL
and initializing it. It also fixes a regression which I introduced
last week, adds a test case for same, and introduces a couple of
assertions to verify critical assumptions.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
1999-08-29 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (TYPE_NEEDS_CONSTRUCTING): Remove #if 0'd definition.
(maybe_inject_for_scope_var): Declare it.
(initialize_local_var): Likewise.
* decl.c (maybe_inject_for_scope_var): Make it global.
(initialize_local_var): Likewise. Move cleanup handling here,
from cp_finish_decl.
(make_rtl_for_nonlocal_decl): Use
push_obstacks_nochange/pop_obstacks, rather than
end_temporary_allocation/resume_temporary_allocation.
(cp_finish_decl): Try to complete the type of a variable when it
is declared. Move cleanup-handling to initialize_local_var.
(expand_static_init): Use tree-building code, rather than
RTL-building code.
* decl2.c (get_temp_name): Assert non-initializedness of
temporaries.
* init.c (create_temporary_var): Move RTL-assigning code to ...
(get_temp_regvar): Here.
* pt.c (tsbust_expr): Fix indentation. Call cp_finish_decl here.
* semantics.c (expand_stmt): Don't call cp_finish_decl here. Just
call initialize_local_var to generate initialization code.
Index: testsuite/g++.old-deja/g++.pt/crash52.C
===================================================================
RCS file: crash52.C
diff -N crash52.C
*** /dev/null Sat Dec 5 20:30:03 1998
--- crash52.C Sun Aug 29 11:51:02 1999
***************
*** 0 ****
--- 1,25 ----
+ // Build don't link:
+ // Origin: Mark Mitchell <mark@codesourcery.com>
+
+ template <class T>
+ struct S1
+ {
+ template <class U>
+ struct S2
+ {
+ S2(U);
+ };
+
+ template <class U>
+ void f(U u)
+ {
+ S2<U> s2u(u);
+ }
+ };
+
+ void g()
+ {
+ S1<int> s1;
+ s1.f(3.0);
+ }
+
Index: cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.275
diff -c -p -r1.275 cp-tree.h
*** cp-tree.h 1999/08/29 01:39:00 1.275
--- cp-tree.h 1999/08/29 18:51:10
*************** extern int flag_new_for_scope;
*** 1690,1702 ****
/* Nonzero for _TYPE means that the _TYPE defines a destructor. */
#define TYPE_HAS_DESTRUCTOR(NODE) (TYPE_LANG_FLAG_2(NODE))
- #if 0
- /* Nonzero for _TYPE node means that creating an object of this type
- will involve a call to a constructor. This can apply to objects
- of ARRAY_TYPE if the type of the elements needs a constructor. */
- #define TYPE_NEEDS_CONSTRUCTING(NODE) ... defined in ../tree.h ...
- #endif
-
/* Nonzero means that an object of this type can not be initialized using
an initializer list. */
#define CLASSTYPE_NON_AGGREGATE(NODE) \
--- 1690,1695 ----
*************** extern tree start_decl PROTO((tree, t
*** 2936,2941 ****
--- 2929,2936 ----
extern void start_decl_1 PROTO((tree));
extern void cp_finish_decl PROTO((tree, tree, tree, int, int));
extern void finish_decl PROTO((tree, tree, tree));
+ extern void maybe_inject_for_scope_var PROTO((tree));
+ extern void initialize_local_var PROTO((tree, tree, int));
extern void expand_static_init PROTO((tree, tree));
extern int complete_array_type PROTO((tree, tree, int));
extern tree build_ptrmemfunc_type PROTO((tree));
Index: cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.420
diff -c -p -r1.420 decl.c
*** decl.c 1999/08/29 01:39:01 1.420
--- decl.c 1999/08/29 18:51:19
*************** static void pop_labels PROTO((tree));
*** 196,203 ****
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 *));
--- 196,201 ----
*************** make_rtl_for_nonlocal_decl (decl, init,
*** 7669,7684 ****
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);
--- 7667,7682 ----
tree init;
const char *asmspec;
{
int toplev;
tree type;
type = TREE_TYPE (decl);
toplev = toplevel_bindings_p ();
! push_obstacks_nochange ();
! if (TREE_STATIC (decl)
! && TYPE_NEEDS_DESTRUCTOR (type)
! && allocation_temporary_p ())
! end_temporary_allocation ();
if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
make_decl_rtl (decl, NULL_PTR, toplev);
*************** make_rtl_for_nonlocal_decl (decl, init,
*** 7747,7754 ****
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
--- 7745,7751 ----
else
rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
! pop_obstacks ();
}
/* The old ARM scoping rules injected variables declared in the
*************** make_rtl_for_nonlocal_decl (decl, init,
*** 7757,7763 ****
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;
{
--- 7754,7760 ----
DECL is a just-declared VAR_DECL; if necessary inject its
declaration into the surrounding scope. */
! void
maybe_inject_for_scope_var (decl)
tree decl;
{
*************** maybe_inject_for_scope_var (decl)
*** 7794,7809 ****
/* 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)
--- 7791,7824 ----
/* Generate code to initialized DECL (a local variable). */
! void
! initialize_local_var (decl, init, flags)
tree decl;
tree init;
int flags;
{
tree type;
+ tree cleanup;
type = TREE_TYPE (decl);
+
+ cleanup = build_cleanup_on_safe_obstack (decl);
+
+ if (DECL_SIZE (decl) == NULL_TREE && !TREE_STATIC (decl))
+ {
+ /* If we used it already as memory, it must stay in memory. */
+ DECL_INITIAL (decl) = NULL_TREE;
+ TREE_ADDRESSABLE (decl) = TREE_USED (decl);
+ }
+
+ if (DECL_RTL (decl))
+ /* Only a RESULT_DECL should have non-NULL RTL when arriving here.
+ All other local variables are assigned RTL in this function. */
+ my_friendly_assert (TREE_CODE (decl) == RESULT_DECL, 19990828);
+ else
+ /* Create RTL for this variable. */
+ expand_decl (decl);
+
expand_start_target_temps ();
if (DECL_SIZE (decl) && type != error_mark_node)
*************** initialize_local_var (decl, init, cleanu
*** 7811,7817 ****
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))
--- 7826,7831 ----
*************** initialize_local_var (decl, init, cleanu
*** 7829,7867 ****
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;
--- 7843,7875 ----
finish_expr_stmt (build_aggr_init (decl, init, flags));
pop_momentary ();
}
+ else
+ expand_decl_init (decl);
/* 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.) */
if (TYPE_NEEDS_CONSTRUCTING (type)
&& ! already_used
&& cleanup == NULL_TREE
&& DECL_NAME (decl))
TREE_USED (decl) = 0;
! else if (already_used)
TREE_USED (decl) = 1;
}
/* Cleanup any temporaries needed for the initial value. */
expand_end_target_temps ();
! /* Record the cleanup required for this declaration. */
! if (DECL_SIZE (decl)
! && type != error_mark_node
! && cleanup
! && !expand_decl_cleanup (decl, cleanup))
! cp_error ("parser lost in parsing declaration of `%D'", decl);
}
/* Finish processing of a declaration;
*************** cp_finish_decl (decl, init, asmspec_tree
*** 7895,7901 ****
{
register tree type;
tree ttype = NULL_TREE;
- int was_incomplete;
int temporary = allocation_temporary_p ();
const char *asmspec = NULL;
int was_readonly = 0;
--- 7903,7908 ----
*************** cp_finish_decl (decl, init, asmspec_tree
*** 7934,7947 ****
/* Leave the namespace of the object. */
pop_decl_namespace ();
}
-
- /* If the type of the thing we are declaring either has
- a constructor, or has a virtual function table pointer,
- AND its initialization was accepted by `start_decl',
- then we stayed on the permanent obstack through the
- declaration, otherwise, changed obstacks as GCC would. */
! type = TREE_TYPE (decl);
if (type == error_mark_node)
{
--- 7941,7948 ----
/* Leave the namespace of the object. */
pop_decl_namespace ();
}
! type = complete_type (TREE_TYPE (decl));
if (type == error_mark_node)
{
*************** cp_finish_decl (decl, init, asmspec_tree
*** 8039,8047 ****
/* Output the assembler code and/or RTL code for variables and functions,
unless the type is an undefined structure or union.
If not, it will get done when the type is completed. */
-
- was_incomplete = (DECL_SIZE (decl) == NULL_TREE);
-
if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == RESULT_DECL)
{
--- 8040,8045 ----
*************** cp_finish_decl (decl, init, asmspec_tree
*** 8078,8121 ****
}
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. */
!
! /* Recompute the RTL of a local array now
! if it used to be an incomplete type. */
! if (was_incomplete && ! TREE_STATIC (decl))
! {
! /* If we used it already as memory, it must stay in memory. */
! TREE_ADDRESSABLE (decl) = TREE_USED (decl);
! /* If it's still incomplete now, no init will save it. */
! if (DECL_SIZE (decl) == NULL_TREE)
! DECL_INITIAL (decl) = NULL_TREE;
! expand_decl (decl);
! }
! else if (! TREE_ASM_WRITTEN (decl)
! && (TYPE_SIZE (type) != NULL_TREE
! || TREE_CODE (type) == ARRAY_TYPE))
! {
! /* Do this here, because we did not expand this decl's
! rtl in start_decl. */
! if (DECL_RTL (decl) == NULL_RTX)
! expand_decl (decl);
! else if (cleanup)
! {
! /* XXX: Why don't we use decl here? */
! /* Ans: Because it was already expanded? */
! if (! expand_decl_cleanup (NULL_TREE, cleanup))
! cp_error ("parser lost in parsing declaration of `%D'",
! decl);
! /* Cleanup used up here. */
! cleanup = NULL_TREE;
! }
! }
!
maybe_inject_for_scope_var (decl);
! initialize_local_var (decl, init, cleanup, flags);
}
finish_end0:
--- 8076,8090 ----
}
else if (! toplev)
{
! /* This is a local declaration. */
maybe_inject_for_scope_var (decl);
! /* Initialize the local variable. But, if we're building a
! statement-tree, we'll do the initialization when we
! expand the tree. */
! if (!building_stmt_tree ())
! initialize_local_var (decl, init, flags);
! else if (init || DECL_INITIAL (decl) == error_mark_node)
! DECL_INITIAL (decl) = init;
}
finish_end0:
*************** expand_static_init (decl, init)
*** 8195,8200 ****
--- 8164,8170 ----
{
/* Emit code to perform this initialization but once. */
tree temp;
+ tree if_stmt;
tree assignment;
tree temp_init;
*************** expand_static_init (decl, init)
*** 8229,8236 ****
rest_of_decl_compilation (temp, NULL_PTR, 0, 0);
/* Begin the conditional initialization. */
! expand_start_cond (build_binary_op (EQ_EXPR, temp,
! integer_zero_node), 0);
/* Do the initialization itself. */
if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
--- 8199,8208 ----
rest_of_decl_compilation (temp, NULL_PTR, 0, 0);
/* Begin the conditional initialization. */
! if_stmt = begin_if_stmt ();
! finish_if_stmt_cond (build_binary_op (EQ_EXPR, temp,
! integer_zero_node),
! if_stmt);
/* Do the initialization itself. */
if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
*************** expand_static_init (decl, init)
*** 8325,8334 ****
expr_tree_cons (NULL_TREE,
cleanup,
NULL_TREE));
! expand_expr_stmt (fcall);
}
- expand_end_cond ();
/* Resume old (possibly temporary) allocation. */
pop_obstacks ();
}
--- 8297,8308 ----
expr_tree_cons (NULL_TREE,
cleanup,
NULL_TREE));
! finish_expr_stmt (fcall);
}
+
+ finish_then_clause (if_stmt);
+ finish_if_stmt ();
/* Resume old (possibly temporary) allocation. */
pop_obstacks ();
}
Index: cp/decl2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl2.c,v
retrieving revision 1.244
diff -c -p -r1.244 decl2.c
*** decl2.c 1999/08/29 01:20:54 1.244
--- decl2.c 1999/08/29 18:51:22
*************** get_temp_name (type, staticp)
*** 2070,2076 ****
if (! toplev)
{
expand_decl (decl);
! expand_decl_init (decl);
}
pop_obstacks ();
--- 2070,2077 ----
if (! toplev)
{
expand_decl (decl);
! my_friendly_assert (DECL_INITIAL (decl) == NULL_TREE,
! 19990826);
}
pop_obstacks ();
Index: cp/init.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/init.c,v
retrieving revision 1.122
diff -c -p -r1.122 init.c
*** init.c 1999/08/25 22:07:03 1.122
--- init.c 1999/08/29 18:51:25
*************** create_temporary_var (type)
*** 2706,2713 ****
if (building_stmt_tree ())
add_decl_stmt (decl);
- else
- DECL_RTL (decl) = assign_temp (type, 2, 0, 1);
return decl;
}
--- 2706,2711 ----
*************** get_temp_regvar (type, init)
*** 2727,2732 ****
--- 2725,2732 ----
decl = create_temporary_var (type);
DECL_REGISTER (decl) = 1;
+ if (!building_stmt_tree ())
+ DECL_RTL (decl) = assign_temp (type, 2, 0, 1);
finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
return decl;
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.342
diff -c -p -r1.342 pt.c
*** pt.c 1999/08/28 21:45:37 1.342
--- pt.c 1999/08/29 18:51:31
*************** tsubst_expr (t, args, complain, in_decl)
*** 7272,7284 ****
decl = tsubst (decl, args, complain, in_decl);
init = tsubst_expr (init, args, complain, in_decl);
DECL_INITIAL (decl) = init;
! /* By marking the declaration as instantiated, we avoid trying
! to instantiate it. Since instantiate_decl can't handle
! local variables, and since we've already done all that
! needs to be done, that's the right thing to do. */
if (TREE_CODE (decl) == VAR_DECL)
DECL_TEMPLATE_INSTANTIATED (decl) = 1;
maybe_push_decl (decl);
add_decl_stmt (decl);
}
resume_momentary (i);
--- 7272,7286 ----
decl = tsubst (decl, args, complain, in_decl);
init = tsubst_expr (init, args, complain, in_decl);
DECL_INITIAL (decl) = init;
! /* By marking the declaration as instantiated, we avoid
! trying to instantiate it. Since instantiate_decl can't
! handle local variables, and since we've already done
! all that needs to be done, that's the right thing to
! do. */
if (TREE_CODE (decl) == VAR_DECL)
DECL_TEMPLATE_INSTANTIATED (decl) = 1;
maybe_push_decl (decl);
+ cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0, 0);
add_decl_stmt (decl);
}
resume_momentary (i);
Index: cp/semantics.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/semantics.c,v
retrieving revision 1.67
diff -c -p -r1.67 semantics.c
*** semantics.c 1999/08/28 21:45:37 1.67
--- semantics.c 1999/08/29 18:51:32
*************** expand_stmt (t)
*** 2046,2052 ****
if (TREE_CODE (decl) == VAR_DECL)
DECL_DEAD_FOR_LOCAL (decl) = 0;
maybe_push_decl (decl);
! cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0, 0);
}
resume_momentary (i);
}
--- 2046,2056 ----
if (TREE_CODE (decl) == VAR_DECL)
DECL_DEAD_FOR_LOCAL (decl) = 0;
maybe_push_decl (decl);
! if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl))
! {
! maybe_inject_for_scope_var (decl);
! initialize_local_var (decl, DECL_INITIAL (decl), 0);
! }
}
resume_momentary (i);
}