2014-07-19 09:39:17 +08:00
// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -Wformat-non-iso -fblocks %s
2011-12-28 21:10:50 +08:00
2012-02-22 04:00:53 +08:00
# include <stdarg.h>
2011-12-28 21:10:50 +08:00
extern " C " {
extern int scanf ( const char * restrict , . . . ) ;
extern int printf ( const char * restrict , . . . ) ;
2012-02-22 04:00:53 +08:00
extern int vprintf ( const char * restrict , va_list ) ;
2011-12-28 21:10:50 +08:00
}
void f ( char * * sp , float * fp ) {
2012-03-09 18:10:54 +08:00
scanf ( " %as " , sp ) ; // expected-warning{{'a' length modifier is not supported by ISO C}}
2011-12-28 21:10:50 +08:00
// TODO: Warn that the 'a' conversion specifier is a C++11 feature.
printf ( " %a " , 1.0 ) ;
scanf ( " %afoobar " , fp ) ;
}
2012-01-31 22:59:59 +08:00
void g ( ) {
printf ( " %ls " , " foo " ) ; // expected-warning{{format specifies type 'wchar_t *' but the argument has type 'const char *'}}
}
2012-02-08 03:01:42 +08:00
// Test that we properly handle format_idx on C++ members.
class Foo {
public :
const char * gettext ( const char * fmt ) __attribute__ ( ( format_arg ( 2 ) ) ) ;
2012-02-22 04:00:53 +08:00
int scanf ( const char * , . . . ) __attribute__ ( ( format ( scanf , 2 , 3 ) ) ) ;
int printf ( const char * , . . . ) __attribute__ ( ( format ( printf , 2 , 3 ) ) ) ;
int printf2 ( const char * , . . . ) ;
2012-02-08 03:01:42 +08:00
static const char * gettext_static ( const char * fmt ) __attribute__ ( ( format_arg ( 1 ) ) ) ;
2012-02-22 04:00:53 +08:00
static int printf_static ( const char * fmt , . . . ) __attribute__ ( ( format ( printf , 1 , 2 ) ) ) ;
2012-02-08 03:01:42 +08:00
} ;
void h ( int * i ) {
Foo foo ;
foo . scanf ( " %d " ) ; // expected-warning{{more '%' conversions than data arguments}}
foo . printf ( " %d " , i ) ; // expected-warning{{format specifies type 'int' but the argument has type 'int *'}}
Foo : : printf_static ( " %d " , i ) ; // expected-warning{{format specifies type 'int' but the argument has type 'int *'}}
printf ( foo . gettext ( " %d " ) , i ) ; // expected-warning{{format specifies type 'int' but the argument has type 'int *'}}
printf ( Foo : : gettext_static ( " %d " ) , i ) ; // expected-warning{{format specifies type 'int' but the argument has type 'int *'}}
}
2012-02-11 03:13:51 +08:00
// Test handling __null for format string literal checking.
extern " C " {
int test_null_format ( const char * format , . . . ) __attribute__ ( ( __format__ ( __printf__ , 1 , 2 ) ) ) ;
}
void rdar8269537 ( const char * f )
{
2012-02-11 05:07:25 +08:00
test_null_format ( false ) ; // expected-warning {{null from a constant boolean}}
test_null_format ( 0 ) ; // no-warning
2012-02-11 03:13:51 +08:00
test_null_format ( __null ) ; // no-warning
test_null_format ( f ) ; // expected-warning {{not a string literal}}
2016-03-16 04:56:38 +08:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2012-02-11 03:13:51 +08:00
}
2012-02-22 04:00:53 +08:00
int Foo : : printf ( const char * fmt , . . . ) {
va_list ap ;
va_start ( ap , fmt ) ;
const char * const format = fmt ;
vprintf ( format , ap ) ; // no-warning
const char * format2 = fmt ;
vprintf ( format2 , ap ) ; // expected-warning{{format string is not a string literal}}
return 0 ;
}
int Foo : : printf2 ( const char * fmt , . . . ) {
va_list ap ;
va_start ( ap , fmt ) ;
vprintf ( fmt , ap ) ; // expected-warning{{format string is not a string literal}}
return 0 ;
}
2012-10-02 09:49:54 +08:00
namespace Templates {
template < typename T >
void my_uninstantiated_print ( const T & arg ) {
printf ( " %d " , arg ) ; // no-warning
}
template < typename T >
void my_print ( const T & arg ) {
printf ( " %d " , arg ) ; // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}}
}
void use_my_print ( ) {
my_print ( " abc " ) ; // expected-note {{requested here}}
}
template < typename T >
class UninstantiatedPrinter {
public :
static void print ( const T & arg ) {
printf ( " %d " , arg ) ; // no-warning
}
} ;
template < typename T >
class Printer {
void format ( const char * fmt , . . . ) __attribute__ ( ( format ( printf , 2 , 3 ) ) ) ;
public :
void print ( const T & arg ) {
format ( " %d " , arg ) ; // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}}
}
} ;
void use_class ( Printer < const char * > & p ) {
p . print ( " abc " ) ; // expected-note {{requested here}}
}
extern void ( ^ block_print ) ( const char * format , . . . ) __attribute__ ( ( format ( printf , 1 , 2 ) ) ) ;
template < typename T >
void uninstantiated_call_block_print ( const T & arg ) {
block_print ( " %d " , arg ) ; // no-warning
}
template < typename T >
void call_block_print ( const T & arg ) {
block_print ( " %d " , arg ) ; // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}}
}
void use_block_print ( ) {
call_block_print ( " abc " ) ; // expected-note {{requested here}}
}
}
2015-04-24 00:14:19 +08:00
namespace implicit_this_tests {
struct t {
void func1 ( const char * , . . . ) __attribute__ ( ( __format__ ( printf , 1 , 2 ) ) ) ; // expected-error {{format attribute cannot specify the implicit this argument as the format string}}
void ( * func2 ) ( const char * , . . . ) __attribute__ ( ( __format__ ( printf , 1 , 2 ) ) ) ;
static void ( * func3 ) ( const char * , . . . ) __attribute__ ( ( __format__ ( printf , 1 , 2 ) ) ) ;
static void func4 ( const char * , . . . ) __attribute__ ( ( __format__ ( printf , 1 , 2 ) ) ) ;
} ;
void f ( ) {
t t1 ;
t1 . func2 ( " Hello %s " ) ; // expected-warning {{more '%' conversions than data arguments}}
t : : func3 ( " Hello %s " ) ; // expected-warning {{more '%' conversions than data arguments}}
t : : func4 ( " Hello %s " ) ; // expected-warning {{more '%' conversions than data arguments}}
}
}