Skip to content

Commit f1f719c

Browse files
committed
Make diagnostic a subgroup of format-nonliteral
1 parent 4fd960b commit f1f719c

File tree

8 files changed

+109
-61
lines changed

8 files changed

+109
-61
lines changed

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,7 @@ def FormatY2K : DiagGroup<"format-y2k">;
11821182
def FormatPedantic : DiagGroup<"format-pedantic">;
11831183
def FormatSignedness : DiagGroup<"format-signedness">;
11841184
def FormatTypeConfusion : DiagGroup<"format-type-confusion">;
1185+
def MissingFormatAttribute : DiagGroup<"missing-format-attribute">;
11851186

11861187
def FormatOverflowNonKprintf: DiagGroup<"format-overflow-non-kprintf">;
11871188
def FormatOverflow: DiagGroup<"format-overflow", [FormatOverflowNonKprintf]>;
@@ -1193,7 +1194,7 @@ def Format : DiagGroup<"format",
11931194
FormatSecurity, FormatY2K, FormatInvalidSpecifier,
11941195
FormatInsufficientArgs, FormatOverflow, FormatTruncation]>,
11951196
DiagCategory<"Format String Issue">;
1196-
def FormatNonLiteral : DiagGroup<"format-nonliteral">;
1197+
def FormatNonLiteral : DiagGroup<"format-nonliteral", [MissingFormatAttribute]>;
11971198
def Format2 : DiagGroup<"format=2",
11981199
[FormatNonLiteral, FormatSecurity, FormatY2K]>;
11991200

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3481,7 +3481,7 @@ def err_format_attribute_implicit_this_format_string : Error<
34813481
def warn_missing_format_attribute : Warning<
34823482
"diagnostic behavior may be improved by adding the '%0' attribute to the "
34833483
"declaration of %1">,
3484-
InGroup<DiagGroup<"missing-format-attribute">>, DefaultIgnore;
3484+
InGroup<MissingFormatAttribute>, DefaultIgnore;
34853485
def err_callback_attribute_no_callee : Error<
34863486
"'callback' attribute specifies no callback callee">;
34873487
def err_callback_attribute_invalid_callee : Error<

clang/lib/Sema/SemaChecking.cpp

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7026,15 +7026,19 @@ std::string escapeFormatString(StringRef Input) {
70267026
return Result;
70277027
}
70287028

7029-
static void CheckMissingFormatAttributes(
7029+
static bool CheckMissingFormatAttribute(
70307030
Sema *S, ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK,
70317031
StringLiteral *ReferenceFormatString, unsigned FormatIdx,
70327032
unsigned FirstDataArg, FormatStringType FormatType, unsigned CallerParamIdx,
70337033
SourceLocation Loc) {
7034-
NamedDecl *Caller = S->getCurFunctionOrMethodDecl();
7035-
if (!Caller)
7036-
return;
7037-
Caller = dyn_cast<NamedDecl>(Caller->getCanonicalDecl());
7034+
if (S->getDiagnostics().isIgnored(diag::warn_missing_format_attribute,
7035+
SourceLocation()))
7036+
return false;
7037+
7038+
DeclContext *DC = S->CurContext;
7039+
if (!isa<ObjCMethodDecl>(DC) && !isa<FunctionDecl>(DC) && !isa<BlockDecl>(DC))
7040+
return false;
7041+
Decl *Caller = cast<Decl>(DC)->getCanonicalDecl();
70387042

70397043
unsigned NumCallerParams = getFunctionOrMethodNumParams(Caller);
70407044

@@ -7055,17 +7059,17 @@ static void CheckMissingFormatAttributes(
70557059
unsigned NumCalleeArgs = Args.size() - FirstDataArg;
70567060
if (NumCalleeArgs == 0 || NumCallerParams < NumCalleeArgs) {
70577061
// There aren't enough arguments in the caller to pass to callee.
7058-
return;
7062+
return false;
70597063
}
70607064
for (unsigned CalleeIdx = Args.size() - 1, CallerIdx = NumCallerParams - 1;
70617065
CalleeIdx >= FirstDataArg; --CalleeIdx, --CallerIdx) {
70627066
const auto *Arg =
70637067
dyn_cast<DeclRefExpr>(Args[CalleeIdx]->IgnoreParenCasts());
70647068
if (!Arg)
7065-
return;
7069+
return false;
70667070
const auto *Param = dyn_cast<ParmVarDecl>(Arg->getDecl());
70677071
if (!Param || Param->getFunctionScopeIndex() != CallerIdx)
7068-
return;
7072+
return false;
70697073
}
70707074
FirstArgumentIndex =
70717075
NumCallerParams + CallerArgumentIndexOffset - NumCalleeArgs;
@@ -7080,13 +7084,14 @@ static void CheckMissingFormatAttributes(
70807084
case Sema::FormatArgumentPassingKind::FAPK_Elsewhere:
70817085
// The callee has a format_matches attribute. We will emit that instead.
70827086
if (!ReferenceFormatString)
7083-
return;
7087+
return false;
70847088
break;
70857089
}
70867090

70877091
// Emit the diagnostic and fixit.
70887092
unsigned FormatStringIndex = CallerParamIdx + CallerArgumentIndexOffset;
70897093
StringRef FormatTypeName = S->GetFormatStringTypeName(FormatType);
7094+
NamedDecl *ND = dyn_cast<NamedDecl>(Caller);
70907095
do {
70917096
std::string Attr, Fixit;
70927097
if (APK != Sema::FormatArgumentPassingKind::FAPK_Elsewhere)
@@ -7098,8 +7103,15 @@ static void CheckMissingFormatAttributes(
70987103
<< "format_matches(" << FormatTypeName << ", " << FormatStringIndex
70997104
<< ", \"" << escapeFormatString(ReferenceFormatString->getString())
71007105
<< "\")";
7101-
auto DB = S->Diag(Loc, diag::warn_missing_format_attribute)
7102-
<< Attr << Caller;
7106+
auto DB = S->Diag(Loc, diag::warn_missing_format_attribute) << Attr;
7107+
if (ND)
7108+
DB << ND;
7109+
else
7110+
DB << "block";
7111+
7112+
// Blocks don't provide a correct end loc, so skip emitting a fixit.
7113+
if (isa<BlockDecl>(Caller))
7114+
break;
71037115

71047116
SourceLocation SL;
71057117
llvm::raw_string_ostream IS(Fixit);
@@ -7124,8 +7136,8 @@ static void CheckMissingFormatAttributes(
71247136

71257137
DB << FixItHint::CreateInsertion(SL, Fixit);
71267138
} while (false);
7127-
S->Diag(Caller->getLocation(), diag::note_entity_declared_at) << Caller;
71287139

7140+
// Add implicit format or format_matches attribute.
71297141
if (APK != Sema::FormatArgumentPassingKind::FAPK_Elsewhere) {
71307142
Caller->addAttr(FormatAttr::CreateImplicit(
71317143
S->getASTContext(), &S->getASTContext().Idents.get(FormatTypeName),
@@ -7135,6 +7147,15 @@ static void CheckMissingFormatAttributes(
71357147
S->getASTContext(), &S->getASTContext().Idents.get(FormatTypeName),
71367148
FormatStringIndex, ReferenceFormatString));
71377149
}
7150+
7151+
{
7152+
auto DB = S->Diag(Caller->getLocation(), diag::note_entity_declared_at);
7153+
if (ND)
7154+
DB << ND;
7155+
else
7156+
DB << "block";
7157+
}
7158+
return true;
71387159
}
71397160

71407161
bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
@@ -7193,11 +7214,10 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
71937214
SourceMgr.isInSystemMacro(FormatLoc))
71947215
return false;
71957216

7196-
const LangOptions &LO = getLangOpts();
7197-
if (CallerParamIdx && (LO.GNUMode || LO.C23 || LO.CPlusPlus11))
7198-
CheckMissingFormatAttributes(this, Args, APK, ReferenceFormatString,
7199-
format_idx, firstDataArg, Type,
7200-
*CallerParamIdx, Loc);
7217+
if (CallerParamIdx && CheckMissingFormatAttribute(
7218+
this, Args, APK, ReferenceFormatString, format_idx,
7219+
firstDataArg, Type, *CallerParamIdx, Loc))
7220+
return false;
72017221

72027222
// Strftime is particular as it always uses a single 'time' argument,
72037223
// so it is safe to pass a non-literal string.
Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
// RUN: %clang_cc1 -fsyntax-only -verify -std=gnu11 -Wmissing-format-attribute %s
2-
// RUN: %clang_cc1 -fsyntax-only -verify -x c++ -std=gnu++98 -Wmissing-format-attribute %s
3-
// RUN: %clang_cc1 -fsyntax-only -std=gnu11 -Wmissing-format-attribute -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
4-
// RUN: %clang_cc1 -fsyntax-only -x c++ -std=gnu++98 -Wmissing-format-attribute -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
1+
// RUN: %clang_cc1 -fsyntax-only -fblocks -verify -std=gnu11 -Wmissing-format-attribute %s
2+
// RUN: %clang_cc1 -fsyntax-only -fblocks -verify -x c++ -std=gnu++98 -Wmissing-format-attribute %s
3+
// RUN: %clang_cc1 -fsyntax-only -fblocks -std=gnu11 -Wmissing-format-attribute -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
4+
// RUN: %clang_cc1 -fsyntax-only -fblocks -x c++ -std=gnu++98 -Wmissing-format-attribute -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
55

66
typedef unsigned long size_t;
77
typedef long ssize_t;
88
typedef __builtin_va_list va_list;
99

10+
__attribute__((format(printf, 1, 2)))
11+
int printf(const char *, ...);
12+
1013
__attribute__((format(printf, 1, 0)))
1114
int vprintf(const char *, va_list);
1215

@@ -18,3 +21,35 @@ void f1(char *out, va_list args) // #f1
1821
vprintf(out, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 0)' attribute to the declaration of 'f1'}}
1922
// expected-note@#f1 {{'f1' declared here}}
2023
}
24+
25+
void f2(void) {
26+
void (^b1)(const char *, ...) = ^(const char *fmt, ...) { // #b1
27+
va_list args;
28+
vprintf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of block}}
29+
// expected-note@#b1 {{block declared here}}
30+
};
31+
32+
void (^b2)(const char *, va_list) = ^(const char *fmt, va_list args) { // #b2
33+
vprintf(fmt, args); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 0)' attribute to the declaration of block}}.
34+
// expected-note@#b2 {{block declared here}}
35+
};
36+
37+
void (^b3)(const char *, int x, float y) = ^(const char *fmt, int x, float y) { // #b3
38+
printf(fmt, x, y); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of block}}.
39+
// expected-note@#b3 {{block declared here}}
40+
};
41+
42+
void __attribute__((__format__(__printf__, 1, 2))) (^b4)(const char *, ...) =
43+
^(const char *fmt, ...) __attribute__((__format__(__printf__, 1, 2))) {
44+
va_list args;
45+
vprintf(fmt, args);
46+
};
47+
48+
void __attribute__((__format__(__printf__, 2, 3))) (^b5)(const char *, const char *, ...) =
49+
^(const char *not_fmt, const char *fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { // #b5
50+
va_list args;
51+
vprintf(fmt, args);
52+
vprintf(not_fmt, args); // expected-warning{{diagnostic behavior may be improved by adding the 'format(printf, 1, 3)' attribute to the declaration of block}}
53+
// expected-note@#b5 {{block declared here}}
54+
};
55+
}

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

