[clang] clang should have a warning to disallow re-externs (PR #109714)
Jeffrey Crowell via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 23 13:24:03 PDT 2024
https://github.com/jchcrsp created https://github.com/llvm/llvm-project/pull/109714
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
}
```
>From 8f512e2a8ad110b1a74c4283f81d4e28555e7567 Mon Sep 17 00:00:00 2001
From: Jeffrey Crowell <jeff at 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
More information about the cfe-commits
mailing list