From: Nathan Sidwell Date: Sun, 16 Mar 2003 14:36:43 +0000 (+0000) Subject: re PR c++/9629 (virtual inheritance segfault) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=1f5a253a36c2e680af7a627a5077a61fb8afe6b6;p=gcc.git re PR c++/9629 (virtual inheritance segfault) cp: PR c++/9629 * cp-tree.h (struct language_function): Add in_base_initializer. (in_base_initializer): define it. (expand_member_init): Remove INIT param. * init.c (expand_member_init): Remove INIT param, return the member. (emit_mem_initializers): Set in_base_initializer. * class.c (build_base_path): Check in_base_initializer. * parser.c (cp_parser_mem_initializer): Set in_base_initializer. * pt.c (tsubst_initializer_list): Likewise. testsuite: PR c++/9629 * g++.dg/init/ctor2.C: New test. From-SVN: r64438 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7cb5c9f931f..4a240a0176d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2003-03-16 Nathan Sidwell + + PR c++/9629 + * cp-tree.h (struct language_function): Add in_base_initializer. + (in_base_initializer): define it. + (expand_member_init): Remove INIT param. + * init.c (expand_member_init): Remove INIT param, return the member. + (emit_mem_initializers): Set in_base_initializer. + * class.c (build_base_path): Check in_base_initializer. + * parser.c (cp_parser_mem_initializer): Set in_base_initializer. + * pt.c (tsubst_initializer_list): Likewise. + 2003-03-16 Gabriel Dos Reis * decl.c (binding_for_name): Fix initialization thinko. @@ -596,7 +608,7 @@ 2003-02-21 Nathan Sidwell - * search.c (bfs_walk_grow): Remove. Fold into ... + * search.c (grow_bfs_bases): Remove. Fold into ... (bfs_walk): ... here, fix fencepost error. Fix merge lossage in previous patch. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 6b89becf176..0df87ae71af 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -302,8 +302,25 @@ build_base_path (enum tree_code code, /* Going via virtual base V_BINFO. We need the static offset from V_BINFO to BINFO, and the dynamic offset from D_BINFO to V_BINFO. That offset is an entry in D_BINFO's vtable. */ - tree v_offset = build_vfield_ref (build_indirect_ref (expr, NULL), - TREE_TYPE (TREE_TYPE (expr))); + tree v_offset; + + if (fixed_type_p < 0 && in_base_initializer) + { + /* In a base member initializer, we cannot rely on + the vtable being set up. We have to use the vtt_parm. */ + tree derived = BINFO_INHERITANCE_CHAIN (v_binfo); + + v_offset = build (PLUS_EXPR, TREE_TYPE (current_vtt_parm), + current_vtt_parm, BINFO_VPTR_INDEX (derived)); + + v_offset = build1 (INDIRECT_REF, + TREE_TYPE (TYPE_VFIELD (BINFO_TYPE (derived))), + v_offset); + + } + else + v_offset = build_vfield_ref (build_indirect_ref (expr, NULL), + TREE_TYPE (TREE_TYPE (expr))); v_offset = build (PLUS_EXPR, TREE_TYPE (v_offset), v_offset, BINFO_VPTR_FIELD (v_binfo)); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 59699cd918c..587acbcdad5 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -866,6 +866,7 @@ struct language_function GTY(()) int returns_null; int returns_abnormally; int in_function_try_handler; + int in_base_initializer; int x_expanding_p; struct named_label_use_list *x_named_label_uses; @@ -936,6 +937,9 @@ struct language_function GTY(()) #define doing_semantic_analysis_p() (!expanding_p) +/* Non-zero if we are processing a base initializer. Zero elsewhere. */ +#define in_base_initializer cp_function_chain->in_base_initializer + #define in_function_try_handler cp_function_chain->in_function_try_handler /* Expression always returned from function, or error_mark_node @@ -3915,7 +3919,7 @@ extern void add_friend (tree, tree); extern tree do_friend (tree, tree, tree, tree, tree, enum overload_flags, tree, int); /* in init.c */ -extern tree expand_member_init (tree, tree); +extern tree expand_member_init (tree); extern void emit_mem_initializers (tree); extern tree build_aggr_init (tree, tree, int); extern tree build_init (tree, tree, int); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 99812c6fbc6..d8542831f8a 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -146,7 +146,7 @@ initialize_vtbl_ptrs (addr) list = build_tree_list (type, addr); /* Walk through the hierarchy, initializing the vptr in each base - class. We do these in pre-order because can't find the virtual + class. We do these in pre-order because we can't find the virtual bases for a class until we've initialized the vtbl for that class. */ dfs_walk_real (TYPE_BINFO (type), dfs_initialize_vtbl_ptrs, @@ -664,6 +664,8 @@ emit_mem_initializers (tree mem_inits) initializations should be performed. */ mem_inits = sort_mem_initializers (current_class_type, mem_inits); + in_base_initializer = 1; + /* Initialize base classes. */ while (mem_inits && TREE_CODE (TREE_PURPOSE (mem_inits)) != FIELD_DECL) @@ -704,10 +706,11 @@ emit_mem_initializers (tree mem_inits) mem_inits = TREE_CHAIN (mem_inits); } + in_base_initializer = 0; /* Initialize the vptrs. */ initialize_vtbl_ptrs (current_class_ptr); - + /* Initialize the data members. */ while (mem_inits) { @@ -951,16 +954,15 @@ member_init_ok_or_else (field, type, member_name) /* NAME is a FIELD_DECL, an IDENTIFIER_NODE which names a field, or it is a _TYPE node or TYPE_DECL which names a base for that type. - INIT is a parameter list for that field's or base's constructor. - Check the validity of NAME, and return a TREE_LIST of the base - _TYPE or FIELD_DECL and the INIT. If NAME is invalid, return + Check the validity of NAME, and return either the base _TYPE, base + binfo, or the FIELD_DECL of the member. If NAME is invalid, return NULL_TREE and issue a diagnostic. An old style unnamed direct single base construction is permitted, where NAME is NULL. */ tree -expand_member_init (tree name, tree init) +expand_member_init (tree name) { tree basetype; tree field; @@ -997,14 +999,12 @@ expand_member_init (tree name, tree init) else basetype = NULL_TREE; - my_friendly_assert (init != NULL_TREE, 0); - if (basetype) { tree binfo; if (current_template_parms) - return build_tree_list (basetype, init); + return basetype; binfo = lookup_base (current_class_type, basetype, ba_ignore, NULL); @@ -1020,7 +1020,7 @@ expand_member_init (tree name, tree init) name, current_class_type); return NULL_TREE; } - return build_tree_list (binfo, init); + return binfo; } else { @@ -1030,7 +1030,7 @@ expand_member_init (tree name, tree init) field = name; if (member_init_ok_or_else (field, current_class_type, name)) - return build_tree_list (field, init); + return field; } return NULL_TREE; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 1c83227b934..f80c260f426 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7236,7 +7236,8 @@ cp_parser_mem_initializer (cp_parser* parser) { tree mem_initializer_id; tree expression_list; - + tree member; + /* Find out what is being initialized. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { @@ -7245,6 +7246,10 @@ cp_parser_mem_initializer (cp_parser* parser) } else mem_initializer_id = cp_parser_mem_initializer_id (parser); + member = expand_member_init (mem_initializer_id); + if (member && !DECL_P (member)) + in_base_initializer = 1; + /* Look for the opening `('. */ cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); /* Parse the expression-list. */ @@ -7256,8 +7261,9 @@ cp_parser_mem_initializer (cp_parser* parser) /* Look for the closing `)'. */ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); - return expand_member_init (mem_initializer_id, - expression_list); + in_base_initializer = 0; + + return member ? build_tree_list (member, expression_list) : NULL_TREE; } /* Parse a mem-initializer-id. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 410cd8fe025..87430b67ffb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11093,9 +11093,12 @@ tsubst_initializer_list (t, argvec) decl = tsubst_copy (TREE_PURPOSE (t), argvec, tf_error | tf_warning, NULL_TREE); + decl = expand_member_init (decl); + if (decl && !DECL_P (decl)) + in_base_initializer = 1; + init = tsubst_expr (TREE_VALUE (t), argvec, tf_error | tf_warning, NULL_TREE); - if (!init) ; else if (TREE_CODE (init) == TREE_LIST) @@ -11104,9 +11107,11 @@ tsubst_initializer_list (t, argvec) else if (init != void_type_node) init = convert_from_reference (init); - init = expand_member_init (decl, init); - if (init) + in_base_initializer = 0; + + if (decl) { + init = build_tree_list (decl, init); TREE_CHAIN (init) = inits; inits = init; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 92db48b9438..d4558f61f9d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2003-03-16 Nathan Sidwell + + PR c++/9629 + * g++.dg/init/ctor2.C: New test. + 2003-03-15 Roger Sayle * g77.f-torture/compile/xformat.f: New test case. diff --git a/gcc/testsuite/g++.dg/init/ctor2.C b/gcc/testsuite/g++.dg/init/ctor2.C new file mode 100644 index 00000000000..cf426f2bf16 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/ctor2.C @@ -0,0 +1,34 @@ +// { dg-do run } + +// Copyright (C) 2003 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 14 Mar 2003 + +// PR 9629. The vtable is not set up until the base initializers have +// run. + +struct A { + static A *a; + A (); +}; +A *A::a; +A::A () {a = this;} + +struct B { + static A *a; + B (A *); +}; +A *B::a; +B::B(A *a_) {a = a_;} + +struct C : virtual public A, public B { + C(); +}; +C::C () : B(this) {} + +struct D : virtual public C {}; + +int main() +{ + new D(); + return A::a != B::a; +}