Stephen Hines | 176edba | 2014-12-01 14:53:08 -0800 | [diff] [blame] | 1 | // RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -Wformat-non-iso -fblocks %s |
Hans Wennborg | 5294c79 | 2011-12-28 13:10:50 +0000 | [diff] [blame] | 2 | |
Jean-Daniel Dupas | f57c413 | 2012-02-21 20:00:53 +0000 | [diff] [blame] | 3 | #include <stdarg.h> |
| 4 | |
Hans Wennborg | 5294c79 | 2011-12-28 13:10:50 +0000 | [diff] [blame] | 5 | extern "C" { |
| 6 | extern int scanf(const char *restrict, ...); |
| 7 | extern int printf(const char *restrict, ...); |
Jean-Daniel Dupas | f57c413 | 2012-02-21 20:00:53 +0000 | [diff] [blame] | 8 | extern int vprintf(const char *restrict, va_list); |
Hans Wennborg | 5294c79 | 2011-12-28 13:10:50 +0000 | [diff] [blame] | 9 | } |
| 10 | |
| 11 | void f(char **sp, float *fp) { |
Hans Wennborg | f856264 | 2012-03-09 10:10:54 +0000 | [diff] [blame] | 12 | scanf("%as", sp); // expected-warning{{'a' length modifier is not supported by ISO C}} |
Hans Wennborg | 5294c79 | 2011-12-28 13:10:50 +0000 | [diff] [blame] | 13 | |
| 14 | // TODO: Warn that the 'a' conversion specifier is a C++11 feature. |
| 15 | printf("%a", 1.0); |
| 16 | scanf("%afoobar", fp); |
| 17 | } |
Hans Wennborg | 7da1f46 | 2012-01-31 14:59:59 +0000 | [diff] [blame] | 18 | |
| 19 | void g() { |
| 20 | printf("%ls", "foo"); // expected-warning{{format specifies type 'wchar_t *' but the argument has type 'const char *'}} |
| 21 | } |
Jean-Daniel Dupas | 52aabaf | 2012-02-07 19:01:42 +0000 | [diff] [blame] | 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 | |
Jean-Daniel Dupas | f57c413 | 2012-02-21 20:00:53 +0000 | [diff] [blame] | 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 *, ...); |
Jean-Daniel Dupas | 52aabaf | 2012-02-07 19:01:42 +0000 | [diff] [blame] | 31 | |
| 32 | static const char *gettext_static(const char *fmt) __attribute__((format_arg(1))); |
Jean-Daniel Dupas | f57c413 | 2012-02-21 20:00:53 +0000 | [diff] [blame] | 33 | static int printf_static(const char *fmt, ...) __attribute__((format(printf, 1, 2))); |
Jean-Daniel Dupas | 52aabaf | 2012-02-07 19:01:42 +0000 | [diff] [blame] | 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 | } |
Ted Kremenek | e3d8e73 | 2012-02-10 19:13:51 +0000 | [diff] [blame] | 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 | { |
David Blaikie | a73cdcb | 2012-02-10 21:07:25 +0000 | [diff] [blame] | 53 | test_null_format(false); // expected-warning {{null from a constant boolean}} |
| 54 | test_null_format(0); // no-warning |
Ted Kremenek | e3d8e73 | 2012-02-10 19:13:51 +0000 | [diff] [blame] | 55 | test_null_format(__null); // no-warning |
| 56 | test_null_format(f); // expected-warning {{not a string literal}} |
| 57 | } |
Jean-Daniel Dupas | f57c413 | 2012-02-21 20:00:53 +0000 | [diff] [blame] | 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 | } |
Jordan Rose | 66360e2 | 2012-10-02 01:49:54 +0000 | [diff] [blame] | 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 | |