]> granicus.if.org Git - clang/commitdiff
Implement -Wmissing-prototypes. Fixes PR3911.
authorDouglas Gregor <dgregor@apple.com>
Tue, 31 Mar 2009 16:35:03 +0000 (16:35 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 31 Mar 2009 16:35:03 +0000 (16:35 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68110 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Driver/Options.def
lib/AST/Decl.cpp
lib/Sema/SemaDecl.cpp
tools/clang-cc/Warnings.cpp

index 69bb13a520cce6846944697f0a0caa2537f7d27b..39a990a2dbc6e0543e9b9150f71b74fd1dbfebaf 100644 (file)
@@ -670,6 +670,9 @@ public:
   /// external, C linkage.
   bool isExternC(ASTContext &Context) const;
 
+  /// \brief Determines whether this is a global function.
+  bool isGlobal() const;
+
   /// getPreviousDeclaration - Return the previous declaration of this
   /// function.
   const FunctionDecl *getPreviousDeclaration() const {
index 69f18214b8f1507cc6cc21bda0c00b6f658acd8e..b16e15ea0b4659aeea10ea687212154e5daf5348 100644 (file)
@@ -712,6 +712,7 @@ def warn_deprecated : Warning<"%0 is deprecated">;
 def warn_unavailable : Warning<"%0 is unavailable">;
 def note_unavailable_here : Note<
   "function has been explicitly marked %select{unavailable|deleted}0 here">;
+def warn_missing_prototype : Warning<"no previous prototype for function %0">;
 def err_redefinition : Error<"redefinition of %0">;
 def err_static_non_static : Error<
   "static declaration of %0 follows non-static declaration">;
index dc5dd85cec41afcfc0055dcc0c03b7e11c25b246..11668bb590832181045b174167f03c081574455f 100644 (file)
@@ -276,12 +276,14 @@ OPTION("-Winline", Winline, Flag, clang_ignored_W_Group, INVALID, "", 0)
 OPTION("-Wint-to-pointer-cast", Wint_to_pointer_cast, Flag, clang_ignored_W_Group, INVALID, "", 0)
 OPTION("-Wl,", Wl_COMMA, CommaJoined, INVALID, INVALID, "li", 0)
 OPTION("-Wmissing-braces", Wmissing_braces, Flag, clang_ignored_W_Group, INVALID, "", 0)
+OPTION("-Wmissing-prototypes", Wmissing_prototypes, Flag, clang_W_Group, INVALID, "", 0)
 OPTION("-Wmost", Wmost, Flag, clang_ignored_W_Group, INVALID, "", 0)
 OPTION("-Wnested-externs", Wnested_externs, Flag, clang_ignored_W_Group, INVALID, "", 0)
 OPTION("-Wno-format-nonliteral", Wno_format_nonliteral, Flag, clang_W_Group, INVALID, "", 0)
 OPTION("-Wno-format-y2k", Wno_format_y2k, Flag, clang_ignored_W_Group, INVALID, "", 0)
 OPTION("-Wno-four-char-constants", Wno_four_char_constants, Flag, clang_ignored_W_Group, INVALID, "", 0)
 OPTION("-Wno-missing-field-initializers", Wno_missing_field_initializers, Flag, clang_ignored_W_Group, INVALID, "", 0)
+OPTION("-Wno-missing-prototypes", Wno_missing_prototypes, Flag, clang_W_Group, INVALID, "", 0)
 OPTION("-Wno-nonportable-cfstrings", Wno_nonportable_cfstrings, Joined, W_Group, INVALID, "", 0)
 OPTION("-Wno-pointer-sign", Wno_pointer_sign, Flag, clang_W_Group, INVALID, "", 0)
 OPTION("-Wno-strict-selector-match", Wno_strict_selector_match, Flag, clang_W_Group, INVALID, "", 0)
index 15a20bd050cc440bb93cd1c23b392fe3653b0dac..f0d32c75de60802389cf6ceac1470f75c16e76b4 100644 (file)
@@ -341,6 +341,26 @@ bool FunctionDecl::isExternC(ASTContext &Context) const {
   return false;
 }
 
+bool FunctionDecl::isGlobal() const {
+  if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(this))
+    return Method->isStatic();
+
+  if (getStorageClass() == Static)
+    return false;
+
+  for (const DeclContext *DC = getDeclContext(); 
+       DC->isNamespace();
+       DC = DC->getParent()) {
+    if (const NamespaceDecl *Namespace = cast<NamespaceDecl>(DC)) {
+      if (!Namespace->getDeclName())
+        return false;
+      break;
+    }
+  }
+
+  return true;
+}
+
 /// \brief Returns a value indicating whether this function
 /// corresponds to a builtin function.
 ///
index be9a0e24d1f06b3c654779849cc4423fe070ed2a..584d2b11f9a01e5452132e1d08d29a74733cb876 100644 (file)
@@ -2741,6 +2741,28 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
                           diag::err_func_def_incomplete_result))
     FD->setInvalidDecl();
 
+  // GNU warning -Wmissing-prototypes:
+  //   Warn if a global function is defined without a previous
+  //   prototype declaration. This warning is issued even if the
+  //   definition itself provides a prototype. The aim is to detect
+  //   global functions that fail to be declared in header files.
+  if (!FD->isInvalidDecl() && FD->isGlobal() && !isa<CXXMethodDecl>(FD)) {
+    bool MissingPrototype = true;
+    for (const FunctionDecl *Prev = FD->getPreviousDeclaration();
+         Prev; Prev = Prev->getPreviousDeclaration()) {
+      // Ignore any declarations that occur in function or method
+      // scope, because they aren't visible from the header.
+      if (Prev->getDeclContext()->isFunctionOrMethod())
+        continue;
+
+      MissingPrototype = !Prev->getType()->isFunctionProtoType();
+      break;
+    }
+
+    if (MissingPrototype)
+      Diag(FD->getLocation(), diag::warn_missing_prototype) << FD;
+  }
+
   PushDeclContext(FnBodyScope, FD);
 
   // Check the validity of our function parameters
index 698e44fb7d4cb92bacc9a2902356510eab090ec8..be93c67fa9672a504b9c8ad41ac5538397cb396b 100644 (file)
@@ -140,6 +140,9 @@ static const diag::kind PointerSignDiags[] = {
   diag::ext_typecheck_convert_incompatible_pointer_sign
 };
 static const diag::kind DeprecatedDeclarations[] = { diag::warn_deprecated };
+static const diag::kind MissingPrototypesDiags[] = { 
+  diag::warn_missing_prototype 
+};
 
 // Hmm ... this option is currently actually completely ignored.
 //static const diag::kind StrictSelectorMatchDiags[] = {  };
@@ -149,6 +152,7 @@ static const WarningOption OptionTable[] = {
   { "float-equal",           DIAGS(FloatEqualDiags) },
   { "format-nonliteral",     DIAGS(FormatNonLiteralDiags) },
   { "implicit-function-declaration", DIAGS(ImplicitFunctionDeclarationDiags) },
+  { "missing-prototypes", DIAGS(MissingPrototypesDiags) },
   { "pointer-sign",          DIAGS(PointerSignDiags) },
   { "readonly-setter-attrs", DIAGS(ReadOnlySetterAttrsDiags) },
   { "undef",                 DIAGS(UndefDiags) },
@@ -179,6 +183,7 @@ bool ProcessWarningOptions(Diagnostic &Diags) {
   Diags.setDiagnosticMapping(diag::err_pp_file_not_found, diag::MAP_FATAL);
   Diags.setDiagnosticMapping(diag::err_template_recursion_depth_exceeded, 
                              diag::MAP_FATAL);
+  Diags.setDiagnosticMapping(diag::warn_missing_prototype, diag::MAP_IGNORE);
   Diags.setSuppressSystemWarnings(!OptWarnInSystemHeaders);
 
   for (OptionsList::iterator it = Options.begin(), e = Options.end();