Example #1
0
tree
get_typeid (tree type)
{
  if (type == error_mark_node || !typeid_ok_p ())
    return error_mark_node;
  
  if (processing_template_decl)
    return build_min (TYPEID_EXPR, const_type_info_type_node, type);

  /* If the type of the type-id is a reference type, the result of the
     typeid expression refers to a type_info object representing the
     referenced type.  */
  type = non_reference (type);

  /* The top-level cv-qualifiers of the lvalue expression or the type-id
     that is the operand of typeid are always ignored.  */
  type = TYPE_MAIN_VARIANT (type);

  if (!VOID_TYPE_P (type))
    type = complete_type_or_else (type, NULL_TREE);
  
  if (!type)
    return error_mark_node;

  return build_indirect_ref (get_tinfo_ptr (type), NULL);
}
Example #2
0
static int
can_convert_eh (tree to, tree from)
{
  to = non_reference (to);
  from = non_reference (from);

  if (TYPE_PTR_P (to) && TYPE_PTR_P (from))
    {
      to = TREE_TYPE (to);
      from = TREE_TYPE (from);

      if (! at_least_as_qualified_p (to, from))
	return 0;

      if (VOID_TYPE_P (to))
	return 1;

      /* Else fall through.  */
    }

  if (CLASS_TYPE_P (to) && CLASS_TYPE_P (from)
      && publicly_uniquely_derived_p (to, from))
    return 1;

  return 0;
}
static void
gimplify_expr_stmt (tree *stmt_p)
{
  tree stmt = EXPR_STMT_EXPR (*stmt_p);

  if (stmt == error_mark_node)
    stmt = NULL;

  /* Gimplification of a statement expression will nullify the
     statement if all its side effects are moved to *PRE_P and *POST_P.

     In this case we will not want to emit the gimplified statement.
     However, we may still want to emit a warning, so we do that before
     gimplification.  */
  if (stmt && (extra_warnings || warn_unused_value))
    {
      if (!TREE_SIDE_EFFECTS (stmt))
	{
	  if (!IS_EMPTY_STMT (stmt)
	      && !VOID_TYPE_P (TREE_TYPE (stmt))
	      && !TREE_NO_WARNING (stmt))
	    warning (0, "statement with no effect");
	}
      else if (warn_unused_value)
	warn_if_unused_value (stmt, input_location);
    }

  if (stmt == NULL_TREE)
    stmt = alloc_stmt_list ();

  *stmt_p = stmt;
}
Example #4
0
static enum in_charge_use
compute_use_thunks (tree fn)
{
  tree last_arg, fn_parm;

  if (DECL_HAS_VTT_PARM_P (fn))
    return NO_THUNKS;

  if (flag_apple_kext)
    return NO_THUNKS;

  if (flag_clone_structors)
    return NO_THUNKS;

  /* Functions that are too small will just get inlined back in anyway.
     Let the inliner do something useful instead.  */
  if (flag_inline_functions
      && estimate_num_insns (DECL_SAVED_TREE (fn)) < MAX_INLINE_INSNS_AUTO)
    return NO_THUNKS;

  /* If function accepts variable arguments, give up.  */
  last_arg = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fn)));
  if ( ! VOID_TYPE_P (TREE_VALUE (last_arg)))
       return NO_THUNKS;

  /* If constructor expects vector (AltiVec) arguments, give up.  */
  for (fn_parm = DECL_ARGUMENTS (fn); fn_parm; fn_parm = TREE_CHAIN (fn_parm))
    if (TREE_CODE (fn_parm) == VECTOR_TYPE)
      return NO_THUNKS;

  if (DECL_HAS_IN_CHARGE_PARM_P (fn))
    {
      int parmno;
      struct thunk_tree_walk_data data;
      for (parmno = 0, fn_parm = DECL_ARGUMENTS (fn);
	   fn_parm;
	   ++parmno, fn_parm = TREE_CHAIN (fn_parm))
	if (parmno == 1)
	  {
	    data.in_charge_parm = fn_parm;
	    break;
	  }
      /* If every use of the in-charge parameter ANDs it
	 with 1, then the functions that have in-charge
	 set to 1 and 3 are equivalent, likewise 0 and 2.
	 Check for this (common in practice).  Likewise,
	 if every use tests for equality with 0, then
	 values 1, 2 and 3 are equivalent.  */
      gcc_assert (data.in_charge_parm != NULL_TREE);
      data.in_charge_use = ALL_THUNKS;
      walk_tree_without_duplicates (&DECL_SAVED_TREE (fn), 
				    examine_tree_for_in_charge_use, 
				    &data);
      return data.in_charge_use;
    }

  return ALL_THUNKS;
}
Example #5
0
bool
is_gimple_stmt (tree t)
{
  enum tree_code code = TREE_CODE (t);

  switch (code)
    {
    case NOP_EXPR:
      /* The only valid NOP_EXPR is the empty statement.  */
      return IS_EMPTY_STMT (t);

    case BIND_EXPR:
    case COND_EXPR:
      /* These are only valid if they're void.  */
      return TREE_TYPE (t) == NULL || VOID_TYPE_P (TREE_TYPE (t));

    case SWITCH_EXPR:
    case GOTO_EXPR:
    case RETURN_EXPR:
    case LABEL_EXPR:
    case CASE_LABEL_EXPR:
    case TRY_CATCH_EXPR:
    case TRY_FINALLY_EXPR:
    case EH_FILTER_EXPR:
    case CATCH_EXPR:
    case ASM_EXPR:
    case RESX_EXPR:
    case PHI_NODE:
    case STATEMENT_LIST:
    case OMP_PARALLEL:
    case OMP_FOR:
    case OMP_SECTIONS:
    case OMP_SECTION:
    case OMP_SINGLE:
    case OMP_MASTER:
    case OMP_ORDERED:
    case OMP_CRITICAL:
    case OMP_RETURN:
    case OMP_CONTINUE:
      /* These are always void.  */
      return true;

    case CALL_EXPR:
    case MODIFY_EXPR:
      /* These are valid regardless of their type.  */
      return true;

    default:
      return false;
    }
}
Example #6
0
static void
cp_ubsan_maybe_instrument_return (tree fndecl)
{
  if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl)))
      || DECL_CONSTRUCTOR_P (fndecl)
      || DECL_DESTRUCTOR_P (fndecl)
      || !targetm.warn_func_return (fndecl))
    return;

  tree t = DECL_SAVED_TREE (fndecl);
  while (t)
    {
      switch (TREE_CODE (t))
	{
	case BIND_EXPR:
	  t = BIND_EXPR_BODY (t);
	  continue;
	case TRY_FINALLY_EXPR:
	  t = TREE_OPERAND (t, 0);
	  continue;
	case STATEMENT_LIST:
	  {
	    tree_stmt_iterator i = tsi_last (t);
	    if (!tsi_end_p (i))
	      {
		t = tsi_stmt (i);
		continue;
	      }
	  }
	  break;
	case RETURN_EXPR:
	  return;
	default:
	  break;
	}
      break;
    }
  if (t == NULL_TREE)
    return;
  t = DECL_SAVED_TREE (fndecl);
  if (TREE_CODE (t) == BIND_EXPR
      && TREE_CODE (BIND_EXPR_BODY (t)) == STATEMENT_LIST)
    {
      tree_stmt_iterator i = tsi_last (BIND_EXPR_BODY (t));
      t = ubsan_instrument_return (DECL_SOURCE_LOCATION (fndecl));
      tsi_link_after (&i, t, TSI_NEW_STMT);
    }
}
Example #7
0
int
cp_empty_type_p (tree exp)
{
  gcc_assert(TYPE_P(exp));
  if (VOID_TYPE_P(exp))
    return 0;

  /* C++ classes with non-trivial constructors or non-trivial
     assignment operators are assumed non-empty, thus assignments of
     these types can't be elided.  */
  if (CLASS_TYPE_P(exp)
      && (TYPE_HAS_COMPLEX_INIT_REF(exp)
          || TYPE_HAS_COMPLEX_ASSIGN_REF(exp)))
    return 0;

  return is_empty_class(exp);
}
Example #8
0
bool
is_gimple_stmt (tree t)
{
  enum tree_code code = TREE_CODE (t);

  if (IS_EMPTY_STMT (t))
    return 1;

  switch (code)
    {
    case BIND_EXPR:
    case COND_EXPR:
      /* These are only valid if they're void.  */
      return TREE_TYPE (t) == NULL || VOID_TYPE_P (TREE_TYPE (t));

    case SWITCH_EXPR:
    case GOTO_EXPR:
    case RETURN_EXPR:
    case LABEL_EXPR:
    case CASE_LABEL_EXPR:
    case TRY_CATCH_EXPR:
    case TRY_FINALLY_EXPR:
    case EH_FILTER_EXPR:
    case CATCH_EXPR:
    case ASM_EXPR:
    case RESX_EXPR:
    case PHI_NODE:
    case STATEMENT_LIST:
      /* These are always void.  */
      return true;

    case CALL_EXPR:
    case MODIFY_EXPR:
      /* These are valid regardless of their type.  */
      return true;

    default:
      return false;
    }
}
Example #9
0
static tree
get_tinfo_decl_dynamic (tree exp)
{
  tree type;
  tree t;
  
  if (exp == error_mark_node)
    return error_mark_node;

  /* peel back references, so they match.  */
  type = non_reference (TREE_TYPE (exp));

  /* Peel off cv qualifiers.  */
  type = TYPE_MAIN_VARIANT (type);
  
  if (!VOID_TYPE_P (type))
    type = complete_type_or_else (type, exp);
  
  if (!type)
    return error_mark_node;

  /* If exp is a reference to polymorphic type, get the real type_info.  */
  if (TYPE_POLYMORPHIC_P (type) && ! resolves_to_fixed_type_p (exp, 0))
    {
      /* build reference to type_info from vtable.  */
      tree index;

      /* The RTTI information is at index -1.  */
      index = build_int_cst (NULL_TREE,
			     -1 * TARGET_VTABLE_DATA_ENTRY_DISTANCE);
      t = build_vtbl_ref (exp, index);
      t = convert (type_info_ptr_type, t);
    }
  else
    /* Otherwise return the type_info for the static type of the expr.  */
    t = get_tinfo_ptr (TYPE_MAIN_VARIANT (type));

  return build_indirect_ref (t, NULL);
}
Example #10
0
/* Return the number of elements in the vector arguments of FNDECL in
   case all it matches for all vector arguments, -1 otherwise.  */
