/* Language-independent node constructors for parse phase of GNU compiler.
- Copyright (C) 1987-2018 Free Software Foundation, Inc.
+ Copyright (C) 1987-2019 Free Software Foundation, Inc.
This file is part of GCC.
static void print_debug_expr_statistics (void);
static void print_value_expr_statistics (void);
+static tree build_array_type_1 (tree, tree, bool, bool);
+
tree global_trees[TI_MAX];
tree integer_types[itk_none];
1, /* OMP_CLAUSE_FIRSTPRIVATE */
2, /* OMP_CLAUSE_LASTPRIVATE */
5, /* OMP_CLAUSE_REDUCTION */
+ 5, /* OMP_CLAUSE_TASK_REDUCTION */
+ 5, /* OMP_CLAUSE_IN_REDUCTION */
1, /* OMP_CLAUSE_COPYIN */
1, /* OMP_CLAUSE_COPYPRIVATE */
3, /* OMP_CLAUSE_LINEAR */
2, /* OMP_CLAUSE_ALIGNED */
1, /* OMP_CLAUSE_DEPEND */
+ 1, /* OMP_CLAUSE_NONTEMPORAL */
1, /* OMP_CLAUSE_UNIFORM */
1, /* OMP_CLAUSE_TO_DECLARE */
1, /* OMP_CLAUSE_LINK */
0, /* OMP_CLAUSE_AUTO */
0, /* OMP_CLAUSE_SEQ */
1, /* OMP_CLAUSE__LOOPTEMP_ */
+ 1, /* OMP_CLAUSE__REDUCTEMP_ */
1, /* OMP_CLAUSE_IF */
1, /* OMP_CLAUSE_NUM_THREADS */
1, /* OMP_CLAUSE_SCHEDULE */
1, /* OMP_CLAUSE_VECTOR_LENGTH */
3, /* OMP_CLAUSE_TILE */
2, /* OMP_CLAUSE__GRIDDIM_ */
+ 0, /* OMP_CLAUSE_IF_PRESENT */
+ 0, /* OMP_CLAUSE_FINALIZE */
};
const char * const omp_clause_code_name[] =
"firstprivate",
"lastprivate",
"reduction",
+ "task_reduction",
+ "in_reduction",
"copyin",
"copyprivate",
"linear",
"aligned",
"depend",
+ "nontemporal",
"uniform",
"to",
"link",
"auto",
"seq",
"_looptemp_",
+ "_reductemp_",
"if",
"num_threads",
"schedule",
"num_workers",
"vector_length",
"tile",
- "_griddim_"
+ "_griddim_",
+ "if_present",
+ "finalize",
};
case UNION_TYPE:
case QUAL_UNION_TYPE:
case VOID_TYPE:
- case POINTER_BOUNDS_TYPE:
case FUNCTION_TYPE:
case METHOD_TYPE:
case LANG_TYPE: return sizeof (tree_type_non_common);
}
}
-/* Record interesting allocation statistics for a tree node with CODE
- and LENGTH. */
+/* Return tree node kind based on tree CODE. */
-static void
-record_node_allocation_statistics (enum tree_code code ATTRIBUTE_UNUSED,
- size_t length ATTRIBUTE_UNUSED)
+static tree_node_kind
+get_stats_node_kind (enum tree_code code)
{
enum tree_code_class type = TREE_CODE_CLASS (code);
- tree_node_kind kind;
-
- if (!GATHER_STATISTICS)
- return;
switch (type)
{
case tcc_declaration: /* A decl node */
- kind = d_kind;
- break;
-
+ return d_kind;
case tcc_type: /* a type node */
- kind = t_kind;
- break;
-
+ return t_kind;
case tcc_statement: /* an expression with side effects */
- kind = s_kind;
- break;
-
+ return s_kind;
case tcc_reference: /* a reference */
- kind = r_kind;
- break;
-
+ return r_kind;
case tcc_expression: /* an expression */
case tcc_comparison: /* a comparison expression */
case tcc_unary: /* a unary arithmetic expression */
case tcc_binary: /* a binary arithmetic expression */
- kind = e_kind;
- break;
-
+ return e_kind;
case tcc_constant: /* a constant */
- kind = c_kind;
- break;
-
+ return c_kind;
case tcc_exceptional: /* something random, like an identifier. */
switch (code)
{
case IDENTIFIER_NODE:
- kind = id_kind;
- break;
-
+ return id_kind;
case TREE_VEC:
- kind = vec_kind;
- break;
-
+ return vec_kind;
case TREE_BINFO:
- kind = binfo_kind;
- break;
-
+ return binfo_kind;
case SSA_NAME:
- kind = ssa_name_kind;
- break;
-
+ return ssa_name_kind;
case BLOCK:
- kind = b_kind;
- break;
-
+ return b_kind;
case CONSTRUCTOR:
- kind = constr_kind;
- break;
-
+ return constr_kind;
case OMP_CLAUSE:
- kind = omp_clause_kind;
- break;
-
+ return omp_clause_kind;
default:
- kind = x_kind;
- break;
+ return x_kind;
}
break;
-
case tcc_vl_exp:
- kind = e_kind;
- break;
-
+ return e_kind;
default:
gcc_unreachable ();
}
+}
+
+/* Record interesting allocation statistics for a tree node with CODE
+ and LENGTH. */
+
+static void
+record_node_allocation_statistics (enum tree_code code, size_t length)
+{
+ if (!GATHER_STATISTICS)
+ return;
+
+ tree_node_kind kind = get_stats_node_kind (code);
tree_code_counts[(int) code]++;
tree_node_counts[(int) kind]++;
enum tree_code code = TREE_CODE (node);
if (GATHER_STATISTICS)
{
+ enum tree_node_kind kind = get_stats_node_kind (code);
+
+ gcc_checking_assert (tree_code_counts[(int) TREE_CODE (node)] != 0);
+ gcc_checking_assert (tree_node_counts[(int) kind] != 0);
+ gcc_checking_assert (tree_node_sizes[(int) kind] >= tree_size (node));
+
tree_code_counts[(int) TREE_CODE (node)]--;
- tree_node_counts[(int) t_kind]--;
- tree_node_sizes[(int) t_kind] -= tree_size (node);
+ tree_node_counts[(int) kind]--;
+ tree_node_sizes[(int) kind] -= tree_size (node);
}
if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
vec_free (CONSTRUCTOR_ELTS (node));
case POINTER_TYPE:
case REFERENCE_TYPE:
- case POINTER_BOUNDS_TYPE:
/* Cache NULL pointer and zero bounds. */
if (hwi == 0)
{
}
}
+/* If TYPE is not a vector type, just return SC, otherwise return
+ build_vector_from_val (TYPE, SC). */
+
+tree
+build_uniform_cst (tree type, tree sc)
+{
+ if (!VECTOR_TYPE_P (type))
+ return sc;
+
+ return build_vector_from_val (type, sc);
+}
+
/* Build a vector series of type TYPE in which element I has the value
BASE + I * STEP. The result is a constant if BASE and STEP are constant
and a VEC_SERIES_EXPR otherwise. */
return build_constructor (type, v);
}
+/* Return a node of type TYPE for which TREE_CLOBBER_P is true. */
+
+tree
+build_clobber (tree type)
+{
+ tree clobber = build_constructor (type, NULL);
+ TREE_THIS_VOLATILE (clobber) = true;
+ return clobber;
+}
+
/* Return a new FIXED_CST node whose type is TYPE and value is F. */
tree
tree
build_complex (tree type, tree real, tree imag)
{
+ gcc_assert (CONSTANT_CLASS_P (real));
+ gcc_assert (CONSTANT_CLASS_P (imag));
+
tree t = make_node (COMPLEX_CST);
TREE_REALPART (t) = real;
/* Return 1 if EXPR is the constant zero, whether it is integral, float or
fixed, and scalar, complex or vector. */
-int
+bool
zerop (const_tree expr)
{
return (integer_zerop (expr)
}
/* Return 1 if EXPR is the integer constant zero or a complex constant
- of zero. */
+ of zero, or a location wrapper for such a constant. */
-int
+bool
integer_zerop (const_tree expr)
{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
switch (TREE_CODE (expr))
{
case INTEGER_CST:
}
/* Return 1 if EXPR is the integer constant one or the corresponding
- complex constant. */
+ complex constant, or a location wrapper for such a constant. */
-int
+bool
integer_onep (const_tree expr)
{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
switch (TREE_CODE (expr))
{
case INTEGER_CST:
}
/* Return 1 if EXPR is the integer constant one. For complex and vector,
- return 1 if every piece is the integer constant one. */
+ return 1 if every piece is the integer constant one.
+ Also return 1 for location wrappers for such a constant. */
-int
+bool
integer_each_onep (const_tree expr)
{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
if (TREE_CODE (expr) == COMPLEX_CST)
return (integer_onep (TREE_REALPART (expr))
&& integer_onep (TREE_IMAGPART (expr)));
}
/* Return 1 if EXPR is an integer containing all 1's in as much precision as
- it contains, or a complex or vector whose subparts are such integers. */
+ it contains, or a complex or vector whose subparts are such integers,
+ or a location wrapper for such a constant. */
-int
+bool
integer_all_onesp (const_tree expr)
{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
if (TREE_CODE (expr) == COMPLEX_CST
&& integer_all_onesp (TREE_REALPART (expr))
&& integer_all_onesp (TREE_IMAGPART (expr)))
- return 1;
+ return true;
else if (TREE_CODE (expr) == VECTOR_CST)
return (VECTOR_CST_NPATTERNS (expr) == 1
&& integer_all_onesp (VECTOR_CST_ENCODED_ELT (expr, 0)));
else if (TREE_CODE (expr) != INTEGER_CST)
- return 0;
+ return false;
return (wi::max_value (TYPE_PRECISION (TREE_TYPE (expr)), UNSIGNED)
== wi::to_wide (expr));
}
-/* Return 1 if EXPR is the integer constant minus one. */
+/* Return 1 if EXPR is the integer constant minus one, or a location wrapper
+ for such a constant. */
-int
+bool
integer_minus_onep (const_tree expr)
{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
if (TREE_CODE (expr) == COMPLEX_CST)
return (integer_all_onesp (TREE_REALPART (expr))
&& integer_zerop (TREE_IMAGPART (expr)));
}
/* Return 1 if EXPR is an integer constant that is a power of 2 (i.e., has only
- one bit on). */
+ one bit on), or a location wrapper for such a constant. */
-int
+bool
integer_pow2p (const_tree expr)
{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
if (TREE_CODE (expr) == COMPLEX_CST
&& integer_pow2p (TREE_REALPART (expr))
&& integer_zerop (TREE_IMAGPART (expr)))
- return 1;
+ return true;
if (TREE_CODE (expr) != INTEGER_CST)
- return 0;
+ return false;
return wi::popcount (wi::to_wide (expr)) == 1;
}
/* Return 1 if EXPR is an integer constant other than zero or a
- complex constant other than zero. */
+ complex constant other than zero, or a location wrapper for such a
+ constant. */
-int
+bool
integer_nonzerop (const_tree expr)
{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
return ((TREE_CODE (expr) == INTEGER_CST
&& wi::to_wide (expr) != 0)
|| (TREE_CODE (expr) == COMPLEX_CST
/* Return 1 if EXPR is the integer constant one. For vector,
return 1 if every piece is the integer constant minus one
- (representing the value TRUE). */
+ (representing the value TRUE).
+ Also return 1 for location wrappers for such a constant. */
-int
+bool
integer_truep (const_tree expr)
{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
if (TREE_CODE (expr) == VECTOR_CST)
return integer_all_onesp (expr);
return integer_onep (expr);
}
-/* Return 1 if EXPR is the fixed-point constant zero. */
+/* Return 1 if EXPR is the fixed-point constant zero, or a location wrapper
+ for such a constant. */
-int
+bool
fixed_zerop (const_tree expr)
{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
return (TREE_CODE (expr) == FIXED_CST
&& TREE_FIXED_CST (expr).data.is_zero ());
}
}
/* Return 1 if EXPR is the real constant zero. Trailing zeroes matter for
- decimal float constants, so don't return 1 for them. */
+ decimal float constants, so don't return 1 for them.
+ Also return 1 for location wrappers around such a constant. */
-int
+bool
real_zerop (const_tree expr)
{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
switch (TREE_CODE (expr))
{
case REAL_CST:
/* Return 1 if EXPR is the real constant one in real or complex form.
Trailing zeroes matter for decimal float constants, so don't return
- 1 for them. */
+ 1 for them.
+ Also return 1 for location wrappers around such a constant. */
-int
+bool
real_onep (const_tree expr)
{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
switch (TREE_CODE (expr))
{
case REAL_CST:
}
/* Return 1 if EXPR is the real constant minus one. Trailing zeroes
- matter for decimal float constants, so don't return 1 for them. */
+ matter for decimal float constants, so don't return 1 for them.
+ Also return 1 for location wrappers around such a constant. */
-int
+bool
real_minus_onep (const_tree expr)
{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
switch (TREE_CODE (expr))
{
case REAL_CST:
/* Nonzero if EXP is a constant or a cast of a constant. */
-int
+bool
really_constant_p (const_tree exp)
{
/* This is not quite the same as STRIP_NOPS. It does more. */
/* Return nonzero if ELEM is part of the chain CHAIN. */
-int
+bool
chain_member (const_tree elem, const_tree chain)
{
while (chain)
{
if (elem == chain)
- return 1;
+ return true;
chain = DECL_CHAIN (chain);
}
- return 0;
+ return false;
}
/* Return the length of a chain of nodes chained through TREE_CHAIN.
switch (TREE_CODE (type))
{
case VOID_TYPE:
- case POINTER_BOUNDS_TYPE:
case COMPLEX_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
switch (TREE_CODE_CLASS (code))
{
case tcc_exceptional:
+ /* Always wrap STATEMENT_LIST into SAVE_EXPR, even if it doesn't
+ have side-effects. */
+ if (code == STATEMENT_LIST)
+ return save_expr (e);
+ /* FALLTHRU */
case tcc_type:
case tcc_declaration:
case tcc_comparison:
return ret;
}
\f
-/* Create a DECL_... node of code CODE, name NAME and data type TYPE.
+/* Create a DECL_... node of code CODE, name NAME (if non-null)
+ and data type TYPE.
We do NOT enter this node in any sort of symbol table.
LOC is the location of the decl.
if (CAN_HAVE_LOCATION_P (t))
SET_EXPR_LOCATION (t, loc);
}
+
+/* Data used when collecting DECLs and TYPEs for language data removal. */
+
+struct free_lang_data_d
+{
+ free_lang_data_d () : decls (100), types (100) {}
+
+ /* Worklist to avoid excessive recursion. */
+ auto_vec<tree> worklist;
+
+ /* Set of traversed objects. Used to avoid duplicate visits. */
+ hash_set<tree> pset;
+
+ /* Array of symbols to process with free_lang_data_in_decl. */
+ auto_vec<tree> decls;
+
+ /* Array of types to process with free_lang_data_in_type. */
+ auto_vec<tree> types;
+};
+
+
+/* Add type or decl T to one of the list of tree nodes that need their
+ language data removed. The lists are held inside FLD. */
+
+static void
+add_tree_to_fld_list (tree t, struct free_lang_data_d *fld)
+{
+ if (DECL_P (t))
+ fld->decls.safe_push (t);
+ else if (TYPE_P (t))
+ fld->types.safe_push (t);
+ else
+ gcc_unreachable ();
+}
+
+/* Push tree node T into FLD->WORKLIST. */
+
+static inline void
+fld_worklist_push (tree t, struct free_lang_data_d *fld)
+{
+ if (t && !is_lang_specific (t) && !fld->pset.contains (t))
+ fld->worklist.safe_push ((t));
+}
+
+
\f
+/* Return simplified TYPE_NAME of TYPE. */
+
+static tree
+fld_simplified_type_name (tree type)
+{
+ if (!TYPE_NAME (type) || TREE_CODE (TYPE_NAME (type)) != TYPE_DECL)
+ return TYPE_NAME (type);
+ /* Drop TYPE_DECLs in TYPE_NAME in favor of the identifier in the
+ TYPE_DECL if the type doesn't have linkage.
+ this must match fld_ */
+ if (type != TYPE_MAIN_VARIANT (type) || ! type_with_linkage_p (type))
+ return DECL_NAME (TYPE_NAME (type));
+ return TYPE_NAME (type);
+}
+
+/* Do same comparsion as check_qualified_type skipping lang part of type
+ and be more permissive about type names: we only care that names are
+ same (for diagnostics) and that ODR names are the same.
+ If INNER_TYPE is non-NULL, be sure that TREE_TYPE match it. */
+
+static bool
+fld_type_variant_equal_p (tree t, tree v, tree inner_type)
+{
+ if (TYPE_QUALS (t) != TYPE_QUALS (v)
+ /* We want to match incomplete variants with complete types.
+ In this case we need to ignore alignment. */
+ || ((!RECORD_OR_UNION_TYPE_P (t) || COMPLETE_TYPE_P (v))
+ && (TYPE_ALIGN (t) != TYPE_ALIGN (v)
+ || TYPE_USER_ALIGN (t) != TYPE_USER_ALIGN (v)))
+ || fld_simplified_type_name (t) != fld_simplified_type_name (v)
+ || !attribute_list_equal (TYPE_ATTRIBUTES (t),
+ TYPE_ATTRIBUTES (v))
+ || (inner_type && TREE_TYPE (v) != inner_type))
+ return false;
+
+ return true;
+}
+
+/* Find variant of FIRST that match T and create new one if necessary.
+ Set TREE_TYPE to INNER_TYPE if non-NULL. */
+
+static tree
+fld_type_variant (tree first, tree t, struct free_lang_data_d *fld,
+ tree inner_type = NULL)
+{
+ if (first == TYPE_MAIN_VARIANT (t))
+ return t;
+ for (tree v = first; v; v = TYPE_NEXT_VARIANT (v))
+ if (fld_type_variant_equal_p (t, v, inner_type))
+ return v;
+ tree v = build_variant_type_copy (first);
+ TYPE_READONLY (v) = TYPE_READONLY (t);
+ TYPE_VOLATILE (v) = TYPE_VOLATILE (t);
+ TYPE_ATOMIC (v) = TYPE_ATOMIC (t);
+ TYPE_RESTRICT (v) = TYPE_RESTRICT (t);
+ TYPE_ADDR_SPACE (v) = TYPE_ADDR_SPACE (t);
+ TYPE_NAME (v) = TYPE_NAME (t);
+ TYPE_ATTRIBUTES (v) = TYPE_ATTRIBUTES (t);
+ TYPE_CANONICAL (v) = TYPE_CANONICAL (t);
+ /* Variants of incomplete types should have alignment
+ set to BITS_PER_UNIT. Do not copy the actual alignment. */
+ if (!RECORD_OR_UNION_TYPE_P (v) || COMPLETE_TYPE_P (v))
+ {
+ SET_TYPE_ALIGN (v, TYPE_ALIGN (t));
+ TYPE_USER_ALIGN (v) = TYPE_USER_ALIGN (t);
+ }
+ if (inner_type)
+ TREE_TYPE (v) = inner_type;
+ gcc_checking_assert (fld_type_variant_equal_p (t,v, inner_type));
+ add_tree_to_fld_list (v, fld);
+ return v;
+}
+
+/* Map complete types to incomplete types. */
+
+static hash_map<tree, tree> *fld_incomplete_types;
+
+/* Map types to simplified types. */
+
+static hash_map<tree, tree> *fld_simplified_types;
+
+/* Produce variant of T whose TREE_TYPE is T2. If it is main variant,
+ use MAP to prevent duplicates. */
+
+static tree
+fld_process_array_type (tree t, tree t2, hash_map<tree, tree> *map,
+ struct free_lang_data_d *fld)
+{
+ if (TREE_TYPE (t) == t2)
+ return t;
+
+ if (TYPE_MAIN_VARIANT (t) != t)
+ {
+ return fld_type_variant
+ (fld_process_array_type (TYPE_MAIN_VARIANT (t),
+ TYPE_MAIN_VARIANT (t2), map, fld),
+ t, fld, t2);
+ }
+
+ bool existed;
+ tree &array
+ = map->get_or_insert (t, &existed);
+ if (!existed)
+ {
+ array = build_array_type_1 (t2, TYPE_DOMAIN (t),
+ TYPE_TYPELESS_STORAGE (t), false);
+ TYPE_CANONICAL (array) = TYPE_CANONICAL (t);
+ add_tree_to_fld_list (array, fld);
+ }
+ return array;
+}
+
+/* Return CTX after removal of contexts that are not relevant */
+
+static tree
+fld_decl_context (tree ctx)
+{
+ /* Variably modified types are needed for tree_is_indexable to decide
+ whether the type needs to go to local or global section.
+ This code is semi-broken but for now it is easiest to keep contexts
+ as expected. */
+ if (ctx && TYPE_P (ctx)
+ && !variably_modified_type_p (ctx, NULL_TREE))
+ {
+ while (ctx && TYPE_P (ctx))
+ ctx = TYPE_CONTEXT (ctx);
+ }
+ return ctx;
+}
+
+/* For T being aggregate type try to turn it into a incomplete variant.
+ Return T if no simplification is possible. */
+
+static tree
+fld_incomplete_type_of (tree t, struct free_lang_data_d *fld)
+{
+ if (!t)
+ return NULL;
+ if (POINTER_TYPE_P (t))
+ {
+ tree t2 = fld_incomplete_type_of (TREE_TYPE (t), fld);
+ if (t2 != TREE_TYPE (t))
+ {
+ tree first;
+ if (TREE_CODE (t) == POINTER_TYPE)
+ first = build_pointer_type_for_mode (t2, TYPE_MODE (t),
+ TYPE_REF_CAN_ALIAS_ALL (t));
+ else
+ first = build_reference_type_for_mode (t2, TYPE_MODE (t),
+ TYPE_REF_CAN_ALIAS_ALL (t));
+ gcc_assert (TYPE_CANONICAL (t2) != t2
+ && TYPE_CANONICAL (t2) == TYPE_CANONICAL (TREE_TYPE (t)));
+ add_tree_to_fld_list (first, fld);
+ return fld_type_variant (first, t, fld);
+ }
+ return t;
+ }
+ if (TREE_CODE (t) == ARRAY_TYPE)
+ return fld_process_array_type (t,
+ fld_incomplete_type_of (TREE_TYPE (t), fld),
+ fld_incomplete_types, fld);
+ if ((!RECORD_OR_UNION_TYPE_P (t) && TREE_CODE (t) != ENUMERAL_TYPE)
+ || !COMPLETE_TYPE_P (t))
+ return t;
+ if (TYPE_MAIN_VARIANT (t) == t)
+ {
+ bool existed;
+ tree ©
+ = fld_incomplete_types->get_or_insert (t, &existed);
+
+ if (!existed)
+ {
+ copy = build_distinct_type_copy (t);
+
+ /* It is possible that type was not seen by free_lang_data yet. */
+ add_tree_to_fld_list (copy, fld);
+ TYPE_SIZE (copy) = NULL;
+ TYPE_USER_ALIGN (copy) = 0;
+ TYPE_SIZE_UNIT (copy) = NULL;
+ TYPE_CANONICAL (copy) = TYPE_CANONICAL (t);
+ TREE_ADDRESSABLE (copy) = 0;
+ if (AGGREGATE_TYPE_P (t))
+ {
+ SET_TYPE_MODE (copy, VOIDmode);
+ SET_TYPE_ALIGN (copy, BITS_PER_UNIT);
+ TYPE_TYPELESS_STORAGE (copy) = 0;
+ TYPE_FIELDS (copy) = NULL;
+ TYPE_BINFO (copy) = NULL;
+ }
+ else
+ TYPE_VALUES (copy) = NULL;
+
+ /* Build copy of TYPE_DECL in TYPE_NAME if necessary.
+ This is needed for ODR violation warnings to come out right (we
+ want duplicate TYPE_DECLs whenever the type is duplicated because
+ of ODR violation. Because lang data in the TYPE_DECL may not
+ have been freed yet, rebuild it from scratch and copy relevant
+ fields. */
+ TYPE_NAME (copy) = fld_simplified_type_name (copy);
+ tree name = TYPE_NAME (copy);
+
+ if (name && TREE_CODE (name) == TYPE_DECL)
+ {
+ gcc_checking_assert (TREE_TYPE (name) == t);
+ tree name2 = build_decl (DECL_SOURCE_LOCATION (name), TYPE_DECL,
+ DECL_NAME (name), copy);
+ if (DECL_ASSEMBLER_NAME_SET_P (name))
+ SET_DECL_ASSEMBLER_NAME (name2, DECL_ASSEMBLER_NAME (name));
+ SET_DECL_ALIGN (name2, 0);
+ DECL_CONTEXT (name2) = fld_decl_context
+ (DECL_CONTEXT (name));
+ TYPE_NAME (copy) = name2;
+ }
+ }
+ return copy;
+ }
+ return (fld_type_variant
+ (fld_incomplete_type_of (TYPE_MAIN_VARIANT (t), fld), t, fld));
+}
+
+/* Simplify type T for scenarios where we do not need complete pointer
+ types. */
+
+static tree
+fld_simplified_type (tree t, struct free_lang_data_d *fld)
+{
+ if (!t)
+ return t;
+ if (POINTER_TYPE_P (t))
+ return fld_incomplete_type_of (t, fld);
+ /* FIXME: This triggers verification error, see PR88140. */
+ if (TREE_CODE (t) == ARRAY_TYPE && 0)
+ return fld_process_array_type (t, fld_simplified_type (TREE_TYPE (t), fld),
+ fld_simplified_types, fld);
+ return t;
+}
+
/* Reset the expression *EXPR_P, a size or position.
??? We could reset all non-constant sizes or positions. But it's cheap
BINFO_BASE_ACCESSES (binfo) = NULL;
BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE;
BINFO_SUBVTT_INDEX (binfo) = NULL_TREE;
+ BINFO_VPTR_FIELD (binfo) = NULL_TREE;
FOR_EACH_VEC_ELT (*BINFO_BASE_BINFOS (binfo), i, t)
free_lang_data_in_binfo (t);
/* Reset all language specific information still present in TYPE. */
static void
-free_lang_data_in_type (tree type)
+free_lang_data_in_type (tree type, struct free_lang_data_d *fld)
{
gcc_assert (TYPE_P (type));
TREE_LANG_FLAG_5 (type) = 0;
TREE_LANG_FLAG_6 (type) = 0;
+ TYPE_NEEDS_CONSTRUCTING (type) = 0;
+
if (TREE_CODE (type) == FUNCTION_TYPE)
{
+ TREE_TYPE (type) = fld_simplified_type (TREE_TYPE (type), fld);
/* Remove the const and volatile qualifiers from arguments. The
C++ front end removes them, but the C front end does not,
leading to false ODR violation errors when merging two
different front ends. */
for (tree p = TYPE_ARG_TYPES (type); p; p = TREE_CHAIN (p))
{
+ TREE_VALUE (p) = fld_simplified_type (TREE_VALUE (p), fld);
tree arg_type = TREE_VALUE (p);
if (TYPE_READONLY (arg_type) || TYPE_VOLATILE (arg_type))
& ~TYPE_QUAL_CONST
& ~TYPE_QUAL_VOLATILE;
TREE_VALUE (p) = build_qualified_type (arg_type, quals);
- free_lang_data_in_type (TREE_VALUE (p));
+ free_lang_data_in_type (TREE_VALUE (p), fld);
}
/* C++ FE uses TREE_PURPOSE to store initial values. */
TREE_PURPOSE (p) = NULL;
}
}
else if (TREE_CODE (type) == METHOD_TYPE)
- for (tree p = TYPE_ARG_TYPES (type); p; p = TREE_CHAIN (p))
- /* C++ FE uses TREE_PURPOSE to store initial values. */
- TREE_PURPOSE (p) = NULL;
+ {
+ TREE_TYPE (type) = fld_simplified_type (TREE_TYPE (type), fld);
+ for (tree p = TYPE_ARG_TYPES (type); p; p = TREE_CHAIN (p))
+ {
+ /* C++ FE uses TREE_PURPOSE to store initial values. */
+ TREE_VALUE (p) = fld_simplified_type (TREE_VALUE (p), fld);
+ TREE_PURPOSE (p) = NULL;
+ }
+ }
else if (RECORD_OR_UNION_TYPE_P (type))
{
/* Remove members that are not FIELD_DECLs from the field list
else
*prev = DECL_CHAIN (member);
- /* FIXME: C FE uses TYPE_VFIELD to record C_TYPE_INCOMPLETE_VARS
- and danagle the pointer from time to time. */
- if (TYPE_VFIELD (type) && TREE_CODE (TYPE_VFIELD (type)) != FIELD_DECL)
- TYPE_VFIELD (type) = NULL_TREE;
+ TYPE_VFIELD (type) = NULL_TREE;
if (TYPE_BINFO (type))
{
|| SCALAR_FLOAT_TYPE_P (type)
|| FIXED_POINT_TYPE_P (type))
{
+ if (TREE_CODE (type) == ENUMERAL_TYPE)
+ {
+ /* Type values are used only for C++ ODR checking. Drop them
+ for all type variants and non-ODR types.
+ For ODR types the data is freed in free_odr_warning_data. */
+ if (TYPE_MAIN_VARIANT (type) != type
+ || !type_with_linkage_p (type))
+ TYPE_VALUES (type) = NULL;
+ else
+ /* Simplify representation by recording only values rather
+ than const decls. */
+ for (tree e = TYPE_VALUES (type); e; e = TREE_CHAIN (e))
+ if (TREE_CODE (TREE_VALUE (e)) == CONST_DECL)
+ TREE_VALUE (e) = DECL_INITIAL (TREE_VALUE (e));
+ }
free_lang_data_in_one_sizepos (&TYPE_MIN_VALUE (type));
free_lang_data_in_one_sizepos (&TYPE_MAX_VALUE (type));
}
TYPE_CONTEXT (type) = ctx;
}
- /* Drop TYPE_DECLs in TYPE_NAME in favor of the identifier in the
- TYPE_DECL if the type doesn't have linkage. */
- if (! type_with_linkage_p (type))
- TYPE_NAME (type) = TYPE_IDENTIFIER (type);
+ TYPE_STUB_DECL (type) = NULL;
+ TYPE_NAME (type) = fld_simplified_type_name (type);
}
e.g. -fno-signed-char/-fsigned-char mismatches to be handled well.
See cp/mangle.c:write_builtin_type for details. */
- if (flag_lto_odr_type_mering
- && TREE_CODE (decl) == TYPE_DECL
- && DECL_NAME (decl)
- && decl == TYPE_NAME (TREE_TYPE (decl))
- && TYPE_MAIN_VARIANT (TREE_TYPE (decl)) == TREE_TYPE (decl)
- && !TYPE_ARTIFICIAL (TREE_TYPE (decl))
- && (type_with_linkage_p (TREE_TYPE (decl))
- || TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE)
- && !variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
- return !DECL_ASSEMBLER_NAME_SET_P (decl);
+ if (TREE_CODE (decl) == TYPE_DECL)
+ {
+ if (flag_lto_odr_type_mering
+ && DECL_NAME (decl)
+ && decl == TYPE_NAME (TREE_TYPE (decl))
+ && TYPE_MAIN_VARIANT (TREE_TYPE (decl)) == TREE_TYPE (decl)
+ && !TYPE_ARTIFICIAL (TREE_TYPE (decl))
+ && (type_with_linkage_p (TREE_TYPE (decl))
+ || TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE)
+ && !variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
+ return !DECL_ASSEMBLER_NAME_SET_P (decl);
+ return false;
+ }
/* Only FUNCTION_DECLs and VAR_DECLs are considered. */
if (!VAR_OR_FUNCTION_DECL_P (decl))
return false;
{
/* Do not set assembler name on builtins. Allow RTL expansion to
decide whether to expand inline or via a regular call. */
- if (DECL_BUILT_IN (decl)
+ if (fndecl_built_in_p (decl)
&& DECL_BUILT_IN_CLASS (decl) != BUILT_IN_FRONTEND)
return false;
DECL. */
static void
-free_lang_data_in_decl (tree decl)
+free_lang_data_in_decl (tree decl, struct free_lang_data_d *fld)
{
gcc_assert (DECL_P (decl));
free_lang_data_in_one_sizepos (&DECL_SIZE_UNIT (decl));
if (TREE_CODE (decl) == FIELD_DECL)
{
+ DECL_FCONTEXT (decl) = NULL;
free_lang_data_in_one_sizepos (&DECL_FIELD_OFFSET (decl));
if (TREE_CODE (DECL_CONTEXT (decl)) == QUAL_UNION_TYPE)
DECL_QUALIFIER (decl) = NULL_TREE;
if (TREE_CODE (decl) == FUNCTION_DECL)
{
struct cgraph_node *node;
+ /* Frontends do not set TREE_ADDRESSABLE on public variables even though
+ the address may be taken in other unit, so this flag has no practical
+ use for middle-end.
+
+ It would make more sense if frontends set TREE_ADDRESSABLE to 0 only
+ for public objects that indeed can not be adressed, but it is not
+ the case. Set the flag to true so we do not get merge failures for
+ i.e. virtual tables between units that take address of it and
+ units that don't. */
+ if (TREE_PUBLIC (decl))
+ TREE_ADDRESSABLE (decl) = true;
+ TREE_TYPE (decl) = fld_simplified_type (TREE_TYPE (decl), fld);
if (!(node = cgraph_node::get (decl))
|| (!node->definition && !node->clones))
{
(DECL_CONTEXT (DECL_ABSTRACT_ORIGIN (decl))))
DECL_ABSTRACT_ORIGIN (decl) = NULL_TREE;
- /* Sometimes the C++ frontend doesn't manage to transform a temporary
- DECL_VINDEX referring to itself into a vtable slot number as it
- should. Happens with functions that are copied and then forgotten
- about. Just clear it, it won't matter anymore. */
- if (DECL_VINDEX (decl) && !tree_fits_shwi_p (DECL_VINDEX (decl)))
- DECL_VINDEX (decl) = NULL_TREE;
+ DECL_VINDEX (decl) = NULL_TREE;
}
else if (VAR_P (decl))
{
+ /* See comment above why we set the flag for functoins. */
+ if (TREE_PUBLIC (decl))
+ TREE_ADDRESSABLE (decl) = true;
if ((DECL_EXTERNAL (decl)
&& (!TREE_STATIC (decl) || !TREE_READONLY (decl)))
|| (decl_function_context (decl) && !TREE_STATIC (decl)))
{
DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
DECL_VISIBILITY_SPECIFIED (decl) = 0;
+ TREE_PUBLIC (decl) = 0;
+ TREE_PRIVATE (decl) = 0;
+ DECL_ARTIFICIAL (decl) = 0;
+ TYPE_DECL_SUPPRESS_DEBUG (decl) = 0;
DECL_INITIAL (decl) = NULL_TREE;
+ DECL_ORIGINAL_TYPE (decl) = NULL_TREE;
+ DECL_MODE (decl) = VOIDmode;
+ SET_DECL_ALIGN (decl, 0);
+ /* TREE_TYPE is cleared at WPA time in free_odr_warning_data. */
}
else if (TREE_CODE (decl) == FIELD_DECL)
- DECL_INITIAL (decl) = NULL_TREE;
+ {
+ TREE_TYPE (decl) = fld_simplified_type (TREE_TYPE (decl), fld);
+ DECL_INITIAL (decl) = NULL_TREE;
+ }
else if (TREE_CODE (decl) == TRANSLATION_UNIT_DECL
&& DECL_INITIAL (decl)
&& TREE_CODE (DECL_INITIAL (decl)) == BLOCK)
nodes and thus we can't use TREE_CHAIN in multiple lists. */
tree *nextp = &BLOCK_VARS (DECL_INITIAL (decl));
while (*nextp)
- {
- tree var = *nextp;
- if (TREE_CODE (var) == FUNCTION_DECL
- && DECL_BUILT_IN (var))
+ {
+ tree var = *nextp;
+ if (fndecl_built_in_p (var))
*nextp = TREE_CHAIN (var);
else
nextp = &TREE_CHAIN (var);
}
}
-}
-
-
-/* Data used when collecting DECLs and TYPEs for language data removal. */
-
-struct free_lang_data_d
-{
- free_lang_data_d () : decls (100), types (100) {}
-
- /* Worklist to avoid excessive recursion. */
- auto_vec<tree> worklist;
-
- /* Set of traversed objects. Used to avoid duplicate visits. */
- hash_set<tree> pset;
-
- /* Array of symbols to process with free_lang_data_in_decl. */
- auto_vec<tree> decls;
-
- /* Array of types to process with free_lang_data_in_type. */
- auto_vec<tree> types;
-};
-
-
-/* Add type or decl T to one of the list of tree nodes that need their
- language data removed. The lists are held inside FLD. */
-
-static void
-add_tree_to_fld_list (tree t, struct free_lang_data_d *fld)
-{
- if (DECL_P (t))
- fld->decls.safe_push (t);
- else if (TYPE_P (t))
- fld->types.safe_push (t);
- else
- gcc_unreachable ();
-}
-
-/* Push tree node T into FLD->WORKLIST. */
+ /* We need to keep field decls associated with their trees. Otherwise tree
+ merging may merge some fileds and keep others disjoint wich in turn will
+ not do well with TREE_CHAIN pointers linking them.
-static inline void
-fld_worklist_push (tree t, struct free_lang_data_d *fld)
-{
- if (t && !is_lang_specific (t) && !fld->pset.contains (t))
- fld->worklist.safe_push ((t));
+ Also do not drop containing types for virtual methods and tables because
+ these are needed by devirtualization. */
+ if (TREE_CODE (decl) != FIELD_DECL
+ && ((TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
+ || !DECL_VIRTUAL_P (decl)))
+ DECL_CONTEXT (decl) = fld_decl_context (DECL_CONTEXT (decl));
}
fld_worklist_push (DECL_ARGUMENTS (t), fld);
fld_worklist_push (DECL_RESULT (t), fld);
}
- else if (TREE_CODE (t) == TYPE_DECL)
- {
- fld_worklist_push (DECL_ORIGINAL_TYPE (t), fld);
- }
else if (TREE_CODE (t) == FIELD_DECL)
{
fld_worklist_push (DECL_FIELD_OFFSET (t), fld);
fld_worklist_push (TYPE_POINTER_TO (t), fld);
fld_worklist_push (TYPE_REFERENCE_TO (t), fld);
fld_worklist_push (TYPE_NAME (t), fld);
- /* Do not walk TYPE_NEXT_PTR_TO or TYPE_NEXT_REF_TO. We do not stream
- them and thus do not and want not to reach unused pointer types
- this way. */
+ /* While we do not stream TYPE_POINTER_TO and TYPE_REFERENCE_TO
+ lists, we may look types up in these lists and use them while
+ optimizing the function body. Thus we need to free lang data
+ in them. */
+ if (TREE_CODE (t) == POINTER_TYPE)
+ fld_worklist_push (TYPE_NEXT_PTR_TO (t), fld);
+ if (TREE_CODE (t) == REFERENCE_TYPE)
+ fld_worklist_push (TYPE_NEXT_REF_TO (t), fld);
if (!POINTER_TYPE_P (t))
fld_worklist_push (TYPE_MIN_VALUE_RAW (t), fld);
/* TYPE_MAX_VALUE_RAW is TYPE_BINFO for record types. */
tree tem;
FOR_EACH_VEC_ELT (*BINFO_BASE_BINFOS (TYPE_BINFO (t)), i, tem)
fld_worklist_push (TREE_TYPE (tem), fld);
- fld_worklist_push (BINFO_VIRTUALS (TYPE_BINFO (t)), fld);
+ fld_worklist_push (BINFO_TYPE (TYPE_BINFO (t)), fld);
+ fld_worklist_push (BINFO_VTABLE (TYPE_BINFO (t)), fld);
}
if (RECORD_OR_UNION_TYPE_P (t))
{
tem = TYPE_FIELDS (t);
while (tem)
{
- if (TREE_CODE (tem) == FIELD_DECL
- || (TREE_CODE (tem) == TYPE_DECL
- && !DECL_IGNORED_P (tem)
- && debug_info_level > DINFO_LEVEL_TERSE
- && !is_redundant_typedef (tem)))
+ if (TREE_CODE (tem) == FIELD_DECL)
fld_worklist_push (tem, fld);
tem = TREE_CHAIN (tem);
}
}
+ if (FUNC_OR_METHOD_TYPE_P (t))
+ fld_worklist_push (TYPE_METHOD_BASETYPE (t), fld);
fld_worklist_push (TYPE_STUB_DECL (t), fld);
*ws = 0;
}
else if (TREE_CODE (t) == BLOCK)
{
- tree tem;
- for (tem = BLOCK_VARS (t); tem; tem = TREE_CHAIN (tem))
- fld_worklist_push (tem, fld);
- for (tem = BLOCK_SUBBLOCKS (t); tem; tem = BLOCK_CHAIN (tem))
+ for (tree *tem = &BLOCK_VARS (t); *tem; )
+ {
+ if (TREE_CODE (*tem) != VAR_DECL
+ || !auto_var_in_fn_p (*tem, DECL_CONTEXT (*tem)))
+ {
+ gcc_assert (TREE_CODE (*tem) != RESULT_DECL
+ && TREE_CODE (*tem) != PARM_DECL);
+ *tem = TREE_CHAIN (*tem);
+ }
+ else
+ {
+ fld_worklist_push (*tem, fld);
+ tem = &TREE_CHAIN (*tem);
+ }
+ }
+ for (tree tem = BLOCK_SUBBLOCKS (t); tem; tem = BLOCK_CHAIN (tem))
fld_worklist_push (tem, fld);
fld_worklist_push (BLOCK_ABSTRACT_ORIGIN (t), fld);
}
been set up. */
static void
-free_lang_data_in_cgraph (void)
+free_lang_data_in_cgraph (struct free_lang_data_d *fld)
{
struct cgraph_node *n;
varpool_node *v;
- struct free_lang_data_d fld;
tree t;
unsigned i;
alias_pair *p;
/* Find decls and types in the body of every function in the callgraph. */
FOR_EACH_FUNCTION (n)
- find_decls_types_in_node (n, &fld);
+ find_decls_types_in_node (n, fld);
FOR_EACH_VEC_SAFE_ELT (alias_pairs, i, p)
- find_decls_types (p->decl, &fld);
+ find_decls_types (p->decl, fld);
/* Find decls and types in every varpool symbol. */
FOR_EACH_VARIABLE (v)
- find_decls_types_in_var (v, &fld);
+ find_decls_types_in_var (v, fld);
/* Set the assembler name on every decl found. We need to do this
now because free_lang_data_in_decl will invalidate data needed
for mangling. This breaks mangling on interdependent decls. */
- FOR_EACH_VEC_ELT (fld.decls, i, t)
+ FOR_EACH_VEC_ELT (fld->decls, i, t)
assign_assembler_name_if_needed (t);
/* Traverse every decl found freeing its language data. */
- FOR_EACH_VEC_ELT (fld.decls, i, t)
- free_lang_data_in_decl (t);
+ FOR_EACH_VEC_ELT (fld->decls, i, t)
+ free_lang_data_in_decl (t, fld);
/* Traverse every type found freeing its language data. */
- FOR_EACH_VEC_ELT (fld.types, i, t)
- free_lang_data_in_type (t);
- if (flag_checking)
- {
- FOR_EACH_VEC_ELT (fld.types, i, t)
- verify_type (t);
- }
+ FOR_EACH_VEC_ELT (fld->types, i, t)
+ free_lang_data_in_type (t, fld);
}
free_lang_data (void)
{
unsigned i;
+ struct free_lang_data_d fld;
/* If we are the LTO frontend we have freed lang-specific data already. */
if (in_lto_p
|| (!flag_generate_lto && !flag_generate_offload))
- return 0;
+ {
+ /* Rebuild type inheritance graph even when not doing LTO to get
+ consistent profile data. */
+ rebuild_type_inheritance_graph ();
+ return 0;
+ }
+
+ fld_incomplete_types = new hash_map<tree, tree>;
+ fld_simplified_types = new hash_map<tree, tree>;
/* Provide a dummy TRANSLATION_UNIT_DECL if the FE failed to provide one. */
if (vec_safe_is_empty (all_translation_units))
/* Traverse the IL resetting language specific information for
operands, expressions, etc. */
- free_lang_data_in_cgraph ();
+ free_lang_data_in_cgraph (&fld);
/* Create gimple variants for common types. */
for (unsigned i = 0;
lang_hooks.dwarf_name = lhd_dwarf_name;
lang_hooks.decl_printable_name = gimple_decl_printable_name;
lang_hooks.gimplify_expr = lhd_gimplify_expr;
+ lang_hooks.overwrite_decl_assembler_name = lhd_overwrite_decl_assembler_name;
+ lang_hooks.print_xnode = lhd_print_tree_nothing;
+ lang_hooks.print_decl = lhd_print_tree_nothing;
+ lang_hooks.print_type = lhd_print_tree_nothing;
+ lang_hooks.print_identifier = lhd_print_tree_nothing;
+
+ lang_hooks.tree_inlining.var_mod_type_p = hook_bool_tree_tree_false;
+
+ if (flag_checking)
+ {
+ int i;
+ tree t;
+
+ FOR_EACH_VEC_ELT (fld.types, i, t)
+ verify_type (t);
+ }
/* We do not want the default decl_assembler_name implementation,
rather if we have fixed everything we want a wrapper around it
/* Reset diagnostic machinery. */
tree_diagnostics_defaults (global_dc);
+ rebuild_type_inheritance_graph ();
+
+ delete fld_incomplete_types;
+ delete fld_simplified_types;
+
return 0;
}
if (*loc)
{
tree t1 = ((type_hash *) *loc)->type;
- gcc_assert (TYPE_MAIN_VARIANT (t1) == t1);
+ gcc_assert (TYPE_MAIN_VARIANT (t1) == t1
+ && t1 != type);
if (TYPE_UID (type) + 1 == next_type_uid)
--next_type_uid;
/* Free also min/max values and the cache for integer
return 1 if the lists contain the same types in the same order.
Also, the TREE_PURPOSEs must match. */
-int
+bool
type_list_equal (const_tree l1, const_tree l2)
{
const_tree t1, t2;
&& ! (1 == simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2))
&& (TREE_TYPE (TREE_PURPOSE (t1))
== TREE_TYPE (TREE_PURPOSE (t2))))))
- return 0;
+ return false;
return t1 == t2;
}
then this function counts only the ordinary arguments. */
int
-type_num_arguments (const_tree type)
+type_num_arguments (const_tree fntype)
{
int i = 0;
- tree t;
- for (t = TYPE_ARG_TYPES (type); t; t = TREE_CHAIN (t))
+ for (tree t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t))
/* If the function does not take a variable number of arguments,
the last element in the list will have type `void'. */
if (VOID_TYPE_P (TREE_VALUE (t)))
return i;
}
+/* Return the type of the function TYPE's argument ARGNO if known.
+ For vararg function's where ARGNO refers to one of the variadic
+ arguments return null. Otherwise, return a void_type_node for
+ out-of-bounds ARGNO. */
+
+tree
+type_argument_type (const_tree fntype, unsigned argno)
+{
+ /* Treat zero the same as an out-of-bounds argument number. */
+ if (!argno)
+ return void_type_node;
+
+ function_args_iterator iter;
+
+ tree argtype;
+ unsigned i = 1;
+ FOREACH_FUNCTION_ARGS (fntype, argtype, iter)
+ {
+ /* A vararg function's argument list ends in a null. Otherwise,
+ an ordinary function's argument list ends with void. Return
+ null if ARGNO refers to a vararg argument, void_type_node if
+ it's out of bounds, and the formal argument type otherwise. */
+ if (!argtype)
+ break;
+
+ if (i == argno || VOID_TYPE_P (argtype))
+ return argtype;
+
+ ++i;
+ }
+
+ return NULL_TREE;
+}
+
/* Nonzero if integer constants T1 and T2
represent the same constant value. */
if (t1 == 0 || t2 == 0)
return 0;
+ STRIP_ANY_LOCATION_WRAPPER (t1);
+ STRIP_ANY_LOCATION_WRAPPER (t2);
+
if (TREE_CODE (t1) == INTEGER_CST
&& TREE_CODE (t2) == INTEGER_CST
&& wi::to_widest (t1) == wi::to_widest (t2))
if (t1 == 0 || t2 == 0)
return 0;
+ /* For location wrappers to be the same, they must be at the same
+ source location (and wrap the same thing). */
+ if (location_wrapper_p (t1) && location_wrapper_p (t2))
+ {
+ if (EXPR_LOCATION (t1) != EXPR_LOCATION (t2))
+ return 0;
+ return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+ }
+
code1 = TREE_CODE (t1);
code2 = TREE_CODE (t2);
case WIDEN_MULT_PLUS_EXPR:
case WIDEN_MULT_MINUS_EXPR:
case DOT_PROD_EXPR:
- case FMA_EXPR:
return true;
default:
for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
inchash::add_expr (TREE_VEC_ELT (t, i), hstate, flags);
return;
+ case IDENTIFIER_NODE:
+ hstate.add_object (IDENTIFIER_HASH_VALUE (t));
+ return;
case FUNCTION_DECL:
/* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
Otherwise nodes that compare equal according to operand_equal_p might
flags &= ~OEP_ADDRESS_OF;
break;
- case FMA_EXPR:
case WIDEN_MULT_PLUS_EXPR:
case WIDEN_MULT_MINUS_EXPR:
{
C++ should really be fixed to use DECL_CONTEXT for the real context,
and use something else for the "virtual context". */
- else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_VINDEX (decl))
+ else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl))
context
= TYPE_MAIN_VARIANT
(TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
return as_combined_fn (CALL_EXPR_IFN (call));
tree fndecl = get_callee_fndecl (call);
- if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+ if (fndecl && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
return as_combined_fn (DECL_FUNCTION_CODE (fndecl));
return CFN_LAST;
}
+/* Comparator of indices based on tree_node_counts. */
+
+static int
+tree_nodes_cmp (const void *p1, const void *p2)
+{
+ const unsigned *n1 = (const unsigned *)p1;
+ const unsigned *n2 = (const unsigned *)p2;
+
+ return tree_node_counts[*n1] - tree_node_counts[*n2];
+}
+
+/* Comparator of indices based on tree_code_counts. */
+
+static int
+tree_codes_cmp (const void *p1, const void *p2)
+{
+ const unsigned *n1 = (const unsigned *)p1;
+ const unsigned *n2 = (const unsigned *)p2;
+
+ return tree_code_counts[*n1] - tree_code_counts[*n2];
+}
+
#define TREE_MEM_USAGE_SPACES 40
/* Print debugging information about tree nodes generated during the compile,
{
if (GATHER_STATISTICS)
{
- int i;
uint64_t total_nodes, total_bytes;
fprintf (stderr, "\nKind Nodes Bytes\n");
mem_usage::print_dash_line (TREE_MEM_USAGE_SPACES);
total_nodes = total_bytes = 0;
- for (i = 0; i < (int) all_kinds; i++)
- {
- fprintf (stderr, "%-20s %7" PRIu64 " %10" PRIu64 "\n",
- tree_node_kind_names[i], tree_node_counts[i],
- tree_node_sizes[i]);
- total_nodes += tree_node_counts[i];
- total_bytes += tree_node_sizes[i];
- }
- mem_usage::print_dash_line (TREE_MEM_USAGE_SPACES);
- fprintf (stderr, "%-20s %7" PRIu64 " %10" PRIu64 "\n", "Total",
- total_nodes, total_bytes);
- mem_usage::print_dash_line (TREE_MEM_USAGE_SPACES);
- fprintf (stderr, "Code Nodes\n");
- mem_usage::print_dash_line (TREE_MEM_USAGE_SPACES);
- for (i = 0; i < (int) MAX_TREE_CODES; i++)
- fprintf (stderr, "%-32s %7" PRIu64 "\n",
- get_tree_code_name ((enum tree_code) i), tree_code_counts[i]);
- mem_usage::print_dash_line (TREE_MEM_USAGE_SPACES);
- fprintf (stderr, "\n");
- ssanames_print_statistics ();
- fprintf (stderr, "\n");
- phinodes_print_statistics ();
- fprintf (stderr, "\n");
+
+ {
+ auto_vec<unsigned> indices (all_kinds);
+ for (unsigned i = 0; i < all_kinds; i++)
+ indices.quick_push (i);
+ indices.qsort (tree_nodes_cmp);
+
+ for (unsigned i = 0; i < (int) all_kinds; i++)
+ {
+ unsigned j = indices[i];
+ fprintf (stderr, "%-20s %6" PRIu64 "%c %9" PRIu64 "%c\n",
+ tree_node_kind_names[i], SIZE_AMOUNT (tree_node_counts[j]),
+ SIZE_AMOUNT (tree_node_sizes[j]));
+ total_nodes += tree_node_counts[j];
+ total_bytes += tree_node_sizes[j];
+ }
+ mem_usage::print_dash_line (TREE_MEM_USAGE_SPACES);
+ fprintf (stderr, "%-20s %6" PRIu64 "%c %9" PRIu64 "%c\n", "Total",
+ SIZE_AMOUNT (total_nodes), SIZE_AMOUNT (total_bytes));
+ mem_usage::print_dash_line (TREE_MEM_USAGE_SPACES);
+ }
+
+ {
+ fprintf (stderr, "Code Nodes\n");
+ mem_usage::print_dash_line (TREE_MEM_USAGE_SPACES);
+
+ auto_vec<unsigned> indices (MAX_TREE_CODES);
+ for (unsigned i = 0; i < MAX_TREE_CODES; i++)
+ indices.quick_push (i);
+ indices.qsort (tree_codes_cmp);
+
+ for (unsigned i = 0; i < MAX_TREE_CODES; i++)
+ {
+ unsigned j = indices[i];
+ fprintf (stderr, "%-32s %6" PRIu64 "%c\n",
+ get_tree_code_name ((enum tree_code) j),
+ SIZE_AMOUNT (tree_code_counts[j]));
+ }
+ mem_usage::print_dash_line (TREE_MEM_USAGE_SPACES);
+ fprintf (stderr, "\n");
+ ssanames_print_statistics ();
+ fprintf (stderr, "\n");
+ phinodes_print_statistics ();
+ fprintf (stderr, "\n");
+ }
}
else
fprintf (stderr, "(No per-node statistics)\n");
{
int_n_trees[i].signed_type = make_signed_type (int_n_data[i].bitsize);
int_n_trees[i].unsigned_type = make_unsigned_type (int_n_data[i].bitsize);
- TYPE_SIZE (int_n_trees[i].signed_type) = bitsize_int (int_n_data[i].bitsize);
- TYPE_SIZE (int_n_trees[i].unsigned_type) = bitsize_int (int_n_data[i].bitsize);
- if (int_n_data[i].bitsize > LONG_LONG_TYPE_SIZE
- && int_n_enabled_p[i])
+ if (int_n_enabled_p[i])
{
integer_types[itk_intN_0 + i * 2] = int_n_trees[i].signed_type;
integer_types[itk_unsigned_intN_0 + i * 2] = int_n_trees[i].unsigned_type;
void_type_node = make_node (VOID_TYPE);
layout_type (void_type_node);
- pointer_bounds_type_node = targetm.chkp_bound_type ();
-
/* We are not going to have real types in C with less than byte alignment,
so we might as well not have any types that claim to have it. */
SET_TYPE_ALIGN (void_type_node, BITS_PER_UNIT);
"__builtin_memcmp_eq",
ECF_PURE | ECF_NOTHROW | ECF_LEAF);
+ local_define_builtin ("__builtin_strncmp_eq", ftype, BUILT_IN_STRNCMP_EQ,
+ "__builtin_strncmp_eq",
+ ECF_PURE | ECF_NOTHROW | ECF_LEAF);
+
+ local_define_builtin ("__builtin_strcmp_eq", ftype, BUILT_IN_STRCMP_EQ,
+ "__builtin_strcmp_eq",
+ ECF_PURE | ECF_NOTHROW | ECF_LEAF);
+
/* If there's a possibility that we might use the ARM EABI, build the
alternate __cxa_end_cleanup node used to resume from C++. */
if (targetm.arm_eabi_unwinder)
*q = TOLOWER (*p);
*q = '\0';
+ /* For -ftrapping-math these should throw from a former
+ -fnon-call-exception stmt. */
built_in_names[mcode] = concat (prefix, "mul", mode_name_buf, "3",
NULL);
local_define_builtin (built_in_names[mcode], ftype, mcode,
built_in_names[mcode],
- ECF_CONST | ECF_NOTHROW | ECF_LEAF);
+ ECF_CONST | ECF_LEAF);
built_in_names[dcode] = concat (prefix, "div", mode_name_buf, "3",
NULL);
local_define_builtin (built_in_names[dcode], ftype, dcode,
built_in_names[dcode],
- ECF_CONST | ECF_NOTHROW | ECF_LEAF);
+ ECF_CONST | ECF_LEAF);
}
}
}
/* Given an initializer INIT, return TRUE if INIT is zero or some
- aggregate of zeros. Otherwise return FALSE. */
+ aggregate of zeros. Otherwise return FALSE. If NONZERO is not
+ null, set *NONZERO if and only if INIT is known not to be all
+ zeros. The combination of return value of false and *NONZERO
+ false implies that INIT may but need not be all zeros. Other
+ combinations indicate definitive answers. */
+
bool
-initializer_zerop (const_tree init)
+initializer_zerop (const_tree init, bool *nonzero /* = NULL */)
{
- tree elt;
+ bool dummy;
+ if (!nonzero)
+ nonzero = &dummy;
+
+ /* Conservatively clear NONZERO and set it only if INIT is definitely
+ not all zero. */
+ *nonzero = false;
STRIP_NOPS (init);
+ unsigned HOST_WIDE_INT off = 0;
+
switch (TREE_CODE (init))
{
case INTEGER_CST:
- return integer_zerop (init);
+ if (integer_zerop (init))
+ return true;
+
+ *nonzero = true;
+ return false;
case REAL_CST:
/* ??? Note that this is not correct for C4X float formats. There,
a bit pattern of all zeros is 1.0; 0.0 is encoded with the most
negative exponent. */
- return real_zerop (init)
- && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init));
+ if (real_zerop (init)
+ && !REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init)))
+ return true;
+
+ *nonzero = true;
+ return false;
case FIXED_CST:
- return fixed_zerop (init);
+ if (fixed_zerop (init))
+ return true;
+
+ *nonzero = true;
+ return false;
case COMPLEX_CST:
- return integer_zerop (init)
- || (real_zerop (init)
- && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_REALPART (init)))
- && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_IMAGPART (init))));
+ if (integer_zerop (init)
+ || (real_zerop (init)
+ && !REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_REALPART (init)))
+ && !REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_IMAGPART (init)))))
+ return true;
+
+ *nonzero = true;
+ return false;
case VECTOR_CST:
- return (VECTOR_CST_NPATTERNS (init) == 1
- && VECTOR_CST_DUPLICATE_P (init)
- && initializer_zerop (VECTOR_CST_ENCODED_ELT (init, 0)));
+ if (VECTOR_CST_NPATTERNS (init) == 1
+ && VECTOR_CST_DUPLICATE_P (init)
+ && initializer_zerop (VECTOR_CST_ENCODED_ELT (init, 0)))
+ return true;
+
+ *nonzero = true;
+ return false;
case CONSTRUCTOR:
{
- unsigned HOST_WIDE_INT idx;
-
if (TREE_CLOBBER_P (init))
return false;
+
+ unsigned HOST_WIDE_INT idx;
+ tree elt;
+
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), idx, elt)
- if (!initializer_zerop (elt))
+ if (!initializer_zerop (elt, nonzero))
return false;
+
return true;
}
+ case MEM_REF:
+ {
+ tree arg = TREE_OPERAND (init, 0);
+ if (TREE_CODE (arg) != ADDR_EXPR)
+ return false;
+ tree offset = TREE_OPERAND (init, 1);
+ if (TREE_CODE (offset) != INTEGER_CST
+ || !tree_fits_uhwi_p (offset))
+ return false;
+ off = tree_to_uhwi (offset);
+ if (INT_MAX < off)
+ return false;
+ arg = TREE_OPERAND (arg, 0);
+ if (TREE_CODE (arg) != STRING_CST)
+ return false;
+ init = arg;
+ }
+ /* Fall through. */
+
case STRING_CST:
{
- int i;
+ gcc_assert (off <= INT_MAX);
+
+ int i = off;
+ int n = TREE_STRING_LENGTH (init);
+ if (n <= i)
+ return false;
/* We need to loop through all elements to handle cases like
"\0" and "\0foobar". */
- for (i = 0; i < TREE_STRING_LENGTH (init); ++i)
+ for (i = 0; i < n; ++i)
if (TREE_STRING_POINTER (init)[i] != '\0')
- return false;
+ {
+ *nonzero = true;
+ return false;
+ }
+
+ return true;
+ }
+
+ default:
+ return false;
+ }
+}
+
+/* Return true if EXPR is an initializer expression in which every element
+ is a constant that is numerically equal to 0 or 1. The elements do not
+ need to be equal to each other. */
+
+bool
+initializer_each_zero_or_onep (const_tree expr)
+{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
+ switch (TREE_CODE (expr))
+ {
+ case INTEGER_CST:
+ return integer_zerop (expr) || integer_onep (expr);
+
+ case REAL_CST:
+ return real_zerop (expr) || real_onep (expr);
+
+ case VECTOR_CST:
+ {
+ unsigned HOST_WIDE_INT nelts = vector_cst_encoded_nelts (expr);
+ if (VECTOR_CST_STEPPED_P (expr)
+ && !TYPE_VECTOR_SUBPARTS (TREE_TYPE (expr)).is_constant (&nelts))
+ return false;
+
+ for (unsigned int i = 0; i < nelts; ++i)
+ {
+ tree elt = VECTOR_CST_ENCODED_ELT (expr, i);
+ if (!initializer_each_zero_or_onep (elt))
+ return false;
+ }
return true;
}
return NULL_TREE;
}
+/* If the argument is INTEGER_CST, return it. If the argument is vector
+ with all elements the same INTEGER_CST, return that INTEGER_CST. Otherwise
+ return NULL_TREE.
+ Look through location wrappers. */
+
+tree
+uniform_integer_cst_p (tree t)
+{
+ STRIP_ANY_LOCATION_WRAPPER (t);
+
+ if (TREE_CODE (t) == INTEGER_CST)
+ return t;
+
+ if (VECTOR_TYPE_P (TREE_TYPE (t)))
+ {
+ t = uniform_vector_p (t);
+ if (t && TREE_CODE (t) == INTEGER_CST)
+ return t;
+ }
+
+ return NULL_TREE;
+}
+
/* Build an empty statement at location LOC. */
tree
}
}
-/* Create a new constant string literal and return a char* pointer to it.
- The STRING_CST value is the LEN characters at STR. */
+/* Create a new constant string literal consisting of elements of type
+ ELTYPE and return a tree node representing char* pointer to it as
+ an ADDR_EXPR (ARRAY_REF (ELTYPE, ...)). The STRING_CST value is
+ the LEN bytes at STR (the representation of the string, which may
+ be wide). */
+
tree
-build_string_literal (int len, const char *str)
+build_string_literal (int len, const char *str,
+ tree eltype /* = char_type_node */)
{
- tree t, elem, index, type;
-
- t = build_string (len, str);
- elem = build_type_variant (char_type_node, 1, 0);
- index = build_index_type (size_int (len - 1));
- type = build_array_type (elem, index);
+ tree t = build_string (len, str);
+ tree index = build_index_type (size_int (len - 1));
+ eltype = build_type_variant (eltype, 1, 0);
+ tree type = build_array_type (eltype, index);
TREE_TYPE (t) = type;
TREE_CONSTANT (t) = 1;
TREE_READONLY (t) = 1;
TREE_STATIC (t) = 1;
- type = build_pointer_type (elem);
+ type = build_pointer_type (eltype);
t = build1 (ADDR_EXPR, type,
- build4 (ARRAY_REF, elem,
+ build4 (ARRAY_REF, eltype,
t, integer_zero_node, NULL_TREE, NULL_TREE));
return t;
}
/* If TYPE is an integral or pointer type, return an integer type with
the same precision which is unsigned iff UNSIGNEDP is true, or itself
- if TYPE is already an integer type of signedness UNSIGNEDP. */
+ if TYPE is already an integer type of signedness UNSIGNEDP.
+ If TYPE is a floating-point type, return an integer type with the same
+ bitsize and with the signedness given by UNSIGNEDP; this is useful
+ when doing bit-level operations on a floating-point value. */
tree
signed_or_unsigned_type_for (int unsignedp, tree type)
{
- if (TREE_CODE (type) == INTEGER_TYPE && TYPE_UNSIGNED (type) == unsignedp)
+ if (ANY_INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type) == unsignedp)
return type;
if (TREE_CODE (type) == VECTOR_TYPE)
return build_vector_type (inner2, TYPE_VECTOR_SUBPARTS (type));
}
- if (!INTEGRAL_TYPE_P (type)
- && !POINTER_TYPE_P (type)
- && TREE_CODE (type) != OFFSET_TYPE)
+ if (TREE_CODE (type) == COMPLEX_TYPE)
+ {
+ tree inner = TREE_TYPE (type);
+ tree inner2 = signed_or_unsigned_type_for (unsignedp, inner);
+ if (!inner2)
+ return NULL_TREE;
+ if (inner == inner2)
+ return type;
+ return build_complex_type (inner2);
+ }
+
+ unsigned int bits;
+ if (INTEGRAL_TYPE_P (type)
+ || POINTER_TYPE_P (type)
+ || TREE_CODE (type) == OFFSET_TYPE)
+ bits = TYPE_PRECISION (type);
+ else if (TREE_CODE (type) == REAL_TYPE)
+ bits = GET_MODE_BITSIZE (SCALAR_TYPE_MODE (type));
+ else
return NULL_TREE;
- return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp);
+ return build_nonstandard_integer_type (bits, unsignedp);
}
/* If TYPE is an integral or pointer type, return an integer type with
the same precision which is unsigned, or itself if TYPE is already an
- unsigned integer type. */
+ unsigned integer type. If TYPE is a floating-point type, return an
+ unsigned integer type with the same bitsize as TYPE. */
tree
unsigned_type_for (tree type)
/* If TYPE is an integral or pointer type, return an integer type with
the same precision which is signed, or itself if TYPE is already a
- signed integer type. */
+ signed integer type. If TYPE is a floating-point type, return a
+ signed integer type with the same bitsize as TYPE. */
tree
signed_type_for (tree type)
case OMP_CLAUSE_SCHEDULE:
case OMP_CLAUSE_UNIFORM:
case OMP_CLAUSE_DEPEND:
+ case OMP_CLAUSE_NONTEMPORAL:
case OMP_CLAUSE_NUM_TEAMS:
case OMP_CLAUSE_THREAD_LIMIT:
case OMP_CLAUSE_DEVICE:
case OMP_CLAUSE_USE_DEVICE_PTR:
case OMP_CLAUSE_IS_DEVICE_PTR:
case OMP_CLAUSE__LOOPTEMP_:
+ case OMP_CLAUSE__REDUCTEMP_:
case OMP_CLAUSE__SIMDUID_:
WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0));
/* FALLTHRU */
case OMP_CLAUSE_SEQ:
case OMP_CLAUSE_TILE:
case OMP_CLAUSE__SIMT_:
+ case OMP_CLAUSE_IF_PRESENT:
+ case OMP_CLAUSE_FINALIZE:
WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
case OMP_CLAUSE_LASTPRIVATE:
WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
case OMP_CLAUSE_REDUCTION:
+ case OMP_CLAUSE_TASK_REDUCTION:
+ case OMP_CLAUSE_IN_REDUCTION:
{
int i;
for (i = 0; i < 5; i++)
&& BLOCK_ABSTRACT_ORIGIN (block))
{
tree ao = BLOCK_ABSTRACT_ORIGIN (block);
-
- while (TREE_CODE (ao) == BLOCK
- && BLOCK_ABSTRACT_ORIGIN (ao)
- && BLOCK_ABSTRACT_ORIGIN (ao) != ao)
- ao = BLOCK_ABSTRACT_ORIGIN (ao);
-
if (TREE_CODE (ao) == FUNCTION_DECL)
{
/* If AO is an artificial inline, point RET to the
{
const_tree const xt = x;
const_tree const yt = y;
- const char *xp;
- const char *yp;
- size_t len;
if (TREE_CODE (xt) != TREE_CODE (yt))
return 0;
if (TREE_CODE (xt) == OPTIMIZATION_NODE)
- {
- xp = (const char *)TREE_OPTIMIZATION (xt);
- yp = (const char *)TREE_OPTIMIZATION (yt);
- len = sizeof (struct cl_optimization);
- }
-
+ return cl_optimization_option_eq (TREE_OPTIMIZATION (xt),
+ TREE_OPTIMIZATION (yt));
else if (TREE_CODE (xt) == TARGET_OPTION_NODE)
- {
- return cl_target_option_eq (TREE_TARGET_OPTION (xt),
- TREE_TARGET_OPTION (yt));
- }
-
+ return cl_target_option_eq (TREE_TARGET_OPTION (xt),
+ TREE_TARGET_OPTION (yt));
else
gcc_unreachable ();
-
- return (memcmp (xp, yp, len) == 0);
}
/* Build an OPTIMIZATION_NODE based on the options in OPTS. */
TREE_TARGET_GLOBALS (*iter) = NULL;
}
-/* Determine the "ultimate origin" of a block. The block may be an inlined
- instance of an inlined instance of a block which is local to an inline
- function, so we have to trace all of the way back through the origin chain
- to find out what sort of node actually served as the original seed for the
- given block. */
+/* Determine the "ultimate origin" of a block. */
tree
block_ultimate_origin (const_tree block)
{
- tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
-
- /* BLOCK_ABSTRACT_ORIGIN can point to itself; ignore that if
- we're trying to output the abstract instance of this function. */
- if (BLOCK_ABSTRACT (block) && immediate_origin == block)
- return NULL_TREE;
+ tree origin = BLOCK_ABSTRACT_ORIGIN (block);
- if (immediate_origin == NULL_TREE)
+ if (origin == NULL_TREE)
return NULL_TREE;
else
{
- tree ret_val;
- tree lookahead = immediate_origin;
-
- do
- {
- ret_val = lookahead;
- lookahead = (TREE_CODE (ret_val) == BLOCK
- ? BLOCK_ABSTRACT_ORIGIN (ret_val) : NULL);
- }
- while (lookahead != NULL && lookahead != ret_val);
-
- /* The block's abstract origin chain may not be the *ultimate* origin of
- the block. It could lead to a DECL that has an abstract origin set.
- If so, we want that DECL's abstract origin (which is what DECL_ORIGIN
- will give us if it has one). Note that DECL's abstract origins are
- supposed to be the most distant ancestor (or so decl_ultimate_origin
- claims), so we don't need to loop following the DECL origins. */
- if (DECL_P (ret_val))
- return DECL_ORIGIN (ret_val);
-
- return ret_val;
+ gcc_checking_assert ((DECL_P (origin)
+ && DECL_ORIGIN (origin) == origin)
+ || BLOCK_ORIGIN (origin) == origin);
+ return origin;
}
}
return true;
}
-/* REF is OBJ_TYPE_REF, return the class the ref corresponds to. */
-
-tree
-obj_type_ref_class (const_tree ref)
-{
- gcc_checking_assert (TREE_CODE (ref) == OBJ_TYPE_REF);
- ref = TREE_TYPE (ref);
- gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE);
- ref = TREE_TYPE (ref);
- /* We look for type THIS points to. ObjC also builds
- OBJ_TYPE_REF with non-method calls, Their first parameter
- ID however also corresponds to class type. */
- gcc_checking_assert (TREE_CODE (ref) == METHOD_TYPE
- || TREE_CODE (ref) == FUNCTION_TYPE);
- ref = TREE_VALUE (TYPE_ARG_TYPES (ref));
- gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE);
- return TREE_TYPE (ref);
-}
-
/* Lookup sub-BINFO of BINFO of TYPE at offset POS. */
static tree
return is_typedef_decl (TYPE_NAME (type));
}
-/* Warn about a use of an identifier which was marked deprecated. */
+/* A class to handle converting a string that might contain
+ control characters, (eg newline, form-feed, etc), into one
+ in which contains escape sequences instead. */
+
+class escaped_string
+{
+ public:
+ escaped_string () { m_owned = false; m_str = NULL; };
+ ~escaped_string () { if (m_owned) free (m_str); }
+ operator const char *() const { return (const char *) m_str; }
+ void escape (const char *);
+ private:
+ char *m_str;
+ bool m_owned;
+};
+
+/* PR 84195: Replace control characters in "unescaped" with their
+ escaped equivalents. Allow newlines if -fmessage-length has
+ been set to a non-zero value. This is done here, rather than
+ where the attribute is recorded as the message length can
+ change between these two locations. */
+
void
+escaped_string::escape (const char *unescaped)
+{
+ char *escaped;
+ size_t i, new_i, len;
+
+ if (m_owned)
+ free (m_str);
+
+ m_str = const_cast<char *> (unescaped);
+ m_owned = false;
+
+ if (unescaped == NULL || *unescaped == 0)
+ return;
+
+ len = strlen (unescaped);
+ escaped = NULL;
+ new_i = 0;
+
+ for (i = 0; i < len; i++)
+ {
+ char c = unescaped[i];
+
+ if (!ISCNTRL (c))
+ {
+ if (escaped)
+ escaped[new_i++] = c;
+ continue;
+ }
+
+ if (c != '\n' || !pp_is_wrapping_line (global_dc->printer))
+ {
+ if (escaped == NULL)
+ {
+ /* We only allocate space for a new string if we
+ actually encounter a control character that
+ needs replacing. */
+ escaped = (char *) xmalloc (len * 2 + 1);
+ strncpy (escaped, unescaped, i);
+ new_i = i;
+ }
+
+ escaped[new_i++] = '\\';
+
+ switch (c)
+ {
+ case '\a': escaped[new_i++] = 'a'; break;
+ case '\b': escaped[new_i++] = 'b'; break;
+ case '\f': escaped[new_i++] = 'f'; break;
+ case '\n': escaped[new_i++] = 'n'; break;
+ case '\r': escaped[new_i++] = 'r'; break;
+ case '\t': escaped[new_i++] = 't'; break;
+ case '\v': escaped[new_i++] = 'v'; break;
+ default: escaped[new_i++] = '?'; break;
+ }
+ }
+ else if (escaped)
+ escaped[new_i++] = c;
+ }
+
+ if (escaped)
+ {
+ escaped[new_i] = 0;
+ m_str = escaped;
+ m_owned = true;
+ }
+}
+
+/* Warn about a use of an identifier which was marked deprecated. Returns
+ whether a warning was given. */
+
+bool
warn_deprecated_use (tree node, tree attr)
{
- const char *msg;
+ escaped_string msg;
if (node == 0 || !warn_deprecated_decl)
- return;
+ return false;
if (!attr)
{
attr = lookup_attribute ("deprecated", attr);
if (attr)
- msg = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)));
- else
- msg = NULL;
+ msg.escape (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
- bool w;
+ bool w = false;
if (DECL_P (node))
{
+ auto_diagnostic_group d;
if (msg)
w = warning (OPT_Wdeprecated_declarations,
- "%qD is deprecated: %s", node, msg);
+ "%qD is deprecated: %s", node, (const char *) msg);
else
w = warning (OPT_Wdeprecated_declarations,
"%qD is deprecated", node);
what = DECL_NAME (TYPE_NAME (node));
}
- if (decl)
+ auto_diagnostic_group d;
+ if (what)
{
- if (what)
- {
- if (msg)
- w = warning (OPT_Wdeprecated_declarations,
- "%qE is deprecated: %s", what, msg);
- else
- w = warning (OPT_Wdeprecated_declarations,
- "%qE is deprecated", what);
- }
+ if (msg)
+ w = warning (OPT_Wdeprecated_declarations,
+ "%qE is deprecated: %s", what, (const char *) msg);
else
- {
- if (msg)
- w = warning (OPT_Wdeprecated_declarations,
- "type is deprecated: %s", msg);
- else
- w = warning (OPT_Wdeprecated_declarations,
- "type is deprecated");
- }
- if (w)
- inform (DECL_SOURCE_LOCATION (decl), "declared here");
+ w = warning (OPT_Wdeprecated_declarations,
+ "%qE is deprecated", what);
}
else
{
- if (what)
- {
- if (msg)
- warning (OPT_Wdeprecated_declarations, "%qE is deprecated: %s",
- what, msg);
- else
- warning (OPT_Wdeprecated_declarations, "%qE is deprecated", what);
- }
+ if (msg)
+ w = warning (OPT_Wdeprecated_declarations,
+ "type is deprecated: %s", (const char *) msg);
else
- {
- if (msg)
- warning (OPT_Wdeprecated_declarations, "type is deprecated: %s",
- msg);
- else
- warning (OPT_Wdeprecated_declarations, "type is deprecated");
- }
+ w = warning (OPT_Wdeprecated_declarations,
+ "type is deprecated");
}
+
+ if (w && decl)
+ inform (DECL_SOURCE_LOCATION (decl), "declared here");
}
+
+ return w;
}
/* Return true if REF has a COMPONENT_REF with a bit-field field declaration
do { \
if (flag (tv) != flag (t)) \
{ \
- error ("type variant differs by " #flag "."); \
+ error ("type variant differs by %s", #flag); \
debug_tree (tv); \
return false; \
} \
}
/* Check various uses of TYPE_VALUES_RAW. */
- if (TREE_CODE (t) == ENUMERAL_TYPE)
+ if (TREE_CODE (t) == ENUMERAL_TYPE
+ && TYPE_VALUES (t))
verify_variant_match (TYPE_VALUES);
else if (TREE_CODE (t) == ARRAY_TYPE)
verify_variant_match (TYPE_DOMAIN);
with variably sized arrays because their sizes possibly
gimplified to different variables. */
&& !variably_modified_type_p (ct, NULL)
- && !gimple_canonical_types_compatible_p (t, ct, false))
+ && !gimple_canonical_types_compatible_p (t, ct, false)
+ && COMPLETE_TYPE_P (t))
{
error ("TYPE_CANONICAL is not compatible");
debug_tree (ct);
if (EXCEPTIONAL_CLASS_P (expr))
return expr;
+ /* If any auto_suppress_location_wrappers are active, don't create
+ wrappers. */
+ if (suppress_location_wrappers > 0)
+ return expr;
+
tree_code code
= (((CONSTANT_CLASS_P (expr) && TREE_CODE (expr) != STRING_CST)
|| (TREE_CODE (expr) == CONST_DECL && !TREE_STATIC (expr)))
return wrapper;
}
+int suppress_location_wrappers;
+
/* Return the name of combined function FN, for debugging purposes. */
const char *
}
}
+/* Return a typenode for the "standard" C type with a given name. */
+tree
+get_typenode_from_name (const char *name)
+{
+ if (name == NULL || *name == '\0')
+ return NULL_TREE;
+
+ if (strcmp (name, "char") == 0)
+ return char_type_node;
+ if (strcmp (name, "unsigned char") == 0)
+ return unsigned_char_type_node;
+ if (strcmp (name, "signed char") == 0)
+ return signed_char_type_node;
+
+ if (strcmp (name, "short int") == 0)
+ return short_integer_type_node;
+ if (strcmp (name, "short unsigned int") == 0)
+ return short_unsigned_type_node;
+
+ if (strcmp (name, "int") == 0)
+ return integer_type_node;
+ if (strcmp (name, "unsigned int") == 0)
+ return unsigned_type_node;
+
+ if (strcmp (name, "long int") == 0)
+ return long_integer_type_node;
+ if (strcmp (name, "long unsigned int") == 0)
+ return long_unsigned_type_node;
+
+ if (strcmp (name, "long long int") == 0)
+ return long_long_integer_type_node;
+ if (strcmp (name, "long long unsigned int") == 0)
+ return long_long_unsigned_type_node;
+
+ gcc_unreachable ();
+}
+
/* List of pointer types used to declare builtins before we have seen their
real declaration.
check_strip_nops (wrapped_int_var, int_var);
}
+/* Test various tree predicates. Verify that location wrappers don't
+ affect the results. */
+
+static void
+test_predicates ()
+{
+ /* Build various constants and wrappers around them. */
+
+ location_t loc = BUILTINS_LOCATION;
+
+ tree i_0 = build_int_cst (integer_type_node, 0);
+ tree wr_i_0 = maybe_wrap_with_location (i_0, loc);
+
+ tree i_1 = build_int_cst (integer_type_node, 1);
+ tree wr_i_1 = maybe_wrap_with_location (i_1, loc);
+
+ tree i_m1 = build_int_cst (integer_type_node, -1);
+ tree wr_i_m1 = maybe_wrap_with_location (i_m1, loc);
+
+ tree f_0 = build_real_from_int_cst (float_type_node, i_0);
+ tree wr_f_0 = maybe_wrap_with_location (f_0, loc);
+ tree f_1 = build_real_from_int_cst (float_type_node, i_1);
+ tree wr_f_1 = maybe_wrap_with_location (f_1, loc);
+ tree f_m1 = build_real_from_int_cst (float_type_node, i_m1);
+ tree wr_f_m1 = maybe_wrap_with_location (f_m1, loc);
+
+ tree c_i_0 = build_complex (NULL_TREE, i_0, i_0);
+ tree c_i_1 = build_complex (NULL_TREE, i_1, i_0);
+ tree c_i_m1 = build_complex (NULL_TREE, i_m1, i_0);
+
+ tree c_f_0 = build_complex (NULL_TREE, f_0, f_0);
+ tree c_f_1 = build_complex (NULL_TREE, f_1, f_0);
+ tree c_f_m1 = build_complex (NULL_TREE, f_m1, f_0);
+
+ /* TODO: vector constants. */
+
+ /* Test integer_onep. */
+ ASSERT_FALSE (integer_onep (i_0));
+ ASSERT_FALSE (integer_onep (wr_i_0));
+ ASSERT_TRUE (integer_onep (i_1));
+ ASSERT_TRUE (integer_onep (wr_i_1));
+ ASSERT_FALSE (integer_onep (i_m1));
+ ASSERT_FALSE (integer_onep (wr_i_m1));
+ ASSERT_FALSE (integer_onep (f_0));
+ ASSERT_FALSE (integer_onep (wr_f_0));
+ ASSERT_FALSE (integer_onep (f_1));
+ ASSERT_FALSE (integer_onep (wr_f_1));
+ ASSERT_FALSE (integer_onep (f_m1));
+ ASSERT_FALSE (integer_onep (wr_f_m1));
+ ASSERT_FALSE (integer_onep (c_i_0));
+ ASSERT_TRUE (integer_onep (c_i_1));
+ ASSERT_FALSE (integer_onep (c_i_m1));
+ ASSERT_FALSE (integer_onep (c_f_0));
+ ASSERT_FALSE (integer_onep (c_f_1));
+ ASSERT_FALSE (integer_onep (c_f_m1));
+
+ /* Test integer_zerop. */
+ ASSERT_TRUE (integer_zerop (i_0));
+ ASSERT_TRUE (integer_zerop (wr_i_0));
+ ASSERT_FALSE (integer_zerop (i_1));
+ ASSERT_FALSE (integer_zerop (wr_i_1));
+ ASSERT_FALSE (integer_zerop (i_m1));
+ ASSERT_FALSE (integer_zerop (wr_i_m1));
+ ASSERT_FALSE (integer_zerop (f_0));
+ ASSERT_FALSE (integer_zerop (wr_f_0));
+ ASSERT_FALSE (integer_zerop (f_1));
+ ASSERT_FALSE (integer_zerop (wr_f_1));
+ ASSERT_FALSE (integer_zerop (f_m1));
+ ASSERT_FALSE (integer_zerop (wr_f_m1));
+ ASSERT_TRUE (integer_zerop (c_i_0));
+ ASSERT_FALSE (integer_zerop (c_i_1));
+ ASSERT_FALSE (integer_zerop (c_i_m1));
+ ASSERT_FALSE (integer_zerop (c_f_0));
+ ASSERT_FALSE (integer_zerop (c_f_1));
+ ASSERT_FALSE (integer_zerop (c_f_m1));
+
+ /* Test integer_all_onesp. */
+ ASSERT_FALSE (integer_all_onesp (i_0));
+ ASSERT_FALSE (integer_all_onesp (wr_i_0));
+ ASSERT_FALSE (integer_all_onesp (i_1));
+ ASSERT_FALSE (integer_all_onesp (wr_i_1));
+ ASSERT_TRUE (integer_all_onesp (i_m1));
+ ASSERT_TRUE (integer_all_onesp (wr_i_m1));
+ ASSERT_FALSE (integer_all_onesp (f_0));
+ ASSERT_FALSE (integer_all_onesp (wr_f_0));
+ ASSERT_FALSE (integer_all_onesp (f_1));
+ ASSERT_FALSE (integer_all_onesp (wr_f_1));
+ ASSERT_FALSE (integer_all_onesp (f_m1));
+ ASSERT_FALSE (integer_all_onesp (wr_f_m1));
+ ASSERT_FALSE (integer_all_onesp (c_i_0));
+ ASSERT_FALSE (integer_all_onesp (c_i_1));
+ ASSERT_FALSE (integer_all_onesp (c_i_m1));
+ ASSERT_FALSE (integer_all_onesp (c_f_0));
+ ASSERT_FALSE (integer_all_onesp (c_f_1));
+ ASSERT_FALSE (integer_all_onesp (c_f_m1));
+
+ /* Test integer_minus_onep. */
+ ASSERT_FALSE (integer_minus_onep (i_0));
+ ASSERT_FALSE (integer_minus_onep (wr_i_0));
+ ASSERT_FALSE (integer_minus_onep (i_1));
+ ASSERT_FALSE (integer_minus_onep (wr_i_1));
+ ASSERT_TRUE (integer_minus_onep (i_m1));
+ ASSERT_TRUE (integer_minus_onep (wr_i_m1));
+ ASSERT_FALSE (integer_minus_onep (f_0));
+ ASSERT_FALSE (integer_minus_onep (wr_f_0));
+ ASSERT_FALSE (integer_minus_onep (f_1));
+ ASSERT_FALSE (integer_minus_onep (wr_f_1));
+ ASSERT_FALSE (integer_minus_onep (f_m1));
+ ASSERT_FALSE (integer_minus_onep (wr_f_m1));
+ ASSERT_FALSE (integer_minus_onep (c_i_0));
+ ASSERT_FALSE (integer_minus_onep (c_i_1));
+ ASSERT_TRUE (integer_minus_onep (c_i_m1));
+ ASSERT_FALSE (integer_minus_onep (c_f_0));
+ ASSERT_FALSE (integer_minus_onep (c_f_1));
+ ASSERT_FALSE (integer_minus_onep (c_f_m1));
+
+ /* Test integer_each_onep. */
+ ASSERT_FALSE (integer_each_onep (i_0));
+ ASSERT_FALSE (integer_each_onep (wr_i_0));
+ ASSERT_TRUE (integer_each_onep (i_1));
+ ASSERT_TRUE (integer_each_onep (wr_i_1));
+ ASSERT_FALSE (integer_each_onep (i_m1));
+ ASSERT_FALSE (integer_each_onep (wr_i_m1));
+ ASSERT_FALSE (integer_each_onep (f_0));
+ ASSERT_FALSE (integer_each_onep (wr_f_0));
+ ASSERT_FALSE (integer_each_onep (f_1));
+ ASSERT_FALSE (integer_each_onep (wr_f_1));
+ ASSERT_FALSE (integer_each_onep (f_m1));
+ ASSERT_FALSE (integer_each_onep (wr_f_m1));
+ ASSERT_FALSE (integer_each_onep (c_i_0));
+ ASSERT_FALSE (integer_each_onep (c_i_1));
+ ASSERT_FALSE (integer_each_onep (c_i_m1));
+ ASSERT_FALSE (integer_each_onep (c_f_0));
+ ASSERT_FALSE (integer_each_onep (c_f_1));
+ ASSERT_FALSE (integer_each_onep (c_f_m1));
+
+ /* Test integer_truep. */
+ ASSERT_FALSE (integer_truep (i_0));
+ ASSERT_FALSE (integer_truep (wr_i_0));
+ ASSERT_TRUE (integer_truep (i_1));
+ ASSERT_TRUE (integer_truep (wr_i_1));
+ ASSERT_FALSE (integer_truep (i_m1));
+ ASSERT_FALSE (integer_truep (wr_i_m1));
+ ASSERT_FALSE (integer_truep (f_0));
+ ASSERT_FALSE (integer_truep (wr_f_0));
+ ASSERT_FALSE (integer_truep (f_1));
+ ASSERT_FALSE (integer_truep (wr_f_1));
+ ASSERT_FALSE (integer_truep (f_m1));
+ ASSERT_FALSE (integer_truep (wr_f_m1));
+ ASSERT_FALSE (integer_truep (c_i_0));
+ ASSERT_TRUE (integer_truep (c_i_1));
+ ASSERT_FALSE (integer_truep (c_i_m1));
+ ASSERT_FALSE (integer_truep (c_f_0));
+ ASSERT_FALSE (integer_truep (c_f_1));
+ ASSERT_FALSE (integer_truep (c_f_m1));
+
+ /* Test integer_nonzerop. */
+ ASSERT_FALSE (integer_nonzerop (i_0));
+ ASSERT_FALSE (integer_nonzerop (wr_i_0));
+ ASSERT_TRUE (integer_nonzerop (i_1));
+ ASSERT_TRUE (integer_nonzerop (wr_i_1));
+ ASSERT_TRUE (integer_nonzerop (i_m1));
+ ASSERT_TRUE (integer_nonzerop (wr_i_m1));
+ ASSERT_FALSE (integer_nonzerop (f_0));
+ ASSERT_FALSE (integer_nonzerop (wr_f_0));
+ ASSERT_FALSE (integer_nonzerop (f_1));
+ ASSERT_FALSE (integer_nonzerop (wr_f_1));
+ ASSERT_FALSE (integer_nonzerop (f_m1));
+ ASSERT_FALSE (integer_nonzerop (wr_f_m1));
+ ASSERT_FALSE (integer_nonzerop (c_i_0));
+ ASSERT_TRUE (integer_nonzerop (c_i_1));
+ ASSERT_TRUE (integer_nonzerop (c_i_m1));
+ ASSERT_FALSE (integer_nonzerop (c_f_0));
+ ASSERT_FALSE (integer_nonzerop (c_f_1));
+ ASSERT_FALSE (integer_nonzerop (c_f_m1));
+
+ /* Test real_zerop. */
+ ASSERT_FALSE (real_zerop (i_0));
+ ASSERT_FALSE (real_zerop (wr_i_0));
+ ASSERT_FALSE (real_zerop (i_1));
+ ASSERT_FALSE (real_zerop (wr_i_1));
+ ASSERT_FALSE (real_zerop (i_m1));
+ ASSERT_FALSE (real_zerop (wr_i_m1));
+ ASSERT_TRUE (real_zerop (f_0));
+ ASSERT_TRUE (real_zerop (wr_f_0));
+ ASSERT_FALSE (real_zerop (f_1));
+ ASSERT_FALSE (real_zerop (wr_f_1));
+ ASSERT_FALSE (real_zerop (f_m1));
+ ASSERT_FALSE (real_zerop (wr_f_m1));
+ ASSERT_FALSE (real_zerop (c_i_0));
+ ASSERT_FALSE (real_zerop (c_i_1));
+ ASSERT_FALSE (real_zerop (c_i_m1));
+ ASSERT_TRUE (real_zerop (c_f_0));
+ ASSERT_FALSE (real_zerop (c_f_1));
+ ASSERT_FALSE (real_zerop (c_f_m1));
+
+ /* Test real_onep. */
+ ASSERT_FALSE (real_onep (i_0));
+ ASSERT_FALSE (real_onep (wr_i_0));
+ ASSERT_FALSE (real_onep (i_1));
+ ASSERT_FALSE (real_onep (wr_i_1));
+ ASSERT_FALSE (real_onep (i_m1));
+ ASSERT_FALSE (real_onep (wr_i_m1));
+ ASSERT_FALSE (real_onep (f_0));
+ ASSERT_FALSE (real_onep (wr_f_0));
+ ASSERT_TRUE (real_onep (f_1));
+ ASSERT_TRUE (real_onep (wr_f_1));
+ ASSERT_FALSE (real_onep (f_m1));
+ ASSERT_FALSE (real_onep (wr_f_m1));
+ ASSERT_FALSE (real_onep (c_i_0));
+ ASSERT_FALSE (real_onep (c_i_1));
+ ASSERT_FALSE (real_onep (c_i_m1));
+ ASSERT_FALSE (real_onep (c_f_0));
+ ASSERT_TRUE (real_onep (c_f_1));
+ ASSERT_FALSE (real_onep (c_f_m1));
+
+ /* Test real_minus_onep. */
+ ASSERT_FALSE (real_minus_onep (i_0));
+ ASSERT_FALSE (real_minus_onep (wr_i_0));
+ ASSERT_FALSE (real_minus_onep (i_1));
+ ASSERT_FALSE (real_minus_onep (wr_i_1));
+ ASSERT_FALSE (real_minus_onep (i_m1));
+ ASSERT_FALSE (real_minus_onep (wr_i_m1));
+ ASSERT_FALSE (real_minus_onep (f_0));
+ ASSERT_FALSE (real_minus_onep (wr_f_0));
+ ASSERT_FALSE (real_minus_onep (f_1));
+ ASSERT_FALSE (real_minus_onep (wr_f_1));
+ ASSERT_TRUE (real_minus_onep (f_m1));
+ ASSERT_TRUE (real_minus_onep (wr_f_m1));
+ ASSERT_FALSE (real_minus_onep (c_i_0));
+ ASSERT_FALSE (real_minus_onep (c_i_1));
+ ASSERT_FALSE (real_minus_onep (c_i_m1));
+ ASSERT_FALSE (real_minus_onep (c_f_0));
+ ASSERT_FALSE (real_minus_onep (c_f_1));
+ ASSERT_TRUE (real_minus_onep (c_f_m1));
+
+ /* Test zerop. */
+ ASSERT_TRUE (zerop (i_0));
+ ASSERT_TRUE (zerop (wr_i_0));
+ ASSERT_FALSE (zerop (i_1));
+ ASSERT_FALSE (zerop (wr_i_1));
+ ASSERT_FALSE (zerop (i_m1));
+ ASSERT_FALSE (zerop (wr_i_m1));
+ ASSERT_TRUE (zerop (f_0));
+ ASSERT_TRUE (zerop (wr_f_0));
+ ASSERT_FALSE (zerop (f_1));
+ ASSERT_FALSE (zerop (wr_f_1));
+ ASSERT_FALSE (zerop (f_m1));
+ ASSERT_FALSE (zerop (wr_f_m1));
+ ASSERT_TRUE (zerop (c_i_0));
+ ASSERT_FALSE (zerop (c_i_1));
+ ASSERT_FALSE (zerop (c_i_m1));
+ ASSERT_TRUE (zerop (c_f_0));
+ ASSERT_FALSE (zerop (c_f_1));
+ ASSERT_FALSE (zerop (c_f_m1));
+
+ /* Test tree_expr_nonnegative_p. */
+ ASSERT_TRUE (tree_expr_nonnegative_p (i_0));
+ ASSERT_TRUE (tree_expr_nonnegative_p (wr_i_0));
+ ASSERT_TRUE (tree_expr_nonnegative_p (i_1));
+ ASSERT_TRUE (tree_expr_nonnegative_p (wr_i_1));
+ ASSERT_FALSE (tree_expr_nonnegative_p (i_m1));
+ ASSERT_FALSE (tree_expr_nonnegative_p (wr_i_m1));
+ ASSERT_TRUE (tree_expr_nonnegative_p (f_0));
+ ASSERT_TRUE (tree_expr_nonnegative_p (wr_f_0));
+ ASSERT_TRUE (tree_expr_nonnegative_p (f_1));
+ ASSERT_TRUE (tree_expr_nonnegative_p (wr_f_1));
+ ASSERT_FALSE (tree_expr_nonnegative_p (f_m1));
+ ASSERT_FALSE (tree_expr_nonnegative_p (wr_f_m1));
+ ASSERT_FALSE (tree_expr_nonnegative_p (c_i_0));
+ ASSERT_FALSE (tree_expr_nonnegative_p (c_i_1));
+ ASSERT_FALSE (tree_expr_nonnegative_p (c_i_m1));
+ ASSERT_FALSE (tree_expr_nonnegative_p (c_f_0));
+ ASSERT_FALSE (tree_expr_nonnegative_p (c_f_1));
+ ASSERT_FALSE (tree_expr_nonnegative_p (c_f_m1));
+
+ /* Test tree_expr_nonzero_p. */
+ ASSERT_FALSE (tree_expr_nonzero_p (i_0));
+ ASSERT_FALSE (tree_expr_nonzero_p (wr_i_0));
+ ASSERT_TRUE (tree_expr_nonzero_p (i_1));
+ ASSERT_TRUE (tree_expr_nonzero_p (wr_i_1));
+ ASSERT_TRUE (tree_expr_nonzero_p (i_m1));
+ ASSERT_TRUE (tree_expr_nonzero_p (wr_i_m1));
+
+ /* Test integer_valued_real_p. */
+ ASSERT_FALSE (integer_valued_real_p (i_0));
+ ASSERT_TRUE (integer_valued_real_p (f_0));
+ ASSERT_TRUE (integer_valued_real_p (wr_f_0));
+ ASSERT_TRUE (integer_valued_real_p (f_1));
+ ASSERT_TRUE (integer_valued_real_p (wr_f_1));
+
+ /* Test integer_pow2p. */
+ ASSERT_FALSE (integer_pow2p (i_0));
+ ASSERT_TRUE (integer_pow2p (i_1));
+ ASSERT_TRUE (integer_pow2p (wr_i_1));
+
+ /* Test uniform_integer_cst_p. */
+ ASSERT_TRUE (uniform_integer_cst_p (i_0));
+ ASSERT_TRUE (uniform_integer_cst_p (wr_i_0));
+ ASSERT_TRUE (uniform_integer_cst_p (i_1));
+ ASSERT_TRUE (uniform_integer_cst_p (wr_i_1));
+ ASSERT_TRUE (uniform_integer_cst_p (i_m1));
+ ASSERT_TRUE (uniform_integer_cst_p (wr_i_m1));
+ ASSERT_FALSE (uniform_integer_cst_p (f_0));
+ ASSERT_FALSE (uniform_integer_cst_p (wr_f_0));
+ ASSERT_FALSE (uniform_integer_cst_p (f_1));
+ ASSERT_FALSE (uniform_integer_cst_p (wr_f_1));
+ ASSERT_FALSE (uniform_integer_cst_p (f_m1));
+ ASSERT_FALSE (uniform_integer_cst_p (wr_f_m1));
+ ASSERT_FALSE (uniform_integer_cst_p (c_i_0));
+ ASSERT_FALSE (uniform_integer_cst_p (c_i_1));
+ ASSERT_FALSE (uniform_integer_cst_p (c_i_m1));
+ ASSERT_FALSE (uniform_integer_cst_p (c_f_0));
+ ASSERT_FALSE (uniform_integer_cst_p (c_f_1));
+ ASSERT_FALSE (uniform_integer_cst_p (c_f_m1));
+}
+
+/* Check that string escaping works correctly. */
+
+static void
+test_escaped_strings (void)
+{
+ int saved_cutoff;
+ escaped_string msg;
+
+ msg.escape (NULL);
+ /* ASSERT_STREQ does not accept NULL as a valid test
+ result, so we have to use ASSERT_EQ instead. */
+ ASSERT_EQ (NULL, (const char *) msg);
+
+ msg.escape ("");
+ ASSERT_STREQ ("", (const char *) msg);
+
+ msg.escape ("foobar");
+ ASSERT_STREQ ("foobar", (const char *) msg);
+
+ /* Ensure that we have -fmessage-length set to 0. */
+ saved_cutoff = pp_line_cutoff (global_dc->printer);
+ pp_line_cutoff (global_dc->printer) = 0;
+
+ msg.escape ("foo\nbar");
+ ASSERT_STREQ ("foo\\nbar", (const char *) msg);
+
+ msg.escape ("\a\b\f\n\r\t\v");
+ ASSERT_STREQ ("\\a\\b\\f\\n\\r\\t\\v", (const char *) msg);
+
+ /* Now repeat the tests with -fmessage-length set to 5. */
+ pp_line_cutoff (global_dc->printer) = 5;
+
+ /* Note that the newline is not translated into an escape. */
+ msg.escape ("foo\nbar");
+ ASSERT_STREQ ("foo\nbar", (const char *) msg);
+
+ msg.escape ("\a\b\f\n\r\t\v");
+ ASSERT_STREQ ("\\a\\b\\f\n\\r\\t\\v", (const char *) msg);
+
+ /* Restore the original message length setting. */
+ pp_line_cutoff (global_dc->printer) = saved_cutoff;
+}
+
/* Run all of the selftests within this file. */
void
test_labels ();
test_vector_cst_patterns ();
test_location_wrappers ();
+ test_predicates ();
+ test_escaped_strings ();
}
} // namespace selftest