Skip to content

Commit 840f8df

Browse files
committedDec 7, 2016
Implement the -Wstrict-prototypes warning
This commit fixes PR20796. It implements the C only -Wstrict-prototypes warning. Clang now emits a warning for function declarations which have no parameters specified and for K&R function definitions with more than 0 parameters that are not preceded by a previous prototype declaration. The patch was originally submitted by Paul Titei! rdar://15060615 Differential Revision: https://reviews.llvm.org/D16533 llvm-svn: 288896
1 parent 32d5aed commit 840f8df

File tree

5 files changed

+114
-0
lines changed

5 files changed

+114
-0
lines changed
 

‎clang/include/clang/Basic/DiagnosticSemaKinds.td

+4
Original file line numberDiff line numberDiff line change
@@ -4411,6 +4411,10 @@ def warn_missing_prototype : Warning<
44114411
InGroup<DiagGroup<"missing-prototypes">>, DefaultIgnore;
44124412
def note_declaration_not_a_prototype : Note<
44134413
"this declaration is not a prototype; add 'void' to make it a prototype for a zero-parameter function">;
4414+
def warn_strict_prototypes : Warning<
4415+
"this %select{function declaration is not|"
4416+
"old-style function definition is not preceded by}0 a prototype">,
4417+
InGroup<DiagGroup<"strict-prototypes">>, DefaultIgnore;
44144418
def warn_missing_variable_declarations : Warning<
44154419
"no previous extern declaration for non-static variable %0">,
44164420
InGroup<DiagGroup<"missing-variable-declarations">>, DefaultIgnore;

‎clang/lib/Sema/SemaDecl.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -11878,6 +11878,21 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
1187811878
<< FixItHint::CreateInsertion(FTL.getRParenLoc(), "void");
1187911879
}
1188011880
}
11881+
11882+
// GNU warning -Wstrict-prototypes
11883+
// Warn if K&R function is defined without a previous declaration.
11884+
// This warning is issued only if the definition itself does not provide
11885+
// a prototype. Only K&R definitions do not provide a prototype.
11886+
// An empty list in a function declarator that is part of a definition
11887+
// of that function specifies that the function has no parameters
11888+
// (C99 6.7.5.3p14)
11889+
if (!FD->hasWrittenPrototype() && FD->getNumParams() > 0 &&
11890+
!LangOpts.CPlusPlus) {
11891+
TypeSourceInfo *TI = FD->getTypeSourceInfo();
11892+
TypeLoc TL = TI->getTypeLoc();
11893+
FunctionTypeLoc FTL = TL.castAs<FunctionTypeLoc>();
11894+
Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 1;
11895+
}
1188111896
}
1188211897

1188311898
if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {

‎clang/lib/Sema/SemaType.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -4320,6 +4320,19 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
43204320
if (FTI.isAmbiguous)
43214321
warnAboutAmbiguousFunction(S, D, DeclType, T);
43224322

4323+
// GNU warning -Wstrict-prototypes
4324+
// Warn if a function declaration is without a prototype.
4325+
// This warning is issued for all kinds of unprototyped function
4326+
// declarations (i.e. function type typedef, function pointer etc.)
4327+
// C99 6.7.5.3p14:
4328+
// The empty list in a function declarator that is not part of a
4329+
// definition of that function specifies that no information
4330+
// about the number or types of the parameters is supplied.
4331+
if (D.getFunctionDefinitionKind() == FDK_Declaration &&
4332+
FTI.NumParams == 0 && !LangOpts.CPlusPlus)
4333+
S.Diag(DeclType.Loc, diag::warn_strict_prototypes)
4334+
<< 0 << FixItHint::CreateInsertion(FTI.getRParenLoc(), "void");
4335+
43234336
FunctionType::ExtInfo EI(getCCForDeclaratorChunk(S, D, FTI, chunkIndex));
43244337

43254338
if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus) {
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// RUN: %clang_cc1 -fsyntax-only -Wstrict-prototypes -verify %s
2+
// RUN: %clang_cc1 -fsyntax-only -Wstrict-prototypes -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
3+
4+
// function declaration with unspecified params
5+
void foo1(); // expected-warning {{this function declaration is not a prototype}}
6+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:11}:"void"
7+
// function declaration with 0 params
8+
void foo2(void);
9+
10+
// function definition with 0 params(for both cases),
11+
// valid according to 6.7.5.3/14
12+
void foo1() {}
13+
void foo2(void) {}
14+
15+
// function type typedef unspecified params
16+
typedef void foo3(); // expected-warning {{this function declaration is not a prototype}}
17+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:19-[[@LINE-1]]:19}:"void"
18+
19+
// global fp unspecified params
20+
void (*foo4)(); // expected-warning {{this function declaration is not a prototype}}
21+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:14-[[@LINE-1]]:14}:"void"
22+
23+
// struct member fp unspecified params
24+
struct { void (*foo5)(); } s; // expected-warning {{this function declaration is not a prototype}}
25+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:23-[[@LINE-1]]:23}:"void"
26+
27+
// param fp unspecified params
28+
void bar2(void (*foo6)()) { // expected-warning {{this function declaration is not a prototype}}
29+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:24-[[@LINE-1]]:24}:"void"
30+
// local fp unspecified params
31+
void (*foo7)() = 0; // expected-warning {{this function declaration is not a prototype}}
32+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:16-[[@LINE-1]]:16}:"void"
33+
// array fp unspecified params
34+
void (*foo8[2])() = {0}; // expected-warning {{this function declaration is not a prototype}}
35+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:19-[[@LINE-1]]:19}:"void"
36+
}
37+
38+
// function type cast using using an anonymous function declaration
39+
void bar3(void) {
40+
// casting function w/out prototype to unspecified params function type
41+
(void)(void(*)()) foo1; // expected-warning {{this function declaration is not a prototype}}
42+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:18-[[@LINE-1]]:18}:"void"
43+
// .. specified params
44+
(void)(void(*)(void)) foo1;
45+
}
46+
47+
// K&R function definition not preceded by full prototype
48+
int foo9(a, b) // expected-warning {{old-style function definition is not preceded by a prototype}}
49+
int a, b;
50+
{
51+
return a + b;
52+
}
53+
54+
// Function declaration with no types
55+
void foo10(); // expected-warning {{this function declaration is not a prototype}}
56+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:12-[[@LINE-1]]:12}:"void"
57+
// K&R function definition with incomplete param list declared
58+
void foo10(p, p2) void *p; {} // expected-warning {{old-style function definition is not preceded by a prototype}}
59+
60+
// K&R function definition with previous prototype declared is not diagnosed.
61+
void foo11(int p, int p2);
62+
void foo11(p, p2) int p; int p2; {}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %clang_cc1 -fsyntax-only -Wstrict-prototypes -verify -fblocks %s
2+
3+
@interface Foo
4+
5+
@property (nonatomic, copy) void (^noProtoBlock)(); // expected-warning {{this function declaration is not a prototype}}
6+
@property (nonatomic, copy) void (^block)(void); // no warning
7+
8+
- doStuff:(void (^)()) completionHandler; // expected-warning {{this function declaration is not a prototype}}
9+
- doOtherStuff:(void (^)(void)) completionHandler; // no warning
10+
11+
@end
12+
13+
void foo() {
14+
void (^block)() = // expected-warning {{this function declaration is not a prototype}}
15+
^void(int arg) { // no warning
16+
};
17+
void (^block2)(void) = // no warning
18+
^void() { // expected-warning {{this function declaration is not a prototype}}
19+
};
20+
}

0 commit comments

Comments
 (0)
Please sign in to comment.