static int
s390_vec_n_elem (tree fndecl)
{
  tree b_arg_chain;
  int n_elem = -1;

  if (TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) == VECTOR_TYPE)
    n_elem = TYPE_VECTOR_SUBPARTS (TREE_TYPE (TREE_TYPE ((fndecl))));

  for (b_arg_chain = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
       !VOID_TYPE_P (TREE_VALUE (b_arg_chain));
       b_arg_chain = TREE_CHAIN (b_arg_chain))
    {
      int tmp_n_elem;
      if (TREE_CODE (TREE_VALUE (b_arg_chain)) != VECTOR_TYPE)
	continue;
      tmp_n_elem = TYPE_VECTOR_SUBPARTS (TREE_VALUE (b_arg_chain));
      if (n_elem != -1 && n_elem != tmp_n_elem)
	return -1;
      n_elem = tmp_n_elem;
    }
  return n_elem;
}
Example #11
0
static int
complete_ptr_ref_or_void_ptr_p (tree type, tree from)
{
  int is_ptr;

  /* Check complete.  */
  type = complete_type_or_else (type, from);
  if (!type)
    return 0;

  /* Or a pointer or ref to one, or cv void *.  */
  is_ptr = TYPE_PTR_P (type);
  if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE)
    {
      tree core = TREE_TYPE (type);

      if (is_ptr && VOID_TYPE_P (core))
	/* OK */;
      else if (!complete_type_or_else (core, from))
	return 0;
    }
  return 1;
}
Example #12
0
bool
cilk_detect_spawn_and_unwrap (tree *exp0)
{
  tree exp = *exp0;

  if (!TREE_SIDE_EFFECTS (exp))
    return false;

  /* Strip off any conversion to void.  It does not affect whether spawn 
     is supported here.  */
  if (TREE_CODE (exp) == CONVERT_EXPR && VOID_TYPE_P (TREE_TYPE (exp)))
    exp = TREE_OPERAND (exp, 0);

  if (TREE_CODE (exp) == MODIFY_EXPR || TREE_CODE (exp) == INIT_EXPR)
    exp = TREE_OPERAND (exp, 1);

  while (cilk_ignorable_spawn_rhs_op (exp))
    exp = TREE_OPERAND (exp, 0);

  if (TREE_CODE (exp) == TARGET_EXPR)
    if (TARGET_EXPR_INITIAL (exp)
	&& TREE_CODE (TARGET_EXPR_INITIAL (exp)) != AGGR_INIT_EXPR)
      exp = TARGET_EXPR_INITIAL (exp);

  /* Happens with C++ TARGET_EXPR.  */
  if (exp == NULL_TREE)
    return false;

  while (TREE_CODE (exp) == CLEANUP_POINT_EXPR || TREE_CODE (exp) == EXPR_STMT)
    exp = TREE_OPERAND (exp, 0);
  
  /* Now we should have a CALL_EXPR with a CILK_SPAWN_STMT wrapper around 
     it, or return false.  */
  if (recognize_spawn (exp, exp0))
    return true;
  return false;
}
Example #13
0
static tree
replace_invariant_exprs (tree *node)
{
  size_t ix = 0;
  tree node_list = NULL_TREE;
  tree t = NULL_TREE, new_var = NULL_TREE;
  struct inv_list data;

  data.list_values = NULL;
  data.replacement = NULL;
  data.additional_tcodes = NULL;
  cp_walk_tree (node, find_inv_trees, (void *) &data, NULL);

  if (vec_safe_length (data.list_values))
    {
      node_list = push_stmt_list ();
      for (ix = 0; vec_safe_iterate (data.list_values, ix, &t); ix++)
	{ 
	  /* Sometimes, when comma_expr has a function call in it, it will
	     typecast it to void.  Find_inv_trees finds those nodes and so
	     if it void type, then don't bother creating a new var to hold 
	     the return value.   */
	  if (VOID_TYPE_P (TREE_TYPE (t)))
	    {
	      finish_expr_stmt (t);
	      new_var = void_node;
	    }
	  else 
	    new_var = get_temp_regvar (TREE_TYPE (t), t); 
	  vec_safe_push (data.replacement, new_var);
	}
      cp_walk_tree (node, replace_inv_trees, (void *) &data, NULL);
      node_list = pop_stmt_list (node_list);
    }
  return node_list;
}
Example #14
0
/* Return a tree expression for a call to the overloaded builtin
   function OB_FNDECL at LOC with arguments PASSED_ARGLIST.  */
tree
s390_resolve_overloaded_builtin (location_t loc,
				 tree ob_fndecl,
				 void *passed_arglist)
{
  vec<tree, va_gc> *arglist = static_cast<vec<tree, va_gc> *> (passed_arglist);
  unsigned int in_args_num = vec_safe_length (arglist);
  unsigned int ob_args_num = 0;
  unsigned int ob_fcode = DECL_FUNCTION_CODE (ob_fndecl);
  enum s390_overloaded_builtin_vars bindex;
  unsigned int i;
  int last_match_type = INT_MAX;
  int last_match_index = -1;
  unsigned int all_op_flags;
  int num_matches = 0;
  tree target_builtin_decl, b_arg_chain, return_type;
  enum s390_builtin_ov_type_index last_match_fntype_index;

  if (TARGET_DEBUG_ARG)
    fprintf (stderr,
      "s390_resolve_overloaded_builtin, code = %4d, %s - %s overloaded\n",
      (int)ob_fcode, IDENTIFIER_POINTER (DECL_NAME (ob_fndecl)),
     ob_fcode < S390_BUILTIN_MAX ? "not" : "");

  /* 0...S390_BUILTIN_MAX-1 is for non-overloaded builtins.  */
  if (ob_fcode < S390_BUILTIN_MAX)
    {
      if (bflags_for_builtin(ob_fcode) & B_INT)
	{
	  error_at (loc,
		    "Builtin %qF is for GCC internal use only.",
		    ob_fndecl);
	  return error_mark_node;
	}
      return NULL_TREE;
    }

  ob_fcode -= S390_BUILTIN_MAX;

  for (b_arg_chain = TYPE_ARG_TYPES (TREE_TYPE (ob_fndecl));
       !VOID_TYPE_P (TREE_VALUE (b_arg_chain));
       b_arg_chain = TREE_CHAIN (b_arg_chain))
    ob_args_num++;

  if (ob_args_num != in_args_num)
    {
      error_at (loc,
		"Mismatch in number of arguments for builtin %qF. "
		"Expected: %d got %d", ob_fndecl,
		ob_args_num, in_args_num);
      return error_mark_node;
    }

  for (i = 0; i < in_args_num; i++)
    if ((*arglist)[i] == error_mark_node)
      return error_mark_node;

  /* Overloaded builtins without any variants are directly expanded here.  */
  if (desc_start_for_overloaded_builtin[ob_fcode] ==
      S390_OVERLOADED_BUILTIN_VAR_MAX)
    return s390_expand_overloaded_builtin (loc, ob_fcode, arglist, NULL_TREE);

  for (bindex = desc_start_for_overloaded_builtin[ob_fcode];
       bindex <= desc_end_for_overloaded_builtin[ob_fcode];
       bindex = (enum s390_overloaded_builtin_vars)((int)bindex + 1))
  {
    int match_type;
    enum s390_builtin_ov_type_index type_index =
      type_for_overloaded_builtin_var[bindex];

    if (TARGET_DEBUG_ARG)
      fprintf (stderr, "checking variant number: %d", (int)bindex);

    match_type = s390_fn_types_compatible (type_index, arglist);

    if (match_type == INT_MAX)
      continue;

    if (TARGET_DEBUG_ARG)
      fprintf (stderr,
	       " %s match score: %d\n", match_type == 0 ? "perfect" : "imperfect",
	       match_type);

    if (match_type < last_match_type)
      {
	num_matches = 1;
	last_match_type = match_type;
	last_match_fntype_index = type_index;
	last_match_index = bindex;
      }
    else if (match_type == last_match_type)
      num_matches++;
  }

  if (last_match_type == INT_MAX)
    {
      error_at (loc, "invalid parameter combination for intrinsic %qs",
		IDENTIFIER_POINTER (DECL_NAME (ob_fndecl)));
      return error_mark_node;
    }
  else if (num_matches > 1)
    {
      error_at (loc, "ambiguous overload for intrinsic %qs",
		IDENTIFIER_POINTER (DECL_NAME (ob_fndecl)));
      return error_mark_node;
    }

  if (bt_for_overloaded_builtin_var[last_match_index] == S390_BUILTIN_MAX)
    target_builtin_decl = ob_fndecl;
  else
    target_builtin_decl = s390_builtin_decls[bt_for_overloaded_builtin_var[last_match_index]];

  all_op_flags = opflags_overloaded_builtin_var[last_match_index];
  return_type = s390_builtin_types[s390_builtin_ov_types[last_match_fntype_index][0]];

  /* Check for the operand flags in the overloaded builtin variant.  */
  for (i = 0; i < ob_args_num; i++)
    {
      unsigned int op_flags = all_op_flags & ((1 << O_SHIFT) - 1);
      tree arg = (*arglist)[i];
      tree type = s390_builtin_types[s390_builtin_ov_types[last_match_fntype_index][i + 1]];

      all_op_flags = all_op_flags >> O_SHIFT;

      if (op_flags == O_ELEM)
	{
	  int n_elem = s390_vec_n_elem (target_builtin_decl);
	  gcc_assert (n_elem > 0);
	  gcc_assert (type == integer_type_node);
	  (*arglist)[i] = build2 (BIT_AND_EXPR, integer_type_node,
				  fold_convert (integer_type_node, arg),
				  build_int_cst (NULL_TREE, n_elem - 1));
	}

      if (TREE_CODE (arg) != INTEGER_CST || !O_IMM_P (op_flags))
	continue;

      if ((TYPE_UNSIGNED (type)
	   && !int_fits_type_p (arg, c_common_unsigned_type (type)))
	  || (!TYPE_UNSIGNED (type)
	      && !int_fits_type_p (arg, c_common_signed_type (type))))
	{
	  error("constant argument %d for builtin %qF is out "
		"of range for target type",
		i + 1, target_builtin_decl);
	  return error_mark_node;
	}

      if (TREE_CODE (arg) == INTEGER_CST
	  && !s390_const_operand_ok (arg, i + 1, op_flags, target_builtin_decl))
	return error_mark_node;
    }

  /* Handle builtins we expand directly - without mapping it to a low
     level builtin.  */
  if (bt_for_overloaded_builtin_var[last_match_index] == S390_BUILTIN_MAX)
    return s390_expand_overloaded_builtin (loc, ob_fcode, arglist, return_type);

  s390_adjust_builtin_arglist (ob_fcode, target_builtin_decl, &arglist);

  if (VOID_TYPE_P (return_type))
    return build_function_call_vec (loc, vNULL, target_builtin_decl,
				    arglist, NULL);
  else
    return fully_fold_convert (return_type,
			       build_function_call_vec (loc, vNULL, target_builtin_decl,
							arglist, NULL));
}
Example #15
0
/* For several overloaded builtins the argument lists do not match
   exactly the signature of a low-level builtin.  This function
   adjusts the argument list ARGLIST for the overloaded builtin
   OB_FCODE to the signature of the low-level builtin given by
   DECL.  */
static void
s390_adjust_builtin_arglist (unsigned int ob_fcode, tree decl,
			     vec<tree, va_gc> **arglist)
{
  tree arg_chain;
  int src_arg_index, dest_arg_index;
  vec<tree, va_gc> *folded_args = NULL;

  /* We at most add one more operand to the list.  */
  vec_alloc (folded_args, (*arglist)->allocated () + 1);
  for (arg_chain = TYPE_ARG_TYPES (TREE_TYPE (decl)),
	 src_arg_index = 0, dest_arg_index = 0;
       !VOID_TYPE_P (TREE_VALUE (arg_chain));
       arg_chain = TREE_CHAIN (arg_chain), dest_arg_index++)
    {
      bool arg_assigned_p = false;
      switch (ob_fcode)
	{
	  /* For all these the low level builtin needs an additional flags parameter.  */
	case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_idx:
	case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_idx:
	case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_or_0_idx:
	case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_or_0_idx:
	case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq:
	case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne:
	case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_idx_cc:
	case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_idx_cc:
	case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_or_0_idx_cc:
	case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_or_0_idx_cc:
	case S390_OVERLOADED_BUILTIN_s390_vec_find_any_eq_cc:
	case S390_OVERLOADED_BUILTIN_s390_vec_find_any_ne_cc:
	  if (dest_arg_index == 2)
	    {
	      folded_args->quick_push (build_int_cst (integer_type_node,
				       s390_get_vstring_flags (ob_fcode)));
	      arg_assigned_p = true;
	    }
	  break;
	case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_idx:
	case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_idx:
	case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_or_0_idx:
	case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_or_0_idx:
	case S390_OVERLOADED_BUILTIN_s390_vec_cmprg:
	case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg:
	case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_idx_cc:
	case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_idx_cc:
	case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_or_0_idx_cc:
	case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_or_0_idx_cc:
	case S390_OVERLOADED_BUILTIN_s390_vec_cmprg_cc:
	case S390_OVERLOADED_BUILTIN_s390_vec_cmpnrg_cc:
	  if (dest_arg_index == 3)
	    {
	      folded_args->quick_push (build_int_cst (integer_type_node,
				       s390_get_vstring_flags (ob_fcode)));
	      arg_assigned_p = true;
	    }
	  break;
	case S390_OVERLOADED_BUILTIN_s390_vec_sel:
	case S390_OVERLOADED_BUILTIN_s390_vec_insert:
	case S390_OVERLOADED_BUILTIN_s390_vec_load_len:
	  /* Swap the first to arguments. It is better to do it here
	     instead of the header file to avoid operand checking
	     throwing error messages for a weird operand index.  */
	  if (dest_arg_index < 2)
	    {
	      folded_args->quick_push (fully_fold_convert (TREE_VALUE (arg_chain),
					 (**arglist)[1 - dest_arg_index]));
	      src_arg_index++;
	      arg_assigned_p = true;
	    }
	  break;
	case S390_OVERLOADED_BUILTIN_s390_vec_store_len:
	  if (dest_arg_index == 1 || dest_arg_index == 2)
	    {
	      folded_args->quick_push (fully_fold_convert (TREE_VALUE (arg_chain),
					 (**arglist)[3 - dest_arg_index]));
	      src_arg_index++;
	      arg_assigned_p = true;
	    }
	  break;

	case S390_OVERLOADED_BUILTIN_s390_vec_load_bndry:
	  {
	    int code;

	    if (dest_arg_index == 1)
	      {
		switch (tree_to_uhwi ((**arglist)[src_arg_index]))
		  {
		  case 64: code = 0; break;
		  case 128: code = 1; break;
		  case 256: code = 2; break;
		  case 512: code = 3; break;
		  case 1024: code = 4; break;
		  case 2048: code = 5; break;
		  case 4096: code = 6; break;
		  default:
		    error ("valid values for builtin %qF argument %d are 64, "
			   "128, 256, 512, 1024, 2048, and 4096", decl,
			   src_arg_index + 1);
		    return;
		  }
		folded_args->quick_push (build_int_cst (integer_type_node,
							code));
		src_arg_index++;
		arg_assigned_p = true;
	      }
	  }
	  break;
	case S390_OVERLOADED_BUILTIN_s390_vec_rl_mask:
	  /* Duplicate the first src arg.  */
	  if (dest_arg_index == 0)
	    {
	      folded_args->quick_push (fully_fold_convert (TREE_VALUE (arg_chain),
					   (**arglist)[src_arg_index]));
	      arg_assigned_p = true;
	    }
	  break;
	default:
	  break;
	}
      if (!arg_assigned_p)
	{
	  folded_args->quick_push (fully_fold_convert (TREE_VALUE (arg_chain),
						 (**arglist)[src_arg_index]));
	  src_arg_index++;
	}
    }
  *arglist = folded_args;
}
Example #16
0
File: cvt.c Project: h4ck3rm1k3/gcc
tree
convert_to_void (tree expr, const char *implicit, tsubst_flags_t complain)
{
  if (expr == error_mark_node
      || TREE_TYPE (expr) == error_mark_node)
    return error_mark_node;
  if (!TREE_TYPE (expr))
    return expr;
  if (invalid_nonstatic_memfn_p (expr, complain))
    return error_mark_node;
  if (TREE_CODE (expr) == PSEUDO_DTOR_EXPR)
    {
      if (complain & tf_error)
        error ("pseudo-destructor is not called");
      return error_mark_node;
    }
  if (VOID_TYPE_P (TREE_TYPE (expr)))
    return expr;
  switch (TREE_CODE (expr))
    {
    case COND_EXPR:
      {
	/* The two parts of a cond expr might be separate lvalues.  */
	tree op1 = TREE_OPERAND (expr,1);
	tree op2 = TREE_OPERAND (expr,2);
	tree new_op1 = convert_to_void
	  (op1, (implicit && !TREE_SIDE_EFFECTS (op2)
		 ? "second operand of conditional" : NULL), complain);
	tree new_op2 = convert_to_void
	  (op2, (implicit && !TREE_SIDE_EFFECTS (op1)
		 ? "third operand of conditional" : NULL), complain);

	expr = build3 (COND_EXPR, TREE_TYPE (new_op1),
		       TREE_OPERAND (expr, 0), new_op1, new_op2);
	break;
      }

    case COMPOUND_EXPR:
      {
	/* The second part of a compound expr contains the value.  */
	tree op1 = TREE_OPERAND (expr,1);
	tree new_op1 = convert_to_void
	  (op1, (implicit && !TREE_NO_WARNING (expr)
		 ? "right-hand operand of comma" : NULL), complain);

	if (new_op1 != op1)
	  {
	    tree t = build2 (COMPOUND_EXPR, TREE_TYPE (new_op1),
			     TREE_OPERAND (expr, 0), new_op1);
	    expr = t;
	  }

	break;
      }

    case NON_LVALUE_EXPR:
    case NOP_EXPR:
      /* These have already decayed to rvalue.  */
      break;

    case CALL_EXPR:   /* We have a special meaning for volatile void fn().  */
      break;

    case INDIRECT_REF:
      {
	tree type = TREE_TYPE (expr);
	int is_reference = TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0)))
			   == REFERENCE_TYPE;
	int is_volatile = TYPE_VOLATILE (type);
	int is_complete = COMPLETE_TYPE_P (complete_type (type));

	/* Can't load the value if we don't know the type.  */
	if (is_volatile && !is_complete)
          {
            if (complain & tf_warning)
              warning (0, "object of incomplete type %qT will not be accessed in %s",
                       type, implicit ? implicit : "void context");
          }
	/* Don't load the value if this is an implicit dereference, or if
	   the type needs to be handled by ctors/dtors.  */
	else if (is_volatile && (is_reference || TREE_ADDRESSABLE (type)))
          {
            if (complain & tf_warning)
              warning (0, "object of type %qT will not be accessed in %s",
                       TREE_TYPE (TREE_OPERAND (expr, 0)),
                       implicit ? implicit : "void context");
          }
	if (is_reference || !is_volatile || !is_complete || TREE_ADDRESSABLE (type))
	  expr = TREE_OPERAND (expr, 0);

	break;
      }

    case VAR_DECL:
      {
	/* External variables might be incomplete.  */
	tree type = TREE_TYPE (expr);
	int is_complete = COMPLETE_TYPE_P (complete_type (type));

	if (TYPE_VOLATILE (type) && !is_complete && (complain & tf_warning))
	  warning (0, "object %qE of incomplete type %qT will not be accessed in %s",
		   expr, type, implicit ? implicit : "void context");
	break;
      }

    case TARGET_EXPR:
      /* Don't bother with the temporary object returned from a function if
	 we don't use it and don't need to destroy it.  We'll still
	 allocate space for it in expand_call or declare_return_variable,
	 but we don't need to track it through all the tree phases.  */
      if (TARGET_EXPR_IMPLICIT_P (expr)
	  && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (expr)))
	{
	  tree init = TARGET_EXPR_INITIAL (expr);
	  if (TREE_CODE (init) == AGGR_INIT_EXPR
	      && !AGGR_INIT_VIA_CTOR_P (init))
	    {
	      tree fn = AGGR_INIT_EXPR_FN (init);
	      expr = build_call_array (TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
				       fn,
				       aggr_init_expr_nargs (init),
				       AGGR_INIT_EXPR_ARGP (init));
	    }
	}
      break;

    default:;
    }
  {
    tree probe = expr;

    if (TREE_CODE (probe) == ADDR_EXPR)
      probe = TREE_OPERAND (expr, 0);
    if (type_unknown_p (probe))
      {
	/* [over.over] enumerates the places where we can take the address
	   of an overloaded function, and this is not one of them.  */
	if (complain & tf_error)
	  error ("%s cannot resolve address of overloaded function",
		 implicit ? implicit : "void cast");
	else
	  return error_mark_node;
	expr = void_zero_node;
      }
    else if (implicit && probe == expr && is_overloaded_fn (probe))
      {
	/* Only warn when there is no &.  */
	if (complain & tf_warning)
	  warning (OPT_Waddress, "%s is a reference, not call, to function %qE",
		   implicit, expr);
	if (TREE_CODE (expr) == COMPONENT_REF)
	  expr = TREE_OPERAND (expr, 0);
      }
  }

  if (expr != error_mark_node && !VOID_TYPE_P (TREE_TYPE (expr)))
    {
      if (implicit
	  && warn_unused_value
	  && !TREE_NO_WARNING (expr)
	  && !processing_template_decl)
	{
	  /* The middle end does not warn about expressions that have
	     been explicitly cast to void, so we must do so here.  */
	  if (!TREE_SIDE_EFFECTS (expr)) {
            if (complain & tf_warning)
              warning (OPT_Wunused_value, "%s has no effect", implicit);
          }
	  else
	    {
	      tree e;
	      enum tree_code code;
	      enum tree_code_class tclass;

	      e = expr;
	      /* We might like to warn about (say) "(int) f()", as the
		 cast has no effect, but the compiler itself will
		 generate implicit conversions under some
		 circumstances.  (For example a block copy will be
		 turned into a call to "__builtin_memcpy", with a
		 conversion of the return value to an appropriate
		 type.)  So, to avoid false positives, we strip
		 conversions.  Do not use STRIP_NOPs because it will
		 not strip conversions to "void", as that is not a
		 mode-preserving conversion.  */
	      while (TREE_CODE (e) == NOP_EXPR)
		e = TREE_OPERAND (e, 0);

	      code = TREE_CODE (e);
	      tclass = TREE_CODE_CLASS (code);
	      if ((tclass == tcc_comparison
		   || tclass == tcc_unary
		   || (tclass == tcc_binary
		       && !(code == MODIFY_EXPR
			    || code == INIT_EXPR
			    || code == PREDECREMENT_EXPR
			    || code == PREINCREMENT_EXPR
			    || code == POSTDECREMENT_EXPR
			    || code == POSTINCREMENT_EXPR)))
                  && (complain & tf_warning))
		warning (OPT_Wunused_value, "value computed is not used");
	    }
	}
      expr = build1 (CONVERT_EXPR, void_type_node, expr);
    }
  if (! TREE_SIDE_EFFECTS (expr))
    expr = void_zero_node;
  return expr;
}
Example #17
0
File: cvt.c Project: h4ck3rm1k3/gcc
static tree
cp_convert_to_pointer (tree type, tree expr)
{
  tree intype = TREE_TYPE (expr);
  enum tree_code form;
  tree rval;
  if (intype == error_mark_node)
    return error_mark_node;

  if (MAYBE_CLASS_TYPE_P (intype))
    {
      intype = complete_type (intype);
      if (!COMPLETE_TYPE_P (intype))
	{
	  error ("can't convert from incomplete type %qT to %qT",
		 intype, type);
	  return error_mark_node;
	}

      rval = build_type_conversion (type, expr);
      if (rval)
	{
	  if (rval == error_mark_node)
	    error ("conversion of %qE from %qT to %qT is ambiguous",
		   expr, intype, type);
	  return rval;
	}
    }

  /* Handle anachronistic conversions from (::*)() to cv void* or (*)().  */
  if (TREE_CODE (type) == POINTER_TYPE
      && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
	  || VOID_TYPE_P (TREE_TYPE (type))))
    {
      if (TYPE_PTRMEMFUNC_P (intype)
	  || TREE_CODE (intype) == METHOD_TYPE)
	return convert_member_func_to_ptr (type, expr);
      if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
	return build_nop (type, expr);
      intype = TREE_TYPE (expr);
    }

  if (expr == error_mark_node)
    return error_mark_node;

  form = TREE_CODE (intype);

  if (POINTER_TYPE_P (intype))
    {
      intype = TYPE_MAIN_VARIANT (intype);

      if (TYPE_MAIN_VARIANT (type) != intype
	  && TREE_CODE (type) == POINTER_TYPE
	  && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
	  && MAYBE_CLASS_TYPE_P (TREE_TYPE (type))
	  && MAYBE_CLASS_TYPE_P (TREE_TYPE (intype))
	  && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE)
	{
	  enum tree_code code = PLUS_EXPR;
	  tree binfo;
	  tree intype_class;
	  tree type_class;
	  bool same_p;

	  intype_class = TREE_TYPE (intype);
	  type_class = TREE_TYPE (type);

	  same_p = same_type_p (TYPE_MAIN_VARIANT (intype_class),
				TYPE_MAIN_VARIANT (type_class));
	  binfo = NULL_TREE;
	  /* Try derived to base conversion.  */
	  if (!same_p)
	    binfo = lookup_base (intype_class, type_class, ba_check, NULL);
	  if (!same_p && !binfo)
	    {
	      /* Try base to derived conversion.  */
	      binfo = lookup_base (type_class, intype_class, ba_check, NULL);
	      code = MINUS_EXPR;
	    }
	  if (binfo == error_mark_node)
	    return error_mark_node;
	  if (binfo || same_p)
	    {
	      if (binfo)
		expr = build_base_path (code, expr, binfo, 0);
	      /* Add any qualifier conversions.  */
	      return build_nop (type, expr);
	    }
	}

      if (TYPE_PTRMEMFUNC_P (type))
	{
	  error ("cannot convert %qE from type %qT to type %qT",
		 expr, intype, type);
	  return error_mark_node;
	}

      return build_nop (type, expr);
    }
  else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
	   || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
    return convert_ptrmem (type, expr, /*allow_inverse_p=*/false,
			   /*c_cast_p=*/false);
  else if (TYPE_PTRMEMFUNC_P (intype))
    {
      if (!warn_pmf2ptr)
	{
	  if (TREE_CODE (expr) == PTRMEM_CST)
	    return cp_convert_to_pointer (type,
					  PTRMEM_CST_MEMBER (expr));
	  else if (TREE_CODE (expr) == OFFSET_REF)
	    {
	      tree object = TREE_OPERAND (expr, 0);
	      return get_member_function_from_ptrfunc (&object,
						       TREE_OPERAND (expr, 1));
	    }
	}
      error ("cannot convert %qE from type %qT to type %qT",
	     expr, intype, type);
      return error_mark_node;
    }

  if (integer_zerop (expr))
    {
      if (TYPE_PTRMEMFUNC_P (type))
	return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0,
				 /*c_cast_p=*/false);

      if (TYPE_PTRMEM_P (type))
	{
	  /* A NULL pointer-to-member is represented by -1, not by
	     zero.  */
	  expr = build_int_cst_type (type, -1);
	}
      else
	expr = build_int_cst (type, 0);

      return expr;
    }
  else if (TYPE_PTR_TO_MEMBER_P (type) && INTEGRAL_CODE_P (form))
    {
      error ("invalid conversion from %qT to %qT", intype, type);
      return error_mark_node;
    }

  if (INTEGRAL_CODE_P (form))
    {
      if (TYPE_PRECISION (intype) == POINTER_SIZE)
	return build1 (CONVERT_EXPR, type, expr);
      expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 0), expr);
      /* Modes may be different but sizes should be the same.  There
	 is supposed to be some integral type that is the same width
	 as a pointer.  */
      gcc_assert (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr)))
		  == GET_MODE_SIZE (TYPE_MODE (type)));

      return convert_to_pointer (type, expr);
    }

  if (type_unknown_p (expr))
    return instantiate_type (type, expr, tf_warning_or_error);

  error ("cannot convert %qE from type %qT to type %qT",
	 expr, intype, type);
  return error_mark_node;
}
Example #18
0
/* Find memcpy, mempcpy, memmove and memset calls, perform
   checks before call and then call no_chk version of
   functions.  We do it on O2 to enable inlining of these
   functions during expand.

   Also try to find memcpy, mempcpy, memmove and memset calls
   which are known to not write pointers to memory and use
   faster function versions for them.  */