Lines changed: 0 additions & 17 deletions
This file was deleted.

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,10 @@ void f15(char *ch, const char *out, ... /* args */) // #f15
177177
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] "
178178
void f16(const char *a, ...) // #f16
179179
{
180-
va_list ap;
180+
va_list args;
181181
const char *const b = a;
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}}
182+
vprintf(b, args); // 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}}
184184
}
185185

186186
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:1-[[@LINE+1]]:1}:"{{\[\[}}gnu::format(printf, 1, 2)]] "

clang/test/Sema/format-strings-scanf.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ int vscanf(const char * restrict, va_list);
3636
int vfscanf(FILE * restrict, const char * restrict, va_list);
3737
int vsscanf(const char * restrict, const char * restrict, va_list);
3838

39-
void test(const char *s, int *i) {
40-
scanf(s, i); // expected-warning{{format string is not a string literal}}
39+
void test(const char *s, int *i) { // #test
40+
scanf(s, i); // expected-warning{{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'test'}}
41+
// expected-note@#test {{'test' declared here}}
4142
scanf("%0d", i); // expected-warning{{zero field width in scanf format string is unused}}
4243
scanf("%00d", i); // expected-warning{{zero field width in scanf format string is unused}}
4344
scanf("%d%[asdfasdfd", i, s); // expected-warning{{no closing ']' for '%[' in scanf format string}}

clang/test/Sema/format-strings.c

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ void check_string_literal1( const char* s, ... ) {
3131
// expected-note@-1{{treat the string as an argument to avoid this}}
3232
}
3333

34-
void check_string_literal2( const char* s, ... ) {
34+
void check_string_literal2( const char* s, ... ) { // #check_string_literal2
3535
va_list ap;
3636
va_start(ap,s);
37-
vprintf(s,ap); // expected-warning {{format string is not a string literal}}
37+
vprintf(s,ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'check_string_literal2'}}
38+
// expected-note@#check_string_literal2 {{'check_string_literal2' declared here}}
3839
}
3940

4041
void check_string_literal3( FILE* fp, const char* s, ... ) {
@@ -44,10 +45,11 @@ void check_string_literal3( FILE* fp, const char* s, ... ) {
4445
// expected-note@-1{{treat the string as an argument to avoid this}}
4546
}
4647

47-
void check_string_literal4( FILE* fp, const char* s, ... ) {
48+
void check_string_literal4( FILE* fp, const char* s, ... ) { // #check_string_literal4
4849
va_list ap;
4950
va_start(ap,s);
50-
vfprintf(fp,s,ap); // expected-warning {{format string is not a string literal}}
51+
vfprintf(fp,s,ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 3)' attribute to the declaration of 'check_string_literal4'}}
52+
// expected-note@#check_string_literal4 {{'check_string_literal4' declared here}}
5153
}
5254

5355
void check_string_literal5( const char* s, ... ) {
@@ -58,11 +60,12 @@ void check_string_literal5( const char* s, ... ) {
5860
// expected-note@-1{{treat the string as an argument to avoid this}}
5961
}
6062

61-
void check_string_literal6( const char* s, ... ) {
63+
void check_string_literal6( const char* s, ... ) { // #check_string_literal6
6264
char * b;
6365
va_list ap;
6466
va_start(ap,s);
65-
vasprintf(&b,s,ap); // expected-warning {{format string is not a string literal}}
67+
vasprintf(&b,s,ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 2)' attribute to the declaration of 'check_string_literal6'}}
68+
// expected-note@#check_string_literal6 {{'check_string_literal6' declared here}}
6669
}
6770

6871
void check_string_literal7( const char* s, char *buf ) {
@@ -89,16 +92,18 @@ void check_string_literal10( const char* s, char *buf, ... ) {
8992
// expected-note@-1{{treat the string as an argument to avoid this}}
9093
}
9194

92-
void check_string_literal11( const char* s, char *buf, ... ) {
95+
void check_string_literal11( const char* s, char *buf, ... ) { // #check_string_literal11
9396
va_list ap;
9497
va_start(ap,buf);
95-
vsprintf(buf,s,ap); // expected-warning {{format string is not a string lit}}
98+
vsprintf(buf,s,ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 3)' attribute to the declaration of 'check_string_literal11'}}
99+
// expected-note@#check_string_literal11 {{'check_string_literal11' declared here}}
96100
}
97101

98-
void check_string_literal12( const char* s, char *buf, ... ) {
102+
void check_string_literal12( const char* s, char *buf, ... ) { // #check_string_literal12
99103
va_list ap;
100104
va_start(ap,buf);
101-
vsnprintf(buf,2,s,ap); // expected-warning {{format string is not a string lit}}
105+
vsnprintf(buf,2,s,ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 1, 3)' attribute to the declaration of 'check_string_literal12'}}
106+
// expected-note@#check_string_literal12 {{'check_string_literal12' declared here}}
102107
}
103108

104109
void check_string_literal13( char *buf, ... ) {
@@ -107,10 +112,11 @@ void check_string_literal13( char *buf, ... ) {
107112
vsnprintf(buf,2,global_fmt,ap); // expected-warning {{format string is not a string literal}}
108113
}
109114

110-
void check_string_literal14( FILE* fp, const char* s, char *buf, ... ) {
115+
void check_string_literal14( FILE* fp, const char* s, char *buf, ... ) { // #check_string_literal14
111116
va_list ap;
112117
va_start(ap,buf);
113-
__builtin___vsnprintf_chk(buf,2,0,-1,s,ap); // expected-warning {{format string is not a string lit}}
118+
__builtin___vsnprintf_chk(buf,2,0,-1,s,ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(printf, 2, 4)' attribute to the declaration of 'check_string_literal14'}}
119+
// expected-note@#check_string_literal14 {{'check_string_literal14' declared here}}
114120
}
115121

116122
void check_string_literal15( FILE* fp, const char* s, char *buf, ... ) {
@@ -119,10 +125,11 @@ void check_string_literal15( FILE* fp, const char* s, char *buf, ... ) {
119125
__builtin___vsnprintf_chk(buf,2,0,-1,global_fmt,ap); // expected-warning {{format string is not a string literal}}
120126
}
121127

122-
void check_string_literal16(const char* s, ... ) {
128+
void check_string_literal16(const char* s, ... ) { // #check_string_literal16
123129
va_list ap;
124130
va_start(ap,s);
125-
vscanf(s, ap); // expected-warning {{format string is not a string literal}}
131+
vscanf(s, ap); // expected-warning {{diagnostic behavior may be improved by adding the 'format(scanf, 1, 2)' attribute to the declaration of 'check_string_literal16'}}
132+
// expected-note@#check_string_literal16 {{'check_string_literal16' declared here}}
126133
}
127134

128135
void check_string_literal17() {
@@ -911,12 +918,13 @@ void test_block(void) {
911918

912919
void __attribute__((__format__(__printf__, 2, 3))) (^printf_arg2)(
913920
const char *, const char *, ...) =
914-
^(const char *not_fmt, const char *fmt, ...)
921+
^(const char *not_fmt, const char *fmt, ...) // #printf_arg2
915922
__attribute__((__format__(__printf__, 2, 3))) {
916923
va_list ap;
917924
va_start(ap, fmt);
918925
vprintf(fmt, ap);
919-
vprintf(not_fmt, ap); // expected-warning{{format string is not a string literal}}
926+
vprintf(not_fmt, ap); // expected-warning{{diagnostic behavior may be improved by adding the 'format(printf, 1, 3)' attribute to the declaration of block}}
927+
// expected-note@#printf_arg2 {{block declared here}}
920928
va_end(ap);
921929
};
922930

0 commit comments

Comments
 (0)