1 // RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -pedantic -fblocks %s 2 3 #include <stdarg.h> 4 5 extern "C" { 6 extern int scanf(const char *restrict, ...); 7 extern int printf(const char *restrict, ...); 8 extern int vprintf(const char *restrict, va_list); 9 } 10 11 void f(char **sp, float *fp) { 12 scanf("%as", sp); // expected-warning{{'a' length modifier is not supported by ISO C}} 13 14 // TODO: Warn that the 'a' conversion specifier is a C++11 feature. 15 printf("%a", 1.0); 16 scanf("%afoobar", fp); 17 } 18 19 void g() { 20 printf("%ls", "foo"); // expected-warning{{format specifies type 'wchar_t *' but the argument has type 'const char *'}} 21 } 22 23 // Test that we properly handle format_idx on C++ members. 24 class Foo { 25 public: 26 const char *gettext(const char *fmt) __attribute__((format_arg(2))); 27 28 int scanf(const char *, ...) __attribute__((format(scanf, 2, 3))); 29 int printf(const char *, ...) __attribute__((format(printf, 2, 3))); 30 int printf2(const char *, ...); 31 32 static const char *gettext_static(const char *fmt) __attribute__((format_arg(1))); 33 static int printf_static(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 34 }; 35 36 void h(int *i) { 37 Foo foo; 38 foo.scanf("%d"); // expected-warning{{more '%' conversions than data arguments}} 39 foo.printf("%d", i); // expected-warning{{format specifies type 'int' but the argument has type 'int *'}} 40 Foo::printf_static("%d", i); // expected-warning{{format specifies type 'int' but the argument has type 'int *'}} 41 42 printf(foo.gettext("%d"), i); // expected-warning{{format specifies type 'int' but the argument has type 'int *'}} 43 printf(Foo::gettext_static("%d"), i); // expected-warning{{format specifies type 'int' but the argument has type 'int *'}} 44 } 45 46 // Test handling __null for format string literal checking. 47 extern "C" { 48 int test_null_format(const char *format, ...) __attribute__((__format__ (__printf__, 1, 2))); 49 } 50 51 void rdar8269537(const char *f) 52 { 53 test_null_format(false); // expected-warning {{null from a constant boolean}} 54 test_null_format(0); // no-warning 55 test_null_format(__null); // no-warning 56 test_null_format(f); // expected-warning {{not a string literal}} 57 } 58 59 int Foo::printf(const char *fmt, ...) { 60 va_list ap; 61 va_start(ap,fmt); 62 const char * const format = fmt; 63 vprintf(format, ap); // no-warning 64 65 const char *format2 = fmt; 66 vprintf(format2, ap); // expected-warning{{format string is not a string literal}} 67 68 return 0; 69 } 70 71 int Foo::printf2(const char *fmt, ...) { 72 va_list ap; 73 va_start(ap,fmt); 74 vprintf(fmt, ap); // expected-warning{{format string is not a string literal}} 75 76 return 0; 77 } 78 79 80 namespace Templates { 81 template<typename T> 82 void my_uninstantiated_print(const T &arg) { 83 printf("%d", arg); // no-warning 84 } 85 86 template<typename T> 87 void my_print(const T &arg) { 88 printf("%d", arg); // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}} 89 } 90 91 void use_my_print() { 92 my_print("abc"); // expected-note {{requested here}} 93 } 94 95 96 template<typename T> 97 class UninstantiatedPrinter { 98 public: 99 static void print(const T &arg) { 100 printf("%d", arg); // no-warning 101 } 102 }; 103 104 template<typename T> 105 class Printer { 106 void format(const char *fmt, ...) __attribute__((format(printf,2,3))); 107 public: 108 109 void print(const T &arg) { 110 format("%d", arg); // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}} 111 } 112 }; 113 114 void use_class(Printer<const char *> &p) { 115 p.print("abc"); // expected-note {{requested here}} 116 } 117 118 119 extern void (^block_print)(const char * format, ...) __attribute__((format(printf, 1, 2))); 120 121 template<typename T> 122 void uninstantiated_call_block_print(const T &arg) { 123 block_print("%d", arg); // no-warning 124 } 125 126 template<typename T> 127 void call_block_print(const T &arg) { 128 block_print("%d", arg); // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}} 129 } 130 131 void use_block_print() { 132 call_block_print("abc"); // expected-note {{requested here}} 133 } 134 } 135 136