On Thu, Oct 03, 2019 at 03:57:17PM -0400, Jason Merrill wrote:
> That sounds better.

Ok.

> > And, second comment, not 100% sure about the unions, e.g. whether we
> > shouldn't somehow try to figure what is the active union member and only use
> > the active one rather than trying all.
> 
> Hmm, good question.  Can we get away with not recursing for unions? Trying
> all of them might end up choosing an inactive member that shares a common
> initial sequence with the active member.  Which is OK for reads, but not for
> writes.

Nothing in check-c++-all cares about unions there, so like this?
Worst case if we have a testcase that will break because of that
we'll need to figure out what to do.  But in unions it could very well just
find an inactive member without common initial sequence that just happens to
have the right type at the same offset.

So, is the following ok for trunk if it passes full bootstrap/regtest?
In attachment is the interdiff from the previous patch.

2019-10-03  Jakub Jelinek  <ja...@redhat.com>

        PR c++/71504
        * constexpr.c (cxx_fold_indirect_ref_1): New function.
        (cxx_fold_indirect_ref): Use it.

        * g++.dg/cpp0x/constexpr-array21.C: New test.
        * g++.dg/cpp1y/constexpr-array7.C: New test.
        * g++.dg/cpp1z/constexpr-array1.C: New test.

2019-10-03  Jason Merrill  <ja...@redhat.com>

        PR c++/71504
        * g++.dg/cpp0x/constexpr-array20.C: New test.

--- gcc/cp/constexpr.c.jj       2019-10-03 00:32:15.603526965 +0200
+++ gcc/cp/constexpr.c  2019-10-03 14:53:59.268559514 +0200
@@ -3346,6 +3346,103 @@ same_type_ignoring_tlq_and_bounds_p (tre
   return same_type_ignoring_top_level_qualifiers_p (type1, type2);
 }
 
+/* Helper function for cxx_fold_indirect_ref_1, called recursively.  */
+
+static tree
+cxx_fold_indirect_ref_1 (location_t loc, tree type, tree op,
+                        unsigned HOST_WIDE_INT off, bool *empty_base)
+{
+  tree optype = TREE_TYPE (op);
+  unsigned HOST_WIDE_INT const_nunits;
+  if (off == 0)
+    {
+      if (similar_type_p (optype, type))
+       return op;
+      /* Also handle conversion to an empty base class, which
+        is represented with a NOP_EXPR.  */
+      /* *(foo *)&complexfoo => __real__ complexfoo */
+      else if (TREE_CODE (optype) == COMPLEX_TYPE
+              && similar_type_p (type, TREE_TYPE (optype)))
+       return build1_loc (loc, REALPART_EXPR, type, op);
+    }
+  /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
+  else if (TREE_CODE (optype) == COMPLEX_TYPE
+          && similar_type_p (type, TREE_TYPE (optype))
+          && tree_to_uhwi (TYPE_SIZE_UNIT (type)) == off)
+    return build1_loc (loc, IMAGPART_EXPR, type, op);
+  if (is_empty_class (type)
+      && CLASS_TYPE_P (optype)
+      && DERIVED_FROM_P (type, optype))
+    {
+      *empty_base = true;
+      return op;
+    }
+  /* ((foo*)&vectorfoo)[x] => BIT_FIELD_REF<vectorfoo,...> */
+  else if (VECTOR_TYPE_P (optype)
+          && similar_type_p (type, TREE_TYPE (optype))
+          && TYPE_VECTOR_SUBPARTS (optype).is_constant (&const_nunits))
+    {
+      unsigned HOST_WIDE_INT part_width = tree_to_uhwi (TYPE_SIZE_UNIT (type));
+      unsigned HOST_WIDE_INT max_offset = part_width * const_nunits;
+      if (off < max_offset && off % part_width == 0)
+       {
+         tree index = bitsize_int (off * BITS_PER_UNIT);
+         return build3_loc (loc, BIT_FIELD_REF, type, op,
+                            TYPE_SIZE (type), index);
+       }
+    }
+  /* ((foo *)&fooarray)[x] => fooarray[x] */
+  else if (TREE_CODE (optype) == ARRAY_TYPE
+          && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (optype)))
+          && !integer_zerop (TYPE_SIZE_UNIT (TREE_TYPE (optype))))
+    {
+      tree type_domain = TYPE_DOMAIN (optype);
+      tree min_val = size_zero_node;
+      if (type_domain && TYPE_MIN_VALUE (type_domain))
+       min_val = TYPE_MIN_VALUE (type_domain);
+      unsigned HOST_WIDE_INT el_sz
+       = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (optype)));
+      unsigned HOST_WIDE_INT idx = off / el_sz;
+      unsigned HOST_WIDE_INT rem = off % el_sz;
+      if (tree_fits_uhwi_p (min_val))
+       {
+         tree index = size_int (idx + tree_to_uhwi (min_val));
+         op = build4_loc (loc, ARRAY_REF, TREE_TYPE (optype), op, index,
+                          NULL_TREE, NULL_TREE);
+         return cxx_fold_indirect_ref_1 (loc, type, op, rem,
+                                         empty_base);
+       }
+    }
+  /* ((foo *)&struct_with_foo_field)[x] => COMPONENT_REF */
+  else if (TREE_CODE (optype) == RECORD_TYPE)
+    {
+      for (tree field = TYPE_FIELDS (optype);
+          field; field = DECL_CHAIN (field))
+       if (TREE_CODE (field) == FIELD_DECL
+           && TREE_TYPE (field) != error_mark_node
+           && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (field))))
+         {
+           tree pos = byte_position (field);
+           if (!tree_fits_uhwi_p (pos))
+             continue;
+           unsigned HOST_WIDE_INT upos = tree_to_uhwi (pos);
+           unsigned el_sz
+             = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
+           if (upos <= off && off < upos + el_sz)
+             {
+               tree cop = build3 (COMPONENT_REF, TREE_TYPE (field),
+                                  op, field, NULL_TREE);
+               if (tree ret = cxx_fold_indirect_ref_1 (loc, type, cop,
+                                                       off - upos,
+                                                       empty_base))
+                 return ret;
+             }
+         }
+    }
+
+  return NULL_TREE;
+}
+
 /* A less strict version of fold_indirect_ref_1, which requires cv-quals to
    match.  We want to be less strict for simple *& folding; if we have a
    non-const temporary that we access through a const pointer, that should
@@ -3353,9 +3450,7 @@ same_type_ignoring_tlq_and_bounds_p (tre
    because we're dealing with things like ADDR_EXPR of INTEGER_CST which
    don't really make sense outside of constant expression evaluation.  Also
    we want to allow folding to COMPONENT_REF, which could cause trouble
-   with TBAA in fold_indirect_ref_1.
-
-   Try to keep this function synced with fold_indirect_ref_1.  */
+   with TBAA in fold_indirect_ref_1.  */
 
 static tree
 cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base)
@@ -3386,139 +3481,19 @@ cxx_fold_indirect_ref (location_t loc, t
          else
            return op;
        }
-      /* *(foo *)&fooarray => fooarray[0] */
-      else if (TREE_CODE (optype) == ARRAY_TYPE
-              && similar_type_p (type, TREE_TYPE (optype)))
-       {
-         tree type_domain = TYPE_DOMAIN (optype);
-         tree min_val = size_zero_node;
-         if (type_domain && TYPE_MIN_VALUE (type_domain))
-           min_val = TYPE_MIN_VALUE (type_domain);
-         return build4_loc (loc, ARRAY_REF, type, op, min_val,
-                            NULL_TREE, NULL_TREE);
-       }
-      /* *(foo *)&complexfoo => __real__ complexfoo */
-      else if (TREE_CODE (optype) == COMPLEX_TYPE
-              && similar_type_p (type, TREE_TYPE (optype)))
-       return fold_build1_loc (loc, REALPART_EXPR, type, op);
-      /* *(foo *)&vectorfoo => BIT_FIELD_REF<vectorfoo,...> */
-      else if (VECTOR_TYPE_P (optype)
-              && similar_type_p (type, TREE_TYPE (optype)))
-       {
-         tree part_width = TYPE_SIZE (type);
-         tree index = bitsize_int (0);
-         return fold_build3_loc (loc, BIT_FIELD_REF, type, op, part_width,
-                                 index);
-       }
-      /* Also handle conversion to an empty base class, which
-        is represented with a NOP_EXPR.  */
-      else if (is_empty_class (type)
-              && CLASS_TYPE_P (optype)
-              && DERIVED_FROM_P (type, optype))
-       {
-         *empty_base = true;
-         return op;
-       }
-      /* *(foo *)&struct_with_foo_field => COMPONENT_REF */
-      else if (RECORD_OR_UNION_TYPE_P (optype))
-       {
-         tree field = TYPE_FIELDS (optype);
-         for (; field; field = DECL_CHAIN (field))
-           if (TREE_CODE (field) == FIELD_DECL
-               && TREE_TYPE (field) != error_mark_node
-               && integer_zerop (byte_position (field))
-               && similar_type_p (TREE_TYPE (field), type))
-             return fold_build3 (COMPONENT_REF, type, op, field, NULL_TREE);
-       }
+      else
+       return cxx_fold_indirect_ref_1 (loc, type, op, 0, empty_base);
     }
   else if (TREE_CODE (sub) == POINTER_PLUS_EXPR
-          && poly_int_tree_p (TREE_OPERAND (sub, 1), &const_op01))
+          && tree_fits_uhwi_p (TREE_OPERAND (sub, 1)))
     {
       tree op00 = TREE_OPERAND (sub, 0);
       tree op01 = TREE_OPERAND (sub, 1);
 
       STRIP_NOPS (op00);
       if (TREE_CODE (op00) == ADDR_EXPR)
-       {
-         tree op00type;
-         op00 = TREE_OPERAND (op00, 0);
-         op00type = TREE_TYPE (op00);
-
-         /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */
-         if (VECTOR_TYPE_P (op00type)
-             && similar_type_p (type, TREE_TYPE (op00type))
-             /* POINTER_PLUS_EXPR second operand is sizetype, unsigned,
-                but we want to treat offsets with MSB set as negative.
-                For the code below negative offsets are invalid and
-                TYPE_SIZE of the element is something unsigned, so
-                check whether op01 fits into poly_int64, which implies
-                it is from 0 to INTTYPE_MAXIMUM (HOST_WIDE_INT), and
-                then just use poly_uint64 because we want to treat the
-                value as unsigned.  */
-             && tree_fits_poly_int64_p (op01))
-           {
-             tree part_width = TYPE_SIZE (type);
-             poly_uint64 max_offset
-               = (tree_to_uhwi (part_width) / BITS_PER_UNIT
-                  * TYPE_VECTOR_SUBPARTS (op00type));
-             if (known_lt (const_op01, max_offset))
-               {
-                 tree index = bitsize_int (const_op01 * BITS_PER_UNIT);
-                 return fold_build3_loc (loc,
-                                         BIT_FIELD_REF, type, op00,
-                                         part_width, index);
-               }
-           }
-         /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
-         else if (TREE_CODE (op00type) == COMPLEX_TYPE
-                  && similar_type_p (type, TREE_TYPE (op00type)))
-           {
-             if (known_eq (wi::to_poly_offset (TYPE_SIZE_UNIT (type)),
-                           const_op01))
-               return fold_build1_loc (loc, IMAGPART_EXPR, type, op00);
-           }
-         /* ((foo *)&fooarray)[1] => fooarray[1] */
-         else if (TREE_CODE (op00type) == ARRAY_TYPE
-                  && similar_type_p (type, TREE_TYPE (op00type)))
-           {
-             tree type_domain = TYPE_DOMAIN (op00type);
-             tree min_val = size_zero_node;
-             if (type_domain && TYPE_MIN_VALUE (type_domain))
-               min_val = TYPE_MIN_VALUE (type_domain);
-             offset_int off = wi::to_offset (op01);
-             offset_int el_sz = wi::to_offset (TYPE_SIZE_UNIT (type));
-             offset_int remainder;
-             off = wi::divmod_trunc (off, el_sz, SIGNED, &remainder);
-             if (remainder == 0 && TREE_CODE (min_val) == INTEGER_CST)
-               {
-                 off = off + wi::to_offset (min_val);
-                 op01 = wide_int_to_tree (sizetype, off);
-                 return build4_loc (loc, ARRAY_REF, type, op00, op01,
-                                    NULL_TREE, NULL_TREE);
-               }
-           }
-         /* Also handle conversion to an empty base class, which
-            is represented with a NOP_EXPR.  */
-         else if (is_empty_class (type)
-                  && CLASS_TYPE_P (op00type)
-                  && DERIVED_FROM_P (type, op00type))
-           {
-             *empty_base = true;
-             return op00;
-           }
-         /* ((foo *)&struct_with_foo_field)[1] => COMPONENT_REF */
-         else if (RECORD_OR_UNION_TYPE_P (op00type))
-           {
-             tree field = TYPE_FIELDS (op00type);
-             for (; field; field = DECL_CHAIN (field))
-               if (TREE_CODE (field) == FIELD_DECL
-                   && TREE_TYPE (field) != error_mark_node
-                   && tree_int_cst_equal (byte_position (field), op01)
-                   && similar_type_p (TREE_TYPE (field), type))
-                 return fold_build3 (COMPONENT_REF, type, op00,
-                                     field, NULL_TREE);
-           }
-       }
+       return cxx_fold_indirect_ref_1 (loc, type, TREE_OPERAND (op00, 0),
+                                       tree_to_uhwi (op01), empty_base);
     }
   /* *(foo *)fooarrptr => (*fooarrptr)[0] */
   else if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
