Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
Implement the -Wstrict-prototypes warning
Browse files Browse the repository at this point in the history
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


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@288896 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
hyp committed Dec 7, 2016
1 parent adfb696 commit 162749f
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 0 deletions.
4 changes: 4 additions & 0 deletions include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -4411,6 +4411,10 @@ def warn_missing_prototype : Warning<
InGroup<DiagGroup<"missing-prototypes">>, DefaultIgnore;
def note_declaration_not_a_prototype : Note<
"this declaration is not a prototype; add 'void' to make it a prototype for a zero-parameter function">;
def warn_strict_prototypes : Warning<
"this %select{function declaration is not|"
"old-style function definition is not preceded by}0 a prototype">,
InGroup<DiagGroup<"strict-prototypes">>, DefaultIgnore;
def warn_missing_variable_declarations : Warning<
"no previous extern declaration for non-static variable %0">,
InGroup<DiagGroup<"missing-variable-declarations">>, DefaultIgnore;
Expand Down
15 changes: 15 additions & 0 deletions lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11878,6 +11878,21 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
<< FixItHint::CreateInsertion(FTL.getRParenLoc(), "void");
}
}

// GNU warning -Wstrict-prototypes
// Warn if K&R function is defined without a previous declaration.
// This warning is issued only if the definition itself does not provide
// a prototype. Only K&R definitions do not provide a prototype.
// An empty list in a function declarator that is part of a definition
// of that function specifies that the function has no parameters
// (C99 6.7.5.3p14)
if (!FD->hasWrittenPrototype() && FD->getNumParams() > 0 &&
!LangOpts.CPlusPlus) {
TypeSourceInfo *TI = FD->getTypeSourceInfo();
TypeLoc TL = TI->getTypeLoc();
FunctionTypeLoc FTL = TL.castAs<FunctionTypeLoc>();
Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 1;
}
}

if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
Expand Down
13 changes: 13 additions & 0 deletions lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4320,6 +4320,19 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (FTI.isAmbiguous)
warnAboutAmbiguousFunction(S, D, DeclType, T);

// GNU warning -Wstrict-prototypes
// Warn if a function declaration is without a prototype.
// This warning is issued for all kinds of unprototyped function
// declarations (i.e. function type typedef, function pointer etc.)
// C99 6.7.5.3p14:
// The empty list in a function declarator that is not part of a
// definition of that function specifies that no information
// about the number or types of the parameters is supplied.
if (D.getFunctionDefinitionKind() == FDK_Declaration &&
FTI.NumParams == 0 && !LangOpts.CPlusPlus)
S.Diag(DeclType.Loc, diag::warn_strict_prototypes)
<< 0 << FixItHint::CreateInsertion(FTI.getRParenLoc(), "void");

FunctionType::ExtInfo EI(getCCForDeclaratorChunk(S, D, FTI, chunkIndex));

if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus) {
Expand Down
62 changes: 62 additions & 0 deletions test/Sema/warn-strict-prototypes.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// RUN: %clang_cc1 -fsyntax-only -Wstrict-prototypes -verify %s
// RUN: %clang_cc1 -fsyntax-only -Wstrict-prototypes -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s

// function declaration with unspecified params
void foo1(); // expected-warning {{this function declaration is not a prototype}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:11}:"void"
// function declaration with 0 params
void foo2(void);

// function definition with 0 params(for both cases),
// valid according to 6.7.5.3/14
void foo1() {}
void foo2(void) {}

// function type typedef unspecified params
typedef void foo3(); // expected-warning {{this function declaration is not a prototype}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:19-[[@LINE-1]]:19}:"void"

// global fp unspecified params
void (*foo4)(); // expected-warning {{this function declaration is not a prototype}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:14-[[@LINE-1]]:14}:"void"

// struct member fp unspecified params
struct { void (*foo5)(); } s; // expected-warning {{this function declaration is not a prototype}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:23-[[@LINE-1]]:23}:"void"

// param fp unspecified params
void bar2(void (*foo6)()) { // expected-warning {{this function declaration is not a prototype}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:24-[[@LINE-1]]:24}:"void"
// local fp unspecified params
void (*foo7)() = 0; // expected-warning {{this function declaration is not a prototype}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:16-[[@LINE-1]]:16}:"void"
// array fp unspecified params
void (*foo8[2])() = {0}; // expected-warning {{this function declaration is not a prototype}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:19-[[@LINE-1]]:19}:"void"
}

// function type cast using using an anonymous function declaration
void bar3(void) {
// casting function w/out prototype to unspecified params function type
(void)(void(*)()) foo1; // expected-warning {{this function declaration is not a prototype}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:18-[[@LINE-1]]:18}:"void"
// .. specified params
(void)(void(*)(void)) foo1;
}

// K&R function definition not preceded by full prototype
int foo9(a, b) // expected-warning {{old-style function definition is not preceded by a prototype}}
int a, b;
{
return a + b;
}

// Function declaration with no types
void foo10(); // expected-warning {{this function declaration is not a prototype}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:12-[[@LINE-1]]:12}:"void"
// K&R function definition with incomplete param list declared
void foo10(p, p2) void *p; {} // expected-warning {{old-style function definition is not preceded by a prototype}}

// K&R function definition with previous prototype declared is not diagnosed.
void foo11(int p, int p2);
void foo11(p, p2) int p; int p2; {}
20 changes: 20 additions & 0 deletions test/Sema/warn-strict-prototypes.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: %clang_cc1 -fsyntax-only -Wstrict-prototypes -verify -fblocks %s

@interface Foo

@property (nonatomic, copy) void (^noProtoBlock)(); // expected-warning {{this function declaration is not a prototype}}
@property (nonatomic, copy) void (^block)(void); // no warning

- doStuff:(void (^)()) completionHandler; // expected-warning {{this function declaration is not a prototype}}
- doOtherStuff:(void (^)(void)) completionHandler; // no warning

@end

void foo() {
void (^block)() = // expected-warning {{this function declaration is not a prototype}}
^void(int arg) { // no warning
};
void (^block2)(void) = // no warning
^void() { // expected-warning {{this function declaration is not a prototype}}
};
}

0 comments on commit 162749f

Please sign in to comment.