genmatch.c (enum tree_code): Remove CONVERT{0,1,2} and VIEW_CONVERT{0,1,2}.
[gcc.git] / gcc / tree.c
index 6be756c19ee17f77a4f434c08646ce4da419115c..7a66d1003ee2887d938eaa0483916333f8ce237a 100644 (file)
@@ -54,7 +54,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-iterator.h"
 #include "gimplify.h"
 #include "tree-dfa.h"
-#include "params.h"
 #include "langhooks-def.h"
 #include "tree-diagnostic.h"
 #include "except.h"
@@ -67,6 +66,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "rtl.h"
 #include "regs.h"
 #include "tree-vector-builder.h"
+#include "gimple-fold.h"
+#include "escaped_string.h"
 
 /* Tree code classes.  */
 
@@ -1168,6 +1169,10 @@ free_node (tree node)
     vec_free (BLOCK_NONLOCALIZED_VARS (node));
   else if (code == TREE_BINFO)
     vec_free (BINFO_BASE_ACCESSES (node));
+  else if (code == OPTIMIZATION_NODE)
+    cl_optimization_option_free (TREE_OPTIMIZATION (node));
+  else if (code == TARGET_OPTION_NODE)
+    cl_target_option_free (TREE_TARGET_OPTION (node));
   ggc_free (node);
 }
 \f
@@ -1547,15 +1552,15 @@ wide_int_to_tree_1 (tree type, const wide_int_ref &pcst)
          if (TYPE_SIGN (type) == UNSIGNED)
            {
              /* Cache [0, N).  */
-             limit = INTEGER_SHARE_LIMIT;
-             if (IN_RANGE (hwi, 0, INTEGER_SHARE_LIMIT - 1))
+             limit = param_integer_share_limit;
+             if (IN_RANGE (hwi, 0, param_integer_share_limit - 1))
                ix = hwi;
            }
          else
            {
              /* Cache [-1, N).  */
-             limit = INTEGER_SHARE_LIMIT + 1;
-             if (IN_RANGE (hwi, -1, INTEGER_SHARE_LIMIT - 1))
+             limit = param_integer_share_limit + 1;
+             if (IN_RANGE (hwi, -1, param_integer_share_limit - 1))
                ix = hwi + 1;
            }
          break;
@@ -1731,23 +1736,24 @@ cache_integer_cst (tree t)
       if (TYPE_UNSIGNED (type))
        {
          /* Cache 0..N */
-         limit = INTEGER_SHARE_LIMIT;
+         limit = param_integer_share_limit;
 
          /* This is a little hokie, but if the prec is smaller than
-            what is necessary to hold INTEGER_SHARE_LIMIT, then the
+            what is necessary to hold param_integer_share_limit, then the
             obvious test will not get the correct answer.  */
          if (prec < HOST_BITS_PER_WIDE_INT)
            {
-             if (tree_to_uhwi (t) < (unsigned HOST_WIDE_INT) INTEGER_SHARE_LIMIT)
+             if (tree_to_uhwi (t)
+                 < (unsigned HOST_WIDE_INT) param_integer_share_limit)
                ix = tree_to_uhwi (t);
            }
-         else if (wi::ltu_p (wi::to_wide (t), INTEGER_SHARE_LIMIT))
+         else if (wi::ltu_p (wi::to_wide (t), param_integer_share_limit))
            ix = tree_to_uhwi (t);
        }
       else
        {
          /* Cache -1..N */
-         limit = INTEGER_SHARE_LIMIT + 1;
+         limit = param_integer_share_limit + 1;
 
          if (integer_minus_onep (t))
            ix = 0;
@@ -1755,10 +1761,10 @@ cache_integer_cst (tree t)
            {
              if (prec < HOST_BITS_PER_WIDE_INT)
                {
-                 if (tree_to_shwi (t) < INTEGER_SHARE_LIMIT)
+                 if (tree_to_shwi (t) < param_integer_share_limit)
                    ix = tree_to_shwi (t) + 1;
                }
-             else if (wi::ltu_p (wi::to_wide (t), INTEGER_SHARE_LIMIT))
+             else if (wi::ltu_p (wi::to_wide (t), param_integer_share_limit))
                ix = tree_to_shwi (t) + 1;
            }
        }
@@ -1852,6 +1858,9 @@ make_vector (unsigned log2_npatterns,
 tree
 build_vector_from_ctor (tree type, vec<constructor_elt, va_gc> *v)
 {
+  if (vec_safe_length (v) == 0)
+    return build_zero_cst (type);
+
   unsigned HOST_WIDE_INT idx, nelts;
   tree value;
 
@@ -3087,6 +3096,25 @@ first_field (const_tree type)
   return t;
 }
 
+/* Returns the last FIELD_DECL in the TYPE_FIELDS of the RECORD_TYPE or
+   UNION_TYPE TYPE, or NULL_TREE if none.  */
+
+tree
+last_field (const_tree type)
+{
+  tree last = NULL_TREE;
+
+  for (tree fld = TYPE_FIELDS (type); fld; fld = TREE_CHAIN (fld))
+    {
+      if (TREE_CODE (fld) != FIELD_DECL)
+       continue;
+
+      last = fld;
+    }
+
+  return last;
+}
+
 /* Concatenate two chains of nodes (chained through TREE_CHAIN)
    by modifying the last node in chain 1 to point to chain 2.
    This is the Lisp primitive `nconc'.  */
@@ -5362,9 +5390,15 @@ fld_incomplete_type_of (tree t, class free_lang_data_d *fld)
              TYPE_TYPELESS_STORAGE (copy) = 0;
              TYPE_FIELDS (copy) = NULL;
              TYPE_BINFO (copy) = NULL;
+             TYPE_FINAL_P (copy) = 0;
+             TYPE_EMPTY_P (copy) = 0;
            }
          else
-           TYPE_VALUES (copy) = NULL;
+           {
+             TYPE_VALUES (copy) = NULL;
+             ENUM_IS_OPAQUE (copy) = 0;
+             ENUM_IS_SCOPED (copy) = 0;
+           }
 
          /* Build copy of TYPE_DECL in TYPE_NAME if necessary.
             This is needed for ODR violation warnings to come out right (we
@@ -5447,6 +5481,7 @@ free_lang_data_in_binfo (tree binfo)
   BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE;
   BINFO_SUBVTT_INDEX (binfo) = NULL_TREE;
   BINFO_VPTR_FIELD (binfo) = NULL_TREE;
+  TREE_PUBLIC (binfo) = 0;
 
   FOR_EACH_VEC_ELT (*BINFO_BASE_BINFOS (binfo), i, t)
     free_lang_data_in_binfo (t);
@@ -5548,6 +5583,8 @@ free_lang_data_in_type (tree type, class free_lang_data_d *fld)
     {
       if (TREE_CODE (type) == ENUMERAL_TYPE)
        {
+         ENUM_IS_OPAQUE (type) = 0;
+         ENUM_IS_SCOPED (type) = 0;
          /* Type values are used only for C++ ODR checking.  Drop them
             for all type variants and non-ODR types.
             For ODR types the data is freed in free_odr_warning_data.  */
