--- libcpp/include/cpplib.h.jj	2024-07-03 14:51:47.517142318 +0200
+++ libcpp/include/cpplib.h	2024-07-03 14:52:04.321921447 +0200
@@ -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.  */			\
--- libcpp/files.cc.jj	2024-07-11 14:19:09.744438223 +0200
+++ libcpp/files.cc	2024-07-11 13:33:28.526384156 +0200
@@ -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)
     {
--- gcc/treestruct.def.jj	2024-01-03 11:51:38.761630845 +0100
+++ gcc/treestruct.def	2024-07-03 17:06:57.539794162 +0200
@@ -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")
--- gcc/tree.def.jj	2024-06-05 19:09:54.045617019 +0200
+++ gcc/tree.def	2024-07-09 16:56:08.859156168 +0200
@@ -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
--- gcc/tree-core.h.jj	2024-07-01 11:28:23.408228952 +0200
+++ gcc/tree-core.h	2024-07-09 15:45:08.097323483 +0200
@@ -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;
--- gcc/tree.h.jj	2024-06-05 19:09:54.046617006 +0200
+++ gcc/tree.h	2024-07-09 13:47:26.260188037 +0200
@@ -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);
--- gcc/tree.cc.jj	2024-07-01 11:28:23.495227837 +0200
+++ gcc/tree.cc	2024-07-09 15:17:55.552479443 +0200
@@ -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 {
--- gcc/gimplify.cc.jj	2024-06-07 12:17:04.926031236 +0200
+++ gcc/gimplify.cc	2024-07-08 12:55:09.831253563 +0200
@@ -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);
--- gcc/fold-const.cc.jj	2024-06-05 15:42:28.144707055 +0200
+++ gcc/fold-const.cc	2024-07-08 11:24:03.260770902 +0200
@@ -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;
--- gcc/gimple-fold.cc.jj	2024-06-05 15:42:28.178706605 +0200
+++ gcc/gimple-fold.cc	2024-07-06 11:14:41.202981865 +0200
@@ -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
--- gcc/varasm.cc.jj	2024-05-07 18:10:10.674871087 +0200
+++ gcc/varasm.cc	2024-07-08 11:00:54.723980651 +0200
@@ -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);
--- gcc/expr.cc.jj	2024-07-01 11:28:22.704237981 +0200
+++ gcc/expr.cc	2024-07-08 11:18:15.657323449 +0200
@@ -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)
--- gcc/tree-streamer.cc.jj	2024-01-03 11:51:28.301776019 +0100
+++ gcc/tree-streamer.cc	2024-07-09 17:48:55.649881800 +0200
@@ -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;
--- gcc/tree-streamer-in.cc.jj	2024-01-03 11:51:42.161583657 +0100
+++ gcc/tree-streamer-in.cc	2024-07-10 12:03:09.872527043 +0200
@@ -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);
 }
