diff options
Diffstat (limited to 'gcc/cp/typeck2.c')
-rw-r--r-- | gcc/cp/typeck2.c | 149 |
1 files changed, 118 insertions, 31 deletions
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 750aa3c94bf..e4929275b91 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -133,6 +133,12 @@ abstract_virtuals_error (decl, type) tree u; tree tu; + if (processing_template_decl) + /* If we are processing a template, TYPE may be a template + class where CLASSTYPE_PURE_VIRTUALS always contains + inline friends. */ + return 0; + if (!CLASS_TYPE_P (type) || !CLASSTYPE_PURE_VIRTUALS (type)) return 0; @@ -273,7 +279,8 @@ retry: break; default: - abort (); + (*p_msg) ("invalid use of incomplete type"); + break; } } @@ -289,6 +296,109 @@ cxx_incomplete_type_error (value, type) } +/* The recursive part of split_nonconstant_init. DEST is an lvalue + expression to which INIT should be assigned. INIT is a CONSTRUCTOR. + PCODE is a pointer to the tail of a chain of statements being emitted. + The return value is the new tail of that chain after new statements + are generated. */ + +static tree * +split_nonconstant_init_1 (tree dest, tree init, tree *pcode) +{ + tree *pelt, elt, type = TREE_TYPE (dest); + tree sub, code, inner_type = NULL; + bool array_type_p = false; + + pelt = &CONSTRUCTOR_ELTS (init); + switch (TREE_CODE (type)) + { + case ARRAY_TYPE: + inner_type = TREE_TYPE (type); + array_type_p = true; + /* FALLTHRU */ + + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + while ((elt = *pelt)) + { + tree field_index = TREE_PURPOSE (elt); + tree value = TREE_VALUE (elt); + + if (!array_type_p) + inner_type = TREE_TYPE (field_index); + + if (TREE_CODE (value) == CONSTRUCTOR) + { + if (array_type_p) + sub = build (ARRAY_REF, inner_type, dest, field_index); + else + sub = build (COMPONENT_REF, inner_type, dest, field_index); + + pcode = split_nonconstant_init_1 (sub, value, pcode); + } + else if (!initializer_constant_valid_p (value, inner_type)) + { + *pelt = TREE_CHAIN (elt); + + if (array_type_p) + sub = build (ARRAY_REF, inner_type, dest, field_index); + else + sub = build (COMPONENT_REF, inner_type, dest, field_index); + + code = build (MODIFY_EXPR, inner_type, sub, value); + code = build_stmt (EXPR_STMT, code); + + *pcode = code; + pcode = &TREE_CHAIN (code); + continue; + } + pelt = &TREE_CHAIN (elt); + } + break; + + case VECTOR_TYPE: + if (!initializer_constant_valid_p (init, type)) + { + CONSTRUCTOR_ELTS (init) = NULL; + code = build (MODIFY_EXPR, type, dest, init); + code = build_stmt (EXPR_STMT, code); + pcode = &TREE_CHAIN (code); + } + break; + + default: + abort (); + } + + return pcode; +} + +/* A subroutine of store_init_value. Splits non-constant static + initializer INIT into a constant part and generates code to + perform the non-constant part of the initialization to DEST. + Returns the code for the runtime init. */ + +static tree +split_nonconstant_init (tree dest, tree init) +{ + tree code; + + if (TREE_CODE (init) == CONSTRUCTOR) + { + code = build_stmt (COMPOUND_STMT, NULL_TREE); + split_nonconstant_init_1 (dest, init, &COMPOUND_BODY (code)); + code = build1 (STMT_EXPR, void_type_node, code); + TREE_SIDE_EFFECTS (code) = 1; + DECL_INITIAL (dest) = init; + TREE_READONLY (dest) = 0; + } + else + code = build (INIT_EXPR, TREE_TYPE (dest), dest, init); + + return code; +} + /* Perform appropriate conversions on the initial value of a variable, store it in the declaration DECL, and print any error messages that are appropriate. @@ -304,9 +414,8 @@ cxx_incomplete_type_error (value, type) into a CONSTRUCTOR and use standard initialization techniques. Perhaps a warning should be generated? - Returns value of initializer if initialization could not be - performed for static variable. In that case, caller must do - the storing. */ + Returns code to be executed if initialization could not be performed + for static variable. In that case, caller must emit the code. */ tree store_init_value (decl, init) @@ -378,35 +487,11 @@ store_init_value (decl, init) constructing never make it into DECL_INITIAL, and passes 'init' to build_aggr_init without checking DECL_INITIAL. So just return. */ else if (TYPE_NEEDS_CONSTRUCTING (type)) - return value; + return build (INIT_EXPR, type, decl, value); else if (TREE_STATIC (decl) && (! TREE_CONSTANT (value) - || ! initializer_constant_valid_p (value, TREE_TYPE (value)) -#if 0 - /* A STATIC PUBLIC int variable doesn't have to be - run time inited when doing pic. (mrs) */ - /* Since ctors and dtors are the only things that can - reference vtables, and they are always written down - the vtable definition, we can leave the - vtables in initialized data space. - However, other initialized data cannot be initialized - this way. Instead a global file-level initializer - must do the job. */ - || (flag_pic && !DECL_VIRTUAL_P (decl) && TREE_PUBLIC (decl)) -#endif - )) - - return value; -#if 0 /* No, that's C. jason 9/19/94 */ - else - { - if (pedantic && TREE_CODE (value) == CONSTRUCTOR) - { - if (! TREE_CONSTANT (value) || ! TREE_STATIC (value)) - pedwarn ("ISO C++ forbids non-constant aggregate initializer expressions"); - } - } -#endif + || ! initializer_constant_valid_p (value, TREE_TYPE (value)))) + return split_nonconstant_init (decl, value); /* Store the VALUE in DECL_INITIAL. If we're building a statement-tree we will actually expand the initialization later @@ -726,6 +811,7 @@ process_init_constructor (type, init, elts) } else if (! zero_init_p (TREE_TYPE (type))) next1 = build_zero_init (TREE_TYPE (type), + /*nelts=*/NULL_TREE, /*static_storage_p=*/false); else /* The default zero-initialization is fine for us; don't @@ -844,6 +930,7 @@ process_init_constructor (type, init, elts) if (! zero_init_p (TREE_TYPE (field))) next1 = build_zero_init (TREE_TYPE (field), + /*nelts=*/NULL_TREE, /*static_storage_p=*/false); else /* The default zero-initialization is fine for us; don't |