@@ -5803,7 +5840,8 @@ free_lang_data_in_decl (tree decl, class free_lang_data_d *fld)
       while (*nextp)
        {
          tree var = *nextp;
-         if (fndecl_built_in_p (var))
+         if (TREE_CODE (var) == FUNCTION_DECL
+             && fndecl_built_in_p (var))
            *nextp = TREE_CHAIN (var);
          else
            nextp = &TREE_CHAIN (var);
@@ -5962,8 +6000,9 @@ find_decls_types_r (tree *tp, int *ws, void *data)
     {
       for (tree *tem = &BLOCK_VARS (t); *tem; )
        {
-         if (TREE_CODE (*tem) != VAR_DECL
-             || !auto_var_in_fn_p (*tem, DECL_CONTEXT (*tem)))
+         if (TREE_CODE (*tem) != LABEL_DECL
+             && (TREE_CODE (*tem) != VAR_DECL
+                 || !auto_var_in_fn_p (*tem, DECL_CONTEXT (*tem))))
            {
              gcc_assert (TREE_CODE (*tem) != RESULT_DECL
                          && TREE_CODE (*tem) != PARM_DECL);
@@ -7787,279 +7826,6 @@ operation_no_trapping_overflow (tree type, enum tree_code code)
     }
 }
 
-namespace inchash
-{
-
-/* Generate a hash value for an expression.  This can be used iteratively
-   by passing a previous result as the HSTATE argument.
-
-   This function is intended to produce the same hash for expressions which
-   would compare equal using operand_equal_p.  */
-void
-add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
-{
-  int i;
-  enum tree_code code;
-  enum tree_code_class tclass;
-
-  if (t == NULL_TREE || t == error_mark_node)
-    {
-      hstate.merge_hash (0);
-      return;
-    }
-
-  STRIP_ANY_LOCATION_WRAPPER (t);
-
-  if (!(flags & OEP_ADDRESS_OF))
-    STRIP_NOPS (t);
-
-  code = TREE_CODE (t);
-
-  switch (code)
-    {
-    /* Alas, constants aren't shared, so we can't rely on pointer
-       identity.  */
-    case VOID_CST:
-      hstate.merge_hash (0);
-      return;
-    case INTEGER_CST:
-      gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
-      for (i = 0; i < TREE_INT_CST_EXT_NUNITS (t); i++)
-       hstate.add_hwi (TREE_INT_CST_ELT (t, i));
-      return;
-    case REAL_CST:
-      {
-       unsigned int val2;
-       if (!HONOR_SIGNED_ZEROS (t) && real_zerop (t))
-         val2 = rvc_zero;
-       else
-         val2 = real_hash (TREE_REAL_CST_PTR (t));
-       hstate.merge_hash (val2);
-       return;
-      }
-    case FIXED_CST:
-      {
-       unsigned int val2 = fixed_hash (TREE_FIXED_CST_PTR (t));
-       hstate.merge_hash (val2);
-       return;
-      }
-    case STRING_CST:
-      hstate.add ((const void *) TREE_STRING_POINTER (t),
-                 TREE_STRING_LENGTH (t));
-      return;
-    case COMPLEX_CST:
-      inchash::add_expr (TREE_REALPART (t), hstate, flags);
-      inchash::add_expr (TREE_IMAGPART (t), hstate, flags);
-      return;
-    case VECTOR_CST:
-      {
-       hstate.add_int (VECTOR_CST_NPATTERNS (t));
-       hstate.add_int (VECTOR_CST_NELTS_PER_PATTERN (t));
-       unsigned int count = vector_cst_encoded_nelts (t);
-       for (unsigned int i = 0; i < count; ++i)
-         inchash::add_expr (VECTOR_CST_ENCODED_ELT (t, i), hstate, flags);
-       return;
-      }
-    case SSA_NAME:
-      /* We can just compare by pointer.  */
-      hstate.add_hwi (SSA_NAME_VERSION (t));
-      return;
-    case PLACEHOLDER_EXPR:
-      /* The node itself doesn't matter.  */
-      return;
-    case BLOCK:
-    case OMP_CLAUSE:
-      /* Ignore.  */
-      return;
-    case TREE_LIST:
-      /* A list of expressions, for a CALL_EXPR or as the elements of a
-        VECTOR_CST.  */
-      for (; t; t = TREE_CHAIN (t))
-       inchash::add_expr (TREE_VALUE (t), hstate, flags);
-      return;
-    case CONSTRUCTOR:
-      {
-       unsigned HOST_WIDE_INT idx;
-       tree field, value;
-       flags &= ~OEP_ADDRESS_OF;
-       FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), idx, field, value)
-         {
-           inchash::add_expr (field, hstate, flags);
-           inchash::add_expr (value, hstate, flags);
-         }
-       return;
-      }
-    case STATEMENT_LIST:
-      {
-       tree_stmt_iterator i;
-       for (i = tsi_start (CONST_CAST_TREE (t));
-            !tsi_end_p (i); tsi_next (&i))
-         inchash::add_expr (tsi_stmt (i), hstate, flags);
-       return;
-      }
-    case TREE_VEC:
-      for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
-       inchash::add_expr (TREE_VEC_ELT (t, i), hstate, flags);
-      return;
-    case IDENTIFIER_NODE:
-      hstate.add_object (IDENTIFIER_HASH_VALUE (t));
-      return;
-    case FUNCTION_DECL:
-      /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
-        Otherwise nodes that compare equal according to operand_equal_p might
-        get different hash codes.  However, don't do this for machine specific
-        or front end builtins, since the function code is overloaded in those
-        cases.  */
-      if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL
-         && builtin_decl_explicit_p (DECL_FUNCTION_CODE (t)))
-       {
-         t = builtin_decl_explicit (DECL_FUNCTION_CODE (t));
-         code = TREE_CODE (t);
-       }
-      /* FALL THROUGH */
-    default:
-      if (POLY_INT_CST_P (t))
-       {
-         for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
-           hstate.add_wide_int (wi::to_wide (POLY_INT_CST_COEFF (t, i)));
-         return;
-       }
-      tclass = TREE_CODE_CLASS (code);
-
-      if (tclass == tcc_declaration)
-       {
-         /* DECL's have a unique ID */
-         hstate.add_hwi (DECL_UID (t));
-       }
-      else if (tclass == tcc_comparison && !commutative_tree_code (code))
-       {
-         /* For comparisons that can be swapped, use the lower
-            tree code.  */
-         enum tree_code ccode = swap_tree_comparison (code);
-         if (code < ccode)
-           ccode = code;
-         hstate.add_object (ccode);
-         inchash::add_expr (TREE_OPERAND (t, ccode != code), hstate, flags);
-         inchash::add_expr (TREE_OPERAND (t, ccode == code), hstate, flags);
-       }
-      else if (CONVERT_EXPR_CODE_P (code))
-       {
-         /* NOP_EXPR and CONVERT_EXPR are considered equal by
-            operand_equal_p.  */
-         enum tree_code ccode = NOP_EXPR;
-         hstate.add_object (ccode);
-
-         /* Don't hash the type, that can lead to having nodes which
-            compare equal according to operand_equal_p, but which
-            have different hash codes.  Make sure to include signedness
-            in the hash computation.  */
-         hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
-         inchash::add_expr (TREE_OPERAND (t, 0), hstate, flags);
-       }
-      /* For OEP_ADDRESS_OF, hash MEM_EXPR[&decl, 0] the same as decl.  */
-      else if (code == MEM_REF
-              && (flags & OEP_ADDRESS_OF) != 0
-              && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
-              && DECL_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0))
-              && integer_zerop (TREE_OPERAND (t, 1)))
-       inchash::add_expr (TREE_OPERAND (TREE_OPERAND (t, 0), 0),
-                          hstate, flags);
-      /* Don't ICE on FE specific trees, or their arguments etc.
-        during operand_equal_p hash verification.  */
-      else if (!IS_EXPR_CODE_CLASS (tclass))
-       gcc_assert (flags & OEP_HASH_CHECK);
-      else
-       {
-         unsigned int sflags = flags;
-
-         hstate.add_object (code);
-
-         switch (code)
-           {
-           case ADDR_EXPR:
-             gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
-             flags |= OEP_ADDRESS_OF;
-             sflags = flags;
-             break;
-
-           case INDIRECT_REF:
-           case MEM_REF:
-           case TARGET_MEM_REF:
-             flags &= ~OEP_ADDRESS_OF;
-             sflags = flags;
-             break;
-
-           case ARRAY_REF:
-           case ARRAY_RANGE_REF:
-           case COMPONENT_REF:
-           case BIT_FIELD_REF:
-             sflags &= ~OEP_ADDRESS_OF;
-             break;
-
-           case COND_EXPR:
-             flags &= ~OEP_ADDRESS_OF;
-             break;
-
-           case WIDEN_MULT_PLUS_EXPR:
-           case WIDEN_MULT_MINUS_EXPR:
-             {
-               /* The multiplication operands are commutative.  */
-               inchash::hash one, two;
-               inchash::add_expr (TREE_OPERAND (t, 0), one, flags);
-               inchash::add_expr (TREE_OPERAND (t, 1), two, flags);
-               hstate.add_commutative (one, two);
-               inchash::add_expr (TREE_OPERAND (t, 2), two, flags);
-               return;
-             }
-
-           case CALL_EXPR:
-             if (CALL_EXPR_FN (t) == NULL_TREE)
-               hstate.add_int (CALL_EXPR_IFN (t));
-             break;
-
-           case TARGET_EXPR:
-             /* For TARGET_EXPR, just hash on the TARGET_EXPR_SLOT.
-                Usually different TARGET_EXPRs just should use
-                different temporaries in their slots.  */
-             inchash::add_expr (TARGET_EXPR_SLOT (t), hstate, flags);
-             return;
-
-           default:
-             break;
-           }
-
-         /* Don't hash the type, that can lead to having nodes which
-            compare equal according to operand_equal_p, but which
-            have different hash codes.  */
-         if (code == NON_LVALUE_EXPR)
-           {
-             /* Make sure to include signness in the hash computation.  */
-             hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
-             inchash::add_expr (TREE_OPERAND (t, 0), hstate, flags);
-           }
-
-         else if (commutative_tree_code (code))
-           {
-             /* It's a commutative expression.  We want to hash it the same
-                however it appears.  We do this by first hashing both operands
-                and then rehashing based on the order of their independent
-                hashes.  */
-             inchash::hash one, two;
-             inchash::add_expr (TREE_OPERAND (t, 0), one, flags);
-             inchash::add_expr (TREE_OPERAND (t, 1), two, flags);
-             hstate.add_commutative (one, two);
-           }
-         else
-           for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
-             inchash::add_expr (TREE_OPERAND (t, i), hstate,
-                                i == 0 ? flags : sflags);
-       }
-      return;
-    }
-}
-
-}
-
 /* Constructors for pointer, array and function types.
    (RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are
    constructed by language-dependent code, not here.)  */
@@ -9670,7 +9436,7 @@ dump_tree_statistics (void)
          {
            unsigned j = indices[i];
            fprintf (stderr, "%-20s %6" PRIu64 "%c %9" PRIu64 "%c\n",
-                    tree_node_kind_names[i], SIZE_AMOUNT (tree_node_counts[j]),
+                    tree_node_kind_names[j], SIZE_AMOUNT (tree_node_counts[j]),
                     SIZE_AMOUNT (tree_node_sizes[j]));
            total_nodes += tree_node_counts[j];
            total_bytes += tree_node_sizes[j];
@@ -10568,23 +10334,23 @@ build_common_tree_nodes (bool signed_char)
   uint64_type_node = make_or_reuse_type (64, 1);
 
   /* Decimal float types. */
-  dfloat32_type_node = make_node (REAL_TYPE);
-  TYPE_PRECISION (dfloat32_type_node) = DECIMAL32_TYPE_SIZE;
-  SET_TYPE_MODE (dfloat32_type_node, SDmode);
-  layout_type (dfloat32_type_node);
-  dfloat32_ptr_type_node = build_pointer_type (dfloat32_type_node);
-
-  dfloat64_type_node = make_node (REAL_TYPE);
-  TYPE_PRECISION (dfloat64_type_node) = DECIMAL64_TYPE_SIZE;
-  SET_TYPE_MODE (dfloat64_type_node, DDmode);
-  layout_type (dfloat64_type_node);
-  dfloat64_ptr_type_node = build_pointer_type (dfloat64_type_node);
-
-  dfloat128_type_node = make_node (REAL_TYPE);
-  TYPE_PRECISION (dfloat128_type_node) = DECIMAL128_TYPE_SIZE;
-  SET_TYPE_MODE (dfloat128_type_node, TDmode);
-  layout_type (dfloat128_type_node);
-  dfloat128_ptr_type_node = build_pointer_type (dfloat128_type_node);
+  if (targetm.decimal_float_supported_p ())
+    {
+      dfloat32_type_node = make_node (REAL_TYPE);
+      TYPE_PRECISION (dfloat32_type_node) = DECIMAL32_TYPE_SIZE;
+      SET_TYPE_MODE (dfloat32_type_node, SDmode);
+      layout_type (dfloat32_type_node);
+
+      dfloat64_type_node = make_node (REAL_TYPE);
+      TYPE_PRECISION (dfloat64_type_node) = DECIMAL64_TYPE_SIZE;
+      SET_TYPE_MODE (dfloat64_type_node, DDmode);
+      layout_type (dfloat64_type_node);
+
+      dfloat128_type_node = make_node (REAL_TYPE);
+      TYPE_PRECISION (dfloat128_type_node) = DECIMAL128_TYPE_SIZE;
+      SET_TYPE_MODE (dfloat128_type_node, TDmode);
+      layout_type (dfloat128_type_node);
+    }
 
   complex_integer_type_node = build_complex_type (integer_type_node, true);
   complex_float_type_node = build_complex_type (float_type_node, true);
@@ -11110,44 +10876,44 @@ build_vector_type (tree innertype, poly_int64 nunits)
   return make_vector_type (innertype, nunits, VOIDmode);
 }
 
-/* Build truth vector with specified length and number of units.  */
+/* Build a truth vector with NUNITS units, giving it mode MASK_MODE.  */
 
 tree
-build_truth_vector_type (poly_uint64 nunits, poly_uint64 vector_size)
+build_truth_vector_type_for_mode (poly_uint64 nunits, machine_mode mask_mode)
 {
-  machine_mode mask_mode
-    = targetm.vectorize.get_mask_mode (nunits, vector_size).else_blk ();
-
-  poly_uint64 vsize;
-  if (mask_mode == BLKmode)
-    vsize = vector_size * BITS_PER_UNIT;
-  else
-    vsize = GET_MODE_BITSIZE (mask_mode);
+  gcc_assert (mask_mode != BLKmode);
 
+  poly_uint64 vsize = GET_MODE_BITSIZE (mask_mode);
   unsigned HOST_WIDE_INT esize = vector_element_size (vsize, nunits);
-
   tree bool_type = build_nonstandard_boolean_type (esize);
 
   return make_vector_type (bool_type, nunits, mask_mode);
 }
 
-/* Returns a vector type corresponding to a comparison of VECTYPE.  */
+/* Build a vector type that holds one boolean result for each element of
+   vector type VECTYPE.  The public interface for this operation is
+   truth_type_for.  */
 
-tree
-build_same_sized_truth_vector_type (tree vectype)
+static tree
+build_truth_vector_type_for (tree vectype)
 {
-  if (VECTOR_BOOLEAN_TYPE_P (vectype))
-    return vectype;
+  machine_mode vector_mode = TYPE_MODE (vectype);
+  poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
 
-  poly_uint64 size = GET_MODE_SIZE (TYPE_MODE (vectype));
+  machine_mode mask_mode;
+  if (VECTOR_MODE_P (vector_mode)
+      && targetm.vectorize.get_mask_mode (vector_mode).exists (&mask_mode))
+    return build_truth_vector_type_for_mode (nunits, mask_mode);
 
-  if (known_eq (size, 0U))
-    size = tree_to_uhwi (TYPE_SIZE_UNIT (vectype));
+  poly_uint64 vsize = tree_to_poly_uint64 (TYPE_SIZE (vectype));
+  unsigned HOST_WIDE_INT esize = vector_element_size (vsize, nunits);
+  tree bool_type = build_nonstandard_boolean_type (esize);
 
-  return build_truth_vector_type (TYPE_VECTOR_SUBPARTS (vectype), size);
+  return make_vector_type (bool_type, nunits, BLKmode);
 }
 
-/* Similarly, but builds a variant type with TYPE_VECTOR_OPAQUE set.  */
+/* Like build_vector_type, but builds a variant type with TYPE_VECTOR_OPAQUE
+   set.  */
 
 tree
 build_opaque_vector_type (tree innertype, poly_int64 nunits)
@@ -11393,73 +11159,6 @@ initializer_each_zero_or_onep (const_tree expr)
     }
 }
 
-/* Given an initializer INIT for a TYPE, return true if INIT is zero
-   so that it can be replaced by value initialization.  This function
-   distinguishes betwen empty strings as initializers for arrays and
-   for pointers (which make it return false).  */
-
-bool
-type_initializer_zero_p (tree type, tree init)
-{
-  if (type  == error_mark_node || init == error_mark_node)
-    return false;
-
-  STRIP_NOPS (init);
-
-  if (POINTER_TYPE_P (type))
-    return TREE_CODE (init) != STRING_CST && initializer_zerop (init);
-
-  if (TREE_CODE (init) != CONSTRUCTOR)
-    return initializer_zerop (init);
-
-  if (TREE_CODE (type) == ARRAY_TYPE)
-    {
-      tree elt_type = TREE_TYPE (type);
-      elt_type = TYPE_MAIN_VARIANT (elt_type);
-      if (elt_type == char_type_node)
-       return initializer_zerop (init);
-
-      tree elt_init;
-      unsigned HOST_WIDE_INT i;
-      FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), i, elt_init)
-       if (!type_initializer_zero_p (elt_type, elt_init))
-         return false;
-      return true;
-    }
-
-  if (TREE_CODE (type) != RECORD_TYPE)
-    return initializer_zerop (init);
-
-  tree fld = TYPE_FIELDS (type);
-
-  tree fld_init;
-  unsigned HOST_WIDE_INT i;
-  FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), i, fld_init)
-    {
-      /* Advance to the next member, skipping over everything that
-        canot be initialized (including unnamed bit-fields).  */
-      while (TREE_CODE (fld) != FIELD_DECL
-            || DECL_ARTIFICIAL (fld)
-            || (DECL_BIT_FIELD (fld) && !DECL_NAME (fld)))
-       {
-         fld = DECL_CHAIN (fld);
-         if (!fld)
-           return true;
-         continue;
-       }
-
-      tree fldtype = TREE_TYPE (fld);
-      if (!type_initializer_zero_p (fldtype, fld_init))
-       return false;
-
-      fld = DECL_CHAIN (fld);
-      if (!fld)
-       break;
-    }
-
-  return true;
-}
-
 /* Check if vector VEC consists of all the equal elements and
    that the number of elements corresponds to the type of VEC.
    The function returns first element of the vector
@@ -12018,8 +11717,7 @@ truth_type_for (tree type)
     {
       if (VECTOR_BOOLEAN_TYPE_P (type))
        return type;
-      return build_truth_vector_type (TYPE_VECTOR_SUBPARTS (type),
-                                     GET_MODE_SIZE (TYPE_MODE (type)));
+      return build_truth_vector_type_for (type);
     }
   else
     return boolean_type_node;
@@ -13223,22 +12921,6 @@ typedef_variant_p (const_tree type)
   return is_typedef_decl (TYPE_NAME (type));
 }
 
-/* A class to handle converting a string that might contain
-   control characters, (eg newline, form-feed, etc), into one
-   in which contains escape sequences instead.  */
-
-class escaped_string
-{
- public:
-  escaped_string () { m_owned = false; m_str = NULL; };
-  ~escaped_string () { if (m_owned) free (m_str); }
-  operator const char *() const { return (const char *) m_str; }
-  void escape (const char *);
- private:
-  char *m_str;
-  bool  m_owned;
-};
-
 /* PR 84195: Replace control characters in "unescaped" with their
    escaped equivalents.  Allow newlines if -fmessage-length has
    been set to a non-zero value.  This is done here, rather than
@@ -13715,8 +13397,8 @@ array_ref_up_bound (tree exp)
   return NULL_TREE;
 }
 
-/* Returns true if REF is an array reference or a component reference
-   to an array at the end of a structure.
+/* Returns true if REF is an array reference, component reference,
+   or memory reference to an array at the end of a structure.
    If this is the case, the array may be allocated larger
    than its upper bound implies.  */
 
@@ -13734,6 +13416,28 @@ array_at_struct_end_p (tree ref)
   else if (TREE_CODE (ref) == COMPONENT_REF
           && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE)
     atype = TREE_TYPE (TREE_OPERAND (ref, 1));
+  else if (TREE_CODE (ref) == MEM_REF)
+    {
+      tree arg = TREE_OPERAND (ref, 0);
+      if (TREE_CODE (arg) == ADDR_EXPR)
+       arg = TREE_OPERAND (arg, 0);
+      tree argtype = TREE_TYPE (arg);
+      if (TREE_CODE (argtype) == RECORD_TYPE)
+       {
+         if (tree fld = last_field (argtype))
+           {
+             atype = TREE_TYPE (fld);
+             if (TREE_CODE (atype) != ARRAY_TYPE)
+               return false;
+             if (VAR_P (arg) && DECL_SIZE (fld))
+               return false;
+           }
+         else
+           return false;
+       }
+      else
+       return false;
+    }
   else
     return false;
 
@@ -13850,6 +13554,202 @@ component_ref_field_offset (tree exp)
     return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp);
 }
 
+/* Given the initializer INIT, return the initializer for the field
+   DECL if it exists, otherwise null.  Used to obtain the initializer
+   for a flexible array member and determine its size.  */
+
+static tree
+get_initializer_for (tree init, tree decl)
+{
+  STRIP_NOPS (init);
+
+  tree fld, fld_init;
+  unsigned HOST_WIDE_INT i;
+  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), i, fld, fld_init)
+    {
+      if (decl == fld)
+       return fld_init;
+
+      if (TREE_CODE (fld) == CONSTRUCTOR)
+       {
+         fld_init = get_initializer_for (fld_init, decl);
+         if (fld_init)
+           return fld_init;
+       }
+    }
+
+  return NULL_TREE;
+}
+
+/* Determines the size of the member referenced by the COMPONENT_REF
+   REF, using its initializer expression if necessary in order to
+   determine the size of an initialized flexible array member.
+   If non-null, *INTERIOR_ZERO_LENGTH is set when REF refers to
+   an interior zero-length array.
+   Returns the size (which might be zero for an object with
+   an uninitialized flexible array member) or null if the size
+   cannot be determined.  */
+
+tree
+component_ref_size (tree ref, bool *interior_zero_length /* = NULL */)
+{
+  gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
+
+  bool int_0_len = false;
+  if (!interior_zero_length)
+    interior_zero_length = &int_0_len;
+
+  tree member = TREE_OPERAND (ref, 1);
+
+  tree memsize = DECL_SIZE_UNIT (member);
+  if (memsize)
+    {
+      tree memtype = TREE_TYPE (member);
+      if (TREE_CODE (memtype) != ARRAY_TYPE)
+       return memsize;
+
+      bool trailing = array_at_struct_end_p (ref);
+      bool zero_length = integer_zerop (memsize);
+      if (!trailing && (!interior_zero_length || !zero_length))
+       /* MEMBER is either an interior array or is an array with
+          more than one element.  */
+       return memsize;
+
+      *interior_zero_length = zero_length && !trailing;
+      if (*interior_zero_length)
+       memsize = NULL_TREE;
+
+      if (!zero_length)
+       if (tree dom = TYPE_DOMAIN (memtype))
+         if (tree min = TYPE_MIN_VALUE (dom))
+           if (tree max = TYPE_MAX_VALUE (dom))
+             if (TREE_CODE (min) == INTEGER_CST
+                 && TREE_CODE (max) == INTEGER_CST)
+               {
+                 offset_int minidx = wi::to_offset (min);
+                 offset_int maxidx = wi::to_offset (max);
+                 if (maxidx - minidx > 0)
+                   /* MEMBER is an array with more than 1 element.  */
+                   return memsize;
+               }
+    }
+
+  /* MEMBER is either a bona fide flexible array member, or a zero-length
+     array member, or an array of length one treated as such.  */
+
+  /* If the reference is to a declared object and the member a true
+     flexible array, try to determine its size from its initializer.  */
+  poly_int64 baseoff = 0;
+  tree base = get_addr_base_and_unit_offset (ref, &baseoff);
+  if (!base || !VAR_P (base))
+    {
+      if (!*interior_zero_length)
+       return NULL_TREE;
+
+      if (TREE_CODE (TREE_OPERAND (ref, 0)) != COMPONENT_REF)
+       return NULL_TREE;
+
+      base = TREE_OPERAND (ref, 0);
+      while (TREE_CODE (base) == COMPONENT_REF)
+       base = TREE_OPERAND (base, 0);
+      baseoff = tree_to_poly_int64 (byte_position (TREE_OPERAND (ref, 1)));
+    }
+
+  /* BASE is the declared object of which MEMBER is either a member
+     or that is is cast to REFTYPE (e.g., a char buffer used to store
+     a REFTYPE object).  */
+  tree reftype = TREE_TYPE (TREE_OPERAND (ref, 0));
+  tree basetype = TREE_TYPE (base);
+
+  /* Determine the base type of the referenced object.  If it's
+     the same as REFTYPE and MEMBER has a known size, return it.  */
+  tree bt = basetype;
+  if (!*interior_zero_length)
+    while (TREE_CODE (bt) == ARRAY_TYPE)
+      bt = TREE_TYPE (bt);
+  bool typematch = useless_type_conversion_p (reftype, bt);
+  if (memsize && typematch)
+    return memsize;
+
+  memsize = NULL_TREE;
+
+  if (typematch)
+    /* MEMBER is a true flexible array member.  Compute its size from
+       the initializer of the BASE object if it has one.  */
+    if (tree init = DECL_P (base) ? DECL_INITIAL (base) : NULL_TREE)
+      {
+       init = get_initializer_for (init, member);
+       if (init)
+         {
+           memsize = TYPE_SIZE_UNIT (TREE_TYPE (init));
+           if (tree refsize = TYPE_SIZE_UNIT (reftype))
+             {
+               /* Use the larger of the initializer size and the tail
+                  padding in the enclosing struct.  */
+               poly_int64 rsz = tree_to_poly_int64 (refsize);
+               rsz -= baseoff;
+               if (known_lt (tree_to_poly_int64 (memsize), rsz))
+                 memsize = wide_int_to_tree (TREE_TYPE (memsize), rsz);
+             }
+
+           baseoff = 0;
+         }
+      }
+
+  if (!memsize)
+    {
+      if (typematch)
+       {
+         if (DECL_P (base)
+             && DECL_EXTERNAL (base)
+             && bt == basetype
+             && !*interior_zero_length)
+           /* The size of a flexible array member of an extern struct
+              with no initializer cannot be determined (it's defined
+              in another translation unit and can have an initializer
+              with an arbitrary number of elements).  */
+           return NULL_TREE;
+
+         /* Use the size of the base struct or, for interior zero-length
+            arrays, the size of the enclosing type.  */
+         memsize = TYPE_SIZE_UNIT (bt);
+       }
+      else if (DECL_P (base))
+       /* Use the size of the BASE object (possibly an array of some
+          other type such as char used to store the struct).  */
+       memsize = DECL_SIZE_UNIT (base);
+      else
+       return NULL_TREE;
+    }
+
+  /* If the flexible array member has a known size use the greater
+     of it and the tail padding in the enclosing struct.
+     Otherwise, when the size of the flexible array member is unknown
+     and the referenced object is not a struct, use the size of its
+     type when known.  This detects sizes of array buffers when cast
+     to struct types with flexible array members.  */
+  if (memsize)
+    {
+      poly_int64 memsz64 = memsize ? tree_to_poly_int64 (memsize) : 0;
+      if (known_lt (baseoff, memsz64))
+       {
+         memsz64 -= baseoff;
+         return wide_int_to_tree (TREE_TYPE (memsize), memsz64);
+       }
+      return integer_zero_node;
+    }
+
+  /* Return "don't know" for an external non-array object since its
+     flexible array member can be initialized to have any number of
+     elements.  Otherwise, return zero because the flexible array
+     member has no elements.  */
+  return (DECL_P (base)
+         && DECL_EXTERNAL (base)
+         && (!typematch
+             || TREE_CODE (basetype) != ARRAY_TYPE)
+         ? NULL_TREE : integer_zero_node);
+}
+
 /* Return the machine mode of T.  For vectors, returns the mode of the
    inner type.  The main use case is to feed the result to HONOR_NANS,
    avoiding the BLKmode that a direct TYPE_MODE (T) might return.  */
@@ -15103,6 +15003,41 @@ default_is_empty_record (const_tree type)
   return default_is_empty_type (TYPE_MAIN_VARIANT (type));
 }
 
+/* Determine whether TYPE is a structure with a flexible array member,
+   or a union containing such a structure (possibly recursively).  */
+
+bool
+flexible_array_type_p (const_tree type)
+{
+  tree x, last;
+  switch (TREE_CODE (type))
+    {
+    case RECORD_TYPE:
+      last = NULL_TREE;
+      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
+       if (TREE_CODE (x) == FIELD_DECL)
+         last = x;
+      if (last == NULL_TREE)
+       return false;
+      if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
+         && TYPE_SIZE (TREE_TYPE (last)) == NULL_TREE
+         && TYPE_DOMAIN (TREE_TYPE (last)) != NULL_TREE
+         && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (last))) == NULL_TREE)
+       return true;
+      return false;
+    case UNION_TYPE:
+      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
+       {
+         if (TREE_CODE (x) == FIELD_DECL
+             && flexible_array_type_p (TREE_TYPE (x)))
+           return true;
+       }
+      return false;
+    default:
+      return false;
+  }
+}
+
 /* Like int_size_in_bytes, but handle empty records specially.  */
 
 HOST_WIDE_INT
@@ -15223,6 +15158,21 @@ max_object_size (void)
   return TYPE_MAX_VALUE (ptrdiff_type_node);
 }
 
+/* A wrapper around TARGET_VERIFY_TYPE_CONTEXT that makes the silent_p
+   parameter default to false and that weeds out error_mark_node.  */
+
+bool
+verify_type_context (location_t loc, type_context_kind context,
+                    const_tree type, bool silent_p)
+{
+  if (type == error_mark_node)
+    return true;
+
+  gcc_assert (TYPE_P (type));
+  return (!targetm.verify_type_context
+         || targetm.verify_type_context (loc, context, type, silent_p));
+}
+
 #if CHECKING_P
 
 namespace selftest {