@@ -144,6 +144,8 @@ class rich_location;
TK(STRING32_USERDEF, LITERAL) /* U"string"_suffix - C++11 */ \
TK(UTF8STRING_USERDEF,LITERAL) /* u8"string"_suffix - C++11 */ \
\
+ TK(EMBED, LITERAL) /* #embed - C23 */ \
+ \
TK(COMMENT, LITERAL) /* Only if output comments. */ \
/* SPELL_LITERAL happens to DTRT. */ \
TK(MACRO_ARG, NONE) /* Macro argument. */ \
@@ -1240,15 +1240,19 @@ finish_embed (cpp_reader *pfile, _cpp_fi
if (params->limit < limit)
limit = params->limit;
- /* For sizes larger than say 64 bytes, this is just a temporary
- solution, we should emit a single new token which the FEs will
- handle as an optimization. */
+ size_t embed_tokens = 0;
+ if (!CPP_OPTION (pfile, cplusplus)
+ && CPP_OPTION (pfile, lang) != CLK_ASM
+ && limit >= 64)
+ embed_tokens = ((limit - 2) / INT_MAX) + (((limit - 2) % INT_MAX) != 0);
+
size_t max = INTTYPE_MAXIMUM (size_t) / sizeof (cpp_token);
- if (limit > max / 2
+ if ((embed_tokens ? (embed_tokens > (max - 3) / 2) : (limit > max / 2))
|| (limit
? (params->prefix.count > max
|| params->suffix.count > max
- || (limit * 2 - 1 + params->prefix.count
+ || ((embed_tokens ? embed_tokens * 2 + 3 : limit * 2 - 1)
+ + params->prefix.count
+ params->suffix.count > max))
: params->if_empty.count > max))
{
@@ -1282,13 +1286,16 @@ finish_embed (cpp_reader *pfile, _cpp_fi
"%s is too large", file->path);
return 0;
}
+ if (embed_tokens && i == 0)
+ i = limit - 2;
}
uchar *s = len ? _cpp_unaligned_alloc (pfile, len) : NULL;
_cpp_buff *tok_buff = NULL;
cpp_token *toks = NULL, *tok = &pfile->directive_result;
size_t count = 0;
if (limit)
- count = (params->prefix.count + limit * 2 - 1
+ count = (params->prefix.count
+ + (embed_tokens ? embed_tokens * 2 + 3 : limit * 2 - 1)
+ params->suffix.count) - 1;
else if (params->if_empty.count)
count = params->if_empty.count - 1;
@@ -1340,6 +1347,34 @@ finish_embed (cpp_reader *pfile, _cpp_fi
tok->flags = NO_EXPAND;
tok++;
}
+ if (i == 0 && embed_tokens)
+ {
+ ++i;
+ for (size_t j = 0; j < embed_tokens; ++j)
+ {
+ tok->src_loc = params->loc;
+ tok->type = CPP_EMBED;
+ tok->flags = NO_EXPAND;
+ tok->val.str.text = &buffer[i];
+ tok->val.str.len
+ = limit - 1 - i > INT_MAX ? INT_MAX : limit - 1 - i;
+ i += tok->val.str.len;
+ if (tok->val.str.len < 32 && j)
+ {
+ /* Avoid CPP_EMBED with a fewer than 32 bytes, shrink the
+ previous CPP_EMBED by 64 and grow this one by 64. */
+ tok[-2].val.str.len -= 64;
+ tok->val.str.text -= 64;
+ tok->val.str.len += 64;
+ }
+ tok++;
+ tok->src_loc = params->loc;
+ tok->type = CPP_COMMA;
+ tok->flags = NO_EXPAND;
+ tok++;
+ }
+ --i;
+ }
}
if (limit && params->suffix.count)
{
@@ -39,6 +39,7 @@ DEFTREESTRUCT(TS_REAL_CST, "real cst")
DEFTREESTRUCT(TS_FIXED_CST, "fixed cst")
DEFTREESTRUCT(TS_VECTOR, "vector")
DEFTREESTRUCT(TS_STRING, "string")
+DEFTREESTRUCT(TS_RAW_DATA_CST, "raw data cst")
DEFTREESTRUCT(TS_COMPLEX, "complex")
DEFTREESTRUCT(TS_IDENTIFIER, "identifier")
DEFTREESTRUCT(TS_DECL_MINIMAL, "decl minimal")
@@ -309,6 +309,14 @@ DEFTREECODE (VECTOR_CST, "vector_cst", t
/* Contents are TREE_STRING_LENGTH and the actual contents of the string. */
DEFTREECODE (STRING_CST, "string_cst", tcc_constant, 0)
+/* Contents are RAW_DATA_LENGTH and the actual content
+ of the raw data, plus RAW_DATA_OWNER for owner of the
+ data. That can be either a STRING_CST, used e.g. when writing
+ PCH header, or another RAW_DATA_CST representing data owned by
+ libcpp and representing the original range (if possible).
+ TREE_TYPE is the type of each of the RAW_DATA_LENGTH elements. */
+DEFTREECODE (RAW_DATA_CST, "raw_data_cst", tcc_constant, 0)
+
/* Declarations. All references to names are represented as ..._DECL
nodes. The decls in one binding context are chained through the
TREE_CHAIN field. Each DECL has a DECL_NAME field which contains
@@ -1516,6 +1516,13 @@ struct GTY(()) tree_string {
char str[1];
};
+struct GTY((user)) tree_raw_data {
+ struct tree_typed typed;
+ tree owner;
+ const char *str;
+ int length;
+};
+
struct GTY(()) tree_complex {
struct tree_typed typed;
tree real;
@@ -2106,6 +2113,7 @@ union GTY ((ptr_alias (union lang_tree_n
struct tree_fixed_cst GTY ((tag ("TS_FIXED_CST"))) fixed_cst;
struct tree_vector GTY ((tag ("TS_VECTOR"))) vector;
struct tree_string GTY ((tag ("TS_STRING"))) string;
+ struct tree_raw_data GTY ((tag ("TS_RAW_DATA_CST"))) raw_data_cst;
struct tree_complex GTY ((tag ("TS_COMPLEX"))) complex;
struct tree_identifier GTY ((tag ("TS_IDENTIFIER"))) identifier;
struct tree_decl_minimal GTY((tag ("TS_DECL_MINIMAL"))) decl_minimal;
@@ -1165,6 +1165,14 @@ extern void omp_clause_range_check_faile
#define TREE_STRING_POINTER(NODE) \
((const char *)(STRING_CST_CHECK (NODE)->string.str))
+/* In a RAW_DATA_CST */
+#define RAW_DATA_LENGTH(NODE) \
+ (RAW_DATA_CST_CHECK (NODE)->raw_data_cst.length)
+#define RAW_DATA_POINTER(NODE) \
+ (RAW_DATA_CST_CHECK (NODE)->raw_data_cst.str)
+#define RAW_DATA_OWNER(NODE) \
+ (RAW_DATA_CST_CHECK (NODE)->raw_data_cst.owner)
+
/* In a COMPLEX_CST node. */
#define TREE_REALPART(NODE) (COMPLEX_CST_CHECK (NODE)->complex.real)
#define TREE_IMAGPART(NODE) (COMPLEX_CST_CHECK (NODE)->complex.imag)
@@ -6757,6 +6765,9 @@ extern location_t set_block (location_t
extern void gt_ggc_mx (tree &);
extern void gt_pch_nx (tree &);
extern void gt_pch_nx (tree &, gt_pointer_operator, void *);
+extern void gt_ggc_mx (tree_raw_data *);
+extern void gt_pch_nx (tree_raw_data *);
+extern void gt_pch_nx (tree_raw_data *, gt_pointer_operator, void *);
extern bool nonnull_arg_p (const_tree);
extern bool is_empty_type (const_tree);
@@ -513,6 +513,7 @@ tree_node_structure_for_code (enum tree_
case STRING_CST: return TS_STRING;
case VECTOR_CST: return TS_VECTOR;
case VOID_CST: return TS_TYPED;
+ case RAW_DATA_CST: return TS_RAW_DATA_CST;
/* tcc_exceptional cases. */
case BLOCK: return TS_BLOCK;
@@ -571,6 +572,7 @@ initialize_tree_contains_struct (void)
case TS_FIXED_CST:
case TS_VECTOR:
case TS_STRING:
+ case TS_RAW_DATA_CST:
case TS_COMPLEX:
case TS_SSA_NAME:
case TS_CONSTRUCTOR:
@@ -1026,6 +1028,7 @@ tree_code_size (enum tree_code code)
case REAL_CST: return sizeof (tree_real_cst);
case FIXED_CST: return sizeof (tree_fixed_cst);
case COMPLEX_CST: return sizeof (tree_complex);
+ case RAW_DATA_CST: return sizeof (tree_raw_data);
case VECTOR_CST: gcc_unreachable ();
case STRING_CST: gcc_unreachable ();
default:
@@ -10467,6 +10470,15 @@ initializer_zerop (const_tree init, bool
*nonzero = true;
return false;
+ case RAW_DATA_CST:
+ for (unsigned int i = 0; i < (unsigned int) RAW_DATA_LENGTH (init); ++i)
+ if (RAW_DATA_POINTER (init)[i])
+ {
+ *nonzero = true;
+ return false;
+ }
+ return true;
+
case CONSTRUCTOR:
{
if (TREE_CLOBBER_P (init))
@@ -15228,6 +15240,50 @@ tree_cc_finalize (void)
vec_free (bitint_type_cache);
}
+void
+gt_ggc_mx (tree_raw_data *x)
+{
+ gt_ggc_m_9tree_node (x->typed.type);
+ gt_ggc_m_9tree_node (x->owner);
+}
+
+void
+gt_pch_nx (tree_raw_data *x)
+{
+ gt_pch_n_9tree_node (x->typed.type);
+ gt_pch_n_9tree_node (x->owner);
+}
+
+/* For PCH we guarantee that RAW_DATA_CST's RAW_DATA_OWNER is a STRING_CST and
+ RAW_DATA_POINTER points into it. We don't want to save/restore
+ RAW_DATA_POINTER on its own but want to restore it pointing at the same
+ offset of the STRING_CST as before. */
+
+void
+gt_pch_nx (tree_raw_data *x, gt_pointer_operator op, void *cookie)
+{
+ op (&x->typed.type, NULL, cookie);
+ gcc_checking_assert (x->owner
+ && TREE_CODE (x->owner) == STRING_CST
+ && x->str >= TREE_STRING_POINTER (x->owner)
+ && (x->str + x->length
+ <= (TREE_STRING_POINTER (x->owner)
+ + TREE_STRING_LENGTH (x->owner))));
+ ptrdiff_t off = x->str - (const char *) (x->owner);
+ tree owner = x->owner;
+ op (&x->owner, NULL, cookie);
+ x->owner = owner;
+ /* The above op call relocates x->owner and remembers the address
+ for relocation e.g. if the compiler is position independent.
+ We then restore x->owner back to its previous value and call
+ op again, for x->owner itself this just repeats (uselessly) what
+ the first call did, but as the second argument is now non-NULL
+ and different, it also arranges for &x->str to be noted for the
+ PIE relocation. */
+ op (&x->owner, &x->str, cookie);
+ x->str = (const char *) (x->owner) + off;
+}
+
#if CHECKING_P
namespace selftest {
@@ -5361,6 +5361,49 @@ gimplify_init_ctor_eval (tree object, ve
&& TREE_CODE (TREE_TYPE (value)) != VECTOR_TYPE)
gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
pre_p, cleared);
+ else if (TREE_CODE (value) == RAW_DATA_CST)
+ {
+ if (RAW_DATA_LENGTH (value) <= 32)
+ {
+ for (unsigned int i = 0; i < (unsigned) RAW_DATA_LENGTH (value);
+ ++i)
+ if (!cleared || RAW_DATA_POINTER (value)[i])
+ {
+ if (i)
+ {
+ tree p
+ = fold_build2 (PLUS_EXPR, TREE_TYPE (purpose),
+ purpose,
+ build_int_cst (TREE_TYPE (purpose),
+ i));
+ cref = build4 (ARRAY_REF, array_elt_type,
+ unshare_expr (object), p, NULL_TREE,
+ NULL_TREE);
+ }
+ tree init
+ = build2 (INIT_EXPR, TREE_TYPE (cref), cref,
+ build_int_cst (TREE_TYPE (value),
+ ((const unsigned char *)
+ RAW_DATA_POINTER (value))[i]));
+ gimplify_and_add (init, pre_p);
+ ggc_free (init);
+ }
+ }
+ else
+ {
+ tree rtype = build_array_type_nelts (TREE_TYPE (value),
+ RAW_DATA_LENGTH (value));
+ tree rctor = build_constructor_single (rtype, bitsize_zero_node,
+ value);
+ tree addr = build_fold_addr_expr (cref);
+ cref = build2 (MEM_REF, rtype, addr,
+ build_int_cst (ptr_type_node, 0));
+ rctor = tree_output_constant_def (rctor);
+ tree init = build2 (INIT_EXPR, rtype, cref, rctor);
+ gimplify_and_add (init, pre_p);
+ ggc_free (init);
+ }
+ }
else
{
tree init = build2 (INIT_EXPR, TREE_TYPE (cref), cref, value);
@@ -3348,8 +3348,14 @@ operand_compare::operand_equal_p (const_
case STRING_CST:
return (TREE_STRING_LENGTH (arg0) == TREE_STRING_LENGTH (arg1)
&& ! memcmp (TREE_STRING_POINTER (arg0),
- TREE_STRING_POINTER (arg1),
- TREE_STRING_LENGTH (arg0)));
+ TREE_STRING_POINTER (arg1),
+ TREE_STRING_LENGTH (arg0)));
+
+ case RAW_DATA_CST:
+ return (RAW_DATA_LENGTH (arg0) == RAW_DATA_LENGTH (arg1)
+ && ! memcmp (RAW_DATA_POINTER (arg0),
+ RAW_DATA_POINTER (arg1),
+ RAW_DATA_LENGTH (arg0)));
case ADDR_EXPR:
gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
@@ -3942,6 +3948,10 @@ operand_compare::hash_operand (const_tre
hstate.add ((const void *) TREE_STRING_POINTER (t),
TREE_STRING_LENGTH (t));
return;
+ case RAW_DATA_CST:
+ hstate.add ((const void *) RAW_DATA_POINTER (t),
+ RAW_DATA_LENGTH (t));
+ return;
case COMPLEX_CST:
hash_operand (TREE_REALPART (t), hstate, flags);
hash_operand (TREE_IMAGPART (t), hstate, flags);
@@ -8405,6 +8415,48 @@ native_encode_initializer (tree init, un
}
curpos = pos;
+ if (val && TREE_CODE (val) == RAW_DATA_CST)
+ {
+ if (count)
+ return 0;
+ if (off == -1
+ || (curpos >= off
+ && (curpos + RAW_DATA_LENGTH (val)
+ <= (HOST_WIDE_INT) off + len)))
+ {
+ if (ptr)
+ memcpy (ptr + (curpos - o), RAW_DATA_POINTER (val),
+ RAW_DATA_LENGTH (val));
+ if (mask)
+ memset (mask + curpos, 0, RAW_DATA_LENGTH (val));
+ }
+ else if (curpos + RAW_DATA_LENGTH (val) > off
+ && curpos < (HOST_WIDE_INT) off + len)
+ {
+ /* Partial overlap. */
+ unsigned char *p = NULL;
+ int no = 0;
+ int l;
+ gcc_assert (mask == NULL);
+ if (curpos >= off)
+ {
+ if (ptr)
+ p = ptr + curpos - off;
+ l = MIN ((HOST_WIDE_INT) off + len - curpos,
+ RAW_DATA_LENGTH (val));
+ }
+ else
+ {
+ p = ptr;
+ no = off - curpos;
+ l = len;
+ }
+ if (p)
+ memcpy (p, RAW_DATA_POINTER (val) + no, l);
+ }
+ curpos += RAW_DATA_LENGTH (val);
+ val = NULL_TREE;
+ }
if (val)
do
{
@@ -13768,6 +13820,9 @@ get_array_ctor_element_at_index (tree ct
else
first_p = false;
+ if (TREE_CODE (cval) == RAW_DATA_CST)
+ max_index += RAW_DATA_LENGTH (cval) - 1;
+
/* Do we have match? */
if (wi::cmp (access_index, index, index_sgn) >= 0)
{
@@ -13867,10 +13922,26 @@ fold (tree expr)
&& TREE_CODE (op0) == CONSTRUCTOR
&& ! type_contains_placeholder_p (TREE_TYPE (op0)))
{
- tree val = get_array_ctor_element_at_index (op0,
- wi::to_offset (op1));
+ unsigned int idx;
+ tree val
+ = get_array_ctor_element_at_index (op0, wi::to_offset (op1),
+ &idx);
if (val)
- return val;
+ {
+ if (TREE_CODE (val) != RAW_DATA_CST)
+ return val;
+ if (CONSTRUCTOR_ELT (op0, idx)->index == NULL_TREE
+ || (TREE_CODE (CONSTRUCTOR_ELT (op0, idx)->index)
+ != INTEGER_CST))
+ return t;
+ offset_int o
+ = (wi::to_offset (op1)
+ - wi::to_offset (CONSTRUCTOR_ELT (op0, idx)->index));
+ gcc_checking_assert (o < RAW_DATA_LENGTH (val));
+ return build_int_cst (TREE_TYPE (val),
+ ((const unsigned char *)
+ RAW_DATA_POINTER (val))[o.to_uhwi ()]);
+ }
}
return t;
@@ -8000,7 +8000,7 @@ fold_array_ctor_reference (tree type, tr
unsigned ctor_idx;
tree val = get_array_ctor_element_at_index (ctor, access_index,
&ctor_idx);
- if (!val && ctor_idx >= CONSTRUCTOR_NELTS (ctor))
+ if (!val && ctor_idx >= CONSTRUCTOR_NELTS (ctor))
return build_zero_cst (type);
/* native-encode adjacent ctor elements. */
@@ -8027,10 +8027,27 @@ fold_array_ctor_reference (tree type, tr
{
if (bufoff + elt_sz > sizeof (buf))
elt_sz = sizeof (buf) - bufoff;
- int len = native_encode_expr (val, buf + bufoff, elt_sz,
+ int len;
+ if (TREE_CODE (val) == RAW_DATA_CST)
+ {
+ gcc_assert (inner_offset == 0);
+ if (!elt->index || TREE_CODE (elt->index) != INTEGER_CST)
+ return NULL_TREE;
+ inner_offset = (access_index
+ - wi::to_offset (elt->index)).to_uhwi ();
+ len = MIN (sizeof (buf) - bufoff,
+ (unsigned) (RAW_DATA_LENGTH (val) - inner_offset));
+ memcpy (buf + bufoff, RAW_DATA_POINTER (val) + inner_offset,
+ len);
+ access_index += len - 1;
+ }
+ else
+ {
+ len = native_encode_expr (val, buf + bufoff, elt_sz,
inner_offset / BITS_PER_UNIT);
- if (len != (int) elt_sz - inner_offset / BITS_PER_UNIT)
- return NULL_TREE;
+ if (len != (int) elt_sz - inner_offset / BITS_PER_UNIT)
+ return NULL_TREE;
+ }
inner_offset = 0;
bufoff += len;
@@ -8072,8 +8089,23 @@ fold_array_ctor_reference (tree type, tr
return native_interpret_expr (type, buf, size / BITS_PER_UNIT);
}
- if (tree val = get_array_ctor_element_at_index (ctor, access_index))
+ unsigned ctor_idx;
+ if (tree val = get_array_ctor_element_at_index (ctor, access_index,
+ &ctor_idx))
{
+ if (TREE_CODE (val) == RAW_DATA_CST)
+ {
+ if (size != BITS_PER_UNIT || elt_sz != 1 || inner_offset != 0)
+ return NULL_TREE;
+ constructor_elt *elt = CONSTRUCTOR_ELT (ctor, ctor_idx);
+ if (elt->index == NULL_TREE || TREE_CODE (elt->index) != INTEGER_CST)
+ return NULL_TREE;
+ *suboff += access_index.to_uhwi () * BITS_PER_UNIT;
+ unsigned o = (access_index - wi::to_offset (elt->index)).to_uhwi ();
+ return build_int_cst (TREE_TYPE (val),
+ ((const unsigned char *)
+ RAW_DATA_POINTER (val))[o]);
+ }
if (!size && TREE_CODE (val) != CONSTRUCTOR)
{
/* For the final reference to the entire accessed element
@@ -3182,6 +3182,11 @@ const_hash_1 (const tree exp)
return hi;
}
+ case RAW_DATA_CST:
+ p = RAW_DATA_POINTER (exp);
+ len = RAW_DATA_LENGTH (exp);
+ break;
+
case CONSTRUCTOR:
{
unsigned HOST_WIDE_INT idx;
@@ -4875,6 +4880,7 @@ initializer_constant_valid_p_1 (tree val
case FIXED_CST:
case STRING_CST:
case COMPLEX_CST:
+ case RAW_DATA_CST:
return null_pointer_node;
case ADDR_EXPR:
@@ -5468,6 +5474,9 @@ array_size_for_constructor (tree val)
{
if (TREE_CODE (index) == RANGE_EXPR)
index = TREE_OPERAND (index, 1);
+ if (value && TREE_CODE (value) == RAW_DATA_CST)
+ index = size_binop (PLUS_EXPR, index,
+ size_int (RAW_DATA_LENGTH (value) - 1));
if (max_index == NULL_TREE || tree_int_cst_lt (max_index, index))
max_index = index;
}
@@ -5659,6 +5668,12 @@ output_constructor_regular_field (oc_loc
/* Output the element's initial value. */
if (local->val == NULL_TREE)
assemble_zeros (fieldsize);
+ else if (local->val && TREE_CODE (local->val) == RAW_DATA_CST)
+ {
+ fieldsize *= RAW_DATA_LENGTH (local->val);
+ assemble_string (RAW_DATA_POINTER (local->val),
+ RAW_DATA_LENGTH (local->val));
+ }
else
fieldsize = output_constant (local->val, fieldsize, align2,
local->reverse, false);
@@ -7144,6 +7144,13 @@ categorize_ctor_elements_1 (const_tree c
init_elts += mult * TREE_STRING_LENGTH (value);
break;
+ case RAW_DATA_CST:
+ nz_elts += mult * RAW_DATA_LENGTH (value);
+ unique_nz_elts += RAW_DATA_LENGTH (value);
+ init_elts += mult * RAW_DATA_LENGTH (value);
+ num_fields += mult * (RAW_DATA_LENGTH (value) - 1);
+ break;
+
case COMPLEX_CST:
if (!initializer_zerop (TREE_REALPART (value)))
{
@@ -11788,7 +11795,8 @@ expand_expr_real_1 (tree exp, rtx target
field, value)
if (tree_int_cst_equal (field, index))
{
- if (!TREE_SIDE_EFFECTS (value))
+ if (!TREE_SIDE_EFFECTS (value)
+ && TREE_CODE (value) != RAW_DATA_CST)
return expand_expr (fold (value), target, tmode, modifier);
break;
}
@@ -11830,7 +11838,8 @@ expand_expr_real_1 (tree exp, rtx target
field, value)
if (tree_int_cst_equal (field, index))
{
- if (TREE_SIDE_EFFECTS (value))
+ if (TREE_SIDE_EFFECTS (value)
+ || TREE_CODE (value) == RAW_DATA_CST)
break;
if (TREE_CODE (value) == CONSTRUCTOR)
@@ -11847,8 +11856,8 @@ expand_expr_real_1 (tree exp, rtx target
break;
}
- return
- expand_expr (fold (value), target, tmode, modifier);
+ return expand_expr (fold (value), target, tmode,
+ modifier);
}
}
else if (TREE_CODE (init) == STRING_CST)
@@ -60,6 +60,7 @@ streamer_check_handled_ts_structures (vo
handled_p[TS_FIXED_CST] = true;
handled_p[TS_VECTOR] = true;
handled_p[TS_STRING] = true;
+ handled_p[TS_RAW_DATA_CST] = true;
handled_p[TS_COMPLEX] = true;
handled_p[TS_IDENTIFIER] = true;
handled_p[TS_DECL_MINIMAL] = true;
@@ -633,6 +633,19 @@ streamer_alloc_tree (class lto_input_blo
= (enum omp_clause_code) streamer_read_uhwi (ib);
return build_omp_clause (UNKNOWN_LOCATION, subcode);
}
+ else if (code == RAW_DATA_CST)
+ {
+ unsigned HOST_WIDE_INT len = streamer_read_uhwi (ib);
+ if (len == 0)
+ result = streamer_read_string_cst (data_in, ib);
+ else
+ {
+ unsigned HOST_WIDE_INT off = streamer_read_uhwi (ib);
+ result = make_node (code);
+ RAW_DATA_LENGTH (result) = len;
+ RAW_DATA_POINTER (result) = (const char *) (uintptr_t) off;
+ }
+ }
else
{
/* For all other nodes, materialize the tree with a raw
@@ -1016,6 +1029,22 @@ lto_input_ts_constructor_tree_pointers (
}
+/* Read all pointer fields in the TS_RAW_DATA_CST structure of EXPR from
+ input block IB. DATA_IN contains tables and descriptors for the
+ file being read. */
+
+static void
+lto_input_ts_raw_data_cst_tree_pointers (class lto_input_block *ib,
+ class data_in *data_in, tree expr)
+{
+ RAW_DATA_OWNER (expr) = stream_read_tree_ref (ib, data_in);
+ gcc_checking_assert (RAW_DATA_OWNER (expr)
+ && TREE_CODE (RAW_DATA_OWNER (expr)) == STRING_CST);
+ RAW_DATA_POINTER (expr) = (TREE_STRING_POINTER (RAW_DATA_OWNER (expr))
+ + (uintptr_t) RAW_DATA_POINTER (expr));
+}
+
+
/* Read all pointer fields in the TS_OMP_CLAUSE structure of EXPR from
input block IB. DATA_IN contains tables and descriptors for the
file being read. */
@@ -1097,6 +1126,9 @@ streamer_read_tree_body (class lto_input
if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
lto_input_ts_constructor_tree_pointers (ib, data_in, expr);
+ if (code == RAW_DATA_CST)
+ lto_input_ts_raw_data_cst_tree_pointers (ib, data_in, expr);
+
if (code == OMP_CLAUSE)
lto_input_ts_omp_clause_tree_pointers (ib, data_in, expr);
}
@@ -862,6 +862,19 @@ write_ts_constructor_tree_pointers (stru
}
+/* Write all pointer fields in the RAW_DATA_CST/TS_RAW_DATA_CST structure of
+ EXPR to output block OB. */
+
+static void
+write_ts_raw_data_cst_tree_pointers (struct output_block *ob, tree expr)
+{
+ /* Only write this for non-NULL RAW_DATA_OWNER. RAW_DATA_CST with
+ NULL RAW_DATA_OWNER is streamed to be read back as STRING_CST. */
+ if (RAW_DATA_OWNER (expr) != NULL_TREE)
+ stream_write_tree_ref (ob, RAW_DATA_OWNER (expr));
+}
+
+
/* Write all pointer fields in the TS_OMP_CLAUSE structure of EXPR
to output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
@@ -955,6 +968,9 @@ streamer_write_tree_body (struct output_
if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
write_ts_constructor_tree_pointers (ob, expr);
+ if (code == RAW_DATA_CST)
+ write_ts_raw_data_cst_tree_pointers (ob, expr);
+
if (code == OMP_CLAUSE)
write_ts_omp_clause_tree_pointers (ob, expr);
}
@@ -1010,6 +1026,35 @@ streamer_write_tree_header (struct outpu
streamer_write_uhwi (ob, call_expr_nargs (expr));
else if (TREE_CODE (expr) == OMP_CLAUSE)
streamer_write_uhwi (ob, OMP_CLAUSE_CODE (expr));
+ else if (TREE_CODE (expr) == RAW_DATA_CST)
+ {
+ if (RAW_DATA_OWNER (expr) == NULL_TREE)
+ {
+ /* RAW_DATA_CST with NULL RAW_DATA_OWNER is an owner of other
+ RAW_DATA_CST's data. This should be streamed out so that
+ it can be streamed back in as a STRING_CST instead, but without
+ the need to duplicate the possibly large data. */
+ streamer_write_uhwi (ob, 0);
+ streamer_write_string_with_length (ob, ob->main_stream,
+ RAW_DATA_POINTER (expr),
+ RAW_DATA_LENGTH (expr), true);
+ }
+ else
+ {
+ streamer_write_uhwi (ob, RAW_DATA_LENGTH (expr));
+ tree owner = RAW_DATA_OWNER (expr);
+ unsigned HOST_WIDE_INT off;
+ if (TREE_CODE (owner) == STRING_CST)
+ off = RAW_DATA_POINTER (expr) - TREE_STRING_POINTER (owner);
+ else
+ {
+ gcc_checking_assert (TREE_CODE (owner) == RAW_DATA_CST
+ && RAW_DATA_OWNER (owner) == NULL_TREE);
+ off = RAW_DATA_POINTER (expr) - RAW_DATA_POINTER (owner);
+ }
+ streamer_write_uhwi (ob, off);
+ }
+ }
else if (CODE_CONTAINS_STRUCT (code, TS_INT_CST))
{
gcc_checking_assert (TREE_INT_CST_NUNITS (expr));
@@ -1161,6 +1161,9 @@ DFS::DFS_write_tree_body (struct output_
}
}
+ if (code == RAW_DATA_CST)
+ DFS_follow_tree_edge (RAW_DATA_OWNER (expr));
+
if (code == OMP_CLAUSE)
{
int i;
@@ -2519,6 +2519,28 @@ dump_generic_node (pretty_printer *pp, t
}
break;
+ case RAW_DATA_CST:
+ for (unsigned i = 0; i < (unsigned) RAW_DATA_LENGTH (node); ++i)
+ {
+ if (TYPE_UNSIGNED (TREE_TYPE (node))
+ || TYPE_PRECISION (TREE_TYPE (node)) > CHAR_BIT)
+ pp_decimal_int (pp, ((const unsigned char *)
+ RAW_DATA_POINTER (node))[i]);
+ else
+ pp_decimal_int (pp, ((const signed char *)
+ RAW_DATA_POINTER (node))[i]);
+ if (i == RAW_DATA_LENGTH (node) - 1U)
+ break;
+ else if (i == 9 && RAW_DATA_LENGTH (node) > 20)
+ {
+ pp_string (pp, ", ..., ");
+ i = RAW_DATA_LENGTH (node) - 11;
+ }
+ else
+ pp_string (pp, ", ");
+ }
+ break;
+
case FUNCTION_TYPE:
case METHOD_TYPE:
dump_generic_node (pp, TREE_TYPE (node), spc, flags, false);
@@ -299,6 +299,60 @@ token_streamer::stream (cpp_reader *pfil
maybe_print_line (UNKNOWN_LOCATION);
in_pragma = false;
}
+ else if (token->type == CPP_EMBED)
+ {
+ char buf[76 + 6];
+ maybe_print_line (token->src_loc);
+ gcc_checking_assert (token->val.str.len != 0);
+ fputs ("#embed \".\" __gnu__::__base64__(", print.outf);
+ if (token->val.str.len > 30)
+ {
+ fputs (" \\\n", print.outf);
+ print.src_line++;
+ }
+ buf[0] = '"';
+ memcpy (buf + 1 + 76, "\" \\\n", 5);
+ unsigned int j = 1;
+ static const char base64_enc[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ for (unsigned i = 0; ; i += 3)
+ {
+ unsigned char a = token->val.str.text[i];
+ unsigned char b = 0, c = 0;
+ unsigned int n = token->val.str.len - i;
+ if (n > 1)
+ b = token->val.str.text[i + 1];
+ if (n > 2)
+ c = token->val.str.text[i + 2];
+ unsigned long v = ((((unsigned long) a) << 16)
+ | (((unsigned long) b) << 8)
+ | c);
+ buf[j++] = base64_enc[(v >> 18) & 63];
+ buf[j++] = base64_enc[(v >> 12) & 63];
+ buf[j++] = base64_enc[(v >> 6) & 63];
+ buf[j++] = base64_enc[v & 63];
+ if (j == 76 + 1 || n <= 3)
+ {
+ if (n < 3)
+ {
+ buf[j - 1] = '=';
+ if (n == 1)
+ buf[j - 2] = '=';
+ }
+ if (n <= 3)
+ memcpy (buf + j, "\")", 3);
+ else
+ print.src_line++;
+ fputs (buf, print.outf);
+ j = 1;
+ if (n <= 3)
+ break;
+ }
+ }
+ print.printed = true;
+ maybe_print_line (token->src_loc);
+ return;
+ }
else
{
if (cpp_get_options (parse_in)->debug)
@@ -781,6 +781,48 @@ c_lex_with_flags (tree *value, location_
*value = build_string (tok->val.str.len, (const char *)tok->val.str.text);
break;
+ case CPP_EMBED:
+ *value = make_node (RAW_DATA_CST);
+ TREE_TYPE (*value) = integer_type_node;
+ RAW_DATA_LENGTH (*value) = tok->val.str.len;
+ if (pch_file)
+ {
+ /* When writing PCH headers, copy the data over, such that
+ the owner is a STRING_CST. */
+ int off = 0;
+ if (tok->val.str.len <= INT_MAX - 2)
+ /* See below. */
+ off = 1;
+ tree owner = build_string (tok->val.str.len + 2 * off,
+ (const char *) tok->val.str.text - off);
+ TREE_TYPE (owner) = build_array_type_nelts (unsigned_char_type_node,
+ tok->val.str.len);
+ RAW_DATA_OWNER (*value) = owner;
+ RAW_DATA_POINTER (*value) = TREE_STRING_POINTER (owner) + off;
+ }
+ else
+ {
+ /* Otherwise add another dummy RAW_DATA_CST as owner which
+ indicates the data is owned by libcpp. */
+ RAW_DATA_POINTER (*value) = (const char *) tok->val.str.text;
+ tree owner = make_node (RAW_DATA_CST);
+ TREE_TYPE (owner) = integer_type_node;
+ RAW_DATA_LENGTH (owner) = tok->val.str.len;
+ RAW_DATA_POINTER (owner) = (const char *) tok->val.str.text;
+ if (tok->val.str.len <= INT_MAX - 2)
+ {
+ /* The preprocessor surrounds at least smaller CPP_EMBEDs
+ in between CPP_NUMBER CPP_COMMA before and
+ CPP_COMMA CPP_NUMBER after, so the actual libcpp buffer
+ holds those 2 extra bytes around it. Don't do that if
+ CPP_EMBED is at the maximum ~ 2GB size. */
+ RAW_DATA_LENGTH (owner) += 2;
+ RAW_DATA_POINTER (owner)--;
+ }
+ RAW_DATA_OWNER (*value) = owner;
+ }
+ break;
+
/* This token should not be visible outside cpplib. */
case CPP_MACRO_ARG:
gcc_unreachable ();
@@ -800,7 +842,7 @@ c_lex_with_flags (tree *value, location_
add_flags |= PREV_FALLTHROUGH;
goto retry_after_at;
}
- goto retry;
+ goto retry;
default:
*value = NULL_TREE;
@@ -6759,6 +6759,8 @@ c_parse_error (const char *gmsgid, enum
message = catenate_messages (gmsgid, " before end of line");
else if (token_type == CPP_DECLTYPE)
message = catenate_messages (gmsgid, " before %<decltype%>");
+ else if (token_type == CPP_EMBED)
+ message = catenate_messages (gmsgid, " before %<#embed%>");
else if (token_type < N_TTYPES)
{
message = catenate_messages (gmsgid, " before %qs token");
@@ -9768,7 +9770,9 @@ maybe_add_include_fixit (rich_location *
/* Attempt to convert a braced array initializer list CTOR for array
TYPE into a STRING_CST for convenience and efficiency. Return
- the converted string on success or the original ctor on failure. */
+ the converted string on success or the original ctor on failure.
+ Also, for non-convertable CTORs which contain RAW_DATA_CST values
+ among the elts try to extend the range of RAW_DATA_CSTs. */
static tree
braced_list_to_string (tree type, tree ctor, bool member)
@@ -9812,26 +9816,155 @@ braced_list_to_string (tree type, tree c
auto_vec<char> str;
str.reserve (nelts + 1);
- unsigned HOST_WIDE_INT i;
+ unsigned HOST_WIDE_INT i, j = HOST_WIDE_INT_M1U;
tree index, value;
+ bool check_raw_data = false;
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), i, index, value)
{
+ if (check_raw_data)
+ {
+ /* The preprocessor always surrounds CPP_EMBED tokens in between
+ CPP_NUMBER and CPP_COMMA tokens. Try to undo that here now that
+ the whole initializer is parsed. E.g. if we have
+ [0] = 'T', [1] = "his is a #embed tex", [20] = 't'
+ where the middle value is RAW_DATA_CST and in its owner this is
+ surrounded by 'T' and 't' characters, we can create from it just
+ [0] = "This is a #embed text"
+ Similarly if a RAW_DATA_CST needs to be split into two parts
+ because of designated init store but the stored value is actually
+ the same as in the RAW_DATA_OWNER's memory we can merge multiple
+ RAW_DATA_CSTs. */
+ if (TREE_CODE (value) == RAW_DATA_CST
+ && index
+ && tree_fits_uhwi_p (index))
+ {
+ tree owner = RAW_DATA_OWNER (value);
+ unsigned int start, end, k;
+ if (TREE_CODE (owner) == STRING_CST)
+ {
+ start
+ = RAW_DATA_POINTER (value) - TREE_STRING_POINTER (owner);
+ end = TREE_STRING_LENGTH (owner) - RAW_DATA_LENGTH (value);
+ }
+ else
+ {
+ gcc_checking_assert (TREE_CODE (owner) == RAW_DATA_CST);
+ start
+ = RAW_DATA_POINTER (value) - RAW_DATA_POINTER (owner);
+ end = RAW_DATA_LENGTH (owner) - RAW_DATA_LENGTH (value);
+ }
+ end -= start;
+ unsigned HOST_WIDE_INT l = j == HOST_WIDE_INT_M1U ? i : j;
+ for (k = 0; k < start && k < l; ++k)
+ {
+ constructor_elt *elt = CONSTRUCTOR_ELT (ctor, l - k - 1);
+ if (elt->index == NULL_TREE
+ || !tree_fits_uhwi_p (elt->index)
+ || !tree_fits_shwi_p (elt->value)
+ || wi::to_widest (index) != (wi::to_widest (elt->index)
+ + (k + 1)))
+ break;
+ if (TYPE_UNSIGNED (TREE_TYPE (value)))
+ {
+ if (tree_to_shwi (elt->value)
+ != *((const unsigned char *)
+ RAW_DATA_POINTER (value) - k - 1))
+ break;
+ }
+ else if (tree_to_shwi (elt->value)
+ != *((const signed char *)
+ RAW_DATA_POINTER (value) - k - 1))
+ break;
+ }
+ start = k;
+ l = 0;
+ for (k = 0; k < end && k + 1 < CONSTRUCTOR_NELTS (ctor) - i; ++k)
+ {
+ constructor_elt *elt = CONSTRUCTOR_ELT (ctor, i + k + 1);
+ if (elt->index == NULL_TREE
+ || !tree_fits_uhwi_p (elt->index)
+ || (wi::to_widest (elt->index)
+ != (wi::to_widest (index)
+ + (RAW_DATA_LENGTH (value) + l))))
+ break;
+ if (TREE_CODE (elt->value) == RAW_DATA_CST
+ && RAW_DATA_OWNER (elt->value) == RAW_DATA_OWNER (value)
+ && (RAW_DATA_POINTER (elt->value)
+ == RAW_DATA_POINTER (value) + l))
+ {
+ l += RAW_DATA_LENGTH (elt->value);
+ end -= RAW_DATA_LENGTH (elt->value) - 1;
+ continue;
+ }
+ if (!tree_fits_shwi_p (elt->value))
+ break;
+ if (TYPE_UNSIGNED (TREE_TYPE (value)))
+ {
+ if (tree_to_shwi (elt->value)
+ != *((const unsigned char *)
+ RAW_DATA_POINTER (value)
+ + RAW_DATA_LENGTH (value) + k))
+ break;
+ }
+ else if (tree_to_shwi (elt->value)
+ != *((const signed char *)
+ RAW_DATA_POINTER (value)
+ + RAW_DATA_LENGTH (value) + k))
+ break;
+ ++l;
+ }
+ end = k;
+ if (start != 0 || end != 0)
+ {
+ if (j == HOST_WIDE_INT_M1U)
+ j = i - start;
+ else
+ j -= start;
+ RAW_DATA_POINTER (value) -= start;
+ RAW_DATA_LENGTH (value) += start + end;
+ i += end;
+ if (start == 0)
+ CONSTRUCTOR_ELT (ctor, j)->index = index;
+ CONSTRUCTOR_ELT (ctor, j)->value = value;
+ ++j;
+ continue;
+ }
+ }
+ if (j != HOST_WIDE_INT_M1U)
+ {
+ CONSTRUCTOR_ELT (ctor, j)->index = index;
+ CONSTRUCTOR_ELT (ctor, j)->value = value;
+ ++j;
+ }
+ continue;
+ }
+
unsigned HOST_WIDE_INT idx = i;
if (index)
{
if (!tree_fits_uhwi_p (index))
- return ctor;
+ {
+ check_raw_data = true;
+ continue;
+ }
idx = tree_to_uhwi (index);
}
/* auto_vec is limited to UINT_MAX elements. */
if (idx > UINT_MAX)
- return ctor;
+ {
+ check_raw_data = true;
+ continue;
+ }
- /* Avoid non-constant initializers. */
- if (!tree_fits_shwi_p (value))
- return ctor;
+ /* Avoid non-constant initializers. */
+ if (!tree_fits_shwi_p (value))
+ {
+ check_raw_data = true;
+ --i;
+ continue;
+ }
/* Skip over embedded nuls except the last one (initializer
elements are in ascending order of indices). */
@@ -9839,14 +9972,20 @@ braced_list_to_string (tree type, tree c
if (!val && i + 1 < nelts)
continue;
- if (idx < str.length())
- return ctor;
+ if (idx < str.length ())
+ {
+ check_raw_data = true;
+ continue;
+ }
/* Bail if the CTOR has a block of more than 256 embedded nuls
due to implicitly initialized elements. */
unsigned nchars = (idx - str.length ()) + 1;
if (nchars > 256)
- return ctor;
+ {
+ check_raw_data = true;
+ continue;
+ }
if (nchars > 1)
{
@@ -9855,11 +9994,21 @@ braced_list_to_string (tree type, tree c
}
if (idx >= maxelts)
- return ctor;
+ {
+ check_raw_data = true;
+ continue;
+ }
str.safe_insert (idx, val);
}
+ if (check_raw_data)
+ {
+ if (j != HOST_WIDE_INT_M1U)
+ CONSTRUCTOR_ELTS (ctor)->truncate (j);
+ return ctor;
+ }
+
/* Append a nul string termination. */
if (maxelts != HOST_WIDE_INT_M1U && str.length () < maxelts)
str.safe_push (0);
@@ -6212,6 +6212,25 @@ c_parser_braced_init (c_parser *parser,
{
last_init_list_comma = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
+ /* CPP_EMBED should be always in between two CPP_COMMA
+ tokens. */
+ while (c_parser_next_token_is (parser, CPP_EMBED))
+ {
+ c_token *embed = c_parser_peek_token (parser);
+ c_parser_consume_token (parser);
+ c_expr embed_val;
+ embed_val.value = embed->value;
+ embed_val.original_code = RAW_DATA_CST;
+ embed_val.original_type = integer_type_node;
+ set_c_expr_source_range (&embed_val, embed->get_range ());
+ embed_val.m_decimal = 0;
+ process_init_element (embed->location, embed_val, false,
+ &braced_init_obstack);
+ gcc_checking_assert (c_parser_next_token_is (parser,
+ CPP_COMMA));
+ last_init_list_comma = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ }
}
else
break;
@@ -12870,8 +12889,27 @@ c_parser_expression (c_parser *parser)
}
if (DECL_P (lhsval) || handled_component_p (lhsval))
mark_exp_read (lhsval);
- next = c_parser_expr_no_commas (parser, NULL);
- next = convert_lvalue_to_rvalue (expr_loc, next, true, false);
+ if (c_parser_next_token_is (parser, CPP_EMBED))
+ {
+ /* Users aren't interested in milions of -Wunused-value
+ warnings when using #embed inside of a comma expression,
+ and one CPP_NUMBER plus CPP_COMMA before it and one
+ CPP_COMMA plus CPP_NUMBER after it is guaranteed by
+ the preprocessor. Thus, parse the whole CPP_EMBED just
+ as a single INTEGER_CST, the last byte in it. */
+ c_token *embed = c_parser_peek_token (parser);
+ tree val = embed->value;
+ unsigned last = RAW_DATA_LENGTH (val) - 1;
+ next.value = build_int_cst (TREE_TYPE (val),
+ ((const unsigned char *)
+ RAW_DATA_POINTER (val))[last]);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ next = c_parser_expr_no_commas (parser, NULL);
+ next = convert_lvalue_to_rvalue (expr_loc, next, true, false);
+ }
expr.value = build_compound_expr (loc, expr.value, next.value);
expr.original_code = COMPOUND_EXPR;
expr.original_type = next.original_type;
@@ -12976,6 +13014,34 @@ c_parser_expr_list (c_parser *parser, bo
while (c_parser_next_token_is (parser, CPP_COMMA))
{
c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_EMBED))
+ {
+ c_token *embed = c_parser_peek_token (parser);
+ tree value = embed->value;
+ expr.original_code = INTEGER_CST;
+ expr.original_type = integer_type_node;
+ expr.value = NULL_TREE;
+ set_c_expr_source_range (&expr, embed->get_range ());
+ expr.m_decimal = 0;
+ for (unsigned int i = 0; i < (unsigned) RAW_DATA_LENGTH (value); i++)
+ {
+ if (literal_zero_mask
+ && idx + 1 < HOST_BITS_PER_INT
+ && RAW_DATA_POINTER (value)[i] == 0)
+ *literal_zero_mask |= 1U << (idx + 1);
+ expr.value = build_int_cst (integer_type_node,
+ ((const unsigned char *)
+ RAW_DATA_POINTER (value))[i]);
+ vec_safe_push (ret, expr.value);
+ if (orig_types)
+ vec_safe_push (orig_types, expr.original_type);
+ if (locations)
+ locations->safe_push (expr.get_location ());
+ ++idx;
+ }
+ c_parser_consume_token (parser);
+ continue;
+ }
if (literal_zero_mask)
c_parser_check_literal_zero (parser, literal_zero_mask, idx + 1);
expr = c_parser_expr_no_commas (parser, NULL);
@@ -8747,12 +8747,13 @@ digest_init (location_t init_loc, tree t
if (!maybe_const)
arith_const_expr = false;
else if (!INTEGRAL_TYPE_P (TREE_TYPE (inside_init))
- && TREE_CODE (TREE_TYPE (inside_init)) != REAL_TYPE
- && TREE_CODE (TREE_TYPE (inside_init)) != COMPLEX_TYPE)
+ && TREE_CODE (TREE_TYPE (inside_init)) != REAL_TYPE
+ && TREE_CODE (TREE_TYPE (inside_init)) != COMPLEX_TYPE)
arith_const_expr = false;
else if (TREE_CODE (inside_init) != INTEGER_CST
- && TREE_CODE (inside_init) != REAL_CST
- && TREE_CODE (inside_init) != COMPLEX_CST)
+ && TREE_CODE (inside_init) != REAL_CST
+ && TREE_CODE (inside_init) != COMPLEX_CST
+ && TREE_CODE (inside_init) != RAW_DATA_CST)
arith_const_expr = false;
else if (TREE_OVERFLOW (inside_init))
arith_const_expr = false;
@@ -9013,6 +9014,22 @@ digest_init (location_t init_loc, tree t
? ic_init_const
: ic_init), null_pointer_constant,
NULL_TREE, NULL_TREE, 0);
+ if (TREE_CODE (inside_init) == RAW_DATA_CST
+ && c_inhibit_evaluation_warnings == 0
+ && warn_overflow
+ && !TYPE_UNSIGNED (type)
+ && TYPE_PRECISION (type) == CHAR_BIT)
+ for (unsigned int i = 0;
+ i < (unsigned) RAW_DATA_LENGTH (inside_init); ++i)
+ if (((const signed char *) RAW_DATA_POINTER (inside_init))[i] < 0)
+ warning_at (init_loc, OPT_Wconversion,
+ "conversion from %qT to %qT changes value from "
+ "%qd to %qd",
+ integer_type_node, type,
+ ((const unsigned char *)
+ RAW_DATA_POINTER (inside_init))[i],
+ ((const signed char *)
+ RAW_DATA_POINTER (inside_init))[i]);
return inside_init;
}
@@ -10124,6 +10141,28 @@ set_init_label (location_t loc, tree fie
while (field != NULL_TREE);
}
+/* Helper function for add_pending_init. Find inorder successor of P
+ in AVL tree. */
+static struct init_node *
+init_node_successor (struct init_node *p)
+{
+ struct init_node *r;
+ if (p->right)
+ {
+ r = p->right;
+ while (r->left)
+ r = r->left;
+ return r;
+ }
+ r = p->parent;
+ while (r && p == r->right)
+ {
+ p = r;
+ r = r->parent;
+ }
+ return r;
+}
+
/* Add a new initializer to the tree of pending initializers. PURPOSE
identifies the initializer, either array index or field in a structure.
VALUE is the value of that index or field. If ORIGTYPE is not
@@ -10151,9 +10190,179 @@ add_pending_init (location_t loc, tree p
if (tree_int_cst_lt (purpose, p->purpose))
q = &p->left;
else if (tree_int_cst_lt (p->purpose, purpose))
- q = &p->right;
+ {
+ if (TREE_CODE (p->value) != RAW_DATA_CST
+ || (p->right
+ && tree_int_cst_le (p->right->purpose, purpose)))
+ q = &p->right;
+ else
+ {
+ widest_int pp = wi::to_widest (p->purpose);
+ widest_int pw = wi::to_widest (purpose);
+ if (pp + RAW_DATA_LENGTH (p->value) <= pw)
+ q = &p->right;
+ else
+ {
+ /* Override which should split the old RAW_DATA_CST
+ into 2 or 3 pieces. */
+ if (!implicit && warn_override_init)
+ warning_init (loc, OPT_Woverride_init,
+ "initialized field overwritten");
+ unsigned HOST_WIDE_INT start = (pw - pp).to_uhwi ();
+ unsigned HOST_WIDE_INT len = 1;
+ if (TREE_CODE (value) == RAW_DATA_CST)
+ len = RAW_DATA_LENGTH (value);
+ unsigned HOST_WIDE_INT end = 0;
+ unsigned plen = RAW_DATA_LENGTH (p->value);
+ gcc_checking_assert (start < plen && start);
+ if (plen - start > len)
+ end = plen - start - len;
+ tree v = p->value;
+ tree origtype = p->origtype;
+ if (start == 1)
+ p->value = build_int_cst (TREE_TYPE (v),
+ *(const unsigned char *)
+ RAW_DATA_POINTER (v));
+ else
+ {
+ p->value = v;
+ if (end > 1)
+ v = copy_node (v);
+ RAW_DATA_LENGTH (p->value) = start;
+ }
+ if (end)
+ {
+ tree epurpose
+ = size_binop (PLUS_EXPR, purpose,
+ bitsize_int (len));
+ if (end > 1)
+ {
+ RAW_DATA_LENGTH (v) -= plen - end;
+ RAW_DATA_POINTER (v) += plen - end;
+ }
+ else
+ v = build_int_cst (TREE_TYPE (v),
+ ((const unsigned char *)
+ RAW_DATA_POINTER (v))[plen
+ - end]);
+ add_pending_init (loc, epurpose, v, origtype,
+ implicit, braced_init_obstack);
+ }
+ q = &constructor_pending_elts;
+ continue;
+ }
+ }
+ }
else
{
+ if (TREE_CODE (p->value) == RAW_DATA_CST
+ && (RAW_DATA_LENGTH (p->value)
+ > (TREE_CODE (value) == RAW_DATA_CST
+ ? RAW_DATA_LENGTH (value) : 1)))
+ {
+ /* Override which should split the old RAW_DATA_CST
+ into 2 pieces. */
+ if (!implicit && warn_override_init)
+ warning_init (loc, OPT_Woverride_init,
+ "initialized field overwritten");
+ unsigned HOST_WIDE_INT len = 1;
+ if (TREE_CODE (value) == RAW_DATA_CST)
+ len = RAW_DATA_LENGTH (value);
+ if ((unsigned) RAW_DATA_LENGTH (p->value) > len + 1)
+ {
+ RAW_DATA_LENGTH (p->value) -= len;
+ RAW_DATA_POINTER (p->value) += len;
+ }
+ else
+ {
+ unsigned int l = RAW_DATA_LENGTH (p->value) - 1;
+ p->value
+ = build_int_cst (TREE_TYPE (p->value),
+ ((const unsigned char *)
+ RAW_DATA_POINTER (p->value))[l]);
+ }
+ p->purpose = size_binop (PLUS_EXPR, p->purpose,
+ bitsize_int (len));
+ continue;
+ }
+ if (TREE_CODE (value) == RAW_DATA_CST)
+ {
+ handle_raw_data:
+ /* RAW_DATA_CST value might overlap various further
+ prior initval entries. Find out how many. */
+ unsigned cnt = 0;
+ widest_int w
+ = wi::to_widest (purpose) + RAW_DATA_LENGTH (value);
+ struct init_node *r = p, *last = NULL;
+ bool override_init = warn_override_init;
+ while ((r = init_node_successor (r))
+ && wi::to_widest (r->purpose) < w)
+ {
+ ++cnt;
+ if (TREE_SIDE_EFFECTS (r->value))
+ warning_init (loc, OPT_Woverride_init_side_effects,
+ "initialized field with side-effects "
+ "overwritten");
+ else if (override_init)
+ {
+ warning_init (loc, OPT_Woverride_init,
+ "initialized field overwritten");
+ override_init = false;
+ }
+ last = r;
+ }
+ if (cnt)
+ {
+ if (TREE_CODE (last->value) == RAW_DATA_CST
+ && (wi::to_widest (last->purpose)
+ + RAW_DATA_LENGTH (last->value) > w))
+ {
+ /* The last overlapping prior initval overlaps
+ only partially. Shrink it and decrease cnt. */
+ unsigned int l = (wi::to_widest (last->purpose)
+ + RAW_DATA_LENGTH (last->value)
+ - w).to_uhwi ();
+ --cnt;
+ RAW_DATA_LENGTH (last->value) -= l;
+ RAW_DATA_POINTER (last->value) += l;
+ if (RAW_DATA_LENGTH (last->value) == 1)
+ {
+ const unsigned char *s
+ = ((const unsigned char *)
+ RAW_DATA_POINTER (last->value));
+ last->value
+ = build_int_cst (TREE_TYPE (last->value), *s);
+ }
+ last->purpose
+ = size_binop (PLUS_EXPR, last->purpose,
+ bitsize_int (l));
+ }
+ /* Instead of deleting cnt nodes from the AVL tree
+ and rebalancing, peel of last cnt bytes from the
+ RAW_DATA_CST. Overriding thousands of previously
+ initialized array elements with #embed needs to work,
+ but doesn't need to be super efficient. */
+ gcc_checking_assert ((unsigned) RAW_DATA_LENGTH (value)
+ > cnt);
+ RAW_DATA_LENGTH (value) -= cnt;
+ const unsigned char *s
+ = ((const unsigned char *) RAW_DATA_POINTER (value)
+ + RAW_DATA_LENGTH (value));
+ unsigned int o = RAW_DATA_LENGTH (value);
+ for (r = p; cnt--; ++o, ++s)
+ {
+ r = init_node_successor (r);
+ r->purpose = size_binop (PLUS_EXPR, purpose,
+ bitsize_int (o));
+ r->value = build_int_cst (TREE_TYPE (value), *s);
+ r->origtype = origtype;
+ }
+ if (RAW_DATA_LENGTH (value) == 1)
+ value = build_int_cst (TREE_TYPE (value),
+ *((const unsigned char *)
+ RAW_DATA_POINTER (value)));
+ }
+ }
if (!implicit)
{
if (TREE_SIDE_EFFECTS (p->value))
@@ -10169,6 +10378,23 @@ add_pending_init (location_t loc, tree p
return;
}
}
+ if (TREE_CODE (value) == RAW_DATA_CST && p)
+ {
+ struct init_node *r;
+ if (q == &p->left)
+ r = p;
+ else
+ r = init_node_successor (p);
+ if (r && wi::to_widest (r->purpose) < (wi::to_widest (purpose)
+ + RAW_DATA_LENGTH (value)))
+ {
+ /* Overlap with at least one prior initval in the range but
+ not at the start. */
+ p = r;
+ p->purpose = purpose;
+ goto handle_raw_data;
+ }
+ }
}
else
{
@@ -10397,8 +10623,8 @@ set_nonincremental_init (struct obstack
{
if (TYPE_DOMAIN (constructor_type))
constructor_unfilled_index
- = convert (bitsizetype,
- TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
+ = convert (bitsizetype,
+ TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
else
constructor_unfilled_index = bitsize_zero_node;
}
@@ -10612,12 +10838,13 @@ output_init_element (location_t loc, tre
if (!maybe_const)
arith_const_expr = false;
else if (!INTEGRAL_TYPE_P (TREE_TYPE (value))
- && TREE_CODE (TREE_TYPE (value)) != REAL_TYPE
- && TREE_CODE (TREE_TYPE (value)) != COMPLEX_TYPE)
+ && TREE_CODE (TREE_TYPE (value)) != REAL_TYPE
+ && TREE_CODE (TREE_TYPE (value)) != COMPLEX_TYPE)
arith_const_expr = false;
else if (TREE_CODE (value) != INTEGER_CST
- && TREE_CODE (value) != REAL_CST
- && TREE_CODE (value) != COMPLEX_CST)
+ && TREE_CODE (value) != REAL_CST
+ && TREE_CODE (value) != COMPLEX_CST
+ && TREE_CODE (value) != RAW_DATA_CST)
arith_const_expr = false;
else if (TREE_OVERFLOW (value))
arith_const_expr = false;
@@ -10722,10 +10949,16 @@ output_init_element (location_t loc, tre
put it on constructor_pending_elts. */
if (TREE_CODE (constructor_type) == ARRAY_TYPE
&& (!constructor_incremental
- || !tree_int_cst_equal (field, constructor_unfilled_index)))
+ || !tree_int_cst_equal (field, constructor_unfilled_index)
+ || (TREE_CODE (value) == RAW_DATA_CST
+ && constructor_pending_elts
+ && pending)))
{
if (constructor_incremental
- && tree_int_cst_lt (field, constructor_unfilled_index))
+ && (tree_int_cst_lt (field, constructor_unfilled_index)
+ || (TREE_CODE (value) == RAW_DATA_CST
+ && constructor_pending_elts
+ && pending)))
set_nonincremental_init (braced_init_obstack);
add_pending_init (loc, field, value, origtype, implicit,
@@ -10784,9 +11017,14 @@ output_init_element (location_t loc, tre
/* Advance the variable that indicates sequential elements output. */
if (TREE_CODE (constructor_type) == ARRAY_TYPE)
- constructor_unfilled_index
- = size_binop_loc (input_location, PLUS_EXPR, constructor_unfilled_index,
- bitsize_one_node);
+ {
+ tree inc = bitsize_one_node;
+ if (value && TREE_CODE (value) == RAW_DATA_CST)
+ inc = bitsize_int (RAW_DATA_LENGTH (value));
+ constructor_unfilled_index
+ = size_binop_loc (input_location, PLUS_EXPR,
+ constructor_unfilled_index, inc);
+ }
else if (TREE_CODE (constructor_type) == RECORD_TYPE)
{
constructor_unfilled_fields
@@ -10795,8 +11033,8 @@ output_init_element (location_t loc, tre
/* Skip any nameless bit fields. */
while (constructor_unfilled_fields != NULL_TREE
&& DECL_UNNAMED_BIT_FIELD (constructor_unfilled_fields))
- constructor_unfilled_fields =
- DECL_CHAIN (constructor_unfilled_fields);
+ constructor_unfilled_fields
+ = DECL_CHAIN (constructor_unfilled_fields);
}
else if (TREE_CODE (constructor_type) == UNION_TYPE)
constructor_unfilled_fields = NULL_TREE;
@@ -11042,6 +11280,23 @@ initialize_elementwise_p (tree type, tre
return false;
}
+/* Helper function for process_init_element. Split first element of
+ RAW_DATA_CST and save the rest to *RAW_DATA. */
+
+static inline tree
+maybe_split_raw_data (tree value, tree *raw_data)
+{
+ if (value == NULL_TREE || TREE_CODE (value) != RAW_DATA_CST)
+ return value;
+ *raw_data = value;
+ value = build_int_cst (integer_type_node,
+ *(const unsigned char *)
+ RAW_DATA_POINTER (*raw_data));
+ ++RAW_DATA_POINTER (*raw_data);
+ --RAW_DATA_LENGTH (*raw_data);
+ return value;
+}
+
/* Add one non-braced element to the current constructor level.
This adjusts the current position within the constructor's type.
This may also start or terminate implicit levels
@@ -11064,7 +11319,9 @@ process_init_element (location_t loc, st
= (orig_value != NULL_TREE && TREE_CODE (orig_value) == STRING_CST);
bool strict_string = value.original_code == STRING_CST;
bool was_designated = designator_depth != 0;
+ tree raw_data = NULL_TREE;
+retry:
designator_depth = 0;
designator_erroneous = 0;
@@ -11232,6 +11489,7 @@ process_init_element (location_t loc, st
continue;
}
+ value.value = maybe_split_raw_data (value.value, &raw_data);
if (value.value)
{
push_member_name (constructor_fields);
@@ -11320,6 +11578,7 @@ process_init_element (location_t loc, st
continue;
}
+ value.value = maybe_split_raw_data (value.value, &raw_data);
if (value.value)
{
push_member_name (constructor_fields);
@@ -11368,26 +11627,66 @@ process_init_element (location_t loc, st
break;
}
- /* Now output the actual element. */
- if (value.value)
+ if (value.value
+ && TREE_CODE (value.value) == RAW_DATA_CST
+ && RAW_DATA_LENGTH (value.value) > 1
+ && (TREE_CODE (elttype) == INTEGER_TYPE
+ || TREE_CODE (elttype) == BITINT_TYPE)
+ && TYPE_PRECISION (elttype) == CHAR_BIT
+ && (constructor_max_index == NULL_TREE
+ || tree_int_cst_lt (constructor_index,
+ constructor_max_index)))
{
+ unsigned int len = RAW_DATA_LENGTH (value.value);
+ if (constructor_max_index)
+ {
+ widest_int w = wi::to_widest (constructor_max_index);
+ w -= wi::to_widest (constructor_index);
+ w += 1;
+ if (w < len)
+ len = w.to_uhwi ();
+ }
+ if (len < (unsigned) RAW_DATA_LENGTH (value.value))
+ {
+ raw_data = copy_node (value.value);
+ RAW_DATA_LENGTH (raw_data) -= len;
+ RAW_DATA_POINTER (raw_data) += len;
+ RAW_DATA_LENGTH (value.value) = len;
+ }
+ TREE_TYPE (value.value) = elttype;
push_array_bounds (tree_to_uhwi (constructor_index));
output_init_element (loc, value.value, value.original_type,
- strict_string, elttype,
- constructor_index, true, implicit,
- braced_init_obstack);
+ false, elttype, constructor_index, true,
+ implicit, braced_init_obstack);
RESTORE_SPELLING_DEPTH (constructor_depth);
+ constructor_index
+ = size_binop_loc (input_location, PLUS_EXPR,
+ constructor_index, bitsize_int (len));
}
+ else
+ {
+ value.value = maybe_split_raw_data (value.value, &raw_data);
+ /* Now output the actual element. */
+ if (value.value)
+ {
+ push_array_bounds (tree_to_uhwi (constructor_index));
+ output_init_element (loc, value.value, value.original_type,
+ strict_string, elttype,
+ constructor_index, true, implicit,
+ braced_init_obstack);
+ RESTORE_SPELLING_DEPTH (constructor_depth);
+ }
- constructor_index
- = size_binop_loc (input_location, PLUS_EXPR,
- constructor_index, bitsize_one_node);
-
- if (!value.value)
- /* If we are doing the bookkeeping for an element that was
- directly output as a constructor, we must update
- constructor_unfilled_index. */
- constructor_unfilled_index = constructor_index;
+ constructor_index
+ = size_binop_loc (input_location, PLUS_EXPR,
+ constructor_index, bitsize_one_node);
+
+ if (!value.value)
+ /* If we are doing the bookkeeping for an element that was
+ directly output as a constructor, we must update
+ constructor_unfilled_index. */
+ constructor_unfilled_index = constructor_index;
+ }
}
else if (gnu_vector_type_p (constructor_type))
{
@@ -11402,6 +11701,7 @@ process_init_element (location_t loc, st
break;
}
+ value.value = maybe_split_raw_data (value.value, &raw_data);
/* Now output the actual element. */
if (value.value)
{
@@ -11435,6 +11735,7 @@ process_init_element (location_t loc, st
}
else
{
+ value.value = maybe_split_raw_data (value.value, &raw_data);
if (value.value)
output_init_element (loc, value.value, value.original_type,
strict_string, constructor_type,
@@ -11506,6 +11807,14 @@ process_init_element (location_t loc, st
}
constructor_range_stack = 0;
+
+ if (raw_data && RAW_DATA_LENGTH (raw_data))
+ {
+ gcc_assert (!string_flag && !was_designated);
+ value.value = raw_data;
+ raw_data = NULL_TREE;
+ goto retry;
+ }
}
/* Build a complete asm-statement, whose components are a CV_QUALIFIER
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-additional-options "-std=c23" { target c } } */
+
+unsigned char a[] = {
+#embed __FILE__
+};
+struct S { unsigned char h[(sizeof (a) - 7) / 2]; short int i; unsigned char j[sizeof (a) - 7 - (sizeof (a) - 7) / 2]; };
+struct T { int a, b, c; struct S d; long long e; double f; long long g; };
+struct T b = {
+#embed __FILE__
+};
+
+int
+main ()
+{
+ if (b.a != a[0] || b.b != a[1] || b.c != a[2]
+ || __builtin_memcmp (b.d.h, a + 3, sizeof (b.d.h))
+ || b.d.i != a[3 + sizeof (b.d.h)]
+ || __builtin_memcmp (b.d.j, a + 4 + sizeof (b.d.h), sizeof (b.d.j))
+ || b.e != a[sizeof (a) - 3] || b.f != a[sizeof (a) - 2]
+ || b.g != a[sizeof (a) - 1])
+ __builtin_abort ();
+}
@@ -0,0 +1,56 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -Wno-psabi" } */
+/* { dg-additional-options "-std=c23" { target c } } */
+
+unsigned char a[] = {
+#embed __FILE__
+};
+const unsigned char b[] = {
+#embed __FILE__
+};
+unsigned char c[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+#embed __FILE__ limit(128) suffix (,)
+#embed __FILE__ limit(128) suffix (,)
+#embed __FILE__
+};
+const unsigned char d[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+#embed __FILE__ limit(128) suffix (,)
+#embed __FILE__ limit(128) suffix (,)
+#embed __FILE__
+};
+typedef char V __attribute__((vector_size (16), may_alias));
+struct __attribute__((may_alias)) S { int a, b, c, d; };
+
+__attribute__((noipa)) int
+foo (V x, V y)
+{
+ return __builtin_memcmp (&x, &y, sizeof (x));
+}
+
+__attribute__((noipa)) int
+bar (struct S x, struct S y)
+{
+ return x.a != y.a || x.b != y.b || x.c != y.c || x.d != y.d;
+}
+
+int
+main ()
+{
+ if (a[0] != b[0]
+ || a[42] != b[42]
+ || a[sizeof (a) - 5] != b[sizeof (a) - 5]
+ || a[sizeof (a) - 1] != b[sizeof (a) - 1])
+ __builtin_abort ();
+ if (foo (((V *) a)[0], ((V *) b)[0])
+ || foo (((V *) a)[1], ((V *) b)[1])
+ || foo (((V *) c)[8], ((V *) d)[8])
+ || foo (((V *) c)[9], ((V *) d)[9]))
+ __builtin_abort ();
+ if (bar (((struct S *) a)[0], ((struct S *) b)[0])
+ || bar (((struct S *) a)[1], ((struct S *) b)[1])
+ || bar (((struct S *) c)[8], ((struct S *) d)[8])
+ || bar (((struct S *) c)[9], ((struct S *) d)[9]))
+ __builtin_abort ();
+}
@@ -0,0 +1,87 @@
+/* { dg-do run } */
+/* { dg-options "-std=c23" } */
+
+unsigned char a[] = {
+#embed __FILE__
+};
+unsigned char b[] = {
+ [26] =
+#embed __FILE__
+};
+unsigned char c[] = {
+#embed __FILE__ suffix (,)
+ [sizeof (a) / 4] = 0,
+ [sizeof (a) / 2] = 1,
+ [1] = 2,
+ [sizeof (a) - 2] = 3
+};
+unsigned char d[] = {
+ [1] = 4,
+ [26] = 5,
+ [sizeof (a) / 4] = 6,
+ [sizeof (a) / 2] = 7,
+ [sizeof (a) - 2] = 8,
+#embed __FILE__ prefix ([0] = )
+};
+unsigned char e[] = {
+#embed __FILE__ suffix (,)
+ [2] = 9,
+ [sizeof (a) - 3] = 10
+};
+unsigned char f[] = {
+ [23] = 11,
+ [sizeof (a) / 4 - 1] = 12,
+#embed __FILE__ limit (128) prefix ([sizeof (a) / 4 - 1] = ) suffix (,)
+#embed __FILE__ limit (130) prefix ([sizeof (a) / 4 - 2] = ) suffix (,)
+#embed __FILE__ prefix ([sizeof (a) / 4 + 10] = ) suffix (,)
+#embed __FILE__ limit (128) prefix ([sizeof (a) + sizeof (a) / 4 - 30] = ) suffix (,)
+#embed __FILE__ limit (128) prefix ([sizeof (a) / 4 + 96] = ) suffix (,)
+};
+const unsigned char g[] = {
+#embed __FILE__ limit (128) prefix ( [10] = 2, [5] = 3, [13] = 4, [17] = 5, [0] = )
+};
+unsigned char z[sizeof (a) / 4] = {
+};
+
+int
+main ()
+{
+ if (sizeof (b) != sizeof (a) + 26
+ || __builtin_memcmp (a, b + 26, sizeof (a)))
+ __builtin_abort ();
+ if (sizeof (c) != sizeof (a)
+ || a[0] != c[0]
+ || c[1] != 2
+ || __builtin_memcmp (a + 2, c + 2, sizeof (a) / 4 - 2)
+ || c[sizeof (a) / 4] != 0
+ || __builtin_memcmp (a + sizeof (a) / 4 + 1, c + sizeof (a) / 4 + 1, sizeof (a) / 2 - sizeof (a) / 4 - 1)
+ || c[sizeof (a) / 2] != 1
+ || __builtin_memcmp (a + sizeof (a) / 2 + 1, c + sizeof (a) / 2 + 1, sizeof (a) - sizeof (a) / 2 - 3)
+ || c[sizeof (a) - 2] != 3
+ || a[sizeof (a) - 1] != c[sizeof (a) - 1])
+ __builtin_abort ();
+ if (sizeof (d) != sizeof (a)
+ || __builtin_memcmp (a, d, sizeof (a)))
+ __builtin_abort ();
+ if (sizeof (e) != sizeof (a)
+ || a[0] != e[0]
+ || a[1] != e[1]
+ || e[2] != 9
+ || __builtin_memcmp (a + 3, e + 3, sizeof (a) - 6)
+ || e[sizeof (a) - 3] != 10
+ || a[sizeof (a) - 2] != e[sizeof (a) - 2]
+ || a[sizeof (a) - 1] != e[sizeof (a) - 1])
+ __builtin_abort ();
+ if (sizeof (f) != sizeof (a) + sizeof (a) / 4 - 30 + 128
+ || __builtin_memcmp (z, f, 23)
+ || f[23] != 11
+ || __builtin_memcmp (z, f + 24, sizeof (a) / 4 - 2 - 24)
+ || __builtin_memcmp (f + sizeof (a) / 4 - 2, a, 12)
+ || __builtin_memcmp (f + sizeof (a) / 4 + 10, a, 86)
+ || __builtin_memcmp (f + sizeof (a) / 4 + 96, a, 128)
+ || __builtin_memcmp (f + sizeof (a) / 4 + 96 + 128, a + 86 + 128, sizeof (a) - 86 - 128 - 40)
+ || __builtin_memcmp (f + sizeof (a) + sizeof (a) / 4 - 30, a, 128))
+ __builtin_abort ();
+ if (sizeof (g) != 128 || __builtin_memcmp (g, a, 128))
+ __builtin_abort ();
+}
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -Woverride-init" } */
+
+unsigned char a[] = {
+#embed __FILE__
+};
+unsigned char b[] = {
+ [26] =
+#embed __FILE__
+};
+unsigned char c[] = {
+#embed __FILE__ suffix (,)
+ [sizeof (a) / 4] = 0, /* { dg-warning "initialized field overwritten" } */
+ [sizeof (a) / 2] = 1, /* { dg-warning "initialized field overwritten" } */
+ [1] = 2, /* { dg-warning "initialized field overwritten" } */
+ [sizeof (a) - 2] = 3 /* { dg-warning "initialized field overwritten" } */
+};
+unsigned char d[] = {
+ [1] = 4,
+ [26] = 5,
+ [sizeof (a) / 4] = 6,
+ [sizeof (a) / 2] = 7,
+ [sizeof (a) - 2] = 8,
+#embed __FILE__ prefix ([0] = ) /* { dg-warning "initialized field overwritten" } */
+};
+unsigned char e[] = {
+#embed __FILE__ suffix (,)
+ [2] = 9, /* { dg-warning "initialized field overwritten" } */
+ [sizeof (a) - 3] = 10 /* { dg-warning "initialized field overwritten" } */
+};
+unsigned char f[] = {
+ [23] = 11,
+ [sizeof (a) / 4 - 1] = 12,
+#embed __FILE__ limit (128) prefix ([sizeof (a) / 4 - 1] = ) suffix (,) /* { dg-warning "initialized field overwritten" } */
+#embed __FILE__ limit (130) prefix ([sizeof (a) / 4 - 2] = ) suffix (,) /* { dg-warning "initialized field overwritten" } */
+#embed __FILE__ prefix ([sizeof (a) / 4 + 10] = ) suffix (,) /* { dg-warning "initialized field overwritten" } */
+#embed __FILE__ limit (128) prefix ([sizeof (a) + sizeof (a) / 4 - 30] = ) suffix (,) /* { dg-warning "initialized field overwritten" } */
+#embed __FILE__ limit (128) prefix ([sizeof (a) / 4 + 96] = ) suffix (,) /* { dg-warning "initialized field overwritten" } */
+};
+const unsigned char g[] = {
+#embed __FILE__ limit (128) prefix ( [10] = 2, [5] = 3, [13] = 4, [17] = 5, [0] = ) /* { dg-warning "initialized field overwritten" } */
+};
@@ -0,0 +1,7 @@
+/* This is a comment with some UTF-8 non-ASCII characters: áéíóú. */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -Wconversion" } */
+
+signed char a[] = {
+#embed __FILE__ /* { dg-warning "conversion from 'int' to 'signed char' changes value from '\[12]\[0-9]\[0-9]' to '-\[0-9]\[0-9]*'" } */
+};
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+struct __attribute__((designated_init)) S {
+ int a, b, c, d;
+ unsigned char e[128];
+};
+
+struct S s = { .a = 1, .b =
+#embed __FILE__ limit(128) /* { dg-warning "positional initialization of field in 'struct' declared with 'designated_init' attribute" } */
+}; /* { dg-message "near initialization" "" { target *-*-* } .-1 } */
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-std=c23" } */
+
+int
+foo (int x)
+{
+ if (x != 3)
+ __builtin_abort ();
+ return 1;
+}
+
+int
+main ()
+{
+ unsigned char a[] = {
+ [5] = foo (0),
+ [7] = foo (1),
+ [42] = foo (2),
+ #embed __FILE__ prefix([0] = ) suffix (,) /* { dg-warning "initialized field with side-effects overwritten" } */
+ [12] = foo (3) /* { dg-message "near initialization" "" { target *-*-* } .-1 } */
+
+ };
+ const unsigned char b[] = {
+ #embed __FILE__
+ };
+ if (sizeof (a) != sizeof (b)
+ || __builtin_memcmp (a, b, 12)
+ || a[12] != 1
+ || __builtin_memcmp (a + 13, b + 13, sizeof (a) - 13))
+ __builtin_abort ();
+}
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "-std=c23 -Wunused-value" } */
+
+#include <stdarg.h>
+
+const unsigned char a[] = {
+ #embed __FILE__ limit (128)
+};
+
+int
+foo (...)
+{
+ va_list ap;
+ va_start (ap);
+ for (int i = 0; i < 128; ++i)
+ if (va_arg (ap, int) != a[i])
+ {
+ va_end (ap);
+ return 1;
+ }
+ va_end (ap);
+ return 0;
+}
+
+int b, c;
+
+int
+main ()
+{
+ if (foo (
+#embed __FILE__ limit (128)
+ ))
+ __builtin_abort ();
+ b = (
+#embed __FILE__ limit (128) prefix (c = 2 * ) suffix ( + 6) /* { dg-warning "right-hand operand of comma expression has no effect" } */
+ );
+ if (b != a[127] + 6 || c != 2 * a[0])
+ __builtin_abort ();
+}
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu23 -Wnonnull" } */
+
+#define A(n) int *p##n
+#define B(n) A(n##0), A(n##1), A(n##2), A(n##3), A(n##4), A(n##5), A(n##6), A(n##7)
+#define C(n) B(n##0), B(n##1), B(n##2), B(n##3), B(n##4), B(n##5), B(n##6), B(n##7)
+#define D C(0), C(1), C(2), C(3)
+
+void foo (D) __attribute__((nonnull ( /* { dg-message "in a call to function 'foo' declared 'nonnull'" } */
+#embed __FILE__ limit (128)
+)));
+[[gnu::nonnull (
+#embed __FILE__ limit (128)
+)]] void bar (D); /* { dg-message "in a call to function 'bar' declared 'nonnull'" } */
+
+#undef A
+#define A(n) nullptr
+
+void
+baz ()
+{
+ foo (D); /* { dg-warning "argument \[0-9]\+ null where non-null expected" } */
+ bar (D); /* { dg-warning "argument \[0-9]\+ null where non-null expected" } */
+}
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-options "-std=gnu23 -O2" } */
+
+const unsigned char a[] = {
+#embed __FILE__
+};
+const unsigned char b[] = {
+ [10] = 2, [5] = 3, [13] = 4, [17] = 5, [0] =
+#embed __FILE__ suffix(,) limit (256)
+ [18] = a[18]
+};
+
+int
+main ()
+{
+ if (sizeof (b) != 256 || __builtin_memcmp (b, a, 256))
+ __builtin_abort ();
+}
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu23 -Woverride-init" } */
+
+const unsigned char a[] = {
+#embed __FILE__
+};
+const unsigned char b[] = {
+ [10] = 2, [5] = 3, [13] = 4, [17] = 5, [0] =
+#embed __FILE__ suffix(,) limit (256) /* { dg-warning "initialized field overwritten" } */
+ [18] = a[18] /* { dg-warning "initialized field overwritten" } */
+};
@@ -0,0 +1,17 @@
+/* { dg-options "-std=c23 --embed-dir=${srcdir}/c-c++-common/cpp/embed-dir" } */
+
+#include "embed-1.h"
+
+const unsigned char b[] = {
+ #embed <magna-carta.txt>
+};
+
+int
+main ()
+{
+ if (sizeof (a) != sizeof (b)
+ || __builtin_memcmp (a, b, 256)
+ || a[256] != 42
+ || __builtin_memcmp (a + 257, b + 257, sizeof (a) - 257))
+ __builtin_abort ();
+}
@@ -0,0 +1,6 @@
+/* { dg-options "-std=c23 --embed-dir=${srcdir}/c-c++-common/cpp/embed-dir" } */
+
+const unsigned char a[] = {
+ #embed <magna-carta.txt> prefix ([0] = ) suffix (,)
+ [256] = 42
+};
@@ -0,0 +1,19 @@
+/* { dg-lto-do run } */
+/* { dg-lto-options { { -std=c23 -flto } } } */
+
+extern const unsigned char a[];
+extern const int asz;
+
+const unsigned char b[] = {
+ #embed "../../c-c++-common/cpp/embed-dir/magna-carta.txt"
+};
+
+int
+main ()
+{
+ if (asz != sizeof (b)
+ || __builtin_memcmp (a, b, 256)
+ || a[256] != 42
+ || __builtin_memcmp (a + 257, b + 257, asz - 257))
+ __builtin_abort ();
+}
@@ -0,0 +1,5 @@
+const unsigned char a[] = {
+ #embed "../../c-c++-common/cpp/embed-dir/magna-carta.txt" prefix ([0] = ) suffix (,)
+ [256] = 42
+};
+const int asz = sizeof (a);