[clang] clang should have a warning to disallow re-externs (PR #109714)

2024-10-09 Thread Jeffrey Crowell via cfe-commits

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 
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, 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 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(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 fi

[clang] clang should have a warning to disallow re-externs (PR #109714)

2024-10-09 Thread Jeffrey Crowell via cfe-commits

jchcrsp wrote:

Ping

fixed merge conflict

https://github.com/llvm/llvm-project/pull/109714
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] clang should have a warning to disallow re-externs (PR #109714)

2024-09-23 Thread Jeffrey Crowell via cfe-commits

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 
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, 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 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(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(

[clang] clang should have a warning to disallow re-externs (PR #109714)

2024-10-01 Thread Jeffrey Crowell via cfe-commits

jchcrsp wrote:

Ping

https://github.com/llvm/llvm-project/pull/109714
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits