예제 #1
0
파일: ipa-devirt.c 프로젝트: Nodplus/gcc
static void
record_target_from_binfo (vec <cgraph_node *> &nodes,
			  tree binfo,
			  tree otr_type,
			  tree type_binfo,
			  HOST_WIDE_INT otr_token,
			  tree outer_type,
			  HOST_WIDE_INT offset,
			  pointer_set_t *inserted,
			  pointer_set_t *matched_vtables,
			  bool anonymous)
{
  tree type = BINFO_TYPE (binfo);
  int i;
  tree base_binfo;

  gcc_checking_assert (BINFO_VTABLE (type_binfo));

  if (types_same_for_odr (type, outer_type))
    {
      tree inner_binfo = get_binfo_at_offset (type_binfo,
					      offset, otr_type);
      /* For types in anonymous namespace first check if the respective vtable
	 is alive. If not, we know the type can't be called.  */
      if (!flag_ltrans && anonymous)
	{
	  tree vtable = BINFO_VTABLE (inner_binfo);
	  struct varpool_node *vnode;

	  if (TREE_CODE (vtable) == POINTER_PLUS_EXPR)
	    vtable = TREE_OPERAND (TREE_OPERAND (vtable, 0), 0);
	  vnode = varpool_get_node (vtable);
	  if (!vnode || !vnode->definition)
	    return;
	}
      gcc_assert (inner_binfo);
      if (!pointer_set_insert (matched_vtables, BINFO_VTABLE (inner_binfo)))
	{
	  tree target = gimple_get_virt_method_for_binfo (otr_token, inner_binfo);
	  if (target)
	    maybe_record_node (nodes, target, inserted, NULL);
	}
      return;
    }

  /* Walk bases.  */
  for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
    /* Walking bases that have no virtual method is pointless excercise.  */
    if (polymorphic_type_binfo_p (base_binfo))
      record_target_from_binfo (nodes, base_binfo, otr_type,
				/* In the case of single inheritance,
				   the virtual table is shared with
				   the outer type.  */
				BINFO_VTABLE (base_binfo) ? base_binfo : type_binfo,
				otr_token, outer_type, offset, inserted,
				matched_vtables, anonymous);
}
예제 #2
0
파일: varpool.c 프로젝트: palves/gcc
/* Return varpool node assigned to DECL.  Create new one when needed.  */
varpool_node *
varpool_node_for_decl (tree decl)
{
  varpool_node *node = varpool_get_node (decl);
  gcc_checking_assert (TREE_CODE (decl) == VAR_DECL);
  if (node)
    return node;

  node = varpool_create_empty_node ();
  node->decl = decl;
  symtab_register_node (node);
  return node;
}
예제 #3
0
/* Return varpool node assigned to DECL.  Create new one when needed.  */
struct varpool_node *
varpool_node (tree decl)
{
  struct varpool_node *node = varpool_get_node (decl);
  gcc_assert (TREE_CODE (decl) == VAR_DECL
	      && (TREE_STATIC (decl) || DECL_EXTERNAL (decl) || in_lto_p));
  if (node)
    return node;

  node = ggc_alloc_cleared_varpool_node ();
  node->symbol.type = SYMTAB_VARIABLE;
  node->symbol.decl = decl;
  symtab_register_node ((symtab_node)node);
  return node;
}
예제 #4
0
파일: varpool.c 프로젝트: palves/gcc
void
varpool_analyze_node (varpool_node *node)
{
  tree decl = node->decl;

  /* When reading back varpool at LTO time, we re-construct the queue in order
     to have "needed" list right by inserting all needed nodes into varpool.
     We however don't want to re-analyze already analyzed nodes.  */
  if (!node->analyzed)
    {
      gcc_assert (!in_lto_p || cgraph_function_flags_ready);
      /* Compute the alignment early so function body expanders are
	 already informed about increased alignment.  */
      align_variable (decl, 0);
    }
  if (node->alias)
    symtab_resolve_alias
       (node, varpool_get_node (node->alias_target));
  else if (DECL_INITIAL (decl))
    record_references_in_initializer (decl, node->analyzed);
  node->analyzed = true;
}
예제 #5
0
파일: varpool.c 프로젝트: palves/gcc
tree
ctor_for_folding (tree decl)
{
  varpool_node *node, *real_node;
  tree real_decl;

  if (TREE_CODE (decl) != VAR_DECL
      && TREE_CODE (decl) != CONST_DECL)
    return error_mark_node;

  if (TREE_CODE (decl) == CONST_DECL
      || DECL_IN_CONSTANT_POOL (decl))
    return DECL_INITIAL (decl);

  if (TREE_THIS_VOLATILE (decl))
    return error_mark_node;

  /* Do not care about automatic variables.  Those are never initialized
     anyway, because gimplifier exapnds the code.  */
  if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
    {
      gcc_assert (!TREE_PUBLIC (decl));
      return error_mark_node;
    }

  gcc_assert (TREE_CODE (decl) == VAR_DECL);

  node = varpool_get_node (decl);
  if (node)
    {
      real_node = varpool_variable_node (node);
      real_decl = real_node->decl;
    }
  else
    real_decl = decl;

  /* See if we are dealing with alias.
     In most cases alias is just alternative symbol pointing to a given
     constructor.  This allows us to use interposition rules of DECL
     constructor of REAL_NODE.  However weakrefs are special by being just
     alternative name of their target (if defined).  */
  if (decl != real_decl)
    {
      gcc_assert (!DECL_INITIAL (decl)
		  || DECL_INITIAL (decl) == error_mark_node);
      if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
	{
	  node = varpool_alias_target (node);
	  decl = node->decl;
	}
    }

  /* Vtables are defined by their types and must match no matter of interposition
     rules.  */
  if (DECL_VIRTUAL_P (real_decl))
    {
      gcc_checking_assert (TREE_READONLY (real_decl));
      return DECL_INITIAL (real_decl);
    }

  /* If there is no constructor, we have nothing to do.  */
  if (DECL_INITIAL (real_decl) == error_mark_node)
    return error_mark_node;

  /* Non-readonly alias of readonly variable is also de-facto readonly,
     because the variable itself is in readonly section.  
     We also honnor READONLY flag on alias assuming that user knows
     what he is doing.  */
  if (!TREE_READONLY (decl) && !TREE_READONLY (real_decl))
    return error_mark_node;

  /* Variables declared 'const' without an initializer
     have zero as the initializer if they may not be
     overridden at link or run time.  */
  if (!DECL_INITIAL (real_decl)
      && (DECL_EXTERNAL (decl) || decl_replaceable_p (decl)))
    return error_mark_node;

  /* Variables declared `const' with an initializer are considered
     to not be overwritable with different initializer by default. 

     ??? Previously we behaved so for scalar variables but not for array
     accesses.  */
  return DECL_INITIAL (real_decl);
}
예제 #6
0
파일: ubsan.c 프로젝트: acoxepochlabs/gcc
tree
ubsan_type_descriptor (tree type, enum ubsan_print_style pstyle)
{
  /* See through any typedefs.  */
  type = TYPE_MAIN_VARIANT (type);

  tree decl = decl_for_type_lookup (type);
  /* It is possible that some of the earlier created DECLs were found
     unused, in that case they weren't emitted and varpool_get_node
     returns NULL node on them.  But now we really need them.  Thus,
     renew them here.  */
  if (decl != NULL_TREE && varpool_get_node (decl))
    return build_fold_addr_expr (decl);

  tree dtype = ubsan_type_descriptor_type ();
  tree type2 = type;
  const char *tname = NULL;
  char *pretty_name;
  unsigned char deref_depth = 0;
  unsigned short tkind, tinfo;

  /* Get the name of the type, or the name of the pointer type.  */
  if (pstyle == UBSAN_PRINT_POINTER)
    {
      gcc_assert (POINTER_TYPE_P (type));
      type2 = TREE_TYPE (type);

      /* Remove any '*' operators from TYPE.  */
      while (POINTER_TYPE_P (type2))
        deref_depth++, type2 = TREE_TYPE (type2);

      if (TREE_CODE (type2) == METHOD_TYPE)
        type2 = TYPE_METHOD_BASETYPE (type2);
    }

  /* If an array, get its type.  */
  type2 = strip_array_types (type2);

  if (pstyle == UBSAN_PRINT_ARRAY)
    {
      while (POINTER_TYPE_P (type2))
        deref_depth++, type2 = TREE_TYPE (type2);
    }

  if (TYPE_NAME (type2) != NULL)
    {
      if (TREE_CODE (TYPE_NAME (type2)) == IDENTIFIER_NODE)
	tname = IDENTIFIER_POINTER (TYPE_NAME (type2));
      else if (DECL_NAME (TYPE_NAME (type2)) != NULL)
	tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type2)));
    }

  if (tname == NULL)
    /* We weren't able to determine the type name.  */
    tname = "<unknown>";

  /* Decorate the type name with '', '*', "struct", or "union".  */
  pretty_name = (char *) alloca (strlen (tname) + 16 + deref_depth);
  if (pstyle == UBSAN_PRINT_POINTER)
    {
      int pos = sprintf (pretty_name, "'%s%s%s%s%s%s%s",
			 TYPE_VOLATILE (type2) ? "volatile " : "",
			 TYPE_READONLY (type2) ? "const " : "",
			 TYPE_RESTRICT (type2) ? "restrict " : "",
			 TYPE_ATOMIC (type2) ? "_Atomic " : "",
			 TREE_CODE (type2) == RECORD_TYPE
			 ? "struct "
			 : TREE_CODE (type2) == UNION_TYPE
			   ? "union " : "", tname,
			 deref_depth == 0 ? "" : " ");
      while (deref_depth-- > 0)
        pretty_name[pos++] = '*';
      pretty_name[pos++] = '\'';
      pretty_name[pos] = '\0';
    }
  else if (pstyle == UBSAN_PRINT_ARRAY)
    {
      /* Pretty print the array dimensions.  */
      gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
      tree t = type;
      int pos = sprintf (pretty_name, "'%s ", tname);
      while (deref_depth-- > 0)
        pretty_name[pos++] = '*';
      while (TREE_CODE (t) == ARRAY_TYPE)
	{
	  pretty_name[pos++] = '[';
	  tree dom = TYPE_DOMAIN (t);
	  if (dom && TREE_CODE (TYPE_MAX_VALUE (dom)) == INTEGER_CST)
	    pos += sprintf (&pretty_name[pos], HOST_WIDE_INT_PRINT_DEC,
			    tree_to_shwi (TYPE_MAX_VALUE (dom)) + 1);
	  else
	    /* ??? We can't determine the variable name; print VLA unspec.  */
	    pretty_name[pos++] = '*';
	  pretty_name[pos++] = ']';
	  t = TREE_TYPE (t);
	}
      pretty_name[pos++] = '\'';
      pretty_name[pos] = '\0';

     /* Save the tree with stripped types.  */
     type = t;
    }
  else
    sprintf (pretty_name, "'%s'", tname);

  switch (TREE_CODE (type))
    {
    case BOOLEAN_TYPE:
    case ENUMERAL_TYPE:
    case INTEGER_TYPE:
      tkind = 0x0000;
      break;
    case REAL_TYPE:
      /* FIXME: libubsan right now only supports float, double and
	 long double type formats.  */
      if (TYPE_MODE (type) == TYPE_MODE (float_type_node)
	  || TYPE_MODE (type) == TYPE_MODE (double_type_node)
	  || TYPE_MODE (type) == TYPE_MODE (long_double_type_node))
	tkind = 0x0001;
      else
	tkind = 0xffff;
      break;
    default:
      tkind = 0xffff;
      break;
    }
  tinfo = get_ubsan_type_info_for_type (type);

  /* Create a new VAR_DECL of type descriptor.  */
  char tmp_name[32];
  static unsigned int type_var_id_num;
  ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_type", type_var_id_num++);
  decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
			  dtype);
  TREE_STATIC (decl) = 1;
  TREE_PUBLIC (decl) = 0;
  DECL_ARTIFICIAL (decl) = 1;
  DECL_IGNORED_P (decl) = 1;
  DECL_EXTERNAL (decl) = 0;

  size_t len = strlen (pretty_name);
  tree str = build_string (len + 1, pretty_name);
  TREE_TYPE (str) = build_array_type (char_type_node,
				      build_index_type (size_int (len)));
  TREE_READONLY (str) = 1;
  TREE_STATIC (str) = 1;
  tree ctor = build_constructor_va (dtype, 3, NULL_TREE,
				    build_int_cst (short_unsigned_type_node,
						   tkind), NULL_TREE,
				    build_int_cst (short_unsigned_type_node,
						   tinfo), NULL_TREE, str);
  TREE_CONSTANT (ctor) = 1;
  TREE_STATIC (ctor) = 1;
  DECL_INITIAL (decl) = ctor;
  varpool_finalize_decl (decl);

  /* Save the VAR_DECL into the hash table.  */
  decl_for_type_insert (type, decl);

  return build_fold_addr_expr (decl);
}
예제 #7
0
static void
lto_symtab_resolve_symbols (void **slot)
{
  lto_symtab_entry_t e;
  lto_symtab_entry_t prevailing = NULL;

  /* Always set e->node so that edges are updated to reflect decl merging. */
  for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
    {
      if (TREE_CODE (e->decl) == FUNCTION_DECL)
	e->node = cgraph_get_node (e->decl);
      else if (TREE_CODE (e->decl) == VAR_DECL)
	e->vnode = varpool_get_node (e->decl);
      if (e->resolution == LDPR_PREVAILING_DEF_IRONLY
	  || e->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP
	  || e->resolution == LDPR_PREVAILING_DEF)
	prevailing = e;
    }

  /* If the chain is already resolved there is nothing else to do.  */
  if (prevailing)
    return;

  /* Find the single non-replaceable prevailing symbol and
     diagnose ODR violations.  */
  for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
    {
      if (!lto_symtab_resolve_can_prevail_p (e))
	{
	  e->resolution = LDPR_RESOLVED_IR;
          e->guessed = true;
	  continue;
	}

      /* Set a default resolution - the final prevailing one will get
         adjusted later.  */
      e->resolution = LDPR_PREEMPTED_IR;
      e->guessed = true;
      if (!lto_symtab_resolve_replaceable_p (e))
	{
	  if (prevailing)
	    {
	      error_at (DECL_SOURCE_LOCATION (e->decl),
			"%qD has already been defined", e->decl);
	      inform (DECL_SOURCE_LOCATION (prevailing->decl),
		      "previously defined here");
	    }
	  prevailing = e;
	}
    }
  if (prevailing)
    goto found;

  /* Do a second round choosing one from the replaceable prevailing decls.  */
  for (e = (lto_symtab_entry_t) *slot; e; e = e->next)
    {
      if (e->resolution != LDPR_PREEMPTED_IR)
	continue;

      /* Choose the first function that can prevail as prevailing.  */
      if (TREE_CODE (e->decl) == FUNCTION_DECL)
	{
	  prevailing = e;
	  break;
	}

      /* From variables that can prevail choose the largest one.  */
      if (!prevailing
	  || tree_int_cst_lt (DECL_SIZE (prevailing->decl),
			      DECL_SIZE (e->decl)))
	prevailing = e;
    }

  if (!prevailing)
    return;

found:
  /* If current lto files represent the whole program,
    it is correct to use LDPR_PREVALING_DEF_IRONLY.
    If current lto files are part of whole program, internal
    resolver doesn't know if it is LDPR_PREVAILING_DEF
    or LDPR_PREVAILING_DEF_IRONLY.  Use IRONLY conforms to
    using -fwhole-program.  Otherwise, it doesn't
    matter using either LDPR_PREVAILING_DEF or
    LDPR_PREVAILING_DEF_IRONLY
    
    FIXME: above workaround due to gold plugin makes some
    variables IRONLY, which are indeed PREVAILING_DEF in
    resolution file.  These variables still need manual
    externally_visible attribute.  */
    prevailing->resolution = LDPR_PREVAILING_DEF_IRONLY;
    prevailing->guessed = true;
}
예제 #8
0
tree
ubsan_type_descriptor (tree type, bool want_pointer_type_p)
{
  /* See through any typedefs.  */
  type = TYPE_MAIN_VARIANT (type);

  tree decl = decl_for_type_lookup (type);
  /* It is possible that some of the earlier created DECLs were found
     unused, in that case they weren't emitted and varpool_get_node
     returns NULL node on them.  But now we really need them.  Thus,
     renew them here.  */
  if (decl != NULL_TREE && varpool_get_node (decl))
    return build_fold_addr_expr (decl);

  tree dtype = ubsan_type_descriptor_type ();
  tree type2 = type;
  const char *tname = NULL;
  char *pretty_name;
  unsigned char deref_depth = 0;
  unsigned short tkind, tinfo;

  /* Get the name of the type, or the name of the pointer type.  */
  if (want_pointer_type_p)
    {
      gcc_assert (POINTER_TYPE_P (type));
      type2 = TREE_TYPE (type);

      /* Remove any '*' operators from TYPE.  */
      while (POINTER_TYPE_P (type2))
        deref_depth++, type2 = TREE_TYPE (type2);

      if (TREE_CODE (type2) == METHOD_TYPE)
        type2 = TYPE_METHOD_BASETYPE (type2);
    }

  if (TYPE_NAME (type2) != NULL)
    {
      if (TREE_CODE (TYPE_NAME (type2)) == IDENTIFIER_NODE)
	tname = IDENTIFIER_POINTER (TYPE_NAME (type2));
      else
	tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type2)));
    }

  if (tname == NULL)
    /* We weren't able to determine the type name.  */
    tname = "<unknown>";

  /* Decorate the type name with '', '*', "struct", or "union".  */
  pretty_name = (char *) alloca (strlen (tname) + 16 + deref_depth);
  if (want_pointer_type_p)
    {
      int pos = sprintf (pretty_name, "'%s%s%s%s%s%s%s",
			 TYPE_VOLATILE (type2) ? "volatile " : "",
			 TYPE_READONLY (type2) ? "const " : "",
			 TYPE_RESTRICT (type2) ? "restrict " : "",
			 TYPE_ATOMIC (type2) ? "_Atomic " : "",
			 TREE_CODE (type2) == RECORD_TYPE
			 ? "struct "
			 : TREE_CODE (type2) == UNION_TYPE
			   ? "union " : "", tname,
			 deref_depth == 0 ? "" : " ");
      while (deref_depth-- > 0)
        pretty_name[pos++] = '*';
      pretty_name[pos++] = '\'';
      pretty_name[pos] = '\0';
    }
  else
    sprintf (pretty_name, "'%s'", tname);

  switch (TREE_CODE (type))
    {
    case INTEGER_TYPE:
      tkind = 0x0000;
      break;
    case REAL_TYPE:
      tkind = 0x0001;
      break;
    default:
      tkind = 0xffff;
      break;
    }
  tinfo = get_ubsan_type_info_for_type (type);

  /* Create a new VAR_DECL of type descriptor.  */
  char tmp_name[32];
  static unsigned int type_var_id_num;
  ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_type", type_var_id_num++);
  decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
			  dtype);
  TREE_STATIC (decl) = 1;
  TREE_PUBLIC (decl) = 0;
  DECL_ARTIFICIAL (decl) = 1;
  DECL_IGNORED_P (decl) = 1;
  DECL_EXTERNAL (decl) = 0;

  size_t len = strlen (pretty_name);
  tree str = build_string (len + 1, pretty_name);
  TREE_TYPE (str) = build_array_type (char_type_node,
				      build_index_type (size_int (len)));
  TREE_READONLY (str) = 1;
  TREE_STATIC (str) = 1;
  tree ctor = build_constructor_va (dtype, 3, NULL_TREE,
				    build_int_cst (short_unsigned_type_node,
						   tkind), NULL_TREE,
				    build_int_cst (short_unsigned_type_node,
						   tinfo), NULL_TREE, str);
  TREE_CONSTANT (ctor) = 1;
  TREE_STATIC (ctor) = 1;
  DECL_INITIAL (decl) = ctor;
  rest_of_decl_compilation (decl, 1, 0);

  /* Save the VAR_DECL into the hash table.  */
  decl_for_type_insert (type, decl);

  return build_fold_addr_expr (decl);
}