static void
chkp_optimize_string_function_calls (void)
{
    basic_block bb;

    if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "Searching for replaceable string function calls...\n");

    FOR_EACH_BB_FN (bb, cfun)
    {
        gimple_stmt_iterator i;

        for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
        {
            gimple *stmt = gsi_stmt (i);
            tree fndecl;

            if (gimple_code (stmt) != GIMPLE_CALL
                    || !gimple_call_with_bounds_p (stmt))
                continue;

            fndecl = gimple_call_fndecl (stmt);

            if (!fndecl || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
                continue;

            if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMCPY_CHKP
                    || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY_CHKP
                    || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMMOVE_CHKP
                    || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET_CHKP)
            {
                tree dst = gimple_call_arg (stmt, 0);
                tree dst_bnd = gimple_call_arg (stmt, 1);
                bool is_memset = DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET_CHKP;
                tree size = gimple_call_arg (stmt, is_memset ? 3 : 4);
                tree fndecl_nochk;
                gimple_stmt_iterator j;
                basic_block check_bb;
                address_t size_val;
                int sign;
                bool known;

                /* We may replace call with corresponding __chkp_*_nobnd
                call in case destination pointer base type is not
                 void or pointer.  */
                if (POINTER_TYPE_P (TREE_TYPE (dst))
                        && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (dst)))
                        && !chkp_type_has_pointer (TREE_TYPE (TREE_TYPE (dst))))
                {
                    tree fndecl_nobnd
                        = chkp_get_nobnd_fndecl (DECL_FUNCTION_CODE (fndecl));

                    if (fndecl_nobnd)
                        fndecl = fndecl_nobnd;
                }

                fndecl_nochk = chkp_get_nochk_fndecl (DECL_FUNCTION_CODE (fndecl));

                if (fndecl_nochk)
                    fndecl = fndecl_nochk;

                if (fndecl != gimple_call_fndecl (stmt))
                {
                    if (dump_file && (dump_flags & TDF_DETAILS))
                    {
                        fprintf (dump_file, "Replacing call: ");
                        print_gimple_stmt (dump_file, stmt, 0,
                                           TDF_VOPS|TDF_MEMSYMS);
                    }

                    gimple_call_set_fndecl (stmt, fndecl);

                    if (dump_file && (dump_flags & TDF_DETAILS))
                    {
                        fprintf (dump_file, "With a new call: ");
                        print_gimple_stmt (dump_file, stmt, 0,
                                           TDF_VOPS|TDF_MEMSYMS);
                    }
                }

                /* If there is no nochk version of function then
                do nothing.  Otherwise insert checks before
                 the call.  */
                if (!fndecl_nochk)
                    continue;

                /* If size passed to call is known and > 0
                then we may insert checks unconditionally.  */
                size_val.pol.create (0);
                chkp_collect_value (size, size_val);
                known = chkp_is_constant_addr (size_val, &sign);
                size_val.pol.release ();

                /* If we are not sure size is not zero then we have
                to perform runtime check for size and perform
                 checks only when size is not zero.  */
                if (!known)
                {
                    gimple *check = gimple_build_cond (NE_EXPR,
                                                       size,
                                                       size_zero_node,
                                                       NULL_TREE,
                                                       NULL_TREE);

                    /* Split block before string function call.  */
                    gsi_prev (&i);
                    check_bb = insert_cond_bb (bb, gsi_stmt (i), check);

                    /* Set position for checks.  */
                    j = gsi_last_bb (check_bb);

                    /* The block was splitted and therefore we
                       need to set iterator to its end.  */
                    i = gsi_last_bb (bb);
                }
                /* If size is known to be zero then no checks
                should be performed.  */
                else if (!sign)
                    continue;
                else
                    j = i;

                size = size_binop (MINUS_EXPR, size, size_one_node);
                if (!is_memset)
                {
                    tree src = gimple_call_arg (stmt, 2);
                    tree src_bnd = gimple_call_arg (stmt, 3);

                    chkp_check_mem_access (src, fold_build_pointer_plus (src, size),
                                           src_bnd, j, gimple_location (stmt),
                                           integer_zero_node);
                }

                chkp_check_mem_access (dst, fold_build_pointer_plus (dst, size),
                                       dst_bnd, j, gimple_location (stmt),
                                       integer_one_node);

            }
        }
    }
