re PR c++/86485 ("anonymous" maybe-uninitialized false positive with ternary operator)
authorJason Merrill <jason@redhat.com>
Tue, 5 Mar 2019 22:17:13 +0000 (17:17 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 5 Mar 2019 22:17:13 +0000 (17:17 -0500)
* 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

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/constexpr.c
gcc/cp/cp-gimplify.c
gcc/cp/cp-tree.h
gcc/cp/init.c

index 699718000999a02d78af9e8bf0d80b36aeb3f301..d2cb7fd1132d78357d3b18afc9c0b0113e2ebcfc 100644 (file)
@@ -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
index 1a29eb7bb192c52609cfceea424f0b0500f56f10..04516eb967c2b982ad7138111058daa3feafd050 100644 (file)
@@ -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);
index f44acfd62b5eaaaf230173d1fc020360a78bb748..0d4d35bd690acdd69d0d2e9c5ea560dc1863f503 100644 (file)
@@ -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;
 }
 
index 65888b60d6325cd7b55ff588f5d9dd61e22db8d1..1c3c7252807164ba808abe8411131587730f03b7 100644 (file)
@@ -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);
index 56f717de85dbdfb2ecec90dab0b65f2e04bd7073..26be1fd15223eb14e5bb8dfd08a3cc1e3595f908 100644 (file)
@@ -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;
index 663a23b4043a783f94b19dbd31fa6aba349b10eb..15e39e1b5453f1ab1d389cbbe10b6310666b24e5 100644 (file)
@@ -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);
index 606d246ef940bb24298b01c8f95b5e7e01b1e971..eb3b504d708d7b80b780f7f4c677d26ab629b708 100644 (file)
@@ -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)