alexfh created this revision.

Missing 'static' on functions that are intended to be local to a translation
unit seems to be the most common cause of -Wmissing-prototypes warnings, so
suggesting a fix seems to be convenient and useful.


https://reviews.llvm.org/D32170

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaDecl.cpp
  test/SemaCXX/warn-missing-prototypes.cpp

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() {}
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,21 +11687,27 @@
   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
     // scope, because they aren't visible from the header.
     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: 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<DiagGroup<"missing-prototypes">>, DefaultIgnore;
+  InGroup<MissingPrototypes>, DefaultIgnore;
+def warn_missing_prototype_maybe_static : Warning<
+  "no previous prototype for function %0; did you mean to mark the function 'static'?">,
+  InGroup<MissingPrototypes>, 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: 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">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D32170: Add a ... Alexander Kornienko via Phabricator via cfe-commits

Reply via email to