https://github.com/jchcrsp updated https://github.com/llvm/llvm-project/pull/109714
>From 8f512e2a8ad110b1a74c4283f81d4e28555e7567 Mon Sep 17 00:00:00 2001 From: Jeffrey Crowell <j...@apple.com> Date: Mon, 23 Sep 2024 16:17:32 -0400 Subject: [PATCH] clang should have a warning to disallow re-externs clang should have a warning to disallow re-externs from the main C translation unit for example, it would be helpful to warn programmers in this situation ```c // file1.c extern int func(int a, int b); int some_func() { func(1,2); } ``` ```c // file2.c int func(int a, int b, char *c, int d) { // function body } ``` --- clang/include/clang/Basic/DiagnosticGroups.td | 3 ++ .../clang/Basic/DiagnosticSemaKinds.td | 6 ++++ clang/include/clang/Sema/Sema.h | 9 +++++ clang/lib/Sema/Sema.cpp | 2 ++ clang/lib/Sema/SemaDecl.cpp | 34 +++++++++++++++++++ .../Sema/warn-extern-func-not-in-header.c | 13 +++++++ 6 files changed, 67 insertions(+) create mode 100644 clang/test/Sema/warn-extern-func-not-in-header.c diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 7d81bdf827ea0c..9e8bd587094423 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1582,3 +1582,6 @@ def ExtractAPIMisuse : DiagGroup<"extractapi-misuse">; // Warnings about using the non-standard extension having an explicit specialization // with a storage class specifier. def ExplicitSpecializationStorageClass : DiagGroup<"explicit-specialization-storage-class">; + +// Warnings about extern functions not in header files. +def ExternalDeclaration : DiagGroup<"external-declaration">; \ No newline at end of file diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e4e04bff8b5120..16529dab1e245d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12614,4 +12614,10 @@ def err_acc_loop_spec_conflict // AMDGCN builtins diagnostics def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">; def note_amdgcn_global_load_lds_size_valid_value : Note<"size must be 1, 2, or 4">; + +// SemaExternWarning diagnostics +def warn_extern_func_not_in_header : Warning< + "extern function '%0' declared in main file '%1' instead of a header">, + InGroup<ExternalDeclaration>, DefaultIgnore; + } // end of sema component. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index e1c3a99cfa167e..76a9f4c84f47f7 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4390,6 +4390,15 @@ class Sema final : public SemaBase { // linkage or not. static bool mightHaveNonExternalLinkage(const DeclaratorDecl *FD); + ///@} + /// \name CheckExternFunction + ///@{ +public: + void CheckExternDecl(Decl *D); + void CheckDeferredExternDecls(); + +private: + std::vector<FunctionDecl *> ExternFuncDecls; ///@} // diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 6d7a57d7b5a41a..4a4aefcd38e4c7 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1177,6 +1177,8 @@ void Sema::ActOnEndOfTranslationUnit() { if (PP.isCodeCompletionEnabled()) return; + CheckDeferredExternDecls(); + // Complete translation units and modules define vtables and perform implicit // instantiations. PCH files do not. if (TUKind != TU_Prefix) { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 31bf50a32a83c3..e2dbf9521aec6c 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6058,6 +6058,10 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { Dcl && Dcl->getDeclContext()->isFileContext()) Dcl->setTopLevelDeclInObjCContainer(); + if (Dcl) { + CheckExternDecl(Dcl); + } + if (!Bases.empty()) OpenMP().ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(Dcl, Bases); @@ -20354,3 +20358,33 @@ bool Sema::diagnoseConflictingFunctionEffect( return false; } + +void Sema::CheckExternDecl(Decl *D) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + SourceLocation Loc = FD->getLocation(); + SourceManager &SM = Context.getSourceManager(); + + // Only consider extern function declarations (not definitions) in the main + // file + if (FD->isExternC() && !FD->isImplicit() && !FD->getBuiltinID() && + !FD->hasBody() && !FD->isThisDeclarationADefinition() && + FD->isFirstDecl() && SM.isInMainFile(Loc)) { + // Defer the warning check until the end of the translation unit + ExternFuncDecls.push_back(FD); + } + } +} + +void Sema::CheckDeferredExternDecls() { + SourceManager &SM = Context.getSourceManager(); + for (FunctionDecl *FD : ExternFuncDecls) { + // Check if there's a definition in the same file + const FunctionDecl *Definition = FD->getDefinition(); + if (!Definition || !SM.isInMainFile(Definition->getLocation())) { + SourceLocation Loc = FD->getLocation(); + Diag(Loc, diag::warn_extern_func_not_in_header) + << FD->getName() << SM.getFilename(Loc); + } + } + ExternFuncDecls.clear(); +} diff --git a/clang/test/Sema/warn-extern-func-not-in-header.c b/clang/test/Sema/warn-extern-func-not-in-header.c new file mode 100644 index 00000000000000..62ba2a00400dd6 --- /dev/null +++ b/clang/test/Sema/warn-extern-func-not-in-header.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wexternal-declaration %s + +extern int +foo(int); // expected-warning{{extern function 'foo' declared in main file}} + +int bar(int); +int bar(int x) { + return x + 1; +} + +int main() { + return foo(42) + bar(10); +} \ No newline at end of file _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits