Skip to content

Commit 4fd960b

Browse files
committed
Add implicit attribute
1 parent 948c282 commit 4fd960b

File tree

4 files changed

+146
-76
lines changed

4 files changed

+146
-76
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3019,7 +3019,7 @@ class Sema final : public SemaBase {
30193019
llvm::SmallBitVector &CheckedVarArgs);
30203020
bool CheckFormatArguments(ArrayRef<const Expr *> Args,
30213021
FormatArgumentPassingKind FAPK,
3022-
const StringLiteral *ReferenceFormatString,
3022+
StringLiteral *ReferenceFormatString,
30233023
unsigned format_idx, unsigned firstDataArg,
30243024
FormatStringType Type, VariadicCallType CallType,
30253025
SourceLocation Loc, SourceRange range,

clang/lib/Sema/SemaChecking.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7028,7 +7028,7 @@ std::string escapeFormatString(StringRef Input) {
70287028

70297029
static void CheckMissingFormatAttributes(
70307030
Sema *S, ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK,
7031-
const StringLiteral *ReferenceFormatString, unsigned FormatIdx,
7031+
StringLiteral *ReferenceFormatString, unsigned FormatIdx,
70327032
unsigned FirstDataArg, FormatStringType FormatType, unsigned CallerParamIdx,
70337033
SourceLocation Loc) {
70347034
NamedDecl *Caller = S->getCurFunctionOrMethodDecl();
@@ -7085,9 +7085,9 @@ static void CheckMissingFormatAttributes(
70857085
}
70867086

70877087
// Emit the diagnostic and fixit.
7088+
unsigned FormatStringIndex = CallerParamIdx + CallerArgumentIndexOffset;
7089+
StringRef FormatTypeName = S->GetFormatStringTypeName(FormatType);
70887090
do {
7089-
unsigned FormatStringIndex = CallerParamIdx + CallerArgumentIndexOffset;
7090-
StringRef FormatTypeName = S->GetFormatStringTypeName(FormatType);
70917091
std::string Attr, Fixit;
70927092
if (APK != Sema::FormatArgumentPassingKind::FAPK_Elsewhere)
70937093
llvm::raw_string_ostream(Attr)
@@ -7125,11 +7125,21 @@ static void CheckMissingFormatAttributes(
71257125
DB << FixItHint::CreateInsertion(SL, Fixit);
71267126
} while (false);
71277127
S->Diag(Caller->getLocation(), diag::note_entity_declared_at) << Caller;
7128+
7129+
if (APK != Sema::FormatArgumentPassingKind::FAPK_Elsewhere) {
7130+
Caller->addAttr(FormatAttr::CreateImplicit(
7131+
S->getASTContext(), &S->getASTContext().Idents.get(FormatTypeName),
7132+
FormatStringIndex, FirstArgumentIndex));
7133+
} else {
7134+
Caller->addAttr(FormatMatchesAttr::CreateImplicit(
7135+
S->getASTContext(), &S->getASTContext().Idents.get(FormatTypeName),
7136+
FormatStringIndex, ReferenceFormatString));
7137+
}
71287138
}
71297139

71307140
bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
71317141
Sema::FormatArgumentPassingKind APK,
7132-
const StringLiteral *ReferenceFormatString,
7142+
StringLiteral *ReferenceFormatString,
71337143
unsigned format_idx, unsigned firstDataArg,
71347144
FormatStringType Type,
71357145
VariadicCallType CallType, SourceLocation Loc,

clang/test/Sema/attr-format-missing.c

Lines changed: 54 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -88,31 +88,42 @@ void f7(char* out, ... /* args */)
8888
vprintf("test", args);
8989
}
9090

91-
// Ok, out is not passed to print functions.
92-
void f8(char *out, va_list args)
91+
// Ok, format string is not passed to format functions.
92+
void f8(va_list args)
9393
{
94-
const char *ch = "format";
94+
const char * const ch = "format";
9595
vprintf(ch, args);
9696
vprintf("test", args);
97-
}
9897

99-
// Ok, out is not passed to scan functions.
100-
void f9(va_list args)
101-
{
102-
const char *ch = "format";
10398
vscanf(ch, args);
10499
vscanf("test", args);
100+
101+
char out[10];
102+
103+
struct tm tm_arg;
104+
tm_arg.i = 0;
105+
strftime(out, sizeof(out), ch, &tm_arg);
106+
strftime(out, sizeof(out), "test", &tm_arg);
107+
108+
strfmon(out, sizeof(out), ch);
109+
strfmon(out, sizeof(out), "test");
105110
}
106111

107-
// CHECK: fix-it:"{{.*}}":{[[@LINE+2]]:1-[[@LINE+2]]:1}:"{{\[\[}}gnu::format(scanf, 1, 2)]] "
108-
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] "
112+
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format_matches(printf, 1, \"%d %f \\\"'\")]] "
113+
void f9(const char *fmt, ...) // #f9
114+
{
115+
va_list args;
116+
custom_print(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format_matches(printf, 1, "%d %f \"'")' attribute to the declaration of 'f9'}}
117+
// expected-note@#f9 {{'f9' declared here}}
118+
}
119+
120+
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(scanf, 1, 2)]] "
109121
void f10(const char *out, ... /* args */) // #f10
110122
{
111123
va_list args;
112124
vscanf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'f10'}}
113125
// expected-note@#f10 {{'f10' declared here}}
114-
vprintf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f10'}}
115-
// expected-note@#f10 {{'f10' declared here}}
126+
vprintf(out, args); // expected-warning {{passing 'scanf' format string where 'printf' format string is expected}}
116127
}
117128