Example #19
0
File: cvt.c Project: Fokycnuk/gcc
static tree
cp_convert_to_pointer (tree type, tree expr, bool force)
{
  tree intype = TREE_TYPE (expr);
  enum tree_code form;
  tree rval;
  if (intype == error_mark_node)
    return error_mark_node;

  if (IS_AGGR_TYPE (intype))
    {
      intype = complete_type (intype);
      if (!COMPLETE_TYPE_P (intype))
	{
	  error ("can't convert from incomplete type `%T' to `%T'",
		    intype, type);
	  return error_mark_node;
	}

      rval = build_type_conversion (type, expr);
      if (rval)
	{
	  if (rval == error_mark_node)
	    error ("conversion of `%E' from `%T' to `%T' is ambiguous",
		      expr, intype, type);
	  return rval;
	}
    }

  /* Handle anachronistic conversions from (::*)() to cv void* or (*)().  */
  if (TREE_CODE (type) == POINTER_TYPE
      && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
	  || VOID_TYPE_P (TREE_TYPE (type))))
    {
      /* Allow an implicit this pointer for pointer to member
	 functions.  */
      if (TYPE_PTRMEMFUNC_P (intype))
	{
	  if (pedantic || warn_pmf2ptr)
	    pedwarn ("converting from `%T' to `%T'", intype, type);
	  if (TREE_CODE (expr) == PTRMEM_CST)
	    expr = build_address (PTRMEM_CST_MEMBER (expr));
	  else
	    {
	      tree decl = maybe_dummy_object (TYPE_PTRMEM_CLASS_TYPE (intype), 
					      0);
	      decl = build_address (decl);
	      expr = get_member_function_from_ptrfunc (&decl, expr);
	    }
	}
      else if (TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE)
	{
	  if (pedantic || warn_pmf2ptr)
	    pedwarn ("converting from `%T' to `%T'", intype, type);
	  expr = build_addr_func (expr);
	}
      if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
	return build_nop (type, expr);
      intype = TREE_TYPE (expr);
    }

  if (expr == error_mark_node)
    return error_mark_node;

  form = TREE_CODE (intype);

  if (POINTER_TYPE_P (intype))
    {
      intype = TYPE_MAIN_VARIANT (intype);

      if (TYPE_MAIN_VARIANT (type) != intype
	  && TREE_CODE (type) == POINTER_TYPE
	  && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
	  && IS_AGGR_TYPE (TREE_TYPE (type))
	  && IS_AGGR_TYPE (TREE_TYPE (intype))
	  && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE)
	{
	  enum tree_code code = PLUS_EXPR;
	  tree binfo;
	  tree intype_class;
	  tree type_class;
	  bool same_p;

	  intype_class = TREE_TYPE (intype);
	  type_class = TREE_TYPE (type);

	  same_p = same_type_p (TYPE_MAIN_VARIANT (intype_class), 
				TYPE_MAIN_VARIANT (type_class));
	  binfo = NULL_TREE;
	  /* Try derived to base conversion.  */
	  if (!same_p)
	    binfo = lookup_base (intype_class, type_class, ba_check, NULL);
	  if (!same_p && !binfo)
	    {
	      /* Try base to derived conversion.  */
	      binfo = lookup_base (type_class, intype_class, ba_check, NULL);
	      code = MINUS_EXPR;
	    }
	  if (binfo == error_mark_node)
	    return error_mark_node;
	  if (binfo || same_p)
	    {
	      if (binfo)
		expr = build_base_path (code, expr, binfo, 0);
	      /* Add any qualifier conversions.  */
	      return build_nop (type, expr);
	    }
	}

      if (TYPE_PTRMEMFUNC_P (type))
	{
	  error ("cannot convert `%E' from type `%T' to type `%T'",
		    expr, intype, type);
	  return error_mark_node;
	}

      return build_nop (type, expr);
    }
  else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
    {
      tree b1; 
      tree b2;
      tree binfo;
      enum tree_code code = PLUS_EXPR;
      base_kind bk;

      b1 = TYPE_PTRMEM_CLASS_TYPE (type);
      b2 = TYPE_PTRMEM_CLASS_TYPE (intype);
      binfo = lookup_base (b1, b2, ba_check, &bk);
      if (!binfo)
	{
	  binfo = lookup_base (b2, b1, ba_check, &bk);
	  code = MINUS_EXPR;
	}
      if (binfo == error_mark_node)
	return error_mark_node;

      if (bk == bk_via_virtual)
	{
	  if (force)
	    warning ("pointer to member cast from `%T' to `%T' is via virtual base",
		     intype, type);
	  else
	    {
	      error ("pointer to member cast from `%T' to `%T' is via virtual base",
		     intype, type);
	      return error_mark_node;
	    }
	  /* This is a reinterpret cast, whose result is unspecified.
	     We choose to do nothing.  */
	  return build1 (NOP_EXPR, type, expr);
	}

      if (TREE_CODE (expr) == PTRMEM_CST)
	expr = cplus_expand_constant (expr);

      if (binfo && !integer_zerop (BINFO_OFFSET (binfo)))
	expr = size_binop (code, 
			   build_nop (sizetype, expr),
			   BINFO_OFFSET (binfo));
      return build_nop (type, expr);
    }
  else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))
    return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
  else if (TYPE_PTRMEMFUNC_P (intype))
    {
      if (!warn_pmf2ptr)
	{
	  if (TREE_CODE (expr) == PTRMEM_CST)
	    return cp_convert_to_pointer (type,
					  PTRMEM_CST_MEMBER (expr),
					  force);
	  else if (TREE_CODE (expr) == OFFSET_REF)
	    {
	      tree object = TREE_OPERAND (expr, 0);
	      return get_member_function_from_ptrfunc (&object,
						       TREE_OPERAND (expr, 1));
	    }
	}
      error ("cannot convert `%E' from type `%T' to type `%T'",
		expr, intype, type);
      return error_mark_node;
    }

  if (integer_zerop (expr))
    {
      if (TYPE_PTRMEMFUNC_P (type))
	return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);

      if (TYPE_PTRMEM_P (type))
	/* A NULL pointer-to-member is represented by -1, not by
	   zero.  */
	expr = build_int_2 (-1, -1);
      else
	expr = build_int_2 (0, 0);
      TREE_TYPE (expr) = type;
      /* Fix up the representation of -1 if appropriate.  */
      force_fit_type (expr, 0);
      return expr;
    }
  else if (TYPE_PTR_TO_MEMBER_P (type) && INTEGRAL_CODE_P (form))
    {
      error ("invalid conversion from '%T' to '%T'", intype, type);
      return error_mark_node;
    }

  if (INTEGRAL_CODE_P (form))
    {
      if (TYPE_PRECISION (intype) == POINTER_SIZE)
	return build1 (CONVERT_EXPR, type, expr);
      expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 0), expr);
      /* Modes may be different but sizes should be the same.  */
      if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr)))
	  != GET_MODE_SIZE (TYPE_MODE (type)))
	/* There is supposed to be some integral type
	   that is the same width as a pointer.  */
	abort ();
      return convert_to_pointer (type, expr);
    }

  if (type_unknown_p (expr))
    return instantiate_type (type, expr, tf_error | tf_warning);

  error ("cannot convert `%E' from type `%T' to type `%T'",
	    expr, intype, type);
  return error_mark_node;
}
Example #20
0
File: cvt.c Project: Fokycnuk/gcc
tree
convert_to_void (tree expr, const char *implicit)
{
  if (expr == error_mark_node 
      || TREE_TYPE (expr) == error_mark_node)
    return error_mark_node;
  if (!TREE_TYPE (expr))
    return expr;
  if (invalid_nonstatic_memfn_p (expr))
    return error_mark_node;
  if (TREE_CODE (expr) == PSEUDO_DTOR_EXPR)
    {
      error ("pseudo-destructor is not called");
      return error_mark_node;
    }
  if (VOID_TYPE_P (TREE_TYPE (expr)))
    return expr;
  switch (TREE_CODE (expr))
    {
    case COND_EXPR:
      {
        /* The two parts of a cond expr might be separate lvalues.  */
        tree op1 = TREE_OPERAND (expr,1);
        tree op2 = TREE_OPERAND (expr,2);
        tree new_op1 = convert_to_void
	  (op1, (implicit && !TREE_SIDE_EFFECTS (op2)
		 ? "second operand of conditional" : NULL));
        tree new_op2 = convert_to_void
	  (op2, (implicit && !TREE_SIDE_EFFECTS (op1)
		 ? "third operand of conditional" : NULL));
        
	expr = build (COND_EXPR, TREE_TYPE (new_op1),
		      TREE_OPERAND (expr, 0), new_op1, new_op2);
        break;
      }
    
    case COMPOUND_EXPR:
      {
        /* The second part of a compound expr contains the value.  */
        tree op1 = TREE_OPERAND (expr,1);
        tree new_op1 = convert_to_void
	  (op1, (implicit && !TREE_NO_UNUSED_WARNING (expr)
		 ? "right-hand operand of comma" : NULL));
        
        if (new_op1 != op1)
	  {
	    tree t = build (COMPOUND_EXPR, TREE_TYPE (new_op1),
			    TREE_OPERAND (expr, 0), new_op1);
	    expr = t;
	  }

        break;
      }
    
    case NON_LVALUE_EXPR:
    case NOP_EXPR:
      /* These have already decayed to rvalue.  */
      break;
    
    case CALL_EXPR:   /* We have a special meaning for volatile void fn().  */
      break;
    
    case INDIRECT_REF:
      {
        tree type = TREE_TYPE (expr);
        int is_reference = TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0)))
                           == REFERENCE_TYPE;
        int is_volatile = TYPE_VOLATILE (type);
        int is_complete = COMPLETE_TYPE_P (complete_type (type));
        
        if (is_volatile && !is_complete)
          warning ("object of incomplete type `%T' will not be accessed in %s",
                      type, implicit ? implicit : "void context");
        else if (is_reference && is_volatile)
          warning ("object of type `%T' will not be accessed in %s",
                      TREE_TYPE (TREE_OPERAND (expr, 0)),
                      implicit ? implicit : "void context");
        if (is_reference || !is_volatile || !is_complete)
          expr = TREE_OPERAND (expr, 0);
      
        break;
      }
    
    case VAR_DECL:
      {
        /* External variables might be incomplete.  */
        tree type = TREE_TYPE (expr);
        int is_complete = COMPLETE_TYPE_P (complete_type (type));
        
        if (TYPE_VOLATILE (type) && !is_complete)
          warning ("object `%E' of incomplete type `%T' will not be accessed in %s",
                      expr, type, implicit ? implicit : "void context");
        break;
      }

    default:;
    }
  {
    tree probe = expr;
  
    if (TREE_CODE (probe) == ADDR_EXPR)
      probe = TREE_OPERAND (expr, 0);
    if (type_unknown_p (probe))
      {
	/* [over.over] enumerates the places where we can take the address
	   of an overloaded function, and this is not one of them.  */
	pedwarn ("%s cannot resolve address of overloaded function",
		    implicit ? implicit : "void cast");
	expr = void_zero_node;
      }
    else if (implicit && probe == expr && is_overloaded_fn (probe))
      /* Only warn when there is no &.  */
      warning ("%s is a reference, not call, to function `%E'",
		  implicit, expr);
  }
  
  if (expr != error_mark_node && !VOID_TYPE_P (TREE_TYPE (expr)))
    {
      if (implicit && !TREE_SIDE_EFFECTS (expr) && warn_unused_value)
	warning ("%s has no effect", implicit);
      expr = build1 (CONVERT_EXPR, void_type_node, expr);
    }
  return expr;
}
Example #21
0
File: c-omp.c Project: ymgcmstk/gcc
static tree
check_omp_for_incr_expr (location_t loc, tree exp, tree decl)
{
  tree t;

  if (!INTEGRAL_TYPE_P (TREE_TYPE (exp))
      || TYPE_PRECISION (TREE_TYPE (exp)) < TYPE_PRECISION (TREE_TYPE (decl)))
    return error_mark_node;

  if (exp == decl)
    return build_int_cst (TREE_TYPE (exp), 0);

  switch (TREE_CODE (exp))
    {
    CASE_CONVERT:
      t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl);
      if (t != error_mark_node)
        return fold_convert_loc (loc, TREE_TYPE (exp), t);
      break;
    case MINUS_EXPR:
      t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl);
      if (t != error_mark_node)
        return fold_build2_loc (loc, MINUS_EXPR,
			    TREE_TYPE (exp), t, TREE_OPERAND (exp, 1));
      break;
    case PLUS_EXPR:
      t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 0), decl);
      if (t != error_mark_node)
        return fold_build2_loc (loc, PLUS_EXPR,
			    TREE_TYPE (exp), t, TREE_OPERAND (exp, 1));
      t = check_omp_for_incr_expr (loc, TREE_OPERAND (exp, 1), decl);
      if (t != error_mark_node)
        return fold_build2_loc (loc, PLUS_EXPR,
			    TREE_TYPE (exp), TREE_OPERAND (exp, 0), t);
      break;
    case COMPOUND_EXPR:
      {
	/* cp_build_modify_expr forces preevaluation of the RHS to make
	   sure that it is evaluated before the lvalue-rvalue conversion
	   is applied to the LHS.  Reconstruct the original expression.  */
	tree op0 = TREE_OPERAND (exp, 0);
	if (TREE_CODE (op0) == TARGET_EXPR
	    && !VOID_TYPE_P (TREE_TYPE (op0)))
	  {
	    tree op1 = TREE_OPERAND (exp, 1);
	    tree temp = TARGET_EXPR_SLOT (op0);
	    if (BINARY_CLASS_P (op1)
		&& TREE_OPERAND (op1, 1) == temp)
	      {
		op1 = copy_node (op1);
		TREE_OPERAND (op1, 1) = TARGET_EXPR_INITIAL (op0);
		return check_omp_for_incr_expr (loc, op1, decl);
	      }
	  }
	break;
      }
    default:
      break;
    }

  return error_mark_node;
}
Example #22
0
void
use_thunk (tree thunk_fndecl, bool emit_p)
{
    tree a, t, function, alias;
    tree virtual_offset;
    HOST_WIDE_INT fixed_offset, virtual_value;
    bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl);

    /* We should have called finish_thunk to give it a name.  */
    gcc_assert (DECL_NAME (thunk_fndecl));

    /* We should never be using an alias, always refer to the
       aliased thunk.  */
    gcc_assert (!THUNK_ALIAS (thunk_fndecl));

    if (TREE_ASM_WRITTEN (thunk_fndecl))
        return;

    function = THUNK_TARGET (thunk_fndecl);
    if (DECL_RESULT (thunk_fndecl))
        /* We already turned this thunk into an ordinary function.
           There's no need to process this thunk again.  */
        return;

    if (DECL_THUNK_P (function))
        /* The target is itself a thunk, process it now.  */
        use_thunk (function, emit_p);

    /* Thunks are always addressable; they only appear in vtables.  */
    TREE_ADDRESSABLE (thunk_fndecl) = 1;

    /* Figure out what function is being thunked to.  It's referenced in
       this translation unit.  */
    TREE_ADDRESSABLE (function) = 1;
    mark_used (function);
    if (!emit_p)
        return;

    if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function))
        alias = make_alias_for_thunk (function);
    else
        alias = function;

    fixed_offset = THUNK_FIXED_OFFSET (thunk_fndecl);
    virtual_offset = THUNK_VIRTUAL_OFFSET (thunk_fndecl);

    if (virtual_offset)
    {
        if (!this_adjusting)
            virtual_offset = BINFO_VPTR_FIELD (virtual_offset);
        virtual_value = tree_low_cst (virtual_offset, /*pos=*/0);
        gcc_assert (virtual_value);
    }
    else
        virtual_value = 0;

    /* And, if we need to emit the thunk, it's used.  */
    mark_used (thunk_fndecl);
    /* This thunk is actually defined.  */
    DECL_EXTERNAL (thunk_fndecl) = 0;
    /* The linkage of the function may have changed.  FIXME in linkage
       rewrite.  */
    TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function);
    DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function);
    DECL_VISIBILITY_SPECIFIED (thunk_fndecl)
        = DECL_VISIBILITY_SPECIFIED (function);
    if (DECL_ONE_ONLY (function))
        make_decl_one_only (thunk_fndecl);

    if (flag_syntax_only)
    {
        TREE_ASM_WRITTEN (thunk_fndecl) = 1;
        return;
    }

    push_to_top_level ();

    if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function)
            && targetm.have_named_sections)
    {
        resolve_unique_section (function, 0, flag_function_sections);

        if (DECL_SECTION_NAME (function) != NULL && DECL_ONE_ONLY (function))
        {
            resolve_unique_section (thunk_fndecl, 0, flag_function_sections);

            /* Output the thunk into the same section as function.  */
            DECL_SECTION_NAME (thunk_fndecl) = DECL_SECTION_NAME (function);
        }
    }

    /* The back-end expects DECL_INITIAL to contain a BLOCK, so we
       create one.  */
    DECL_INITIAL (thunk_fndecl) = make_node (BLOCK);

    /* Set up cloned argument trees for the thunk.  */
    t = NULL_TREE;
    for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
    {
        tree x = copy_node (a);
        TREE_CHAIN (x) = t;
        DECL_CONTEXT (x) = thunk_fndecl;
        SET_DECL_RTL (x, NULL_RTX);
        DECL_HAS_VALUE_EXPR_P (x) = 0;
        t = x;
    }
    a = nreverse (t);
    DECL_ARGUMENTS (thunk_fndecl) = a;
    BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) = a;

    if (this_adjusting
            && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
                    virtual_value, alias))
    {
        const char *fnname;
        current_function_decl = thunk_fndecl;
        DECL_RESULT (thunk_fndecl)
            = build_decl (RESULT_DECL, 0, integer_type_node);
        fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
        init_function_start (thunk_fndecl);
        current_function_is_thunk = 1;
        assemble_start_function (thunk_fndecl, fnname);

        targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl,
                                         fixed_offset, virtual_value, alias);

        assemble_end_function (thunk_fndecl, fnname);
        init_insn_lengths ();
        current_function_decl = 0;
        cfun = 0;
        TREE_ASM_WRITTEN (thunk_fndecl) = 1;
    }
    else
    {
        /* If this is a covariant thunk, or we don't have the necessary
        code for efficient thunks, generate a thunk function that
         just makes a call to the real function.  Unfortunately, this
         doesn't work for varargs.  */

        if (varargs_function_p (function))
            error ("generic thunk code fails for method %q#D which uses %<...%>",
                   function);

        DECL_RESULT (thunk_fndecl) = NULL_TREE;

        start_preparsed_function (thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
        /* We don't bother with a body block for thunks.  */

        /* There's no need to check accessibility inside the thunk body.  */
        push_deferring_access_checks (dk_no_check);

        t = a;
        if (this_adjusting)
            t = thunk_adjust (t, /*this_adjusting=*/1,
                              fixed_offset, virtual_offset);

        /* Build up the call to the real function.  */
        t = tree_cons (NULL_TREE, t, NULL_TREE);
        for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
            t = tree_cons (NULL_TREE, a, t);
        t = nreverse (t);
        t = build_call (alias, t);
        CALL_FROM_THUNK_P (t) = 1;

        if (VOID_TYPE_P (TREE_TYPE (t)))
            finish_expr_stmt (t);
        else
        {
            if (!this_adjusting)
            {
                tree cond = NULL_TREE;

                if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
                {
                    /* If the return type is a pointer, we need to
                       protect against NULL.  We know there will be an
                       adjustment, because that's why we're emitting a
                       thunk.  */
                    t = save_expr (t);
                    cond = cp_convert (boolean_type_node, t);
                }

                t = thunk_adjust (t, /*this_adjusting=*/0,
                                  fixed_offset, virtual_offset);
                if (cond)
                    t = build3 (COND_EXPR, TREE_TYPE (t), cond, t,
                                cp_convert (TREE_TYPE (t), integer_zero_node));
            }
            if (IS_AGGR_TYPE (TREE_TYPE (t)))
                t = build_cplus_new (TREE_TYPE (t), t);
            finish_return_stmt (t);
        }

        /* Since we want to emit the thunk, we explicitly mark its name as
        referenced.  */
        mark_decl_referenced (thunk_fndecl);

        /* But we don't want debugging information about it.  */
        DECL_IGNORED_P (thunk_fndecl) = 1;

        /* Re-enable access control.  */
        pop_deferring_access_checks ();

        thunk_fndecl = finish_function (0);
        tree_lowering_passes (thunk_fndecl);
        expand_body (thunk_fndecl);
    }

    pop_from_top_level ();
}
Example #23
0
static tree
build_dynamic_cast_1 (tree type, tree expr)
{
  enum tree_code tc = TREE_CODE (type);
  tree exprtype = TREE_TYPE (expr);
  tree dcast_fn;
  tree old_expr = expr;
  const char *errstr = NULL;

  /* T shall be a pointer or reference to a complete class type, or
     `pointer to cv void''.  */
  switch (tc)
    {
    case POINTER_TYPE:
      if (TREE_CODE (TREE_TYPE (type)) == VOID_TYPE)
	break;
      /* Fall through.  */
    case REFERENCE_TYPE:
      if (! IS_AGGR_TYPE (TREE_TYPE (type)))
	{
	  errstr = "target is not pointer or reference to class";
	  goto fail;
	}
      if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (type))))
	{
	  errstr = "target is not pointer or reference to complete type";
	  goto fail;
	}
      break;

    default:
      errstr = "target is not pointer or reference";
      goto fail;
    }

  if (tc == POINTER_TYPE)
    {
      /* If T is a pointer type, v shall be an rvalue of a pointer to
	 complete class type, and the result is an rvalue of type T.  */

      if (TREE_CODE (exprtype) != POINTER_TYPE)
	{
	  errstr = "source is not a pointer";
	  goto fail;
	}
      if (! IS_AGGR_TYPE (TREE_TYPE (exprtype)))
	{
	  errstr = "source is not a pointer to class";
	  goto fail;
	}
      if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (exprtype))))
	{
	  errstr = "source is a pointer to incomplete type";
	  goto fail;
	}
    }
  else
    {
      /* Apply trivial conversion T -> T& for dereferenced ptrs.  */
      exprtype = build_reference_type (exprtype);
      expr = convert_to_reference (exprtype, expr, CONV_IMPLICIT,
				   LOOKUP_NORMAL, NULL_TREE);

      /* T is a reference type, v shall be an lvalue of a complete class
	 type, and the result is an lvalue of the type referred to by T.  */

      if (! IS_AGGR_TYPE (TREE_TYPE (exprtype)))
	{
	  errstr = "source is not of class type";
	  goto fail;
	}
      if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (exprtype))))
	{
	  errstr = "source is of incomplete class type";
	  goto fail;
	}
      
    }

  /* The dynamic_cast operator shall not cast away constness.  */
  if (!at_least_as_qualified_p (TREE_TYPE (type),
				TREE_TYPE (exprtype)))
    {
      errstr = "conversion casts away constness";
      goto fail;
    }

  /* If *type is an unambiguous accessible base class of *exprtype,
     convert statically.  */
  {
    tree binfo;

    binfo = lookup_base (TREE_TYPE (exprtype), TREE_TYPE (type),
			 ba_check, NULL);

    if (binfo)
      {
	expr = build_base_path (PLUS_EXPR, convert_from_reference (expr),
				binfo, 0);
	if (TREE_CODE (exprtype) == POINTER_TYPE)
	  expr = non_lvalue (expr);
	return expr;
      }
  }

  /* Otherwise *exprtype must be a polymorphic class (have a vtbl).  */
  if (TYPE_POLYMORPHIC_P (TREE_TYPE (exprtype)))
    {
      tree expr1;
      /* if TYPE is `void *', return pointer to complete object.  */
      if (tc == POINTER_TYPE && VOID_TYPE_P (TREE_TYPE (type)))
	{
	  /* if b is an object, dynamic_cast<void *>(&b) == (void *)&b.  */
	  if (TREE_CODE (expr) == ADDR_EXPR
	      && TREE_CODE (TREE_OPERAND (expr, 0)) == VAR_DECL
	      && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE)
	    return build1 (NOP_EXPR, type, expr);

	  /* Since expr is used twice below, save it.  */
	  expr = save_expr (expr);

	  expr1 = build_headof (expr);
	  if (TREE_TYPE (expr1) != type)
	    expr1 = build1 (NOP_EXPR, type, expr1);
	  return ifnonnull (expr, expr1);
	}
      else
	{
	  tree retval;
          tree result, td2, td3, elems;
          tree static_type, target_type, boff;

 	  /* If we got here, we can't convert statically.  Therefore,
	     dynamic_cast<D&>(b) (b an object) cannot succeed.  */
	  if (tc == REFERENCE_TYPE)
	    {
	      if (TREE_CODE (old_expr) == VAR_DECL
		  && TREE_CODE (TREE_TYPE (old_expr)) == RECORD_TYPE)
		{
	          tree expr = throw_bad_cast ();
		  warning ("dynamic_cast of %q#D to %q#T can never succeed",
                           old_expr, type);
	          /* Bash it to the expected type.  */
	          TREE_TYPE (expr) = type;
		  return expr;
		}
	    }
	  /* Ditto for dynamic_cast<D*>(&b).  */
	  else if (TREE_CODE (expr) == ADDR_EXPR)
	    {
	      tree op = TREE_OPERAND (expr, 0);
	      if (TREE_CODE (op) == VAR_DECL
		  && TREE_CODE (TREE_TYPE (op)) == RECORD_TYPE)
		{
		  warning ("dynamic_cast of %q#D to %q#T can never succeed",
                           op, type);
		  retval = build_int_cst (type, 0); 
		  return retval;
		}
	    }

	  target_type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
	  static_type = TYPE_MAIN_VARIANT (TREE_TYPE (exprtype));
	  td2 = get_tinfo_decl (target_type);
	  mark_used (td2);
	  td2 = build_unary_op (ADDR_EXPR, td2, 0);
	  td3 = get_tinfo_decl (static_type);
	  mark_used (td3);
	  td3 = build_unary_op (ADDR_EXPR, td3, 0);

          /* Determine how T and V are related.  */
          boff = dcast_base_hint (static_type, target_type);
          
	  /* Since expr is used twice below, save it.  */
	  expr = save_expr (expr);

	  expr1 = expr;
	  if (tc == REFERENCE_TYPE)
	    expr1 = build_unary_op (ADDR_EXPR, expr1, 0);

	  elems = tree_cons
	    (NULL_TREE, expr1, tree_cons
	     (NULL_TREE, td3, tree_cons
	      (NULL_TREE, td2, tree_cons
	       (NULL_TREE, boff, NULL_TREE))));

	  dcast_fn = dynamic_cast_node;
	  if (!dcast_fn)
	    {
	      tree tmp;
	      tree tinfo_ptr;
	      tree ns = abi_node;
	      const char *name;
	      
	      push_nested_namespace (ns);
	      tinfo_ptr = xref_tag (class_type,
				    get_identifier ("__class_type_info"),
				    /* APPLE LOCAL 4184203 */
				    /*tag_scope=*/ts_global, false);
	      
	      tinfo_ptr = build_pointer_type
		(build_qualified_type
		 (tinfo_ptr, TYPE_QUAL_CONST));
	      name = "__dynamic_cast";
	      tmp = tree_cons
		(NULL_TREE, const_ptr_type_node, tree_cons
		 (NULL_TREE, tinfo_ptr, tree_cons
		  (NULL_TREE, tinfo_ptr, tree_cons
		   (NULL_TREE, ptrdiff_type_node, void_list_node))));
	      tmp = build_function_type (ptr_type_node, tmp);
	      dcast_fn = build_library_fn_ptr (name, tmp);
	      DECL_IS_PURE (dcast_fn) = 1;
              pop_nested_namespace (ns);
              dynamic_cast_node = dcast_fn;
	    }
          result = build_cxx_call (dcast_fn, elems);

	  if (tc == REFERENCE_TYPE)
	    {
	      tree bad = throw_bad_cast ();
	      
	      result = save_expr (result);
	      return build3 (COND_EXPR, type, result, result, bad);
	    }

	  /* Now back to the type we want from a void*.  */
	  result = cp_convert (type, result);
          return ifnonnull (expr, result);
	}
    }
  else
    errstr = "source type is not polymorphic";

 fail:
  error ("cannot dynamic_cast %qE (of type %q#T) to type %q#T (%s)",
         expr, exprtype, type, errstr);
  return error_mark_node;
}
Example #24
0
tree
convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
{
  if (expr == error_mark_node
      || TREE_TYPE (expr) == error_mark_node)
    return error_mark_node;

  if (implicit == ICV_CAST)
    mark_exp_read (expr);
  else
    {
      tree exprv = expr;

      while (TREE_CODE (exprv) == COMPOUND_EXPR)
	exprv = TREE_OPERAND (exprv, 1);
      if (DECL_P (exprv)
	  || handled_component_p (exprv)
	  || TREE_CODE (exprv) == INDIRECT_REF)
	/* Expr is not being 'used' here, otherwise we whould have
	   called mark_{rl}value_use use here, which would have in turn
	   called mark_exp_read.  Rather, we call mark_exp_read directly
	   to avoid some warnings when
	   -Wunused-but-set-{variable,parameter} is in effect.  */
	mark_exp_read (exprv);
    }

  if (!TREE_TYPE (expr))
    return expr;
  if (invalid_nonstatic_memfn_p (expr, complain))
    return error_mark_node;
  if (TREE_CODE (expr) == PSEUDO_DTOR_EXPR)
    {
      if (complain & tf_error)
        error ("pseudo-destructor is not called");
      return error_mark_node;
    }
  if (VOID_TYPE_P (TREE_TYPE (expr)))
    return expr;
  switch (TREE_CODE (expr))
    {
    case COND_EXPR:
      {
	/* The two parts of a cond expr might be separate lvalues.  */
	tree op1 = TREE_OPERAND (expr,1);
	tree op2 = TREE_OPERAND (expr,2);
	bool side_effects = TREE_SIDE_EFFECTS (op1) || TREE_SIDE_EFFECTS (op2);
	tree new_op1, new_op2;
	if (implicit != ICV_CAST && !side_effects)
	  {
	    new_op1 = convert_to_void (op1, ICV_SECOND_OF_COND, complain);
	    new_op2 = convert_to_void (op2, ICV_THIRD_OF_COND, complain);
	  }
	else
	  {
	    new_op1 = convert_to_void (op1, ICV_CAST, complain);
	    new_op2 = convert_to_void (op2, ICV_CAST, complain);
	  }

	expr = build3 (COND_EXPR, TREE_TYPE (new_op1),
		       TREE_OPERAND (expr, 0), new_op1, new_op2);
	break;
      }

    case COMPOUND_EXPR:
      {
	/* The second part of a compound expr contains the value.  */
	tree op1 = TREE_OPERAND (expr,1);
	tree new_op1;
	if (implicit != ICV_CAST && !TREE_NO_WARNING (expr))
	  new_op1 = convert_to_void (op1, ICV_RIGHT_OF_COMMA, complain);
	else
	  new_op1 = convert_to_void (op1, ICV_CAST, complain);

	if (new_op1 != op1)
	  {
	    tree t = build2 (COMPOUND_EXPR, TREE_TYPE (new_op1),
			     TREE_OPERAND (expr, 0), new_op1);
	    expr = t;
	  }

	break;
      }

    case NON_LVALUE_EXPR:
    case NOP_EXPR:
      /* These have already decayed to rvalue.  */
      break;

    case CALL_EXPR:   /* We have a special meaning for volatile void fn().  */
      break;

    case INDIRECT_REF:
      {
	tree type = TREE_TYPE (expr);
	int is_reference = TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0)))
			   == REFERENCE_TYPE;
	int is_volatile = TYPE_VOLATILE (type);
	int is_complete = COMPLETE_TYPE_P (complete_type (type));

	/* Can't load the value if we don't know the type.  */
	if (is_volatile && !is_complete)
          {
            if (complain & tf_warning)
	      switch (implicit)
		{
	      	  case ICV_CAST:
		    warning (0, "conversion to void will not access "
				"object of incomplete type %qT", type);
		    break;
		  case ICV_SECOND_OF_COND:
		    warning (0, "indirection will not access object of "
				"incomplete type %qT in second operand "
				"of conditional expression", type);
		    break;
		  case ICV_THIRD_OF_COND:
		    warning (0, "indirection will not access object of "
				"incomplete type %qT in third operand "
				"of conditional expression", type);
		    break;
		  case ICV_RIGHT_OF_COMMA:
		    warning (0, "indirection will not access object of "
				"incomplete type %qT in right operand of "
				"comma operator", type);
		    break;
		  case ICV_LEFT_OF_COMMA:
		    warning (0, "indirection will not access object of "
				"incomplete type %qT in left operand of "
				"comma operator", type);
		    break;
		  case ICV_STATEMENT:
		    warning (0, "indirection will not access object of "
				"incomplete type %qT in statement", type);
		     break;
		  case ICV_THIRD_IN_FOR:
		    warning (0, "indirection will not access object of "
				"incomplete type %qT in for increment "
				"expression", type);
		    break;
		  default:
		    gcc_unreachable ();
		}
          }
	/* Don't load the value if this is an implicit dereference, or if
	   the type needs to be handled by ctors/dtors.  */
	else if (is_volatile && is_reference)
          {
            if (complain & tf_warning)
	      switch (implicit)
		{
	      	  case ICV_CAST:
		    warning (0, "conversion to void will not access "
				"object of type %qT", type);
		    break;
		  case ICV_SECOND_OF_COND:
		    warning (0, "implicit dereference will not access object "
				"of type %qT in second operand of "
				"conditional expression", type);
		    break;
		  case ICV_THIRD_OF_COND:
		    warning (0, "implicit dereference will not access object "
		  	      	"of type %qT in third operand of "
				"conditional expression", type);
		    break;
		  case ICV_RIGHT_OF_COMMA:
		    warning (0, "implicit dereference will not access object "
		    		"of type %qT in right operand of "
				"comma operator", type);
		    break;
		  case ICV_LEFT_OF_COMMA:
		    warning (0, "implicit dereference will not access object "
		    		"of type %qT in left operand of comma operator",
			     type);
		    break;
		  case ICV_STATEMENT:
		    warning (0, "implicit dereference will not access object "
		     		"of type %qT in statement",  type);
		     break;
		  case ICV_THIRD_IN_FOR:
		    warning (0, "implicit dereference will not access object "
		    		"of type %qT in for increment expression",
			     type);
		    break;
		  default:
		    gcc_unreachable ();
		}
          }
	else if (is_volatile && TREE_ADDRESSABLE (type))
	  {
	    if (complain & tf_warning)
	      switch (implicit)
		{
	      	  case ICV_CAST:
		    warning (0, "conversion to void will not access "
				"object of non-trivially-copyable type %qT",
			     type);
		    break;
		  case ICV_SECOND_OF_COND:
		    warning (0, "indirection will not access object of "
				"non-trivially-copyable type %qT in second "
				"operand of conditional expression", type);
		    break;
		  case ICV_THIRD_OF_COND:
		    warning (0, "indirection will not access object of "
		  	      	"non-trivially-copyable type %qT in third "
				"operand of conditional expression", type);
		    break;
		  case ICV_RIGHT_OF_COMMA:
		    warning (0, "indirection will not access object of "
		    		"non-trivially-copyable type %qT in right "
				"operand of comma operator", type);
		    break;
		  case ICV_LEFT_OF_COMMA:
		    warning (0, "indirection will not access object of "
		    		"non-trivially-copyable type %qT in left "
				"operand of comma operator", type);
		    break;
		  case ICV_STATEMENT:
		    warning (0, "indirection will not access object of "
		     		"non-trivially-copyable type %qT in statement",
			      type);
		     break;
		  case ICV_THIRD_IN_FOR:
		    warning (0, "indirection will not access object of "
		    		"non-trivially-copyable type %qT in for "
				"increment expression", type);
		    break;
		  default:
		    gcc_unreachable ();
		}
	  }
	if (is_reference || !is_volatile || !is_complete || TREE_ADDRESSABLE (type))
          {
            /* Emit a warning (if enabled) when the "effect-less" INDIRECT_REF
               operation is stripped off. Note that we don't warn about
               - an expression with TREE_NO_WARNING set. (For an example of
                 such expressions, see build_over_call in call.c.)
               - automatic dereferencing of references, since the user cannot
                 control it. (See also warn_if_unused_value() in stmt.c.)  */
            if (warn_unused_value
		&& implicit != ICV_CAST
                && (complain & tf_warning)
                && !TREE_NO_WARNING (expr)
                && !is_reference)
              warning (OPT_Wunused_value, "value computed is not used");
            expr = TREE_OPERAND (expr, 0);
          }

	break;
      }

    case VAR_DECL:
      {
	/* External variables might be incomplete.  */
	tree type = TREE_TYPE (expr);
	int is_complete = COMPLETE_TYPE_P (complete_type (type));

	if (TYPE_VOLATILE (type) && !is_complete && (complain & tf_warning))
	  switch (implicit)
	    {
	      case ICV_CAST:
		warning (0, "conversion to void will not access "
			    "object %qE of incomplete type %qT", expr, type);
		break;
	      case ICV_SECOND_OF_COND:
	        warning (0, "variable %qE of incomplete type %qT will not "
			    "be accessed in second operand of "
			    "conditional expression", expr, type);
		break;
	      case ICV_THIRD_OF_COND:
	        warning (0, "variable %qE of incomplete type %qT will not "
			    "be accessed in third operand of "
			    "conditional expression", expr, type);
		break;
	      case ICV_RIGHT_OF_COMMA:
	        warning (0, "variable %qE of incomplete type %qT will not "
			    "be accessed in right operand of comma operator",
			 expr, type);
		break;
	      case ICV_LEFT_OF_COMMA:
	        warning (0, "variable %qE of incomplete type %qT will not "
			    "be accessed in left operand of comma operator",
			 expr, type);
		break;
	      case ICV_STATEMENT:
	        warning (0, "variable %qE of incomplete type %qT will not "
		            "be accessed in statement", expr, type);
		break;
	      case ICV_THIRD_IN_FOR:
	        warning (0, "variable %qE of incomplete type %qT will not "
			    "be accessed in for increment expression",
		         expr, type);
		break;
	      default:
	        gcc_unreachable ();
	    }

	break;
      }

    case TARGET_EXPR:
      /* Don't bother with the temporary object returned from a function if
	 we don't use it and don't need to destroy it.  We'll still
	 allocate space for it in expand_call or declare_return_variable,
	 but we don't need to track it through all the tree phases.  */
      if (TARGET_EXPR_IMPLICIT_P (expr)
	  && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (expr)))
	{
	  tree init = TARGET_EXPR_INITIAL (expr);
	  if (TREE_CODE (init) == AGGR_INIT_EXPR
	      && !AGGR_INIT_VIA_CTOR_P (init))
	    {
	      tree fn = AGGR_INIT_EXPR_FN (init);
	      expr = build_call_array_loc (input_location,
					   TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
					   fn,
					   aggr_init_expr_nargs (init),
					   AGGR_INIT_EXPR_ARGP (init));
	    }
	}
      break;

    default:;
    }
  expr = resolve_nondeduced_context (expr);
  {
    tree probe = expr;

    if (TREE_CODE (probe) == ADDR_EXPR)
      probe = TREE_OPERAND (expr, 0);
    if (type_unknown_p (probe))
      {
	/* [over.over] enumerates the places where we can take the address
	   of an overloaded function, and this is not one of them.  */
	if (complain & tf_error)
	  switch (implicit)
	    {
	      case ICV_CAST:
		error ("conversion to void "
		       "cannot resolve address of overloaded function");
		break;
	      case ICV_SECOND_OF_COND:
		error ("second operand of conditional expression "
		       "cannot resolve address of overloaded function");
		break;
	      case ICV_THIRD_OF_COND:
		error ("third operand of conditional expression "
		       "cannot resolve address of overloaded function");
		break;
	      case ICV_RIGHT_OF_COMMA:
		error ("right operand of comma operator "
		       "cannot resolve address of overloaded function");
		break;
	      case ICV_LEFT_OF_COMMA:
		error ("left operand of comma operator "
		       "cannot resolve address of overloaded function");
		break;
	      case ICV_STATEMENT:
		error ("statement "
		       "cannot resolve address of overloaded function");
		break;
	      case ICV_THIRD_IN_FOR:
		error ("for increment expression "
		       "cannot resolve address of overloaded function");
		break;
	    }
	else
	  return error_mark_node;
	expr = void_zero_node;
      }
    else if (implicit != ICV_CAST && probe == expr && is_overloaded_fn (probe))
      {
	/* Only warn when there is no &.  */
	if (complain & tf_warning)
	  switch (implicit)
	    {
	      case ICV_SECOND_OF_COND:
	        warning (OPT_Waddress,
			 "second operand of conditional expression "
			 "is a reference, not call, to function %qE", expr);
		break;
	      case ICV_THIRD_OF_COND:
	        warning (OPT_Waddress,
			 "third operand of conditional expression "
			 "is a reference, not call, to function %qE", expr);
		break;
	      case ICV_RIGHT_OF_COMMA:
	        warning (OPT_Waddress,
			 "right operand of comma operator "
			 "is a reference, not call, to function %qE", expr);
		break;
	      case ICV_LEFT_OF_COMMA:
	        warning (OPT_Waddress,
			 "left operand of comma operator "
			 "is a reference, not call, to function %qE", expr);
		break;
	      case ICV_STATEMENT:
	        warning (OPT_Waddress,
			 "statement is a reference, not call, to function %qE",
			 expr);
		break;
	      case ICV_THIRD_IN_FOR:
	        warning (OPT_Waddress,
			 "for increment expression "
			 "is a reference, not call, to function %qE", expr);
		break;
	      default:
	        gcc_unreachable ();
	    }

	if (TREE_CODE (expr) == COMPONENT_REF)
	  expr = TREE_OPERAND (expr, 0);
      }
  }

  if (expr != error_mark_node && !VOID_TYPE_P (TREE_TYPE (expr)))
    {
      if (implicit != ICV_CAST
	  && warn_unused_value
	  && !TREE_NO_WARNING (expr)
	  && !processing_template_decl)
	{
	  /* The middle end does not warn about expressions that have
	     been explicitly cast to void, so we must do so here.  */
	  if (!TREE_SIDE_EFFECTS (expr)) {
            if (complain & tf_warning)
	      switch (implicit)
		{
		  case ICV_SECOND_OF_COND:
		    warning (OPT_Wunused_value,
			     "second operand of conditional expression has no effect");
		    break;
		  case ICV_THIRD_OF_COND:
		    warning (OPT_Wunused_value,
		    	     "third operand of conditional expression has no effect");
		    break;
		  case ICV_RIGHT_OF_COMMA:
		    warning (OPT_Wunused_value,
		    	     "right operand of comma operator has no effect");
		    break;
		  case ICV_LEFT_OF_COMMA:
		    warning (OPT_Wunused_value,
		    	     "left operand of comma operator has no effect");
		    break;
		  case ICV_STATEMENT:
		    warning (OPT_Wunused_value,
		    	     "statement has no effect");
		    break;
		  case ICV_THIRD_IN_FOR:
		    warning (OPT_Wunused_value,
		    	     "for increment expression has no effect");
		    break;
		  default:
		    gcc_unreachable ();
		}
          }
	  else
	    {
	      tree e;
	      enum tree_code code;
	      enum tree_code_class tclass;

	      e = expr;
	      /* We might like to warn about (say) "(int) f()", as the
		 cast has no effect, but the compiler itself will
		 generate implicit conversions under some
		 circumstances.  (For example a block copy will be
		 turned into a call to "__builtin_memcpy", with a
		 conversion of the return value to an appropriate
		 type.)  So, to avoid false positives, we strip
		 conversions.  Do not use STRIP_NOPs because it will
		 not strip conversions to "void", as that is not a
		 mode-preserving conversion.  */
	      while (TREE_CODE (e) == NOP_EXPR)
		e = TREE_OPERAND (e, 0);

	      code = TREE_CODE (e);
	      tclass = TREE_CODE_CLASS (code);
	      if ((tclass == tcc_comparison
		   || tclass == tcc_unary
		   || (tclass == tcc_binary
		       && !(code == MODIFY_EXPR
			    || code == INIT_EXPR
			    || code == PREDECREMENT_EXPR
			    || code == PREINCREMENT_EXPR
			    || code == POSTDECREMENT_EXPR
			    || code == POSTINCREMENT_EXPR)))
                  && (complain & tf_warning))
		warning (OPT_Wunused_value, "value computed is not used");
	    }
	}
      expr = build1 (CONVERT_EXPR, void_type_node, expr);
    }
  if (! TREE_SIDE_EFFECTS (expr))
    expr = void_zero_node;
  return expr;
}