llvm/clang/test/Preprocessor/embed_weird.cpp

// RUN: rm -rf %t && mkdir -p %t/media
// RUN: cp %S/Inputs/single_byte.txt %S/Inputs/jk.txt %S/Inputs/numbers.txt %t/
// RUN: cp %S/Inputs/media/empty %t/media/
// RUN: printf "\0" > %t/null_byte.bin
// RUN: %clang_cc1 %s -fsyntax-only --embed-dir=%t -verify=expected,cxx -Wno-c23-extensions
// RUN: %clang_cc1 -x c -std=c23 %s -fsyntax-only --embed-dir=%t -verify=expected,c
// RUN: %clang_cc1 %s -fsyntax-only -fexperimental-new-constant-interpreter --embed-dir=%t -verify=expected,cxx -Wno-c23-extensions
// RUN: %clang_cc1 -x c -std=c23 %s -fsyntax-only -fexperimental-new-constant-interpreter --embed-dir=%t -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(int)
, ""
);
_Static_assert(sizeof
#embed <single_byte.txt>
, ""
);
_Static_assert(sizeof(
#embed <jk.txt>
) ==
sizeof(int)
, ""
);

#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 'int'}} \
     cxx-error@-2 {{cannot initialize a variable of type 'const unsigned char *' with an rvalue of type 'int'}}

// 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);

void foobar(float x, char y, char z);
void g1() { foobar((float)
#embed "numbers.txt" limit(3)
);
}

#if __cplusplus
struct S { S(char x); ~S(); };
void f1() {
  S s[] = {
#embed "null_byte.bin"
  };
}
#endif

static_assert(_Generic(
#embed __FILE__ limit(1)
  , int : 1, default : 0));

static_assert(alignof(typeof(
#embed __FILE__ limit(1)
)) == alignof(int));

struct HasChar {
  signed char ch;
};

constexpr struct HasChar c = {
#embed "Inputs/big_char.txt" // cxx-error {{constant expression evaluates to 255 which cannot be narrowed to type 'signed char'}} \
                                cxx-note {{insert an explicit cast to silence this issue}} \
                                c-error {{constexpr initializer evaluates to 255 which is not exactly representable in type 'signed char'}}

};