aboutsummaryrefslogtreecommitdiff
path: root/clang/test
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test')
-rw-r--r--clang/test/C/C2x/Inputs/bits.bin1
-rw-r--r--clang/test/C/C2x/Inputs/boop.h1
-rw-r--r--clang/test/C/C2x/Inputs/i.dat1
-rw-r--r--clang/test/C/C2x/Inputs/jump.wav1
-rw-r--r--clang/test/C/C2x/Inputs/s.dat1
-rw-r--r--clang/test/C/C2x/n3017.c216
-rw-r--r--clang/test/Preprocessor/Inputs/jk.txt1
-rw-r--r--clang/test/Preprocessor/Inputs/media/art.txt9
-rw-r--r--clang/test/Preprocessor/Inputs/media/empty0
-rw-r--r--clang/test/Preprocessor/Inputs/null_byte.binbin0 -> 1 bytes
-rw-r--r--clang/test/Preprocessor/Inputs/numbers.txt1
-rw-r--r--clang/test/Preprocessor/Inputs/single_byte.txt1
-rw-r--r--clang/test/Preprocessor/embed___has_embed.c60
-rw-r--r--clang/test/Preprocessor/embed___has_embed_parsing_errors.c240
-rw-r--r--clang/test/Preprocessor/embed___has_embed_supported.c24
-rw-r--r--clang/test/Preprocessor/embed_art.c104
-rw-r--r--clang/test/Preprocessor/embed_codegen.cpp84
-rw-r--r--clang/test/Preprocessor/embed_constexpr.cpp97
-rw-r--r--clang/test/Preprocessor/embed_dependencies.c20
-rw-r--r--clang/test/Preprocessor/embed_ext_compat_diags.c16
-rw-r--r--clang/test/Preprocessor/embed_feature_test.cpp7
-rw-r--r--clang/test/Preprocessor/embed_file_not_found_chevron.c4
-rw-r--r--clang/test/Preprocessor/embed_file_not_found_quote.c4
-rw-r--r--clang/test/Preprocessor/embed_init.c29
-rw-r--r--clang/test/Preprocessor/embed_parameter_if_empty.c24
-rw-r--r--clang/test/Preprocessor/embed_parameter_limit.c94
-rw-r--r--clang/test/Preprocessor/embed_parameter_offset.c89
-rw-r--r--clang/test/Preprocessor/embed_parameter_prefix.c38
-rw-r--r--clang/test/Preprocessor/embed_parameter_suffix.c39
-rw-r--r--clang/test/Preprocessor/embed_parameter_unrecognized.c9
-rw-r--r--clang/test/Preprocessor/embed_parsing_errors.c130
-rw-r--r--clang/test/Preprocessor/embed_path_chevron.c8
-rw-r--r--clang/test/Preprocessor/embed_path_quote.c8
-rw-r--r--clang/test/Preprocessor/embed_preprocess_to_file.c39
-rw-r--r--clang/test/Preprocessor/embed_single_entity.c7
-rw-r--r--clang/test/Preprocessor/embed_weird.cpp98
-rw-r--r--clang/test/Preprocessor/init-aarch64.c3
-rw-r--r--clang/test/Preprocessor/init.c3
-rw-r--r--clang/test/Preprocessor/single_byte.txt1
39 files changed, 1512 insertions, 0 deletions
diff --git a/clang/test/C/C2x/Inputs/bits.bin b/clang/test/C/C2x/Inputs/bits.bin
new file mode 100644
index 0000000..ad47100
--- /dev/null
+++ b/clang/test/C/C2x/Inputs/bits.bin
@@ -0,0 +1 @@
+0123456789 \ No newline at end of file
diff --git a/clang/test/C/C2x/Inputs/boop.h b/clang/test/C/C2x/Inputs/boop.h
new file mode 100644
index 0000000..d3e3967
--- /dev/null
+++ b/clang/test/C/C2x/Inputs/boop.h
@@ -0,0 +1 @@
+*boop* \ No newline at end of file
diff --git a/clang/test/C/C2x/Inputs/i.dat b/clang/test/C/C2x/Inputs/i.dat
new file mode 100644
index 0000000..c227083
--- /dev/null
+++ b/clang/test/C/C2x/Inputs/i.dat
@@ -0,0 +1 @@
+0 \ No newline at end of file
diff --git a/clang/test/C/C2x/Inputs/jump.wav b/clang/test/C/C2x/Inputs/jump.wav
new file mode 100644
index 0000000..a711006
--- /dev/null
+++ b/clang/test/C/C2x/Inputs/jump.wav
@@ -0,0 +1 @@
+RIFF \ No newline at end of file
diff --git a/clang/test/C/C2x/Inputs/s.dat b/clang/test/C/C2x/Inputs/s.dat
new file mode 100644
index 0000000..3a332e6
--- /dev/null
+++ b/clang/test/C/C2x/Inputs/s.dat
@@ -0,0 +1 @@
+012345678 \ No newline at end of file
diff --git a/clang/test/C/C2x/n3017.c b/clang/test/C/C2x/n3017.c
new file mode 100644
index 0000000..0d22d31
--- /dev/null
+++ b/clang/test/C/C2x/n3017.c
@@ -0,0 +1,216 @@
+// RUN: %clang_cc1 -verify -fsyntax-only --embed-dir=%S/Inputs -std=c2x %s -Wno-constant-logical-operand
+
+/* WG14 N3017: full
+ * #embed - a scannable, tooling-friendly binary resource inclusion mechanism
+ */
+
+// C23 6.10p6
+char b1[] = {
+#embed "boop.h" limit(5)
+,
+#embed "boop.h" __limit__(5)
+};
+
+// C23 6.10.1p19
+#if __has_embed(__FILE__ ext::token(0xB055))
+#error "Supports an extension parameter Clang never claimed to support?"
+#endif
+
+#if !__has_embed(__FILE__ clang::offset(0))
+#error "Doesn't support an extension Clang claims to support?"
+#endif
+
+// C23 6.10.1p20
+void parse_into_s(short* ptr, unsigned char* ptr_bytes, unsigned long long size);
+int f() {
+#if __has_embed ("bits.bin" ds9000::element_type(short))
+ /* Implementation extension: create short integers from the */
+ /* translation environment resource into */
+ /* a sequence of integer constants */
+ short meow[] = {
+#embed "bits.bin" ds9000::element_type(short)
+ };
+#elif __has_embed ("bits.bin")
+ /* no support for implementation-specific */
+ /* ds9000::element_type(short) parameter */
+ unsigned char meow_bytes[] = {
+ #embed "bits.bin"
+ };
+ short meow[sizeof(meow_bytes) / sizeof(short)] = {};
+ /* parse meow_bytes into short values by-hand! */
+ parse_into_s(meow, meow_bytes, sizeof(meow_bytes));
+#else
+#error "cannot find bits.bin resource"
+#endif
+ return (int)(meow[0] + meow[(sizeof(meow) / sizeof(*meow)) - 1]);
+}
+
+// NOTE: we don't have a good way to test infinite resources from within lit.
+int g() {
+#if __has_embed(<infinite-resource> limit(0)) == 2
+ // if <infinite-resource> exists, this
+ // token sequence is always taken.
+ return 0;
+#else
+ // the ’infinite-resource’ resource does not exist
+ #error "The resource does not exist"
+#endif
+ // expected-error@-2 {{"The resource does not exist"}}
+}
+
+#include <stddef.h>
+void have_you_any_wool(const unsigned char*, size_t);
+int h() {
+ static const unsigned char baa_baa[] = {
+#embed __FILE__
+ };
+ have_you_any_wool(baa_baa, sizeof(baa_baa));
+ return 0;
+}
+
+// C23 6.10.3.1p17: not tested here because we do not currently support any
+// platforms where CHAR_BIT != 8.
+
+// C23 6.10.3.1p18
+int i() {
+/* Braces may be kept or elided as per normal initialization rules */
+ int i = {
+#embed "i.dat"
+ }; /* valid if i.dat produces 1 value,
+ i value is [0, 2(embed element width)) */
+ int i2 =
+#embed "i.dat"
+ ; /* valid if i.dat produces 1 value,
+ i2 value is [0, 2(embed element width)) */
+ struct s {
+ double a, b, c;
+ struct { double e, f, g; };
+ double h, i, j;
+ };
+ struct s x = {
+ /* initializes each element in order according to initialization
+ rules with comma-separated list of integer constant expressions
+ inside of braces */
+ #embed "s.dat"
+ };
+ return 0;
+}
+
+// C23 6.10.3.1p19: not tested here because it's a runtime test rather than one
+// which can be handled at compile time (it validates file contents via fread).
+
+// C23 6.10.3.2p5
+int j() {
+ static const char sound_signature[] = {
+#embed <jump.wav> limit(2+2)
+ };
+ static_assert((sizeof(sound_signature) / sizeof(*sound_signature)) == 4,
+ "There should only be 4 elements in this array.");
+ // verify PCM WAV resource
+ static_assert(sound_signature[0] == 'R');
+ static_assert(sound_signature[1] == 'I');
+ static_assert(sound_signature[2] == 'F');
+ static_assert(sound_signature[3] == 'F');
+ static_assert(sizeof(sound_signature) == 4);
+ return 0;
+}
+
+// C23 6.10.3p6
+int k() {
+#define TWO_PLUS_TWO 2+2
+ static const char sound_signature[] = {
+#embed <jump.wav> limit(TWO_PLUS_TWO)
+ };
+ static_assert((sizeof(sound_signature) / sizeof(*sound_signature)) == 4,
+ "There should only be 4 elements in this array.");
+ // verify PCM WAV resource
+ static_assert(sound_signature[0] == 'R');
+ static_assert(sound_signature[1] == 'I');
+ static_assert(sound_signature[2] == 'F');
+ static_assert(sound_signature[3] == 'F');
+ static_assert(sizeof(sound_signature) == 4);
+ return 0;
+}
+
+// C23 6.10.3.2p7: not tested here because we do not currently support any
+// platforms where CHAR_BIT != 8.
+
+// C23 6.10.3.2p8: not tested here because it requires access to an infinite
+// resource like /dev/urandom.
+
+// C23 6.10.3.3p4
+char *strcpy(char *, const char *);
+#ifndef SHADER_TARGET
+ #define SHADER_TARGET "bits.bin"
+#endif
+extern char* null_term_shader_data;
+void fill_in_data () {
+ const char internal_data[] = {
+#embed SHADER_TARGET \
+ suffix(,)
+ 0
+ };
+ strcpy(null_term_shader_data, internal_data);
+}
+
+// C23 6.10.3.4p4
+#ifndef SHADER_TARGET
+#define SHADER_TARGET "bits.bin"
+#endif
+extern char* merp;
+void init_data () {
+ const char whl[] = {
+#embed SHADER_TARGET \
+ prefix(0xEF, 0xBB, 0xBF, ) /* UTF-8 BOM */ \
+ suffix(,)
+ 0
+ };
+ // always null terminated,
+ // contains BOM if not-empty
+ const int is_good = (sizeof(whl) == 1 && whl[0] == '\0')
+ || (whl[0] == '\xEF' && whl[1] == '\xBB'
+ && whl[2] == '\xBF' && whl[sizeof(whl) - 1] == '\0');
+ static_assert(is_good);
+ strcpy(merp, whl);
+}
+
+// C23 6.10.3.5p3
+int l() {
+ return
+#embed <bits.bin> limit(0) prefix(1) if_empty(0)
+ ;
+ // becomes:
+ // return 0;
+
+ // Validating the assumption from the example in the standard.
+ static_assert(
+#embed <bits.bin> limit(0) prefix(1) if_empty(0)
+ == 0);
+}
+
+// C23 6.10.3.5p4
+void fill_in_data_again() {
+ const char internal_data[] = {
+#embed SHADER_TARGET \
+ suffix(, 0) \
+ if_empty(0)
+ };
+ strcpy(null_term_shader_data, internal_data);
+}
+
+// C23 6.10.3.5p5
+int m() {
+ return
+#embed __FILE__ limit(0) if_empty(45540)
+ ;
+
+ // Validating the assumption from the example in the standard.
+ static_assert(
+#embed __FILE__ limit(0) if_empty(45540)
+ == 45540);
+}
+
+// 6.10.9.1p1
+static_assert(__STDC_EMBED_NOT_FOUND__ == 0);
+static_assert(__STDC_EMBED_FOUND__ == 1);
+static_assert(__STDC_EMBED_EMPTY__ == 2);
diff --git a/clang/test/Preprocessor/Inputs/jk.txt b/clang/test/Preprocessor/Inputs/jk.txt
new file mode 100644
index 0000000..93d177a
--- /dev/null
+++ b/clang/test/Preprocessor/Inputs/jk.txt
@@ -0,0 +1 @@
+jk \ No newline at end of file
diff --git a/clang/test/Preprocessor/Inputs/media/art.txt b/clang/test/Preprocessor/Inputs/media/art.txt
new file mode 100644
index 0000000..1ce9ab9
--- /dev/null
+++ b/clang/test/Preprocessor/Inputs/media/art.txt
@@ -0,0 +1,9 @@
+ __ _
+ .-.' `; `-._ __ _
+ (_, .-:' `; `-._
+ ,'o"( (_, )
+ (__,-' ,'o"( )>
+ ( (__,-' )
+ `-'._.--._( )
+ ||| |||`-'._.--._.-'
+ ||| |||
diff --git a/clang/test/Preprocessor/Inputs/media/empty b/clang/test/Preprocessor/Inputs/media/empty
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/clang/test/Preprocessor/Inputs/media/empty
diff --git a/clang/test/Preprocessor/Inputs/null_byte.bin b/clang/test/Preprocessor/Inputs/null_byte.bin
new file mode 100644
index 0000000..f76dd23
--- /dev/null
+++ b/clang/test/Preprocessor/Inputs/null_byte.bin
Binary files differ
diff --git a/clang/test/Preprocessor/Inputs/numbers.txt b/clang/test/Preprocessor/Inputs/numbers.txt
new file mode 100644
index 0000000..11f11f9
--- /dev/null
+++ b/clang/test/Preprocessor/Inputs/numbers.txt
@@ -0,0 +1 @@
+0123456789
diff --git a/clang/test/Preprocessor/Inputs/single_byte.txt b/clang/test/Preprocessor/Inputs/single_byte.txt
new file mode 100644
index 0000000..63d8dbd
--- /dev/null
+++ b/clang/test/Preprocessor/Inputs/single_byte.txt
@@ -0,0 +1 @@
+b \ No newline at end of file
diff --git a/clang/test/Preprocessor/embed___has_embed.c b/clang/test/Preprocessor/embed___has_embed.c
new file mode 100644
index 0000000..43a3068
--- /dev/null
+++ b/clang/test/Preprocessor/embed___has_embed.c
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -std=c23 %s -E --embed-dir=%S/Inputs -verify
+// expected-no-diagnostics
+
+#if __has_embed(__FILE__) != __STDC_EMBED_FOUND__
+#error 1
+#elif __has_embed("media/art.txt") != __STDC_EMBED_FOUND__
+#error 2
+#elif __has_embed("asdkasdjkadsjkdsfjk") != __STDC_EMBED_NOT_FOUND__
+#error 3
+#elif __has_embed("asdkasdjkadsjkdsfjk" limit(1)) != __STDC_EMBED_NOT_FOUND__
+#error 4
+#elif __has_embed("asdkasdjkadsjkdsfjk" suffix(x) limit(1)) != __STDC_EMBED_NOT_FOUND__
+#error 5
+#elif __has_embed("asdkasdjkadsjkdsfjk" suffix(x) djsakdasjd::xmeow("xD")) != __STDC_EMBED_NOT_FOUND__
+#error 6
+#elif __has_embed(__FILE__ limit(2) prefix(y)) != __STDC_EMBED_FOUND__
+#error 7
+#elif __has_embed(__FILE__ limit(2)) != __STDC_EMBED_FOUND__
+#error 8
+// 6.10.1p7, if the search fails or any of the embed parameters in the embed
+// parameter sequence specified are not supported by the implementation for the
+// #embed directive;
+// We don't support one of the embed parameters.
+#elif __has_embed(__FILE__ dajwdwdjdahwk::meow(x)) != __STDC_EMBED_NOT_FOUND__
+#error 9
+#elif __has_embed(<media/empty>) != __STDC_EMBED_EMPTY__
+#error 10
+// 6.10.1p7: if the search for the resource succeeds and all embed parameters
+// in the embed parameter sequence specified are supported by the
+// implementation for the #embed directive and the resource is empty
+// Limiting to zero characters means the resource is empty.
+#elif __has_embed(<media/empty> limit(0)) != __STDC_EMBED_EMPTY__
+#error 11
+#elif __has_embed(<media/art.txt> limit(0)) != __STDC_EMBED_EMPTY__
+#error 12
+// Test that an offset past the end of the file produces an empty file.
+#elif __has_embed(<single_byte.txt> clang::offset(1)) != __STDC_EMBED_EMPTY__
+#error 13
+// Test that we apply the offset before we apply the limit. If we did this in
+// the reverse order, this would cause the file to be empty because we would
+// have limited it to 1 byte and then offset past it.
+#elif __has_embed(<media/art.txt> limit(1) clang::offset(12)) != __STDC_EMBED_FOUND__
+#error 14
+#elif __has_embed(<media/art.txt>) != __STDC_EMBED_FOUND__
+#error 15
+#elif __has_embed(<media/art.txt> if_empty(meow)) != __STDC_EMBED_FOUND__
+#error 16
+#endif
+
+// Ensure that when __has_embed returns true, the file can actually be
+// embedded. This was previously failing because the way in which __has_embed
+// would search for files was differentl from how #embed would resolve them
+// when the file path included relative path markers like `./` or `../`.
+#if __has_embed("./embed___has_embed.c") == __STDC_EMBED_FOUND__
+unsigned char buffer[] = {
+#embed "./embed___has_embed.c"
+};
+#else
+#error 17
+#endif
diff --git a/clang/test/Preprocessor/embed___has_embed_parsing_errors.c b/clang/test/Preprocessor/embed___has_embed_parsing_errors.c
new file mode 100644
index 0000000..fcaf693
--- /dev/null
+++ b/clang/test/Preprocessor/embed___has_embed_parsing_errors.c
@@ -0,0 +1,240 @@
+// RUN: %clang_cc1 -std=c23 %s -E -verify
+
+// Test the parsing behavior for __has_embed and all of its parameters to ensure we
+// recover from failures gracefully.
+
+// expected-error@+2 {{missing '(' after '__has_embed'}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed
+#endif
+
+// expected-error@+3 {{expected '>'}} \
+ expected-note@+3 {{to match this '<'}} \
+ expected-error@+3 {{expected value in expression}}
+#if __has_embed(<)
+#endif
+
+// expected-error@+3 {{expected "FILENAME" or <FILENAME>}} \
+ expected-warning@+3 {{missing terminating '"' character}} \
+ expected-error@+3 {{invalid token at start of a preprocessor expression}}
+#if __has_embed(")
+#endif
+
+// expected-error@+2 {{missing '(' after '__has_embed'}} \
+ expected-error@+2 {{token is not a valid binary operator in a preprocessor subexpression}}
+#if __has_embed file.txt
+#endif
+
+// OK, no diagnostic for an unknown embed parameter.
+#if __has_embed("media/empty" xxx)
+#endif
+
+// expected-error@+2 {{expected identifier}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" xxx::)
+#endif
+
+// OK, no diagnostic for an unknown embed parameter.
+#if __has_embed("media/empty" xxx::xxx)
+#endif
+
+// expected-error@+2 {{expected identifier}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" xxx::42)
+#endif
+
+// expected-error@+2 {{expected '('}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" limit)
+#endif
+
+// We get the same diagnostic twice intentionally. The first one is because of
+// the missing value within limit() and the second one is because the #if does
+// not resolve to a value due to the earlier error.
+// expected-error@+1 2 {{expected value in expression}}
+#if __has_embed("media/empty" limit()
+#endif
+
+// expected-error@+3 {{missing ')' after '__has_embed'}} \
+ expected-error@+3 {{expected value in expression}} \
+ expected-note@+3 {{to match this '('}}
+#if __has_embed("media/empty" limit(xxx)
+#endif
+
+// expected-error@+3 {{missing ')' after '__has_embed'}} \
+ expected-error@+3 {{expected value in expression}} \
+ expected-note@+3 {{to match this '('}}
+#if __has_embed("media/empty" limit(42)
+#endif
+
+// expected-error@+2 {{invalid token at start of a preprocessor expression}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" limit([)
+#endif
+
+// expected-error@+2 {{invalid token at start of a preprocessor expression}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" limit([))
+#endif
+
+// expected-error@+2 {{division by zero in preprocessor expression}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" limit(1/0))
+#endif
+
+// expected-error@+2 {{expected '('}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" clang::offset)
+#endif
+
+// We get the same diagnostic twice intentionally. The first one is because of
+// the missing value within clang::offset() and the second one is because the
+// #if does not resolve to a value due to the earlier error.
+// expected-error@+1 2 {{expected value in expression}}
+#if __has_embed("media/empty" clang::offset()
+#endif
+
+// expected-error@+3 {{missing ')' after '__has_embed'}} \
+ expected-error@+3 {{expected value in expression}} \
+ expected-note@+3 {{to match this '('}}
+#if __has_embed("media/empty" clang::offset(xxx)
+#endif
+
+// expected-error@+3 {{missing ')' after '__has_embed'}} \
+ expected-error@+3 {{expected value in expression}} \
+ expected-note@+3 {{to match this '('}}
+#if __has_embed("media/empty" clang::offset(42)
+#endif
+
+// expected-error@+2 {{invalid token at start of a preprocessor expression}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" clang::offset([)
+#endif
+
+// expected-error@+2 {{invalid token at start of a preprocessor expression}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" clang::offset([))
+#endif
+
+// expected-error@+2 {{division by zero in preprocessor expression}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" clang::offset(1/0))
+#endif
+
+// expected-error@+2 {{expected '('}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" clang::offset 42)
+#endif
+
+// expected-error@+2 {{expected '('}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" prefix)
+#endif
+
+// expected-error@+3 {{missing ')' after '__has_embed'}} \
+ expected-error@+3 {{expected value in expression}} \
+ expected-note@+3 {{to match this '('}}
+#if __has_embed("media/empty" prefix()
+#endif
+
+// expected-error@+3 {{missing ')' after '__has_embed'}} \
+ expected-error@+3 {{expected value in expression}} \
+ expected-note@+3 {{to match this '('}}
+#if __has_embed("media/empty" prefix(xxx)
+#endif
+
+#if __has_embed("media/empty" prefix(1/0)) // OK: emitted as tokens, not evaluated yet.
+#endif
+#if __has_embed("media/empty" prefix(([{}]))) // OK: delimiters balanced
+#endif
+// expected-error@+3 {{expected '}'}} \
+ expected-note@+3 {{to match this '{'}} \
+ expected-error@+3 {{expected value in expression}}
+#if __has_embed("media/empty" prefix(([{)]}))
+#endif
+// expected-error@+3 {{expected ']'}} \
+ expected-note@+3 {{to match this '['}} \
+ expected-error@+3 {{expected value in expression}}
+#if __has_embed("media/empty" prefix(([{})}))
+#endif
+// expected-error@+3 {{expected ')'}} \
+ expected-note@+3 {{to match this '('}} \
+ expected-error@+3 {{expected value in expression}}
+#if __has_embed("media/empty" prefix(([{}]}))
+#endif
+#if __has_embed("media/empty" prefix()) // OK: tokens within parens are optional
+#endif
+// expected-error@+2 {{expected '('}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" prefix))
+#endif
+
+// expected-error@+2 {{expected '('}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" suffix)
+#endif
+
+// expected-error@+3 {{missing ')' after '__has_embed'}} \
+ expected-error@+3 {{expected value in expression}} \
+ expected-note@+3 {{to match this '('}}
+#if __has_embed("media/empty" suffix()
+#endif
+
+// expected-error@+3 {{missing ')' after '__has_embed'}} \
+ expected-error@+3 {{expected value in expression}} \
+ expected-note@+3 {{to match this '('}}
+#if __has_embed("media/empty" suffix(xxx)
+#endif
+
+#if __has_embed("media/empty" suffix(1/0)) // OK: emitted as tokens, not evaluated yet.
+#endif
+#if __has_embed("media/empty" suffix(([{}]))) // OK: delimiters balanced
+#endif
+// expected-error@+3 {{expected '}'}} \
+ expected-note@+3 {{to match this '{'}} \
+ expected-error@+3 {{expected value in expression}}
+#if __has_embed("media/empty" suffix(([{)]}))
+#endif
+// expected-error@+3 {{expected ']'}} \
+ expected-note@+3 {{to match this '['}} \
+ expected-error@+3 {{expected value in expression}}
+#if __has_embed("media/empty" suffix(([{})}))
+#endif
+// expected-error@+3 {{expected ')'}} \
+ expected-note@+3 {{to match this '('}} \
+ expected-error@+3 {{expected value in expression}}
+#if __has_embed("media/empty" suffix(([{}]}))
+#endif
+#if __has_embed("media/empty" suffix()) // OK: tokens within parens are optional
+#endif
+// expected-error@+2 {{expected '('}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/empty" suffix))
+#endif
+
+#if __has_embed("media/art.txt" if_empty(1/0)) // OK: emitted as tokens, not evaluated yet.
+#endif
+#if __has_embed("media/art.txt" if_empty(([{}]))) // OK: delimiters balanced
+#endif
+// expected-error@+3 {{expected '}'}} \
+ expected-note@+3 {{to match this '{'}} \
+ expected-error@+3 {{expected value in expression}}
+#if __has_embed("media/art.txt" if_empty(([{)]}))
+#endif
+// expected-error@+3 {{expected ']'}} \
+ expected-note@+3 {{to match this '['}} \
+ expected-error@+3 {{expected value in expression}}
+#if __has_embed("media/art.txt" if_empty(([{})}))
+#endif
+// expected-error@+3 {{expected ')'}} \
+ expected-note@+3 {{to match this '('}} \
+ expected-error@+3 {{expected value in expression}}
+#if __has_embed("media/art.txt" if_empty(([{}]}))
+#endif
+#if __has_embed("media/art.txt" if_empty()) // OK: tokens within parens are optional
+#endif
+// expected-error@+2 {{expected '('}} \
+ expected-error@+2 {{expected value in expression}}
+#if __has_embed("media/art.txt" if_empty))
+#endif
+
diff --git a/clang/test/Preprocessor/embed___has_embed_supported.c b/clang/test/Preprocessor/embed___has_embed_supported.c
new file mode 100644
index 0000000..e51dbb8
--- /dev/null
+++ b/clang/test/Preprocessor/embed___has_embed_supported.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c23 %s -E -verify
+
+#if __has_embed(__FILE__) != __STDC_EMBED_FOUND__
+#error 1
+#elif __has_embed(__FILE__) != __STDC_EMBED_FOUND__
+#error 2
+#elif __has_embed(__FILE__ suffix(x)) != __STDC_EMBED_FOUND__
+#error 3
+#elif __has_embed(__FILE__ suffix(x) limit(1)) != __STDC_EMBED_FOUND__
+#error 4
+#elif __has_embed(__FILE__ suffix(x) limit(1) prefix(1)) != __STDC_EMBED_FOUND__
+#error 5
+#elif __has_embed(__FILE__ suffix(x) limit(2) prefix(1) clang::offset(1)) != __STDC_EMBED_FOUND__
+#error 6
+#elif __has_embed(__FILE__ suffix(x) limit(0) prefix(1)) != __STDC_EMBED_EMPTY__
+#error 7
+#elif __has_embed(__FILE__ suffix(x) limit(1) prefix(1) clang::offset(1)) != __STDC_EMBED_FOUND__
+#error 8
+#elif __has_embed(__FILE__ suffix(x) limit(0)) != __STDC_EMBED_EMPTY__
+#error 9
+#elif __has_embed(__FILE__ suffix(x) limit(0) if_empty(:3)) != __STDC_EMBED_EMPTY__
+#error 10
+#endif
+// expected-no-diagnostics
diff --git a/clang/test/Preprocessor/embed_art.c b/clang/test/Preprocessor/embed_art.c
new file mode 100644
index 0000000..a664715
--- /dev/null
+++ b/clang/test/Preprocessor/embed_art.c
@@ -0,0 +1,104 @@
+// RUN: %clang_cc1 -std=c23 %s -fsyntax-only --embed-dir=%S/Inputs -verify
+// expected-no-diagnostics
+
+const char data[] = {
+#embed <media/art.txt>
+};
+const char data2[] = {
+#embed <media/art.txt>
+, 0
+};
+const char data3[] = {
+#embed <media/art.txt> suffix(, 0)
+};
+const char data4[] = {
+#embed <media/art.txt> suffix(,)
+0
+};
+static_assert(sizeof(data) == 274);
+static_assert(' ' == data[0]);
+static_assert('_' == data[11]);
+static_assert('\n' == data[273]);
+static_assert(sizeof(data2) == 275);
+static_assert(' ' == data2[0]);
+static_assert('_' == data2[11]);
+static_assert('\n' == data2[273]);
+static_assert('\0' == data2[274]);
+static_assert(sizeof(data3) == 275);
+static_assert(' ' == data3[0]);
+static_assert('_' == data3[11]);
+static_assert('\n' == data3[273]);
+static_assert('\0' == data3[274]);
+static_assert(sizeof(data4) == 275);
+static_assert(' ' == data4[0]);
+static_assert('_' == data4[11]);
+static_assert('\n' == data4[273]);
+static_assert('\0' == data4[274]);
+
+const signed char data5[] = {
+#embed <media/art.txt>
+};
+const signed char data6[] = {
+#embed <media/art.txt>
+, 0
+};
+const signed char data7[] = {
+#embed <media/art.txt> suffix(, 0)
+};
+const signed char data8[] = {
+#embed <media/art.txt> suffix(,)
+0
+};
+static_assert(sizeof(data5) == 274);
+static_assert(' ' == data5[0]);
+static_assert('_' == data5[11]);
+static_assert('\n' == data5[273]);
+static_assert(sizeof(data6) == 275);
+static_assert(' ' == data6[0]);
+static_assert('_' == data6[11]);
+static_assert('\n' == data6[273]);
+static_assert('\0' == data6[274]);
+static_assert(sizeof(data7) == 275);
+static_assert(' ' == data7[0]);
+static_assert('_' == data7[11]);
+static_assert('\n' == data7[273]);
+static_assert('\0' == data7[274]);
+static_assert(sizeof(data8) == 275);
+static_assert(' ' == data8[0]);
+static_assert('_' == data8[11]);
+static_assert('\n' == data8[273]);
+static_assert('\0' == data8[274]);
+
+const unsigned char data9[] = {
+#embed <media/art.txt>
+};
+const unsigned char data10[] = {
+0,
+#embed <media/art.txt>
+};
+const unsigned char data11[] = {
+#embed <media/art.txt> prefix(0,)
+};
+const unsigned char data12[] = {
+0
+#embed <media/art.txt> prefix(,)
+};
+static_assert(sizeof(data9) == 274);
+static_assert(' ' == data9[0]);
+static_assert('_' == data9[11]);
+static_assert('\n' == data9[273]);
+static_assert(sizeof(data10) == 275);
+static_assert(' ' == data10[1]);
+static_assert('_' == data10[12]);
+static_assert('\n' == data10[274]);
+static_assert('\0' == data10[0]);
+static_assert(sizeof(data11) == 275);
+static_assert(' ' == data11[1]);
+static_assert('_' == data11[12]);
+static_assert('\n' == data11[274]);
+static_assert('\0' == data11[0]);
+static_assert(sizeof(data12) == 275);
+static_assert(' ' == data12[1]);
+static_assert('_' == data12[12]);
+static_assert('\n' == data12[274]);
+static_assert('\0' == data12[0]);
diff --git a/clang/test/Preprocessor/embed_codegen.cpp b/clang/test/Preprocessor/embed_codegen.cpp
new file mode 100644
index 0000000..64110af
--- /dev/null
+++ b/clang/test/Preprocessor/embed_codegen.cpp
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 %s -triple x86_64 --embed-dir=%S/Inputs -emit-llvm -o - | FileCheck %s
+
+// CHECK: @__const._Z3fooi.ca = private unnamed_addr constant [3 x i32] [i32 0, i32 106, i32 107], align 4
+// CHECK: @__const._Z3fooi.sc = private unnamed_addr constant %struct.S1 { i32 106, i32 107, i32 0 }, align 4
+// CHECK: @__const._Z3fooi.t = private unnamed_addr constant [3 x %struct.T] [%struct.T { [2 x i32] [i32 48, i32 49], %struct.S1 { i32 50, i32 51, i32 52 } }, %struct.T { [2 x i32] [i32 53, i32 54], %struct.S1 { i32 55, i32 56, i32 57 } }, %struct.T { [2 x i32] [i32 10, i32 0], %struct.S1 zeroinitializer }], align 16
+void foo(int a) {
+// CHECK: %a.addr = alloca i32, align 4
+// CHECK: store i32 %a, ptr %a.addr, align 4
+// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %ca, ptr align 4 @__const._Z3fooi.ca, i64 12, i1 false)
+int ca[] = {
+0
+#embed <jk.txt> prefix(,)
+};
+
+// CHECK: %arrayinit.element = getelementptr inbounds i32, ptr %notca, i64 1
+// CHECK: store i8 106, ptr %arrayinit.element, align 4
+// CHECK: %arrayinit.element1 = getelementptr inbounds i32, ptr %notca, i64 2
+// CHECK: store i8 107, ptr %arrayinit.element1, align 4
+int notca[] = {
+a
+#embed <jk.txt> prefix(,)
+};
+
+struct S1 {
+ int x, y, z;
+};
+
+// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %sc, ptr align 4 @__const._Z3fooi.sc, i64 12, i1 false)
+S1 sc = {
+#embed <jk.txt> suffix(,)
+0
+};
+
+// CHECK: %x = getelementptr inbounds %struct.S1, ptr %s, i32 0, i32 0
+// CHECK: store i32 106, ptr %x, align 4
+// CHECK: %y = getelementptr inbounds %struct.S1, ptr %s, i32 0, i32 1
+// CHECK: store i32 107, ptr %y, align 4
+// CHECK: %z = getelementptr inbounds %struct.S1, ptr %s, i32 0, i32 2
+// CHECK: %1 = load i32, ptr %a.addr, align 4
+S1 s = {
+#embed <jk.txt> suffix(,)
+a
+};
+
+// CHECK: store i32 107, ptr %b, align 4
+int b =
+#embed<jk.txt>
+;
+
+
+struct T {
+ int arr[2];
+ struct S1 s;
+};
+
+// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 16 %t, ptr align 16 @__const._Z3fooi.t, i64 60, i1 false)
+constexpr struct T t[] = {
+#embed <numbers.txt>
+};
+
+// CHECK: %arr = getelementptr inbounds %struct.T, ptr %tnonc, i32 0, i32 0
+// CHECK: %2 = load i32, ptr %a.addr, align 4
+// CHECK: store i32 %2, ptr %arr, align 4
+// CHECK: %arrayinit.element2 = getelementptr inbounds i32, ptr %arr, i64 1
+// CHECK: store i32 300, ptr %arrayinit.element2, align 4
+// CHECK: %s3 = getelementptr inbounds %struct.T, ptr %tnonc, i32 0, i32 1
+// CHECK: %x4 = getelementptr inbounds %struct.S1, ptr %s3, i32 0, i32 0
+// CHECK: store i32 1, ptr %x4, align 4
+// CHECK: %y5 = getelementptr inbounds %struct.S1, ptr %s3, i32 0, i32 1
+// CHECK: store i32 2, ptr %y5, align 4
+// CHECK: %z6 = getelementptr inbounds %struct.S1, ptr %s3, i32 0, i32 2
+// CHECK: store i32 3, ptr %z6, align 4
+// CHECK: %arrayinit.element7 = getelementptr inbounds %struct.T, ptr %tnonc, i64 1
+// CHECK: call void @llvm.memset.p0.i64(ptr align 4 %arrayinit.element7, i8 0, i64 20, i1 false)
+// CHECK: %arr8 = getelementptr inbounds %struct.T, ptr %arrayinit.element7, i32 0, i32 0
+// CHECK: store i8 106, ptr %arr8, align 4
+// CHECK: %arrayinit.element9 = getelementptr inbounds i32, ptr %arr8, i64 1
+// CHECK: store i8 107, ptr %arrayinit.element9, align 4
+struct T tnonc[] = {
+ a, 300, 1, 2, 3
+#embed <jk.txt> prefix(,)
+};
+
+}
diff --git a/clang/test/Preprocessor/embed_constexpr.cpp b/clang/test/Preprocessor/embed_constexpr.cpp
new file mode 100644
index 0000000..1cadff7
--- /dev/null
+++ b/clang/test/Preprocessor/embed_constexpr.cpp
@@ -0,0 +1,97 @@
+// RUN: %clang_cc1 %s -fsyntax-only --embed-dir=%S/Inputs -verify -Wno-c23-extensions
+// RUN: %clang_cc1 %s -fsyntax-only --embed-dir=%S/Inputs -verify -fexperimental-new-constant-interpreter -Wno-c23-extensions
+
+constexpr int value(int a, int b) {
+ return a + b;
+}
+
+constexpr int func_call() {
+ return value(
+#embed <jk.txt>
+ );
+}
+
+constexpr int init_list_expr() {
+ int vals[] = {
+#embed <jk.txt>
+ };
+ return value(vals[0], vals[1]);
+}
+
+template <int N, int M>
+struct Hurr {
+ static constexpr int V1 = N;
+ static constexpr int V2 = M;
+};
+
+constexpr int template_args() {
+ Hurr<
+#embed <jk.txt>
+ > H;
+ return value(H.V1, H.V2);
+}
+
+constexpr int ExpectedValue = 'j' + 'k';
+static_assert(func_call() == ExpectedValue);
+static_assert(init_list_expr() == ExpectedValue);
+static_assert(template_args() == ExpectedValue);
+
+static_assert(
+#embed <jk.txt> limit(1) suffix(== 'j')
+);
+
+int array[
+#embed <jk.txt> limit(1)
+];
+static_assert(sizeof(array) / sizeof(int) == 'j');
+
+constexpr int comma_expr = (
+#embed <jk.txt> // expected-warning {{left operand of comma operator has no effect}}
+);
+static_assert(comma_expr == 'k');
+
+constexpr int comma_expr_init_list{ (
+#embed <jk.txt> limit(1)
+) };
+static_assert(comma_expr_init_list == 'j');
+
+constexpr int paren_init(
+#embed <jk.txt> limit(1)
+);
+static_assert(paren_init == 'j');
+
+struct S {
+ const char buffer[2] = {
+#embed "jk.txt"
+ };
+};
+
+constexpr struct S s;
+static_assert(s.buffer[1] == 'k');
+
+struct S1 {
+ int x, y;
+};
+
+struct T {
+ int x, y;
+ struct S1 s;
+};
+
+constexpr struct T t[] = {
+#embed <numbers.txt>
+};
+static_assert(t[0].s.x == '2');
+
+constexpr int func(int i, int) { return i; }
+static_assert(
+ func(
+#embed <jk.txt>
+ ) == 'j');
+
+template <int N>
+struct ST {};
+
+ST<
+#embed <jk.txt> limit(1)
+> st;
diff --git a/clang/test/Preprocessor/embed_dependencies.c b/clang/test/Preprocessor/embed_dependencies.c
new file mode 100644
index 0000000..4e00dc7
--- /dev/null
+++ b/clang/test/Preprocessor/embed_dependencies.c
@@ -0,0 +1,20 @@
+// RUN: %clang %s -fsyntax-only -std=c23 -M --embed-dir=%S/Inputs -Xclang -verify | FileCheck %s
+
+// Yes this looks very strange indeed, but the goal is to test that we add
+// files referenced by both __has_embed and #embed when we generate
+// dependencies, so we're trying to see that both of these files are in the
+// output.
+#if __has_embed(<jk.txt>)
+const char data =
+#embed "Inputs/single_byte.txt"
+;
+_Static_assert('b' == data);
+#else
+#error "oops"
+#endif
+// expected-no-diagnostics
+
+// CHECK: embed_dependencies.c \
+// CHECK-NEXT: jk.txt \
+// CHECK-NEXT: Inputs{{[/\\]}}single_byte.txt
+
diff --git a/clang/test/Preprocessor/embed_ext_compat_diags.c b/clang/test/Preprocessor/embed_ext_compat_diags.c
new file mode 100644
index 0000000..74f2417
--- /dev/null
+++ b/clang/test/Preprocessor/embed_ext_compat_diags.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c23 %s -fsyntax-only --embed-dir=%S/Inputs -verify=none -pedantic
+// RUN: %clang_cc1 -std=c23 %s -fsyntax-only --embed-dir=%S/Inputs -verify=compat -Wpre-c23-compat
+// RUN: %clang_cc1 -std=c17 %s -fsyntax-only --embed-dir=%S/Inputs -verify=ext -pedantic
+// RUN: %clang_cc1 -x c++ %s -fsyntax-only --embed-dir=%S/Inputs -verify=cxx -pedantic
+// none-no-diagnostics
+
+#if __has_embed("jk.txt")
+
+const char buffer[] = {
+#embed "jk.txt" /* compat-warning {{#embed is incompatible with C standards before C23}}
+ ext-warning {{#embed is a C23 extension}}
+ cxx-warning {{#embed is a Clang extension}}
+ */
+};
+#endif
+
diff --git a/clang/test/Preprocessor/embed_feature_test.cpp b/clang/test/Preprocessor/embed_feature_test.cpp
new file mode 100644
index 0000000..2648804
--- /dev/null
+++ b/clang/test/Preprocessor/embed_feature_test.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -E -CC -verify
+// RUN: %clang_cc1 -x c %s -E -CC -verify
+// expected-no-diagnostics
+
+#if !defined(__has_embed)
+#error 1
+#endif
diff --git a/clang/test/Preprocessor/embed_file_not_found_chevron.c b/clang/test/Preprocessor/embed_file_not_found_chevron.c
new file mode 100644
index 0000000..472222a
--- /dev/null
+++ b/clang/test/Preprocessor/embed_file_not_found_chevron.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -std=c23 %s -E -verify
+
+#embed <nfejfNejAKFe>
+// expected-error@-1 {{'nfejfNejAKFe' file not found}}
diff --git a/clang/test/Preprocessor/embed_file_not_found_quote.c b/clang/test/Preprocessor/embed_file_not_found_quote.c
new file mode 100644
index 0000000..bf9c62b
--- /dev/null
+++ b/clang/test/Preprocessor/embed_file_not_found_quote.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -std=c23 %s -E -verify
+
+#embed "nfejfNejAKFe"
+// expected-error@-1 {{'nfejfNejAKFe' file not found}}
diff --git a/clang/test/Preprocessor/embed_init.c b/clang/test/Preprocessor/embed_init.c
new file mode 100644
index 0000000..79b1743
--- /dev/null
+++ b/clang/test/Preprocessor/embed_init.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c23 %s -fsyntax-only --embed-dir=%S/Inputs -verify
+// RUN: %clang_cc1 -std=c23 %s -fsyntax-only --embed-dir=%S/Inputs -verify -fexperimental-new-constant-interpreter
+// expected-no-diagnostics
+
+typedef struct kitty {
+ int purr;
+} kitty;
+
+typedef struct kitty_kitty {
+ int here;
+ kitty kit;
+} kitty_kitty;
+
+const int meow =
+#embed <single_byte.txt>
+;
+
+const kitty kit = {
+#embed <single_byte.txt>
+};
+
+const kitty_kitty kit_kit = {
+#embed <jk.txt>
+};
+
+static_assert(meow == 'b');
+static_assert(kit.purr == 'b');
+static_assert(kit_kit.here == 'j');
+static_assert(kit_kit.kit.purr == 'k');
diff --git a/clang/test/Preprocessor/embed_parameter_if_empty.c b/clang/test/Preprocessor/embed_parameter_if_empty.c
new file mode 100644
index 0000000..70f1bc6
--- /dev/null
+++ b/clang/test/Preprocessor/embed_parameter_if_empty.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c23 %s --embed-dir=%S/Inputs -fsyntax-only -verify
+
+const char data[] = {
+#embed <media/empty> if_empty(123, 124, 125)
+};
+const char non_empty_data[] = {
+#embed <jk.txt> if_empty(123, 124, 125)
+};
+static_assert(sizeof(data) == 3);
+static_assert(123 == data[0]);
+static_assert(124 == data[1]);
+static_assert(125 == data[2]);
+static_assert(sizeof(non_empty_data) == 2);
+static_assert('j' == non_empty_data[0]);
+static_assert('k' == non_empty_data[1]);
+
+// Ensure we diagnose duplicate parameters even if they're the same value.
+const unsigned char a[] = {
+#embed <jk.txt> if_empty(1) prefix() if_empty(2)
+// expected-error@-1 {{cannot specify parameter 'if_empty' twice in the same '#embed' directive}}
+,
+#embed <jk.txt> if_empty(1) suffix() if_empty(2)
+// expected-error@-1 {{cannot specify parameter 'if_empty' twice in the same '#embed' directive}}
+};
diff --git a/clang/test/Preprocessor/embed_parameter_limit.c b/clang/test/Preprocessor/embed_parameter_limit.c
new file mode 100644
index 0000000..da3e4fb
--- /dev/null
+++ b/clang/test/Preprocessor/embed_parameter_limit.c
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 -std=c23 %s --embed-dir=%S/Inputs -fsyntax-only -verify
+
+const char data[] = {
+#embed <jk.txt>
+};
+const char offset_data[] = {
+#embed <jk.txt> limit(1)
+};
+static_assert(sizeof(data) == 2);
+static_assert('j' == data[0]);
+static_assert('k' == data[1]);
+static_assert(sizeof(offset_data) == 1);
+static_assert('j' == offset_data[0]);
+static_assert(offset_data[0] == data[0]);
+
+// Cannot have a negative limit.
+#embed <jk.txt> limit(-1)
+// expected-error@-1 {{invalid value '-1'; must be positive}}
+
+// It can have a limit of 0, in which case the __has_embed should return false.
+#if __has_embed(<jk.txt> limit(0)) != __STDC_EMBED_EMPTY__
+#error "__has_embed should return false when there's no data"
+#endif
+
+// When the limit is zero, the resource is empty, so if_empty kicks in.
+const unsigned char buffer[] = {
+#embed <jk.txt> limit(0) if_empty(1)
+};
+static_assert(sizeof(buffer) == 1);
+static_assert(buffer[0] == 1);
+
+// However, prefix and suffix do not kick in.
+const unsigned char other_buffer[] = {
+ 1,
+#embed <jk.txt> limit(0) prefix(2,) suffix(3)
+};
+static_assert(sizeof(other_buffer) == 1);
+static_assert(other_buffer[0] == 1);
+
+// Ensure we can limit to something larger than the file size as well.
+const unsigned char third_buffer[] = {
+#embed <jk.txt> limit(100)
+};
+static_assert(sizeof(third_buffer) == 2);
+static_assert('j' == third_buffer[0]);
+static_assert('k' == third_buffer[1]);
+
+// Test the limits of a file with more than one character in it.
+const unsigned char fourth_buffer[] = {
+#embed <media/art.txt> limit(10)
+};
+static_assert(sizeof(fourth_buffer) == 10);
+static_assert(' ' == fourth_buffer[0]);
+static_assert(' ' == fourth_buffer[1]);
+static_assert(' ' == fourth_buffer[2]);
+static_assert(' ' == fourth_buffer[3]);
+static_assert(' ' == fourth_buffer[4]);
+static_assert(' ' == fourth_buffer[5]);
+static_assert(' ' == fourth_buffer[6]);
+static_assert(' ' == fourth_buffer[7]);
+static_assert(' ' == fourth_buffer[8]);
+static_assert(' ' == fourth_buffer[9]);
+
+// Ensure that a limit larger than what can fit into a 64-bit value is
+// rejected. This limit is fine because it fits in a 64-bit value.
+const unsigned char fifth_buffer[] = {
+#embed <jk.txt> limit(0xFFFF'FFFF'FFFF'FFFF)
+};
+static_assert(sizeof(fifth_buffer) == 2);
+static_assert('j' == fifth_buffer[0]);
+static_assert('k' == fifth_buffer[1]);
+
+// But this one is not fine because it does not fit into a 64-bit value.
+const unsigned char sixth_buffer[] = {
+#embed <jk.txt> limit(0xFFFF'FFFF'FFFF'FFFF'1)
+};
+// expected-error@-2 {{integer literal is too large to be represented in any integer type}}
+// Note: the preprocessor will continue with the truncated value, so the parser
+// will treat this case and the previous one identically in terms of what
+// contents are retained from the embedded resource (which is the entire file).
+
+// Ensure we diagnose duplicate parameters even if they're the same value.
+const unsigned char a[] = {
+#embed <jk.txt> limit(1) prefix() limit(1)
+// expected-error@-1 {{cannot specify parameter 'limit' twice in the same '#embed' directive}}
+,
+#embed <jk.txt> limit(1) if_empty() limit(2)
+// expected-error@-1 {{cannot specify parameter 'limit' twice in the same '#embed' directive}}
+};
+
+// C23 6.10.3.2p2
+static_assert(
+#embed <jk.txt> limit(defined(FOO)) // expected-error {{'defined' cannot appear within this context}}
+ == 0); // expected-error {{expected expression}}
diff --git a/clang/test/Preprocessor/embed_parameter_offset.c b/clang/test/Preprocessor/embed_parameter_offset.c
new file mode 100644
index 0000000..ab1bd3f
--- /dev/null
+++ b/clang/test/Preprocessor/embed_parameter_offset.c
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -std=c23 %s --embed-dir=%S/Inputs -fsyntax-only -verify
+
+const char data[] = {
+#embed <jk.txt>
+};
+const char offset_data[] = {
+#embed <jk.txt> clang::offset(1)
+};
+static_assert(sizeof(data) == 2);
+static_assert('j' == data[0]);
+static_assert('k' == data[1]);
+static_assert(sizeof(offset_data) == 1);
+static_assert('k' == offset_data[0]);
+static_assert(offset_data[0] == data[1]);
+
+// Cannot have a negative offset.
+#embed <jk.txt> clang::offset(-1)
+// expected-error@-1 {{invalid value '-1'; must be positive}}
+
+// If the offset is past the end of the file, the file should be considered
+// empty.
+#if __has_embed(<jk.txt> clang::offset(3)) != __STDC_EMBED_EMPTY__
+#error "__has_embed should return false when there's no data"
+#endif
+
+// When the offset is past the end of the file, the resource is empty, so if_empty kicks in.
+const unsigned char buffer[] = {
+#embed <jk.txt> clang::offset(3) if_empty(1)
+};
+static_assert(sizeof(buffer) == 1);
+static_assert(buffer[0] == 1);
+
+// However, prefix and suffix do not kick in.
+const unsigned char other_buffer[] = {
+ 1,
+#embed <jk.txt> clang::offset(3) prefix(2,) suffix(3)
+};
+static_assert(sizeof(other_buffer) == 1);
+static_assert(other_buffer[0] == 1);
+
+// Ensure we can offset to zero (that's the default behavior)
+const unsigned char third_buffer[] = {
+#embed <jk.txt> clang::offset(0)
+};
+static_assert(sizeof(third_buffer) == 2);
+static_assert('j' == third_buffer[0]);
+static_assert('k' == third_buffer[1]);
+
+// Test the offsets of a file with more than one character in it.
+const unsigned char fourth_buffer[] = {
+#embed <media/art.txt> clang::offset(24) limit(4)
+};
+static_assert(sizeof(fourth_buffer) == 4);
+static_assert('.' == fourth_buffer[0]);
+static_assert('-' == fourth_buffer[1]);
+static_assert('.' == fourth_buffer[2]);
+static_assert('\'' == fourth_buffer[3]);
+
+// Ensure that an offset larger than what can fit into a 64-bit value is
+// rejected. This offset is fine because it fits in a 64-bit value.
+const unsigned char fifth_buffer[] = {
+ 1,
+#embed <jk.txt> clang::offset(0xFFFF'FFFF'FFFF'FFFF)
+};
+static_assert(sizeof(fifth_buffer) == 1);
+static_assert(1 == fifth_buffer[0]);
+
+// But this one is not fine because it does not fit into a 64-bit value.
+const unsigned char sixth_buffer[] = {
+#embed <jk.txt> clang::offset(0xFFFF'FFFF'FFFF'FFFF'1)
+};
+// expected-error@-2 {{integer literal is too large to be represented in any integer type}}
+
+// Ensure we diagnose duplicate parameters even if they're the same value.
+const unsigned char a[] = {
+#embed <jk.txt> clang::offset(1) prefix() clang::offset(1)
+// expected-error@-1 {{cannot specify parameter 'clang::offset' twice in the same '#embed' directive}}
+,
+#embed <jk.txt> clang::offset(1) if_empty() clang::offset(2)
+// expected-error@-1 {{cannot specify parameter 'clang::offset' twice in the same '#embed' directive}}
+};
+
+// Matches with C23 6.10.3.2p2, is documented as part of our extension.
+static_assert(
+#embed <jk.txt> clang::offset(defined(FOO))
+ == 0); // expected-error {{expected expression}}
+ /* expected-error@-2 {{'defined' cannot appear within this context}}
+ pedantic-warning@-2 {{'clang::offset' is a Clang extension}}
+ */
diff --git a/clang/test/Preprocessor/embed_parameter_prefix.c b/clang/test/Preprocessor/embed_parameter_prefix.c
new file mode 100644
index 0000000..b55c08f
--- /dev/null
+++ b/clang/test/Preprocessor/embed_parameter_prefix.c
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -std=c23 %s --embed-dir=%S/Inputs -fsyntax-only -verify
+
+const char data[] = {
+#embed <single_byte.txt> prefix('\xA', )
+};
+const char empty_data[] = {
+#embed <media/empty> prefix('\xA', )
+1
+};
+static_assert(sizeof(data) == 2);
+static_assert('\xA' == data[0]);
+static_assert('b' == data[1]);
+static_assert(sizeof(empty_data) == 1);
+static_assert(1 == empty_data[0]);
+
+struct S {
+ int x, y, z;
+};
+
+const struct S s = {
+#embed <single_byte.txt> prefix( .x = 100, .y = 10, )
+};
+static_assert(s.x == 100);
+static_assert(s.y == 10);
+static_assert(s.z == 'b');
+
+// Ensure that an empty file does not produce any prefix tokens. If it did,
+// there would be random tokens here that the parser would trip on.
+#embed <media/empty> prefix(0)
+
+// Ensure we diagnose duplicate parameters even if they're the same value.
+const unsigned char a[] = {
+#embed <jk.txt> prefix(1,) limit(1) prefix(1,)
+// expected-error@-1 {{cannot specify parameter 'prefix' twice in the same '#embed' directive}}
+,
+#embed <jk.txt> prefix(1,) if_empty() prefix(2,)
+// expected-error@-1 {{cannot specify parameter 'prefix' twice in the same '#embed' directive}}
+};
diff --git a/clang/test/Preprocessor/embed_parameter_suffix.c b/clang/test/Preprocessor/embed_parameter_suffix.c
new file mode 100644
index 0000000..7d768268
--- /dev/null
+++ b/clang/test/Preprocessor/embed_parameter_suffix.c
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -std=c23 %s --embed-dir=%S/Inputs -fsyntax-only -verify
+
+const char data[] = {
+#embed <single_byte.txt> suffix(, '\xA')
+};
+const char empty_data[] = {
+#embed <media/empty> suffix(, '\xA')
+1
+};
+static_assert(sizeof(data) == 2);
+static_assert('b' == data[0]);
+static_assert('\xA' == data[1]);
+static_assert(sizeof(empty_data) == 1);
+static_assert(1 == empty_data[0]);
+
+struct S {
+ int x, y, z;
+};
+
+const struct S s = {
+#embed <single_byte.txt> suffix( , .y = 100, .z = 10 )
+};
+
+static_assert(s.x == 'b');
+static_assert(s.y == 100);
+static_assert(s.z == 10);
+
+// Ensure that an empty file does not produce any suffix tokens. If it did,
+// there would be random tokens here that the parser would trip on.
+#embed <media/empty> suffix(0)
+
+// Ensure we diagnose duplicate parameters even if they're the same value.
+const unsigned char a[] = {
+#embed <jk.txt> suffix(,1) prefix() suffix(,1)
+// expected-error@-1 {{cannot specify parameter 'suffix' twice in the same '#embed' directive}}
+,
+#embed <jk.txt> suffix(,1) if_empty() suffix(,2)
+// expected-error@-1 {{cannot specify parameter 'suffix' twice in the same '#embed' directive}}
+};
diff --git a/clang/test/Preprocessor/embed_parameter_unrecognized.c b/clang/test/Preprocessor/embed_parameter_unrecognized.c
new file mode 100644
index 0000000..b033843
--- /dev/null
+++ b/clang/test/Preprocessor/embed_parameter_unrecognized.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -std=c23 -E -verify
+// okay-no-diagnostics
+
+#embed __FILE__ unrecognized
+// expected-error@-1 {{unknown embed preprocessor parameter 'unrecognized'}}
+#embed __FILE__ unrecognized::param
+// expected-error@-1 {{unknown embed preprocessor parameter 'unrecognized::param'}}
+#embed __FILE__ unrecognized::param(with, args)
+// expected-error@-1 {{unknown embed preprocessor parameter 'unrecognized::param'}}
diff --git a/clang/test/Preprocessor/embed_parsing_errors.c b/clang/test/Preprocessor/embed_parsing_errors.c
new file mode 100644
index 0000000..490ec6d
--- /dev/null
+++ b/clang/test/Preprocessor/embed_parsing_errors.c
@@ -0,0 +1,130 @@
+// RUN: %clang_cc1 -std=c23 %s -E -verify
+
+// Test the parsing behavior for #embed and all of its parameters to ensure we
+// recover from failures gracefully.
+char buffer[] = {
+#embed
+// expected-error@-1 {{expected "FILENAME" or <FILENAME>}}
+
+#embed <
+// expected-error@-1 {{expected '>'}} \
+ expected-note@-1 {{to match this '<'}}
+
+#embed "
+// expected-error@-1 {{expected "FILENAME" or <FILENAME>}} \
+ expected-warning@-1 {{missing terminating '"' character}}
+
+#embed file.txt
+// expected-error@-1{{expected "FILENAME" or <FILENAME>}}
+
+#embed "embed_parsing_errors.c" xxx
+// expected-error@-1 {{unknown embed preprocessor parameter 'xxx'}}
+
+#embed "embed_parsing_errors.c" xxx::
+// expected-error@-1 {{expected identifier}}
+
+#embed "embed_parsing_errors.c" xxx::xxx
+// expected-error@-1 {{unknown embed preprocessor parameter 'xxx::xxx'}}
+
+#embed "embed_parsing_errors.c" xxx::42
+// expected-error@-1 {{expected identifier}}
+
+#embed "embed_parsing_errors.c" limit
+// expected-error@-1 {{expected '('}}
+
+#embed "embed_parsing_errors.c" limit(
+// expected-error@-1 {{expected value in expression}}
+
+#embed "embed_parsing_errors.c" limit(xxx
+// expected-error@-1 {{expected ')'}}
+
+#embed "embed_parsing_errors.c" limit(42
+// expected-error@-1 {{expected ')'}}
+
+#embed "embed_parsing_errors.c" limit([
+// expected-error@-1 {{invalid token at start of a preprocessor expression}}
+
+#embed "embed_parsing_errors.c" limit([)
+// expected-error@-1 {{invalid token at start of a preprocessor expression}}
+
+#embed "embed_parsing_errors.c" limit(1/0)
+// expected-error@-1 {{division by zero in preprocessor expression}}
+
+#embed "embed_parsing_errors.c" clang::offset
+// expected-error@-1 {{expected '('}}
+
+#embed "embed_parsing_errors.c" clang::offset(
+// expected-error@-1 {{expected value in expression}}
+
+#embed "embed_parsing_errors.c" clang::offset(xxx
+// expected-error@-1 {{expected ')'}}
+
+#embed "embed_parsing_errors.c" clang::offset(42
+// expected-error@-1 {{expected ')'}}
+
+#embed "embed_parsing_errors.c" clang::offset([
+// expected-error@-1 {{invalid token at start of a preprocessor expression}}
+
+#embed "embed_parsing_errors.c" clang::offset([)
+// expected-error@-1 {{invalid token at start of a preprocessor expression}}
+
+#embed "embed_parsing_errors.c" clang::offset(1/0)
+// expected-error@-1 {{division by zero in preprocessor expression}}
+
+#embed "embed_parsing_errors.c" clang::offset 42
+// expected-error@-1 {{expected '('}}
+
+#embed "embed_parsing_errors.c" prefix
+// expected-error@-1 {{expected '('}}
+
+#embed "embed_parsing_errors.c" prefix(
+// expected-error@-1 {{expected ')'}}
+
+#embed "embed_parsing_errors.c" prefix(xxx
+// expected-error@-1 {{expected ')'}}
+
+#embed "embed_parsing_errors.c" prefix(1/0) // OK: emitted as tokens, not evaluated yet.
+#embed "embed_parsing_errors.c" prefix(([{}])) // OK: delimiters balanced
+#embed "embed_parsing_errors.c" prefix(([{)]})
+// expected-error@-1 {{expected '}'}} expected-note@-1 {{to match this '{'}}
+#embed "embed_parsing_errors.c" prefix(([{})})
+// expected-error@-1 {{expected ']'}} expected-note@-1 {{to match this '['}}
+#embed "embed_parsing_errors.c" prefix(([{}]})
+// expected-error@-1 {{expected ')'}} expected-note@-1 {{to match this '('}}
+#embed "embed_parsing_errors.c" prefix() // OK: tokens within parens are optional
+#embed "embed_parsing_errors.c" prefix)
+// expected-error@-1 {{expected '('}}
+
+#embed "embed_parsing_errors.c" suffix
+// expected-error@-1 {{expected '('}}
+
+#embed "embed_parsing_errors.c" suffix(
+// expected-error@-1 {{expected ')'}}
+
+#embed "embed_parsing_errors.c" suffix(xxx
+// expected-error@-1 {{expected ')'}}
+
+#embed "embed_parsing_errors.c" suffix(1/0) // OK: emitted as tokens, not evaluated yet.
+#embed "embed_parsing_errors.c" suffix(([{}])) // OK: delimiters balanced
+#embed "embed_parsing_errors.c" suffix(([{)]})
+// expected-error@-1 {{expected '}'}} expected-note@-1 {{to match this '{'}}
+#embed "embed_parsing_errors.c" suffix(([{})})
+// expected-error@-1 {{expected ']'}} expected-note@-1 {{to match this '['}}
+#embed "embed_parsing_errors.c" suffix(([{}]})
+// expected-error@-1 {{expected ')'}} expected-note@-1 {{to match this '('}}
+#embed "embed_parsing_errors.c" suffix() // OK: tokens within parens are optional
+#embed "embed_parsing_errors.c" suffix)
+// expected-error@-1 {{expected '('}}
+
+#embed "embed_parsing_errors.c" if_empty(1/0) // OK: emitted as tokens, not evaluated yet.
+#embed "embed_parsing_errors.c" if_empty(([{}])) // OK: delimiters balanced
+#embed "embed_parsing_errors.c" if_empty(([{)]})
+// expected-error@-1 {{expected '}'}} expected-note@-1 {{to match this '{'}}
+#embed "embed_parsing_errors.c" if_empty(([{})})
+// expected-error@-1 {{expected ']'}} expected-note@-1 {{to match this '['}}
+#embed "embed_parsing_errors.c" if_empty(([{}]})
+// expected-error@-1 {{expected ')'}} expected-note@-1 {{to match this '('}}
+#embed "embed_parsing_errors.c" if_empty() // OK: tokens within parens are optional
+#embed "embed_parsing_errors.c" if_empty)
+// expected-error@-1 {{expected '('}}
+};
diff --git a/clang/test/Preprocessor/embed_path_chevron.c b/clang/test/Preprocessor/embed_path_chevron.c
new file mode 100644
index 0000000..b12cb9ce
--- /dev/null
+++ b/clang/test/Preprocessor/embed_path_chevron.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -std=c23 -fsyntax-only --embed-dir=%S/Inputs -verify
+// expected-no-diagnostics
+
+const char data[] = {
+#embed <single_byte.txt>
+};
+static_assert(sizeof(data) == 1);
+static_assert('b' == data[0]);
diff --git a/clang/test/Preprocessor/embed_path_quote.c b/clang/test/Preprocessor/embed_path_quote.c
new file mode 100644
index 0000000..79ca1e5
--- /dev/null
+++ b/clang/test/Preprocessor/embed_path_quote.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c23 %s -fsyntax-only --embed-dir=%S/Inputs -verify
+// expected-no-diagnostics
+
+const char data[] = {
+#embed "single_byte.txt"
+};
+static_assert(sizeof(data) == 1);
+static_assert('a' == data[0]);
diff --git a/clang/test/Preprocessor/embed_preprocess_to_file.c b/clang/test/Preprocessor/embed_preprocess_to_file.c
new file mode 100644
index 0000000..9895d95
--- /dev/null
+++ b/clang/test/Preprocessor/embed_preprocess_to_file.c
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -std=c23 %s -E --embed-dir=%S/Inputs | FileCheck %s --check-prefix EXPANDED
+// RUN: %clang_cc1 -std=c23 %s -E -dE --embed-dir=%S/Inputs | FileCheck %s --check-prefix DIRECTIVE
+
+// Ensure that we correctly preprocess to a file, both with expanding embed
+// directives fully and with printing the directive instead.
+const char data[] = {
+#embed <jk.txt> if_empty('a', 'b') clang::offset(0) limit(1) suffix(, 'a', 0) prefix('h',)
+};
+
+// EXPANDED: const char data[] = {'h',106 , 'a', 0};
+// DIRECTIVE: const char data[] = {
+// DIRECTIVE-NEXT: #embed <jk.txt> if_empty('a', 'b') limit(1) clang::offset(0) prefix('h',) suffix(, 'a', 0) /* clang -E -dE */
+// DIRECTIVE-NEXT: };
+
+const char more[] = {
+#embed <media/empty> if_empty('a', 'b')
+};
+
+// EXPANDED: const char more[] = {'a', 'b'}
+// DIRECTIVE: const char more[] = {
+// DIRECTIVE-NEXT: #embed <media/empty> if_empty('a', 'b') /* clang -E -dE */
+// DIRECTIVE-NEXT: };
+
+const char even_more[] = {
+ 1, 2, 3,
+#embed <jk.txt> prefix(4, 5,) suffix(, 6, 7)
+ , 8, 9, 10
+};
+
+// EXPANDED: const char even_more[] = {
+// EXPANDED-NEXT: 1, 2, 3,4, 5,106, 107 , 6, 7 , 8, 9, 10
+// EXPANDED-EMPTY:
+// EXPANDED-EMPTY:
+// EXPANDED-NEXT: };
+// DIRECTIVE: const char even_more[] = {
+// DIRECTIVE-NEXT: 1, 2, 3,
+// DIRECTIVE-NEXT: #embed <jk.txt> prefix(4, 5,) suffix(, 6, 7) /* clang -E -dE */
+// DIRECTIVE-NEXT: , 8, 9, 10
+// DIRECTIVE-NEXT: };
diff --git a/clang/test/Preprocessor/embed_single_entity.c b/clang/test/Preprocessor/embed_single_entity.c
new file mode 100644
index 0000000..2019118
--- /dev/null
+++ b/clang/test/Preprocessor/embed_single_entity.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -fsyntax-only -std=c23 --embed-dir=%S/Inputs -verify
+
+const char data =
+#embed <single_byte.txt>
+;
+_Static_assert('b' == data);
+// expected-no-diagnostics
diff --git a/clang/test/Preprocessor/embed_weird.cpp b/clang/test/Preprocessor/embed_weird.cpp
new file mode 100644
index 0000000..a31b083
--- /dev/null
+++ b/clang/test/Preprocessor/embed_weird.cpp
@@ -0,0 +1,98 @@
+// RUN: %clang_cc1 %s -fsyntax-only --embed-dir=%S/Inputs -verify=expected,cxx -Wno-c23-extensions
+// RUN: %clang_cc1 -x c -std=c23 %s -fsyntax-only --embed-dir=%S/Inputs -verify=expected,c
+#embed <media/empty>
+;
+
+void f (unsigned char x) { (void)x;}
+void g () {}
+void h (unsigned char x, int y) {(void)x; (void)y;}
+int i () {
+ return
+#embed <single_byte.txt>
+ ;
+}
+
+_Static_assert(
+#embed <single_byte.txt> suffix(,)
+""
+);
+_Static_assert(
+#embed <single_byte.txt>
+, ""
+);
+_Static_assert(sizeof(
+#embed <single_byte.txt>
+) ==
+sizeof(unsigned char)
+, ""
+);
+_Static_assert(sizeof
+#embed <single_byte.txt>
+, ""
+);
+_Static_assert(sizeof(
+#embed <jk.txt> // expected-warning {{left operand of comma operator has no effect}}
+) ==
+sizeof(unsigned char)
+, ""
+);
+
+#ifdef __cplusplus
+template <int First, int Second>
+void j() {
+ static_assert(First == 'j', "");
+ static_assert(Second == 'k', "");
+}
+#endif
+
+void do_stuff() {
+ f(
+#embed <single_byte.txt>
+ );
+ g(
+#embed <media/empty>
+ );
+ h(
+#embed <jk.txt>
+ );
+ int r = i();
+ (void)r;
+#ifdef __cplusplus
+ j<
+#embed <jk.txt>
+ >(
+#embed <media/empty>
+ );
+#endif
+}
+
+// Ensure that we don't accidentally allow you to initialize an unsigned char *
+// from embedded data; the data is modeled as a string literal internally, but
+// is not actually a string literal.
+const unsigned char *ptr =
+#embed <jk.txt> // expected-warning {{left operand of comma operator has no effect}}
+; // c-error@-2 {{incompatible integer to pointer conversion initializing 'const unsigned char *' with an expression of type 'unsigned char'}} \
+ cxx-error@-2 {{cannot initialize a variable of type 'const unsigned char *' with an rvalue of type 'unsigned char'}}
+
+// However, there are some cases where this is fine and should work.
+const unsigned char *null_ptr_1 =
+#embed <media/empty> if_empty(0)
+;
+
+const unsigned char *null_ptr_2 =
+#embed <null_byte.bin>
+;
+
+const unsigned char *null_ptr_3 = {
+#embed <null_byte.bin>
+};
+
+#define FILE_NAME <null_byte.bin>
+#define LIMIT 1
+#define OFFSET 0
+#define EMPTY_SUFFIX suffix()
+
+constexpr unsigned char ch =
+#embed FILE_NAME limit(LIMIT) clang::offset(OFFSET) EMPTY_SUFFIX
+;
+static_assert(ch == 0);
diff --git a/clang/test/Preprocessor/init-aarch64.c b/clang/test/Preprocessor/init-aarch64.c
index f084598..9e425ac 100644
--- a/clang/test/Preprocessor/init-aarch64.c
+++ b/clang/test/Preprocessor/init-aarch64.c
@@ -272,6 +272,9 @@
// AARCH64-NEXT: #define __SIZE_WIDTH__ 64
// AARCH64_CXX: #define __STDCPP_DEFAULT_NEW_ALIGNMENT__ 16UL
// AARCH64_CXX: #define __STDCPP_THREADS__ 1
+// AARCH64-NEXT: #define __STDC_EMBED_EMPTY__ 2
+// AARCH64-NEXT: #define __STDC_EMBED_FOUND__ 1
+// AARCH64-NEXT: #define __STDC_EMBED_NOT_FOUND__ 0
// AARCH64-NEXT: #define __STDC_HOSTED__ 1
// AARCH64-NEXT: #define __STDC_UTF_16__ 1
// AARCH64-NEXT: #define __STDC_UTF_32__ 1
diff --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c
index 2641fee..57bf671 100644
--- a/clang/test/Preprocessor/init.c
+++ b/clang/test/Preprocessor/init.c
@@ -1875,6 +1875,9 @@
// WEBASSEMBLY-NEXT:#define __SIZE_TYPE__ long unsigned int
// WEBASSEMBLY32-NEXT:#define __SIZE_WIDTH__ 32
// WEBASSEMBLY64-NEXT:#define __SIZE_WIDTH__ 64
+// WEBASSEMBLY-NEXT:#define __STDC_EMBED_EMPTY__ 2
+// WEBASSEMBLY-NEXT:#define __STDC_EMBED_FOUND__ 1
+// WEBASSEMBLY-NEXT:#define __STDC_EMBED_NOT_FOUND__ 0
// WEBASSEMBLY-NEXT:#define __STDC_HOSTED__ 0
// WEBASSEMBLY-NOT:#define __STDC_MB_MIGHT_NEQ_WC__
// WEBASSEMBLY-NOT:#define __STDC_NO_ATOMICS__
diff --git a/clang/test/Preprocessor/single_byte.txt b/clang/test/Preprocessor/single_byte.txt
new file mode 100644
index 0000000..2e65efe
--- /dev/null
+++ b/clang/test/Preprocessor/single_byte.txt
@@ -0,0 +1 @@
+a \ No newline at end of file