This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Patch for C++ uninitialized pointer-to-member value
On May 13, 2002, Alexandre Oliva <aoliva@redhat.com> wrote:
> On May 13, 2002, Jason Merrill <jason@redhat.com> wrote:
>>> Ok. I didn't find a nice way to merge the code from
>>> build_default_init into it, thought. Is this ok?
>> Much of build_default_init can be moved to build_forced_zero_init and
>> replaced with a call; only the NEEDS_CONSTRUCTING and reference cases need
>> to be retained.
> Yeah, but then I'd have to remove the sanity check from
> build_forced_zero_init(), that is supposed to catch types that don't
> really need forced zero initialization. Besides,
> build_forced_zero_init() does not handle ENUMERAL_TYPEs, so it would
> call digest_init() an initializer of the wrong type, unless I moved
> this handling into forced_zero_init().
> Is this what you have in mind?
I've just tested this patch. Ok to install?
Index: gcc/cp/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
* cp-tree.h (struct lang_type): Added non_zero_init.
(CLASS_NON_ZERO_INIT_P): New macro.
(zero_init_p, force_store_init_value, build_forced_zero_init): Declare.
* class.c (check_field_decls): Test non_zero_init.
* cvt.c (convert_to_pointer_force): Use cp_convert_to_pointer for
zero-to-NULL conversions.
* decl.c (obscure_complex_init): Don't reset DECL_INITIAL of a
type that needs zero-initialization without zeros.
(check_initializer_decl): Compute zero-initializer for types
that require a non-trivial one.
* init.c (build_forced_zero_init): New function.
(build_default_init): Use it.
* tree.c (zero_init_p): New function.
* typeck2.c (force_store_init_value): New function.
(process_init_constructor): Create non-trivial zero-initializers
for array members and class fields.
Index: gcc/cp/class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.447
diff -u -p -r1.447 class.c
--- gcc/cp/class.c 30 Apr 2002 21:53:53 -0000 1.447
+++ gcc/cp/class.c 13 May 2002 08:49:57 -0000
@@ -3443,6 +3443,9 @@ check_field_decls (t, access_decls, empt
to be allowed in POD structs. */
CLASSTYPE_NON_POD_P (t) = 1;
+ if (! zero_init_p (type))
+ CLASSTYPE_NON_ZERO_INIT_P (t) = 1;
+
/* If any field is const, the structure type is pseudo-const. */
if (CP_TYPE_CONST_P (type))
{
Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.713
diff -u -p -r1.713 cp-tree.h
--- gcc/cp/cp-tree.h 9 May 2002 22:48:35 -0000 1.713
+++ gcc/cp/cp-tree.h 13 May 2002 08:50:00 -0000
@@ -1240,6 +1240,8 @@ struct lang_type
unsigned is_partial_instantiation : 1;
unsigned java_interface : 1;
+ unsigned non_zero_init : 1;
+
/* When adding a flag here, consider whether or not it ought to
apply to a template instance if it applies to the template. If
so, make sure to copy it in instantiate_class_template! */
@@ -1247,7 +1249,7 @@ struct lang_type
/* There are some bits left to fill out a 32-bit word. Keep track
of this by updating the size of this bitfield whenever you add or
remove a flag. */
- unsigned dummy : 8;
+ unsigned dummy : 7;
int vsize;
@@ -1501,9 +1503,14 @@ struct lang_type
#define CLASSTYPE_HAS_MUTABLE(NODE) (TYPE_LANG_SPECIFIC (NODE)->has_mutable)
#define TYPE_HAS_MUTABLE_P(NODE) (cp_has_mutable_p (NODE))
-/* Nonzero means that this class type is a non-POD class. */
+/* Nonzero means that this class type is a non-POD class. */
#define CLASSTYPE_NON_POD_P(NODE) (TYPE_LANG_SPECIFIC (NODE)->non_pod_class)
+/* Nonzero means that this class contains pod types whose default
+ initialization is not a zero initialization (namely, pointers to
+ data members). */
+#define CLASSTYPE_NON_ZERO_INIT_P(NODE) (TYPE_LANG_SPECIFIC (NODE)->non_zero_init)
+
/* Nonzero if this class is "nearly empty", i.e., contains only a
virtual function table pointer. */
#define CLASSTYPE_NEARLY_EMPTY_P(NODE) \
@@ -3912,6 +3919,7 @@ extern tree build_init PARAMS ((tree,
extern int is_aggr_type PARAMS ((tree, int));
extern tree get_aggr_from_typedef PARAMS ((tree, int));
extern tree get_type_value PARAMS ((tree));
+extern tree build_forced_zero_init PARAMS ((tree));
extern tree build_member_call PARAMS ((tree, tree, tree));
extern tree build_offset_ref PARAMS ((tree, tree));
extern tree resolve_offset_ref PARAMS ((tree));
@@ -4230,6 +4238,7 @@ extern tree cxx_unsave_expr_now PARAMS
extern tree cxx_maybe_build_cleanup PARAMS ((tree));
extern void init_tree PARAMS ((void));
extern int pod_type_p PARAMS ((tree));
+extern int zero_init_p PARAMS ((tree));
extern tree canonical_type_variant PARAMS ((tree));
extern void unshare_base_binfos PARAMS ((tree));
extern int member_p PARAMS ((tree));
@@ -4376,6 +4385,7 @@ extern int abstract_virtuals_error PARA
#define my_friendly_assert(EXP, N) (void) \
(((EXP) == 0) ? (fancy_abort (__FILE__, __LINE__, __FUNCTION__), 0) : 0)
+extern tree force_store_init_value PARAMS ((tree, tree));
extern tree store_init_value PARAMS ((tree, tree));
extern tree digest_init PARAMS ((tree, tree, tree *));
extern tree build_scoped_ref PARAMS ((tree, tree, tree *));
Index: gcc/cp/cvt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cvt.c,v
retrieving revision 1.117
diff -u -p -r1.117 cvt.c
--- gcc/cp/cvt.c 9 May 2002 17:27:36 -0000 1.117
+++ gcc/cp/cvt.c 13 May 2002 08:50:01 -0000
@@ -1,6 +1,6 @@
/* Language-level data type conversion for GNU C++.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -288,13 +288,6 @@ convert_to_pointer_force (type, expr)
register tree intype = TREE_TYPE (expr);
register enum tree_code form = TREE_CODE (intype);
- if (integer_zerop (expr))
- {
- expr = build_int_2 (0, 0);
- TREE_TYPE (expr) = type;
- return expr;
- }
-
if (form == POINTER_TYPE)
{
intype = TYPE_MAIN_VARIANT (intype);
Index: gcc/cp/decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.907
diff -u -p -r1.907 decl.c
--- gcc/cp/decl.c 3 May 2002 12:09:35 -0000 1.907
+++ gcc/cp/decl.c 13 May 2002 08:50:10 -0000
@@ -7592,7 +7592,13 @@ obscure_complex_init (decl, init)
NULL_TREE);
else
#endif
- DECL_INITIAL (decl) = error_mark_node;
+ {
+ if (zero_init_p (TREE_TYPE (decl)))
+ DECL_INITIAL (decl) = error_mark_node;
+ /* Otherwise, force_store_init_value will have already stored a
+ zero-init initializer in DECL_INITIAL, that should be
+ retained. */
+ }
return init;
}
@@ -7838,8 +7844,16 @@ check_initializer (decl, init)
if (init)
init = obscure_complex_init (decl, init);
}
+ else if (!DECL_EXTERNAL (decl) && !zero_init_p (type))
+ {
+ force_store_init_value (decl, build_forced_zero_init (type));
+
+ if (init)
+ goto process_init;
+ }
else if (init)
{
+ process_init:
if (TYPE_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type))
{
if (TREE_CODE (type) == ARRAY_TYPE)
Index: gcc/cp/init.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/init.c,v
retrieving revision 1.277
diff -u -p -r1.277 init.c
--- gcc/cp/init.c 17 Apr 2002 01:47:33 -0000 1.277
+++ gcc/cp/init.c 13 May 2002 08:50:13 -0000
@@ -1,6 +1,6 @@
/* Handle initialization things in C++.
Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -156,6 +156,44 @@ initialize_vtbl_ptrs (addr)
dfs_marked_real_bases_queue_p, type);
}
+/* Types containing pointers to data members cannot be
+ zero-initialized with zeros, because the NULL value for such
+ pointers is -1.
+
+ TYPE is a type that requires such zero initialization. The
+ returned value is the initializer. */
+
+tree
+build_forced_zero_init (type)
+ tree type;
+{
+ tree init = NULL;
+
+ if (AGGREGATE_TYPE_P (type) && !TYPE_PTRMEMFUNC_P (type))
+ {
+ /* This is a default initialization of an aggregate, but not one of
+ non-POD class type. We cleverly notice that the initialization
+ rules in such a case are the same as for initialization with an
+ empty brace-initialization list. */
+ init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, NULL_TREE);
+ }
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
+ /* --if T is a reference type, no initialization is performed. */
+ return NULL_TREE;
+ else
+ {
+ init = integer_zero_node;
+
+ if (TREE_CODE (type) == ENUMERAL_TYPE)
+ /* We must make enumeral types the right type. */
+ init = fold (build1 (NOP_EXPR, type, init));
+ }
+
+ init = digest_init (type, init, 0);
+
+ return init;
+}
+
/* [dcl.init]:
To default-initialize an object of type T means:
@@ -182,28 +220,8 @@ build_default_init (type)
anything with a CONSTRUCTOR for arrays here, as that would imply
copy-initialization. */
return NULL_TREE;
- else if (AGGREGATE_TYPE_P (type) && !TYPE_PTRMEMFUNC_P (type))
- {
- /* This is a default initialization of an aggregate, but not one of
- non-POD class type. We cleverly notice that the initialization
- rules in such a case are the same as for initialization with an
- empty brace-initialization list. */
- init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, NULL_TREE);
- }
- else if (TREE_CODE (type) == REFERENCE_TYPE)
- /* --if T is a reference type, no initialization is performed. */
- return NULL_TREE;
- else
- {
- init = integer_zero_node;
-
- if (TREE_CODE (type) == ENUMERAL_TYPE)
- /* We must make enumeral types the right type. */
- init = fold (build1 (NOP_EXPR, type, init));
- }
- init = digest_init (type, init, 0);
- return init;
+ return build_forced_zero_init (type);
}
/* Subroutine of emit_base_init. */
Index: gcc/cp/tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/tree.c,v
retrieving revision 1.282
diff -u -p -r1.282 tree.c
--- gcc/cp/tree.c 3 May 2002 16:22:08 -0000 1.282
+++ gcc/cp/tree.c 13 May 2002 08:50:15 -0000
@@ -1,6 +1,6 @@
/* Language-dependent node constructors for parse phase of GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -1898,6 +1898,27 @@ pod_type_p (t)
return 0; /* other non-class type (reference or function) */
if (CLASSTYPE_NON_POD_P (t))
return 0;
+ return 1;
+}
+
+/* Returns 1 iff zero initialization of type T means actually storing
+ zeros in it. */
+
+int
+zero_init_p (t)
+ tree t;
+{
+ t = strip_array_types (t);
+
+ /* NULL pointers to data members are initialized with -1. */
+ if (TYPE_PTRMEM_P (t))
+ return 0;
+
+ /* Classes that contain types that can't be zero-initialized, cannot
+ be zero-initialized themselves. */
+ if (CLASS_TYPE_P (t) && CLASSTYPE_NON_ZERO_INIT_P (t))
+ return 0;
+
return 1;
}
Index: gcc/cp/typeck2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/typeck2.c,v
retrieving revision 1.119
diff -u -p -r1.119 typeck2.c
--- gcc/cp/typeck2.c 18 Apr 2002 17:53:59 -0000 1.119
+++ gcc/cp/typeck2.c 13 May 2002 08:50:16 -0000
@@ -1,7 +1,7 @@
/* Report error messages, build initializers, and perform
some front-end optimizations for C++ compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -420,6 +420,28 @@ store_init_value (decl, init)
DECL_INITIAL (decl) = value;
return NULL_TREE;
}
+
+/* Same as store_init_value, but used for known-to-be-valid static
+ initializers. Used to introduce a static initializer even in data
+ structures that may require dynamic initialization. */
+
+tree
+force_store_init_value (decl, init)
+ tree decl, init;
+{
+ tree type = TREE_TYPE (decl);
+ int needs_constructing = TYPE_NEEDS_CONSTRUCTING (type);
+
+ TYPE_NEEDS_CONSTRUCTING (type) = 0;
+
+ init = store_init_value (decl, init);
+ if (init)
+ abort ();
+
+ TYPE_NEEDS_CONSTRUCTING (type) = needs_constructing;
+
+ return init;
+}
/* Digest the parser output INIT as an initializer for type TYPE.
Return a C expression of type TYPE to represent the initial value.
@@ -732,6 +754,8 @@ process_init_constructor (type, init, el
next1 = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, NULL_TREE);
next1 = digest_init (TREE_TYPE (type), next1, 0);
}
+ else if (! zero_init_p (TREE_TYPE (type)))
+ next1 = build_forced_zero_init (TREE_TYPE (type));
else
/* The default zero-initialization is fine for us; don't
add anything to the CONSTRUCTOR. */
@@ -848,9 +872,12 @@ process_init_constructor (type, init, el
&& (!init || TREE_HAS_CONSTRUCTOR (init)))
warning ("missing initializer for member `%D'", field);
- /* The default zero-initialization is fine for us; don't
- add anything to the CONSTRUCTOR. */
- continue;
+ if (! zero_init_p (TREE_TYPE (field)))
+ next1 = build_forced_zero_init (TREE_TYPE (field));
+ else
+ /* The default zero-initialization is fine for us; don't
+ add anything to the CONSTRUCTOR. */
+ continue;
}
if (next1 == error_mark_node)
Index: gcc/testsuite/g++.old-deja/g++.oliva/ChangeLog
from Jason Merrill <jason@redhat.com>, Alexandre Oliva <aoliva@redhat.com>
* pm1.C: New test.
Index: gcc/testsuite/g++.old-deja/g++.oliva/pm1.C
===================================================================
RCS file: gcc/testsuite/g++.old-deja/g++.oliva/pm1.C
diff -N gcc/testsuite/g++.old-deja/g++.oliva/pm1.C
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/g++.old-deja/g++.oliva/pm1.C 13 May 2002 08:50:16 -0000
@@ -0,0 +1,86 @@
+// Copyright 2002 Free Software Foundation
+// Contributed by Jason Merrill and Alexandre Oliva
+
+// Test zero-initialization of pointers to data members. Their NULL
+// value is represented with -1, not 0.
+
+#include <stdlib.h>
+
+struct A
+{
+ int i;
+};
+
+int A::* gp;
+
+typedef int A::* iApm;
+
+iApm gp_zero = 0;
+iApm gp_dflt = iApm();
+iApm gp_cast = (iApm)0;
+iApm gp_func = iApm(0);
+iApm gp_stat = static_cast<iApm>(0);
+
+struct AD : A {};
+
+int AD::* gp_impl = gp_dflt;
+int AD::* gp_down = static_cast<int AD::*>(gp_stat);
+
+int A::* ga[2];
+
+// Test use in a simple struct.
+struct B
+{
+ int A::* mp;
+};
+
+B gb;
+
+struct D;
+struct C;
+extern D gd;
+extern C gc;
+
+// Test that in a class with a constructor, the pointer to member is
+// zero-initialized until the constructor is run.
+struct C
+{
+ int A::* mp;
+ inline C ();
+};
+
+int fail;
+struct D
+{
+ int count;
+ inline D ();
+};
+
+C::C() : mp (&A::i) { gd.count++; }
+
+D::D() : count (0)
+{
+ if (gc.mp != 0)
+ abort ();
+}
+
+// The D must come first for this to work.
+D gd;
+C gc;
+
+int main()
+{
+ static int A::* slp;
+ static int A::* sla[2];
+ static B slb;
+
+ if (gp != 0 || slp != 0
+ || gp_zero != 0 || gp_dflt != 0 || gp_cast != 0
+ || gp_func != 0 || gp_stat != 0
+ || gp_impl != 0 || gp_down != 0)
+ abort ();
+ if (ga[1] != 0 || sla[1] != 0)
+ abort ();
+ if (gb.mp != 0 || slb.mp != 0)
+ abort ();
+}
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist Professional serial bug killer