--- gcc/testsuite/g++.dg/cpp0x/constexpr-array20.C.jj   2019-10-03 
15:59:29.108161779 +0200
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-array20.C      2019-10-03 
14:29:34.443660433 +0200
@@ -0,0 +1,15 @@
+// PR c++/71504
+// { dg-do compile { target c++11 } }
+
+enum E { e };
+
+constexpr bool arr[1][1] = {{true}};
+
+template<E x, E y>
+void check() { 
+    static_assert(arr[x][y], ""); 
+}
+
+int main() { 
+    check<e, e>(); 
+}
--- gcc/testsuite/g++.dg/cpp0x/constexpr-array21.C.jj   2019-10-03 
15:59:32.840105187 +0200
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-array21.C      2019-10-03 
15:15:42.260881097 +0200
@@ -0,0 +1,27 @@
+// PR c++/71504
+// { dg-do compile { target c++11 } }
+
+typedef const char A4 [10];
+
+constexpr A4 a [] = { "123", "123456", "123456789" };
+
+constexpr int len (const char *s)
+{
+  return *s ? 1 + len (s + 1) : 0;
+}
+
+constexpr const char *s = a[0];
+constexpr const char *t = (a + 2)[-2];
+
+constexpr int n0 = len (s);
+constexpr int n1 = len (t);
+
+constexpr int n2 = len (a[0]);
+constexpr int n3 = len ((a + 2)[-2]);
+
+#define A(e) static_assert ((e), #e)
+
+A (n0 == 3);
+A (n0 == n1);
+A (n0 == n2);
+A (n0 == n3);
--- gcc/testsuite/g++.dg/cpp1y/constexpr-array7.C.jj    2019-10-03 
16:04:04.280988955 +0200
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-array7.C       2019-10-03 
16:01:46.674075678 +0200
@@ -0,0 +1,16 @@
+// PR c++/71504
+// { dg-do compile { target c++14 } }
+
+template <typename A>
+constexpr auto
+sum (A const &a)
+{
+  int tot = 0;
+  for (auto &row : a)
+    for (auto elem : row)
+      tot += elem;
+  return tot;
+}
+
+constexpr int const a22[2][2] = {{1,2},{3,4}};
+static_assert (sum(a22) == 10, "badsum");
--- gcc/testsuite/g++.dg/cpp1z/constexpr-array1.C.jj    2019-10-03 
16:00:05.962602903 +0200
+++ gcc/testsuite/g++.dg/cpp1z/constexpr-array1.C       2019-10-03 
15:40:09.290739197 +0200
@@ -0,0 +1,46 @@
+// PR c++/71504
+// { dg-do compile { target c++17 } }
+
+typedef __SIZE_TYPE__ size_t;
+template <typename T, T v>
+struct integral_constant
+{
+  static constexpr T value = v;
+  typedef T value_type;
+  typedef integral_constant<T, v> type;
+  constexpr operator value_type () const noexcept { return value; }
+  constexpr value_type operator() () const noexcept { return value; }
+};
+template <typename T, T v>
+constexpr T integral_constant<T, v>::value;
+typedef integral_constant<bool, true> true_type;
+typedef integral_constant<bool, false> false_type;
+template <typename>
+struct is_array : public false_type { };
+template <typename T, size_t s>
+struct is_array<T[s]> : public true_type { };
+template <typename T>
+struct is_array<T[]> : public true_type { };
+template <bool, typename, typename>
+struct conditional;
+template <bool C, typename T, typename F>
+struct conditional { typedef T type; };
+template <typename T, typename F>
+struct conditional<false, T, F> { typedef F type; };
+template <typename T>
+struct array_ref;
+template <typename T>
+using ref_t = typename conditional<is_array<T>::value, array_ref<T>, T&>::type;
+template <typename T, unsigned N>
+struct array_ref<T[N]>
+{
+  T *a;
+  using const_reference = const ref_t<T>;
+  constexpr const_reference operator[] (unsigned I) const { return {a[I]}; }
+};
+template <typename A>
+array_ref (A&) -> array_ref<A>;
+constexpr int a2[2] = {1,2};
+static_assert (array_ref{a2}[0] == 1);
+constexpr int a22[2][2] = {{1,2},{3,4}};
+static_assert (array_ref{a22}[0][0] == 1);


        Jakub
diff -u gcc/cp/constexpr.c gcc/cp/constexpr.c
--- gcc/cp/constexpr.c  2019-10-03 14:53:59.268559514 +0200
+++ gcc/cp/constexpr.c  2019-10-03 14:53:59.268559514 +0200
@@ -3398,21 +3398,13 @@
     {
       tree type_domain = TYPE_DOMAIN (optype);
       tree min_val = size_zero_node;
-      tree max_val = NULL_TREE;
       if (type_domain && TYPE_MIN_VALUE (type_domain))
        min_val = TYPE_MIN_VALUE (type_domain);
-      if (type_domain && TYPE_MAX_VALUE (type_domain))
-       max_val = TYPE_MAX_VALUE (type_domain);
       unsigned HOST_WIDE_INT el_sz
        = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (optype)));
       unsigned HOST_WIDE_INT idx = off / el_sz;
       unsigned HOST_WIDE_INT rem = off % el_sz;
-      if (tree_fits_uhwi_p (min_val)
-         && (max_val == NULL_TREE
-             /* Punt on checking VLA bounds here.  */
-             || TREE_CODE (max_val) != INTEGER_CST
-             || (tree_fits_uhwi_p (max_val)
-                 && idx <= tree_to_uhwi (max_val))))
+      if (tree_fits_uhwi_p (min_val))
        {
          tree index = size_int (idx + tree_to_uhwi (min_val));
          op = build4_loc (loc, ARRAY_REF, TREE_TYPE (optype), op, index,
@@ -3422,7 +3414,7 @@
        }
     }
   /* ((foo *)&struct_with_foo_field)[x] => COMPONENT_REF */
-  else if (RECORD_OR_UNION_TYPE_P (optype))
+  else if (TREE_CODE (optype) == RECORD_TYPE)
     {
       for (tree field = TYPE_FIELDS (optype);
           field; field = DECL_CHAIN (field))
reverted:
--- gcc/testsuite/g++.dg/cpp0x/constexpr-array13.C      2019-10-03 
16:13:58.636977962 +0200
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-array13.C.jj   2015-11-26 
10:40:59.546389024 +0100
@@ -3,4 +3,4 @@
 
 constexpr char c[] = "hello";
 constexpr const char *p = c;
+constexpr char ch = *(p-1);  // { dg-error "array subscript" }
-constexpr char ch = *(p-1);  // { dg-error "is not a constant expression" }
reverted:
--- gcc/testsuite/g++.dg/ubsan/pr63956.C        2019-10-03 18:57:25.541783658 
+0200
+++ gcc/testsuite/g++.dg/ubsan/pr63956.C.jj     2019-06-19 10:20:12.390666122 
+0200
@@ -80,7 +80,7 @@
 fn5 (const int *a, int b)
 {
   if (b != 2)
+    b = a[b]; // { dg-error "array subscript" }
-    b = a[b]; // { dg-error "is not a constant expression" }
   return b;
 }
 

Reply via email to