aboutsummaryrefslogtreecommitdiff
path: root/clang/test/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test/Sema')
-rw-r--r--clang/test/Sema/AArch64/builtin_vectorelements.c46
-rw-r--r--clang/test/Sema/AArch64/sve-vector-conditional-op.cpp47
-rw-r--r--clang/test/Sema/PR166843.cpp7
-rw-r--r--clang/test/Sema/aarch64-tme-errors.c8
-rw-r--r--clang/test/Sema/aarch64-tme-tcancel-errors.c9
-rw-r--r--clang/test/Sema/attr-malloc_span.c82
-rw-r--r--clang/test/Sema/attr-modular-format.c26
-rw-r--r--clang/test/Sema/attr-target-clones-aarch64.c12
-rw-r--r--clang/test/Sema/attr-target-clones.c13
-rw-r--r--clang/test/Sema/attr-target-version.c11
-rw-r--r--clang/test/Sema/builtin-counted-by-ref.c87
-rw-r--r--clang/test/Sema/constant-builtins-2.c22
-rw-r--r--clang/test/Sema/constant-builtins.c5
-rw-r--r--clang/test/Sema/format-attr-missing-gnu.c55
-rw-r--r--clang/test/Sema/format-attr-missing.c228
-rw-r--r--clang/test/Sema/format-attr-missing.cpp68
-rw-r--r--clang/test/Sema/format-attr-missing.m68
-rw-r--r--clang/test/Sema/format-strings-nonnull.c79
-rw-r--r--clang/test/Sema/format-strings-nonnull.cpp49
-rw-r--r--clang/test/Sema/format-strings-scanf.c5
-rw-r--r--clang/test/Sema/format-strings.c115
-rw-r--r--clang/test/Sema/scoped-atomic-ops.c25
-rw-r--r--clang/test/Sema/type-dependent-attrs.c10
-rw-r--r--clang/test/Sema/warn-enum-compare-typo.c98
-rw-r--r--clang/test/Sema/warn-fortify-scanf.c7
-rw-r--r--clang/test/Sema/warn-fortify-source.c8
-rw-r--r--clang/test/Sema/warn-lifetime-safety-dataflow.cpp45
-rw-r--r--clang/test/Sema/warn-lifetime-safety-suggestions.cpp109
-rw-r--r--clang/test/Sema/warn-lifetime-safety.cpp371
-rw-r--r--clang/test/Sema/warn-unreachable-file-scope.c37
30 files changed, 1687 insertions, 65 deletions
diff --git a/clang/test/Sema/AArch64/builtin_vectorelements.c b/clang/test/Sema/AArch64/builtin_vectorelements.c
new file mode 100644
index 0000000..3391da3
--- /dev/null
+++ b/clang/test/Sema/AArch64/builtin_vectorelements.c
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsyntax-only -verify %s
+// REQUIRES: aarch64-registered-target
+
+#include <arm_sve.h>
+
+__attribute__((target("sve")))
+long test_builtin_vectorelements_sve(void) {
+ return __builtin_vectorelements(svuint8_t);
+}
+
+__attribute__((target("sve2p1")))
+long test_builtin_vectorelements_sve2p1(void) {
+ return __builtin_vectorelements(svuint8_t);
+}
+
+long test_builtin_vectorelements_no_sve(void) {
+ // expected-error@+1 {{SVE vector type 'svuint8_t' (aka '__SVUint8_t') cannot be used in a target without sve}}
+ return __builtin_vectorelements(svuint8_t);
+}
+
+__attribute__((target("sme")))
+long test_builtin_vectorelements_sme_streaming(void) __arm_streaming {
+ return __builtin_vectorelements(svuint8_t);
+}
+
+__attribute__((target("sme2p1")))
+long test_builtin_vectorelements_sme2p1_streaming(void) __arm_streaming {
+ return __builtin_vectorelements(svuint8_t);
+}
+
+__attribute__((target("sme")))
+long test_builtin_vectorelements_sme(void) {
+ // expected-error@+1 {{SVE vector type 'svuint8_t' (aka '__SVUint8_t') cannot be used in a non-streaming function}}
+ return __builtin_vectorelements(svuint8_t);
+}
+
+__attribute__((target("sve,sme")))
+long test_builtin_vectorelements_sve_sme_streaming_compatible(void) __arm_streaming_compatible {
+ return __builtin_vectorelements(svuint8_t);
+}
+
+__attribute__((target("sme")))
+long test_builtin_vectorelements_sme_streaming_compatible(void) __arm_streaming_compatible {
+ // expected-error@+1 {{SVE vector type 'svuint8_t' (aka '__SVUint8_t') cannot be used in a non-streaming function}}
+ return __builtin_vectorelements(svuint8_t);
+}
diff --git a/clang/test/Sema/AArch64/sve-vector-conditional-op.cpp b/clang/test/Sema/AArch64/sve-vector-conditional-op.cpp
new file mode 100644
index 0000000..7fa4ce8
--- /dev/null
+++ b/clang/test/Sema/AArch64/sve-vector-conditional-op.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 %s -fsyntax-only -triple aarch64-none-linux-gnu -target-feature +sve -verify
+
+typedef int fixed_vector __attribute__((vector_size(4)));
+
+auto error_fixed_vector_result(__SVBool_t svbool, fixed_vector a, fixed_vector b) {
+ // expected-error@+1 {{vector condition type '__SVBool_t' and result type 'fixed_vector' (vector of 1 'int' value) do not have the same number of elements}}
+ return svbool ? a : b;
+}
+
+auto error_void_result(__SVBool_t svbool) {
+ // expected-error@+1 {{GNU vector conditional operand cannot be void}}
+ return svbool ? (void)0 : (void)1;
+}
+
+auto error_sve_splat_result_unsupported(__SVBool_t svbool, long long a, long long b) {
+ // expected-error@+1 {{scalar type 'long long' not supported with vector condition type '__SVBool_t'}}
+ return svbool ? a : b;
+}
+
+auto error_sve_vector_result_matched_element_count(__SVBool_t svbool, __SVUint32_t a, __SVUint32_t b) {
+ // expected-error@+1 {{vector condition type '__SVBool_t' and result type '__SVUint32_t' do not have the same number of elements}}
+ return svbool ? a : b;
+}
+
+auto error_fixed_cond_mixed_scalar_and_vector_operands(fixed_vector cond, unsigned char a, __SVUint8_t b) {
+ // expected-error@+1 {{cannot mix vectors and sizeless vectors in a vector conditional}}
+ return cond ? a : b;
+}
+
+auto error_scalable_cond_mixed_scalar_and_vector_operands(__SVBool_t svbool, unsigned char a, fixed_vector b) {
+ // expected-error@+1 {{cannot mix vectors and sizeless vectors in a vector conditional}}
+ return svbool ? a : b;
+}
+
+// The following cases should be supported:
+
+__SVBool_t cond_svbool(__SVBool_t a, __SVBool_t b) {
+ return a < b ? a : b;
+}
+
+__SVFloat32_t cond_svf32(__SVFloat32_t a, __SVFloat32_t b) {
+ return a < b ? a : b;
+}
+
+__SVUint64_t cond_u64_splat(__SVUint64_t a) {
+ return a < 1ul ? a : 1ul;
+}
diff --git a/clang/test/Sema/PR166843.cpp b/clang/test/Sema/PR166843.cpp
new file mode 100644
index 0000000..5a6223b
--- /dev/null
+++ b/clang/test/Sema/PR166843.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only %s -verify
+namespace a {
+template <class b>
+void c() {
+ ((::c::x)); // expected-error {{'c' is not a class, namespace, or enumeration}}
+}
+}
diff --git a/clang/test/Sema/aarch64-tme-errors.c b/clang/test/Sema/aarch64-tme-errors.c
deleted file mode 100644
index 1cb6f690..0000000
--- a/clang/test/Sema/aarch64-tme-errors.c
+++ /dev/null
@@ -1,8 +0,0 @@
-// RUN: %clang_cc1 -triple aarch64 -verify %s
-
-#include "arm_acle.h"
-
-void test_no_tme_funcs(void) {
- __tstart(); // expected-error{{call to undeclared function '__tstart'; ISO C99 and later do not support implicit function declarations}}
- __builtin_tstart(); // expected-error{{use of unknown builtin '__builtin_tstart'}}
-}
diff --git a/clang/test/Sema/aarch64-tme-tcancel-errors.c b/clang/test/Sema/aarch64-tme-tcancel-errors.c
deleted file mode 100644
index 365bf81..0000000
--- a/clang/test/Sema/aarch64-tme-tcancel-errors.c
+++ /dev/null
@@ -1,9 +0,0 @@
-// RUN: %clang_cc1 -triple aarch64 -target-feature +tme -verify %s
-void t_cancel_const(unsigned short u) {
- __builtin_arm_tcancel(u); // expected-error{{argument to '__builtin_arm_tcancel' must be a constant integer}}
-}
-
-// RUN: %clang_cc1 -triple aarch64 -target-feature +tme -verify %s
-void t_cancel_range(void) {
- __builtin_arm_tcancel(0x12345u); // expected-error{{argument value 74565 is outside the valid range [0, 65535]}}
-}
diff --git a/clang/test/Sema/attr-malloc_span.c b/clang/test/Sema/attr-malloc_span.c
new file mode 100644
index 0000000..9238b60
--- /dev/null
+++ b/clang/test/Sema/attr-malloc_span.c
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+
+typedef __SIZE_TYPE__ size_t;
+
+typedef struct {
+ void *ptr;
+ size_t n;
+} span;
+span returns_span (void) __attribute((malloc_span)); // no-warning
+
+typedef struct {
+ size_t n;
+ void *ptr;
+} span2;
+span2 returns_span2 (void) __attribute((malloc_span)); // no-warning
+
+typedef struct {
+ void *ptr;
+ void *ptr2;
+} span3;
+span3 returns_span3 (void) __attribute((malloc_span)); // no-warning
+
+typedef struct {
+ void *ptr;
+ int n;
+} span4;
+span4 returns_span4 (void) __attribute((malloc_span)); // no-warning
+
+typedef struct incomplete_span incomplete_span;
+// expected-warning@+2 {{attribute only applies to functions that return span-like structures}}
+// expected-note@+1 {{returned type is incomplete}}
+incomplete_span returns_incomplete_span (void) __attribute((malloc_span));
+
+// expected-warning@+2 {{attribute only applies to functions that return span-like structures}}
+// expected-note@+1 {{returned type is not a struct type}}
+int *returns_int_ptr (void) __attribute((malloc_span));
+
+typedef struct {
+ void *ptr;
+ size_t n;
+ size_t n2;
+} too_long_span;
+// expected-warning@+2 {{attribute only applies to functions that return span-like structures}}
+// expected-note@+1 {{returned struct has 3 fields, expected 2}}
+too_long_span returns_too_long_span (void) __attribute((malloc_span));
+
+// Function pointers are not allowed.
+typedef struct {
+ int (*func_ptr)(void);
+ size_t n;
+} func_span;
+// expected-warning@+2 {{attribute only applies to functions that return span-like structures}}
+// expected-note@+1 {{returned struct fields are not a supported combination}}
+func_span returns_func_span (void) __attribute((malloc_span));
+
+// Integer should not be an enum.
+enum some_enum { some_value, other_value };
+typedef struct {
+ void *ptr;
+ enum some_enum field;
+} enum_span;
+// expected-warning@+2 {{attribute only applies to functions that return span-like structures}}
+// expected-note@+1 {{2nd field is expected to be an integer}}
+enum_span returns_enum_span (void) __attribute((malloc_span));
+
+// Bit integers are also not supported.
+typedef struct {
+ void *ptr;
+ _BitInt(16) n;
+} bit_span;
+// expected-warning@+2 {{attribute only applies to functions that return span-like structures}}
+// expected-note@+1 {{2nd field is expected to be an integer}}
+bit_span returns_bit_span (void) __attribute((malloc_span));
+
+// Integer must be at least as big as int.
+typedef struct {
+ void *ptr;
+ short n;
+} short_span;
+// expected-warning@+2 {{attribute only applies to functions that return span-like structures}}
+// expected-note@+1 {{2nd field of span-like type is not a wide enough integer (minimum width: 32)}}
+short_span returns_short_span (void) __attribute((malloc_span));
diff --git a/clang/test/Sema/attr-modular-format.c b/clang/test/Sema/attr-modular-format.c
new file mode 100644
index 0000000..fc5b28b
--- /dev/null
+++ b/clang/test/Sema/attr-modular-format.c
@@ -0,0 +1,26 @@
+//RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int printf(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"))); // no-error
+int myprintf(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"))); // expected-error {{'modular_format' attribute requires 'format' attribute}}
+
+int dupe(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float", "int", "float"), format(printf, 1, 2))); // expected-error {{duplicate aspect 'float' in 'modular_format' attribute}}
+int multi_dupe(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float", "int", "float", "int"), format(printf, 1, 2))); // expected-error {{duplicate aspect 'float' in 'modular_format' attribute}} \
+ // expected-error {{duplicate aspect 'int' in 'modular_format' attribute}}
+
+// Test with multiple identical attributes on the same declaration.
+int same_attr(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"), modular_format(__modular_printf, "__printf", "float"), format(printf, 1, 2))); // no-warning
+
+// Test with multiple different attributes on the same declaration.
+int diff_attr(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"), format(printf, 1, 2), modular_format(__modular_printf, "__printf", "int"))); // expected-error {{attribute 'modular_format' is already applied with different arguments}} expected-note {{conflicting attribute is here}}
+
+int diff_attr2(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"), format(printf, 1, 2), modular_format(__modular_printf, "__other", "float"))); // expected-error {{attribute 'modular_format' is already applied with different arguments}} expected-note {{conflicting attribute is here}}
+
+int diff_attr3(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"), format(printf, 1, 2), modular_format(__other, "__printf", "float"))); // expected-error {{attribute 'modular_format' is already applied with different arguments}} expected-note {{conflicting attribute is here}}
+
+// Test with same attributes but different aspect order.
+int diff_order(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float", "int"), format(printf, 1, 2), modular_format(__modular_printf, "__printf", "int", "float"))); // no-error
+
+// Test with multiple different attributes on a declaration and a redeclaration
+int redecl(const char *fmt, ...) __attribute__((format(printf, 1, 2))); // no-error
+int redecl(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"))); // expected-note {{conflicting attribute is here}}
+int redecl(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "int"))); // expected-error {{attribute 'modular_format' is already applied with different arguments}}
diff --git a/clang/test/Sema/attr-target-clones-aarch64.c b/clang/test/Sema/attr-target-clones-aarch64.c
index 93d87ce..e468fd8 100644
--- a/clang/test/Sema/attr-target-clones-aarch64.c
+++ b/clang/test/Sema/attr-target-clones-aarch64.c
@@ -80,3 +80,15 @@ int useage(void) {
int __attribute__((target_clones("sve2-sha3+ssbs", "sm4"))) mv_after_use(void) { return 1; }
// expected-error@+1 {{'main' cannot be a multiversioned function}}
int __attribute__((target_clones("i8mm"))) main() { return 1; }
+
+int __attribute__((target_clones("aes + sve2 ; priority=100", "default"))) priority_whitespace(void) { return 0; }
+
+//expected-warning@+2 {{unsupported 'priority=10' in the 'target_clones' attribute string; 'target_clones' attribute ignored}}
+//expected-warning@+1 {{version list contains entries that don't impact code generation}}
+int __attribute__((target_clones("priority=10;aes", "default"))) priority_before_features(void) { return 0; }
+
+//expected-warning@+1 {{version priority '0' is outside the allowed range [1-255]; ignoring priority}}
+int __attribute__((target_clones("aes;priority=0", "default"))) priority_out_of_range(void) { return 0; }
+
+//expected-warning@+1 {{priority of default version cannot be overridden; ignoring priority}}
+int __attribute__((target_clones("aes", "default;priority=10"))) priority_default_version(void) { return 0; }
diff --git a/clang/test/Sema/attr-target-clones.c b/clang/test/Sema/attr-target-clones.c
index 4597ea5..4068877 100644
--- a/clang/test/Sema/attr-target-clones.c
+++ b/clang/test/Sema/attr-target-clones.c
@@ -28,6 +28,17 @@ int __attribute__((target_clones("sse4.2", "arch=atom", "default"))) redecl4(voi
int __attribute__((target_clones("sse4.2", "arch=sandybridge", "default")))
redecl4(void) { return 1; }
+int __attribute__((target_clones("sse4.2", "default"))) redecl5(void);
+int redecl5(void) { return 1; }
+
+int redecl6(void);
+int __attribute__((target_clones("sse4.2", "default"))) redecl6(void) { return 1; }
+
+int __attribute__((target_clones("sse4.2", "default"))) redecl7(void);
+// expected-error@+2 {{multiversioning attributes cannot be combined}}
+// expected-note@-2 {{previous declaration is here}}
+int __attribute__((target("sse4.2"))) redecl7(void) { return 1; }
+
int __attribute__((target("sse4.2"))) redef2(void) { return 1; }
// expected-error@+2 {{multiversioning attributes cannot be combined}}
// expected-note@-2 {{previous declaration is here}}
@@ -87,6 +98,8 @@ int useage(void) {
int __attribute__((target_clones("sse4.2", "default"))) mv_after_use(void) { return 1; }
void bad_overload1(void) __attribute__((target_clones("mmx", "sse4.2", "default")));
+// expected-error@+2 {{conflicting types for 'bad_overload1'}}
+// expected-note@-2 {{previous declaration is here}}
void bad_overload1(int p) {}
void bad_overload2(int p) {}
diff --git a/clang/test/Sema/attr-target-version.c b/clang/test/Sema/attr-target-version.c
index d062212..29dfc3e 100644
--- a/clang/test/Sema/attr-target-version.c
+++ b/clang/test/Sema/attr-target-version.c
@@ -117,3 +117,14 @@ int unspec_args_implicit_default_first();
int __attribute__((target_version("aes"))) unspec_args_implicit_default_first() { return -1; }
// expected-note@+1 {{function multiversioning caused by this declaration}}
int __attribute__((target_version("default"))) unspec_args_implicit_default_first() { return 0; }
+
+int __attribute__((target_version("aes + sve2 ; priority=100"))) priority_whitespace(void) { return 0; }
+
+//expected-warning@+1 {{unsupported 'priority=10' in the 'target_version' attribute string; 'target_version' attribute ignored}}
+int __attribute__((target_version("priority=10;aes"))) priority_before_features(void) { return 0; }
+
+//expected-warning@+1 {{version priority '256' is outside the allowed range [1-255]; ignoring priority}}
+int __attribute__((target_version("aes;priority=256"))) priority_out_of_range(void) { return 0; }
+
+//expected-warning@+1 {{priority of default version cannot be overridden; ignoring priority}}
+int __attribute__((target_version("default;priority=10"))) priority_default_version(void) { return 0; }
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index a9f46a3..ed766d3 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -32,14 +32,14 @@ void test2(struct fam_struct *ptr, int idx) {
}
void test3(struct fam_struct *ptr, int idx) {
- __builtin_counted_by_ref(&ptr->array[0]); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- __builtin_counted_by_ref(&ptr->array[idx]); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- __builtin_counted_by_ref(&ptr->array); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- __builtin_counted_by_ref(ptr->x); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- __builtin_counted_by_ref(&ptr->x); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- __builtin_counted_by_ref(global_array); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- __builtin_counted_by_ref(global_int); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- __builtin_counted_by_ref(&global_int); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ __builtin_counted_by_ref(&ptr->array[0]); // expected-error {{'__builtin_counted_by_ref' argument must reference a member with the 'counted_by' attribute}}
+ __builtin_counted_by_ref(&ptr->array[idx]); // expected-error {{'__builtin_counted_by_ref' argument must reference a member with the 'counted_by' attribute}}
+ __builtin_counted_by_ref(&ptr->array); // expected-error {{'__builtin_counted_by_ref' argument must reference a member with the 'counted_by' attribute}}
+ __builtin_counted_by_ref(ptr->x); // expected-error {{'__builtin_counted_by_ref' argument must reference a member with the 'counted_by' attribute}}
+ __builtin_counted_by_ref(&ptr->x); // expected-error {{'__builtin_counted_by_ref' argument must reference a member with the 'counted_by' attribute}}
+ __builtin_counted_by_ref(global_array); // expected-error {{'__builtin_counted_by_ref' argument must reference a member with the 'counted_by' attribute}}
+ __builtin_counted_by_ref(global_int); // expected-error {{'__builtin_counted_by_ref' argument must reference a member with the 'counted_by' attribute}}
+ __builtin_counted_by_ref(&global_int); // expected-error {{'__builtin_counted_by_ref' argument must reference a member with the 'counted_by' attribute}}
}
void test4(struct fam_struct *ptr, int idx) {
@@ -78,10 +78,12 @@ struct non_fam_struct {
};
void *test7(struct non_fam_struct *ptr, int size) {
- *__builtin_counted_by_ref(ptr->array) = size // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- *__builtin_counted_by_ref(&ptr->array[0]) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- *__builtin_counted_by_ref(ptr->pointer) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- *__builtin_counted_by_ref(&ptr->pointer[0]) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ // Arrays and pointers without counted_by return void*
+ _Static_assert(_Generic(__builtin_counted_by_ref(ptr->array), void * : 1, default : 0) == 1, "should be void*");
+ _Static_assert(_Generic(__builtin_counted_by_ref(ptr->pointer), void * : 1, default : 0) == 1, "should be void*");
+ // These are not direct member accesses, so they error
+ __builtin_counted_by_ref(&ptr->array[0]); // expected-error {{'__builtin_counted_by_ref' argument must reference a member with the 'counted_by' attribute}}
+ __builtin_counted_by_ref(&ptr->pointer[0]); // expected-error {{'__builtin_counted_by_ref' argument must reference a member with the 'counted_by' attribute}}
}
struct char_count {
@@ -122,3 +124,64 @@ void test8(void) {
_Static_assert(_Generic(__builtin_counted_by_ref(lp->array), long * : 1, default : 0) == 1, "wrong return type");
_Static_assert(_Generic(__builtin_counted_by_ref(ulp->array), unsigned long * : 1, default : 0) == 1, "wrong return type");
}
+
+// Tests for pointer members with counted_by attribute
+struct ptr_char_count {
+ char count;
+ int *ptr __attribute__((counted_by(count)));
+} *pcp;
+
+struct ptr_short_count {
+ short count;
+ int *ptr __attribute__((counted_by(count)));
+} *psp;
+
+struct ptr_int_count {
+ int count;
+ int *ptr __attribute__((counted_by(count)));
+} *pip;
+
+struct ptr_unsigned_count {
+ unsigned count;
+ int *ptr __attribute__((counted_by(count)));
+} *pup;
+
+struct ptr_long_count {
+ long count;
+ int *ptr __attribute__((counted_by(count)));
+} *plp;
+
+struct ptr_unsigned_long_count {
+ unsigned long count;
+ int *ptr __attribute__((counted_by(count)));
+} *pulp;
+
+void test9(struct ptr_int_count *ptr, int size) {
+ size_t size_of = sizeof(__builtin_counted_by_ref(ptr->ptr)); // ok
+ int align_of = __alignof(__builtin_counted_by_ref(ptr->ptr)); // ok
+ size_t __ignored_assignment;
+
+ *__builtin_counted_by_ref(ptr->ptr) = size; // ok
+ *_Generic(__builtin_counted_by_ref(ptr->ptr),
+ void *: &__ignored_assignment,
+ default: __builtin_counted_by_ref(ptr->ptr)) = 42; // ok
+}
+
+void test10(void) {
+ _Static_assert(_Generic(__builtin_counted_by_ref(pcp->ptr), char * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_counted_by_ref(psp->ptr), short * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_counted_by_ref(pip->ptr), int * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_counted_by_ref(pup->ptr), unsigned int * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_counted_by_ref(plp->ptr), long * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_counted_by_ref(pulp->ptr), unsigned long * : 1, default : 0) == 1, "wrong return type");
+}
+
+// Pointer without counted_by returns void*
+struct ptr_no_attr {
+ int count;
+ int *ptr; // No counted_by attribute
+};
+
+void test11(struct ptr_no_attr *p) {
+ _Static_assert(_Generic(__builtin_counted_by_ref(p->ptr), void * : 1, default : 0) == 1, "should be void*");
+}
diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c
index e465a3c5f..9579052b 100644
--- a/clang/test/Sema/constant-builtins-2.c
+++ b/clang/test/Sema/constant-builtins-2.c
@@ -479,6 +479,28 @@ int h0 = __builtin_types_compatible_p(int, float);
int h3 = __builtin_bswap16(0x1234) == 0x3412 ? 1 : f();
int h4 = __builtin_bswap32(0x1234) == 0x34120000 ? 1 : f();
int h5 = __builtin_bswap64(0x1234) == 0x3412000000000000 ? 1 : f();
+int h6 = __builtin_bswapg((char)(0x12)) == (char)(0x12) ? 1 : f();
+int h7 = __builtin_bswapg((short)(0x1234)) == (short)(0x3412) ? 1 : f();
+int h8 = __builtin_bswapg(0x00001234) == 0x34120000 ? 1 : f();
+int h9 = __builtin_bswapg(0x0000000000001234ULL) == 0x3412000000000000 ? 1 : f();
+float h10 = __builtin_bswapg(1.0f); // expected-error {{1st argument must be a scalar integer type (was 'float')}}
+double h12 = __builtin_bswapg(1.0L); // expected-error {{1st argument must be a scalar integer type (was 'long double')}}
+char *h13 = __builtin_bswapg("hello"); // expected-error {{1st argument must be a scalar integer type (was 'char[6]')}}
+int h14 = __builtin_bswapg(1, 2); // expected-error {{too many arguments to function call, expected 1, have 2}}
+int *h15 = __builtin_bswapg(&h9); // expected-error {{1st argument must be a scalar integer type (was 'int *')}}
+int arr[4] = {0x12, 0x34, 0x56, 0x78};
+int h16 = __builtin_bswapg(arr); // expected-error {{1st argument must be a scalar integer type (was 'int[4]')}}
+enum BasicEnum {
+ ENUM_VALUE1 = 0x1234,
+};
+int h17 = __builtin_bswapg(ENUM_VALUE1) == 0x34120000 ? 1 : f();
+int h18 = __builtin_bswapg((_BitInt(8))0x12) == (_BitInt(8))0x12 ? 1 : f();
+int h19 = __builtin_bswapg((_BitInt(16))0x1234) == (_BitInt(16))0x3412 ? 1 : f();
+int h20 = __builtin_bswapg((_BitInt(32))0x00001234) == (_BitInt(32))0x34120000 ? 1 : f();
+int h21 = __builtin_bswapg((_BitInt(64))0x0000000000001234) == (_BitInt(64))0x3412000000000000 ? 1 : f();
+int h22 = __builtin_bswapg(~(_BitInt(128))0) == (~(_BitInt(128))0) ? 1 : f();
+int h23 = __builtin_bswapg((_BitInt(24))0x1234) == (_BitInt(24))0x3412 ? 1 : f();
+// expected-error@-1 {{_BitInt type '_BitInt(24)' (24 bits) must be a multiple of 16 bits for byte swapping}}
extern long int bi0;
extern __typeof__(__builtin_expect(0, 0)) bi0;
diff --git a/clang/test/Sema/constant-builtins.c b/clang/test/Sema/constant-builtins.c
index 964ab59..6c13fe9 100644
--- a/clang/test/Sema/constant-builtins.c
+++ b/clang/test/Sema/constant-builtins.c
@@ -25,7 +25,10 @@ int h0 = __builtin_types_compatible_p(int,float);
int h3 = __builtin_bswap16(0x1234) == 0x3412 ? 1 : f();
int h4 = __builtin_bswap32(0x1234) == 0x34120000 ? 1 : f();
int h5 = __builtin_bswap64(0x1234) == 0x3412000000000000 ? 1 : f();
-
+int h6 = __builtin_bswapg((char)0x12) == (char)0x12 ? 1 : f();
+int h7 = __builtin_bswapg((short)(0x1234)) == (short)(0x3412) ? 1 : f();
+int h8 = __builtin_bswapg(0x00001234) == 0x34120000 ? 1 : f();
+int h9 = __builtin_bswapg(0x0000000000001234ULL) == 0x3412000000000000 ? 1 : f();
short somefunc(void);
short t = __builtin_constant_p(5353) ? 42 : somefunc();
diff --git a/clang/test/Sema/format-attr-missing-gnu.c b/clang/test/Sema/format-attr-missing-gnu.c
new file mode 100644
index 0000000..196b45c
--- /dev/null
+++ b/clang/test/Sema/format-attr-missing-gnu.c
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify -std=gnu11 -Wmissing-format-attribute %s
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify -x c++ -std=gnu++98 -Wmissing-format-attribute %s
+// RUN: %clang_cc1 -fsyntax-only -fblocks -std=gnu11 -Wmissing-format-attribute -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -fblocks -x c++ -std=gnu++98 -Wmissing-format-attribute -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+typedef unsigned long size_t;
+typedef long ssize_t;
+typedef __builtin_va_list va_list;
+
+__attribute__((format(printf, 1, 2)))
+int printf(const char *, ...);
+
+__attribute__((format(printf, 1, 0)))
+int vprintf(const char *, va_list);
+
+// Test that attribute fixit is specified using the GNU extension format when -std=gnuXY or -std=gnu++XY.
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"__attribute__((format(printf, 1, 0))) "
+void f1(char *out, va_list args) // #f1
+{
+ vprintf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 0)' attribute to the declaration of 'f1'}}
+ // expected-note@#f1 {{'f1' declared here}}
+}
+
+void f2(void) {
+ void (^b1)(const char *, ...) = ^(const char *fmt, ...) { // #b1
+ va_list args;
+ vprintf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of block}}
+ // expected-note@#b1 {{block declared here}}
+ };
+
+ void (^b2)(const char *, va_list) = ^(const char *fmt, va_list args) { // #b2
+ vprintf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 0)' attribute to the declaration of block}}.
+ // expected-note@#b2 {{block declared here}}
+ };
+
+ void (^b3)(const char *, int x, float y) = ^(const char *fmt, int x, float y) { // #b3
+ printf(fmt, x, y); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of block}}.
+ // expected-note@#b3 {{block declared here}}
+ };
+
+ void __attribute__((__format__(__printf__, 1, 2))) (^b4)(const char *, ...) =
+ ^(const char *fmt, ...) __attribute__((__format__(__printf__, 1, 2))) {
+ va_list args;
+ vprintf(fmt, args);
+ };
+
+ void __attribute__((__format__(__printf__, 2, 3))) (^b5)(const char *, const char *, ...) =
+ ^(const char *not_fmt, const char *fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { // #b5
+ va_list args;
+ vprintf(fmt, args);
+ vprintf(not_fmt, args); // expected-warning{{diagnostic behavior may be improved by adding the 'format(printf, 1, 3)' attribute to the declaration of block}}
+ // expected-note@#b5 {{block declared here}}
+ };
+}
diff --git a/clang/test/Sema/format-attr-missing.c b/clang/test/Sema/format-attr-missing.c
new file mode 100644
index 0000000..5133e59
--- /dev/null
+++ b/clang/test/Sema/format-attr-missing.c
@@ -0,0 +1,228 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c23 -Wmissing-format-attribute %s
+// RUN: %clang_cc1 -fsyntax-only -std=c23 -Wmissing-format-attribute -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+typedef unsigned long size_t;
+typedef long ssize_t;
+typedef __builtin_va_list va_list;
+
+[[gnu::format(printf, 1, 2)]]
+int printf(const char *, ...);
+
+[[gnu::format(scanf, 1, 2)]]
+int scanf(const char *, ...);
+
+[[gnu::format(printf, 1, 0)]]
+int vprintf(const char *, va_list);
+
+[[gnu::format(scanf, 1, 0)]]
+int vscanf(const char *, va_list);
+
+[[gnu::format(printf, 2, 0)]]
+int vsprintf(char *, const char *, va_list);
+
+struct tm { unsigned i; };
+[[gnu::format(strftime, 3, 0)]]
+size_t strftime(char *, size_t, const char *, const struct tm *);
+
+[[gnu::format(strfmon, 3, 4)]]
+ssize_t strfmon(char *, size_t, const char *, ...);
+
+[[gnu::format_matches(printf, 1, "%d %f \"'")]]
+int custom_print(const char *, va_list);
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 0)]] "
+void f1(const char *fmt, va_list args) // #f1
+{
+ vprintf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 0)' attribute to the declaration of 'f1'}}
+ // expected-note@#f1 {{'f1' declared here}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(scanf, 1, 0)]] "
+void f2(const char *fmt, va_list args) // #f2
+{
+ vscanf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 0)' attribute to the declaration of 'f2'}}
+ // expected-note@#f2 {{'f2' declared here}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] "
+void f3(const char *fmt, ... /* args */) // #f3
+{
+ va_list args;
+ vprintf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f3'}}
+ // expected-note@#f3 {{'f3' declared here}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(scanf, 1, 2)]] "
+void f4(const char *fmt, ... /* args */) // #f4
+{
+ va_list args;
+ vscanf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'f4'}}
+ // expected-note@#f4 {{'f4' declared here}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+2]]:1-[[@LINE+2]]:1}:"{{\[\[}}gnu::format(printf, 2, 3)]] "
+[[gnu::format(printf, 1, 3)]]
+void f5(char *out, const char *format, ... /* args */) // #f5
+{
+ va_list args;
+ vsprintf(out, format, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of 'f5'}}
+ // expected-note@#f5 {{'f5' declared here}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+2]]:1-[[@LINE+2]]:1}:"{{\[\[}}gnu::format(printf, 2, 3)]] "
+[[gnu::format(scanf, 1, 3)]]
+void f6(char *out, const char *format, ... /* args */) // #f6
+{
+ va_list args;
+ vsprintf(out, format, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of 'f6'}}
+ // expected-note@#f6 {{'f6' declared here}}
+}
+
+// Ok, out is not passed to print functions.
+void f7(char* out, ... /* args */)
+{
+ va_list args;
+
+ const char *ch = "format";
+ vprintf(ch, args);
+ vprintf("test", args);
+}
+
+// Ok, format string is not passed to format functions.
+void f8(va_list args)
+{
+ const char * const ch = "format";
+ vprintf(ch, args);
+ vprintf("test", args);
+
+ vscanf(ch, args);
+ vscanf("test", args);
+
+ char out[10];
+
+ struct tm tm_arg;
+ tm_arg.i = 0;
+ strftime(out, sizeof(out), ch, &tm_arg);
+ strftime(out, sizeof(out), "test", &tm_arg);
+
+ strfmon(out, sizeof(out), ch);
+ strfmon(out, sizeof(out), "test");
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format_matches(printf, 1, \"%d %f \\\"'\")]] "
+void f9(const char *fmt, ...) // #f9
+{
+ va_list args;
+ custom_print(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format_matches(printf, 1, "%d %f \"'")' attribute to the declaration of 'f9'}}
+ // expected-note@#f9 {{'f9' declared here}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(scanf, 1, 2)]] "
+void f10(const char *out, ... /* args */) // #f10
+{
+ va_list args;
+ vscanf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'f10'}}
+ // expected-note@#f10 {{'f10' declared here}}
+ vprintf(out, args); // expected-warning {{passing 'scanf' format string where 'printf' format string is expected}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] "
+void f11(const char out[], ... /* args */) // #f11
+{
+ va_list args;
+ char ch[10] = "format";
+ vprintf(ch, args);
+ vsprintf(ch, out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f11'}}
+ // expected-note@#f11 {{'f11' declared here}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 0)]] "
+void f12(char* out) // #f12
+{
+ va_list args;
+ const char *ch = "format";
+ vsprintf(out, ch, args);
+ vprintf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 0)' attribute to the declaration of 'f12'}}
+ // expected-note@#f12 {{'f12' declared here}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 0)]] "
+void f13(char *out, va_list args) // #f13
+{
+ vprintf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 0)' attribute to the declaration of 'f13'}}
+ // expected-note@#f13 {{'f13' declared here}}
+ vscanf(out, args); // expected-warning {{passing 'printf' format string where 'scanf' format string is expected}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(scanf, 1, 2)]] "
+void f14(char *out, ... /* args */) // #f14
+{
+ va_list args;
+ vscanf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'f14'}}
+ // expected-note@#f14 {{'f14' declared here}}
+ vscanf(out, args);
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+2]]:1-[[@LINE+2]]:1}:"{{\[\[}}gnu::format(printf, 1, 3)]] "
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 2, 3)]] "
+void f15(char *ch, const char *out, ... /* args */) // #f15
+{
+ va_list args;
+ vprintf(ch, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 3)' attribute to the declaration of 'f15'}}
+ // expected-note@#f15 {{'f15' declared here}}
+ vprintf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of 'f15'}}
+ // expected-note@#f15 {{'f15' declared here}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] "
+void f16(const char *a, ...) // #f16
+{
+ va_list args;
+ const char *const b = a;
+ vprintf(b, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f16'}}
+ // expected-note@#f16 {{'f16' declared here}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] "
+void f17(char *fmt, unsigned x, unsigned y, unsigned z) // #f17
+{
+ printf(fmt, x, y, z); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f17'}}
+ // expected-note@#f17 {{'f17' declared here}}
+}
+
+void f18(char *fmt, unsigned x, unsigned y, unsigned z) // #f18
+{
+ // Arguments are not passed in the same order.
+ printf(fmt, x, z, y);
+}
+
+void f19(char *out, ... /* args */)
+{
+ printf(out, 1); // No warning, arguments are not passed to printf.
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(strftime, 3, 0)]] "
+void f20(char *out, const size_t len, const char *format) // #f20
+{
+ struct tm tm_arg;
+ tm_arg.i = 0;
+ strftime(out, len, format, &tm_arg); // expected-warning {{diagnostic behavior may be improved by adding the 'format(strftime, 3, 0)' attribute to the declaration of 'f20'}}
+ // expected-note@#f20 {{'f20' declared here}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(strfmon, 3, 4)]] "
+void f21(char *out, const size_t len, const char *format, int x, int y) // #f21
+{
+ strfmon(out, len, format, x, y); // expected-warning {{diagnostic behavior may be improved by adding the 'format(strfmon, 3, 4)' attribute to the declaration of 'f21'}}
+ // expected-note@#f21 {{'f21' declared here}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] "
+void f22(const char *fmt, ... /* args */); // #f22
+
+void f22(const char *fmt, ... /* args */)
+{
+ va_list args;
+ vprintf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f22'}}
+ // expected-note@#f22 {{'f22' declared here}}
+}
diff --git a/clang/test/Sema/format-attr-missing.cpp b/clang/test/Sema/format-attr-missing.cpp
new file mode 100644
index 0000000..06b5ad1a
--- /dev/null
+++ b/clang/test/Sema/format-attr-missing.cpp
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++23 -Wmissing-format-attribute %s
+// RUN: %clang_cc1 -fsyntax-only -Wmissing-format-attribute -fdiagnostics-parseable-fixits -std=c++23 %s 2>&1 | FileCheck %s
+
+typedef __SIZE_TYPE__ size_t;
+typedef __builtin_va_list va_list;
+
+[[gnu::format(printf, 1, 2)]]
+int printf(const char *, ...);
+
+[[gnu::format(scanf, 1, 2)]]
+int scanf(const char *, ...);
+
+[[gnu::format(printf, 1, 0)]]
+int vprintf(const char *, va_list);
+
+[[gnu::format(scanf, 1, 0)]]
+int vscanf(const char *, va_list);
+
+[[gnu::format(printf, 2, 0)]]
+int vsprintf(char *, const char *, va_list);
+
+[[gnu::format(printf, 3, 0)]]
+int vsnprintf(char *, size_t, const char *, va_list);
+
+struct S1
+{
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:3-[[@LINE+1]]:3}:"{{\[\[}}gnu::format(scanf, 2, 3)]] "
+ void fn1(const char *out, ... /* args */) // #S1_fn1
+ {
+ va_list args;
+ vscanf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 2, 3)' attribute to the declaration of 'fn1'}}
+ // expected-note@#S1_fn1 {{'fn1' declared here}}
+ }
+
+ [[gnu::format(printf, 2, 0)]]
+ void print(const char *out, va_list args);
+
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:3-[[@LINE+1]]:3}:"{{\[\[}}gnu::format(printf, 2, 3)]] "
+ void fn2(const char *out, ... /* args */) // #S1_fn2
+ {
+ va_list args;
+ print(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of 'fn2'}}
+ // expected-note@#S1_fn2 {{'fn2' declared here}}
+ }
+
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:3-[[@LINE+1]]:3}:"{{\[\[}}gnu::format(printf, 2, 0)]] "
+ void fn3(const char *out, va_list args) // #S1_fn3
+ {
+ print(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 0)' attribute to the declaration of 'fn3'}}
+ // expected-note@#S1_fn3 {{'fn3' declared here}}
+ }
+
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:3-[[@LINE+1]]:3}:"{{\[\[}}gnu::format(printf, 2, 3)]] "
+ void fn4(this S1& self, const char *out, ... /* args */) // #S1_fn4
+ {
+ va_list args;
+ self.print(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of 'fn4'}}
+ // expected-note@#S1_fn4 {{'fn4' declared here}}
+ }
+
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:3-[[@LINE+1]]:3}:"{{\[\[}}gnu::format(printf, 2, 0)]] "
+ void fn5(this S1& self, const char *out, va_list args) // #S1_fn5
+ {
+ self.print(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 0)' attribute to the declaration of 'fn5'}}
+ // expected-note@#S1_fn5 {{'fn5' declared here}}
+ }
+};
+
diff --git a/clang/test/Sema/format-attr-missing.m b/clang/test/Sema/format-attr-missing.m
new file mode 100644
index 0000000..159b4ba
--- /dev/null
+++ b/clang/test/Sema/format-attr-missing.m
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wmissing-format-attribute %s
+// RUN: %clang_cc1 -fsyntax-only -Wmissing-format-attribute -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+#include <stdarg.h>
+
+@interface PrintCallee
+-(void)printf:(const char *)fmt, ... __attribute__((format(printf, 1, 2)));
+-(void)vprintf:(const char *)fmt list:(va_list)ap __attribute__((format(printf, 1, 0)));
+@end
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"__attribute__((format(printf, 2, 3))) "
+void f1(PrintCallee *p, const char *fmt, int x) // #f1
+{
+ [p printf:fmt, x]; // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of 'f1'}}
+ // expected-note@#f1 {{'f1' declared here}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"__attribute__((format(printf, 2, 3))) "
+void f2(PrintCallee *p, const char *fmt, ...) // #f2
+{
+ va_list ap;
+ [p vprintf:fmt list:ap]; // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of 'f2'}}
+ // expected-note@#f2 {{'f2' declared here}}
+}
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"__attribute__((format(printf, 2, 0))) "
+void f3(PrintCallee *p, const char *fmt, va_list ap) // #f3
+{
+ [p vprintf:fmt list:ap]; // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 0)' attribute to the declaration of 'f3'}}
+ // expected-note@#f3 {{'f3' declared here}}
+}
+
+__attribute__((format(printf, 1, 2)))
+int printf(const char *, ...);
+__attribute__((format(printf, 1, 0)))
+int vprintf(const char *, va_list ap);
+
+__attribute__((objc_root_class))
+@interface PrintCaller
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:33-[[@LINE+1]]:33}:" __attribute__((format(printf, 1, 2)))"
+-(void)f4:(const char *)fmt, ...; // #f4
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:45-[[@LINE+1]]:45}:" __attribute__((format(printf, 1, 0)))"
+-(void)f5:(const char *)fmt list:(va_list)ap; // #f5
+
+// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:37-[[@LINE+1]]:37}:" __attribute__((format(printf, 1, 2)))"
+-(void)f6:(const char *)fmt x:(int)x; // #f6
+@end
+
+@implementation PrintCaller
+-(void)f4:(const char *)fmt, ... {
+ va_list ap;
+ va_start(ap, fmt);
+ vprintf(fmt, ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f4:'}}
+ // expected-note@#f4 {{'f4:' declared here}}
+ va_end(ap);
+}
+
+-(void)f5:(const char *)fmt list:(va_list)ap {
+ vprintf(fmt, ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 0)' attribute to the declaration of 'f5:list:'}}
+ // expected-note@#f5 {{'f5:list:' declared here}}
+}
+
+-(void)f6:(const char *)fmt x:(int)x {
+ printf(fmt, x); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f6:x:'}}
+ // expected-note@#f6 {{'f6:x:' declared here}}
+}
+@end
diff --git a/clang/test/Sema/format-strings-nonnull.c b/clang/test/Sema/format-strings-nonnull.c
new file mode 100644
index 0000000..b9eeb59
--- /dev/null
+++ b/clang/test/Sema/format-strings-nonnull.c
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -fsyntax-only --std=c23 -verify -Wnonnull -Wno-format-security %s
+
+#define NULL (void*)0
+
+typedef struct _FILE FILE;
+typedef __SIZE_TYPE__ size_t;
+typedef __builtin_va_list va_list;
+int printf(char const* restrict, ...);
+int __builtin_printf(char const* restrict, ...);
+int fprintf(FILE* restrict, char const* restrict, ...);
+int snprintf(char* restrict, size_t, char const* restrict, ...);
+int sprintf(char* restrict, char const* restrict, ...);
+int vprintf(char const* restrict, __builtin_va_list);
+int vfprintf(FILE* restrict, char const* restrict, __builtin_va_list);
+int vsnprintf(char* restrict, size_t, char const* restrict, __builtin_va_list);
+int vsprintf(char* restrict, char const* restrict, __builtin_va_list);
+
+int scanf(char const* restrict, ...);
+int fscanf(FILE* restrict, char const* restrict, ...);
+int sscanf(char const* restrict, char const* restrict, ...);
+int vscanf(char const* restrict, __builtin_va_list);
+int vfscanf(FILE* restrict, char const* restrict, __builtin_va_list);
+int vsscanf(char const* restrict, char const* restrict, __builtin_va_list);
+
+
+void check_format_string(FILE *fp, va_list ap) {
+ char buf[256];
+ int num;
+ char* const fmt = NULL;
+
+ printf(fmt);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+
+ __builtin_printf(NULL, "xxd");
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+
+ fprintf(fp, NULL, 25);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+
+ sprintf(NULL, NULL, 42);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+ // expected-warning@-2{{null passed to a callee that requires a non-null argument}}
+
+ snprintf(buf, 10, 0, 42);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+
+ vprintf(fmt, ap);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+
+ vfprintf(fp, 0, ap);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+
+ vsprintf(buf, nullptr, ap);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+
+ vsnprintf(buf, 10, fmt, ap);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+
+ scanf(NULL);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+
+ fscanf(nullptr, nullptr);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+ // expected-warning@-2{{null passed to a callee that requires a non-null argument}}
+
+ sscanf(NULL, "%d %s", &num, buf);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+ sscanf(buf, fmt);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+
+ vscanf(NULL, ap);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+
+ vfscanf(fp, fmt, ap);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+
+ vsscanf(buf, NULL, ap);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
+}
diff --git a/clang/test/Sema/format-strings-nonnull.cpp b/clang/test/Sema/format-strings-nonnull.cpp
new file mode 100644
index 0000000..6c25679
--- /dev/null
+++ b/clang/test/Sema/format-strings-nonnull.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wnonnull %s
+
+#ifdef __cplusplus
+# define EXTERN_C extern "C"
+#else
+# define EXTERN_C extern
+#endif
+
+typedef struct _FILE FILE;
+typedef __SIZE_TYPE__ size_t;
+typedef __builtin_va_list va_list;
+
+EXTERN_C int printf(const char *, ...);
+EXTERN_C int fprintf(FILE *, const char *restrict, ...);
+EXTERN_C int sprintf(char* restrict, char const* res, ...);
+EXTERN_C int vfprintf(FILE* restrict, char const* res, __builtin_va_list);
+
+EXTERN_C int scanf(char const *restrict, ...);
+EXTERN_C int fscanf(FILE* restrict, char const* res, ...);
+EXTERN_C int sscanf(char const* restrict, char const* res, ...);
+
+void test(FILE *fp, va_list ap) {
+ char buf[256];
+ int num;
+
+ __builtin_printf(__null, "x");
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
+
+ printf(__null, "xxd");
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
+
+ fprintf(fp, __null, 42);
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
+
+ sprintf(buf, __null);
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
+
+ scanf(__null);
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
+
+ fscanf(fp, __null);
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
+
+ vfprintf(__null, "xxd", ap);
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
+
+ sscanf(__null, "%d", &num);
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
+}
diff --git a/clang/test/Sema/format-strings-scanf.c b/clang/test/Sema/format-strings-scanf.c
index 22c1cce..941e3f7 100644
--- a/clang/test/Sema/format-strings-scanf.c
+++ b/clang/test/Sema/format-strings-scanf.c
@@ -36,8 +36,9 @@ int vscanf(const char * restrict, va_list);
int vfscanf(FILE * restrict, const char * restrict, va_list);
int vsscanf(const char * restrict, const char * restrict, va_list);
-void test(const char *s, int *i) {
- scanf(s, i); // expected-warning{{format string is not a string literal}}
+void test(const char *s, int *i) { // #test
+ scanf(s, i); // expected-warning{{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'test'}}
+ // expected-note@#test {{'test' declared here}}
scanf("%0d", i); // expected-warning{{zero field width in scanf format string is unused}}
scanf("%00d", i); // expected-warning{{zero field width in scanf format string is unused}}
scanf("%d%[asdfasdfd", i, s); // expected-warning{{no closing ']' for '%[' in scanf format string}}
diff --git a/clang/test/Sema/format-strings.c b/clang/test/Sema/format-strings.c
index 103dd8a..5280549 100644
--- a/clang/test/Sema/format-strings.c
+++ b/clang/test/Sema/format-strings.c
@@ -24,37 +24,115 @@ int vscanf(const char *restrict format, va_list arg);
char * global_fmt;
-void check_string_literal( FILE* fp, const char* s, char *buf, ... ) {
-
- char * b;
+void check_string_literal1( const char* s, ... ) {
va_list ap;
- va_start(ap,buf);
-
+ va_start(ap,s);
printf(s); // expected-warning {{format string is not a string literal}}
// expected-note@-1{{treat the string as an argument to avoid this}}
- vprintf(s,ap); // expected-warning {{format string is not a string literal}}
+}
+
+void check_string_literal2( const char* s, ... ) { // #check_string_literal2
+ va_list ap;
+ va_start(ap,s);
+ vprintf(s,ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'check_string_literal2'}}
+ // expected-note@#check_string_literal2 {{'check_string_literal2' declared here}}
+}
+
+void check_string_literal3( FILE* fp, const char* s, ... ) {
+ va_list ap;
+ va_start(ap,s);
fprintf(fp,s); // expected-warning {{format string is not a string literal}}
// expected-note@-1{{treat the string as an argument to avoid this}}
- vfprintf(fp,s,ap); // expected-warning {{format string is not a string literal}}
+}
+
+void check_string_literal4( FILE* fp, const char* s, ... ) { // #check_string_literal4
+ va_list ap;
+ va_start(ap,s);
+ vfprintf(fp,s,ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of 'check_string_literal4'}}
+ // expected-note@#check_string_literal4 {{'check_string_literal4' declared here}}
+}
+
+void check_string_literal5( const char* s, ... ) {
+ char * b;
+ va_list ap;
+ va_start(ap,s);
asprintf(&b,s); // expected-warning {{format string is not a string lit}}
// expected-note@-1{{treat the string as an argument to avoid this}}
- vasprintf(&b,s,ap); // expected-warning {{format string is not a string literal}}
+}
+
+void check_string_literal6( const char* s, ... ) { // #check_string_literal6
+ char * b;
+ va_list ap;
+ va_start(ap,s);
+ vasprintf(&b,s,ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'check_string_literal6'}}
+ // expected-note@#check_string_literal6 {{'check_string_literal6' declared here}}
+}
+
+void check_string_literal7( const char* s, char *buf ) {
sprintf(buf,s); // expected-warning {{format string is not a string literal}}
// expected-note@-1{{treat the string as an argument to avoid this}}
+}
+
+void check_string_literal8( const char* s, char *buf ) {
snprintf(buf,2,s); // expected-warning {{format string is not a string lit}}
// expected-note@-1{{treat the string as an argument to avoid this}}
+}
+
+void check_string_literal9( const char* s, char *buf, ... ) {
+ va_list ap;
+ va_start(ap,buf);
__builtin___sprintf_chk(buf,0,-1,s); // expected-warning {{format string is not a string literal}}
// expected-note@-1{{treat the string as an argument to avoid this}}
+}
+
+void check_string_literal10( const char* s, char *buf, ... ) {
+ va_list ap;
+ va_start(ap,buf);
__builtin___snprintf_chk(buf,2,0,-1,s); // expected-warning {{format string is not a string lit}}
// expected-note@-1{{treat the string as an argument to avoid this}}
- vsprintf(buf,s,ap); // expected-warning {{format string is not a string lit}}
- vsnprintf(buf,2,s,ap); // expected-warning {{format string is not a string lit}}
+}
+
+void check_string_literal11( const char* s, char *buf, ... ) { // #check_string_literal11
+ va_list ap;
+ va_start(ap,buf);
+ vsprintf(buf,s,ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 3)' attribute to the declaration of 'check_string_literal11'}}
+ // expected-note@#check_string_literal11 {{'check_string_literal11' declared here}}
+}
+
+void check_string_literal12( const char* s, char *buf, ... ) { // #check_string_literal12
+ va_list ap;
+ va_start(ap,buf);
+ vsnprintf(buf,2,s,ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 3)' attribute to the declaration of 'check_string_literal12'}}
+ // expected-note@#check_string_literal12 {{'check_string_literal12' declared here}}
+}
+
+void check_string_literal13( char *buf, ... ) {
+ va_list ap;
+ va_start(ap,buf);
vsnprintf(buf,2,global_fmt,ap); // expected-warning {{format string is not a string literal}}
- __builtin___vsnprintf_chk(buf,2,0,-1,s,ap); // expected-warning {{format string is not a string lit}}
+}
+
+void check_string_literal14( FILE* fp, const char* s, char *buf, ... ) { // #check_string_literal14
+ va_list ap;
+ va_start(ap,buf);
+ __builtin___vsnprintf_chk(buf,2,0,-1,s,ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 4)' attribute to the declaration of 'check_string_literal14'}}
+ // expected-note@#check_string_literal14 {{'check_string_literal14' declared here}}
+}
+
+void check_string_literal15( FILE* fp, const char* s, char *buf, ... ) {
+ va_list ap;
+ va_start(ap,buf);
__builtin___vsnprintf_chk(buf,2,0,-1,global_fmt,ap); // expected-warning {{format string is not a string literal}}
+}
- vscanf(s, ap); // expected-warning {{format string is not a string literal}}
+void check_string_literal16(const char* s, ... ) { // #check_string_literal16
+ va_list ap;
+ va_start(ap,s);
+ vscanf(s, ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'check_string_literal16'}}
+ // expected-note@#check_string_literal16 {{'check_string_literal16' declared here}}
+}
+void check_string_literal17() {
const char *const fmt = "%d"; // FIXME -- defined here
printf(fmt, 1, 2); // expected-warning{{data argument not used}}
@@ -74,7 +152,7 @@ def"
// warn only if the format string argument is a parameter that is not itself
// declared as a format string with compatible format.
__attribute__((__format__ (__printf__, 2, 4)))
-void check_string_literal2( FILE* fp, const char* s, char *buf, ... ) {
+void check_string_literal18( FILE* fp, const char* s, char *buf, ... ) {
char * b;
va_list ap;
va_start(ap,buf);
@@ -480,11 +558,9 @@ void pr7981(wint_t c, wchar_t c2) {
#endif
}
-// -Wformat-security says NULL is not a string literal
void rdar8269537(void) {
- // This is likely to crash in most cases, but -Wformat-nonliteral technically
- // doesn't warn in this case.
- printf(0); // no-warning
+ printf(0);
+ // expected-warning@-1{{null passed to a callee that requires a non-null argument}}
}
// Handle functions with multiple format attributes.
@@ -840,12 +916,13 @@ void test_block(void) {
void __attribute__((__format__(__printf__, 2, 3))) (^printf_arg2)(
const char *, const char *, ...) =
- ^(const char *not_fmt, const char *fmt, ...)
+ ^(const char *not_fmt, const char *fmt, ...) // #printf_arg2
__attribute__((__format__(__printf__, 2, 3))) {
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
- vprintf(not_fmt, ap); // expected-warning{{format string is not a string literal}}
+ vprintf(not_fmt, ap); // expected-warning{{diagnostic behavior may be improved by adding the 'format(printf, 1, 3)' attribute to the declaration of block}}
+ // expected-note@#printf_arg2 {{block declared here}}
va_end(ap);
};
diff --git a/clang/test/Sema/scoped-atomic-ops.c b/clang/test/Sema/scoped-atomic-ops.c
index 33044aa..23512a9 100644
--- a/clang/test/Sema/scoped-atomic-ops.c
+++ b/clang/test/Sema/scoped-atomic-ops.c
@@ -31,7 +31,7 @@ void fi2b(int *i) {
__scoped_atomic_store_n(i, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
}
-void fi3a(int *a, int *b, int *c, int *d, int *e, int *f, int *g, int *h) {
+void fi3a(int *a, int *b, int *c, int *d, int *e, int *f, int *g, int *h, unsigned *i, unsigned *j) {
*a = __scoped_atomic_fetch_add(a, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
*b = __scoped_atomic_fetch_sub(b, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
*c = __scoped_atomic_fetch_and(c, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
@@ -40,9 +40,11 @@ void fi3a(int *a, int *b, int *c, int *d, int *e, int *f, int *g, int *h) {
*f = __scoped_atomic_fetch_nand(f, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
*g = __scoped_atomic_fetch_min(g, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
*h = __scoped_atomic_fetch_max(h, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
+ *i = __scoped_atomic_uinc_wrap(i, 1u, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
+ *j = __scoped_atomic_udec_wrap(j, 1u, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
}
-void fi3b(int *a, int *b, int *c, int *d, int *e, int *f, int *g, int *h) {
+void fi3b(int *a, int *b, int *c, int *d, int *e, int *f, int *g, int *h, unsigned *i, unsigned *j) {
*a = __scoped_atomic_fetch_add(1, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM); // expected-error {{address argument to atomic builtin must be a pointer ('int' invalid)}}
*b = __scoped_atomic_fetch_sub(1, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM); // expected-error {{address argument to atomic builtin must be a pointer ('int' invalid)}}
*c = __scoped_atomic_fetch_and(1, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM); // expected-error {{address argument to atomic builtin must be a pointer ('int' invalid)}}
@@ -51,9 +53,11 @@ void fi3b(int *a, int *b, int *c, int *d, int *e, int *f, int *g, int *h) {
*f = __scoped_atomic_fetch_nand(1, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM); // expected-error {{address argument to atomic builtin must be a pointer ('int' invalid)}}
*g = __scoped_atomic_fetch_min(1, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM); // expected-error {{address argument to atomic builtin must be a pointer ('int' invalid)}}
*h = __scoped_atomic_fetch_max(1, 1, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM); // expected-error {{address argument to atomic builtin must be a pointer ('int' invalid)}}
+ *i = __scoped_atomic_uinc_wrap(1, 1u, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM); // expected-error {{address argument to atomic builtin must be a pointer ('int' invalid)}}
+ *g = __scoped_atomic_udec_wrap(1, 1u, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM); // expected-error {{address argument to atomic builtin must be a pointer ('int' invalid)}}
}
-void fi3c(int *a, int *b, int *c, int *d, int *e, int *f, int *g, int *h) {
+void fi3c(int *a, int *b, int *c, int *d, int *e, int *f, int *g, int *h, unsigned *i, unsigned *j) {
*a = __scoped_atomic_fetch_add(a, 1, __ATOMIC_RELAXED); // expected-error {{too few arguments to function call, expected 4, have 3}}
*b = __scoped_atomic_fetch_sub(b, 1, __ATOMIC_RELAXED); // expected-error {{too few arguments to function call, expected 4, have 3}}
*c = __scoped_atomic_fetch_and(c, 1, __ATOMIC_RELAXED); // expected-error {{too few arguments to function call, expected 4, have 3}}
@@ -62,9 +66,11 @@ void fi3c(int *a, int *b, int *c, int *d, int *e, int *f, int *g, int *h) {
*f = __scoped_atomic_fetch_nand(f, 1, __ATOMIC_RELAXED); // expected-error {{too few arguments to function call, expected 4, have 3}}
*g = __scoped_atomic_fetch_min(g, 1, __ATOMIC_RELAXED); // expected-error {{too few arguments to function call, expected 4, have 3}}
*h = __scoped_atomic_fetch_max(h, 1, __ATOMIC_RELAXED); // expected-error {{too few arguments to function call, expected 4, have 3}}
+ *i = __scoped_atomic_uinc_wrap(i, 1u, __ATOMIC_RELAXED); // expected-error {{too few arguments to function call, expected 4, have 3}}
+ *j = __scoped_atomic_udec_wrap(j, 1u, __ATOMIC_RELAXED); // expected-error {{too few arguments to function call, expected 4, have 3}}
}
-void fi3d(int *a, int *b, int *c, int *d, int *e, int *f, int *g, int *h) {
+void fi3d(int *a, int *b, int *c, int *d, int *e, int *f, int *g, int *h, unsigned *i, unsigned *j) {
*a = __scoped_atomic_fetch_add(a, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
*b = __scoped_atomic_fetch_sub(b, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
*c = __scoped_atomic_fetch_and(c, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
@@ -73,6 +79,17 @@ void fi3d(int *a, int *b, int *c, int *d, int *e, int *f, int *g, int *h) {
*f = __scoped_atomic_fetch_nand(f, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
*g = __scoped_atomic_fetch_min(g, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
*h = __scoped_atomic_fetch_max(h, 1, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
+ *i = __scoped_atomic_uinc_wrap(i, 1u, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
+ *j = __scoped_atomic_udec_wrap(j, 1u, __ATOMIC_RELAXED, 42); // expected-error {{synchronization scope argument to atomic operation is invalid}}
+}
+
+void fi3e(float *a, float *b, float *c, float *d, float *e, float *f) {
+ *a = __scoped_atomic_fetch_and(a, 1, __ATOMIC_RELAXED, 42); // expected-error {{address argument to atomic operation must be a pointer to integer ('float *' invalid)}}
+ *b = __scoped_atomic_fetch_or(b, 1, __ATOMIC_RELAXED, 42); // expected-error {{address argument to atomic operation must be a pointer to integer ('float *' invalid)}}
+ *c = __scoped_atomic_fetch_xor(c, 1, __ATOMIC_RELAXED, 42); // expected-error {{address argument to atomic operation must be a pointer to integer ('float *' invalid)}}
+ *d = __scoped_atomic_fetch_nand(d, 1, __ATOMIC_RELAXED, 42); // expected-error {{address argument to atomic operation must be a pointer to integer ('float *' invalid)}}
+ *f = __scoped_atomic_uinc_wrap(f, 1u, __ATOMIC_RELAXED, 42); // expected-error {{address argument to atomic operation must be a pointer to integer ('float *' invalid)}}
+ *e = __scoped_atomic_udec_wrap(e, 1u, __ATOMIC_RELAXED, 42); // expected-error {{address argument to atomic operation must be a pointer to integer ('float *' invalid)}}
}
int fi4a(int *i) {
diff --git a/clang/test/Sema/type-dependent-attrs.c b/clang/test/Sema/type-dependent-attrs.c
new file mode 100644
index 0000000..13068b3
--- /dev/null
+++ b/clang/test/Sema/type-dependent-attrs.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify %s
+
+int open() { return 0; }
+void close(typeof(open()) *) {}
+
+void cleanup_attr() {
+ int fd_int [[gnu::cleanup(close)]] = open();
+ auto fd_auto [[gnu::cleanup(close)]] = open();
+ float fd_invalid [[gnu::cleanup(close)]] = open(); // expected-error {{'cleanup' function 'close' parameter has type 'typeof (open()) *' (aka 'int *') which is incompatible with type 'float *'}}
+}
diff --git a/clang/test/Sema/warn-enum-compare-typo.c b/clang/test/Sema/warn-enum-compare-typo.c
new file mode 100644
index 0000000..f937df1
--- /dev/null
+++ b/clang/test/Sema/warn-enum-compare-typo.c
@@ -0,0 +1,98 @@
+// RUN: %clang_cc1 -fsyntax-only -Wenum-compare-typo -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wenum-compare-typo -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+
+enum PossibleTypoLeft {
+ Val1 = 1 << 0,
+ // expected-warning@+3 {{comparison operator '<' is potentially a typo for a shift operator '<<'}}
+ // expected-note@+2 {{use '<<' to perform a bitwise shift}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:12-[[@LINE+1]]:13}:"<<"
+ Bad1 = 1 < 2,
+ // expected-warning@+3 {{comparison operator '>' is potentially a typo for a shift operator '>>'}}
+ // expected-note@+2 {{use '>>' to perform a bitwise shift}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:12-[[@LINE+1]]:13}:">>"
+ Bad2 = 1 > 3,
+ // expected-warning@+3 {{comparison operator '>' is potentially a typo for a shift operator '>>'}}
+ // expected-note@+2 {{use '>>' to perform a bitwise shift}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:13-[[@LINE+1]]:14}:">>"
+ Bad3 = (1 > 3)
+};
+
+enum PossibleTypoRight {
+ Val2 = 1 >> 0,
+ // expected-warning@+3 {{comparison operator '<' is potentially a typo for a shift operator '<<'}}
+ // expected-note@+2 {{use '<<' to perform a bitwise shift}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:12-[[@LINE+1]]:13}:"<<"
+ Bad4 = 1 < 2,
+ // expected-warning@+3 {{comparison operator '>' is potentially a typo for a shift operator '>>'}}
+ // expected-note@+2 {{use '>>' to perform a bitwise shift}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:12-[[@LINE+1]]:13}:">>"
+ Bad5 = 1 > 3,
+ // expected-warning@+3 {{comparison operator '<' is potentially a typo for a shift operator '<<'}}
+ // expected-note@+2 {{use '<<' to perform a bitwise shift}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:13-[[@LINE+1]]:14}:"<<"
+ Bad6 = (1 < 3)
+};
+
+// Case 3: Context provided by other bitwise operators (&, |)
+// Even though there are no shifts, the presence of '|' implies flags.
+enum PossibleTypoBitwiseOr {
+ FlagA = 0x1,
+ FlagB = 0x2,
+ FlagCombo = FlagA | FlagB,
+ // expected-warning@+3 {{comparison operator '<' is potentially a typo for a shift operator '<<'}}
+ // expected-note@+2 {{use '<<' to perform a bitwise shift}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:17-[[@LINE+1]]:18}:"<<"
+ FlagTypo1 = 1 < FlagCombo,
+ // expected-warning@+3 {{comparison operator '>' is potentially a typo for a shift operator '>>'}}
+ // expected-note@+2 {{use '>>' to perform a bitwise shift}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:17-[[@LINE+1]]:18}:">>"
+ FlagTypo2 = 1 > FlagCombo
+};
+
+enum PossibleTypoBitwiseAnd {
+ FlagAnd = FlagA & FlagB,
+ // expected-warning@+3 {{comparison operator '<' is potentially a typo for a shift operator '<<'}}
+ // expected-note@+2 {{use '<<' to perform a bitwise shift}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:17-[[@LINE+1]]:18}:"<<"
+ FlagTypo3 = 1 < FlagAnd,
+ // expected-warning@+3 {{comparison operator '>' is potentially a typo for a shift operator '>>'}}
+ // expected-note@+2 {{use '>>' to perform a bitwise shift}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:17-[[@LINE+1]]:18}:">>"
+ FlagTypo4 = 1 > FlagAnd
+};
+
+enum NoWarningOnDirectInit {
+ A = 0,
+ B = 1,
+ Ok1 = 1 < 2, // No warning expected
+ Ok2 = 1 > 2 // No warning expected
+};
+
+enum NoWarningOnArith {
+ D = 0 + 1,
+ E = D * 10,
+ F = E - D,
+ G = F / D,
+ Ok3 = 1 < E, // No warning expected
+ Ok4 = 1 > E // No warning expected
+};
+
+enum NoWarningOnExplicitCast {
+ Bit1 = 1 << 0,
+ Ok5 = (int)(1 < 2) // No warning expected
+};
+
+enum NoWarningOnNoneBitShift {
+ Bit2 = 1 << 0,
+ Ok6 = (3 < 2) // No warning expected
+};
+
+// Ensure the diagnostic group works
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wenum-compare-typo"
+enum IGNORED {
+ Ok7 = 1 << 1,
+ Ignored3 = 1 < 10 // No warning
+};
+#pragma clang diagnostic pop
diff --git a/clang/test/Sema/warn-fortify-scanf.c b/clang/test/Sema/warn-fortify-scanf.c
index 16cbfa2..7b8f4b7 100644
--- a/clang/test/Sema/warn-fortify-scanf.c
+++ b/clang/test/Sema/warn-fortify-scanf.c
@@ -59,10 +59,17 @@ void call_fscanf(void) {
char buf20[20];
char buf30[30];
fscanf(0, "%4s %5s %10s", buf20, buf30, buf10); // expected-warning {{'fscanf' may overflow; destination buffer in argument 5 has size 10, but the corresponding specifier may require size 11}}
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
fscanf(0, "%4s %5s %11s", buf20, buf30, buf10); // expected-warning {{'fscanf' may overflow; destination buffer in argument 5 has size 10, but the corresponding specifier may require size 12}}
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
fscanf(0, "%4s %5s %9s", buf20, buf30, buf10);
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
fscanf(0, "%20s %5s %9s", buf20, buf30, buf10); // expected-warning {{'fscanf' may overflow; destination buffer in argument 3 has size 20, but the corresponding specifier may require size 21}}
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
fscanf(0, "%21s %5s %9s", buf20, buf30, buf10); // expected-warning {{'fscanf' may overflow; destination buffer in argument 3 has size 20, but the corresponding specifier may require size 22}}
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
fscanf(0, "%19s %5s %9s", buf20, buf30, buf10);
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
fscanf(0, "%19s %29s %9s", buf20, buf30, buf10);
+ // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
}
diff --git a/clang/test/Sema/warn-fortify-source.c b/clang/test/Sema/warn-fortify-source.c
index 216878c..750bd53 100644
--- a/clang/test/Sema/warn-fortify-source.c
+++ b/clang/test/Sema/warn-fortify-source.c
@@ -76,6 +76,14 @@ void call_strcpy_nowarn(void) {
__builtin_strcpy(dst, src);
}
+void call_strcat(void) {
+ const char *const src = "abcd";
+ char dst1[5];
+ char dst2[4];
+ __builtin_strcat(dst1, src);
+ __builtin_strcat(dst2, src); // expected-warning {{'strcat' will always overflow; destination buffer has size 4, but the source string has length 5 (including NUL byte)}}
+}
+
void call_stpcpy(void) {
const char *const src = "abcd";
char dst1[5];
diff --git a/clang/test/Sema/warn-lifetime-safety-dataflow.cpp b/clang/test/Sema/warn-lifetime-safety-dataflow.cpp
index 31148b9..7b6fc92 100644
--- a/clang/test/Sema/warn-lifetime-safety-dataflow.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-dataflow.cpp
@@ -18,8 +18,8 @@ MyObj* return_local_addr() {
return p;
// CHECK: Use ([[O_P]] (Decl: p), Read)
// CHECK: OriginFlow (Dest: [[O_RET_VAL:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_P]] (Decl: p))
-// CHECK: ReturnOfOrigin ([[O_RET_VAL]] (Expr: ImplicitCastExpr))
// CHECK: Expire ([[L_X]] (Path: x))
+// CHECK: OriginEscapes ([[O_RET_VAL]] (Expr: ImplicitCastExpr))
}
@@ -49,8 +49,8 @@ MyObj* assign_and_return_local_addr() {
return ptr2;
// CHECK: Use ([[O_PTR2]] (Decl: ptr2), Read)
// CHECK: OriginFlow (Dest: [[O_RET_VAL:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_PTR2]] (Decl: ptr2))
-// CHECK: ReturnOfOrigin ([[O_RET_VAL]] (Expr: ImplicitCastExpr))
// CHECK: Expire ([[L_Y]] (Path: y))
+// CHECK: OriginEscapes ([[O_RET_VAL]] (Expr: ImplicitCastExpr))
}
// Return of Non-Pointer Type
@@ -59,6 +59,7 @@ int return_int_val() {
int x = 10;
// CHECK: Block B{{[0-9]+}}:
// CHECK: Issue ([[L_X:[0-9]+]] (Path: x), ToOrigin: {{[0-9]+}} (Expr: DeclRefExpr))
+// CHECK: Expire ([[L_X:[0-9]+]] (Path: x))
return x;
}
// CHECK-NEXT: End of Block
@@ -77,7 +78,6 @@ void loan_expires_cpp() {
}
-// FIXME: No expire for Trivial Destructors
// CHECK-LABEL: Function: loan_expires_trivial
void loan_expires_trivial() {
int trivial_obj = 1;
@@ -86,11 +86,29 @@ void loan_expires_trivial() {
// CHECK: OriginFlow (Dest: [[O_ADDR_TRIVIAL_OBJ:[0-9]+]] (Expr: UnaryOperator), Src: [[O_DRE_TRIVIAL]] (Expr: DeclRefExpr))
int* pTrivialObj = &trivial_obj;
// CHECK: OriginFlow (Dest: {{[0-9]+}} (Decl: pTrivialObj), Src: [[O_ADDR_TRIVIAL_OBJ]] (Expr: UnaryOperator))
-// CHECK-NOT: Expire
+// CHECK: Expire ([[L_TRIVIAL_OBJ:[0-9]+]] (Path: trivial_obj))
// CHECK-NEXT: End of Block
- // FIXME: Add check for Expire once trivial destructors are handled for expiration.
}
+// Trivial Destructors
+// CHECK-LABEL: Function: return_int_pointer
+int* return_int_pointer() {
+ int* ptr;
+// CHECK: Block B{{[0-9]+}}:
+ int x = 1;
+// CHECK: Issue ([[L_X:[0-9]+]] (Path: x), ToOrigin: [[O_DRE_X:[0-9]+]] (Expr: DeclRefExpr))
+// CHECK: OriginFlow (Dest: [[O_ADDR_X:[0-9]+]] (Expr: UnaryOperator), Src: [[O_DRE_X]] (Expr: DeclRefExpr))
+ ptr = &x;
+// CHECK: Use ([[O_PTR:[0-9]+]] (Decl: ptr), Write)
+// CHECK: OriginFlow (Dest: [[O_PTR]] (Decl: ptr), Src: [[O_ADDR_X]] (Expr: UnaryOperator))
+// CHECK: Use ([[O_PTR]] (Decl: ptr), Read)
+// CHECK: OriginFlow (Dest: [[O_RET_VAL:[0-9]+]] (Expr: ImplicitCastExpr), Src: [[O_PTR]] (Decl: ptr))
+// CHECK: Expire ([[L_X]] (Path: x))
+// CHECK: OriginEscapes ([[O_RET_VAL]] (Expr: ImplicitCastExpr))
+ return ptr;
+}
+// CHECK-NEXT: End of Block
+
// CHECK-LABEL: Function: conditional
void conditional(bool condition) {
int a = 5;
@@ -414,3 +432,20 @@ void test_use_lifetimebound_call() {
// CHECK: Expire ([[L_Y]] (Path: y))
// CHECK: Expire ([[L_X]] (Path: x))
}
+// CHECK-LABEL: Function: test_conditional_operator
+void test_conditional_operator(bool cond) {
+ MyObj x, y;
+ MyObj *p = cond ? &x : &y;
+// CHECK: Block B{{[0-9]+}}:
+// CHECK: Issue ([[L_X:[0-9]+]] (Path: x), ToOrigin: [[O_DRE_X:[0-9]+]] (Expr: DeclRefExpr))
+// CHECK: OriginFlow (Dest: [[O_ADDR_X:[0-9]+]] (Expr: UnaryOperator), Src: [[O_DRE_X]] (Expr: DeclRefExpr))
+// CHECK: Block B{{[0-9]+}}:
+// CHECK: Issue ([[L_Y:[0-9]+]] (Path: y), ToOrigin: [[O_DRE_Y:[0-9]+]] (Expr: DeclRefExpr))
+// CHECK: OriginFlow (Dest: [[O_ADDR_Y:[0-9]+]] (Expr: UnaryOperator), Src: [[O_DRE_Y]] (Expr: DeclRefExpr))
+// CHECK: Block B{{[0-9]+}}:
+// CHECK: OriginFlow (Dest: [[O_COND_OP:[0-9]+]] (Expr: ConditionalOperator), Src: [[O_ADDR_X]] (Expr: UnaryOperator))
+// CHECK: OriginFlow (Dest: [[O_COND_OP]] (Expr: ConditionalOperator), Src: [[O_ADDR_Y]] (Expr: UnaryOperator), Merge)
+// CHECK: OriginFlow (Dest: [[O_P:[0-9]+]] (Decl: p), Src: [[O_COND_OP]] (Expr: ConditionalOperator))
+// CHECK: Expire ([[L_Y]] (Path: y))
+// CHECK: Expire ([[L_X]] (Path: x))
+}
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
new file mode 100644
index 0000000..c0f675a
--- /dev/null
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -0,0 +1,109 @@
+// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety-suggestions -verify %s
+
+struct MyObj {
+ int id;
+ ~MyObj() {} // Non-trivial destructor
+ MyObj operator+(MyObj);
+};
+
+struct [[gsl::Pointer()]] View {
+ View(const MyObj&); // Borrows from MyObj
+ View();
+ void use() const;
+};
+
+View return_view_directly (View a) { // expected-warning {{param should be marked [[clang::lifetimebound]]}}.
+ return a; // expected-note {{param returned here}}
+}
+
+View conditional_return_view (
+ View a, // expected-warning {{param should be marked [[clang::lifetimebound]]}}.
+ View b, // expected-warning {{param should be marked [[clang::lifetimebound]]}}.
+ bool c) {
+ View res;
+ if (c)
+ res = a;
+ else
+ res = b;
+ return res; // expected-note 2 {{param returned here}}
+}
+
+// FIXME: Fails to generate lifetime suggestion for reference types as these are not handled currently.
+MyObj& return_reference (MyObj& a, MyObj& b, bool c) {
+ if(c) {
+ return a;
+ }
+ return b;
+}
+
+// FIXME: Fails to generate lifetime suggestion for reference types as these are not handled currently.
+View return_view_from_reference (MyObj& p) {
+ return p;
+}
+
+int* return_pointer_directly (int* a) { // expected-warning {{param should be marked [[clang::lifetimebound]]}}.
+ return a; // expected-note {{param returned here}}
+}
+
+MyObj* return_pointer_object (MyObj* a) { // expected-warning {{param should be marked [[clang::lifetimebound]]}}.
+ return a; // expected-note {{param returned here}}
+}
+
+View only_one_paramter_annotated (View a [[clang::lifetimebound]],
+ View b, // expected-warning {{param should be marked [[clang::lifetimebound]]}}.
+ bool c) {
+ if(c)
+ return a;
+ return b; // expected-note {{param returned here}}
+}
+
+View reassigned_to_another_parameter (
+ View a,
+ View b) { // expected-warning {{param should be marked [[clang::lifetimebound]]}}.
+ a = b;
+ return a; // expected-note {{param returned here}}
+}
+
+struct ReturnsSelf {
+ const ReturnsSelf& get() const {
+ return *this;
+ }
+};
+
+struct ViewProvider {
+ MyObj data;
+ View getView() const {
+ return data;
+ }
+};
+
+// FIXME: Fails to generate lifetime suggestions for the implicit 'this' parameter, as this feature is not yet implemented.
+void test_get_on_temporary() {
+ const ReturnsSelf& s_ref = ReturnsSelf().get();
+ (void)s_ref;
+}
+
+// FIXME: Fails to generate lifetime suggestions for the implicit 'this' parameter, as this feature is not yet implemented.
+void test_getView_on_temporary() {
+ View sv = ViewProvider{1}.getView();
+ (void)sv;
+}
+
+//===----------------------------------------------------------------------===//
+// Negative Test Cases
+//===----------------------------------------------------------------------===//
+
+View already_annotated(View a [[clang::lifetimebound]]) {
+ return a;
+}
+
+MyObj return_obj_by_value(MyObj& p) {
+ return p;
+}
+
+MyObj GlobalMyObj;
+View Global = GlobalMyObj;
+View Reassigned(View a) {
+ a = Global;
+ return a;
+}
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 4f234f0..1191469e 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety -Wno-dangling -verify %s
struct MyObj {
int id;
@@ -12,6 +12,10 @@ struct [[gsl::Pointer()]] View {
void use() const;
};
+class TriviallyDestructedClass {
+ View a, b;
+};
+
//===----------------------------------------------------------------------===//
// Basic Definite Use-After-Free (-W...permissive)
// These are cases where the pointer is guaranteed to be dangling at the use site.
@@ -396,6 +400,186 @@ void loan_from_previous_iteration(MyObj safe, bool condition) {
} // expected-note {{destroyed here}}
}
+void trivial_int_uaf() {
+ int * a;
+ {
+ int b = 1;
+ a = &b; // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)*a; // expected-note {{later used here}}
+}
+
+void trivial_class_uaf() {
+ TriviallyDestructedClass* ptr;
+ {
+ TriviallyDestructedClass s;
+ ptr = &s; // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
+}
+
+//===----------------------------------------------------------------------===//
+// Basic Definite Use-After-Return (Return-Stack-Address) (-W...permissive)
+// These are cases where the pointer is guaranteed to be dangling at the use site.
+//===----------------------------------------------------------------------===//
+
+MyObj* simple_return_stack_address() {
+ MyObj s;
+ MyObj* p = &s; // expected-warning {{address of stack memory is returned later}}
+ return p; // expected-note {{returned here}}
+}
+
+MyObj* direct_return() {
+ MyObj s;
+ return &s; // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+}
+
+const MyObj* conditional_assign_unconditional_return(const MyObj& safe, bool c) {
+ MyObj s;
+ const MyObj* p = &safe;
+ if (c) {
+ p = &s; // expected-warning {{address of stack memory is returned later}}
+ }
+ return p; // expected-note {{returned here}}
+}
+
+View conditional_assign_both_branches(const MyObj& safe, bool c) {
+ MyObj s;
+ View p;
+ if (c) {
+ p = s; // expected-warning {{address of stack memory is returned later}}
+ }
+ else {
+ p = safe;
+ }
+ return p; // expected-note {{returned here}}
+
+}
+
+View reassign_safe_to_local(const MyObj& safe) {
+ MyObj local;
+ View p = safe;
+ p = local; // expected-warning {{address of stack memory is returned later}}
+ return p; // expected-note {{returned here}}
+}
+
+View pointer_chain_to_local() {
+ MyObj local;
+ View p1 = local; // expected-warning {{address of stack memory is returned later}}
+ View p2 = p1;
+ return p2; // expected-note {{returned here}}
+}
+
+View multiple_assign_multiple_return(const MyObj& safe, bool c1, bool c2) {
+ MyObj local1;
+ MyObj local2;
+ View p;
+ if (c1) {
+ p = local1; // expected-warning {{address of stack memory is returned later}}
+ return p; // expected-note {{returned here}}
+ }
+ else if (c2) {
+ p = local2; // expected-warning {{address of stack memory is returned later}}
+ return p; // expected-note {{returned here}}
+ }
+ p = safe;
+ return p;
+}
+
+View multiple_assign_single_return(const MyObj& safe, bool c1, bool c2) {
+ MyObj local1;
+ MyObj local2;
+ View p;
+ if (c1) {
+ p = local1; // expected-warning {{address of stack memory is returned later}}
+ }
+ else if (c2) {
+ p = local2; // expected-warning {{address of stack memory is returned later}}
+ }
+ else {
+ p = safe;
+ }
+ return p; // expected-note 2 {{returned here}}
+}
+
+View direct_return_of_local() {
+ MyObj stack;
+ return stack; // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+}
+
+MyObj& reference_return_of_local() {
+ MyObj stack;
+ return stack; // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+}
+
+int* trivial_int_uar() {
+ int *a;
+ int b = 1;
+ a = &b; // expected-warning {{address of stack memory is returned later}}
+ return a; // expected-note {{returned here}}
+}
+
+TriviallyDestructedClass* trivial_class_uar () {
+ TriviallyDestructedClass *ptr;
+ TriviallyDestructedClass s;
+ ptr = &s; // expected-warning {{address of stack memory is returned later}}
+ return ptr; // expected-note {{returned here}}
+}
+
+const int& return_parameter(int a) {
+ return a; // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+}
+
+int* return_pointer_to_parameter(int a) {
+ return &a; // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+}
+
+const int& return_reference_to_parameter(int a)
+{
+ const int &b = a;
+ return b; // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+}
+
+const int& get_ref_to_local() {
+ int a = 42;
+ return a; // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+}
+
+//===----------------------------------------------------------------------===//
+// Use-After-Scope & Use-After-Return (Return-Stack-Address) Combined
+// These are cases where the diagnostic kind is determined by location
+//===----------------------------------------------------------------------===//
+
+MyObj* uaf_before_uar() {
+ MyObj* p;
+ {
+ MyObj local_obj;
+ p = &local_obj; // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ return p; // expected-note {{later used here}}
+}
+
+View uar_before_uaf(const MyObj& safe, bool c) {
+ View p;
+ {
+ MyObj local_obj;
+ p = local_obj; // expected-warning {{address of stack memory is returned later}}
+ if (c) {
+ return p; // expected-note {{returned here}}
+ }
+ }
+ p.use();
+ p = safe;
+ return p;
+}
+
//===----------------------------------------------------------------------===//
// No-Error Cases
//===----------------------------------------------------------------------===//
@@ -434,12 +618,20 @@ void no_error_loan_from_current_iteration(bool cond) {
}
}
+View safe_return(const MyObj& safe) {
+ MyObj local;
+ View p = local;
+ p = safe; // p has been reassigned
+ return p; // This is safe
+}
//===----------------------------------------------------------------------===//
// Lifetimebound Attribute Tests
//===----------------------------------------------------------------------===//
View Identity(View v [[clang::lifetimebound]]);
+const MyObj& IdentityRef(const MyObj& obj [[clang::lifetimebound]]);
+MyObj* Identity(MyObj* v [[clang::lifetimebound]]);
View Choose(bool cond, View a [[clang::lifetimebound]], View b [[clang::lifetimebound]]);
MyObj* GetPointer(const MyObj& obj [[clang::lifetimebound]]);
@@ -555,7 +747,8 @@ void lifetimebound_partial_safety(bool cond) {
v.use(); // expected-note {{later used here}}
}
-// FIXME: Creating reference from lifetimebound call doesn't propagate loans.
+// FIXME: Warning should be on the 'GetObject' call, not the assignment to 'ptr'.
+// The loan from the lifetimebound argument is not propagated to the call expression itself.
const MyObj& GetObject(View v [[clang::lifetimebound]]);
void lifetimebound_return_reference() {
View v;
@@ -564,9 +757,9 @@ void lifetimebound_return_reference() {
MyObj obj;
View temp_v = obj;
const MyObj& ref = GetObject(temp_v);
- ptr = &ref;
- }
- (void)*ptr;
+ ptr = &ref; // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)*ptr; // expected-note {{later used here}}
}
// FIXME: No warning for non gsl::Pointer types. Origin tracking is only supported for pointer types.
@@ -582,3 +775,171 @@ void lifetimebound_ctor() {
}
(void)v;
}
+
+View lifetimebound_return_of_local() {
+ MyObj stack;
+ return Identity(stack); // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+}
+
+const MyObj& lifetimebound_return_ref_to_local() {
+ MyObj stack;
+ return IdentityRef(stack); // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+}
+
+View lifetimebound_return_by_value_param(MyObj stack_param) {
+ return Identity(stack_param); // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+}
+
+View lifetimebound_return_by_value_multiple_param(int cond, MyObj a, MyObj b, MyObj c) {
+ if (cond == 1)
+ return Identity(a); // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+ if (cond == 2)
+ return Identity(b); // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+ return Identity(c); // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+}
+
+template<class T>
+View lifetimebound_return_by_value_param_template(T t) {
+ return Identity(t); // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+}
+void use_lifetimebound_return_by_value_param_template() {
+ lifetimebound_return_by_value_param_template(MyObj{}); // expected-note {{in instantiation of}}
+}
+
+void lambda_uar_param() {
+ auto lambda = [](MyObj stack_param) {
+ return Identity(stack_param); // expected-warning {{address of stack memory is returned later}}
+ // expected-note@-1 {{returned here}}
+ };
+ lambda(MyObj{});
+}
+
+// FIXME: This should be detected. We see correct destructors but origin flow breaks somewhere.
+namespace VariadicTemplatedParamsUAR{
+
+template<typename... Args>
+View Max(Args... args [[clang::lifetimebound]]);
+
+template<typename... Args>
+View lifetimebound_return_of_variadic_param(Args... args) {
+ return Max(args...);
+}
+void test_variadic() {
+ lifetimebound_return_of_variadic_param(MyObj{1}, MyObj{2}, MyObj{3});
+}
+}
+
+// FIXME: Fails to diagnose UAF when a reference to a by-value param escapes via an out-param.
+void uaf_from_by_value_param_failing(MyObj param, View* out_p) {
+ *out_p = Identity(param);
+}
+
+// Conditional operator.
+void conditional_operator_one_unsafe_branch(bool cond) {
+ MyObj safe;
+ MyObj* p = &safe;
+ {
+ MyObj temp;
+ p = cond ? &temp // expected-warning {{object whose reference is captured may not live long enough}}
+ : &safe;
+ } // expected-note {{destroyed here}}
+
+ // This is not a use-after-free for any value of `cond` but the analysis
+ // cannot reason this and marks the above as a false positive. This
+ // ensures safety regardless of cond's value.
+ if (cond)
+ p = &safe;
+ (void)*p; // expected-note {{later used here}}
+}
+
+void conditional_operator_two_unsafe_branches(bool cond) {
+ MyObj* p;
+ {
+ MyObj a, b;
+ p = cond ? &a // expected-warning {{object whose reference is captured does not live long enough}}
+ : &b; // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note 2 {{destroyed here}}
+ (void)*p; // expected-note 2 {{later used here}}
+}
+
+void conditional_operator_nested(bool cond) {
+ MyObj* p;
+ {
+ MyObj a, b, c, d;
+ p = cond ? cond ? &a // expected-warning {{object whose reference is captured does not live long enough}}.
+ : &b // expected-warning {{object whose reference is captured does not live long enough}}.
+ : cond ? &c // expected-warning {{object whose reference is captured does not live long enough}}.
+ : &d; // expected-warning {{object whose reference is captured does not live long enough}}.
+ } // expected-note 4 {{destroyed here}}
+ (void)*p; // expected-note 4 {{later used here}}
+}
+
+void conditional_operator_lifetimebound(bool cond) {
+ MyObj* p;
+ {
+ MyObj a, b;
+ p = Identity(cond ? &a // expected-warning {{object whose reference is captured does not live long enough}}
+ : &b); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note 2 {{destroyed here}}
+ (void)*p; // expected-note 2 {{later used here}}
+}
+
+void conditional_operator_lifetimebound_nested(bool cond) {
+ MyObj* p;
+ {
+ MyObj a, b;
+ p = Identity(cond ? Identity(&a) // expected-warning {{object whose reference is captured does not live long enough}}
+ : Identity(&b)); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note 2 {{destroyed here}}
+ (void)*p; // expected-note 2 {{later used here}}
+}
+
+void conditional_operator_lifetimebound_nested_deep(bool cond) {
+ MyObj* p;
+ {
+ MyObj a, b, c, d;
+ p = Identity(cond ? Identity(cond ? &a // expected-warning {{object whose reference is captured does not live long enough}}
+ : &b) // expected-warning {{object whose reference is captured does not live long enough}}
+ : Identity(cond ? &c // expected-warning {{object whose reference is captured does not live long enough}}
+ : &d)); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note 4 {{destroyed here}}
+ (void)*p; // expected-note 4 {{later used here}}
+}
+
+void parentheses(bool cond) {
+ MyObj* p;
+ {
+ MyObj a;
+ p = &((((a)))); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)*p; // expected-note {{later used here}}
+
+ {
+ MyObj a;
+ p = ((GetPointer((a)))); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)*p; // expected-note {{later used here}}
+
+ {
+ MyObj a, b, c, d;
+ p = &(cond ? (cond ? a // expected-warning {{object whose reference is captured does not live long enough}}.
+ : b) // expected-warning {{object whose reference is captured does not live long enough}}.
+ : (cond ? c // expected-warning {{object whose reference is captured does not live long enough}}.
+ : d)); // expected-warning {{object whose reference is captured does not live long enough}}.
+ } // expected-note 4 {{destroyed here}}
+ (void)*p; // expected-note 4 {{later used here}}
+
+ {
+ MyObj a, b, c, d;
+ p = ((cond ? (((cond ? &a : &b))) // expected-warning 2 {{object whose reference is captured does not live long enough}}.
+ : &(((cond ? c : d))))); // expected-warning 2 {{object whose reference is captured does not live long enough}}.
+ } // expected-note 4 {{destroyed here}}
+ (void)*p; // expected-note 4 {{later used here}}
+}
diff --git a/clang/test/Sema/warn-unreachable-file-scope.c b/clang/test/Sema/warn-unreachable-file-scope.c
new file mode 100644
index 0000000..64a6918
--- /dev/null
+++ b/clang/test/Sema/warn-unreachable-file-scope.c
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef unsigned char u8;
+
+u8 a1 = (0 ? 0xffff : 0xff);
+u8 a2 = (1 ? 0xffff : 0xff); // expected-warning {{implicit conversion from 'int' to 'u8' (aka 'unsigned char') changes value from 65535 to 255}}
+u8 a3 = (1 ? 0xff : 0xffff);
+u8 a4 = (0 ? 0xff : 0xffff); // expected-warning {{implicit conversion from 'int' to 'u8' (aka 'unsigned char') changes value from 65535 to 255}}
+
+unsigned long long b1 = 1 ? 0 : 1ULL << 64;
+unsigned long long b2 = 0 ? 0 : 1ULL << 64; // expected-warning {{shift count >= width of type}}
+unsigned long long b3 = 1 ? 1ULL << 64 : 0; // expected-warning {{shift count >= width of type}}
+
+#define M(n) (((n) == 64) ? ~0ULL : ((1ULL << (n)) - 1))
+unsigned long long c1 = M(64);
+unsigned long long c2 = M(32);
+
+static u8 d1 = (0 ? 0xffff : 0xff);
+static u8 d2 = (1 ? 0xffff : 0xff); // expected-warning {{implicit conversion from 'int' to 'u8' (aka 'unsigned char') changes value from 65535 to 255}}
+
+int a = 1 ? 6 : (1,2);
+int b = 0 ? 6 : (1,2); // expected-warning {{left operand of comma operator has no effect}}
+
+void f(void) {
+ u8 e1 = (0 ? 0xffff : 0xff);
+ u8 e2 = (1 ? 0xffff : 0xff); // expected-warning {{implicit conversion from 'int' to 'u8' (aka 'unsigned char') changes value from 65535 to 255}}
+
+ unsigned long long e3 = 1 ? 0 : 1ULL << 64;
+ unsigned long long e4 = 0 ? 0 : 1ULL << 64; // expected-warning {{shift count >= width of type}}
+}
+
+void statics(void) {
+ static u8 f1 = (0 ? 0xffff : 0xff);
+ static u8 f2 = (1 ? 0xffff : 0xff); // expected-warning {{implicit conversion from 'int' to 'u8' (aka 'unsigned char') changes value from 65535 to 255}}
+ static u8 f3 = (1 ? 0xff : 0xffff);
+ static u8 f4 = (0 ? 0xff : 0xffff); // expected-warning {{implicit conversion from 'int' to 'u8' (aka 'unsigned char') changes value from 65535 to 255}}
+}