118129
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] "
@@ -135,105 +146,83 @@ void f12(char* out) // #f12
135146
// expected-note@#f12 {{'f12' declared here}}
136147
}
137148

138-
// CHECK: fix-it:"{{.*}}":{[[@LINE+2]]:1-[[@LINE+2]]:1}:"{{\[\[}}gnu::format(scanf, 1, 2)]] "
139-
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] "
140-
void f13(char *out, ... /* args */) // #f13
141-
{
142-
va_list args;
143-
vscanf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'f13'}}
144-
// expected-note@#f13 {{'f13' declared here}}
145-
vprintf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f13'}}
146-
// expected-note@#f13 {{'f13' declared here}}
147-
}
148-
149-
// CHECK: fix-it:"{{.*}}":{[[@LINE+2]]:1-[[@LINE+2]]:1}:"{{\[\[}}gnu::format(scanf, 1, 0)]] "
150149
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 0)]] "
151-
void f14(char *out, va_list args) // #f14
150+
void f13(char *out, va_list args) // #f13
152151
{
153-
vscanf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 0)' attribute to the declaration of 'f14'}}
154-
// expected-note@#f14 {{'f14' declared here}}
155-
vprintf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 0)' attribute to the declaration of 'f14'}}
156-
// expected-note@#f14 {{'f14' declared here}}
152+
vprintf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 0)' attribute to the declaration of 'f13'}}
153+
// expected-note@#f13 {{'f13' declared here}}
154+
vscanf(out, args); // expected-warning {{passing 'printf' format string where 'scanf' format string is expected}}
157155
}
158156

159157
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(scanf, 1, 2)]] "
160-
void f15(char *out, ... /* args */) // #f15
158+
void f14(char *out, ... /* args */) // #f14
161159
{
162160
va_list args;
163-
vscanf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'f15'}}
164-
// expected-note@#f15 {{'f15' declared here}}
165-
vscanf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'f15'}}
166-
// expected-note@#f15 {{'f15' declared here}}
161+
vscanf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'f14'}}
162+
// expected-note@#f14 {{'f14' declared here}}
163+
vscanf(out, args);
167164
}
168165

169166
// CHECK: fix-it:"{{.*}}":{[[@LINE+2]]:1-[[@LINE+2]]:1}:"{{\[\[}}gnu::format(printf, 1, 3)]] "
170167
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 2, 3)]] "
171-
void f16(char *ch, const char *out, ... /* args */) // #f16
168+
void f15(char *ch, const char *out, ... /* args */) // #f15
172169
{
173170
va_list args;
174-
vprintf(ch, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 3)' attribute to the declaration of 'f16'}}
175-
// expected-note@#f16 {{'f16' declared here}}
176-
vprintf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of 'f16'}}
177-
// expected-note@#f16 {{'f16' declared here}}
171+
vprintf(ch, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 3)' attribute to the declaration of 'f15'}}
172+
// expected-note@#f15 {{'f15' declared here}}
173+
vprintf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of 'f15'}}
174+
// expected-note@#f15 {{'f15' declared here}}
178175
}
179176

