diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 34 | ||||
-rw-r--r-- | gcc/cp/call.c | 50 | ||||
-rw-r--r-- | gcc/cp/class.c | 69 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 22 | ||||
-rw-r--r-- | gcc/cp/cxx-pretty-print.c | 6 | ||||
-rw-r--r-- | gcc/cp/decl.c | 40 | ||||
-rw-r--r-- | gcc/cp/init.c | 4 | ||||
-rw-r--r-- | gcc/cp/parser.c | 8 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 26 | ||||
-rw-r--r-- | gcc/cp/tree.c | 116 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 4 |
11 files changed, 294 insertions, 85 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4265fa9..81cc8e0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,37 @@ +2009-07-16 Jason Merrill <jason@redhat.com> + + PR libstdc++/37907 + Split POD into "standard-layout" and "trivial" as per N2230, + Support std::is_standard_layout and std::is_trivial traits. + * cp-tree.h (enum cp_trait_kind): Add CPTK_IS_STD_LAYOUT, + CPTK_IS_TRIVIAL. + (struct lang_type_class): Add non_std_layout. + (CLASSTYPE_NON_STD_LAYOUT): New. + * class.c (check_bases): Set it. + (check_field_decls): Likewise. + (check_bases_and_members): Likewise. + * parser.c (cp_parser_primary_expression): Handle RID_IS_STD_LAYOUT, + RID_IS_TRIVIAL. + (cp_parser_trait_expr): Likewise. + * semantics.c (trait_expr_value): Handle CPTK_IS_STD_LAYOUT, + CPTK_IS_TRIVIAL. + (finish_trait_expr): Likewise. + * tree.c (scalarish_type_p, trivial_type_p, std_layout_type_p): New. + (pod_type_p): Use them. + (type_has_nontrivial_copy_init, type_has_nontrivial_default_init): New. + + Adjust bits of the language that no longer refer to POD types. + * call.c (convert_arg_to_ellipsis): Use type_has_nontrivial_copy_init + and TYPE_HAS_NONTRIVIAL_DESTRUCTOR rather than pod_type_p. + (build_x_va_arg): Likewise. + (call_builtin_trap): Remove. + * decl.c (declare_local_label): Use type_has_nontrivial_default_init + and TYPE_HAS_NONTRIVIAL_DESTRUCTOR rather than pod_type_p. + (cp_finish_decl): Likewise. + (check_previous_goto_1, check_goto): Adjust error. + * typeck.c (build_class_member_access_expr): Check + CLASSTYPE_NON_STD_LAYOUT rather than CLASSTYPE_NON_POD_P. + 2009-07-14 Taras Glek <tglek@mozilla.com> Rafael Espindola <espindola@google.com> diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 588c997..6a7a1b8 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -197,7 +197,6 @@ static conversion *direct_reference_binding (tree, conversion *); static bool promoted_arithmetic_type_p (tree); static conversion *conditional_conversion (tree, tree); static char *name_as_c_string (tree, tree, bool *); -static tree call_builtin_trap (void); static tree prep_operand (tree); static void add_candidates (tree, const VEC(tree,gc) *, tree, bool, tree, tree, int, struct z_candidate **); @@ -5042,18 +5041,6 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, return expr; } -/* Build a call to __builtin_trap. */ - -static tree -call_builtin_trap (void) -{ - tree fn = implicit_built_in_decls[BUILT_IN_TRAP]; - - gcc_assert (fn != NULL); - fn = build_call_n (fn, 0); - return fn; -} - /* ARG is being passed to a varargs function. Perform any conversions required. Return the converted value. */ @@ -5082,20 +5069,23 @@ convert_arg_to_ellipsis (tree arg) arg = require_complete_type (arg); if (arg != error_mark_node - && !pod_type_p (TREE_TYPE (arg))) + && (type_has_nontrivial_copy_init (TREE_TYPE (arg)) + || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (arg)))) { - /* Undefined behavior [expr.call] 5.2.2/7. We used to just warn - here and do a bitwise copy, but now cp_expr_size will abort if we - try to do that. + /* [expr.call] 5.2.2/7: + Passing a potentially-evaluated argument of class type (Clause 9) + with a non-trivial copy constructor or a non-trivial destructor + with no corresponding parameter is conditionally-supported, with + implementation-defined semantics. + + We used to just warn here and do a bitwise copy, but now + cp_expr_size will abort if we try to do that. + If the call appears in the context of a sizeof expression, - there is no need to emit a warning, since the expression won't be - evaluated. We keep the builtin_trap just as a safety check. */ + it is not potentially-evaluated. */ if (cp_unevaluated_operand == 0) - warning (0, "cannot pass objects of non-POD type %q#T through %<...%>; " - "call will abort at runtime", TREE_TYPE (arg)); - arg = call_builtin_trap (); - arg = build2 (COMPOUND_EXPR, integer_type_node, arg, - integer_zero_node); + error ("cannot pass objects of non-trivially-copyable " + "type %q#T through %<...%>", TREE_TYPE (arg)); } return arg; @@ -5114,16 +5104,16 @@ build_x_va_arg (tree expr, tree type) if (expr == error_mark_node || !type) return error_mark_node; - if (! pod_type_p (type)) + if (type_has_nontrivial_copy_init (type) + || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) + || TREE_CODE (type) == REFERENCE_TYPE) { /* Remove reference types so we don't ICE later on. */ tree type1 = non_reference (type); - /* Undefined behavior [expr.call] 5.2.2/7. */ - warning (0, "cannot receive objects of non-POD type %q#T through %<...%>; " - "call will abort at runtime", type); + /* conditionally-supported behavior [expr.call] 5.2.2/7. */ + error ("cannot receive objects of non-trivially-copyable type %q#T " + "through %<...%>; ", type); expr = convert (build_pointer_type (type1), null_node); - expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), - call_builtin_trap (), expr); expr = cp_build_indirect_ref (expr, NULL, tf_warning_or_error); return expr; } diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 4668c68..373f457 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1248,9 +1248,15 @@ check_bases (tree t, int seen_non_virtual_nearly_empty_base_p; tree base_binfo; tree binfo; + tree field = NULL_TREE; seen_non_virtual_nearly_empty_base_p = 0; + if (!CLASSTYPE_NON_STD_LAYOUT (t)) + for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL) + break; + for (binfo = TYPE_BINFO (t), i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) { @@ -1305,6 +1311,36 @@ check_bases (tree t, CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t) |= CLASSTYPE_CONTAINS_EMPTY_CLASS_P (basetype); TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_HAS_COMPLEX_DFLT (basetype); + + /* A standard-layout class is a class that: + ... + * has no non-standard-layout base classes, */ + CLASSTYPE_NON_STD_LAYOUT (t) |= CLASSTYPE_NON_STD_LAYOUT (basetype); + if (!CLASSTYPE_NON_STD_LAYOUT (t)) + { + tree basefield; + /* ...has no base classes of the same type as the first non-static + data member... */ + if (field && DECL_CONTEXT (field) == t + && (same_type_ignoring_top_level_qualifiers_p + (TREE_TYPE (field), basetype))) + CLASSTYPE_NON_STD_LAYOUT (t) = 1; + else + /* ...either has no non-static data members in the most-derived + class and at most one base class with non-static data + members, or has no base classes with non-static data + members */ + for (basefield = TYPE_FIELDS (basetype); basefield; + basefield = TREE_CHAIN (basefield)) + if (TREE_CODE (basefield) == FIELD_DECL) + { + if (field) + CLASSTYPE_NON_STD_LAYOUT (t) = 1; + else + field = basefield; + break; + } + } } } @@ -2870,6 +2906,7 @@ check_field_decls (tree t, tree *access_decls, bool has_pointers; int any_default_members; int cant_pack = 0; + int field_access = -1; /* Assume there are no access declarations. */ *access_decls = NULL_TREE; @@ -2883,6 +2920,7 @@ check_field_decls (tree t, tree *access_decls, { tree x = *field; tree type = TREE_TYPE (x); + int this_field_access; next = &TREE_CHAIN (x); @@ -2957,10 +2995,21 @@ check_field_decls (tree t, tree *access_decls, if (TREE_PRIVATE (x) || TREE_PROTECTED (x)) CLASSTYPE_NON_AGGREGATE (t) = 1; + /* A standard-layout class is a class that: + ... + has the same access control (Clause 11) for all non-static data members, + ... */ + this_field_access = TREE_PROTECTED (x) ? 1 : TREE_PRIVATE (x) ? 2 : 0; + if (field_access == -1) + field_access = this_field_access; + else if (this_field_access != field_access) + CLASSTYPE_NON_STD_LAYOUT (t) = 1; + /* If this is of reference type, check if it needs an init. */ if (TREE_CODE (type) == REFERENCE_TYPE) { - CLASSTYPE_NON_POD_P (t) = 1; + CLASSTYPE_NON_LAYOUT_POD_P (t) = 1; + CLASSTYPE_NON_STD_LAYOUT (t) = 1; if (DECL_INITIAL (x) == NULL_TREE) SET_CLASSTYPE_REF_FIELDS_NEED_INIT (t, 1); @@ -2975,7 +3024,7 @@ check_field_decls (tree t, tree *access_decls, if (TYPE_PACKED (t)) { - if (!pod_type_p (type) && !TYPE_PACKED (type)) + if (!layout_pod_type_p (type) && !TYPE_PACKED (type)) { warning (0, @@ -3024,10 +3073,13 @@ check_field_decls (tree t, tree *access_decls, if (DECL_MUTABLE_P (x) || TYPE_HAS_MUTABLE_P (type)) CLASSTYPE_HAS_MUTABLE (t) = 1; - if (! pod_type_p (type)) + if (! layout_pod_type_p (type)) /* DR 148 now allows pointers to members (which are POD themselves), to be allowed in POD structs. */ - CLASSTYPE_NON_POD_P (t) = 1; + CLASSTYPE_NON_LAYOUT_POD_P (t) = 1; + + if (!std_layout_type_p (type)) + CLASSTYPE_NON_STD_LAYOUT (t) = 1; if (! zero_init_p (type)) CLASSTYPE_NON_ZERO_INIT_P (t) = 1; @@ -4280,7 +4332,7 @@ type_requires_array_cookie (tree type) /* Check the validity of the bases and members declared in T. Add any implicitly-generated functions (like copy-constructors and assignment operators). Compute various flag bits (like - CLASSTYPE_NON_POD_T) for T. This routine works purely at the C++ + CLASSTYPE_NON_LAYOUT_POD_T) for T. This routine works purely at the C++ level: i.e., independently of the ABI in use. */ static void @@ -4346,9 +4398,12 @@ check_bases_and_members (tree t) elsewhere. */ CLASSTYPE_NON_AGGREGATE (t) |= (type_has_user_provided_constructor (t) || TYPE_POLYMORPHIC_P (t)); - CLASSTYPE_NON_POD_P (t) + /* This is the C++98/03 definition of POD; it changed in C++0x, but we + retain the old definition internally for ABI reasons. */ + CLASSTYPE_NON_LAYOUT_POD_P (t) |= (CLASSTYPE_NON_AGGREGATE (t) || saved_nontrivial_dtor || saved_complex_asn_ref); + CLASSTYPE_NON_STD_LAYOUT (t) |= TYPE_CONTAINS_VPTR_P (t); TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_CONTAINS_VPTR_P (t); TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_CONTAINS_VPTR_P (t); @@ -5031,7 +5086,7 @@ layout_class_type (tree t, tree *virtuals_p) /* Create the version of T used for virtual bases. We do not use make_class_type for this version; this is an artificial type. For a POD type, we just reuse T. */ - if (CLASSTYPE_NON_POD_P (t) || CLASSTYPE_EMPTY_P (t)) + if (CLASSTYPE_NON_LAYOUT_POD_P (t) || CLASSTYPE_EMPTY_P (t)) { base_t = make_node (TREE_CODE (t)); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 933da19..6ad039a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -494,6 +494,8 @@ typedef enum cp_trait_kind CPTK_IS_ENUM, CPTK_IS_POD, CPTK_IS_POLYMORPHIC, + CPTK_IS_STD_LAYOUT, + CPTK_IS_TRIVIAL, CPTK_IS_UNION } cp_trait_kind; @@ -1124,6 +1126,7 @@ struct GTY(()) lang_type_class { unsigned non_aggregate : 1; unsigned has_complex_dflt : 1; unsigned has_list_ctor : 1; + unsigned non_std_layout : 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 @@ -1132,7 +1135,7 @@ struct GTY(()) lang_type_class { /* 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 : 10; + unsigned dummy : 9; tree primary_base; VEC(tree_pair_s,gc) *vcall_indices; @@ -1385,8 +1388,14 @@ struct GTY(()) lang_type { #define CLASSTYPE_HAS_MUTABLE(NODE) (LANG_TYPE_CLASS_CHECK (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. */ -#define CLASSTYPE_NON_POD_P(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->non_pod_class) +/* Nonzero means that this class type is not POD for the purpose of layout + (as defined in the ABI). This is different from the language's POD. */ +#define CLASSTYPE_NON_LAYOUT_POD_P(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->non_pod_class) + +/* Nonzero means that this class type is a non-standard-layout class. */ +#define CLASSTYPE_NON_STD_LAYOUT(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->non_std_layout) /* Nonzero means that this class contains pod types whose default initialization is not a zero initialization (namely, pointers to @@ -4877,7 +4886,12 @@ extern void stabilize_aggr_init (tree, tree *); extern bool stabilize_init (tree, tree *); extern tree add_stmt_to_compound (tree, tree); extern void init_tree (void); -extern int pod_type_p (const_tree); +extern bool pod_type_p (const_tree); +extern bool layout_pod_type_p (const_tree); +extern bool std_layout_type_p (const_tree); +extern bool trivial_type_p (const_tree); +extern bool type_has_nontrivial_default_init (const_tree); +extern bool type_has_nontrivial_copy_init (const_tree); extern bool class_tmpl_impl_spec_p (const_tree); extern int zero_init_p (const_tree); extern tree strip_typedefs (tree); diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index b8732896..0b13bc1 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -2296,6 +2296,12 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) case CPTK_IS_POLYMORPHIC: pp_cxx_ws_string (pp, "__is_polymorphic"); break; + case CPTK_IS_STD_LAYOUT: + pp_cxx_ws_string (pp, "__is_std_layout"); + break; + case CPTK_IS_TRIVIAL: + pp_cxx_ws_string (pp, "__is_trivial"); + break; case CPTK_IS_UNION: pp_cxx_ws_string (pp, "__is_union"); break; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index e1b6678..e65e636 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2473,20 +2473,28 @@ declare_local_label (tree id) static int decl_jump_unsafe (tree decl) { + /* [stmt.dcl]/3: A program that jumps from a point where a local variable + with automatic storage duration is not in scope to a point where it is + in scope is ill-formed unless the variable has scalar type, class type + with a trivial default constructor and a trivial destructor, a + cv-qualified version of one of these types, or an array of one of the + preceding types and is declared without an initializer (8.5). */ + tree type = TREE_TYPE (decl); + if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl) - || TREE_TYPE (decl) == error_mark_node) + || type == error_mark_node) return 0; - if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)) + type = strip_array_types (type); + + if (type_has_nontrivial_default_init (TREE_TYPE (decl)) || DECL_NONTRIVIALLY_INITIALIZED_P (decl)) return 2; - if (pod_type_p (TREE_TYPE (decl))) - return 0; + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (decl))) + return 1; - /* The POD stuff is just pedantry; why should it matter if the class - contains a field of pointer to member type? */ - return 1; + return 0; } /* A subroutine of check_previous_goto_1 to identify a branch to the user. */ @@ -2541,7 +2549,8 @@ check_previous_goto_1 (tree decl, struct cp_binding_level* level, tree names, if (problem > 1) error (" crosses initialization of %q+#D", new_decls); else - permerror (input_location, " enters scope of non-POD %q+#D", new_decls); + permerror (input_location, " enters scope of %q+#D which has " + "non-trivial destructor", new_decls); } if (b == level) @@ -2656,7 +2665,8 @@ check_goto (tree decl) else if (u > 1) error (" skips initialization of %q+#D", b); else - permerror (input_location, " enters scope of non-POD %q+#D", b); + permerror (input_location, " enters scope of %q+#D which has " + "non-trivial destructor", b); } if (ent->in_try_scope) @@ -5687,11 +5697,13 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, 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_P (decl) && !pod_type_p (TREE_TYPE (decl))) - error ("%qD cannot be thread-local because it has non-POD type %qT", - decl, TREE_TYPE (decl)); + /* Only variables with trivial initialization and destruction can + have thread-local storage. */ + if (DECL_THREAD_LOCAL_P (decl) + && (type_has_nontrivial_default_init (TREE_TYPE (decl)) + || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))) + error ("%qD cannot be thread-local because it has non-trivial " + "type %qT", decl, TREE_TYPE (decl)); /* If this is a local variable that will need a mangled name, register it now. We must do this before processing the initializer for the variable, since the initialization might diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 19b2489..9118c61 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2703,7 +2703,7 @@ build_vec_init (tree base, tree maxindex, tree init, || ! TYPE_HAS_NONTRIVIAL_DESTRUCTOR (inner_elt_type))) || from_array)) { - /* Do non-default initialization of POD arrays resulting from + /* Do non-default initialization of trivial arrays resulting from brace-enclosed initializers. In this case, digest_init and store_constructor will handle the semantics for us. */ @@ -2769,7 +2769,7 @@ build_vec_init (tree base, tree maxindex, tree init, if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR) { - /* Do non-default initialization of non-POD arrays resulting from + /* Do non-default initialization of non-trivial arrays resulting from brace-enclosed initializers. */ unsigned HOST_WIDE_INT idx; tree elt; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 94fba02..e64d0bf 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -3399,6 +3399,8 @@ cp_parser_primary_expression (cp_parser *parser, case RID_IS_ENUM: case RID_IS_POD: case RID_IS_POLYMORPHIC: + case RID_IS_STD_LAYOUT: + case RID_IS_TRIVIAL: case RID_IS_UNION: return cp_parser_trait_expr (parser, token->keyword); @@ -6865,6 +6867,12 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) case RID_IS_POLYMORPHIC: kind = CPTK_IS_POLYMORPHIC; break; + case RID_IS_STD_LAYOUT: + kind = CPTK_IS_STD_LAYOUT; + break; + case RID_IS_TRIVIAL: + kind = CPTK_IS_TRIVIAL; + break; case RID_IS_UNION: kind = CPTK_IS_UNION; break; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 61dff51..4473c49 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4878,6 +4878,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) switch (kind) { case CPTK_HAS_NOTHROW_ASSIGN: + type1 = strip_array_types (type1); return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE && (trait_expr_value (CPTK_HAS_TRIVIAL_ASSIGN, type1, type2) || (CLASS_TYPE_P (type1) @@ -4885,8 +4886,11 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) true)))); case CPTK_HAS_TRIVIAL_ASSIGN: + /* ??? The standard seems to be missing the "or array of such a class + type" wording for this trait. */ + type1 = strip_array_types (type1); return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE - && (pod_type_p (type1) + && (trivial_type_p (type1) || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_ASSIGN_REF (type1)))); @@ -4899,21 +4903,25 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_HAS_TRIVIAL_CONSTRUCTOR: type1 = strip_array_types (type1); - return (pod_type_p (type1) + return (trivial_type_p (type1) || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1))); case CPTK_HAS_NOTHROW_COPY: + type1 = strip_array_types (type1); return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2) || (CLASS_TYPE_P (type1) && classtype_has_nothrow_assign_or_copy_p (type1, false))); case CPTK_HAS_TRIVIAL_COPY: - return (pod_type_p (type1) || type_code1 == REFERENCE_TYPE + /* ??? The standard seems to be missing the "or array of such a class + type" wording for this trait. */ + type1 = strip_array_types (type1); + return (trivial_type_p (type1) || type_code1 == REFERENCE_TYPE || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_INIT_REF (type1))); case CPTK_HAS_TRIVIAL_DESTRUCTOR: type1 = strip_array_types (type1); - return (pod_type_p (type1) || type_code1 == REFERENCE_TYPE + return (trivial_type_p (type1) || type_code1 == REFERENCE_TYPE || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1))); @@ -4947,6 +4955,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_POLYMORPHIC: return (CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1)); + case CPTK_IS_STD_LAYOUT: + return (std_layout_type_p (type1)); + + case CPTK_IS_TRIVIAL: + return (trivial_type_p (type1)); + case CPTK_IS_UNION: return (type_code1 == UNION_TYPE); @@ -4995,6 +5009,8 @@ finish_trait_expr (cp_trait_kind kind, tree type1, tree type2) || kind == CPTK_IS_ENUM || kind == CPTK_IS_POD || kind == CPTK_IS_POLYMORPHIC + || kind == CPTK_IS_STD_LAYOUT + || kind == CPTK_IS_TRIVIAL || kind == CPTK_IS_UNION); if (kind == CPTK_IS_CONVERTIBLE_TO) @@ -5036,6 +5052,8 @@ finish_trait_expr (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_EMPTY: case CPTK_IS_POD: case CPTK_IS_POLYMORPHIC: + case CPTK_IS_STD_LAYOUT: + case CPTK_IS_TRIVIAL: if (!check_trait_type (type1)) { error ("incomplete type %qT not allowed", type1); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index a003b44..255a297 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2238,36 +2238,108 @@ is_dummy_object (const_tree ob) && TREE_OPERAND (ob, 0) == void_zero_node); } +/* Returns 1 iff type T is something we want to treat as a scalar type for + the purpose of deciding whether it is trivial/POD/standard-layout. */ + +static bool +scalarish_type_p (const_tree t) +{ + if (t == error_mark_node) + return 1; + + return (SCALAR_TYPE_P (t) + || TREE_CODE (t) == VECTOR_TYPE); +} + +/* Returns true iff T requires non-trivial default initialization. */ + +bool +type_has_nontrivial_default_init (const_tree t) +{ + t = strip_array_types (CONST_CAST_TREE (t)); + + if (CLASS_TYPE_P (t)) + return TYPE_HAS_COMPLEX_DFLT (t); + else + return 0; +} + +/* Returns true iff copying an object of type T is non-trivial. */ + +bool +type_has_nontrivial_copy_init (const_tree t) +{ + t = strip_array_types (CONST_CAST_TREE (t)); + + if (CLASS_TYPE_P (t)) + return TYPE_HAS_COMPLEX_INIT_REF (t); + else + return 0; +} + +/* Returns 1 iff type T is a trivial type, as defined in [basic.types]. */ + +bool +trivial_type_p (const_tree t) +{ + t = strip_array_types (CONST_CAST_TREE (t)); + + if (CLASS_TYPE_P (t)) + return !(TYPE_HAS_COMPLEX_DFLT (t) + || TYPE_HAS_COMPLEX_INIT_REF (t) + || TYPE_HAS_COMPLEX_ASSIGN_REF (t) + || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)); + else + return scalarish_type_p (t); +} + /* Returns 1 iff type T is a POD type, as defined in [basic.types]. */ -int +bool pod_type_p (const_tree t) { /* This CONST_CAST is okay because strip_array_types returns its argument unmodified and we assign it to a const_tree. */ t = strip_array_types (CONST_CAST_TREE(t)); - if (t == error_mark_node) - return 1; - if (INTEGRAL_OR_ENUMERATION_TYPE_P (t)) - return 1; /* integral, character or enumeral type */ - if (FLOAT_TYPE_P (t)) - return 1; - if (TYPE_PTR_P (t)) - return 1; /* pointer to non-member */ - if (TYPE_PTR_TO_MEMBER_P (t)) - return 1; /* pointer to member */ - - if (TREE_CODE (t) == VECTOR_TYPE) - return 1; /* vectors are (small) arrays of scalars */ - - if (! RECORD_OR_UNION_CODE_P (TREE_CODE (t))) - return 0; /* other non-class type (reference or function) */ - if (! CLASS_TYPE_P (t)) - return 1; /* struct created by the back end */ - if (CLASSTYPE_NON_POD_P (t)) - return 0; - return 1; + if (CLASS_TYPE_P (t)) + /* [class]/10: A POD struct is a class that is both a trivial class and a + standard-layout class, and has no non-static data members of type + non-POD struct, non-POD union (or array of such types). + + We don't need to check individual members because if a member is + non-std-layout or non-trivial, the class will be too. */ + return (std_layout_type_p (t) && trivial_type_p (t)); + else + return scalarish_type_p (t); +} + +/* Returns true iff T is POD for the purpose of layout, as defined in the + C++ ABI. */ + +bool +layout_pod_type_p (const_tree t) +{ + t = strip_array_types (CONST_CAST_TREE (t)); + + if (CLASS_TYPE_P (t)) + return !CLASSTYPE_NON_LAYOUT_POD_P (t); + else + return scalarish_type_p (t); +} + +/* Returns true iff T is a standard-layout type, as defined in + [basic.types]. */ + +bool +std_layout_type_p (const_tree t) +{ + t = strip_array_types (CONST_CAST_TREE (t)); + + if (CLASS_TYPE_P (t)) + return !CLASSTYPE_NON_STD_LAYOUT (t); + else + return scalarish_type_p (t); } /* Nonzero iff type T is a class template implicit specialization. */ diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 6a4802e..9e49ce5 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2017,7 +2017,7 @@ build_class_member_access_expr (tree object, tree member, in various testsuite cases where a null object is passed where a vtable access is required. */ if (null_object_p && warn_invalid_offsetof - && CLASSTYPE_NON_POD_P (object_type) + && CLASSTYPE_NON_STD_LAYOUT (object_type) && !DECL_FIELD_IS_BASE (member) && cp_unevaluated_operand == 0 && (complain & tf_warning)) @@ -3134,7 +3134,7 @@ convert_arguments (tree typelist, VEC(tree,gc) **values, tree fndecl, if (fndecl && DECL_BUILT_IN (fndecl) && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CONSTANT_P) /* Don't do ellipsis conversion for __built_in_constant_p - as this will result in spurious warnings for non-POD + as this will result in spurious errors for non-trivial types. */ val = require_complete_type (val); else |