2009-12-15 20:14:24 +00:00
//RUN: %clang_cc1 -fsyntax-only -verify %s
2008-03-07 18:43:49 +00:00
# include <stdarg.h>
Allow non-variadic functions to be attributed with `__attribute__((format))`
Clang only allows you to use __attribute__((format)) on variadic functions. There are legit use cases for __attribute__((format)) on non-variadic functions, such as:
(1) variadic templates
```c++
template<typename… Args>
void print(const char *fmt, Args… &&args) __attribute__((format(1, 2))); // error: format attribute requires variadic function
```
(2) functions which take fixed arguments and a custom format:
```c++
void print_number_string(const char *fmt, unsigned number, const char *string) __attribute__((format(1, 2)));
// ^error: format attribute requires variadic function
void foo(void) {
print_number_string(“%08x %s\n”, 0xdeadbeef, “hello”);
print_number_string(“%d %s”, 0xcafebabe, “bar”);
}
```
This change allows Clang users to attach __attribute__((format)) to non-variadic functions, including functions with C++ variadic templates. It replaces the error with a GCC compatibility warning and improves the type checker to ensure that received arrays are treated like pointers (this is a possibility in C++ since references to template types can bind to arrays).
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D112579
rdar://84629099
2022-06-07 15:45:07 -07:00
void a ( const char * a , . . . ) __attribute__ ( ( format ( printf , 1 , 2 ) ) ) ; // no-error
void b ( const char * a , . . . ) __attribute__ ( ( format ( printf , 1 , 1 ) ) ) ; // expected-error {{'format' attribute parameter 3 is out of bounds}}
void c ( const char * a , . . . ) __attribute__ ( ( format ( printf , 0 , 2 ) ) ) ; // expected-error {{'format' attribute parameter 2 is out of bounds}}
void d ( const char * a , int c ) __attribute__ ( ( format ( printf , 1 , 2 ) ) ) ; // expected-warning {{GCC requires a function with the 'format' attribute to be variadic}}
void e ( char * str , int c , . . . ) __attribute__ ( ( format ( printf , 2 , 3 ) ) ) ; // expected-error {{format argument not a string type}}
[Clang][Sema] Fix attribute((format)) bug on non-variadic functions
The [initial implementation][1] of __attribute__((format)) on non-variadic functions
accidentally only accepted one data argument. This worked:
```c
__attribute__((format(printf, 1, 2)))
void f(const char *, int);
```
but this didn't:
```c
__attribute__((format(printf, 1, 2)))
void f(const char *, int, int);
```
This is due to an oversight in changing the way diagnostics are emitted for
`attribute((format))`, and to a coincidence in the handling of the variadic case. Test
cases only covered the case that worked by coincidence.
Before the previous change, using `__attribute__((format))` on a non-variadic function at
all was an error and clang bailed out. After that change, it only generates a GCC
compatibility warning. However, as execution falls through, it hits a second diagnostic
when the first data argument is neither 0 nor the last parameter of the function.
This change updates that check to allow any parameter after the format string to be the
first data argument when the function is non-variadic. When the function is variadic, it
still needs to be the index of the `...` "parameter". Attribute documentation is updated
to reflect the change and new tests are added to verify that it works with _two_ data
parameters.
[1]: https://reviews.llvm.org/D112579
Radar-Id: rdar://102069446
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D137603
2022-12-06 13:00:12 -08:00
void f ( int a , const char * b , . . . ) __attribute__ ( ( format ( printf , 2 , 1 ) ) ) ; // expected-error {{'format' attribute parameter 3 is out of bounds}}
void g ( int a , const char * b , . . . ) __attribute__ ( ( format ( printf , 2 , 2 ) ) ) ; // expected-error {{'format' attribute parameter 3 is out of bounds}}
void h ( int a , const char * b , . . . ) __attribute__ ( ( format ( printf , 2 , 3 ) ) ) ; // no-error
void i ( const char * a , int b , . . . ) __attribute__ ( ( format ( printf , 1 , 2 ) ) ) ; // expected-error {{'format' attribute parameter 3 is out of bounds}}
2008-03-07 18:43:49 +00:00
Allow non-variadic functions to be attributed with `__attribute__((format))`
Clang only allows you to use __attribute__((format)) on variadic functions. There are legit use cases for __attribute__((format)) on non-variadic functions, such as:
(1) variadic templates
```c++
template<typename… Args>
void print(const char *fmt, Args… &&args) __attribute__((format(1, 2))); // error: format attribute requires variadic function
```
(2) functions which take fixed arguments and a custom format:
```c++
void print_number_string(const char *fmt, unsigned number, const char *string) __attribute__((format(1, 2)));
// ^error: format attribute requires variadic function
void foo(void) {
print_number_string(“%08x %s\n”, 0xdeadbeef, “hello”);
print_number_string(“%d %s”, 0xcafebabe, “bar”);
}
```
This change allows Clang users to attach __attribute__((format)) to non-variadic functions, including functions with C++ variadic templates. It replaces the error with a GCC compatibility warning and improves the type checker to ensure that received arrays are treated like pointers (this is a possibility in C++ since references to template types can bind to arrays).
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D112579
rdar://84629099
2022-06-07 15:45:07 -07:00
typedef const char * xpto ;
[Clang][Sema] Fix attribute((format)) bug on non-variadic functions
The [initial implementation][1] of __attribute__((format)) on non-variadic functions
accidentally only accepted one data argument. This worked:
```c
__attribute__((format(printf, 1, 2)))
void f(const char *, int);
```
but this didn't:
```c
__attribute__((format(printf, 1, 2)))
void f(const char *, int, int);
```
This is due to an oversight in changing the way diagnostics are emitted for
`attribute((format))`, and to a coincidence in the handling of the variadic case. Test
cases only covered the case that worked by coincidence.
Before the previous change, using `__attribute__((format))` on a non-variadic function at
all was an error and clang bailed out. After that change, it only generates a GCC
compatibility warning. However, as execution falls through, it hits a second diagnostic
when the first data argument is neither 0 nor the last parameter of the function.
This change updates that check to allow any parameter after the format string to be the
first data argument when the function is non-variadic. When the function is variadic, it
still needs to be the index of the `...` "parameter". Attribute documentation is updated
to reflect the change and new tests are added to verify that it works with _two_ data
parameters.
[1]: https://reviews.llvm.org/D112579
Radar-Id: rdar://102069446
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D137603
2022-12-06 13:00:12 -08:00
void j ( xpto c , va_list list ) __attribute__ ( ( format ( printf , 1 , 0 ) ) ) ; // no-error
void k ( xpto c ) __attribute__ ( ( format ( printf , 1 , 0 ) ) ) ; // no-error
2008-03-07 18:43:49 +00:00
Allow non-variadic functions to be attributed with `__attribute__((format))`
Clang only allows you to use __attribute__((format)) on variadic functions. There are legit use cases for __attribute__((format)) on non-variadic functions, such as:
(1) variadic templates
```c++
template<typename… Args>
void print(const char *fmt, Args… &&args) __attribute__((format(1, 2))); // error: format attribute requires variadic function
```
(2) functions which take fixed arguments and a custom format:
```c++
void print_number_string(const char *fmt, unsigned number, const char *string) __attribute__((format(1, 2)));
// ^error: format attribute requires variadic function
void foo(void) {
print_number_string(“%08x %s\n”, 0xdeadbeef, “hello”);
print_number_string(“%d %s”, 0xcafebabe, “bar”);
}
```
This change allows Clang users to attach __attribute__((format)) to non-variadic functions, including functions with C++ variadic templates. It replaces the error with a GCC compatibility warning and improves the type checker to ensure that received arrays are treated like pointers (this is a possibility in C++ since references to template types can bind to arrays).
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D112579
rdar://84629099
2022-06-07 15:45:07 -07:00
void y ( char * str ) __attribute__ ( ( format ( strftime , 1 , 0 ) ) ) ; // no-error
void z ( char * str , int c , . . . ) __attribute__ ( ( format ( strftime , 1 , 2 ) ) ) ; // expected-error {{strftime format attribute requires 3rd parameter to be 0}}
2008-03-25 23:01:48 +00:00
int ( * f_ptr ) ( char * , . . . ) __attribute__ ( ( format ( printf , 1 , 2 ) ) ) ; // no-error
int ( * f2_ptr ) ( double , . . . ) __attribute__ ( ( format ( printf , 1 , 2 ) ) ) ; // expected-error {{format argument not a string type}}
2008-04-18 22:43:39 +00:00
struct _mystruct {
int ( * printf ) ( const char * format , . . . ) __attribute__ ( ( __format__ ( printf , 1 , 2 ) ) ) ; // no-error
int ( * printf2 ) ( double format , . . . ) __attribute__ ( ( __format__ ( printf , 1 , 2 ) ) ) ; // expected-error {{format argument not a string type}}
} ;
2008-05-09 17:36:24 +00:00
typedef int ( * f3_ptr ) ( char * , . . . ) __attribute__ ( ( format ( printf , 1 , 0 ) ) ) ; // no-error
2009-02-27 17:58:43 +00:00
int rdar6623513 ( void * , const char * , const char * , . . . )
__attribute__ ( ( format ( printf , 3 , 0 ) ) ) ;
int rdar6623513_aux ( int len , const char * s ) {
rdar6623513 ( 0 , " hello " , " %.*s " , len , s ) ;
}
2010-03-22 21:05:15 +00:00
// same as format(printf(...))...
Allow non-variadic functions to be attributed with `__attribute__((format))`
Clang only allows you to use __attribute__((format)) on variadic functions. There are legit use cases for __attribute__((format)) on non-variadic functions, such as:
(1) variadic templates
```c++
template<typename… Args>
void print(const char *fmt, Args… &&args) __attribute__((format(1, 2))); // error: format attribute requires variadic function
```
(2) functions which take fixed arguments and a custom format:
```c++
void print_number_string(const char *fmt, unsigned number, const char *string) __attribute__((format(1, 2)));
// ^error: format attribute requires variadic function
void foo(void) {
print_number_string(“%08x %s\n”, 0xdeadbeef, “hello”);
print_number_string(“%d %s”, 0xcafebabe, “bar”);
}
```
This change allows Clang users to attach __attribute__((format)) to non-variadic functions, including functions with C++ variadic templates. It replaces the error with a GCC compatibility warning and improves the type checker to ensure that received arrays are treated like pointers (this is a possibility in C++ since references to template types can bind to arrays).
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D112579
rdar://84629099
2022-06-07 15:45:07 -07:00
void a2 ( const char * a , . . . ) __attribute__ ( ( format ( printf0 , 1 , 2 ) ) ) ; // no-error
void b2 ( const char * a , . . . ) __attribute__ ( ( format ( printf0 , 1 , 1 ) ) ) ; // expected-error {{'format' attribute parameter 3 is out of bounds}}
void c2 ( const char * a , . . . ) __attribute__ ( ( format ( printf0 , 0 , 2 ) ) ) ; // expected-error {{'format' attribute parameter 2 is out of bounds}}
void d2 ( const char * a , int c ) __attribute__ ( ( format ( printf0 , 1 , 2 ) ) ) ; // expected-warning {{GCC requires a function with the 'format' attribute to be variadic}}
void e2 ( char * str , int c , . . . ) __attribute__ ( ( format ( printf0 , 2 , 3 ) ) ) ; // expected-error {{format argument not a string type}}
2010-03-22 21:05:15 +00:00
// FreeBSD usage
Allow non-variadic functions to be attributed with `__attribute__((format))`
Clang only allows you to use __attribute__((format)) on variadic functions. There are legit use cases for __attribute__((format)) on non-variadic functions, such as:
(1) variadic templates
```c++
template<typename… Args>
void print(const char *fmt, Args… &&args) __attribute__((format(1, 2))); // error: format attribute requires variadic function
```
(2) functions which take fixed arguments and a custom format:
```c++
void print_number_string(const char *fmt, unsigned number, const char *string) __attribute__((format(1, 2)));
// ^error: format attribute requires variadic function
void foo(void) {
print_number_string(“%08x %s\n”, 0xdeadbeef, “hello”);
print_number_string(“%d %s”, 0xcafebabe, “bar”);
}
```
This change allows Clang users to attach __attribute__((format)) to non-variadic functions, including functions with C++ variadic templates. It replaces the error with a GCC compatibility warning and improves the type checker to ensure that received arrays are treated like pointers (this is a possibility in C++ since references to template types can bind to arrays).
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D112579
rdar://84629099
2022-06-07 15:45:07 -07:00
# define __printf0like(fmt, va) __attribute__((__format__(__printf0__, fmt, va)))
void null ( int i , const char * a , . . . ) __printf0like ( 2 , 0 ) ; // no-error
void null ( int i , const char * a , . . . ) { // expected-note{{passing argument to parameter 'a' here}}
2010-03-22 21:05:15 +00:00
if ( a )
( void ) 0 /* vprintf(...) would go here */ ;
}
void callnull ( void ) {
null ( 0 , 0 ) ; // no error
null ( 0 , ( char * ) 0 ) ; // no error
null ( 0 , ( void * ) 0 ) ; // no error
null ( 0 , ( int * ) 0 ) ; // expected-warning {{incompatible pointer types}}
}
2015-02-19 22:32:33 +00:00
// FreeBSD kernel extensions
Allow non-variadic functions to be attributed with `__attribute__((format))`
Clang only allows you to use __attribute__((format)) on variadic functions. There are legit use cases for __attribute__((format)) on non-variadic functions, such as:
(1) variadic templates
```c++
template<typename… Args>
void print(const char *fmt, Args… &&args) __attribute__((format(1, 2))); // error: format attribute requires variadic function
```
(2) functions which take fixed arguments and a custom format:
```c++
void print_number_string(const char *fmt, unsigned number, const char *string) __attribute__((format(1, 2)));
// ^error: format attribute requires variadic function
void foo(void) {
print_number_string(“%08x %s\n”, 0xdeadbeef, “hello”);
print_number_string(“%d %s”, 0xcafebabe, “bar”);
}
```
This change allows Clang users to attach __attribute__((format)) to non-variadic functions, including functions with C++ variadic templates. It replaces the error with a GCC compatibility warning and improves the type checker to ensure that received arrays are treated like pointers (this is a possibility in C++ since references to template types can bind to arrays).
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D112579
rdar://84629099
2022-06-07 15:45:07 -07:00
void a3 ( const char * a , . . . ) __attribute__ ( ( format ( freebsd_kprintf , 1 , 2 ) ) ) ; // no-error
void b3 ( const char * a , . . . ) __attribute__ ( ( format ( freebsd_kprintf , 1 , 1 ) ) ) ; // expected-error {{'format' attribute parameter 3 is out of bounds}}
void c3 ( const char * a , . . . ) __attribute__ ( ( format ( freebsd_kprintf , 0 , 2 ) ) ) ; // expected-error {{'format' attribute parameter 2 is out of bounds}}
void d3 ( const char * a , int c ) __attribute__ ( ( format ( freebsd_kprintf , 1 , 2 ) ) ) ; // expected-warning {{GCC requires a function with the 'format' attribute to be variadic}}
void e3 ( char * str , int c , . . . ) __attribute__ ( ( format ( freebsd_kprintf , 2 , 3 ) ) ) ; // expected-error {{format argument not a string type}}
2010-03-22 21:05:15 +00:00
// PR4470
int xx_vprintf ( const char * , va_list ) ;
const char * foo ( const char * format ) __attribute__ ( ( format_arg ( 1 ) ) ) ;
void __attribute__ ( ( format ( printf , 1 , 0 ) ) )
foo2 ( const char * fmt , va_list va ) {
xx_vprintf ( foo ( fmt ) , va ) ;
}
2010-03-22 21:08:50 +00:00
// PR6542
Allow non-variadic functions to be attributed with `__attribute__((format))`
Clang only allows you to use __attribute__((format)) on variadic functions. There are legit use cases for __attribute__((format)) on non-variadic functions, such as:
(1) variadic templates
```c++
template<typename… Args>
void print(const char *fmt, Args… &&args) __attribute__((format(1, 2))); // error: format attribute requires variadic function
```
(2) functions which take fixed arguments and a custom format:
```c++
void print_number_string(const char *fmt, unsigned number, const char *string) __attribute__((format(1, 2)));
// ^error: format attribute requires variadic function
void foo(void) {
print_number_string(“%08x %s\n”, 0xdeadbeef, “hello”);
print_number_string(“%d %s”, 0xcafebabe, “bar”);
}
```
This change allows Clang users to attach __attribute__((format)) to non-variadic functions, including functions with C++ variadic templates. It replaces the error with a GCC compatibility warning and improves the type checker to ensure that received arrays are treated like pointers (this is a possibility in C++ since references to template types can bind to arrays).
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D112579
rdar://84629099
2022-06-07 15:45:07 -07:00
extern void gcc_format ( const char * , . . . )
__attribute__ ( ( __format__ ( __gcc_diag__ , 1 , 2 ) ) ) ;
extern void gcc_cformat ( const char * , . . . )
__attribute__ ( ( __format__ ( __gcc_cdiag__ , 1 , 2 ) ) ) ;
extern void gcc_cxxformat ( const char * , . . . )
__attribute__ ( ( __format__ ( __gcc_cxxdiag__ , 1 , 2 ) ) ) ;
extern void gcc_tformat ( const char * , . . . )
__attribute__ ( ( __format__ ( __gcc_tdiag__ , 1 , 2 ) ) ) ;
const char * foo3 ( const char * format ) __attribute__ ( ( format_arg ( " foo " ) ) ) ; // expected-error{{'format_arg' attribute requires parameter 1 to be an integer constant}}
void call_nonvariadic ( void ) {
d3 ( " %i " , 123 ) ;
d3 ( " %d " , 123 ) ;
d3 ( " %s " , 123 ) ; // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
}
[Sema] tolerate more promotion matches in format string checking
It's been reported that when using __attribute__((format)) on non-variadic
functions, certain values that normally get promoted when passed as variadic
arguments now unconditionally emit a diagnostic:
```c
void foo(const char *fmt, float f) __attribute__((format(printf, 1, 2)));
void bar(void) {
foo("%g", 123.f);
// ^ format specifies type 'double' but the argument has type 'float'
}
```
This is normally not an issue because float values get promoted to doubles when
passed as variadic arguments, but needless to say, variadic argument promotion
does not apply to non-variadic arguments.
While this can be fixed by adjusting the prototype of `foo`, this is sometimes
undesirable in C (for instance, if `foo` is ABI). In C++, using variadic
templates, this might instead require call-site fixing, which is tedious and
arguably needless work:
```c++
template<typename... Args>
void foo(const char *fmt, Args &&...args) __attribute__((format(printf, 1, 2)));
void bar(void) {
foo("%g", 123.f);
// ^ format specifies type 'double' but the argument has type 'float'
}
```
To address this issue, we teach FormatString about a few promotions that have
always been around but that have never been exercised in the direction that
FormatString checks for:
* `char`, `unsigned char` -> `int`, `unsigned`
* `half`, `float16`, `float` -> `double`
This addresses issue https://github.com/llvm/llvm-project/issues/59824.
2023-08-18 14:53:33 -07:00
__attribute__ ( ( format ( printf , 1 , 2 ) ) )
void forward_fixed ( const char * fmt , _Bool b , char i , short j , int k , float l , double m ) { // expected-warning{{GCC requires a function with the 'format' attribute to be variadic}}
forward_fixed ( fmt , b , i , j , k , l , m ) ;
a ( fmt , b , i , j , k , l , m ) ;
[Clang][Sema] Fix attribute((format)) bug on non-variadic functions
The [initial implementation][1] of __attribute__((format)) on non-variadic functions
accidentally only accepted one data argument. This worked:
```c
__attribute__((format(printf, 1, 2)))
void f(const char *, int);
```
but this didn't:
```c
__attribute__((format(printf, 1, 2)))
void f(const char *, int, int);
```
This is due to an oversight in changing the way diagnostics are emitted for
`attribute((format))`, and to a coincidence in the handling of the variadic case. Test
cases only covered the case that worked by coincidence.
Before the previous change, using `__attribute__((format))` on a non-variadic function at
all was an error and clang bailed out. After that change, it only generates a GCC
compatibility warning. However, as execution falls through, it hits a second diagnostic
when the first data argument is neither 0 nor the last parameter of the function.
This change updates that check to allow any parameter after the format string to be the
first data argument when the function is non-variadic. When the function is variadic, it
still needs to be the index of the `...` "parameter". Attribute documentation is updated
to reflect the change and new tests are added to verify that it works with _two_ data
parameters.
[1]: https://reviews.llvm.org/D112579
Radar-Id: rdar://102069446
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D137603
2022-12-06 13:00:12 -08:00
}
2024-07-25 18:57:14 -04:00
// OpenBSD
// same as format(printf(...))...
void a2 ( const char * a , . . . ) __attribute__ ( ( format ( syslog , 1 , 2 ) ) ) ; // no-error
void b2 ( const char * a , . . . ) __attribute__ ( ( format ( syslog , 1 , 1 ) ) ) ; // expected-error {{'format' attribute parameter 3 is out of bounds}}
void c2 ( const char * a , . . . ) __attribute__ ( ( format ( syslog , 0 , 2 ) ) ) ; // expected-error {{'format' attribute parameter 2 is out of bounds}}
void d2 ( const char * a , int c ) __attribute__ ( ( format ( syslog , 1 , 2 ) ) ) ; // expected-warning {{GCC requires a function with the 'format' attribute to be variadic}}
void e2 ( char * str , int c , . . . ) __attribute__ ( ( format ( syslog , 2 , 3 ) ) ) ; // expected-error {{format argument not a string type}}