This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: Fix copy constructor problems
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: oldham at codesourcery dot com
- Date: Fri, 11 Oct 2002 09:54:25 -0700
- Subject: C++ PATCH: Fix copy constructor problems
- Reply-to: mark at codesourcery dot com
Our ABI testsuite accidentally discovered this bug:
+ struct S { S (); };
+
+ volatile S s[1] = { S () };
This program was incorrectly rejected by G++. The basic problem was
that for array initializers, we called digest_init (to handle brace
elision so that we could compute the size of the array if an explicit
bound was not provided) and then later called build_aggr_init to
convert the initializer. But, digest_init had already done that, so
we ended up trying to do the conversions twice. In this case, we
complained that a "volatile S" could not be passed to "const S&".
A more insidious case is this one:
+ S s[1] = { S () };
With -fno-elide-constructors, we actually copied the object *twice*,
which is a case of silent bad code generation.
In the process of fixing this (by separating the handling of brace
elision from the process of conversion), I accidentally fixed things
like this:
! int (Foo::*pA)() = { &Foo::DoSomething }; // ERROR -
which we previously accepted despite the invalid extra set of braces.
I suspect that there is now some cleanup that could be done in
digest_init (it should no longer have to hadle brace elision), but I
didn't go that far.
To make things a little simpler, I removed the already deprecated
"new X = ..." extension. (This extension was already documented as
having been removed, but it wasn't.)
Bootstrapped and tested on i686-pc-linux-gnu, applied on the mainline.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
2002-10-11 Mark Mitchell <mark@codesourcery.com>
* NEWS: Document removal of "new X = ..." extension.
* class.c (initialize_array): Set TREE_HAS_CONSTRUCTOR on
brace-enclosed initializers.
* cp-tree.h (CP_AGGREGATE_TYPE_P): New macro.
(initialize_local_var): Remove declaration.
(expand_static_init): Likewise.
* decl.c (next_initializable_field): New function.
(reshape_init): Likewise.
(check_initializer): Use them. Build dynamic initializer for
aggregates here too.
(initialize_local_var): Simplify, and incorporate cleanup
insertion code as well.
(destroy_local_var): Remove.
(cp_finish_decl): Tidy.
(expand_static_init): Fold checks for whether or not a variable
needs initialization into this function. Simplify.
* decl2.c (do_static_initialization): Simplify.
* init.c (build_init): Do not set TREE_SIDE_EFFECTS when it will
be done for us automatically.
(expand_default_init): Handle brace-enclosed initializers
correctly.
(expand_aggr_init_1): Remove RTL-generation code.
(build_vec_init): Remove "new X = ..." support.
* parse.y (new_initializer): Likewise.
* rtti.c (get_pseudo_ti_init): Set TREE_HAS_CONSTRUCTOR on
brace-enclosed initializer.
(create_pseudo_type_info): Likewise.
* typeck2.c (store_init_value): Don't try to handle digest_init
being called more than once.
(digest_init): Tidy handling of brace-enclosed initializers.
2002-10-11 Mark Mitchell <mark@codesourcery.com>
* g++.dg/init/array1.C: Remove invalid braces.
* g++.dg/init/brace1.C: New test.
* g++.dg/init/copy2.C: Likewise.
* g++.dg/init/copy3.C: Likewise.
* g++.old-deja/g++.ext/arrnew.C: Change WARNING to ERROR.
* g++.old-deja/g++.mike/p9129.C: Add ERROR on invalid use of
braces.
Index: cp/NEWS
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/NEWS,v
retrieving revision 1.34
diff -c -5 -p -r1.34 NEWS
*** cp/NEWS 19 Mar 2002 00:21:38 -0000 1.34
--- cp/NEWS 11 Oct 2002 16:19:51 -0000
***************
*** 1,5 ****
--- 1,9 ----
+ *** Changes in GCC 3.3:
+
+ * The "new X = 3" extension has been removed; you must now use "new X(3)".
+
*** Changes in GCC 3.1:
* -fhonor-std and -fno-honor-std have been removed. -fno-honor-std was
a workaround to allow std compliant code to work with the non-std
compliant libstdc++-v2. libstdc++-v3 is std compliant.
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.473
diff -c -5 -p -r1.473 class.c
*** cp/class.c 2 Oct 2002 20:02:10 -0000 1.473
--- cp/class.c 11 Oct 2002 16:19:52 -0000
*************** initialize_array (decl, inits)
*** 6992,7001 ****
--- 6992,7002 ----
tree context;
context = DECL_CONTEXT (decl);
DECL_CONTEXT (decl) = NULL_TREE;
DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE, inits);
+ TREE_HAS_CONSTRUCTOR (DECL_INITIAL (decl)) = 1;
cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0);
DECL_CONTEXT (decl) = context;
}
/* Build the VTT (virtual table table) for T.
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.756
diff -c -5 -p -r1.756 cp-tree.h
*** cp/cp-tree.h 2 Oct 2002 20:01:35 -0000 1.756
--- cp/cp-tree.h 11 Oct 2002 16:19:53 -0000
*************** struct lang_decl GTY(())
*** 2435,2446 ****
|| TREE_CODE (TYPE) == ENUMERAL_TYPE \
|| TYPE_PTR_P (TYPE) \
|| TYPE_PTRMEM_P (TYPE) \
|| TYPE_PTRMEMFUNC_P (TYPE))
! /* Nonzero for _TYPE means that the _TYPE defines
! at least one constructor. */
#define TYPE_HAS_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1 (NODE))
/* When appearing in an INDIRECT_REF, it means that the tree structure
underneath is actually a call to a constructor. This is needed
when the constructor must initialize local storage (which can
--- 2435,2456 ----
|| TREE_CODE (TYPE) == ENUMERAL_TYPE \
|| TYPE_PTR_P (TYPE) \
|| TYPE_PTRMEM_P (TYPE) \
|| TYPE_PTRMEMFUNC_P (TYPE))
! /* [dcl.init.aggr]
!
! An aggregate is an array or a class with no user-declared
! constructors, no private or protected non-static data members, no
! base classes, and no virtual functions. */
! #define CP_AGGREGATE_TYPE_P(TYPE) \
! (TREE_CODE (TYPE) == ARRAY_TYPE \
! || (CLASS_TYPE_P (TYPE) \
! && !CLASSTYPE_NON_AGGREGATE (TYPE)))
!
! /* Nonzero for a class type means that the class type has a
! user-declared constructor. */
#define TYPE_HAS_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1 (NODE))
/* When appearing in an INDIRECT_REF, it means that the tree structure
underneath is actually a call to a constructor. This is needed
when the constructor must initialize local storage (which can
*************** extern tree groktypename PARAMS ((tree
*** 3665,3676 ****
extern tree start_decl PARAMS ((tree, tree, int, tree, tree));
extern void start_decl_1 PARAMS ((tree));
extern void cp_finish_decl PARAMS ((tree, tree, tree, int));
extern void finish_decl PARAMS ((tree, tree, tree));
extern void maybe_inject_for_scope_var PARAMS ((tree));
- extern void initialize_local_var PARAMS ((tree, tree, int));
- extern void expand_static_init PARAMS ((tree, tree));
extern tree start_handler_parms PARAMS ((tree, tree));
extern int complete_array_type PARAMS ((tree, tree, int));
extern tree build_ptrmemfunc_type PARAMS ((tree));
extern tree build_ptrmem_type (tree, tree);
/* the grokdeclarator prototype is in decl.h */
--- 3675,3684 ----
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.945
diff -c -5 -p -r1.945 decl.c
*** cp/decl.c 11 Oct 2002 01:28:26 -0000 1.945
--- cp/decl.c 11 Oct 2002 16:19:56 -0000
*************** static void check_previous_gotos PARAMS
*** 119,133 ****
static void pop_label PARAMS ((tree, tree));
static void pop_labels PARAMS ((tree));
static void maybe_deduce_size_from_array_init PARAMS ((tree, tree));
static void layout_var_decl PARAMS ((tree));
static void maybe_commonize_var PARAMS ((tree));
! static tree check_initializer PARAMS ((tree, tree));
static void make_rtl_for_nonlocal_decl PARAMS ((tree, tree, const char *));
static void save_function_data PARAMS ((tree));
static void check_function_type PARAMS ((tree, tree));
- static void destroy_local_var PARAMS ((tree));
static void begin_constructor_body PARAMS ((void));
static void finish_constructor_body PARAMS ((void));
static void begin_destructor_body PARAMS ((void));
static void finish_destructor_body PARAMS ((void));
static tree create_array_type_for_decl PARAMS ((tree, tree, tree));
--- 119,132 ----
static void pop_label PARAMS ((tree, tree));
static void pop_labels PARAMS ((tree));
static void maybe_deduce_size_from_array_init PARAMS ((tree, tree));
static void layout_var_decl PARAMS ((tree));
static void maybe_commonize_var PARAMS ((tree));
! static tree check_initializer (tree, tree, int);
static void make_rtl_for_nonlocal_decl PARAMS ((tree, tree, const char *));
static void save_function_data PARAMS ((tree));
static void check_function_type PARAMS ((tree, tree));
static void begin_constructor_body PARAMS ((void));
static void finish_constructor_body PARAMS ((void));
static void begin_destructor_body PARAMS ((void));
static void finish_destructor_body PARAMS ((void));
static tree create_array_type_for_decl PARAMS ((tree, tree, tree));
*************** static tree check_special_function_retur
*** 141,150 ****
--- 140,153 ----
PARAMS ((special_function_kind, tree, tree));
static tree push_cp_library_fn PARAMS ((enum tree_code, tree));
static tree build_cp_library_fn PARAMS ((tree, enum tree_code, tree));
static void store_parm_decls PARAMS ((tree));
static int cp_missing_noreturn_ok_p PARAMS ((tree));
+ static void initialize_local_var (tree, tree);
+ static void expand_static_init (tree, tree);
+ static tree next_initializable_field (tree);
+ static tree reshape_init (tree, tree *);
#if defined (DEBUG_BINDING_LEVELS)
static void indent PARAMS ((void));
#endif
*************** check_for_uninitialized_const_var (decl)
*** 7725,7742 ****
&& !TYPE_NEEDS_CONSTRUCTING (type)
&& !DECL_INITIAL (decl))
error ("uninitialized const `%D'", decl);
}
/* Verify INIT (the initializer for DECL), and record the
! initialization in DECL_INITIAL, if appropriate. Returns a new
! value for INIT. */
static tree
! check_initializer (decl, init)
! tree decl;
! tree init;
{
tree type = TREE_TYPE (decl);
/* If `start_decl' didn't like having an initialization, ignore it now. */
if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE)
--- 7728,7951 ----
&& !TYPE_NEEDS_CONSTRUCTING (type)
&& !DECL_INITIAL (decl))
error ("uninitialized const `%D'", decl);
}
+ /* FIELD is a FIELD_DECL or NULL. In the former case, the value
+ returned is the next FIELD_DECL (possibly FIELD itself) that can be
+ initialized. If there are no more such fields, the return value
+ will be NULL. */
+
+ static tree
+ next_initializable_field (tree field)
+ {
+ while (field
+ && (TREE_CODE (field) != FIELD_DECL
+ || (DECL_C_BIT_FIELD (field) && !DECL_NAME (field))
+ || DECL_ARTIFICIAL (field)))
+ field = TREE_CHAIN (field);
+
+ return field;
+ }
+
+ /* Undo the brace-elision allowed by [dcl.init.aggr] in a
+ brace-enclosed aggregate initializer.
+
+ *INITP is one of a list of initializers describing a brace-enclosed
+ initializer for an entity of the indicated aggregate TYPE. It may
+ not presently match the shape of the TYPE; for example:
+
+ struct S { int a; int b; };
+ struct S a[] = { 1, 2, 3, 4 };
+
+ Here *INITP will point to TREE_LIST of four elements, rather than a
+ list of two elements, each itself a list of two elements. This
+ routine transforms INIT from the former form into the latter. The
+ revised initializer is returned. */
+
+ static tree
+ reshape_init (tree type, tree *initp)
+ {
+ tree inits;
+ tree old_init;
+ tree old_init_value;
+ tree new_init;
+ bool brace_enclosed_p;
+
+ old_init = *initp;
+ old_init_value = (TREE_CODE (*initp) == TREE_LIST
+ ? TREE_VALUE (*initp) : old_init);
+
+ /* If the initializer is brace-enclosed, pull initializers from the
+ enclosed elements. Advance past the brace-enclosed initializer
+ now. */
+ if (TREE_CODE (old_init_value) == CONSTRUCTOR
+ && TREE_HAS_CONSTRUCTOR (old_init_value))
+ {
+ *initp = TREE_CHAIN (old_init);
+ TREE_CHAIN (old_init) = NULL_TREE;
+ inits = CONSTRUCTOR_ELTS (old_init_value);
+ initp = &inits;
+ brace_enclosed_p = true;
+ }
+ else
+ {
+ inits = NULL_TREE;
+ brace_enclosed_p = false;
+ }
+
+ /* A non-aggregate type is always initialized with a single
+ initializer. */
+ if (!CP_AGGREGATE_TYPE_P (type))
+ {
+ *initp = TREE_CHAIN (old_init);
+ TREE_CHAIN (old_init) = NULL_TREE;
+ /* It is invalid to initialize a non-aggregate type with a
+ brace-enclosed initializer. */
+ if (brace_enclosed_p)
+ {
+ error ("brace-enclosed initializer used to initialize `%T'",
+ type);
+ if (TREE_CODE (old_init) == TREE_LIST)
+ TREE_VALUE (old_init) = error_mark_node;
+ else
+ old_init = error_mark_node;
+ }
+
+ return old_init;
+ }
+
+ /* [dcl.init.aggr]
+
+ All implicit type conversions (clause _conv_) are considered when
+ initializing the aggregate member with an initializer from an
+ initializer-list. If the initializer can initialize a member,
+ the member is initialized. Otherwise, if the member is itself a
+ non-empty subaggregate, brace elision is assumed and the
+ initializer is considered for the initialization of the first
+ member of the subaggregate. */
+ if (CLASS_TYPE_P (type)
+ && !brace_enclosed_p
+ && can_convert_arg (type, TREE_TYPE (old_init_value), old_init_value))
+ {
+ *initp = TREE_CHAIN (old_init);
+ TREE_CHAIN (old_init) = NULL_TREE;
+ return old_init;
+ }
+
+ if (TREE_CODE (old_init) == STRING_CST
+ && TREE_CODE (type) == ARRAY_TYPE
+ && char_type_p (TREE_TYPE (type)))
+ {
+ /* [dcl.init.string]
+
+ A char array (whether plain char, signed char, or unsigned char)
+ can be initialized by a string-literal (optionally enclosed in
+ braces); a wchar_t array can be initialized by a wide
+ string-literal (optionally enclosed in braces). */
+ new_init = old_init;
+ /* Move past the initializer. */
+ *initp = TREE_CHAIN (old_init);
+ TREE_CHAIN (old_init) = NULL_TREE;
+ }
+ else
+ {
+ /* Build a CONSTRUCTOR to hold the contents of the aggregate. */
+ new_init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+ TREE_HAS_CONSTRUCTOR (new_init) = 1;
+
+ if (CLASS_TYPE_P (type))
+ {
+ tree field;
+
+ field = next_initializable_field (TYPE_FIELDS (type));
+
+ if (!field)
+ {
+ /* [dcl.init.aggr]
+
+ An initializer for an aggregate member that is an
+ empty class shall have the form of an empty
+ initializer-list {}. */
+ if (!brace_enclosed_p)
+ error ("initializer for `%T' must be brace-enclosed",
+ type);
+ }
+ else
+ {
+ /* Loop through the initializable fields, gathering
+ initializers. */
+ while (*initp && field)
+ {
+ tree field_init;
+
+ field_init = reshape_init (TREE_TYPE (field), initp);
+ TREE_CHAIN (field_init) = CONSTRUCTOR_ELTS (new_init);
+ CONSTRUCTOR_ELTS (new_init) = field_init;
+ /* [dcl.init.aggr]
+
+ When a union is initialized with a brace-enclosed
+ initializer, the braces shall only contain an
+ initializer for the first member of the union. */
+ if (TREE_CODE (type) == UNION_TYPE)
+ break;
+ if (TREE_PURPOSE (field_init))
+ field = TREE_PURPOSE (field_init);
+ field = next_initializable_field (TREE_CHAIN (field));
+ }
+ }
+ }
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree index;
+ tree max_index;
+
+ /* If the bound of the array is known, take no more initializers
+ than are allowed. */
+ max_index = (TYPE_DOMAIN (type)
+ ? array_type_nelts (type) : NULL_TREE);
+ /* Loop through the array elements, gathering initializers. */
+ for (index = size_zero_node;
+ *initp && (!max_index || !tree_int_cst_lt (max_index, index));
+ index = size_binop (PLUS_EXPR, index, size_one_node))
+ {
+ tree element_init;
+
+ element_init = reshape_init (TREE_TYPE (type), initp);
+ TREE_CHAIN (element_init) = CONSTRUCTOR_ELTS (new_init);
+ CONSTRUCTOR_ELTS (new_init) = element_init;
+ if (TREE_PURPOSE (element_init))
+ index = TREE_PURPOSE (element_init);
+ }
+ }
+ else
+ abort ();
+
+ /* The initializers were placed in reverse order in the
+ CONSTRUCTOR. */
+ CONSTRUCTOR_ELTS (new_init) = nreverse (CONSTRUCTOR_ELTS (new_init));
+
+ if (TREE_CODE (old_init) == TREE_LIST)
+ new_init = build_tree_list (TREE_PURPOSE (old_init), new_init);
+ }
+
+ /* If this was a brace-enclosed initializer and all of the
+ initializers were not used up, there is a problem. */
+ if (brace_enclosed_p && *initp)
+ error ("too many initializers for `%T'", type);
+
+ return new_init;
+ }
+
/* Verify INIT (the initializer for DECL), and record the
! initialization in DECL_INITIAL, if appropriate.
!
! If the return value is non-NULL, it is an expression that must be
! evaluated dynamically to initialize DECL. */
static tree
! check_initializer (tree decl, tree init, int flags)
{
tree type = TREE_TYPE (decl);
/* If `start_decl' didn't like having an initialization, ignore it now. */
if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE)
*************** check_initializer (decl, init)
*** 7788,7842 ****
}
else if (!DECL_EXTERNAL (decl) && TREE_CODE (type) == REFERENCE_TYPE)
init = grok_reference_init (decl, type, init);
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))
{
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);
}
}
else if (DECL_EXTERNAL (decl))
;
! else if (TYPE_P (type)
! && (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))
! error ("structure `%D' with uninitialized const members", decl);
! if (CLASSTYPE_REF_FIELDS_NEED_INIT (core_type))
! error ("structure `%D' with uninitialized reference members",
! decl);
! }
check_for_uninitialized_const_var (decl);
}
else
check_for_uninitialized_const_var (decl);
return init;
}
/* If DECL is not a local variable, give it RTL. */
--- 7997,8079 ----
}
else if (!DECL_EXTERNAL (decl) && TREE_CODE (type) == REFERENCE_TYPE)
init = grok_reference_init (decl, type, init);
else if (init)
{
+ if (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init))
+ init = reshape_init (type, &init);
+
+ /* If DECL has an array type without a specific bound, deduce the
+ array size from the initializer. */
+ maybe_deduce_size_from_array_init (decl, init);
+ type = TREE_TYPE (decl);
+ if (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init))
+ TREE_TYPE (init) = type;
+
if (TYPE_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type))
{
if (TREE_CODE (type) == ARRAY_TYPE)
! goto initialize_aggr;
else if (TREE_CODE (init) == CONSTRUCTOR
&& TREE_HAS_CONSTRUCTOR (init))
{
if (TYPE_NON_AGGREGATE_CLASS (type))
{
error ("`%D' must be initialized by constructor, not by `{...}'",
! decl);
init = error_mark_node;
}
else
goto dont_use_constructor;
}
+ else
+ {
+ int saved_stmts_are_full_exprs_p;
+
+ initialize_aggr:
+ saved_stmts_are_full_exprs_p = 0;
+ if (building_stmt_tree ())
+ {
+ saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
+ current_stmt_tree ()->stmts_are_full_exprs_p = 1;
+ }
+ init = build_aggr_init (decl, init, flags);
+ if (building_stmt_tree ())
+ current_stmt_tree ()->stmts_are_full_exprs_p =
+ saved_stmts_are_full_exprs_p;
+ return init;
+ }
}
else
{
dont_use_constructor:
if (TREE_CODE (init) != TREE_VEC)
init = store_init_value (decl, init);
}
}
else if (DECL_EXTERNAL (decl))
;
! else if (TYPE_P (type) && TYPE_NEEDS_CONSTRUCTING (type))
! goto initialize_aggr;
! else if (IS_AGGR_TYPE (type))
{
tree core_type = strip_array_types (type);
! if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type))
! error ("structure `%D' with uninitialized const members", decl);
! if (CLASSTYPE_REF_FIELDS_NEED_INIT (core_type))
! error ("structure `%D' with uninitialized reference members",
! decl);
check_for_uninitialized_const_var (decl);
}
else
check_for_uninitialized_const_var (decl);
+ if (init && init != error_mark_node)
+ init = build (INIT_EXPR, type, decl, init);
+
return init;
}
/* If DECL is not a local variable, give it RTL. */
*************** maybe_inject_for_scope_var (decl)
*** 7966,8019 ****
}
}
/* Generate code to initialize DECL (a local variable). */
! void
! initialize_local_var (decl, init, flags)
tree decl;
tree init;
- int flags;
{
tree type = TREE_TYPE (decl);
! /* If the type is bogus, don't bother initializing the variable. */
! if (type == error_mark_node)
! return;
! 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);
}
- /* Local statics are handled differently from ordinary automatic
- variables. */
- if (TREE_STATIC (decl))
- {
- if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
- || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
- expand_static_init (decl, init);
- return;
- }
-
if (DECL_SIZE (decl) && type != error_mark_node)
{
int already_used;
/* Compute and store the initial value. */
already_used = TREE_USED (decl) || TREE_USED (type);
! if (init || TYPE_NEEDS_CONSTRUCTING (type))
{
int saved_stmts_are_full_exprs_p;
my_friendly_assert (building_stmt_tree (), 20000906);
saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
current_stmt_tree ()->stmts_are_full_exprs_p = 1;
! finish_expr_stmt (build_aggr_init (decl, init, flags));
current_stmt_tree ()->stmts_are_full_exprs_p =
saved_stmts_are_full_exprs_p;
}
/* Set this to 0 so we can tell whether an aggregate which was
--- 8203,8247 ----
}
}
/* Generate code to initialize DECL (a local variable). */
! static void
! initialize_local_var (decl, init)
tree decl;
tree init;
{
tree type = TREE_TYPE (decl);
! my_friendly_assert (TREE_CODE (decl) == VAR_DECL
! || TREE_CODE (decl) == RESULT_DECL,
! 20021010);
! my_friendly_assert (!TREE_STATIC (decl), 20021010);
! if (DECL_SIZE (decl) == NULL_TREE)
{
/* 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_SIZE (decl) && type != error_mark_node)
{
int already_used;
/* Compute and store the initial value. */
already_used = TREE_USED (decl) || TREE_USED (type);
! /* Perform the initialization. */
! if (init)
{
int saved_stmts_are_full_exprs_p;
my_friendly_assert (building_stmt_tree (), 20000906);
saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
current_stmt_tree ()->stmts_are_full_exprs_p = 1;
! finish_expr_stmt (init);
current_stmt_tree ()->stmts_are_full_exprs_p =
saved_stmts_are_full_exprs_p;
}
/* Set this to 0 so we can tell whether an aggregate which was
*************** initialize_local_var (decl, init, flags)
*** 8028,8070 ****
&& DECL_NAME (decl))
TREE_USED (decl) = 0;
else if (already_used)
TREE_USED (decl) = 1;
}
- }
-
- /* Generate code to destroy DECL (a local variable). */
-
- static void
- destroy_local_var (decl)
- tree decl;
- {
- tree type = TREE_TYPE (decl);
- tree cleanup;
-
- /* Only variables get cleaned up. */
- if (TREE_CODE (decl) != VAR_DECL)
- return;
-
- /* And only things with destructors need cleaning up. */
- if (type == error_mark_node
- || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
- return;
! 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;
!
! /* Compute the cleanup. */
! cleanup = cxx_maybe_build_cleanup (decl);
! /* Record the cleanup required for this declaration. */
! if (DECL_SIZE (decl) && cleanup)
! finish_decl_cleanup (decl, cleanup);
}
/* Finish processing of a declaration;
install its line number and initial value.
If the length of an array type is not known before,
--- 8256,8278 ----
&& DECL_NAME (decl))
TREE_USED (decl) = 0;
else if (already_used)
TREE_USED (decl) = 1;
}
! /* Generate a cleanup, if necessary. */
! if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
! {
! tree cleanup;
! /* Compute the cleanup. */
! cleanup = cxx_maybe_build_cleanup (decl);
!
! /* Record the cleanup required for this declaration. */
! if (DECL_SIZE (decl) && cleanup)
! finish_decl_cleanup (decl, cleanup);
! }
}
/* 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
*** 8191,8201 ****
SET_DECL_RTL (TREE_TYPE (decl), NULL_RTX);
SET_DECL_ASSEMBLER_NAME (decl, get_identifier (asmspec));
make_decl_rtl (decl, asmspec);
}
else if (TREE_CODE (decl) == RESULT_DECL)
! init = check_initializer (decl, init);
else if (TREE_CODE (decl) == VAR_DECL)
{
/* Only PODs can have thread-local storage. Other types may require
various kinds of non-trivial initialization. */
if (DECL_THREAD_LOCAL (decl) && !pod_type_p (TREE_TYPE (decl)))
--- 8399,8409 ----
SET_DECL_RTL (TREE_TYPE (decl), NULL_RTX);
SET_DECL_ASSEMBLER_NAME (decl, get_identifier (asmspec));
make_decl_rtl (decl, asmspec);
}
else if (TREE_CODE (decl) == RESULT_DECL)
! init = check_initializer (decl, init, flags);
else if (TREE_CODE (decl) == VAR_DECL)
{
/* Only PODs can have thread-local storage. Other types may require
various kinds of non-trivial initialization. */
if (DECL_THREAD_LOCAL (decl) && !pod_type_p (TREE_TYPE (decl)))
*************** cp_finish_decl (decl, init, asmspec_tree
*** 8203,8234 ****
decl, TREE_TYPE (decl));
/* Convert the initializer to the type of DECL, if we have not
already initialized DECL. */
if (!DECL_INITIALIZED_P (decl)
/* If !DECL_EXTERNAL then DECL is being defined. In the
! case of a static data memberm initialized inside the
class-specifier, there can be an initializer even if DECL
is *not* defined. */
&& (!DECL_EXTERNAL (decl) || init))
{
! init = check_initializer (decl, init);
/* Thread-local storage cannot be dynamically initialized. */
if (DECL_THREAD_LOCAL (decl) && init)
{
error ("`%D' is thread-local and so cannot be dynamically "
"initialized", decl);
init = NULL_TREE;
}
- /* If DECL has an array type without a specific bound, deduce the
- array size from the initializer. Note that this must be done
- after check_initializer is called because of cases like this:
-
- struct S { int a; int b; };
- struct S a[] = { 1, 2 };
-
- which creates a one-element array, not a two-element array. */
- maybe_deduce_size_from_array_init (decl, init);
/* Handle:
[dcl.init]
The memory occupied by any object of static storage
--- 8411,8433 ----
decl, TREE_TYPE (decl));
/* Convert the initializer to the type of DECL, if we have not
already initialized DECL. */
if (!DECL_INITIALIZED_P (decl)
/* If !DECL_EXTERNAL then DECL is being defined. In the
! case of a static data member initialized inside the
class-specifier, there can be an initializer even if DECL
is *not* defined. */
&& (!DECL_EXTERNAL (decl) || init))
{
! init = check_initializer (decl, init, flags);
/* Thread-local storage cannot be dynamically initialized. */
if (DECL_THREAD_LOCAL (decl) && init)
{
error ("`%D' is thread-local and so cannot be dynamically "
"initialized", decl);
init = NULL_TREE;
}
/* Handle:
[dcl.init]
The memory occupied by any object of static storage
*************** cp_finish_decl (decl, init, asmspec_tree
*** 8281,8328 ****
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)
;
else if (DECL_EXTERNAL (decl)
&& ! (DECL_LANG_SPECIFIC (decl)
&& DECL_NOT_REALLY_EXTERN (decl)))
{
if (init)
DECL_INITIAL (decl) = init;
}
! else if (TREE_CODE (CP_DECL_CONTEXT (decl)) == FUNCTION_DECL)
{
! /* This is a local declaration. */
! if (doing_semantic_analysis_p ())
! 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 (processing_template_decl)
{
! if (init || DECL_INITIAL (decl) == error_mark_node)
! DECL_INITIAL (decl) = init;
! }
! else
! {
! /* If we're not building RTL, then we need to do so
! now. */
! my_friendly_assert (building_stmt_tree (), 20000906);
! /* Initialize the variable. */
! initialize_local_var (decl, init, flags);
! /* Clean up the variable. */
! destroy_local_var (decl);
}
! }
! else if (TREE_STATIC (decl) && type != error_mark_node)
! {
! /* Cleanups for static variables are handled by `finish_file'. */
! if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
! || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
expand_static_init (decl, init);
}
finish_end0:
/* Undo call to `pushclass' that was done in `start_decl'
--- 8480,8519 ----
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
! || TREE_TYPE (decl) == error_mark_node)
! /* No initialization required. */
;
else if (DECL_EXTERNAL (decl)
&& ! (DECL_LANG_SPECIFIC (decl)
&& DECL_NOT_REALLY_EXTERN (decl)))
{
if (init)
DECL_INITIAL (decl) = init;
}
! else
{
! /* A variable definition. */
! if (DECL_FUNCTION_SCOPE_P (decl))
{
! /* This is a local declaration. */
! if (doing_semantic_analysis_p ())
! maybe_inject_for_scope_var (decl);
! /* Initialize the local variable. */
! if (processing_template_decl)
! {
! if (init || DECL_INITIAL (decl) == error_mark_node)
! DECL_INITIAL (decl) = init;
! }
! else if (!TREE_STATIC (decl))
! initialize_local_var (decl, init);
}
!
! if (TREE_STATIC (decl))
expand_static_init (decl, init);
}
finish_end0:
/* Undo call to `pushclass' that was done in `start_decl'
*************** register_dtor_fn (decl)
*** 8598,8613 ****
else
args = tree_cons (NULL_TREE, cleanup, NULL_TREE);
finish_expr_stmt (build_function_call (get_atexit_node (), args));
}
! void
expand_static_init (decl, init)
tree decl;
tree init;
{
! tree oldstatic = value_member (decl, static_aggregates);
if (oldstatic)
{
if (TREE_PURPOSE (oldstatic) && init != NULL_TREE)
error ("multiple initializations given for `%D'", decl);
--- 8789,8819 ----
else
args = tree_cons (NULL_TREE, cleanup, NULL_TREE);
finish_expr_stmt (build_function_call (get_atexit_node (), args));
}
! /* DECL is a VAR_DECL with static storage duration. INIT, if present,
! is its initializer. Generate code to handle the construction
! and destruction of DECL. */
!
! static void
expand_static_init (decl, init)
tree decl;
tree init;
{
! tree oldstatic;
!
! my_friendly_assert (TREE_CODE (decl) == VAR_DECL, 20021010);
! my_friendly_assert (TREE_STATIC (decl), 20021010);
!
! /* Some variables require no initialization. */
! if (!init
! && !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
! && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
! return;
!
! oldstatic = value_member (decl, static_aggregates);
if (oldstatic)
{
if (TREE_PURPOSE (oldstatic) && init != NULL_TREE)
error ("multiple initializations given for `%D'", decl);
*************** expand_static_init (decl, init)
*** 8653,8671 ****
if_stmt = begin_if_stmt ();
finish_if_stmt_cond (get_guard_cond (guard), if_stmt);
then_clause = begin_compound_stmt (/*has_no_scope=*/0);
/* Do the initialization itself. */
! if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
! || (init && TREE_CODE (init) == TREE_LIST))
! assignment = build_aggr_init (decl, init, 0);
! else if (init)
! /* The initialization we're doing here is just a bitwise
! copy. */
! assignment = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
! else
! assignment = NULL_TREE;
/* Once the assignment is complete, set TEMP to 1. Since the
construction of the static object is complete at this point,
we want to make sure TEMP is set to 1 even if a temporary
constructed during the initialization throws an exception
--- 8859,8869 ----
if_stmt = begin_if_stmt ();
finish_if_stmt_cond (get_guard_cond (guard), if_stmt);
then_clause = begin_compound_stmt (/*has_no_scope=*/0);
/* Do the initialization itself. */
! assignment = init ? init : NULL_TREE;
/* Once the assignment is complete, set TEMP to 1. Since the
construction of the static object is complete at this point,
we want to make sure TEMP is set to 1 even if a temporary
constructed during the initialization throws an exception
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.567
diff -c -5 -p -r1.567 decl2.c
*** cp/decl2.c 9 Oct 2002 21:08:42 -0000 1.567
--- cp/decl2.c 11 Oct 2002 16:19:57 -0000
*************** finish_static_initialization_or_destruct
*** 2506,2543 ****
member of its class any longer. */
DECL_CONTEXT (current_function_decl) = NULL_TREE;
DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
}
! /* Generate code to do the static initialization of DECL. The
! initialization is INIT. If DECL may be initialized more than once
! in different object files, GUARD is the guard variable to
! check. PRIORITY is the priority for the initialization. */
static void
do_static_initialization (decl, init)
tree decl;
tree init;
{
- tree expr;
tree guard_if_stmt;
/* Set up for the initialization. */
guard_if_stmt
= start_static_initialization_or_destruction (decl,
/*initp=*/1);
!
! /* Do the initialization itself. */
! if (IS_AGGR_TYPE (TREE_TYPE (decl))
! || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
! expr = build_aggr_init (decl, init, 0);
! else
! {
! expr = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
! TREE_SIDE_EFFECTS (expr) = 1;
! }
! finish_expr_stmt (expr);
/* If we're using __cxa_atexit, register a a function that calls the
destructor for the object. */
if (flag_use_cxa_atexit)
register_dtor_fn (decl);
--- 2506,2533 ----
member of its class any longer. */
DECL_CONTEXT (current_function_decl) = NULL_TREE;
DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
}
! /* Generate code to do the initialization of DECL, a VAR_DECL with
! static storage duration. The initialization is INIT. */
static void
do_static_initialization (decl, init)
tree decl;
tree init;
{
tree guard_if_stmt;
/* Set up for the initialization. */
guard_if_stmt
= start_static_initialization_or_destruction (decl,
/*initp=*/1);
!
! /* Perform the initialization. */
! if (init)
! finish_expr_stmt (init);
/* If we're using __cxa_atexit, register a a function that calls the
destructor for the object. */
if (flag_use_cxa_atexit)
register_dtor_fn (decl);
*************** do_static_destruction (decl)
*** 2565,2575 ****
if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
return;
/* Actually do the destruction. */
guard_if_stmt = start_static_initialization_or_destruction (decl,
! /*initp=*/0);
finish_expr_stmt (build_cleanup (decl));
finish_static_initialization_or_destruction (guard_if_stmt);
}
/* VARS is a list of variables with static storage duration which may
--- 2555,2565 ----
if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
return;
/* Actually do the destruction. */
guard_if_stmt = start_static_initialization_or_destruction (decl,
! /*initp=*/0);
finish_expr_stmt (build_cleanup (decl));
finish_static_initialization_or_destruction (guard_if_stmt);
}
/* VARS is a list of variables with static storage duration which may
Index: cp/init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.294
diff -c -5 -p -r1.294 init.c
*** cp/init.c 2 Oct 2002 20:01:35 -0000 1.294
--- cp/init.c 11 Oct 2002 16:19:58 -0000
*************** expand_member_init (tree name, tree init
*** 1039,1050 ****
initialization.
The virtual function table pointer cannot be set up here, because
we do not really know its type.
- Virtual baseclass pointers are also set up here.
-
This never calls operator=().
When initializing, nothing is CONST.
A default copy constructor may have to be used to perform the
--- 1039,1048 ----
*************** build_init (decl, init, flags)
*** 1142,1155 ****
if (IS_AGGR_TYPE (TREE_TYPE (decl))
|| TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
expr = build_aggr_init (decl, init, flags);
else
! {
! expr = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
! TREE_SIDE_EFFECTS (expr) = 1;
! }
return expr;
}
static void
expand_default_init (binfo, true_exp, exp, init, flags)
--- 1140,1151 ----
if (IS_AGGR_TYPE (TREE_TYPE (decl))
|| TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
expr = build_aggr_init (decl, init, flags);
else
! expr = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
!
return expr;
}
static void
expand_default_init (binfo, true_exp, exp, init, flags)
*************** expand_default_init (binfo, true_exp, ex
*** 1182,1194 ****
where we aren't initializing a real variable, so we don't want
to run a new constructor; and catching an exception, where we
have already built up the constructor call so we could wrap it
in an exception region. */;
else if (TREE_CODE (init) == CONSTRUCTOR)
! /* A brace-enclosed initializer has whatever type is
! required. There's no need to convert it. */
! ;
else
init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
if (TREE_CODE (init) == TRY_CATCH_EXPR)
/* We need to protect the initialization of a catch parm
--- 1178,1198 ----
where we aren't initializing a real variable, so we don't want
to run a new constructor; and catching an exception, where we
have already built up the constructor call so we could wrap it
in an exception region. */;
else if (TREE_CODE (init) == CONSTRUCTOR)
! {
! if (!TYPE_HAS_CONSTRUCTOR (type))
! /* A brace-enclosed initializer has whatever type is
! required. There's no need to convert it. */
! ;
! else
! init = ocp_convert (type,
! TREE_VALUE (CONSTRUCTOR_ELTS (init)),
! CONV_IMPLICIT | CONV_FORCE_TEMP,
! flags);
! }
else
init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
if (TREE_CODE (init) == TRY_CATCH_EXPR)
/* We need to protect the initialization of a catch parm
*************** expand_aggr_init_1 (binfo, true_exp, exp
*** 1257,1266 ****
--- 1261,1271 ----
int flags;
{
tree type = TREE_TYPE (exp);
my_friendly_assert (init != error_mark_node && type != error_mark_node, 211);
+ my_friendly_assert (building_stmt_tree (), 20021010);
/* Use a function returning the desired type to initialize EXP for us.
If the function is a constructor, and its first argument is
NULL_TREE, know that it was meant for us--just slide exp on
in and expand the constructor. Constructors now come
*************** expand_aggr_init_1 (binfo, true_exp, exp
*** 1271,1286 ****
&& TREE_HAS_CONSTRUCTOR (init))
{
/* If store_init_value returns NULL_TREE, the INIT has been
record in the DECL_INITIAL for EXP. That means there's
nothing more we have to do. */
! if (!store_init_value (exp, init))
! {
! if (!building_stmt_tree ())
! expand_decl_init (exp);
! }
! else
finish_expr_stmt (build (INIT_EXPR, type, exp, init));
return;
}
/* We know that expand_default_init can handle everything we want
--- 1276,1286 ----
&& TREE_HAS_CONSTRUCTOR (init))
{
/* If store_init_value returns NULL_TREE, the INIT has been
record in the DECL_INITIAL for EXP. That means there's
nothing more we have to do. */
! if (store_init_value (exp, init))
finish_expr_stmt (build (INIT_EXPR, type, exp, init));
return;
}
/* We know that expand_default_init can handle everything we want
*************** build_vec_init (base, init, from_array)
*** 2723,2736 ****
tree maxindex = array_type_nelts (TREE_TYPE (base));
if (maxindex == error_mark_node)
return error_mark_node;
- /* For g++.ext/arrnew.C. */
- if (init && TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == NULL_TREE)
- init = digest_init (atype, init, 0);
-
if (init
&& (from_array == 2
? (!CLASS_TYPE_P (type) || !TYPE_HAS_COMPLEX_ASSIGN_REF (type))
: !TYPE_NEEDS_CONSTRUCTING (type))
&& ((TREE_CODE (init) == CONSTRUCTOR
--- 2723,2732 ----
*************** build_vec_init (base, init, from_array)
*** 2743,2753 ****
/* Do non-default initialization of POD arrays resulting from
brace-enclosed initializers. In this case, digest_init and
store_constructor will handle the semantics for us. */
stmt_expr = build (INIT_EXPR, atype, base, init);
- TREE_SIDE_EFFECTS (stmt_expr) = 1;
return stmt_expr;
}
maxindex = cp_convert (ptrdiff_type_node, maxindex);
ptype = build_pointer_type (type);
--- 2739,2748 ----
Index: cp/parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parse.y,v
retrieving revision 1.281
diff -c -5 -p -r1.281 parse.y
*** cp/parse.y 2 Oct 2002 20:01:35 -0000 1.281
--- cp/parse.y 11 Oct 2002 16:19:58 -0000
*************** new_initializer:
*** 1349,1373 ****
| '(' typespec ')'
{
error ("`%T' is not a valid expression", $2.t);
$$ = error_mark_node;
}
- /* GNU extension so people can use initializer lists. Note that
- this alters the meaning of `new int = 1', which was previously
- syntactically valid but semantically invalid.
- This feature is now deprecated and will be removed in a future
- release. */
| '=' init
{
! if (pedantic)
! pedwarn ("ISO C++ forbids initialization of new expression with `='");
! cp_deprecated ("new initializer lists extension");
! if (TREE_CODE ($2) != TREE_LIST
! && TREE_CODE ($2) != CONSTRUCTOR)
! $$ = build_tree_list (NULL_TREE, $2);
! else
! $$ = $2;
}
;
/* This is necessary to postpone reduction of `int ((int)(int)(int))'. */
regcast_or_absdcl:
--- 1349,1364 ----
| '(' typespec ')'
{
error ("`%T' is not a valid expression", $2.t);
$$ = error_mark_node;
}
| '=' init
{
! /* This was previously allowed as an extension, but
! was removed in G++ 3.3. */
! error ("initialization of new expression with `='");
! $$ = error_mark_node;
}
;
/* This is necessary to postpone reduction of `int ((int)(int)(int))'. */
regcast_or_absdcl:
Index: cp/rtti.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/rtti.c,v
retrieving revision 1.143
diff -c -5 -p -r1.143 rtti.c
*** cp/rtti.c 29 Sep 2002 18:27:01 -0000 1.143
--- cp/rtti.c 11 Oct 2002 16:19:59 -0000
*************** get_pseudo_ti_init (type, var_desc, non_
*** 1094,1107 ****
--- 1094,1109 ----
offset = cp_build_binary_op (BIT_IOR_EXPR, offset,
build_int_2 (flags, 0));
base_init = tree_cons (NULL_TREE, offset, base_init);
base_init = tree_cons (NULL_TREE, tinfo, base_init);
base_init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, base_init);
+ TREE_HAS_CONSTRUCTOR (base_init) = 1;
base_inits = tree_cons (NULL_TREE, base_init, base_inits);
}
base_inits = build (CONSTRUCTOR,
NULL_TREE, NULL_TREE, base_inits);
+ TREE_HAS_CONSTRUCTOR (base_inits) = 1;
base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE);
/* Prepend the number of bases. */
base_inits = tree_cons (NULL_TREE,
build_int_2 (nbases, 0), base_inits);
/* Prepend the hint flags. */
*************** create_pseudo_type_info VPARAMS((const c
*** 1161,1171 ****
fields[++ix] = field_decl;
/* Create the pseudo type. */
pseudo_type = make_aggr_type (RECORD_TYPE);
finish_builtin_type (pseudo_type, pseudo_name, fields, ix, ptr_type_node);
! TYPE_HAS_CONSTRUCTOR (pseudo_type) = 1;
result = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
TINFO_REAL_NAME (result) = get_identifier (real_name);
TINFO_PSEUDO_TYPE (result) =
cp_build_qualified_type (pseudo_type, TYPE_QUAL_CONST);
--- 1163,1173 ----
fields[++ix] = field_decl;
/* Create the pseudo type. */
pseudo_type = make_aggr_type (RECORD_TYPE);
finish_builtin_type (pseudo_type, pseudo_name, fields, ix, ptr_type_node);
! CLASSTYPE_AS_BASE (pseudo_type) = pseudo_type;
result = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
TINFO_REAL_NAME (result) = get_identifier (real_name);
TINFO_PSEUDO_TYPE (result) =
cp_build_qualified_type (pseudo_type, TYPE_QUAL_CONST);
Index: cp/typeck2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck2.c,v
retrieving revision 1.129
diff -c -5 -p -r1.129 typeck2.c
*** cp/typeck2.c 30 Sep 2002 16:52:15 -0000 1.129
--- cp/typeck2.c 11 Oct 2002 16:19:59 -0000
*************** store_init_value (decl, init)
*** 365,383 ****
}
}
/* End of special C++ code. */
! /* We might have already run this bracketed initializer through
! digest_init. Don't do so again. */
! if (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init)
! && TREE_TYPE (init)
! && TYPE_MAIN_VARIANT (TREE_TYPE (init)) == TYPE_MAIN_VARIANT (type))
! value = init;
! else
! /* Digest the specified initializer into an expression. */
! value = digest_init (type, init, (tree *) 0);
/* Store the expression if valid; else report error. */
if (TREE_CODE (value) == ERROR_MARK)
;
--- 365,376 ----
}
}
/* End of special C++ code. */
! /* Digest the specified initializer into an expression. */
! value = digest_init (type, init, (tree *) 0);
/* Store the expression if valid; else report error. */
if (TREE_CODE (value) == ERROR_MARK)
;
*************** digest_init (type, init, tail)
*** 437,448 ****
tree type, init, *tail;
{
enum tree_code code = TREE_CODE (type);
tree element = NULL_TREE;
tree old_tail_contents = NULL_TREE;
! /* Nonzero if INIT is a braced grouping, which comes in as a CONSTRUCTOR
! tree node which has no TREE_TYPE. */
int raw_constructor;
/* By default, assume we use one element from a list.
We correct this later in the sole case where it is not true. */
--- 430,440 ----
tree type, init, *tail;
{
enum tree_code code = TREE_CODE (type);
tree element = NULL_TREE;
tree old_tail_contents = NULL_TREE;
! /* Nonzero if INIT is a braced grouping. */
int raw_constructor;
/* By default, assume we use one element from a list.
We correct this later in the sole case where it is not true. */
*************** digest_init (type, init, tail)
*** 469,482 ****
/* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
if (TREE_CODE (init) == NON_LVALUE_EXPR)
init = TREE_OPERAND (init, 0);
! if (TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == type)
! return init;
!
! raw_constructor = TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == 0;
if (raw_constructor
&& CONSTRUCTOR_ELTS (init) != 0
&& TREE_CHAIN (CONSTRUCTOR_ELTS (init)) == 0)
{
--- 461,472 ----
/* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
if (TREE_CODE (init) == NON_LVALUE_EXPR)
init = TREE_OPERAND (init, 0);
! raw_constructor = (TREE_CODE (init) == CONSTRUCTOR
! && TREE_HAS_CONSTRUCTOR (init));
if (raw_constructor
&& CONSTRUCTOR_ELTS (init) != 0
&& TREE_CHAIN (CONSTRUCTOR_ELTS (init)) == 0)
{
Index: testsuite/g++.dg/init/array1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/init/array1.C,v
retrieving revision 1.1
diff -c -5 -p -r1.1 array1.C
*** testsuite/g++.dg/init/array1.C 9 Oct 2001 15:44:25 -0000 1.1
--- testsuite/g++.dg/init/array1.C 11 Oct 2002 16:20:00 -0000
***************
*** 4,22 ****
// { dg-do run }
typedef int iArr[];
const iArr array4={
! {1},{2},{3},{4}
};
const iArr array3={
! {1},{2},{3}
};
const iArr array5={
! {1},{2},{3},{4},{5}
};
int main()
{
if (sizeof (array4)/sizeof (array4[0]) != 4
--- 4,22 ----
// { dg-do run }
typedef int iArr[];
const iArr array4={
! 1, 2, 3, 4
};
const iArr array3={
! 1, 2, 3
};
const iArr array5={
! 1, 2, 3, 4, 5
};
int main()
{
if (sizeof (array4)/sizeof (array4[0]) != 4
Index: testsuite/g++.dg/init/brace1.C
===================================================================
RCS file: testsuite/g++.dg/init/brace1.C
diff -N testsuite/g++.dg/init/brace1.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/init/brace1.C 11 Oct 2002 16:20:00 -0000
***************
*** 0 ****
--- 1,4 ----
+ // { dg-do compile }
+
+ int i[4] = { { 3 } }; // { dg-error "brace" }
+
Index: testsuite/g++.dg/init/copy2.C
===================================================================
RCS file: testsuite/g++.dg/init/copy2.C
diff -N testsuite/g++.dg/init/copy2.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/init/copy2.C 11 Oct 2002 16:20:00 -0000
***************
*** 0 ****
--- 1,5 ----
+ // { dg-do compile }
+
+ struct S { S (); };
+
+ volatile S s[1] = { S () };
Index: testsuite/g++.dg/init/copy3.C
===================================================================
RCS file: testsuite/g++.dg/init/copy3.C
diff -N testsuite/g++.dg/init/copy3.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/init/copy3.C 11 Oct 2002 16:20:00 -0000
***************
*** 0 ****
--- 1,16 ----
+ // { dg-do run }
+ // { dg-options "-fno-elide-constructors" }
+
+ int copies;
+
+ struct S {
+ S () {}
+ S (const S&) { ++copies; }
+ };
+
+ S s[1] = { S () };
+
+ int main () {
+ if (copies != 1)
+ return 1;
+ }
Index: testsuite/g++.old-deja/g++.ext/arrnew.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.ext/arrnew.C,v
retrieving revision 1.3
diff -c -5 -p -r1.3 arrnew.C
*** testsuite/g++.old-deja/g++.ext/arrnew.C 12 Feb 2001 14:29:13 -0000 1.3
--- testsuite/g++.old-deja/g++.ext/arrnew.C 11 Oct 2002 16:20:00 -0000
***************
*** 1,7 ****
// PRMS Id: 4992
// Build don't link:
// Special g++ Options:
int *f(){
! return new int[1] = { 1 }; // WARNING - deprecated
}
--- 1,7 ----
// PRMS Id: 4992
// Build don't link:
// Special g++ Options:
int *f(){
! return new int[1] = { 1 }; // ERROR - removed
}
Index: testsuite/g++.old-deja/g++.mike/p9129.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.mike/p9129.C,v
retrieving revision 1.3
diff -c -5 -p -r1.3 p9129.C
*** testsuite/g++.old-deja/g++.mike/p9129.C 16 Dec 1998 21:48:47 -0000 1.3
--- testsuite/g++.old-deja/g++.mike/p9129.C 11 Oct 2002 16:20:00 -0000
***************
*** 5,12 ****
class Foo {
public:
int DoSomething();
};
! int (Foo::*pA)() = { &Foo::DoSomething };
int (Foo::*X[1])(int) = { { &Foo::DoSomething } }; // ERROR -
int (Foo::*Y[])(int) = { { &Foo::DoSomething, &Foo::DoSomething, 0 } }; // ERROR -
--- 5,12 ----
class Foo {
public:
int DoSomething();
};
! int (Foo::*pA)() = { &Foo::DoSomething }; // ERROR -
int (Foo::*X[1])(int) = { { &Foo::DoSomething } }; // ERROR -
int (Foo::*Y[])(int) = { { &Foo::DoSomething, &Foo::DoSomething, 0 } }; // ERROR -