https://github.com/BStott6 updated 
https://github.com/llvm/llvm-project/pull/166542

>From 8b4ff4f264b471e77da96b8161829a9208a316bb Mon Sep 17 00:00:00 2001
From: BStott <[email protected]>
Date: Wed, 5 Nov 2025 12:08:56 +0000
Subject: [PATCH 1/2] [Clang] Warn when `std::atomic_thread_fence` is used with
 `fsanitize=thread`

---
 clang/include/clang/Basic/DiagnosticGroups.td |  2 ++
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 ++
 clang/include/clang/Sema/Sema.h               |  2 ++
 clang/lib/Sema/SemaChecking.cpp               | 34 +++++++++++++++++++
 clang/test/SemaCXX/warn-tsan-atomic-fence.cpp | 11 ++++++
 5 files changed, 52 insertions(+)
 create mode 100644 clang/test/SemaCXX/warn-tsan-atomic-fence.cpp

diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 8aa3489a2a62b..489b9f5ec552b 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1769,3 +1769,5 @@ def ExplicitSpecializationStorageClass : 
DiagGroup<"explicit-specialization-stor
 
 // A warning for options that enable a feature that is not yet complete
 def ExperimentalOption : DiagGroup<"experimental-option">;
+
+def TSan : DiagGroup<"tsan">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4e369be0bbb92..928b52b3d41f0 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -112,6 +112,9 @@ def warn_max_unsigned_zero : Warning<
   "%select{a value and unsigned zero|unsigned zero and a value}0 "
   "is always equal to the other value">,
   InGroup<MaxUnsignedZero>;
