FreeBSD/contrib/gcc/cp/class.c
/* Convert to or from a base subobject.  EXPR is an expression of type
   `A' or `A*', an expression of type `B' or `B*' is returned.  To
   convert A to a base B, CODE is PLUS_EXPR and BINFO is the binfo for
   the B base instance within A.  To convert base A to derived B, CODE
   is MINUS_EXPR and BINFO is the binfo for the A instance within B.
   In this latter case, A must not be a morally virtual base of B.
   NONNULL is true if EXPR is known to be non-NULL (this is only
   needed when EXPR is of pointer type).  CV qualifiers are preserved
   from EXPR.  */
Convert to or from a base subobject.  EXPR is an expression of type
`A' or `A*', an expression of type `B' or `B*' is returned.  To
convert A to a base B, CODE is PLUS_EXPR and BINFO is the binfo for
the B base instance within A.  To convert base A to derived B, CODE
is MINUS_EXPR and BINFO is the binfo for the A instance within B.
In this latter case, A must not be a morally virtual base of B.
NONNULL is true if EXPR is known to be non-NULL (this is only
needed when EXPR is of pointer type).  CV qualifiers are preserved
from EXPR.
Convert to or from a base subobject . EXPR is an expression of type ` A ' or ` A * ' an expression of type ` B ' or ` B * ' is returned . To convert A to a base B CODE is PLUS_EXPR and BINFO is the binfo for the B base instance within A . To convert base A to derived B CODE is MINUS_EXPR and BINFO is the binfo for the A instance within B . In this latter case A must not be a morally virtual base of B . NONNULL is true if EXPR is known to be non - NULL ( this is only needed when EXPR is of pointer type ) . CV qualifiers are preserved from EXPR .
tree
build_base_path (enum tree_code code,
		 tree expr,
		 tree binfo,
		 int nonnull)
{
  tree v_binfo = NULL_TREE;
  tree d_binfo = NULL_TREE;
  tree probe;
  tree offset;
  tree target_type;
  tree null_test = NULL;
  tree ptr_target_type;
  int fixed_type_p;
  int want_pointer = TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE;
  bool has_empty = false;
  bool virtual_access;
  if (expr == error_mark_node || binfo == error_mark_node || !binfo)
    return error_mark_node;
  for (probe = binfo; probe; probe = BINFO_INHERITANCE_CHAIN (probe))
    {
      d_binfo = probe;
      if (is_empty_class (BINFO_TYPE (probe)))
	has_empty = true;
      if (!v_binfo && BINFO_VIRTUAL_P (probe))
	v_binfo = probe;
    }
  probe = TYPE_MAIN_VARIANT (TREE_TYPE (expr));
  if (want_pointer)
    probe = TYPE_MAIN_VARIANT (TREE_TYPE (probe));
  gcc_assert ((code == MINUS_EXPR
	       && SAME_BINFO_TYPE_P (BINFO_TYPE (binfo), probe))
	      || (code == PLUS_EXPR
		  && SAME_BINFO_TYPE_P (BINFO_TYPE (d_binfo), probe)));
  if (binfo == d_binfo)
    return expr;
  if (code == MINUS_EXPR && v_binfo)
    {
      error ("cannot convert from base %qT to derived type %qT via virtual base %qT",
	     BINFO_TYPE (binfo), BINFO_TYPE (d_binfo), BINFO_TYPE (v_binfo));
      return error_mark_node;
    }
  if (!want_pointer)
    expr = build_unary_op (ADDR_EXPR, expr, 0);
  offset = BINFO_OFFSET (binfo);
  fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
  target_type = code == PLUS_EXPR ? BINFO_TYPE (binfo) : BINFO_TYPE (d_binfo);
  virtual_access = (v_binfo && fixed_type_p <= 0);
  if (want_pointer && !nonnull)
    {
      if (!virtual_access && integer_zerop (offset))
	{
	  tree class_type;
	  class_type = TREE_TYPE (TREE_TYPE (expr));
	  target_type
	    = cp_build_qualified_type (target_type,
				       cp_type_quals (class_type));
	  return build_nop (build_pointer_type (target_type), expr);
	}
      null_test = error_mark_node;
    }
  if (TREE_SIDE_EFFECTS (expr) && (null_test || virtual_access))
    expr = save_expr (expr);
  if (null_test)
    {
      tree zero = cp_convert (TREE_TYPE (expr), integer_zero_node);
      null_test = fold_build2 (NE_EXPR, boolean_type_node,
			       expr, zero);
    }
  if (code == PLUS_EXPR && !virtual_access
      && !has_empty)
    {
      expr = build_indirect_ref (expr, NULL);
      expr = build_simple_base_path (expr, binfo);
      if (want_pointer)
	expr = build_address (expr);
      target_type = TREE_TYPE (expr);
      goto out;
    }
  if (virtual_access)
    {
      tree v_offset;
      if (fixed_type_p < 0 && in_base_initializer)
	{
	  tree t;
	  t = TREE_TYPE (TYPE_VFIELD (current_class_type));
	  t = build_pointer_type (t);
	  v_offset = convert (t, current_vtt_parm);
	  v_offset = build_indirect_ref (v_offset, NULL);
	}
      else
	v_offset = build_vfield_ref (build_indirect_ref (expr, NULL),
				     TREE_TYPE (TREE_TYPE (expr)));
      v_offset = build2 (PLUS_EXPR, TREE_TYPE (v_offset),
			 v_offset,  BINFO_VPTR_FIELD (v_binfo));
      v_offset = build1 (NOP_EXPR,
			 build_pointer_type (ptrdiff_type_node),
			 v_offset);
      v_offset = build_indirect_ref (v_offset, NULL);
      TREE_CONSTANT (v_offset) = 1;
      TREE_INVARIANT (v_offset) = 1;
      offset = convert_to_integer (ptrdiff_type_node,
				   size_diffop (offset,
						BINFO_OFFSET (v_binfo)));
      if (!integer_zerop (offset))
	v_offset = build2 (code, ptrdiff_type_node, v_offset, offset);
      if (fixed_type_p < 0)
	offset = build3 (COND_EXPR, ptrdiff_type_node,
			 build2 (EQ_EXPR, boolean_type_node,
				 current_in_charge_parm, integer_zero_node),
			 v_offset,
			 convert_to_integer (ptrdiff_type_node,
					     BINFO_OFFSET (binfo)));
      else
	offset = v_offset;
    }
  target_type = cp_build_qualified_type
    (target_type, cp_type_quals (TREE_TYPE (TREE_TYPE (expr))));
  ptr_target_type = build_pointer_type (target_type);
  if (want_pointer)
    target_type = ptr_target_type;
  expr = build1 (NOP_EXPR, ptr_target_type, expr);
  if (!integer_zerop (offset))
    expr = build2 (code, ptr_target_type, expr, offset);
  else
    null_test = NULL;
  if (!want_pointer)
    expr = build_indirect_ref (expr, NULL);
 out:
  if (null_test)
    expr = fold_build3 (COND_EXPR, target_type, null_test, expr,
			fold_build1 (NOP_EXPR, target_type,
				     integer_zero_node));
  return expr;
}
tree build_base_path ( enum tree_code code , tree expr , tree binfo , int nonnull ) { tree v_binfo = NULL_TREE ; tree d_binfo = NULL_TREE ; tree probe ; tree offset ; tree target_type ; tree null_test = NULL ; tree ptr_target_type ; int fixed_type_p ; int want_pointer = TREE_CODE ( TREE_TYPE ( expr ) ) == POINTER_TYPE ; bool has_empty = false ; bool virtual_access ; if ( expr == error_mark_node || binfo == error_mark_node || ! binfo ) return error_mark_node ; for ( probe = binfo ; probe ; probe = BINFO_INHERITANCE_CHAIN ( probe ) ) { d_binfo = probe ; if ( is_empty_class ( BINFO_TYPE ( probe ) ) ) has_empty = true ; if ( ! v_binfo && BINFO_VIRTUAL_P ( probe ) ) v_binfo = probe ; } probe = TYPE_MAIN_VARIANT ( TREE_TYPE ( expr ) ) ; if ( want_pointer ) probe = TYPE_MAIN_VARIANT ( TREE_TYPE ( probe ) ) ; gcc_assert ( ( code == MINUS_EXPR && SAME_BINFO_TYPE_P ( BINFO_TYPE ( binfo ) , probe ) ) || ( code == PLUS_EXPR && SAME_BINFO_TYPE_P ( BINFO_TYPE ( d_binfo ) , probe ) ) ) ; if ( binfo == d_binfo ) return expr ; if ( code == MINUS_EXPR && v_binfo ) { error ( " " , BINFO_TYPE ( binfo ) , BINFO_TYPE ( d_binfo ) , BINFO_TYPE ( v_binfo ) ) ; return error_mark_node ; } if ( ! want_pointer ) expr = build_unary_op ( ADDR_EXPR , expr , 0 ) ; offset = BINFO_OFFSET ( binfo ) ; fixed_type_p = resolves_to_fixed_type_p ( expr , & nonnull ) ; target_type = code == PLUS_EXPR ? BINFO_TYPE ( binfo ) : BINFO_TYPE ( d_binfo ) ; virtual_access = ( v_binfo && fixed_type_p <= 0 ) ; if ( want_pointer && ! nonnull ) { if ( ! virtual_access && integer_zerop ( offset ) ) { tree class_type ; class_type = TREE_TYPE ( TREE_TYPE ( expr ) ) ; target_type = cp_build_qualified_type ( target_type , cp_type_quals ( class_type ) ) ; return build_nop ( build_pointer_type ( target_type ) , expr ) ; } null_test = error_mark_node ; } if ( TREE_SIDE_EFFECTS ( expr ) && ( null_test || virtual_access ) ) expr = save_expr ( expr ) ; if ( null_test ) { tree zero = cp_convert ( TREE_TYPE ( expr ) , integer_zero_node ) ; null_test = fold_build2 ( NE_EXPR , boolean_type_node , expr , zero ) ; } if ( code == PLUS_EXPR && ! virtual_access && ! has_empty ) { expr = build_indirect_ref ( expr , NULL ) ; expr = build_simple_base_path ( expr , binfo ) ; if ( want_pointer ) expr = build_address ( expr ) ; target_type = TREE_TYPE ( expr ) ; goto out ; } if ( virtual_access ) { tree v_offset ; if ( fixed_type_p < 0 && in_base_initializer ) { tree t ; t = TREE_TYPE ( TYPE_VFIELD ( current_class_type ) ) ; t = build_pointer_type ( t ) ; v_offset = convert ( t , current_vtt_parm ) ; v_offset = build_indirect_ref ( v_offset , NULL ) ; } else v_offset = build_vfield_ref ( build_indirect_ref ( expr , NULL ) , TREE_TYPE ( TREE_TYPE ( expr ) ) ) ; v_offset = build2 ( PLUS_EXPR , TREE_TYPE ( v_offset ) , v_offset , BINFO_VPTR_FIELD ( v_binfo ) ) ; v_offset = build1 ( NOP_EXPR , build_pointer_type ( ptrdiff_type_node ) , v_offset ) ; v_offset = build_indirect_ref ( v_offset , NULL ) ; TREE_CONSTANT ( v_offset ) = 1 ; TREE_INVARIANT ( v_offset ) = 1 ; offset = convert_to_integer ( ptrdiff_type_node , size_diffop ( offset , BINFO_OFFSET ( v_binfo ) ) ) ; if ( ! integer_zerop ( offset ) ) v_offset = build2 ( code , ptrdiff_type_node , v_offset , offset ) ; if ( fixed_type_p < 0 ) offset = build3 ( COND_EXPR , ptrdiff_type_node , build2 ( EQ_EXPR , boolean_type_node , current_in_charge_parm , integer_zero_node ) , v_offset , convert_to_integer ( ptrdiff_type_node , BINFO_OFFSET ( binfo ) ) ) ; else offset = v_offset ; } target_type = cp_build_qualified_type ( target_type , cp_type_quals ( TREE_TYPE ( TREE_TYPE ( expr ) ) ) ) ; ptr_target_type = build_pointer_type ( target_type ) ; if ( want_pointer ) target_type = ptr_target_type ; expr = build1 ( NOP_EXPR , ptr_target_type , expr ) ; if ( ! integer_zerop ( offset ) ) expr = build2 ( code , ptr_target_type , expr , offset ) ; else null_test = NULL ; if ( ! want_pointer ) expr = build_indirect_ref ( expr , NULL ) ; out : if ( null_test ) expr = fold_build3 ( COND_EXPR , target_type , null_test , expr , fold_build1 ( NOP_EXPR , target_type , integer_zero_node ) ) ; return expr ; }
Convert to or from a base subobject.
Convert to or from a base subobject .
/* Nothing to do.  */ /* This must happen before the call to save_expr.  */ /* Do we need to look in the vtable for the real offset?  */ /* Do we need to check for a null pointer?  */ /* If we know the conversion will not actually change the value
	 of EXPR, then we can avoid testing the expression for NULL.
	 We have to avoid generating a COMPONENT_REF for a base class
	 field, because other parts of the compiler know that such
	 expressions are always non-NULL.  */ /* TARGET_TYPE has been extracted from BINFO, and, is
	     therefore always cv-unqualified.  Extract the
	     cv-qualifiers from EXPR so that the expression returned
	     matches the input.  */ /* Protect against multiple evaluation if necessary.  */ /* Now that we've saved expr, build the real null test.  */ /* If this is a simple base reference, express it as a COMPONENT_REF.  */ /* We don't build base fields for empty bases, and they aren't very
	 interesting to the optimizers anyway.  */ /* Going via virtual base V_BINFO.  We need the static offset
	 from V_BINFO to BINFO, and the dynamic offset from D_BINFO to
	 V_BINFO.  That offset is an entry in D_BINFO's vtable.  */ /* In a base member initializer, we cannot rely on the
	     vtable being set up.  We have to indirect via the
	     vtt_parm.  */ /* Negative fixed_type_p means this is a constructor or destructor;
	   virtual base layout is fixed in in-charge [cd]tors, but not in
	   base [cd]tors.  */