mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 09:06:43 +00:00

Track the identity of each string literal object produced by evaluation with a global version number. Accept comparisons between literals of the same version, and between literals of different versions that cannot possibly be placed in overlapping storage. Treat the remaining comparisons as non-constant. --------- Co-authored-by: Timm Baeder <tbaeder@redhat.com> Co-authored-by: Aaron Ballman <aaron@aaronballman.com>
206 lines
8.2 KiB
C++
206 lines
8.2 KiB
C++
// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++11 -fcxx-exceptions -fptrauth-intrinsics
|
|
// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++1z -fcxx-exceptions -fptrauth-intrinsics
|
|
typedef const struct __CFString * CFStringRef;
|
|
#define CFSTR __builtin___CFStringMakeConstantString
|
|
#define NSSTR __builtin___NSStringMakeConstantString
|
|
|
|
void f() {
|
|
#if !defined(__MVS__) && !defined(_AIX)
|
|
// Builtin function __builtin___CFStringMakeConstantString is currently
|
|
// unsupported on z/OS and AIX.
|
|
(void)CFStringRef(CFSTR("Hello"));
|
|
|
|
constexpr bool a = CFSTR("Hello") == CFSTR("Hello");
|
|
// expected-error@-1 {{constant expression}}
|
|
// expected-note@-2 {{comparison against opaque constant address '&__builtin___CFStringMakeConstantString("Hello")'}}
|
|
constexpr bool b = NSSTR("Hello") == NSSTR("Hello");
|
|
// expected-error@-1 {{constant expression}}
|
|
// expected-note@-2 {{comparison against opaque constant address '&__builtin___NSStringMakeConstantString("Hello")'}}
|
|
#endif
|
|
}
|
|
|
|
void a() { __builtin_va_list x, y; ::__builtin_va_copy(x, y); }
|
|
|
|
template<int (*Compare)(const char *s1, const char *s2)>
|
|
int equal(const char *s1, const char *s2) {
|
|
return Compare(s1, s2) == 0;
|
|
}
|
|
template int equal<&__builtin_strcmp>(const char*, const char*); // expected-error {{builtin functions must be directly called}}
|
|
|
|
// PR13195
|
|
void f2() {
|
|
__builtin_isnan; // expected-error {{builtin functions must be directly called}}
|
|
}
|
|
|
|
// pr14895
|
|
typedef __typeof(sizeof(int)) size_t;
|
|
extern "C" void *__builtin_alloca (size_t);
|
|
|
|
namespace addressof {
|
|
struct S {} s;
|
|
static_assert(__builtin_addressof(s) == &s, "");
|
|
|
|
struct T { constexpr T *operator&() const { return nullptr; } int n; } t;
|
|
constexpr T *pt = __builtin_addressof(t);
|
|
static_assert(&pt->n == &t.n, "");
|
|
|
|
struct U { int n : 5; } u;
|
|
int *pbf = __builtin_addressof(u.n); // expected-error {{address of bit-field requested}}
|
|
|
|
S *ptmp = __builtin_addressof(S{}); // expected-error {{taking the address of a temporary}} expected-warning {{temporary whose address is used as value of local variable 'ptmp' will be destroyed at the end of the full-expression}}
|
|
}
|
|
|
|
namespace function_start {
|
|
void a(void) {}
|
|
int n;
|
|
void *p = __builtin_function_start(n); // expected-error {{argument must be a function}}
|
|
static_assert(__builtin_function_start(a) == a, ""); // expected-error {{static assertion expression is not an integral constant expression}}
|
|
// expected-note@-1 {{comparison against opaque constant address '&__builtin_function_start(a)'}}
|
|
} // namespace function_start
|
|
|
|
void no_ms_builtins() {
|
|
__assume(1); // expected-error {{use of undeclared}}
|
|
__noop(1); // expected-error {{use of undeclared}}
|
|
__debugbreak(); // expected-error {{use of undeclared}}
|
|
}
|
|
|
|
struct FILE;
|
|
extern "C" int vfprintf(FILE *__restrict, const char *__restrict,
|
|
__builtin_va_list va);
|
|
|
|
void synchronize_args() {
|
|
__sync_synchronize(0); // expected-error {{too many arguments}}
|
|
}
|
|
|
|
namespace test_launder {
|
|
#define TEST_TYPE(Ptr, Type) \
|
|
static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
|
|
|
|
struct Dummy {};
|
|
|
|
using FnType = int(char);
|
|
using MemFnType = int (Dummy::*)(char);
|
|
using ConstMemFnType = int (Dummy::*)() const;
|
|
|
|
void foo() {}
|
|
|
|
void test_builtin_empty_parentheses_diags() {
|
|
__is_trivially_copyable(); // expected-error {{expected a type}}
|
|
__is_trivially_copyable(1); // expected-error {{expected a type}}
|
|
}
|
|
|
|
void test_builtin_launder_diags(void *vp, const void *cvp, FnType *fnp,
|
|
MemFnType mfp, ConstMemFnType cmfp, int (&Arr)[5]) {
|
|
__builtin_launder(vp); // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
|
|
__builtin_launder(cvp); // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
|
|
__builtin_launder(fnp); // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
|
|
__builtin_launder(mfp); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
|
|
__builtin_launder(cmfp); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
|
|
(void)__builtin_launder(&fnp);
|
|
__builtin_launder(42); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
|
|
__builtin_launder(nullptr); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
|
|
__builtin_launder(foo); // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
|
|
(void)__builtin_launder(Arr);
|
|
}
|
|
|
|
void test_builtin_launder(char *p, const volatile int *ip, const float *&fp,
|
|
double *__restrict dp) {
|
|
int x;
|
|
__builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
|
|
|
|
TEST_TYPE(p, char*);
|
|
TEST_TYPE(ip, const volatile int*);
|
|
TEST_TYPE(fp, const float*);
|
|
TEST_TYPE(dp, double *__restrict);
|
|
|
|
char *d = __builtin_launder(p);
|
|
const volatile int *id = __builtin_launder(ip);
|
|
int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
|
|
const float* fd = __builtin_launder(fp);
|
|
}
|
|
|
|
void test_launder_return_type(const int (&ArrayRef)[101], int (&MArrRef)[42][13],
|
|
void (**&FuncPtrRef)()) {
|
|
TEST_TYPE(ArrayRef, const int *);
|
|
TEST_TYPE(MArrRef, int(*)[13]);
|
|
TEST_TYPE(FuncPtrRef, void (**)());
|
|
}
|
|
|
|
template <class Tp>
|
|
constexpr Tp *test_constexpr_launder(Tp *tp) {
|
|
return __builtin_launder(tp);
|
|
}
|
|
constexpr int const_int = 42;
|
|
constexpr int const_int2 = 101;
|
|
constexpr const int *const_ptr = test_constexpr_launder(&const_int);
|
|
static_assert(&const_int == const_ptr, "");
|
|
static_assert(const_ptr != test_constexpr_launder(&const_int2), "");
|
|
|
|
void test_non_constexpr() {
|
|
constexpr int i = 42; // expected-note {{address of non-static constexpr variable 'i' may differ on each invocation}}
|
|
constexpr const int *ip = __builtin_launder(&i); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
|
|
// expected-note@-1 {{pointer to 'i' is not a constant expression}}
|
|
}
|
|
|
|
constexpr bool test_in_constexpr(const int &i) {
|
|
return (__builtin_launder(&i) == &i);
|
|
}
|
|
|
|
static_assert(test_in_constexpr(const_int), "");
|
|
void f() {
|
|
constexpr int i = 42;
|
|
static_assert(test_in_constexpr(i), "");
|
|
}
|
|
|
|
struct Incomplete; // expected-note {{forward declaration}}
|
|
struct IncompleteMember {
|
|
Incomplete &i;
|
|
};
|
|
void test_incomplete(Incomplete *i, IncompleteMember *im) {
|
|
// expected-error@+1 {{incomplete type 'Incomplete' where a complete type is required}}
|
|
__builtin_launder(i);
|
|
__builtin_launder(&i); // OK
|
|
__builtin_launder(im); // OK
|
|
}
|
|
|
|
void test_noexcept(int *i) {
|
|
static_assert(noexcept(__builtin_launder(i)), "");
|
|
}
|
|
#undef TEST_TYPE
|
|
} // end namespace test_launder
|
|
|
|
template<typename T> void test_builtin_complex(T v, double d) {
|
|
(void)__builtin_complex(v, d); // expected-error {{different types}} expected-error {{not a real floating}}
|
|
(void)__builtin_complex(d, v); // expected-error {{different types}} expected-error {{not a real floating}}
|
|
(void)__builtin_complex(v, v); // expected-error {{not a real floating}}
|
|
}
|
|
template void test_builtin_complex(double, double);
|
|
template void test_builtin_complex(float, double); // expected-note {{instantiation of}}
|
|
template void test_builtin_complex(int, double); // expected-note {{instantiation of}}
|
|
|
|
#ifdef __x86_64__
|
|
// This previously would cause an assertion when emitting the note diagnostic.
|
|
static void __builtin_cpu_init(); // expected-error {{static declaration of '__builtin_cpu_init' follows non-static declaration}} \
|
|
expected-note {{'__builtin_cpu_init' is a builtin with type 'void () noexcept'}}
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
constexpr int x = [] {
|
|
__noop;
|
|
return 0;
|
|
}(); // expected-no-diagnostics
|
|
static_assert([] { return __noop; }() == 0);
|
|
static_assert([] { return __noop(4); }() == 0);
|
|
extern int not_accessed;
|
|
void not_called();
|
|
static_assert([] { return __noop(not_accessed *= 6); }() == 0);
|
|
static_assert([] { return __noop(not_called()); }() == 0);
|
|
static_assert([] { return __noop(throw ""); }() == 0);
|
|
static_assert([] { return __noop(throw "", throw ""); }() == 0);
|
|
static_assert([] {
|
|
int a = 5;
|
|
__noop(++a);
|
|
return a;
|
|
}() == 5);
|
|
#endif
|