+def warn_atomic_thread_fence_with_tsan : Warning<
+  "`std::atomic_thread_fence` is not supported with `-fsanitize=thread`">,
+  InGroup<TSan>;
 def note_remove_max_call : Note<
   "remove call to max function and unsigned zero argument">;
 
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index c67ed99b1f49e..99e486179dd2e 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3033,6 +3033,8 @@ class Sema final : public SemaBase {
 
   void CheckMaxUnsignedZero(const CallExpr *Call, const FunctionDecl *FDecl);
 
+  void CheckUseOfAtomicThreadFenceWithTSan(const CallExpr *Call, const 
FunctionDecl *FDecl);
+
   /// Check for dangerous or invalid arguments to memset().
   ///
   /// This issues warnings on known problematic, dangerous or unspecified
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ad2c2e4a97bb9..13b61ea453f80 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -45,6 +45,7 @@
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/LangOptions.h"
+#include "clang/Basic/NoSanitizeList.h"
 #include "clang/Basic/OpenCLOptions.h"
 #include "clang/Basic/OperatorKinds.h"
 #include "clang/Basic/PartialDiagnostic.h"
@@ -4100,6 +4101,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, 
CallExpr *TheCall,
   CheckAbsoluteValueFunction(TheCall, FDecl);
   CheckMaxUnsignedZero(TheCall, FDecl);
   CheckInfNaNFunction(TheCall, FDecl);
+  CheckUseOfAtomicThreadFenceWithTSan(TheCall, FDecl);
 
   if (getLangOpts().ObjC)
     ObjC().DiagnoseCStringFormatDirectiveInCFAPI(FDecl, Args, NumArgs);
@@ -9822,6 +9824,38 @@ void Sema::CheckMaxUnsignedZero(const CallExpr *Call,
         << FixItHint::CreateRemoval(RemovalRange);
 }
 
+//===--- CHECK: Warn on use of `std::atomic_thread_fence` with TSan. 
------===//
+void Sema::CheckUseOfAtomicThreadFenceWithTSan(const CallExpr *Call,
+                                               const FunctionDecl *FDecl) {
+  // Thread sanitizer currently does not support `std::atomic_thread_fence`,
+  // leading to false positive. Example issue:
+  // https://github.com/llvm/llvm-project/issues/52942
+
+  if (!Call || !FDecl)
+    return;
+
+  if (!IsStdFunction(FDecl, "atomic_thread_fence"))
+    return;
+
+  // See if TSan is enabled in this function
+  const auto EnabledTSanMask =
+      Context.getLangOpts().Sanitize.Mask & (SanitizerKind::Thread);
+  if (!EnabledTSanMask)
+    return;
+
+  const auto &NoSanitizeList = Context.getNoSanitizeList();
+  if (NoSanitizeList.containsLocation(EnabledTSanMask,
+                                      Call->getSourceRange().getBegin()))
+    // File is excluded
+    return;
+  if (NoSanitizeList.containsFunction(EnabledTSanMask,
+                                      FDecl->getQualifiedNameAsString()))
+    // Function is excluded
+    return;
+
+  Diag(Call->getExprLoc(), diag::warn_atomic_thread_fence_with_tsan);
+}
+
 //===--- CHECK: Standard memory functions 
---------------------------------===//
 
 /// Takes the expression passed to the size_t parameter of functions
diff --git a/clang/test/SemaCXX/warn-tsan-atomic-fence.cpp 
b/clang/test/SemaCXX/warn-tsan-atomic-fence.cpp
new file mode 100644
index 0000000000000..b8720260fe1c1
--- /dev/null
+++ b/clang/test/SemaCXX/warn-tsan-atomic-fence.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang -std=c++17 %s 2>&1 | FileCheck %s --check-prefix=NO-TSAN 
--allow-empty
+// RUN: %clang -std=c++17 -fsanitize=thread %s 2>&1 | FileCheck %s 
--check-prefix=WITH-TSAN
+
+// WITH-TSAN: `std::atomic_thread_fence` is not supported with 
`-fsanitize=thread`
+// NO-TSAN-NOT: `std::atomic_thread_fence` is not supported with 
`-fsanitize=thread`
+
+#include <atomic>
+
+int main() {
+    std::atomic_thread_fence(std::memory_order::memory_order_relaxed);
+}

>From 25585490503c017ed2055765cff01c1b7b8482d1 Mon Sep 17 00:00:00 2001
From: BStott <[email protected]>
Date: Thu, 6 Nov 2025 10:57:30 +0000
Subject: [PATCH 2/2] Implement suggestions, fix handling of ignored functions,
 handle nosanitize attributes

---
 clang/docs/ReleaseNotes.rst                   |  2 +
 clang/include/clang/Basic/DiagnosticGroups.td |  2 -
 .../clang/Basic/DiagnosticSemaKinds.td        |  4 +-
 clang/lib/Sema/SemaChecking.cpp               | 26 ++++++++---
 clang/test/SemaCXX/warn-tsan-atomic-fence.cpp | 45 ++++++++++++++++---
 5 files changed, 62 insertions(+), 17 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92fc9381a5868..d5a1a7fa9b5fc 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -349,6 +349,8 @@ Improvements to Clang's diagnostics
 - Fixed false positives in ``-Waddress-of-packed-member`` diagnostics when
   potential misaligned members get processed before they can get discarded.
   (#GH144729)
+- Clang now emits a warning when `std::atomic_thread_fence` is used with 
`-fsanitize=thread` as this can
+  lead to false positives. (This can be disabled with ``-Wno-tsan``)
 
 - Clang now emits dignostic with correct message in case of assigning to const 
reference captured in lambda. (#GH105647)
 
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 489b9f5ec552b..8aa3489a2a62b 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1769,5 +1769,3 @@ def ExplicitSpecializationStorageClass : 
DiagGroup<"explicit-specialization-stor
 
 // A warning for options that enable a feature that is not yet complete
 def ExperimentalOption : DiagGroup<"experimental-option">;
-
-def TSan : DiagGroup<"tsan">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 928b52b3d41f0..c90b018f64f81 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -113,8 +113,8 @@ def warn_max_unsigned_zero : Warning<
   "is always equal to the other value">,
   InGroup<MaxUnsignedZero>;
 def warn_atomic_thread_fence_with_tsan : Warning<
-  "`std::atomic_thread_fence` is not supported with `-fsanitize=thread`">,
-  InGroup<TSan>;
+  "'std::atomic_thread_fence' is not supported with '-fsanitize=thread'">,
+  InGroup<DiagGroup<"tsan">>;
 def note_remove_max_call : Note<
   "remove call to max function and unsigned zero argument">;
 
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 13b61ea453f80..8621e1db4e561 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -9828,7 +9828,7 @@ void Sema::CheckMaxUnsignedZero(const CallExpr *Call,
 void Sema::CheckUseOfAtomicThreadFenceWithTSan(const CallExpr *Call,
                                                const FunctionDecl *FDecl) {
   // Thread sanitizer currently does not support `std::atomic_thread_fence`,
-  // leading to false positive. Example issue:
+  // leading to false positives. Example issue:
   // https://github.com/llvm/llvm-project/issues/52942
 
   if (!Call || !FDecl)
@@ -9837,22 +9837,34 @@ void Sema::CheckUseOfAtomicThreadFenceWithTSan(const 
CallExpr *Call,
   if (!IsStdFunction(FDecl, "atomic_thread_fence"))
     return;
 
-  // See if TSan is enabled in this function
+  // Check that TSan is enabled in this context
   const auto EnabledTSanMask =
       Context.getLangOpts().Sanitize.Mask & (SanitizerKind::Thread);
   if (!EnabledTSanMask)
     return;
 
+  // Check that the file isn't in the no-sanitize list
   const auto &NoSanitizeList = Context.getNoSanitizeList();
   if (NoSanitizeList.containsLocation(EnabledTSanMask,
                                       Call->getSourceRange().getBegin()))
-    // File is excluded
-    return;
-  if (NoSanitizeList.containsFunction(EnabledTSanMask,
-                                      FDecl->getQualifiedNameAsString()))
-    // Function is excluded
     return;
 
+  // Check that the calling function:
+  //  - Does not have any attributes preventing TSan checking
+  //  - Is not in the ignore list
+  if (const NamedDecl *Caller = getCurFunctionOrMethodDecl()) {
+    if (Caller->hasAttr<DisableSanitizerInstrumentationAttr>())
+      return;
+
+    for (const auto *Attr : Caller->specific_attrs<NoSanitizeAttr>())
+      if (Attr->getMask() & SanitizerKind::Thread)
+        return;
+
+    if (NoSanitizeList.containsFunction(EnabledTSanMask,
+                                        Caller->getQualifiedNameAsString()))
+      return;
+  }
+
   Diag(Call->getExprLoc(), diag::warn_atomic_thread_fence_with_tsan);
 }
 
diff --git a/clang/test/SemaCXX/warn-tsan-atomic-fence.cpp 
b/clang/test/SemaCXX/warn-tsan-atomic-fence.cpp
index b8720260fe1c1..ae0afbed749d7 100644
--- a/clang/test/SemaCXX/warn-tsan-atomic-fence.cpp
+++ b/clang/test/SemaCXX/warn-tsan-atomic-fence.cpp
@@ -1,11 +1,44 @@
-// RUN: %clang -std=c++17 %s 2>&1 | FileCheck %s --check-prefix=NO-TSAN 
--allow-empty
-// RUN: %clang -std=c++17 -fsanitize=thread %s 2>&1 | FileCheck %s 
--check-prefix=WITH-TSAN
+// No warnings in regular compile
+// RUN: %clang_cc1 -verify=no-tsan %s
 
-// WITH-TSAN: `std::atomic_thread_fence` is not supported with 
`-fsanitize=thread`
-// NO-TSAN-NOT: `std::atomic_thread_fence` is not supported with 
`-fsanitize=thread`
+// Emits warning with `-fsanitize=thread`
+// RUN: %clang_cc1 -verify=with-tsan -fsanitize=thread %s
 
-#include <atomic>
+// No warnings if `-Wno-tsan` is passed
+// RUN: %clang_cc1 -verify=no-tsan -fsanitize=thread -Wno-tsan %s
+
+// Ignoring function
+// RUN: echo "fun:main" > %t
+// RUN: %clang_cc1 -verify=no-tsan -fsanitize=thread -fsanitize-ignorelist=%t 
%s
+
+// Ignoring source file
+// RUN: echo "src:%s" > %t
+// RUN: %clang_cc1 -verify=no-tsan -fsanitize=thread -fsanitize-ignorelist=%t 
%s
+
+// no-tsan-no-diagnostics
+
+namespace std {
+  enum memory_order {
+    memory_order_relaxed,
+    memory_order_consume,
+    memory_order_acquire,
+    memory_order_release,
+    memory_order_acq_rel,
+    memory_order_seq_cst,
+  };
+  void atomic_thread_fence(memory_order) {}
+};
+
+__attribute__((no_sanitize("thread")))
+void ignore_1() {
+  std::atomic_thread_fence(std::memory_order_relaxed);
+}
+
+__attribute__((no_sanitize_thread))
+void ignore_2() {
+  std::atomic_thread_fence(std::memory_order_relaxed);
+}
 
 int main() {
-    std::atomic_thread_fence(std::memory_order::memory_order_relaxed);
+  std::atomic_thread_fence(std::memory_order_relaxed); // with-tsan-warning 
{{'std::atomic_thread_fence' is not supported with '-fsanitize=thread'}}
 }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to