From f1b876d5dee320019ef9819810ac5b76df5ec465 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 31 Mar 2009 16:35:03 +0000 Subject: [PATCH] Implement -Wmissing-prototypes. Fixes PR3911. llvm-svn: 68110 --- clang/include/clang/AST/Decl.h | 3 +++ .../clang/Basic/DiagnosticSemaKinds.td | 1 + clang/include/clang/Driver/Options.def | 2 ++ clang/lib/AST/Decl.cpp | 20 +++++++++++++++++ clang/lib/Sema/SemaDecl.cpp | 22 +++++++++++++++++++ clang/tools/clang-cc/Warnings.cpp | 5 +++++ 6 files changed, 53 insertions(+) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 69bb13a520cc..39a990a2dbc6 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -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 { diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 69f18214b8f1..b16e15ea0b46 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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">; diff --git a/clang/include/clang/Driver/Options.def b/clang/include/clang/Driver/Options.def index dc5dd85cec41..11668bb59083 100644 --- a/clang/include/clang/Driver/Options.def +++ b/clang/include/clang/Driver/Options.def @@ -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) diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 15a20bd050cc..f0d32c75de60 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -341,6 +341,26 @@ bool FunctionDecl::isExternC(ASTContext &Context) const { return false; } +bool FunctionDecl::isGlobal() const { + if (const CXXMethodDecl *Method = dyn_cast(this)) + return Method->isStatic(); + + if (getStorageClass() == Static) + return false; + + for (const DeclContext *DC = getDeclContext(); + DC->isNamespace(); + DC = DC->getParent()) { + if (const NamespaceDecl *Namespace = cast(DC)) { + if (!Namespace->getDeclName()) + return false; + break; + } + } + + return true; +} + /// \brief Returns a value indicating whether this function /// corresponds to a builtin function. /// diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index be9a0e24d1f0..584d2b11f9a0 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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(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 diff --git a/clang/tools/clang-cc/Warnings.cpp b/clang/tools/clang-cc/Warnings.cpp index 698e44fb7d4c..be93c67fa967 100644 --- a/clang/tools/clang-cc/Warnings.cpp +++ b/clang/tools/clang-cc/Warnings.cpp @@ -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();