Commit dbcd32f8 by Jason Merrill Committed by Jason Merrill

re PR c++/86485 ("anonymous" maybe-uninitialized false positive with ternary operator)

	* class.c (is_really_empty_class): Add ignore_vptr parm.

While looking at PR86485, I noticed that many uses of is_really_empty_class
were overlooking that it returned true for a class with only a vptr;
initialization of such a class is not trivial.  Marek's P1064 patch fixed
one place in constexpr.c to also check for a vtable, but there are several
others that still don't.

This patch requires callers to explicitly choose which behavior they want.
Currently the uses in constexpr.c want to consider the vptr, and other uses
don't.

	* 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.

From-SVN: r269402
parent 9bf54c93
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
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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;
......
......@@ -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);
......
......@@ -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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment