[gcc/devel/rust/master] rust constexpr: porting cxx_eval_builtin_function_call

Thomas Schwinge tschwinge@gcc.gnu.org
Mon Aug 29 15:35:11 GMT 2022


https://gcc.gnu.org/g:8c2da345e08b313dfd0548064cdb3813a7c86d5a

commit 8c2da345e08b313dfd0548064cdb3813a7c86d5a
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date:   Tue Aug 9 14:52:54 2022 +0100

    rust constexpr: porting cxx_eval_builtin_function_call
    
    Signed-off-by: Faisal Abbas <90.abbasfaisal@gmail.com>

Diff:
---
 gcc/rust/backend/rust-tree.cc | 680 ++++++++++++++++++++++++++++++++++++++++++
 gcc/rust/backend/rust-tree.h  |  55 ++++
 2 files changed, 735 insertions(+)

diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 7f622cbbeb5..e1e56fc8336 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -5257,4 +5257,684 @@ fold_builtin_is_pointer_inverconvertible_with_class (location_t loc, int nargs,
 		      build_zero_cst (TREE_TYPE (arg)));
 }
 
+/* Used for communication between c_common_type_for_mode and
+   c_register_builtin_type.  */
+tree registered_builtin_types;
+
+/* Return a data type that has machine mode MODE.
+   If the mode is an integer,
+   then UNSIGNEDP selects between signed and unsigned types.
+   If the mode is a fixed-point mode,
+   then UNSIGNEDP selects between saturating and nonsaturating types.  */
+
+tree
+c_common_type_for_mode (machine_mode mode, int unsignedp)
+{
+  tree t;
+  int i;
+
+  if (mode == TYPE_MODE (integer_type_node))
+    return unsignedp ? unsigned_type_node : integer_type_node;
+
+  if (mode == TYPE_MODE (signed_char_type_node))
+    return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+
+  if (mode == TYPE_MODE (short_integer_type_node))
+    return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+
+  if (mode == TYPE_MODE (long_integer_type_node))
+    return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+  if (mode == TYPE_MODE (long_long_integer_type_node))
+    return unsignedp ? long_long_unsigned_type_node
+		     : long_long_integer_type_node;
+
+  for (i = 0; i < NUM_INT_N_ENTS; i++)
+    if (int_n_enabled_p[i] && mode == int_n_data[i].m)
+      return (unsignedp ? int_n_trees[i].unsigned_type
+			: int_n_trees[i].signed_type);
+
+  if (mode == QImode)
+    return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
+
+  if (mode == HImode)
+    return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
+
+  if (mode == SImode)
+    return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
+
+  if (mode == DImode)
+    return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
+
+#if HOST_BITS_PER_WIDE_INT >= 64
+  if (mode == TYPE_MODE (intTI_type_node))
+    return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
+#endif
+
+  if (mode == TYPE_MODE (float_type_node))
+    return float_type_node;
+
+  if (mode == TYPE_MODE (double_type_node))
+    return double_type_node;
+
+  if (mode == TYPE_MODE (long_double_type_node))
+    return long_double_type_node;
+
+  for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+    if (FLOATN_NX_TYPE_NODE (i) != NULL_TREE
+	&& mode == TYPE_MODE (FLOATN_NX_TYPE_NODE (i)))
+      return FLOATN_NX_TYPE_NODE (i);
+
+  if (mode == TYPE_MODE (void_type_node))
+    return void_type_node;
+
+  if (mode == TYPE_MODE (build_pointer_type (char_type_node))
+      || mode == TYPE_MODE (build_pointer_type (integer_type_node)))
+    {
+      unsigned int precision
+	= GET_MODE_PRECISION (as_a<scalar_int_mode> (mode));
+      return (unsignedp ? make_unsigned_type (precision)
+			: make_signed_type (precision));
+    }
+
+  if (COMPLEX_MODE_P (mode))
+    {
+      machine_mode inner_mode;
+      tree inner_type;
+
+      if (mode == TYPE_MODE (complex_float_type_node))
+	return complex_float_type_node;
+      if (mode == TYPE_MODE (complex_double_type_node))
+	return complex_double_type_node;
+      if (mode == TYPE_MODE (complex_long_double_type_node))
+	return complex_long_double_type_node;
+
+      for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+	if (COMPLEX_FLOATN_NX_TYPE_NODE (i) != NULL_TREE
+	    && mode == TYPE_MODE (COMPLEX_FLOATN_NX_TYPE_NODE (i)))
+	  return COMPLEX_FLOATN_NX_TYPE_NODE (i);
+
+      if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
+	return complex_integer_type_node;
+
+      inner_mode = GET_MODE_INNER (mode);
+      inner_type = c_common_type_for_mode (inner_mode, unsignedp);
+      if (inner_type != NULL_TREE)
+	return build_complex_type (inner_type);
+    }
+  else if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL
+	   && valid_vector_subparts_p (GET_MODE_NUNITS (mode)))
+    {
+      unsigned int elem_bits
+	= vector_element_size (GET_MODE_BITSIZE (mode), GET_MODE_NUNITS (mode));
+      tree bool_type = build_nonstandard_boolean_type (elem_bits);
+      return build_vector_type_for_mode (bool_type, mode);
+    }
+  else if (VECTOR_MODE_P (mode)
+	   && valid_vector_subparts_p (GET_MODE_NUNITS (mode)))
+    {
+      machine_mode inner_mode = GET_MODE_INNER (mode);
+      tree inner_type = c_common_type_for_mode (inner_mode, unsignedp);
+      if (inner_type != NULL_TREE)
+	return build_vector_type_for_mode (inner_type, mode);
+    }
+
+  if (dfloat32_type_node != NULL_TREE && mode == TYPE_MODE (dfloat32_type_node))
+    return dfloat32_type_node;
+  if (dfloat64_type_node != NULL_TREE && mode == TYPE_MODE (dfloat64_type_node))
+    return dfloat64_type_node;
+  if (dfloat128_type_node != NULL_TREE
+      && mode == TYPE_MODE (dfloat128_type_node))
+    return dfloat128_type_node;
+
+  if (ALL_SCALAR_FIXED_POINT_MODE_P (mode))
+    {
+      if (mode == TYPE_MODE (short_fract_type_node))
+	return unsignedp ? sat_short_fract_type_node : short_fract_type_node;
+      if (mode == TYPE_MODE (fract_type_node))
+	return unsignedp ? sat_fract_type_node : fract_type_node;
+      if (mode == TYPE_MODE (long_fract_type_node))
+	return unsignedp ? sat_long_fract_type_node : long_fract_type_node;
+      if (mode == TYPE_MODE (long_long_fract_type_node))
+	return unsignedp ? sat_long_long_fract_type_node
+			 : long_long_fract_type_node;
+
+      if (mode == TYPE_MODE (unsigned_short_fract_type_node))
+	return unsignedp ? sat_unsigned_short_fract_type_node
+			 : unsigned_short_fract_type_node;
+      if (mode == TYPE_MODE (unsigned_fract_type_node))
+	return unsignedp ? sat_unsigned_fract_type_node
+			 : unsigned_fract_type_node;
+      if (mode == TYPE_MODE (unsigned_long_fract_type_node))
+	return unsignedp ? sat_unsigned_long_fract_type_node
+			 : unsigned_long_fract_type_node;
+      if (mode == TYPE_MODE (unsigned_long_long_fract_type_node))
+	return unsignedp ? sat_unsigned_long_long_fract_type_node
+			 : unsigned_long_long_fract_type_node;
+
+      if (mode == TYPE_MODE (short_accum_type_node))
+	return unsignedp ? sat_short_accum_type_node : short_accum_type_node;
+      if (mode == TYPE_MODE (accum_type_node))
+	return unsignedp ? sat_accum_type_node : accum_type_node;
+      if (mode == TYPE_MODE (long_accum_type_node))
+	return unsignedp ? sat_long_accum_type_node : long_accum_type_node;
+      if (mode == TYPE_MODE (long_long_accum_type_node))
+	return unsignedp ? sat_long_long_accum_type_node
+			 : long_long_accum_type_node;
+
+      if (mode == TYPE_MODE (unsigned_short_accum_type_node))
+	return unsignedp ? sat_unsigned_short_accum_type_node
+			 : unsigned_short_accum_type_node;
+      if (mode == TYPE_MODE (unsigned_accum_type_node))
+	return unsignedp ? sat_unsigned_accum_type_node
+			 : unsigned_accum_type_node;
+      if (mode == TYPE_MODE (unsigned_long_accum_type_node))
+	return unsignedp ? sat_unsigned_long_accum_type_node
+			 : unsigned_long_accum_type_node;
+      if (mode == TYPE_MODE (unsigned_long_long_accum_type_node))
+	return unsignedp ? sat_unsigned_long_long_accum_type_node
+			 : unsigned_long_long_accum_type_node;
+
+      if (mode == QQmode)
+	return unsignedp ? sat_qq_type_node : qq_type_node;
+      if (mode == HQmode)
+	return unsignedp ? sat_hq_type_node : hq_type_node;
+      if (mode == SQmode)
+	return unsignedp ? sat_sq_type_node : sq_type_node;
+      if (mode == DQmode)
+	return unsignedp ? sat_dq_type_node : dq_type_node;
+      if (mode == TQmode)
+	return unsignedp ? sat_tq_type_node : tq_type_node;
+
+      if (mode == UQQmode)
+	return unsignedp ? sat_uqq_type_node : uqq_type_node;
+      if (mode == UHQmode)
+	return unsignedp ? sat_uhq_type_node : uhq_type_node;
+      if (mode == USQmode)
+	return unsignedp ? sat_usq_type_node : usq_type_node;
+      if (mode == UDQmode)
+	return unsignedp ? sat_udq_type_node : udq_type_node;
+      if (mode == UTQmode)
+	return unsignedp ? sat_utq_type_node : utq_type_node;
+
+      if (mode == HAmode)
+	return unsignedp ? sat_ha_type_node : ha_type_node;
+      if (mode == SAmode)
+	return unsignedp ? sat_sa_type_node : sa_type_node;
+      if (mode == DAmode)
+	return unsignedp ? sat_da_type_node : da_type_node;
+      if (mode == TAmode)
+	return unsignedp ? sat_ta_type_node : ta_type_node;
+
+      if (mode == UHAmode)
+	return unsignedp ? sat_uha_type_node : uha_type_node;
+      if (mode == USAmode)
+	return unsignedp ? sat_usa_type_node : usa_type_node;
+      if (mode == UDAmode)
+	return unsignedp ? sat_uda_type_node : uda_type_node;
+      if (mode == UTAmode)
+	return unsignedp ? sat_uta_type_node : uta_type_node;
+    }
+
+  for (t = registered_builtin_types; t; t = TREE_CHAIN (t))
+    {
+      tree type = TREE_VALUE (t);
+      if (TYPE_MODE (type) == mode
+	  && VECTOR_TYPE_P (type) == VECTOR_MODE_P (mode)
+	  && !!unsignedp == !!TYPE_UNSIGNED (type))
+	return type;
+    }
+  return NULL_TREE;
+}
+
+/* Implement the __underlying_type keyword: Return the underlying
+   type of TYPE, suitable for use as a type-specifier.  */
+
+tree
+finish_underlying_type (tree type)
+{
+  tree underlying_type;
+
+  if (!complete_type_or_else (type, NULL_TREE))
+    return error_mark_node;
+
+  if (TREE_CODE (type) != ENUMERAL_TYPE)
+    {
+      error ("%qT is not an enumeration type", type);
+      return error_mark_node;
+    }
+
+  underlying_type = ENUM_UNDERLYING_TYPE (type);
+
+  /* Fixup necessary in this case because ENUM_UNDERLYING_TYPE
+     includes TYPE_MIN_VALUE and TYPE_MAX_VALUE information.
+     See finish_enum_value_list for details.  */
+  if (!ENUM_FIXED_UNDERLYING_TYPE_P (type))
+    underlying_type = c_common_type_for_mode (TYPE_MODE (underlying_type),
+					      TYPE_UNSIGNED (underlying_type));
+
+  return underlying_type;
+}
+
+/* Return true if TYPE1 and TYPE2 are layout-compatible types.  */
+
+bool
+layout_compatible_type_p (tree type1, tree type2)
+{
+  if (type1 == error_mark_node || type2 == error_mark_node)
+    return false;
+  if (type1 == type2)
+    return true;
+  if (TREE_CODE (type1) != TREE_CODE (type2))
+    return false;
+
+  type1 = rs_build_qualified_type (type1, TYPE_UNQUALIFIED);
+  type2 = rs_build_qualified_type (type2, TYPE_UNQUALIFIED);
+
+  if (TREE_CODE (type1) == ENUMERAL_TYPE)
+    return (TYPE_ALIGN (type1) == TYPE_ALIGN (type2)
+	    && tree_int_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2))
+	    && same_type_p (finish_underlying_type (type1),
+			    finish_underlying_type (type2)));
+
+  if (CLASS_TYPE_P (type1) && std_layout_type_p (type1)
+      && std_layout_type_p (type2) && TYPE_ALIGN (type1) == TYPE_ALIGN (type2)
+      && tree_int_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2)))
+    {
+      tree field1 = TYPE_FIELDS (type1);
+      tree field2 = TYPE_FIELDS (type2);
+      if (TREE_CODE (type1) == RECORD_TYPE)
+	{
+	  while (1)
+	    {
+	      if (!next_common_initial_seqence (field1, field2))
+		return false;
+	      if (field1 == NULL_TREE)
+		return true;
+	      field1 = DECL_CHAIN (field1);
+	      field2 = DECL_CHAIN (field2);
+	    }
+	}
+      /* Otherwise both types must be union types.
+	 The standard says:
+	 "Two standard-layout unions are layout-compatible if they have
+	 the same number of non-static data members and corresponding
+	 non-static data members (in any order) have layout-compatible
+	 types."
+	 but the code anticipates that bitfield vs. non-bitfield,
+	 different bitfield widths or presence/absence of
+	 [[no_unique_address]] should be checked as well.  */
+      auto_vec<tree, 16> vec;
+      unsigned int count = 0;
+      for (; field1; field1 = DECL_CHAIN (field1))
+	if (TREE_CODE (field1) == FIELD_DECL)
+	  count++;
+      for (; field2; field2 = DECL_CHAIN (field2))
+	if (TREE_CODE (field2) == FIELD_DECL)
+	  vec.safe_push (field2);
+      /* Discussions on core lean towards treating multiple union fields
+	 of the same type as the same field, so this might need changing
+	 in the future.  */
+      if (count != vec.length ())
+	return false;
+      for (field1 = TYPE_FIELDS (type1); field1; field1 = DECL_CHAIN (field1))
+	{
+	  if (TREE_CODE (field1) != FIELD_DECL)
+	    continue;
+	  unsigned int j;
+	  tree t1 = DECL_BIT_FIELD_TYPE (field1);
+	  if (t1 == NULL_TREE)
+	    t1 = TREE_TYPE (field1);
+	  FOR_EACH_VEC_ELT (vec, j, field2)
+	    {
+	      tree t2 = DECL_BIT_FIELD_TYPE (field2);
+	      if (t2 == NULL_TREE)
+		t2 = TREE_TYPE (field2);
+	      if (DECL_BIT_FIELD_TYPE (field1))
+		{
+		  if (!DECL_BIT_FIELD_TYPE (field2))
+		    continue;
+		  if (TYPE_PRECISION (TREE_TYPE (field1))
+		      != TYPE_PRECISION (TREE_TYPE (field2)))
+		    continue;
+		}
+	      else if (DECL_BIT_FIELD_TYPE (field2))
+		continue;
+	      if (!layout_compatible_type_p (t1, t2))
+		continue;
+	      if ((!lookup_attribute ("no_unique_address",
+				      DECL_ATTRIBUTES (field1)))
+		  != !lookup_attribute ("no_unique_address",
+					DECL_ATTRIBUTES (field2)))
+		continue;
+	      break;
+	    }
+	  if (j == vec.length ())
+	    return false;
+	  vec.unordered_remove (j);
+	}
+      return true;
+    }
+
+  return same_type_p (type1, type2);
+}
+
+/* Helper function for is_corresponding_member_aggr.  Return true if
+   MEMBERTYPE pointer-to-data-member ARG can be found in anonymous
+   union or structure BASETYPE.  */
+
+static bool
+is_corresponding_member_union (tree basetype, tree membertype, tree arg)
+{
+  for (tree field = TYPE_FIELDS (basetype); field; field = DECL_CHAIN (field))
+    if (TREE_CODE (field) != FIELD_DECL || DECL_BIT_FIELD_TYPE (field))
+      continue;
+    else if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field),
+							membertype))
+      {
+	if (TREE_CODE (arg) != INTEGER_CST
+	    || tree_int_cst_equal (arg, byte_position (field)))
+	  return true;
+      }
+    else if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+      {
+	tree narg = arg;
+	if (TREE_CODE (basetype) != UNION_TYPE
+	    && TREE_CODE (narg) == INTEGER_CST)
+	  narg = size_binop (MINUS_EXPR, arg, byte_position (field));
+	if (is_corresponding_member_union (TREE_TYPE (field), membertype, narg))
+	  return true;
+      }
+  return false;
+}
+
+/* Helper function for layout_compatible_type_p and
+   is_corresponding_member_aggr.  Advance to next members (NULL if
+   no further ones) and return true if those members are still part of
+   the common initial sequence.  */
+
+bool
+next_common_initial_seqence (tree &memb1, tree &memb2)
+{
+  while (memb1)
+    {
+      if (TREE_CODE (memb1) != FIELD_DECL
+	  || (DECL_FIELD_IS_BASE (memb1) && is_empty_field (memb1)))
+	{
+	  memb1 = DECL_CHAIN (memb1);
+	  continue;
+	}
+      if (DECL_FIELD_IS_BASE (memb1))
+	{
+	  memb1 = TYPE_FIELDS (TREE_TYPE (memb1));
+	  continue;
+	}
+      break;
+    }
+  while (memb2)
+    {
+      if (TREE_CODE (memb2) != FIELD_DECL
+	  || (DECL_FIELD_IS_BASE (memb2) && is_empty_field (memb2)))
+	{
+	  memb2 = DECL_CHAIN (memb2);
+	  continue;
+	}
+      if (DECL_FIELD_IS_BASE (memb2))
+	{
+	  memb2 = TYPE_FIELDS (TREE_TYPE (memb2));
+	  continue;
+	}
+      break;
+    }
+  if (memb1 == NULL_TREE && memb2 == NULL_TREE)
+    return true;
+  if (memb1 == NULL_TREE || memb2 == NULL_TREE)
+    return false;
+  if (DECL_BIT_FIELD_TYPE (memb1))
+    {
+      if (!DECL_BIT_FIELD_TYPE (memb2))
+	return false;
+      if (!layout_compatible_type_p (DECL_BIT_FIELD_TYPE (memb1),
+				     DECL_BIT_FIELD_TYPE (memb2)))
+	return false;
+      if (TYPE_PRECISION (TREE_TYPE (memb1))
+	  != TYPE_PRECISION (TREE_TYPE (memb2)))
+	return false;
+    }
+  else if (DECL_BIT_FIELD_TYPE (memb2))
+    return false;
+  else if (!layout_compatible_type_p (TREE_TYPE (memb1), TREE_TYPE (memb2)))
+    return false;
+  if ((!lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (memb1)))
+      != !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (memb2)))
+    return false;
+  if (!tree_int_cst_equal (bit_position (memb1), bit_position (memb2)))
+    return false;
+  return true;
+}
+
+/* Helper function for fold_builtin_is_corresponding_member call.
+   Return boolean_false_node if MEMBERTYPE1 BASETYPE1::*ARG1 and
+   MEMBERTYPE2 BASETYPE2::*ARG2 aren't corresponding members,
+   boolean_true_node if they are corresponding members, or for
+   non-constant ARG2 the highest member offset for corresponding
+   members.  */
+
+static tree
+is_corresponding_member_aggr (location_t loc, tree basetype1, tree membertype1,
+			      tree arg1, tree basetype2, tree membertype2,
+			      tree arg2)
+{
+  tree field1 = TYPE_FIELDS (basetype1);
+  tree field2 = TYPE_FIELDS (basetype2);
+  tree ret = boolean_false_node;
+  while (1)
+    {
+      bool r = next_common_initial_seqence (field1, field2);
+      if (field1 == NULL_TREE || field2 == NULL_TREE)
+	break;
+      if (r
+	  && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field1),
+							membertype1)
+	  && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field2),
+							membertype2))
+	{
+	  tree pos = byte_position (field1);
+	  if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_equal (arg1, pos))
+	    {
+	      if (TREE_CODE (arg2) == INTEGER_CST)
+		return boolean_true_node;
+	      return pos;
+	    }
+	  else if (TREE_CODE (arg1) != INTEGER_CST)
+	    ret = pos;
+	}
+      else if (ANON_AGGR_TYPE_P (TREE_TYPE (field1))
+	       && ANON_AGGR_TYPE_P (TREE_TYPE (field2)))
+	{
+	  if ((!lookup_attribute ("no_unique_address",
+				  DECL_ATTRIBUTES (field1)))
+	      != !lookup_attribute ("no_unique_address",
+				    DECL_ATTRIBUTES (field2)))
+	    break;
+	  if (!tree_int_cst_equal (bit_position (field1),
+				   bit_position (field2)))
+	    break;
+	  bool overlap = true;
+	  tree pos = byte_position (field1);
+	  if (TREE_CODE (arg1) == INTEGER_CST)
+	    {
+	      tree off1 = fold_convert (sizetype, arg1);
+	      tree sz1 = TYPE_SIZE_UNIT (TREE_TYPE (field1));
+	      if (tree_int_cst_lt (off1, pos)
+		  || tree_int_cst_le (size_binop (PLUS_EXPR, pos, sz1), off1))
+		overlap = false;
+	    }
+	  if (TREE_CODE (arg2) == INTEGER_CST)
+	    {
+	      tree off2 = fold_convert (sizetype, arg2);
+	      tree sz2 = TYPE_SIZE_UNIT (TREE_TYPE (field2));
+	      if (tree_int_cst_lt (off2, pos)
+		  || tree_int_cst_le (size_binop (PLUS_EXPR, pos, sz2), off2))
+		overlap = false;
+	    }
+	  if (overlap && NON_UNION_CLASS_TYPE_P (TREE_TYPE (field1))
+	      && NON_UNION_CLASS_TYPE_P (TREE_TYPE (field2)))
+	    {
+	      tree narg1 = arg1;
+	      if (TREE_CODE (arg1) == INTEGER_CST)
+		narg1
+		  = size_binop (MINUS_EXPR, fold_convert (sizetype, arg1), pos);
+	      tree narg2 = arg2;
+	      if (TREE_CODE (arg2) == INTEGER_CST)
+		narg2
+		  = size_binop (MINUS_EXPR, fold_convert (sizetype, arg2), pos);
+	      tree t1 = TREE_TYPE (field1);
+	      tree t2 = TREE_TYPE (field2);
+	      tree nret
+		= is_corresponding_member_aggr (loc, t1, membertype1, narg1, t2,
+						membertype2, narg2);
+	      if (nret != boolean_false_node)
+		{
+		  if (nret == boolean_true_node)
+		    return nret;
+		  if (TREE_CODE (arg1) == INTEGER_CST)
+		    return size_binop (PLUS_EXPR, nret, pos);
+		  ret = size_binop (PLUS_EXPR, nret, pos);
+		}
+	    }
+	  else if (overlap && TREE_CODE (TREE_TYPE (field1)) == UNION_TYPE
+		   && TREE_CODE (TREE_TYPE (field2)) == UNION_TYPE)
+	    {
+	      tree narg1 = arg1;
+	      if (TREE_CODE (arg1) == INTEGER_CST)
+		narg1
+		  = size_binop (MINUS_EXPR, fold_convert (sizetype, arg1), pos);
+	      tree narg2 = arg2;
+	      if (TREE_CODE (arg2) == INTEGER_CST)
+		narg2
+		  = size_binop (MINUS_EXPR, fold_convert (sizetype, arg2), pos);
+	      if (is_corresponding_member_union (TREE_TYPE (field1),
+						 membertype1, narg1)
+		  && is_corresponding_member_union (TREE_TYPE (field2),
+						    membertype2, narg2))
+		{
+		  sorry_at (loc, "%<__builtin_is_corresponding_member%> "
+				 "not well defined for anonymous unions");
+		  return boolean_false_node;
+		}
+	    }
+	}
+      if (!r)
+	break;
+      field1 = DECL_CHAIN (field1);
+      field2 = DECL_CHAIN (field2);
+    }
+  return ret;
+}
+
+/* Returns true iff T is a null member pointer value (4.11).  */
+
+bool
+null_member_pointer_value_p (tree t)
+{
+  tree type = TREE_TYPE (t);
+  if (!type)
+    return false;
+  else if (TYPE_PTRMEMFUNC_P (type))
+    return (TREE_CODE (t) == CONSTRUCTOR && CONSTRUCTOR_NELTS (t)
+	    && integer_zerop (CONSTRUCTOR_ELT (t, 0)->value));
+  else if (TYPE_PTRDATAMEM_P (type))
+    return integer_all_onesp (t);
+  else
+    return false;
+}
+
+/* Fold __builtin_is_corresponding_member call.  */
+
+tree
+fold_builtin_is_corresponding_member (location_t loc, int nargs, tree *args)
+{
+  /* Unless users call the builtin directly, the following 3 checks should be
+     ensured from std::is_corresponding_member function template.  */
+  if (nargs != 2)
+    {
+      error_at (loc, "%<__builtin_is_corresponding_member%> "
+		     "needs two arguments");
+      return boolean_false_node;
+    }
+  tree arg1 = args[0];
+  tree arg2 = args[1];
+  if (error_operand_p (arg1) || error_operand_p (arg2))
+    return boolean_false_node;
+  if (!TYPE_PTRMEM_P (TREE_TYPE (arg1)) || !TYPE_PTRMEM_P (TREE_TYPE (arg2)))
+    {
+      error_at (loc, "%<__builtin_is_corresponding_member%> "
+		     "argument is not pointer to member");
+      return boolean_false_node;
+    }
+
+  if (!TYPE_PTRDATAMEM_P (TREE_TYPE (arg1))
+      || !TYPE_PTRDATAMEM_P (TREE_TYPE (arg2)))
+    return boolean_false_node;
+
+  tree membertype1 = TREE_TYPE (TREE_TYPE (arg1));
+  tree basetype1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg1));
+  if (!complete_type_or_else (basetype1, NULL_TREE))
+    return boolean_false_node;
+
+  tree membertype2 = TREE_TYPE (TREE_TYPE (arg2));
+  tree basetype2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg2));
+  if (!complete_type_or_else (basetype2, NULL_TREE))
+    return boolean_false_node;
+
+  if (!NON_UNION_CLASS_TYPE_P (basetype1) || !NON_UNION_CLASS_TYPE_P (basetype2)
+      || !std_layout_type_p (basetype1) || !std_layout_type_p (basetype2))
+    return boolean_false_node;
+
+  /* If the member types aren't layout compatible, then they
+     can't be corresponding members.  */
+  if (!layout_compatible_type_p (membertype1, membertype2))
+    return boolean_false_node;
+
+  if (null_member_pointer_value_p (arg1) || null_member_pointer_value_p (arg2))
+    return boolean_false_node;
+
+  if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg2) == INTEGER_CST
+      && !tree_int_cst_equal (arg1, arg2))
+    return boolean_false_node;
+
+  if (TREE_CODE (arg2) == INTEGER_CST && TREE_CODE (arg1) != INTEGER_CST)
+    {
+      std::swap (arg1, arg2);
+      std::swap (membertype1, membertype2);
+      std::swap (basetype1, basetype2);
+    }
+
+  tree ret = is_corresponding_member_aggr (loc, basetype1, membertype1, arg1,
+					   basetype2, membertype2, arg2);
+  if (TREE_TYPE (ret) == boolean_type_node)
+    return ret;
+  /* If both arg1 and arg2 are INTEGER_CSTs, is_corresponding_member_aggr
+     already returns boolean_{true,false}_node whether those particular
+     members are corresponding members or not.  Otherwise, if only
+     one of them is INTEGER_CST (canonicalized to first being INTEGER_CST
+     above), it returns boolean_false_node if it is certainly not a
+     corresponding member and otherwise we need to do a runtime check that
+     those two OFFSET_TYPE offsets are equal.
+     If neither of the operands is INTEGER_CST, is_corresponding_member_aggr
+     returns the largest offset at which the members would be corresponding
+     members, so perform arg1 <= ret && arg1 == arg2 runtime check.  */
+  gcc_assert (TREE_CODE (arg2) != INTEGER_CST);
+  if (TREE_CODE (arg1) == INTEGER_CST)
+    return fold_build2 (EQ_EXPR, boolean_type_node, arg1,
+			fold_convert (TREE_TYPE (arg1), arg2));
+  ret = fold_build2 (LE_EXPR, boolean_type_node,
+		     fold_convert (pointer_sized_int_node, arg1),
+		     fold_convert (pointer_sized_int_node, ret));
+  return fold_build2 (TRUTH_AND_EXPR, boolean_type_node, ret,
+		      fold_build2 (EQ_EXPR, boolean_type_node, arg1,
+				   fold_convert (TREE_TYPE (arg1), arg2)));
+}
+
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index 3fd9484d47d..57440af632d 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -1319,6 +1319,33 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
   (CLASS_TYPE_P (NODE) && LANG_TYPE_CLASS_CHECK (NODE)->anon_aggr)
 #define SET_ANON_AGGR_TYPE_P(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->anon_aggr = 1)
 
+/* Nonzero if T is a class type but not a union.  */
+#define NON_UNION_CLASS_TYPE_P(T)                                              \
+  (TREE_CODE (T) == RECORD_TYPE && TYPE_LANG_FLAG_5 (T))
+
+/* Determines whether an ENUMERAL_TYPE has an explicit
+   underlying type.  */
+#define ENUM_FIXED_UNDERLYING_TYPE_P(NODE) (TYPE_LANG_FLAG_5 (NODE))
+
+/* Returns the underlying type of the given enumeration type. The
+   underlying type is determined in different ways, depending on the
+   properties of the enum:
+
+     - In C++0x, the underlying type can be explicitly specified, e.g.,
+
+	 enum E1 : char { ... } // underlying type is char
+
+     - In a C++0x scoped enumeration, the underlying type is int
+       unless otherwises specified:
+
+	 enum class E2 { ... } // underlying type is int
+
+     - Otherwise, the underlying type is determined based on the
+       values of the enumerators. In this case, the
+       ENUM_UNDERLYING_TYPE will not be set until after the definition
+       of the enumeration is completed by finish_enum.  */
+#define ENUM_UNDERLYING_TYPE(TYPE) TREE_TYPE (ENUMERAL_TYPE_CHECK (TYPE))
+
 #if defined ENABLE_TREE_CHECKING
 
 #define LANG_DECL_MIN_CHECK(NODE)                                              \
@@ -2764,6 +2791,34 @@ is_class_type (tree, int);
 
 extern tree braced_lists_to_strings (tree, tree);
 
+extern tree
+fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *);
+
+extern bool layout_compatible_type_p (tree, tree);
+
+extern tree finish_underlying_type (tree);
+
+extern tree
+c_common_type_for_mode (machine_mode, int);
+
+extern bool std_layout_type_p (const_tree);
+
+extern tree complete_type (tree);
+
+extern tree complete_type_or_else (tree, tree);
+
+extern void note_failed_type_completion_for_satisfaction (tree);
+
+extern tree complete_type_or_maybe_complain (tree, tree, tsubst_flags_t);
+
+extern bool
+next_common_initial_seqence (tree &, tree &);
+
+extern bool null_member_pointer_value_p (tree);
+
+extern tree
+fold_builtin_is_corresponding_member (location_t, int, tree *);
+
 // forked from gcc/cp/cp-tree.h
 
 enum


More information about the Gcc-cvs mailing list