--- gcc/tree-streamer-out.cc.jj	2024-01-03 11:51:42.364580839 +0100
+++ gcc/tree-streamer-out.cc	2024-07-10 12:21:04.754870641 +0200
@@ -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));
--- gcc/lto-streamer-out.cc.jj	2024-01-03 11:51:38.840629749 +0100
+++ gcc/lto-streamer-out.cc	2024-07-10 12:27:14.753182127 +0200
@@ -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;
--- gcc/tree-pretty-print.cc.jj	2024-06-14 19:45:09.446777591 +0200
+++ gcc/tree-pretty-print.cc	2024-07-04 14:58:33.571465397 +0200
@@ -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);
--- gcc/c-family/c-ppoutput.cc.jj	2024-07-01 11:28:17.831300468 +0200
+++ gcc/c-family/c-ppoutput.cc	2024-07-03 14:52:12.232817472 +0200
@@ -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)
--- gcc/c-family/c-lex.cc.jj	2024-02-22 19:29:51.226074838 +0100
+++ gcc/c-family/c-lex.cc	2024-07-11 16:13:08.986032306 +0200
@@ -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;
--- gcc/c-family/c-common.cc.jj	2024-06-17 22:02:14.676329357 +0200
+++ gcc/c-family/c-common.cc	2024-07-11 09:00:10.482657046 +0200
@@ -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);
--- gcc/c/c-parser.cc.jj	2024-07-01 11:28:21.840249061 +0200
+++ gcc/c/c-parser.cc	2024-07-08 18:01:09.722758582 +0200
@@ -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);
--- gcc/c/c-typeck.cc.jj	2024-06-14 19:45:07.455803708 +0200
+++ gcc/c/c-typeck.cc	2024-07-10 17:12:13.584204677 +0200
@@ -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
--- gcc/testsuite/c-c++-common/cpp/embed-20.c.jj	2024-07-05 11:30:09.333874817 +0200
+++ gcc/testsuite/c-c++-common/cpp/embed-20.c	2024-07-05 11:35:19.825724327 +0200
@@ -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 ();
+}
--- gcc/testsuite/c-c++-common/cpp/embed-21.c.jj	2024-07-08 11:48:51.584293819 +0200
+++ gcc/testsuite/c-c++-common/cpp/embed-21.c	2024-07-08 11:50:59.137624774 +0200
@@ -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 ();
+}
--- gcc/testsuite/gcc.dg/cpp/embed-8.c.jj	2024-07-05 13:25:08.339965010 +0200
+++ gcc/testsuite/gcc.dg/cpp/embed-8.c	2024-07-10 19:59:46.607573298 +0200
@@ -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 ();
+}
--- gcc/testsuite/gcc.dg/cpp/embed-9.c.jj	2024-07-05 13:27:28.580097964 +0200
+++ gcc/testsuite/gcc.dg/cpp/embed-9.c	2024-07-10 19:59:53.545485849 +0200
@@ -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" } */
+};
--- gcc/testsuite/gcc.dg/cpp/embed-10.c.jj	2024-07-05 13:37:25.289157048 +0200
+++ gcc/testsuite/gcc.dg/cpp/embed-10.c	2024-07-05 13:39:15.232694163 +0200
@@ -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]*'" } */
+};
--- gcc/testsuite/gcc.dg/cpp/embed-11.c.jj	2024-07-05 13:54:06.976828053 +0200
+++ gcc/testsuite/gcc.dg/cpp/embed-11.c	2024-07-05 13:53:54.994987508 +0200
@@ -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 } */
--- gcc/testsuite/gcc.dg/cpp/embed-12.c.jj	2024-07-08 12:47:12.908507612 +0200
+++ gcc/testsuite/gcc.dg/cpp/embed-12.c	2024-07-10 17:17:47.533999076 +0200
@@ -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 ();
+}
--- gcc/testsuite/gcc.dg/cpp/embed-13.c.jj	2024-07-08 13:47:27.416775033 +0200
+++ gcc/testsuite/gcc.dg/cpp/embed-13.c	2024-07-08 20:01:07.576011169 +0200
@@ -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 ();
+}
--- gcc/testsuite/gcc.dg/cpp/embed-14.c.jj	2024-07-08 13:54:57.288917957 +0200
+++ gcc/testsuite/gcc.dg/cpp/embed-14.c	2024-07-08 14:05:41.960504845 +0200
@@ -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" } */
+}
--- gcc/testsuite/gcc.dg/cpp/embed-15.c.jj	2024-07-10 19:59:24.441852673 +0200
+++ gcc/testsuite/gcc.dg/cpp/embed-15.c	2024-07-10 20:06:22.506583334 +0200
@@ -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 ();
+}
--- gcc/testsuite/gcc.dg/cpp/embed-16.c.jj	2024-07-10 19:59:35.333715390 +0200
+++ gcc/testsuite/gcc.dg/cpp/embed-16.c	2024-07-10 20:06:32.284460092 +0200
@@ -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" } */
+};
--- gcc/testsuite/gcc.dg/pch/embed-1.c.jj	2024-07-09 15:32:18.459279355 +0200
+++ gcc/testsuite/gcc.dg/pch/embed-1.c	2024-07-09 15:41:21.628253034 +0200
@@ -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 ();
+}
--- gcc/testsuite/gcc.dg/pch/embed-1.hs.jj	2024-07-09 15:30:28.152706259 +0200
+++ gcc/testsuite/gcc.dg/pch/embed-1.hs	2024-07-09 15:37:54.525932069 +0200
@@ -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
+};
--- gcc/testsuite/gcc.dg/lto/embed-1_0.c.jj	2024-07-10 13:23:59.652727923 +0200
+++ gcc/testsuite/gcc.dg/lto/embed-1_0.c	2024-07-10 13:22:55.562530776 +0200
@@ -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 ();
+}
--- gcc/testsuite/gcc.dg/lto/embed-1_1.c.jj	2024-07-10 13:24:03.151684089 +0200
+++ gcc/testsuite/gcc.dg/lto/embed-1_1.c	2024-07-10 13:22:42.700691898 +0200
@@ -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);
