diff options
Diffstat (limited to 'clang/test/Sema')
-rw-r--r-- | clang/test/Sema/aarch64-sve-intrinsics/acle_sve_compact.cpp | 18 | ||||
-rw-r--r-- | clang/test/Sema/address-packed.c | 8 | ||||
-rw-r--r-- | clang/test/Sema/attr-cfi-salt.c | 60 | ||||
-rw-r--r-- | clang/test/Sema/builtin-object-size.c | 4 | ||||
-rw-r--r-- | clang/test/Sema/builtins-elementwise-math.c | 36 | ||||
-rw-r--r-- | clang/test/Sema/builtins-wasm.c | 17 | ||||
-rw-r--r-- | clang/test/Sema/constant-builtins-vector.cpp | 34 | ||||
-rw-r--r-- | clang/test/Sema/designated-initializers.c | 7 | ||||
-rw-r--r-- | clang/test/Sema/format-strings-signedness.c | 60 | ||||
-rw-r--r-- | clang/test/Sema/implicit-void-ptr-cast.c | 12 | ||||
-rw-r--r-- | clang/test/Sema/ptrauth-qualifier.c | 16 | ||||
-rw-r--r-- | clang/test/Sema/warn-lifetime-safety-dataflow.cpp | 153 | ||||
-rw-r--r-- | clang/test/Sema/warn-lifetime-safety.cpp | 273 |
13 files changed, 586 insertions, 112 deletions
diff --git a/clang/test/Sema/aarch64-sve-intrinsics/acle_sve_compact.cpp b/clang/test/Sema/aarch64-sve-intrinsics/acle_sve_compact.cpp new file mode 100644 index 0000000..4de3f39 --- /dev/null +++ b/clang/test/Sema/aarch64-sve-intrinsics/acle_sve_compact.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve \ +// RUN: -verify -verify-ignore-unexpected=error,note -emit-llvm -o - %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme \ +// RUN: -verify -verify-ignore-unexpected=error,note -emit-llvm -o - %s +// REQUIRES: aarch64-registered-target +// expected-no-diagnostics + +#include <arm_sve.h> + +__attribute__((target("sme2p2"))) +void test_svcompact(svbool_t pg, svfloat32_t op) __arm_streaming{ + svcompact(pg, op); +} + +void test_svcompact_nofeature(svbool_t pg, svfloat32_t op) __arm_streaming{ + // expected-error@+1 {{'svcompact' needs target feature (sve)|(sme, sme2p2)}} + svcompact(pg, op); +}
\ No newline at end of file diff --git a/clang/test/Sema/address-packed.c b/clang/test/Sema/address-packed.c index 29f1249..f826b7d 100644 --- a/clang/test/Sema/address-packed.c +++ b/clang/test/Sema/address-packed.c @@ -338,3 +338,11 @@ struct Invalid0 { void *g14(struct Invalid0 *ivl) { return &(ivl->x); } + +void to_void_with_expr(void *ptr, int expr); + +void g15(void) { + struct Arguable arguable; + to_void_with_expr(&arguable.x, 3); // no-warning + to_void_with_expr(&arguable.x, ({3;})); // no-warning +} diff --git a/clang/test/Sema/attr-cfi-salt.c b/clang/test/Sema/attr-cfi-salt.c new file mode 100644 index 0000000..bccdfc4 --- /dev/null +++ b/clang/test/Sema/attr-cfi-salt.c @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 -std=c11 -fsyntax-only -fsanitize=kcfi -verify %s +// RUN: %clang_cc1 -std=c89 -DKNR -fsyntax-only -fsanitize=kcfi -verify %s + +#define __cfi_salt(S) __attribute__((cfi_salt(S))) + +int bad1(void) __cfi_salt(); // expected-error{{'cfi_salt' attribute takes one argument}} +int bad2(void) __cfi_salt(42); // expected-error{{expected string literal as argument of 'cfi_salt' attribute}} +int bad3(void) __attribute__((cfi_salt("a", "b", "c"))); // expected-error{{'cfi_salt' attribute takes one argument}} + + +int foo(int a, int b) __cfi_salt("pepper"); // ok +int foo(int a, int b) __cfi_salt("pepper"); // ok + +#ifndef KNR +typedef int (*bar_t)(void) __cfi_salt("pepper"); // ok +typedef int (*bar_t)(void) __cfi_salt("pepper"); // ok +#endif + +// FIXME: Should we allow this? +// int b(void) __cfi_salt("salt 'n") __cfi_salt("pepper"); +// bar_t bar_fn __cfi_salt("salt 'n"); + +int baz __cfi_salt("salt"); // expected-warning{{'cfi_salt' only applies to function types}} + +int baz_fn(int a, int b) __cfi_salt("salt 'n"); // expected-note{{previous declaration is here}} +int baz_fn(int a, int b) __cfi_salt("pepper"); // expected-error{{conflicting types for 'baz_fn'}} + +int mux_fn(int a, int b) __cfi_salt("salt 'n"); // expected-note{{previous declaration is here}} +int mux_fn(int a, int b) __cfi_salt("pepper") { // expected-error{{conflicting types for 'mux_fn'}} + return a * b; +} + +typedef int qux_t __cfi_salt("salt"); // expected-warning{{'cfi_salt' only applies to function types}} + +typedef int (*quux_t)(void) __cfi_salt("salt 'n"); // expected-note{{previous definition is here}} +typedef int (*quux_t)(void) __cfi_salt("pepper"); // expected-error{{typedef redefinition with different type}} + +void func1(int a) __cfi_salt("pepper"); // expected-note{{previous declaration is here}} +void func1(int a) { } // expected-error{{conflicting types for 'func1'}} +void (*fp1)(int) = func1; // expected-error{{incompatible function pointer types initializing 'void (*)(int)' with an expression of type 'void (int)'}} + +void func2(int) [[clang::cfi_salt("test")]]; // expected-note{{previous declaration is here}} +void func2(int a) { } // expected-error{{conflicting types for 'func2'}} +void (*fp2)(int) = func2; // expected-error{{incompatible function pointer types initializing 'void (*)(int)' with an expression of type 'void (int)'}} + +void func3(int) __cfi_salt("pepper"); // ok +void func3(int a) __cfi_salt("pepper") { } // ok +void (* __cfi_salt("pepper") fp3)(int) = func3; // ok +void (*fp3_noattr)(int) = func3; // expected-error{{incompatible function pointer types initializing 'void (*)(int)' with an expression of type 'void (int)'}} + +void func4(int) [[clang::cfi_salt("test")]]; // ok +void func4(int a) [[clang::cfi_salt("test")]] { } // ok +void (* [[clang::cfi_salt("test")]] fp4)(int) = func4; // ok +void (*fp4_noattr)(int) = func4; // expected-error{{incompatible function pointer types initializing 'void (*)(int)' with an expression of type 'void (int)'}} + +#ifdef KNR +// K&R C function without a prototype +void func() __attribute__((cfi_salt("pepper"))); // expected-error {{attribute only applies to non-K&R-style functions}} +void (*fp)() __attribute__((cfi_salt("pepper"))); // expected-error {{attribute only applies to non-K&R-style functions}} +#endif diff --git a/clang/test/Sema/builtin-object-size.c b/clang/test/Sema/builtin-object-size.c index 20d4e2a..a763c24 100644 --- a/clang/test/Sema/builtin-object-size.c +++ b/clang/test/Sema/builtin-object-size.c @@ -2,6 +2,10 @@ // RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin9 -verify %s // RUN: %clang_cc1 -DDYNAMIC -fsyntax-only -triple x86_64-apple-darwin9 -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin9 -verify %s -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -DDYNAMIC -fsyntax-only -triple x86_64-apple-darwin9 -verify %s -fexperimental-new-constant-interpreter + #ifndef DYNAMIC #define OBJECT_SIZE_BUILTIN __builtin_object_size #else diff --git a/clang/test/Sema/builtins-elementwise-math.c b/clang/test/Sema/builtins-elementwise-math.c index 8548d3b..a80ff4b 100644 --- a/clang/test/Sema/builtins-elementwise-math.c +++ b/clang/test/Sema/builtins-elementwise-math.c @@ -1294,6 +1294,42 @@ void test_builtin_elementwise_fma(int i32, int2 v2i32, short i16, // expected-error@-1 {{3rd argument must be a scalar or vector of floating-point types (was '_Complex float')}} } +void test_builtin_elementwise_fsh(int i32, int2 v2i32, short i16, int3 v3i32, + double f64, float f32, float2 v2f32) { + i32 = __builtin_elementwise_fshl(); + // expected-error@-1 {{too few arguments to function call, expected 3, have 0}} + + i32 = __builtin_elementwise_fshr(); + // expected-error@-1 {{too few arguments to function call, expected 3, have 0}} + + i32 = __builtin_elementwise_fshl(i32, i32); + // expected-error@-1 {{too few arguments to function call, expected 3, have 2}} + + i32 = __builtin_elementwise_fshr(i32, i32); + // expected-error@-1 {{too few arguments to function call, expected 3, have 2}} + + i32 = __builtin_elementwise_fshl(i32, i32, i16); + // expected-error@-1 {{arguments are of different types ('int' vs 'short')}} + + i16 = __builtin_elementwise_fshr(i16, i32, i16); + // expected-error@-1 {{arguments are of different types ('short' vs 'int')}} + + f32 = __builtin_elementwise_fshl(f32, f32, f32); + // expected-error@-1 {{argument must be a scalar or vector of integer types (was 'float')}} + + f64 = __builtin_elementwise_fshr(f64, f64, f64); + // expected-error@-1 {{argument must be a scalar or vector of integer types (was 'double')}} + + v2i32 = __builtin_elementwise_fshl(v2i32, v2i32, v2f32); + // expected-error@-1 {{argument must be a scalar or vector of integer types (was 'float2' (vector of 2 'float' values))}} + + v2i32 = __builtin_elementwise_fshr(v2i32, v2i32, v3i32); + // expected-error@-1 {{arguments are of different types ('int2' (vector of 2 'int' values) vs 'int3' (vector of 3 'int' values))}} + + v3i32 = __builtin_elementwise_fshl(v3i32, v3i32, v2i32); + // expected-error@-1 {{arguments are of different types ('int3' (vector of 3 'int' values) vs 'int2' (vector of 2 'int' values))}} +} + typedef struct { float3 b; } struct_float3; diff --git a/clang/test/Sema/builtins-wasm.c b/clang/test/Sema/builtins-wasm.c index a3486b1..9075e9e 100644 --- a/clang/test/Sema/builtins-wasm.c +++ b/clang/test/Sema/builtins-wasm.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify -triple wasm32 -target-feature +reference-types %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple wasm32 -target-abi experimental-mv -DMULTIVALUE -target-feature +reference-types %s #define EXPR_HAS_TYPE(expr, type) _Generic((expr), type : 1, default : 0) @@ -57,8 +58,8 @@ void test_table_copy(int dst_idx, int src_idx, int nelem) { typedef void (*F1)(void); typedef int (*F2)(int); -typedef int (*F3)(__externref_t); -typedef __externref_t (*F4)(int); +typedef void (*F3)(struct {int x; double y;}); +typedef struct {int x; double y;} (*F4)(void); void test_function_pointer_signature() { // Test argument count validation @@ -68,8 +69,6 @@ void test_function_pointer_signature() { // // Test argument type validation - should require function pointer (void)__builtin_wasm_test_function_pointer_signature((void*)0); // expected-error {{used type 'void *' where function pointer is required}} (void)__builtin_wasm_test_function_pointer_signature((int)0); // expected-error {{used type 'int' where function pointer is required}} - (void)__builtin_wasm_test_function_pointer_signature((F3)0); // expected-error {{not supported for function pointers with a reference type parameter}} - (void)__builtin_wasm_test_function_pointer_signature((F4)0); // expected-error {{not supported for function pointers with a reference type return value}} // // Test valid usage int res = __builtin_wasm_test_function_pointer_signature((F1)0); @@ -77,4 +76,14 @@ void test_function_pointer_signature() { // Test return type _Static_assert(EXPR_HAS_TYPE(__builtin_wasm_test_function_pointer_signature((F1)0), int), ""); + +#ifdef MULTIVALUE + // Test that struct arguments and returns are rejected with multivalue abi + (void)__builtin_wasm_test_function_pointer_signature((F3)0); // expected-error {{not supported with the multivalue ABI for function pointers with a struct/union as parameter}} + (void)__builtin_wasm_test_function_pointer_signature((F4)0); // expected-error {{not supported with the multivalue ABI for function pointers with a struct/union as return value}} +#else + // with default abi they are fine + (void)__builtin_wasm_test_function_pointer_signature((F3)0); + (void)__builtin_wasm_test_function_pointer_signature((F4)0); +#endif } diff --git a/clang/test/Sema/constant-builtins-vector.cpp b/clang/test/Sema/constant-builtins-vector.cpp index bde5c47..2b7d76e 100644 --- a/clang/test/Sema/constant-builtins-vector.cpp +++ b/clang/test/Sema/constant-builtins-vector.cpp @@ -860,3 +860,37 @@ static_assert(__builtin_elementwise_sub_sat(0U, 1U) == 0U); static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_sub_sat((vector4char){5, 4, 3, 2}, (vector4char){1, 1, 1, 1})) == (LITTLE_END ? 0x01020304 : 0x04030201)); static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_sub_sat((vector4uchar){5, 4, 3, 2}, (vector4uchar){1, 1, 1, 1})) == (LITTLE_END ? 0x01020304U : 0x04030201U)); static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_sub_sat((vector4short){(short)0x8000, (short)0x8001, (short)0x8002, (short)0x8003}, (vector4short){7, 8, 9, 10}) == (LITTLE_END ? 0x8000800080008000 : 0x8000800080008000))); + +static_assert(__builtin_elementwise_max(1, 2) == 2); +static_assert(__builtin_elementwise_max(-1, 1) == 1); +static_assert(__builtin_elementwise_max(1U, 2U) == 2U); +static_assert(__builtin_elementwise_max(~0U, 0U) == ~0U); +static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_max((vector4char){1, -2, 3, -4}, (vector4char){4, -3, 2, -1})) == (LITTLE_END ? 0xFF03FE04 : 0x04FE03FF )); +static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_max((vector4uchar){1, 2, 3, 4}, (vector4uchar){4, 3, 2, 1})) == 0x04030304U); +static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_max((vector4short){1, -2, 3, -4}, (vector4short){4, -3, 2, -1})) == (LITTLE_END ? 0xFFFF0003FFFE0004 : 0x0004FFFE0003FFFF)); + +static_assert(__builtin_elementwise_min(1, 2) == 1); +static_assert(__builtin_elementwise_min(-1, 1) == -1); +static_assert(__builtin_elementwise_min(1U, 2U) == 1U); +static_assert(__builtin_elementwise_min(~0U, 0U) == 0U); +static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_min((vector4char){1, -2, 3, -4}, (vector4char){4, -3, 2, -1})) == (LITTLE_END ? 0xFC02FD01 : 0x01FD02FC)); +static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_min((vector4uchar){1, 2, 3, 4}, (vector4uchar){4, 3, 2, 1})) == 0x01020201U); +static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_min((vector4short){1, -2, 3, -4}, (vector4short){4, -3, 2, -1})) == (LITTLE_END ? 0xFFFC0002FFFD0001 : 0x0001FFFD0002FFFC)); + +static_assert(__builtin_elementwise_abs(10) == 10); +static_assert(__builtin_elementwise_abs(-10) == 10); +static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_abs((vector4char){-1, -2, -3, 4})) == (LITTLE_END ? 0x04030201 : 0x01020304)); +static_assert(__builtin_elementwise_abs((int)(-2147483648)) == (int)(-2147483648)); // the absolute value of the most negative integer remains the most negative integer + +// check floating point for elementwise abs +#define CHECK_FOUR_FLOAT_VEC(vec1, vec2) \ + static_assert(__builtin_fabs(vec1[0] - vec2[0]) < 1e-6); \ + static_assert(__builtin_fabs(vec1[1] - vec2[1]) < 1e-6); \ + static_assert(__builtin_fabs(vec1[2] - vec2[2]) < 1e-6); \ + static_assert(__builtin_fabs(vec1[3] - vec2[3]) < 1e-6); + +// checking floating point vector +CHECK_FOUR_FLOAT_VEC(__builtin_elementwise_abs((vector4float){-1.123, 2.123, -3.123, 4.123}), ((vector4float){1.123, 2.123, 3.123, 4.123})) +CHECK_FOUR_FLOAT_VEC(__builtin_elementwise_abs((vector4double){-1.123, 2.123, -3.123, 4.123}), ((vector4double){1.123, 2.123, 3.123, 4.123})) +static_assert(__builtin_elementwise_abs((float)-1.123) - (float)1.123 < 1e-6); // making sure one element works +#undef CHECK_FOUR_FLOAT_VEC diff --git a/clang/test/Sema/designated-initializers.c b/clang/test/Sema/designated-initializers.c index 31a3380..11dc3a2 100644 --- a/clang/test/Sema/designated-initializers.c +++ b/clang/test/Sema/designated-initializers.c @@ -368,3 +368,10 @@ struct { .b = 0, // expected-warning {{initializer overrides prior initialization of this subobject}} }, }; + +void gh154046(void) { + (void)(const char[]) { + [0] = "", // expected-error {{incompatible pointer to integer conversion initializing 'const char' with an expression of type 'char[1]'}} + [1] = "" // expected-error {{incompatible pointer to integer conversion initializing 'const char' with an expression of type 'char[1]'}} + }[1]; +} diff --git a/clang/test/Sema/format-strings-signedness.c b/clang/test/Sema/format-strings-signedness.c index d5a8140..773ff41 100644 --- a/clang/test/Sema/format-strings-signedness.c +++ b/clang/test/Sema/format-strings-signedness.c @@ -39,13 +39,13 @@ void test_printf_unsigned_char(unsigned char x) void test_printf_int(int x) { printf("%d", x); // no-warning - printf("%u", x); // expected-warning{{format specifies type 'unsigned int' but the argument has type 'int'}} - printf("%x", x); // expected-warning{{format specifies type 'unsigned int' but the argument has type 'int'}} + printf("%u", x); // expected-warning{{format specifies type 'unsigned int' but the argument has type 'int', which differs in signedness}} + printf("%x", x); // expected-warning{{format specifies type 'unsigned int' but the argument has type 'int', which differs in signedness}} } void test_printf_unsigned(unsigned x) { - printf("%d", x); // expected-warning{{format specifies type 'int' but the argument has type 'unsigned int'}} + printf("%d", x); // expected-warning{{format specifies type 'int' but the argument has type 'unsigned int', which differs in signedness}} printf("%u", x); // no-warning printf("%x", x); // no-warning } @@ -53,13 +53,13 @@ void test_printf_unsigned(unsigned x) void test_printf_long(long x) { printf("%ld", x); // no-warning - printf("%lu", x); // expected-warning{{format specifies type 'unsigned long' but the argument has type 'long'}} - printf("%lx", x); // expected-warning{{format specifies type 'unsigned long' but the argument has type 'long'}} + printf("%lu", x); // expected-warning{{format specifies type 'unsigned long' but the argument has type 'long', which differs in signedness}} + printf("%lx", x); // expected-warning{{format specifies type 'unsigned long' but the argument has type 'long', which differs in signedness}} } void test_printf_unsigned_long(unsigned long x) { - printf("%ld", x); // expected-warning{{format specifies type 'long' but the argument has type 'unsigned long'}} + printf("%ld", x); // expected-warning{{format specifies type 'long' but the argument has type 'unsigned long', which differs in signedness}} printf("%lu", x); // no-warning printf("%lx", x); // no-warning } @@ -67,13 +67,13 @@ void test_printf_unsigned_long(unsigned long x) void test_printf_long_long(long long x) { printf("%lld", x); // no-warning - printf("%llu", x); // expected-warning{{format specifies type 'unsigned long long' but the argument has type 'long long'}} - printf("%llx", x); // expected-warning{{format specifies type 'unsigned long long' but the argument has type 'long long'}} + printf("%llu", x); // expected-warning{{format specifies type 'unsigned long long' but the argument has type 'long long', which differs in signedness}} + printf("%llx", x); // expected-warning{{format specifies type 'unsigned long long' but the argument has type 'long long', which differs in signedness}} } void test_printf_unsigned_long_long(unsigned long long x) { - printf("%lld", x); // expected-warning{{format specifies type 'long long' but the argument has type 'unsigned long long'}} + printf("%lld", x); // expected-warning{{format specifies type 'long long' but the argument has type 'unsigned long long', which differs in signedness}} printf("%llu", x); // no-warning printf("%llx", x); // no-warning } @@ -85,8 +85,8 @@ enum enum_int { void test_printf_enum_int(enum enum_int x) { printf("%d", x); // no-warning - printf("%u", x); // expected-warning{{format specifies type 'unsigned int' but the argument has underlying type 'int'}} - printf("%x", x); // expected-warning{{format specifies type 'unsigned int' but the argument has underlying type 'int'}} + printf("%u", x); // expected-warning{{format specifies type 'unsigned int' but the argument has underlying type 'int', which differs in signedness}} + printf("%x", x); // expected-warning{{format specifies type 'unsigned int' but the argument has underlying type 'int', which differs in signedness}} } #ifndef _WIN32 // Disabled due to enums have different underlying type on _WIN32 @@ -96,7 +96,7 @@ enum enum_unsigned { void test_printf_enum_unsigned(enum enum_unsigned x) { - printf("%d", x); // expected-warning{{format specifies type 'int' but the argument has underlying type 'unsigned int'}} + printf("%d", x); // expected-warning{{format specifies type 'int' but the argument has underlying type 'unsigned int', which differs in signedness}} printf("%u", x); // no-warning printf("%x", x); // no-warning } @@ -110,8 +110,8 @@ enum enum_long { void test_printf_enum_long(enum enum_long x) { printf("%ld", x); // no-warning - printf("%lu", x); // expected-warning{{format specifies type 'unsigned long' but the argument has underlying type 'long'}} - printf("%lx", x); // expected-warning{{format specifies type 'unsigned long' but the argument has underlying type 'long'}} + printf("%lu", x); // expected-warning{{format specifies type 'unsigned long' but the argument has underlying type 'long', which differs in signedness}} + printf("%lx", x); // expected-warning{{format specifies type 'unsigned long' but the argument has underlying type 'long', which differs in signedness}} } enum enum_unsigned_long { @@ -120,7 +120,7 @@ enum enum_unsigned_long { void test_printf_enum_unsigned_long(enum enum_unsigned_long x) { - printf("%ld", x); // expected-warning{{format specifies type 'long' but the argument has underlying type 'unsigned long'}} + printf("%ld", x); // expected-warning{{format specifies type 'long' but the argument has underlying type 'unsigned long', which differs in signedness}} printf("%lu", x); // no-warning printf("%lx", x); // no-warning } @@ -136,61 +136,61 @@ void test_scanf_unsigned_char(unsigned char *y) { void test_scanf_int(int *x) { scanf("%d", x); // no-warning - scanf("%u", x); // expected-warning{{format specifies type 'unsigned int *' but the argument has type 'int *'}} - scanf("%x", x); // expected-warning{{format specifies type 'unsigned int *' but the argument has type 'int *'}} + scanf("%u", x); // expected-warning{{format specifies type 'unsigned int *' but the argument has type 'int *', which differs in signedness}} + scanf("%x", x); // expected-warning{{format specifies type 'unsigned int *' but the argument has type 'int *', which differs in signedness}} } void test_scanf_unsigned(unsigned *x) { - scanf("%d", x); // expected-warning{{format specifies type 'int *' but the argument has type 'unsigned int *'}} + scanf("%d", x); // expected-warning{{format specifies type 'int *' but the argument has type 'unsigned int *', which differs in signedness}} scanf("%u", x); // no-warning scanf("%x", x); // no-warning } void test_scanf_long(long *x) { scanf("%ld", x); // no-warning - scanf("%lu", x); // expected-warning{{format specifies type 'unsigned long *' but the argument has type 'long *'}} - scanf("%lx", x); // expected-warning{{format specifies type 'unsigned long *' but the argument has type 'long *'}} + scanf("%lu", x); // expected-warning{{format specifies type 'unsigned long *' but the argument has type 'long *', which differs in signedness}} + scanf("%lx", x); // expected-warning{{format specifies type 'unsigned long *' but the argument has type 'long *', which differs in signedness}} } void test_scanf_unsigned_long(unsigned long *x) { - scanf("%ld", x); // expected-warning{{format specifies type 'long *' but the argument has type 'unsigned long *'}} + scanf("%ld", x); // expected-warning{{format specifies type 'long *' but the argument has type 'unsigned long *', which differs in signedness}} scanf("%lu", x); // no-warning scanf("%lx", x); // no-warning } void test_scanf_longlong(long long *x) { scanf("%lld", x); // no-warning - scanf("%llu", x); // expected-warning{{format specifies type 'unsigned long long *' but the argument has type 'long long *'}} - scanf("%llx", x); // expected-warning{{format specifies type 'unsigned long long *' but the argument has type 'long long *'}} + scanf("%llu", x); // expected-warning{{format specifies type 'unsigned long long *' but the argument has type 'long long *', which differs in signedness}} + scanf("%llx", x); // expected-warning{{format specifies type 'unsigned long long *' but the argument has type 'long long *', which differs in signedness}} } void test_scanf_unsigned_longlong(unsigned long long *x) { - scanf("%lld", x); // expected-warning{{format specifies type 'long long *' but the argument has type 'unsigned long long *'}} + scanf("%lld", x); // expected-warning{{format specifies type 'long long *' but the argument has type 'unsigned long long *', which differs in signedness}} scanf("%llu", x); // no-warning scanf("%llx", x); // no-warning } void test_scanf_enum_int(enum enum_int *x) { scanf("%d", x); // no-warning - scanf("%u", x); // expected-warning{{format specifies type 'unsigned int *' but the argument has type 'enum enum_int *'}} - scanf("%x", x); // expected-warning{{format specifies type 'unsigned int *' but the argument has type 'enum enum_int *'}} + scanf("%u", x); // expected-warning{{format specifies type 'unsigned int *' but the argument has type 'enum enum_int *', which differs in signedness}} + scanf("%x", x); // expected-warning{{format specifies type 'unsigned int *' but the argument has type 'enum enum_int *', which differs in signedness}} } #ifndef _WIN32 // Disabled due to enums have different underlying type on _WIN32 void test_scanf_enum_unsigned(enum enum_unsigned *x) { - scanf("%d", x); // expected-warning{{format specifies type 'int *' but the argument has type 'enum enum_unsigned *'}} + scanf("%d", x); // expected-warning{{format specifies type 'int *' but the argument has type 'enum enum_unsigned *', which differs in signedness}} scanf("%u", x); // no-warning scanf("%x", x); // no-warning } void test_scanf_enum_long(enum enum_long *x) { scanf("%ld", x); // no-warning - scanf("%lu", x); // expected-warning{{format specifies type 'unsigned long *' but the argument has type 'enum enum_long *'}} - scanf("%lx", x); // expected-warning{{format specifies type 'unsigned long *' but the argument has type 'enum enum_long *'}} + scanf("%lu", x); // expected-warning{{format specifies type 'unsigned long *' but the argument has type 'enum enum_long *', which differs in signedness}} + scanf("%lx", x); // expected-warning{{format specifies type 'unsigned long *' but the argument has type 'enum enum_long *', which differs in signedness}} } void test_scanf_enum_unsigned_long(enum enum_unsigned_long *x) { - scanf("%ld", x); // expected-warning{{format specifies type 'long *' but the argument has type 'enum enum_unsigned_long *'}} + scanf("%ld", x); // expected-warning{{format specifies type 'long *' but the argument has type 'enum enum_unsigned_long *', which differs in signedness}} scanf("%lu", x); // no-warning scanf("%lx", x); // no-warning } diff --git a/clang/test/Sema/implicit-void-ptr-cast.c b/clang/test/Sema/implicit-void-ptr-cast.c index 3c3e153..f083cfb 100644 --- a/clang/test/Sema/implicit-void-ptr-cast.c +++ b/clang/test/Sema/implicit-void-ptr-cast.c @@ -82,3 +82,15 @@ void more(void) { ptr3 = SOMETHING_THAT_IS_NOT_NULL; // c-warning {{implicit conversion when assigning to 'char *' from type 'void *' is not permitted in C++}} \ cxx-error {{assigning to 'char *' from incompatible type 'void *'}} } + +void gh154157(void) { + #define ATOMIC_VAR_INIT(value) (value) + + typedef const struct T * T_Ref; + static T_Ref _Atomic x = ATOMIC_VAR_INIT((void*)NULL); // c-warning {{implicit conversion when initializing '_Atomic(T_Ref)' with an expression of type 'void *' is not permitted in C++}} \ + cxx-error {{cannot initialize a variable of type '_Atomic(T_Ref)' with an rvalue of type 'void *'}} + static T_Ref const y = ATOMIC_VAR_INIT((void*)NULL); // c-warning {{implicit conversion when initializing 'const T_Ref' (aka 'const struct T *const') with an expression of type 'void *' is not permitted in C++}} \ + cxx-error {{cannot initialize a variable of type 'const T_Ref' (aka 'const struct T *const') with an rvalue of type 'void *'}} + static T_Ref z = ATOMIC_VAR_INIT((void*)NULL); // c-warning {{implicit conversion when initializing 'T_Ref' (aka 'const struct T *') with an expression of type 'void *' is not permitted in C++}} \ + cxx-error {{cannot initialize a variable of type 'T_Ref' (aka 'const struct T *') with an rvalue of type 'void *'}} +} diff --git a/clang/test/Sema/ptrauth-qualifier.c b/clang/test/Sema/ptrauth-qualifier.c index 5d932b7..3e568ce 100644 --- a/clang/test/Sema/ptrauth-qualifier.c +++ b/clang/test/Sema/ptrauth-qualifier.c @@ -1,13 +1,25 @@ -// RUN: %clang_cc1 -triple arm64-apple-ios -std=c23 -fsyntax-only -verify -fptrauth-intrinsics %s +// RUN: %clang_cc1 -triple arm64-apple-ios -DIS_DARWIN -std=c23 -fsyntax-only -verify -fptrauth-intrinsics %s // RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c23 -fsyntax-only -verify -fptrauth-intrinsics %s -#if !__has_extension(ptrauth_qualifier) +#if defined(IS_DARWIN) && !__has_extension(ptrauth_qualifier) // This error means that the __ptrauth qualifier availability test says that it // is not available. This error is not expected in the output, if it is seen // there is a feature detection regression. #error __ptrauth qualifier not enabled #endif +#if defined(IS_DARWIN) && !__has_feature(ptrauth_qualifier) +// This error means that the __has_feature test for ptrauth_qualifier has +// failed, despite it being expected on darwin. +#error __ptrauth qualifier not enabled +#elif !defined(IS_DARWIN) && (__has_feature(ptrauth_qualifier) || __has_extension(ptrauth_qualifier)) +#error ptrauth_qualifier labeled a feature on a non-darwin platform +#endif + +#if !defined (__PTRAUTH__) +#error __PTRAUTH__ test macro not defined when ptrauth is enabled +#endif + #if __aarch64__ #define VALID_CODE_KEY 0 #define VALID_DATA_KEY 2 diff --git a/clang/test/Sema/warn-lifetime-safety-dataflow.cpp b/clang/test/Sema/warn-lifetime-safety-dataflow.cpp index 2b934ac..bcde9ad 100644 --- a/clang/test/Sema/warn-lifetime-safety-dataflow.cpp +++ b/clang/test/Sema/warn-lifetime-safety-dataflow.cpp @@ -12,11 +12,11 @@ MyObj* return_local_addr() { MyObj x {10}; MyObj* p = &x; // CHECK: Block B{{[0-9]+}}: -// CHECK: Issue (LoanID: [[L_X:[0-9]+]], OriginID: [[O_ADDR_X:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P:[0-9]+]], SrcID: [[O_ADDR_X]]) +// CHECK: Issue (LoanID: [[L_X:[0-9]+]], ToOrigin: [[O_ADDR_X:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P:[0-9]+]] (Decl: p), Src: [[O_ADDR_X]] (Expr: UnaryOperator)) return p; -// CHECK: AssignOrigin (DestID: [[O_RET_VAL:[0-9]+]], SrcID: [[O_P]]) -// CHECK: ReturnOfOrigin (OriginID: [[O_RET_VAL]]) +// CHECK: AssignOrigin (Dest: [[O_RET_VAL:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_P]] (Decl: p)) +// CHECK: ReturnOfOrigin ([[O_RET_VAL]] (Expr: ImplicitCastExpr)) // CHECK: Expire (LoanID: [[L_X]]) } @@ -27,20 +27,20 @@ MyObj* return_local_addr() { MyObj* assign_and_return_local_addr() { MyObj y{20}; MyObj* ptr1 = &y; -// CHECK: Issue (LoanID: [[L_Y:[0-9]+]], OriginID: [[O_ADDR_Y:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_PTR1:[0-9]+]], SrcID: [[O_ADDR_Y]]) +// CHECK: Issue (LoanID: [[L_Y:[0-9]+]], ToOrigin: [[O_ADDR_Y:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_PTR1:[0-9]+]] (Decl: ptr1), Src: [[O_ADDR_Y]] (Expr: UnaryOperator)) MyObj* ptr2 = ptr1; -// CHECK: AssignOrigin (DestID: [[O_PTR1_RVAL:[0-9]+]], SrcID: [[O_PTR1]]) -// CHECK: AssignOrigin (DestID: [[O_PTR2:[0-9]+]], SrcID: [[O_PTR1_RVAL]]) +// CHECK: AssignOrigin (Dest: [[O_PTR1_RVAL:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_PTR1]] (Decl: ptr1)) +// CHECK: AssignOrigin (Dest: [[O_PTR2:[0-9]+]] (Decl: ptr2), Src: [[O_PTR1_RVAL]] (Expr: ImplicitCastExpr)) ptr2 = ptr1; -// CHECK: AssignOrigin (DestID: [[O_PTR1_RVAL_2:[0-9]+]], SrcID: [[O_PTR1]]) -// CHECK: AssignOrigin (DestID: [[O_PTR2]], SrcID: [[O_PTR1_RVAL_2]]) +// CHECK: AssignOrigin (Dest: [[O_PTR1_RVAL_2:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_PTR1]] (Decl: ptr1)) +// CHECK: AssignOrigin (Dest: [[O_PTR2]] (Decl: ptr2), Src: [[O_PTR1_RVAL_2]] (Expr: ImplicitCastExpr)) ptr2 = ptr2; // Self assignment. -// CHECK: AssignOrigin (DestID: [[O_PTR2_RVAL:[0-9]+]], SrcID: [[O_PTR2]]) -// CHECK: AssignOrigin (DestID: [[O_PTR2]], SrcID: [[O_PTR2_RVAL]]) +// CHECK: AssignOrigin (Dest: [[O_PTR2_RVAL:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_PTR2]] (Decl: ptr2)) +// CHECK: AssignOrigin (Dest: [[O_PTR2]] (Decl: ptr2), Src: [[O_PTR2_RVAL]] (Expr: ImplicitCastExpr)) return ptr2; -// CHECK: AssignOrigin (DestID: [[O_PTR2_RVAL_2:[0-9]+]], SrcID: [[O_PTR2]]) -// CHECK: ReturnOfOrigin (OriginID: [[O_PTR2_RVAL_2]]) +// CHECK: AssignOrigin (Dest: [[O_PTR2_RVAL_2:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_PTR2]] (Decl: ptr2)) +// CHECK: ReturnOfOrigin ([[O_PTR2_RVAL_2]] (Expr: ImplicitCastExpr)) // CHECK: Expire (LoanID: [[L_Y]]) } @@ -60,8 +60,8 @@ int return_int_val() { void loan_expires_cpp() { MyObj obj{1}; MyObj* pObj = &obj; -// CHECK: Issue (LoanID: [[L_OBJ:[0-9]+]], OriginID: [[O_ADDR_OBJ:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_POBJ:[0-9]+]], SrcID: [[O_ADDR_OBJ]]) +// CHECK: Issue (LoanID: [[L_OBJ:[0-9]+]], ToOrigin: [[O_ADDR_OBJ:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_POBJ:[0-9]+]] (Decl: pObj), Src: [[O_ADDR_OBJ]] (Expr: UnaryOperator)) // CHECK: Expire (LoanID: [[L_OBJ]]) } @@ -72,8 +72,8 @@ void loan_expires_cpp() { void loan_expires_trivial() { int trivial_obj = 1; int* pTrivialObj = &trivial_obj; -// CHECK: Issue (LoanID: [[L_TRIVIAL_OBJ:[0-9]+]], OriginID: [[O_ADDR_TRIVIAL_OBJ:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_PTOBJ:[0-9]+]], SrcID: [[O_ADDR_TRIVIAL_OBJ]]) +// CHECK: Issue (LoanID: [[L_TRIVIAL_OBJ:[0-9]+]], ToOrigin: [[O_ADDR_TRIVIAL_OBJ:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_PTOBJ:[0-9]+]] (Decl: pTrivialObj), Src: [[O_ADDR_TRIVIAL_OBJ]] (Expr: UnaryOperator)) // CHECK-NOT: Expire (LoanID: [[L_TRIVIAL_OBJ]]) // CHECK-NEXT: End of Block // FIXME: Add check for Expire once trivial destructors are handled for expiration. @@ -87,15 +87,15 @@ void conditional(bool condition) { if (condition) p = &a; - // CHECK: Issue (LoanID: [[L_A:[0-9]+]], OriginID: [[O_ADDR_A:[0-9]+]]) - // CHECK: AssignOrigin (DestID: [[O_P:[0-9]+]], SrcID: [[O_ADDR_A]]) +// CHECK: Issue (LoanID: [[L_A:[0-9]+]], ToOrigin: [[O_ADDR_A:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P:[0-9]+]] (Decl: p), Src: [[O_ADDR_A]] (Expr: UnaryOperator)) else p = &b; - // CHECK: Issue (LoanID: [[L_B:[0-9]+]], OriginID: [[O_ADDR_B:[0-9]+]]) - // CHECK: AssignOrigin (DestID: [[O_P]], SrcID: [[O_ADDR_B]]) +// CHECK: Issue (LoanID: [[L_B:[0-9]+]], ToOrigin: [[O_ADDR_B:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P]] (Decl: p), Src: [[O_ADDR_B]] (Expr: UnaryOperator)) int *q = p; - // CHECK: AssignOrigin (DestID: [[O_P_RVAL:[0-9]+]], SrcID: [[O_P]]) - // CHECK: AssignOrigin (DestID: [[O_Q:[0-9]+]], SrcID: [[O_P_RVAL]]) +// CHECK: AssignOrigin (Dest: [[O_P_RVAL:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_P]] (Decl: p)) +// CHECK: AssignOrigin (Dest: [[O_Q:[0-9]+]] (Decl: q), Src: [[O_P_RVAL]] (Expr: ImplicitCastExpr)) } @@ -109,12 +109,12 @@ void pointers_in_a_cycle(bool condition) { MyObj* p2 = &v2; MyObj* p3 = &v3; // CHECK: Block B{{[0-9]+}}: -// CHECK: Issue (LoanID: [[L_V1:[0-9]+]], OriginID: [[O_ADDR_V1:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P1:[0-9]+]], SrcID: [[O_ADDR_V1]]) -// CHECK: Issue (LoanID: [[L_V2:[0-9]+]], OriginID: [[O_ADDR_V2:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P2:[0-9]+]], SrcID: [[O_ADDR_V2]]) -// CHECK: Issue (LoanID: [[L_V3:[0-9]+]], OriginID: [[O_ADDR_V3:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P3:[0-9]+]], SrcID: [[O_ADDR_V3]]) +// CHECK: Issue (LoanID: [[L_V1:[0-9]+]], ToOrigin: [[O_ADDR_V1:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P1:[0-9]+]] (Decl: p1), Src: [[O_ADDR_V1]] (Expr: UnaryOperator)) +// CHECK: Issue (LoanID: [[L_V2:[0-9]+]], ToOrigin: [[O_ADDR_V2:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P2:[0-9]+]] (Decl: p2), Src: [[O_ADDR_V2]] (Expr: UnaryOperator)) +// CHECK: Issue (LoanID: [[L_V3:[0-9]+]], ToOrigin: [[O_ADDR_V3:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P3:[0-9]+]] (Decl: p3), Src: [[O_ADDR_V3]] (Expr: UnaryOperator)) while (condition) { MyObj* temp = p1; @@ -122,14 +122,14 @@ void pointers_in_a_cycle(bool condition) { p2 = p3; p3 = temp; // CHECK: Block B{{[0-9]+}}: -// CHECK: AssignOrigin (DestID: [[O_P1_RVAL:[0-9]+]], SrcID: [[O_P1]]) -// CHECK: AssignOrigin (DestID: [[O_TEMP:[0-9]+]], SrcID: [[O_P1_RVAL]]) -// CHECK: AssignOrigin (DestID: [[O_P2_RVAL:[0-9]+]], SrcID: [[O_P2]]) -// CHECK: AssignOrigin (DestID: [[O_P1]], SrcID: [[O_P2_RVAL]]) -// CHECK: AssignOrigin (DestID: [[O_P3_RVAL:[0-9]+]], SrcID: [[O_P3]]) -// CHECK: AssignOrigin (DestID: [[O_P2]], SrcID: [[O_P3_RVAL]]) -// CHECK: AssignOrigin (DestID: [[O_TEMP_RVAL:[0-9]+]], SrcID: [[O_TEMP]]) -// CHECK: AssignOrigin (DestID: [[O_P3]], SrcID: [[O_TEMP_RVAL]]) +// CHECK: AssignOrigin (Dest: [[O_P1_RVAL:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_P1]] (Decl: p1)) +// CHECK: AssignOrigin (Dest: [[O_TEMP:[0-9]+]] (Decl: temp), Src: [[O_P1_RVAL]] (Expr: ImplicitCastExpr)) +// CHECK: AssignOrigin (Dest: [[O_P2_RVAL:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_P2]] (Decl: p2)) +// CHECK: AssignOrigin (Dest: [[O_P1]] (Decl: p1), Src: [[O_P2_RVAL]] (Expr: ImplicitCastExpr)) +// CHECK: AssignOrigin (Dest: [[O_P3_RVAL:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_P3]] (Decl: p3)) +// CHECK: AssignOrigin (Dest: [[O_P2]] (Decl: p2), Src: [[O_P3_RVAL]] (Expr: ImplicitCastExpr)) +// CHECK: AssignOrigin (Dest: [[O_TEMP_RVAL:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_TEMP]] (Decl: temp)) +// CHECK: AssignOrigin (Dest: [[O_P3]] (Decl: p3), Src: [[O_TEMP_RVAL]] (Expr: ImplicitCastExpr)) } } @@ -139,11 +139,11 @@ void overwrite_origin() { MyObj s2; MyObj* p = &s1; // CHECK: Block B{{[0-9]+}}: -// CHECK: Issue (LoanID: [[L_S1:[0-9]+]], OriginID: [[O_ADDR_S1:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P:[0-9]+]], SrcID: [[O_ADDR_S1]]) +// CHECK: Issue (LoanID: [[L_S1:[0-9]+]], ToOrigin: [[O_ADDR_S1:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P:[0-9]+]] (Decl: p), Src: [[O_ADDR_S1]] (Expr: UnaryOperator)) p = &s2; -// CHECK: Issue (LoanID: [[L_S2:[0-9]+]], OriginID: [[O_ADDR_S2:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P]], SrcID: [[O_ADDR_S2]]) +// CHECK: Issue (LoanID: [[L_S2:[0-9]+]], ToOrigin: [[O_ADDR_S2:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P]] (Decl: p), Src: [[O_ADDR_S2]] (Expr: UnaryOperator)) // CHECK: Expire (LoanID: [[L_S2]]) // CHECK: Expire (LoanID: [[L_S1]]) } @@ -153,10 +153,11 @@ void reassign_to_null() { MyObj s1; MyObj* p = &s1; // CHECK: Block B{{[0-9]+}}: -// CHECK: Issue (LoanID: [[L_S1:[0-9]+]], OriginID: [[O_ADDR_S1:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P:[0-9]+]], SrcID: [[O_ADDR_S1]]) +// CHECK: Issue (LoanID: [[L_S1:[0-9]+]], ToOrigin: [[O_ADDR_S1:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P:[0-9]+]] (Decl: p), Src: [[O_ADDR_S1]] (Expr: UnaryOperator)) p = nullptr; -// CHECK: AssignOrigin (DestID: [[O_P]], SrcID: [[O_NULLPTR:[0-9]+]]) +// CHECK: AssignOrigin (Dest: [[O_NULLPTR_CAST:[0-9]+]] (Expr: ImplicitCastExpr), Src: {{[0-9]+}} (Expr: CXXNullPtrLiteralExpr)) +// CHECK: AssignOrigin (Dest: [[O_P]] (Decl: p), Src: [[O_NULLPTR_CAST]] (Expr: ImplicitCastExpr)) // CHECK: Expire (LoanID: [[L_S1]]) } // FIXME: Have a better representation for nullptr than just an empty origin. @@ -169,13 +170,13 @@ void reassign_in_if(bool condition) { MyObj s2; MyObj* p = &s1; // CHECK: Block B{{[0-9]+}}: -// CHECK: Issue (LoanID: [[L_S1:[0-9]+]], OriginID: [[O_ADDR_S1:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P:[0-9]+]], SrcID: [[O_ADDR_S1]]) +// CHECK: Issue (LoanID: [[L_S1:[0-9]+]], ToOrigin: [[O_ADDR_S1:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P:[0-9]+]] (Decl: p), Src: [[O_ADDR_S1]] (Expr: UnaryOperator)) if (condition) { p = &s2; // CHECK: Block B{{[0-9]+}}: -// CHECK: Issue (LoanID: [[L_S2:[0-9]+]], OriginID: [[O_ADDR_S2:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P]], SrcID: [[O_ADDR_S2]]) +// CHECK: Issue (LoanID: [[L_S2:[0-9]+]], ToOrigin: [[O_ADDR_S2:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P]] (Decl: p), Src: [[O_ADDR_S2]] (Expr: UnaryOperator)) } // CHECK: Block B{{[0-9]+}}: // CHECK: Expire (LoanID: [[L_S2]]) @@ -190,26 +191,26 @@ void assign_in_switch(int mode) { MyObj s3; MyObj* p = nullptr; // CHECK: Block B{{[0-9]+}}: -// CHECK: AssignOrigin (DestID: [[O_NULLPTR_CAST:[0-9]+]], SrcID: [[O_NULLPTR:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P:[0-9]+]], SrcID: [[O_NULLPTR_CAST]]) +// CHECK: AssignOrigin (Dest: [[O_NULLPTR_CAST:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_NULLPTR:[0-9]+]] (Expr: CXXNullPtrLiteralExpr)) +// CHECK: AssignOrigin (Dest: [[O_P:[0-9]+]] (Decl: p), Src: [[O_NULLPTR_CAST]] (Expr: ImplicitCastExpr)) switch (mode) { case 1: p = &s1; // CHECK: Block B{{[0-9]+}}: -// CHECK: Issue (LoanID: [[L_S1:[0-9]+]], OriginID: [[O_ADDR_S1:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P]], SrcID: [[O_ADDR_S1]]) +// CHECK: Issue (LoanID: [[L_S1:[0-9]+]], ToOrigin: [[O_ADDR_S1:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P]] (Decl: p), Src: [[O_ADDR_S1]] (Expr: UnaryOperator)) break; case 2: p = &s2; // CHECK: Block B{{[0-9]+}}: -// CHECK: Issue (LoanID: [[L_S2:[0-9]+]], OriginID: [[O_ADDR_S2:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P]], SrcID: [[O_ADDR_S2]]) +// CHECK: Issue (LoanID: [[L_S2:[0-9]+]], ToOrigin: [[O_ADDR_S2:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P]] (Decl: p), Src: [[O_ADDR_S2]] (Expr: UnaryOperator)) break; default: p = &s3; // CHECK: Block B{{[0-9]+}}: -// CHECK: Issue (LoanID: [[L_S3:[0-9]+]], OriginID: [[O_ADDR_S3:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P]], SrcID: [[O_ADDR_S3]]) +// CHECK: Issue (LoanID: [[L_S3:[0-9]+]], ToOrigin: [[O_ADDR_S3:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P]] (Decl: p), Src: [[O_ADDR_S3]] (Expr: UnaryOperator)) break; } // CHECK: Block B{{[0-9]+}}: @@ -221,14 +222,14 @@ void assign_in_switch(int mode) { // CHECK-LABEL: Function: loan_in_loop void loan_in_loop(bool condition) { MyObj* p = nullptr; - // CHECK: AssignOrigin (DestID: [[O_NULLPTR_CAST:[0-9]+]], SrcID: [[O_NULLPTR:[0-9]+]]) - // CHECK: AssignOrigin (DestID: [[O_P:[0-9]+]], SrcID: [[O_NULLPTR_CAST]]) + // CHECK: AssignOrigin (Dest: [[O_NULLPTR_CAST:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_NULLPTR:[0-9]+]] (Expr: CXXNullPtrLiteralExpr)) + // CHECK: AssignOrigin (Dest: [[O_P:[0-9]+]] (Decl: p), Src: [[O_NULLPTR_CAST]] (Expr: ImplicitCastExpr)) while (condition) { MyObj inner; p = &inner; // CHECK: Block B{{[0-9]+}}: -// CHECK: Issue (LoanID: [[L_INNER:[0-9]+]], OriginID: [[O_ADDR_INNER:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P]], SrcID: [[O_ADDR_INNER]]) +// CHECK: Issue (LoanID: [[L_INNER:[0-9]+]], ToOrigin: [[O_ADDR_INNER:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P]] (Decl: p), Src: [[O_ADDR_INNER]] (Expr: UnaryOperator)) // CHECK: Expire (LoanID: [[L_INNER]]) } } @@ -239,14 +240,14 @@ void loop_with_break(int count) { MyObj s2; MyObj* p = &s1; // CHECK: Block B{{[0-9]+}}: -// CHECK: Issue (LoanID: [[L_S1:[0-9]+]], OriginID: [[O_ADDR_S1:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P:[0-9]+]], SrcID: [[O_ADDR_S1]]) +// CHECK: Issue (LoanID: [[L_S1:[0-9]+]], ToOrigin: [[O_ADDR_S1:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P:[0-9]+]] (Decl: p), Src: [[O_ADDR_S1]] (Expr: UnaryOperator)) for (int i = 0; i < count; ++i) { if (i == 5) { p = &s2; // CHECK: Block B{{[0-9]+}}: -// CHECK: Issue (LoanID: [[L_S2:[0-9]+]], OriginID: [[O_ADDR_S2:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P]], SrcID: [[O_ADDR_S2]]) +// CHECK: Issue (LoanID: [[L_S2:[0-9]+]], ToOrigin: [[O_ADDR_S2:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P]] (Decl: p), Src: [[O_ADDR_S2]] (Expr: UnaryOperator)) break; } } @@ -259,18 +260,18 @@ void loop_with_break(int count) { void nested_scopes() { MyObj* p = nullptr; // CHECK: Block B{{[0-9]+}}: -// CHECK: AssignOrigin (DestID: [[O_NULLPTR_CAST:[0-9]+]], SrcID: [[O_NULLPTR:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P:[0-9]+]], SrcID: [[O_NULLPTR_CAST]]) +// CHECK: AssignOrigin (Dest: [[O_NULLPTR_CAST:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_NULLPTR:[0-9]+]] (Expr: CXXNullPtrLiteralExpr)) +// CHECK: AssignOrigin (Dest: [[O_P:[0-9]+]] (Decl: p), Src: [[O_NULLPTR_CAST]] (Expr: ImplicitCastExpr)) { MyObj outer; p = &outer; -// CHECK: Issue (LoanID: [[L_OUTER:[0-9]+]], OriginID: [[O_ADDR_OUTER:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P]], SrcID: [[O_ADDR_OUTER]]) +// CHECK: Issue (LoanID: [[L_OUTER:[0-9]+]], ToOrigin: [[O_ADDR_OUTER:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P]] (Decl: p), Src: [[O_ADDR_OUTER]] (Expr: UnaryOperator)) { MyObj inner; p = &inner; -// CHECK: Issue (LoanID: [[L_INNER:[0-9]+]], OriginID: [[O_ADDR_INNER:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P]], SrcID: [[O_ADDR_INNER]]) +// CHECK: Issue (LoanID: [[L_INNER:[0-9]+]], ToOrigin: [[O_ADDR_INNER:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P]] (Decl: p), Src: [[O_ADDR_INNER]] (Expr: UnaryOperator)) } // CHECK: Expire (LoanID: [[L_INNER]]) } @@ -282,13 +283,13 @@ void pointer_indirection() { int a; int *p = &a; // CHECK: Block B1: -// CHECK: Issue (LoanID: [[L_A:[0-9]+]], OriginID: [[O_ADDR_A:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_P:[0-9]+]], SrcID: [[O_ADDR_A]]) +// CHECK: Issue (LoanID: [[L_A:[0-9]+]], ToOrigin: [[O_ADDR_A:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_P:[0-9]+]] (Decl: p), Src: [[O_ADDR_A]] (Expr: UnaryOperator)) int **pp = &p; -// CHECK: Issue (LoanID: [[L_P:[0-9]+]], OriginID: [[O_ADDR_P:[0-9]+]]) -// CHECK: AssignOrigin (DestID: [[O_PP:[0-9]+]], SrcID: [[O_ADDR_P]]) +// CHECK: Issue (LoanID: [[L_P:[0-g]+]], ToOrigin: [[O_ADDR_P:[0-9]+]] (Expr: UnaryOperator)) +// CHECK: AssignOrigin (Dest: [[O_PP:[0-9]+]] (Decl: pp), Src: [[O_ADDR_P]] (Expr: UnaryOperator)) // FIXME: The Origin for the RHS is broken int *q = *pp; -// CHECK: AssignOrigin (DestID: [[O_Q:[0-9]+]], SrcID: {{[0-9]+}}) +// CHECK: AssignOrigin (Dest: {{[0-9]+}} (Decl: q), Src: {{[0-9]+}} (Expr: ImplicitCastExpr)) } diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp new file mode 100644 index 0000000..660b9c9 --- /dev/null +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -0,0 +1,273 @@ +// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety -verify %s + +struct MyObj { + int id; + ~MyObj() {} // Non-trivial destructor + MyObj operator+(MyObj); +}; + +//===----------------------------------------------------------------------===// +// Basic Definite Use-After-Free (-W...permissive) +// These are cases where the pointer is guaranteed to be dangling at the use site. +//===----------------------------------------------------------------------===// + +void definite_simple_case() { + MyObj* p; + { + MyObj s; + p = &s; // expected-warning {{object whose reference is captured does not live long enough}} + } // expected-note {{destroyed here}} + (void)*p; // expected-note {{later used here}} +} + +void no_use_no_error() { + MyObj* p; + { + MyObj s; + p = &s; + } +} + +void definite_pointer_chain() { + MyObj* p; + MyObj* q; + { + MyObj s; + p = &s; // expected-warning {{does not live long enough}} + q = p; + } // expected-note {{destroyed here}} + (void)*q; // expected-note {{later used here}} +} + +void definite_multiple_uses_one_warning() { + MyObj* p; + { + MyObj s; + p = &s; // expected-warning {{does not live long enough}} + } // expected-note {{destroyed here}} + (void)*p; // expected-note {{later used here}} + // No second warning for the same loan. + p->id = 1; + MyObj* q = p; + (void)*q; +} + +void definite_multiple_pointers() { + MyObj *p, *q, *r; + { + MyObj s; + p = &s; // expected-warning {{does not live long enough}} + q = &s; // expected-warning {{does not live long enough}} + r = &s; // expected-warning {{does not live long enough}} + } // expected-note 3 {{destroyed here}} + (void)*p; // expected-note {{later used here}} + (void)*q; // expected-note {{later used here}} + (void)*r; // expected-note {{later used here}} +} + +void definite_single_pointer_multiple_loans(bool cond) { + MyObj *p; + if (cond){ + MyObj s; + p = &s; // expected-warning {{does not live long enough}} + } // expected-note {{destroyed here}} + else { + MyObj t; + p = &t; // expected-warning {{does not live long enough}} + } // expected-note {{destroyed here}} + (void)*p; // expected-note 2 {{later used here}} +} + + +//===----------------------------------------------------------------------===// +// Potential (Maybe) Use-After-Free (-W...strict) +// These are cases where the pointer *may* become dangling, depending on the path taken. +//===----------------------------------------------------------------------===// + +void potential_if_branch(bool cond) { + MyObj safe; + MyObj* p = &safe; + if (cond) { + MyObj temp; + p = &temp; // expected-warning {{object whose reference is captured may not live long enough}} + } // expected-note {{destroyed here}} + (void)*p; // expected-note {{later used here}} +} + +// If all paths lead to a dangle, it becomes a definite error. +void potential_becomes_definite(bool cond) { + MyObj* p; + if (cond) { + MyObj temp1; + p = &temp1; // expected-warning {{does not live long enough}} + } // expected-note {{destroyed here}} + else { + MyObj temp2; + p = &temp2; // expected-warning {{does not live long enough}} + } // expected-note {{destroyed here}} + (void)*p; // expected-note 2 {{later used here}} +} + +void definite_potential_together(bool cond) { + MyObj safe; + MyObj* p_maybe = &safe; + MyObj* p_definite = nullptr; + + { + MyObj s; + p_definite = &s; // expected-warning {{does not live long enough}} + if (cond) { + p_maybe = &s; // expected-warning {{may not live long enough}} + } + } // expected-note 2 {{destroyed here}} + (void)*p_definite; // expected-note {{later used here}} + (void)*p_maybe; // expected-note {{later used here}} +} + +void definite_overrides_potential(bool cond) { + MyObj safe; + MyObj* p; + MyObj* q; + { + MyObj s; + q = &s; // expected-warning {{does not live long enough}} + p = q; + } // expected-note {{destroyed here}} + + if (cond) { + // 'q' is conditionally "rescued". 'p' is not. + q = &safe; + } + + // The use of 'p' is a definite error because it was never rescued. + (void)*q; + (void)*p; // expected-note {{later used here}} + (void)*q; +} + + +//===----------------------------------------------------------------------===// +// Control Flow Tests +//===----------------------------------------------------------------------===// + +void potential_for_loop_use_after_loop_body(MyObj safe) { + MyObj* p = &safe; + for (int i = 0; i < 1; ++i) { + MyObj s; + p = &s; // expected-warning {{may not live long enough}} + } // expected-note {{destroyed here}} + (void)*p; // expected-note {{later used here}} +} + +void potential_for_loop_use_before_loop_body(MyObj safe) { + MyObj* p = &safe; + for (int i = 0; i < 1; ++i) { + (void)*p; // expected-note {{later used here}} + MyObj s; + p = &s; // expected-warning {{may not live long enough}} + } // expected-note {{destroyed here}} + (void)*p; +} + +void potential_loop_with_break(bool cond) { + MyObj safe; + MyObj* p = &safe; + for (int i = 0; i < 10; ++i) { + if (cond) { + MyObj temp; + p = &temp; // expected-warning {{may not live long enough}} + break; // expected-note {{destroyed here}} + } + } + (void)*p; // expected-note {{later used here}} +} + +void potential_multiple_expiry_of_same_loan(bool cond) { + // Choose the last expiry location for the loan. + MyObj safe; + MyObj* p = &safe; + for (int i = 0; i < 10; ++i) { + MyObj unsafe; + if (cond) { + p = &unsafe; // expected-warning {{may not live long enough}} + break; + } + } // expected-note {{destroyed here}} + (void)*p; // expected-note {{later used here}} + + p = &safe; + for (int i = 0; i < 10; ++i) { + MyObj unsafe; + if (cond) { + p = &unsafe; // expected-warning {{may not live long enough}} + if (cond) + break; + } + } // expected-note {{destroyed here}} + (void)*p; // expected-note {{later used here}} + + p = &safe; + for (int i = 0; i < 10; ++i) { + if (cond) { + MyObj unsafe2; + p = &unsafe2; // expected-warning {{may not live long enough}} + break; // expected-note {{destroyed here}} + } + } + (void)*p; // expected-note {{later used here}} +} + +void potential_switch(int mode) { + MyObj safe; + MyObj* p = &safe; + switch (mode) { + case 1: { + MyObj temp; + p = &temp; // expected-warning {{object whose reference is captured may not live long enough}} + break; // expected-note {{destroyed here}} + } + case 2: { + p = &safe; // This path is okay. + break; + } + } + (void)*p; // expected-note {{later used here}} +} + +void definite_switch(int mode) { + MyObj safe; + MyObj* p = &safe; + // All cases are UaF --> Definite error. + switch (mode) { + case 1: { + MyObj temp1; + p = &temp1; // expected-warning {{does not live long enough}} + break; // expected-note {{destroyed here}} + } + case 2: { + MyObj temp2; + p = &temp2; // expected-warning {{does not live long enough}} + break; // expected-note {{destroyed here}} + } + default: { + MyObj temp2; + p = &temp2; // expected-warning {{does not live long enough}} + break; // expected-note {{destroyed here}} + } + } + (void)*p; // expected-note 3 {{later used here}} +} + +//===----------------------------------------------------------------------===// +// No-Error Cases +//===----------------------------------------------------------------------===// +void no_error_if_dangle_then_rescue() { + MyObj safe; + MyObj* p; + { + MyObj temp; + p = &temp; // p is temporarily dangling. + } + p = &safe; // p is "rescued" before use. + (void)*p; // This is safe. +} |