1 | // RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -Wformat-non-iso -fblocks %s |
2 | // RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -Wformat-non-iso -fblocks -std=c++98 %s |
3 | // RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -Wformat-non-iso -fblocks -std=c++11 %s |
4 | |
5 | #include <stdarg.h> |
6 | |
7 | extern "C" { |
8 | extern int scanf(const char *restrict, ...); |
9 | extern int printf(const char *restrict, ...); |
10 | extern int vprintf(const char *restrict, va_list); |
11 | } |
12 | |
13 | void f(char **sp, float *fp) { |
14 | scanf("%as", sp); |
15 | #if __cplusplus <= 199711L |
16 | // expected-warning@-2 {{'a' length modifier is not supported by ISO C}} |
17 | #else |
18 | // expected-warning@-4 {{format specifies type 'float *' but the argument has type 'char **'}} |
19 | #endif |
20 | |
21 | printf("%a", 1.0); |
22 | scanf("%afoobar", fp); |
23 | } |
24 | |
25 | void g() { |
26 | printf("%ls", "foo"); // expected-warning{{format specifies type 'wchar_t *' but the argument has type 'const char *'}} |
27 | } |
28 | |
29 | // Test that we properly handle format_idx on C++ members. |
30 | class Foo { |
31 | public: |
32 | const char *gettext(const char *fmt) __attribute__((format_arg(2))); |
33 | |
34 | int scanf(const char *, ...) __attribute__((format(scanf, 2, 3))); |
35 | int printf(const char *, ...) __attribute__((format(printf, 2, 3))); |
36 | int printf2(const char *, ...); |
37 | |
38 | static const char *gettext_static(const char *fmt) __attribute__((format_arg(1))); |
39 | static int printf_static(const char *fmt, ...) __attribute__((format(printf, 1, 2))); |
40 | }; |
41 | |
42 | void h(int *i) { |
43 | Foo foo; |
44 | foo.scanf("%d"); // expected-warning{{more '%' conversions than data arguments}} |
45 | foo.printf("%d", i); // expected-warning{{format specifies type 'int' but the argument has type 'int *'}} |
46 | Foo::printf_static("%d", i); // expected-warning{{format specifies type 'int' but the argument has type 'int *'}} |
47 | |
48 | printf(foo.gettext("%d"), i); // expected-warning{{format specifies type 'int' but the argument has type 'int *'}} |
49 | printf(Foo::gettext_static("%d"), i); // expected-warning{{format specifies type 'int' but the argument has type 'int *'}} |
50 | } |
51 | |
52 | // Test handling __null for format string literal checking. |
53 | extern "C" { |
54 | int test_null_format(const char *format, ...) __attribute__((__format__ (__printf__, 1, 2))); |
55 | #if __cplusplus >= 201103L |
56 | // expected-note@-2 {{candidate function not viable: no known conversion from 'bool' to 'const char *' for 1st argument}} |
57 | #endif |
58 | } |
59 | |
60 | void rdar8269537(const char *f) |
61 | { |
62 | test_null_format(false); |
63 | #if __cplusplus <= 199711L |
64 | // expected-warning@-2 {{null from a constant boolean}} |
65 | #else |
66 | // expected-error@-4 {{no matching function for call to 'test_null_format'}} |
67 | #endif |
68 | test_null_format(0); // no-warning |
69 | test_null_format(__null); // no-warning |
70 | test_null_format(f); // expected-warning {{not a string literal}} |
71 | // expected-note@-1{{treat the string as an argument to avoid this}} |
72 | } |
73 | |
74 | int Foo::printf(const char *fmt, ...) { |
75 | va_list ap; |
76 | va_start(ap,fmt); |
77 | const char * const format = fmt; |
78 | vprintf(format, ap); // no-warning |
79 | |
80 | const char *format2 = fmt; |
81 | vprintf(format2, ap); // expected-warning{{format string is not a string literal}} |
82 | |
83 | return 0; |
84 | } |
85 | |
86 | int Foo::printf2(const char *fmt, ...) { |
87 | va_list ap; |
88 | va_start(ap,fmt); |
89 | vprintf(fmt, ap); // expected-warning{{format string is not a string literal}} |
90 | |
91 | return 0; |
92 | } |
93 | |
94 | |
95 | namespace Templates { |
96 | template<typename T> |
97 | void my_uninstantiated_print(const T &arg) { |
98 | printf("%d", arg); // no-warning |
99 | } |
100 | |
101 | template<typename T> |
102 | void my_print(const T &arg) { |
103 | printf("%d", arg); // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}} |
104 | } |
105 | |
106 | void use_my_print() { |
107 | my_print("abc"); // expected-note {{requested here}} |
108 | } |
109 | |
110 | |
111 | template<typename T> |
112 | class UninstantiatedPrinter { |
113 | public: |
114 | static void print(const T &arg) { |
115 | printf("%d", arg); // no-warning |
116 | } |
117 | }; |
118 | |
119 | template<typename T> |
120 | class Printer { |
121 | void format(const char *fmt, ...) __attribute__((format(printf,2,3))); |
122 | public: |
123 | |
124 | void print(const T &arg) { |
125 | format("%d", arg); // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}} |
126 | } |
127 | }; |
128 | |
129 | void use_class(Printer<const char *> &p) { |
130 | p.print("abc"); // expected-note {{requested here}} |
131 | } |
132 | |
133 | |
134 | extern void (^block_print)(const char * format, ...) __attribute__((format(printf, 1, 2))); |
135 | |
136 | template<typename T> |
137 | void uninstantiated_call_block_print(const T &arg) { |
138 | block_print("%d", arg); // no-warning |
139 | } |
140 | |
141 | template<typename T> |
142 | void call_block_print(const T &arg) { |
143 | block_print("%d", arg); // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}} |
144 | } |
145 | |
146 | void use_block_print() { |
147 | call_block_print("abc"); // expected-note {{requested here}} |
148 | } |
149 | } |
150 | |
151 | namespace implicit_this_tests { |
152 | struct t { |
153 | void func1(const char *, ...) __attribute__((__format__(printf, 1, 2))); // expected-error {{format attribute cannot specify the implicit this argument as the format string}} |
154 | void (*func2)(const char *, ...) __attribute__((__format__(printf, 1, 2))); |
155 | static void (*func3)(const char *, ...) __attribute__((__format__(printf, 1, 2))); |
156 | static void func4(const char *, ...) __attribute__((__format__(printf, 1, 2))); |
157 | }; |
158 | |
159 | void f() { |
160 | t t1; |
161 | t1.func2("Hello %s"); // expected-warning {{more '%' conversions than data arguments}} |
162 | t::func3("Hello %s"); // expected-warning {{more '%' conversions than data arguments}} |
163 | t::func4("Hello %s"); // expected-warning {{more '%' conversions than data arguments}} |
164 | } |
165 | } |
166 | |