180177
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] "
181-
void f17(const char *a, ...) // #f17
178+
void f16(const char *a, ...) // #f16
182179
{
183180
va_list ap;
184181
const char *const b = a;
185-
vprintf(b, ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f17'}}
186-
// expected-note@#f17 {{'f17' declared here}}
182+
vprintf(b, ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f16'}}
183+
// expected-note@#f16 {{'f16' declared here}}
187184
}
188185

189186
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] "
190-
void f18(char *fmt, unsigned x, unsigned y, unsigned z) // #f18
187+
void f17(char *fmt, unsigned x, unsigned y, unsigned z) // #f17
191188
{
192-
printf(fmt, x, y, z); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f18'}}
193-
// expected-note@#f18 {{'f18' declared here}}
189+
printf(fmt, x, y, z); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f17'}}
190+
// expected-note@#f17 {{'f17' declared here}}
194191
}
195192

196-
void f19(char *fmt, unsigned x, unsigned y, unsigned z) // #f19
193+
void f18(char *fmt, unsigned x, unsigned y, unsigned z) // #f18
197194
{
198195
// Arguments are not passed in the same order.
199196
printf(fmt, x, z, y);
200197
}
201198

202-
void f20(char *out, ... /* args */)
199+
void f19(char *out, ... /* args */)
203200
{
204201
printf(out, 1); // No warning, arguments are not passed to printf.
205202
}
206203

207204
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(strftime, 3, 0)]] "
208-
void f21(char *out, const size_t len, const char *format) // #f21
205+
void f20(char *out, const size_t len, const char *format) // #f20
209206
{
210207
struct tm tm_arg;
211208
tm_arg.i = 0;
212-
strftime(out, len, format, &tm_arg); // expected-warning {{diagnostic behavior may be improved by adding the 'format(strftime, 3, 0)' attribute to the declaration of 'f21'}}
213-
// expected-note@#f21 {{'f21' declared here}}
209+
strftime(out, len, format, &tm_arg); // expected-warning {{diagnostic behavior may be improved by adding the 'format(strftime, 3, 0)' attribute to the declaration of 'f20'}}
210+
// expected-note@#f20 {{'f20' declared here}}
214211
}
215212

216213
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(strfmon, 3, 4)]] "
217-
void f22(char *out, const size_t len, const char *format, int x, int y) // #f22
214+
void f21(char *out, const size_t len, const char *format, int x, int y) // #f21
218215
{
219-
strfmon(out, len, format, x, y); // expected-warning {{diagnostic behavior may be improved by adding the 'format(strfmon, 3, 4)' attribute to the declaration of 'f22'}}
220-
// expected-note@#f22 {{'f22' declared here}}
216+
strfmon(out, len, format, x, y); // expected-warning {{diagnostic behavior may be improved by adding the 'format(strfmon, 3, 4)' attribute to the declaration of 'f21'}}
217+
// expected-note@#f21 {{'f21' declared here}}
221218
}
222219

223220
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] "
224-
void f23(const char *fmt, ... /* args */); // #f23
225-
226-
void f23(const char *fmt, ... /* args */)
227-
{
228-
va_list args;
229-
vprintf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f23'}}
230-
// expected-note@#f23 {{'f23' declared here}}
231-
}
221+
void f22(const char *fmt, ... /* args */); // #f22
232222

233-
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format_matches(printf, 1, \"%d %f \\\"'\")]] "
234-
void f24(const char *fmt, ...) // #f24
223+
void f22(const char *fmt, ... /* args */)
235224
{
236225
va_list args;
237-
custom_print(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format_matches(printf, 1, "%d %f \"'")' attribute to the declaration of 'f24'}}
238-
// expected-note@#f24 {{'f24' declared here}}
226+
vprintf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'f22'}}
227+
// expected-note@#f22 {{'f22' declared here}}
239228
}

clang/test/Sema/format-strings.c

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,37 +24,108 @@ int vscanf(const char *restrict format, va_list arg);
2424

2525
char * global_fmt;
2626

