diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 699718000999a02d78af9e8bf0d80b36aeb3f301..d2cb7fd1132d78357d3b18afc9c0b0113e2ebcfc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2019-03-05 Jason Merrill <jason@redhat.com> + + * class.c (is_really_empty_class): Add ignore_vptr parm. + (trivial_default_constructor_is_constexpr): Pass it. + * call.c (build_over_call): Pass it. + * constexpr.c (cxx_eval_constant_expression): Pass it instead of + checking TYPE_POLYMORPHIC_P. + (cxx_eval_component_reference, potential_constant_expression_1): + Pass it. + * cp-gimplify.c (simple_empty_class_p): Pass it. + * init.c (expand_aggr_init_1): Pass it. + 2019-03-04 Paolo Carlini <paolo.carlini@oracle.com> PR c++/84605 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 1a29eb7bb192c52609cfceea424f0b0500f56f10..04516eb967c2b982ad7138111058daa3feafd050 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -8566,7 +8566,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) tree arg = argarray[1]; location_t loc = cp_expr_loc_or_loc (arg, input_location); - if (is_really_empty_class (type)) + if (is_really_empty_class (type, /*ignore_vptr*/true)) { /* Avoid copying empty classes. */ val = build2 (COMPOUND_EXPR, type, arg, to); diff --git a/gcc/cp/class.c b/gcc/cp/class.c index f44acfd62b5eaaaf230173d1fc020360a78bb748..0d4d35bd690acdd69d0d2e9c5ea560dc1863f503 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5137,7 +5137,8 @@ trivial_default_constructor_is_constexpr (tree t) /* A defaulted trivial default constructor is constexpr if there is nothing to initialize. */ gcc_assert (!TYPE_HAS_COMPLEX_DFLT (t)); - return is_really_empty_class (t); + /* A class with a vptr doesn't have a trivial default ctor. */ + return is_really_empty_class (t, /*ignore_vptr*/true); } /* Returns true iff class T has a constexpr default constructor. */ @@ -8310,10 +8311,12 @@ is_empty_class (tree type) } /* Returns true if TYPE contains no actual data, just various - possible combinations of empty classes and possibly a vptr. */ + possible combinations of empty classes. If IGNORE_VPTR is true, + a vptr doesn't prevent the class from being considered empty. Typically + we want to ignore the vptr on assignment, and not on initialization. */ bool -is_really_empty_class (tree type) +is_really_empty_class (tree type, bool ignore_vptr) { if (CLASS_TYPE_P (type)) { @@ -8327,22 +8330,25 @@ is_really_empty_class (tree type) if (COMPLETE_TYPE_P (type) && is_empty_class (type)) return true; + if (!ignore_vptr && TYPE_CONTAINS_VPTR_P (type)) + return false; + for (binfo = TYPE_BINFO (type), i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i) - if (!is_really_empty_class (BINFO_TYPE (base_binfo))) + if (!is_really_empty_class (BINFO_TYPE (base_binfo), ignore_vptr)) return false; for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL && !DECL_ARTIFICIAL (field) /* An unnamed bit-field is not a data member. */ && !DECL_UNNAMED_BIT_FIELD (field) - && !is_really_empty_class (TREE_TYPE (field))) + && !is_really_empty_class (TREE_TYPE (field), ignore_vptr)) return false; return true; } else if (TREE_CODE (type) == ARRAY_TYPE) return (integer_zerop (array_type_nelts_top (type)) - || is_really_empty_class (TREE_TYPE (type))); + || is_really_empty_class (TREE_TYPE (type), ignore_vptr)); return false; } diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 65888b60d6325cd7b55ff588f5d9dd61e22db8d1..1c3c7252807164ba808abe8411131587730f03b7 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -2714,7 +2714,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, /* We only create a CONSTRUCTOR for a subobject when we modify it, so empty classes never get represented; throw together a value now. */ - if (is_really_empty_class (TREE_TYPE (t))) + if (is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/false)) return build_constructor (TREE_TYPE (t), NULL); gcc_assert (DECL_CONTEXT (part) == TYPE_MAIN_VARIANT (TREE_TYPE (whole))); @@ -4427,12 +4427,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, CONST_DECL for aggregate constants. */ if (lval) return t; - /* is_really_empty_class doesn't take into account _vptr, so initializing - otherwise empty class with { } would overwrite the initializer that - initialize_vtable created for us. */ if (COMPLETE_TYPE_P (TREE_TYPE (t)) - && !TYPE_POLYMORPHIC_P (TREE_TYPE (t)) - && is_really_empty_class (TREE_TYPE (t))) + && is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/false)) { /* If the class is empty, we aren't actually loading anything. */ r = build_constructor (TREE_TYPE (t), NULL); @@ -4480,7 +4476,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, else if (TYPE_REF_P (TREE_TYPE (t))) /* Defer, there's no lvalue->rvalue conversion. */; else if (COMPLETE_TYPE_P (TREE_TYPE (t)) - && is_really_empty_class (TREE_TYPE (t))) + && is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/false)) { /* If the class is empty, we aren't actually loading anything. */ r = build_constructor (TREE_TYPE (t), NULL); @@ -5956,7 +5952,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, || (DECL_INITIAL (t) && !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (t))) && COMPLETE_TYPE_P (TREE_TYPE (t)) - && !is_really_empty_class (TREE_TYPE (t))) + && !is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/false)) { if (flags & tf_error) non_const_var_error (t); diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 56f717de85dbdfb2ecec90dab0b65f2e04bd7073..26be1fd15223eb14e5bb8dfd08a3cc1e3595f908 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -584,7 +584,7 @@ simple_empty_class_p (tree type, tree op) && !TREE_CLOBBER_P (op)) || (TREE_CODE (op) == CALL_EXPR && !CALL_EXPR_RETURN_SLOT_OPT (op))) - && is_really_empty_class (type); + && is_really_empty_class (type, /*ignore_vptr*/true); } /* Returns true if evaluating E as an lvalue has side-effects; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 663a23b4043a783f94b19dbd31fa6aba349b10eb..15e39e1b5453f1ab1d389cbbe10b6310666b24e5 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6267,7 +6267,7 @@ extern void finish_struct_1 (tree); extern int resolves_to_fixed_type_p (tree, int *); extern void init_class_processing (void); extern int is_empty_class (tree); -extern bool is_really_empty_class (tree); +extern bool is_really_empty_class (tree, bool); extern void pushclass (tree); extern void popclass (void); extern void push_nested_class (tree); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 606d246ef940bb24298b01c8f95b5e7e01b1e971..eb3b504d708d7b80b780f7f4c677d26ab629b708 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2058,7 +2058,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, /* If the type has data but no user-provided ctor, we need to zero out the object. */ if (!type_has_user_provided_constructor (type) - && !is_really_empty_class (type)) + && !is_really_empty_class (type, /*ignore_vptr*/true)) { tree field_size = NULL_TREE; if (exp != true_exp && CLASSTYPE_AS_BASE (type) != type)