Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -285,6 +285,7 @@ def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">; def MismatchedTags : DiagGroup<"mismatched-tags">; def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; +def MissingPrototypes : DiagGroup<"missing-prototypes">; def ModuleBuild : DiagGroup<"module-build">; def ModuleConflict : DiagGroup<"module-conflict">; def ModuleFileExtension : DiagGroup<"module-file-extension">; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -4545,9 +4545,12 @@ "%select{function|method|block}0 has been explicitly marked sentinel here">; def warn_missing_prototype : Warning< "no previous prototype for function %0">, - InGroup>, DefaultIgnore; + InGroup, DefaultIgnore; +def warn_missing_prototype_maybe_static : Warning< + "no previous prototype for function %0; did you mean to mark the function 'static'?">, + InGroup, 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">; + "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">, Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -11649,7 +11649,8 @@ } static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD, - const FunctionDecl*& PossibleZeroParamPrototype) { + const FunctionDecl*& PossibleZeroParamPrototype, + bool *PossibleMissingStatic) { // Don't warn about invalid declarations. if (FD->isInvalidDecl()) return false; @@ -11686,7 +11687,6 @@ if (FD->isDeleted()) return false; - bool MissingPrototype = true; for (const FunctionDecl *Prev = FD->getPreviousDecl(); Prev; Prev = Prev->getPreviousDecl()) { // Ignore any declarations that occur in function or method @@ -11694,13 +11694,20 @@ if (Prev->getLexicalDeclContext()->isFunctionOrMethod()) continue; - MissingPrototype = !Prev->getType()->isFunctionProtoType(); + if (Prev->getType()->isFunctionProtoType()) + return false; + if (FD->getNumParams() == 0) PossibleZeroParamPrototype = Prev; break; } - return MissingPrototype; + // Check whether applying a 'static' could make sense for this function. + *PossibleMissingStatic = FD->getDeclContext() && + FD->getDeclContext()->isTranslationUnit() && + FD->getStorageClass() == SC_None; + + return true; } void @@ -12099,8 +12106,19 @@ // definition itself provides a prototype. The aim is to detect // global functions that fail to be declared in header files. const FunctionDecl *PossibleZeroParamPrototype = nullptr; - if (ShouldWarnAboutMissingPrototype(FD, PossibleZeroParamPrototype)) { - Diag(FD->getLocation(), diag::warn_missing_prototype) << FD; + bool PossibleMissingStatic = false; + if (ShouldWarnAboutMissingPrototype(FD, PossibleZeroParamPrototype, + &PossibleMissingStatic)) { + if (PossibleMissingStatic) { + auto DiagBuilder = + Diag(FD->getLocation(), diag::warn_missing_prototype_maybe_static) + << FD; + SourceLocation Loc = FD->getLocStart(); + if (Loc.isFileID()) + DiagBuilder << FixItHint::CreateInsertion(Loc, "static "); + } else { + Diag(FD->getLocation(), diag::warn_missing_prototype) << FD; + } if (PossibleZeroParamPrototype) { // We found a declaration that is not a prototype, Index: test/SemaCXX/warn-missing-prototypes.cpp =================================================================== --- test/SemaCXX/warn-missing-prototypes.cpp +++ test/SemaCXX/warn-missing-prototypes.cpp @@ -1,6 +1,22 @@ // RUN: %clang_cc1 -fsyntax-only -verify -Wmissing-prototypes -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -Wmissing-prototypes -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s -implicit-check-not=fix-it: -void f() { } // expected-warning {{no previous prototype for function 'f'}} +void f() { } // expected-warning {{no previous prototype for function 'f'; did you mean to mark the function 'static'?}} +// CHECK: fix-it:"{{.*}}":{4:1-4:1}:"static " + +#define F2 void f2() { } + +F2 // expected-warning {{no previous prototype for function 'f2'}} + +extern void f3() {} // expected-warning {{no previous prototype for function 'f3'}} +extern "C" void f4() {} // expected-warning {{no previous prototype for function 'f4'}} +extern "C++" void f5() {} // expected-warning {{no previous prototype for function 'f5'}} +extern "C" { + void f6() {} // expected-warning {{no previous prototype for function 'f6'}} +} +extern "C++" { + void f7() {} // expected-warning {{no previous prototype for function 'f7'}} +} namespace NS { void f() { } // expected-warning {{no previous prototype for function 'f'}} @@ -16,6 +32,7 @@ void f() { } }; + // Don't warn about inline functions. inline void g() { } @@ -32,3 +49,6 @@ // Don't warn on explicitly deleted functions. void j() = delete; + +// Don't warn on static functions. +static void s() {}