27-
void check_string_literal( FILE* fp, const char* s, char *buf, ... ) {
28-
29-
char * b;
27+
void check_string_literal1( const char* s, ... ) {
3028
va_list ap;
31-
va_start(ap,buf);
32-
29+
va_start(ap,s);
3330
printf(s); // expected-warning {{format string is not a string literal}}
3431
// expected-note@-1{{treat the string as an argument to avoid this}}
32+
}
33+
34+
void check_string_literal2( const char* s, ... ) {
35+
va_list ap;
36+
va_start(ap,s);
3537
vprintf(s,ap); // expected-warning {{format string is not a string literal}}
38+
}
39+
40+
void check_string_literal3( FILE* fp, const char* s, ... ) {
41+
va_list ap;
42+
va_start(ap,s);
3643
fprintf(fp,s); // expected-warning {{format string is not a string literal}}
3744
// expected-note@-1{{treat the string as an argument to avoid this}}
45+
}
46+
47+
void check_string_literal4( FILE* fp, const char* s, ... ) {
48+
va_list ap;
49+
va_start(ap,s);
3850
vfprintf(fp,s,ap); // expected-warning {{format string is not a string literal}}
51+
}
52+
53+
void check_string_literal5( const char* s, ... ) {
54+
char * b;
55+
va_list ap;
56+
va_start(ap,s);
3957
asprintf(&b,s); // expected-warning {{format string is not a string lit}}
4058
// expected-note@-1{{treat the string as an argument to avoid this}}
59+
}
60+
61+
void check_string_literal6( const char* s, ... ) {
62+
char * b;
63+
va_list ap;
64+
va_start(ap,s);
4165
vasprintf(&b,s,ap); // expected-warning {{format string is not a string literal}}
66+
}
67+
68+
void check_string_literal7( const char* s, char *buf ) {
4269
sprintf(buf,s); // expected-warning {{format string is not a string literal}}
4370
// expected-note@-1{{treat the string as an argument to avoid this}}
71+
}
72+
73+
void check_string_literal8( const char* s, char *buf ) {
4474
snprintf(buf,2,s); // expected-warning {{format string is not a string lit}}
4575
// expected-note@-1{{treat the string as an argument to avoid this}}
76+
}
77+
78+
void check_string_literal9( const char* s, char *buf, ... ) {
79+
va_list ap;
80+
va_start(ap,buf);
4681
__builtin___sprintf_chk(buf,0,-1,s); // expected-warning {{format string is not a string literal}}
4782
// expected-note@-1{{treat the string as an argument to avoid this}}
83+
}
84+
85+
void check_string_literal10( const char* s, char *buf, ... ) {
86+
va_list ap;
87+
va_start(ap,buf);
4888
__builtin___snprintf_chk(buf,2,0,-1,s); // expected-warning {{format string is not a string lit}}
4989
// expected-note@-1{{treat the string as an argument to avoid this}}
90+
}
91+
92+
void check_string_literal11( const char* s, char *buf, ... ) {
93+
va_list ap;
94+
va_start(ap,buf);
5095
vsprintf(buf,s,ap); // expected-warning {{format string is not a string lit}}
96+
}
97+
98+
void check_string_literal12( const char* s, char *buf, ... ) {
99+
va_list ap;
100+
va_start(ap,buf);
51101
vsnprintf(buf,2,s,ap); // expected-warning {{format string is not a string lit}}
102+
}
103+
104+
void check_string_literal13( char *buf, ... ) {
105+
va_list ap;
106+
va_start(ap,buf);
52107
vsnprintf(buf,2,global_fmt,ap); // expected-warning {{format string is not a string literal}}
108+
}
109+
110+
void check_string_literal14( FILE* fp, const char* s, char *buf, ... ) {
111+
va_list ap;
112+
va_start(ap,buf);
53113
__builtin___vsnprintf_chk(buf,2,0,-1,s,ap); // expected-warning {{format string is not a string lit}}
114+
}
115+
116+
void check_string_literal15( FILE* fp, const char* s, char *buf, ... ) {
117+
va_list ap;
118+
va_start(ap,buf);
54119
__builtin___vsnprintf_chk(buf,2,0,-1,global_fmt,ap); // expected-warning {{format string is not a string literal}}
120+
}
55121

122+
void check_string_literal16(const char* s, ... ) {
123+
va_list ap;
124+
va_start(ap,s);
56125
vscanf(s, ap); // expected-warning {{format string is not a string literal}}
126+
}
57127

128+
void check_string_literal17() {
58129
const char *const fmt = "%d"; // FIXME -- defined here
59130
printf(fmt, 1, 2); // expected-warning{{data argument not used}}
60131

@@ -74,7 +145,7 @@ def"
74145
// warn only if the format string argument is a parameter that is not itself
75146
// declared as a format string with compatible format.
76147
__attribute__((__format__ (__printf__, 2, 4)))
77-
void check_string_literal2( FILE* fp, const char* s, char *buf, ... ) {
148+
void check_string_literal18( FILE* fp, const char* s, char *buf, ... ) {
78149
char * b;
79150
va_list ap;
80151
va_start(ap,buf);

0 commit comments

Comments
 (0)