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/5] [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/5] 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'}}
 }

>From 30835da9bd16ade2eecf20866a418e18382837d2 Mon Sep 17 00:00:00 2001
From: BStott <[email protected]>
Date: Thu, 6 Nov 2025 16:44:04 +0000
Subject: [PATCH 3/5] Fix formatting mistake

---
 clang/include/clang/Sema/Sema.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 99e486179dd2e..d78d912c16104 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3033,7 +3033,8 @@ class Sema final : public SemaBase {
 
   void CheckMaxUnsignedZero(const CallExpr *Call, const FunctionDecl *FDecl);
 
-  void CheckUseOfAtomicThreadFenceWithTSan(const CallExpr *Call, const 
FunctionDecl *FDecl);
+  void CheckUseOfAtomicThreadFenceWithTSan(const CallExpr *Call,
+                                           const FunctionDecl *FDecl);
 
   /// Check for dangerous or invalid arguments to memset().
   ///

>From 8a1b662160b455b10c1503dbc4cf154c947f4e02 Mon Sep 17 00:00:00 2001
From: BStott <[email protected]>
Date: Fri, 7 Nov 2025 17:40:46 +0000
Subject: [PATCH 4/5] Improve test, account for lambda attributes, use mangled
 name to lookup in ignore list

---
 clang/lib/Sema/SemaChecking.cpp               | 38 +++++++++++++------
 clang/test/SemaCXX/warn-tsan-atomic-fence.cpp | 24 ++++++++----
 2 files changed, 44 insertions(+), 18 deletions(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 8621e1db4e561..52ba36ab93642 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -29,6 +29,7 @@
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/FormatString.h"
 #include "clang/AST/IgnoreExpr.h"
+#include "clang/AST/Mangle.h"
 #include "clang/AST/NSAPI.h"
 #include "clang/AST/NonTrivialTypeVisitor.h"
 #include "clang/AST/OperationKinds.h"
@@ -9849,21 +9850,36 @@ void Sema::CheckUseOfAtomicThreadFenceWithTSan(const 
CallExpr *Call,
                                       Call->getSourceRange().getBegin()))
     return;
 
-  // Check that the calling function:
+  std::unique_ptr<MangleContext> MC(Context.createMangleContext());
+
+  // Check that the calling function or lambda:
   //  - Does not have any attributes preventing TSan checking
   //  - Is not in the ignore list
-  if (const NamedDecl *Caller = getCurFunctionOrMethodDecl()) {
-    if (Caller->hasAttr<DisableSanitizerInstrumentationAttr>())
-      return;
+  auto IsNotSanitized = [&](NamedDecl *Decl) {
+    const auto SpecificAttrs = Decl->specific_attrs<NoSanitizeAttr>();
+    const auto IsNoSanitizeThreadAttr = [](NoSanitizeAttr *Attr) {
+      return static_cast<bool>(Attr->getMask() & SanitizerKind::Thread);
+    };
 
-    for (const auto *Attr : Caller->specific_attrs<NoSanitizeAttr>())
-      if (Attr->getMask() & SanitizerKind::Thread)
-        return;
+    // Get mangled name for ignorelist lookup
+    std::string MangledName;
+    if (MC->shouldMangleDeclName(Decl)) {
+      llvm::raw_string_ostream S = llvm::raw_string_ostream(MangledName);
+      MC->mangleName(Decl, S);
+    } else {
+      MangledName = Decl->getName();
+    }
 
-    if (NoSanitizeList.containsFunction(EnabledTSanMask,
-                                        Caller->getQualifiedNameAsString()))
-      return;
-  }
+    return Decl &&
+           (Decl->hasAttr<DisableSanitizerInstrumentationAttr>() ||
+            std::any_of(SpecificAttrs.begin(), SpecificAttrs.end(),
+                        IsNoSanitizeThreadAttr) ||
+            NoSanitizeList.containsFunction(EnabledTSanMask, MangledName));
+  };
+  if (IsNotSanitized(getCurFunctionOrMethodDecl()))
+    return;
+  if (IsNotSanitized(getCurFunctionDecl(/*AllowLambdas*/ true)))
+    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 ae0afbed749d7..a7db3958696db 100644
--- a/clang/test/SemaCXX/warn-tsan-atomic-fence.cpp
+++ b/clang/test/SemaCXX/warn-tsan-atomic-fence.cpp
@@ -7,8 +7,8 @@
 // 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
+// Ignoring func1
+// RUN: echo "fun:*func1*" > %t
 // RUN: %clang_cc1 -verify=no-tsan -fsanitize=thread -fsanitize-ignorelist=%t 
%s
 
 // Ignoring source file
@@ -29,16 +29,26 @@ namespace std {
   void atomic_thread_fence(memory_order) {}
 };
 
+void func1() { // extern "C" to stop name mangling
+  std::atomic_thread_fence(std::memory_order_relaxed); // with-tsan-warning 
{{'std::atomic_thread_fence' is not supported with '-fsanitize=thread'}}
+
+  auto lam = []() __attribute__((no_sanitize("thread"))) {
+    std::atomic_thread_fence(std::memory_order_relaxed);
+  };
+}
+
 __attribute__((no_sanitize("thread")))
-void ignore_1() {
+void func2() {
   std::atomic_thread_fence(std::memory_order_relaxed);
+
+  auto lam = []() {
+    std::atomic_thread_fence(std::memory_order_relaxed);
+  };
 }
 
 __attribute__((no_sanitize_thread))
-void ignore_2() {
+void func3() {
   std::atomic_thread_fence(std::memory_order_relaxed);
 }
 
-int main() {
-  std::atomic_thread_fence(std::memory_order_relaxed); // with-tsan-warning 
{{'std::atomic_thread_fence' is not supported with '-fsanitize=thread'}}
-}
+int main() {}

>From df5a1ab0e2c376789983834be1936664d67f2714 Mon Sep 17 00:00:00 2001
From: BStott <[email protected]>
Date: Thu, 27 Nov 2025 11:26:47 +0000
Subject: [PATCH 5/5] Apply suggestions

---
 clang/include/clang/Sema/Sema.h               |  6 +-
 clang/lib/Sema/Sema.cpp                       |  4 +-
 clang/lib/Sema/SemaChecking.cpp               | 95 ++++++++++---------
 clang/test/SemaCXX/warn-tsan-atomic-fence.cpp | 56 +++++++----
 4 files changed, 92 insertions(+), 69 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index dd1ff842eaf62..711239f0e98d6 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1165,8 +1165,10 @@ class Sema final : public SemaBase {
 
   /// getCurFunctionOrMethodDecl - Return the Decl for the current ObjC method
   /// or C function we're in, otherwise return null.  If we're currently
-  /// in a 'block', this returns the containing context.
-  NamedDecl *getCurFunctionOrMethodDecl() const;
+  /// in a 'block', this returns the containing context. If \p AllowLambda is
+  /// true, this can return the call operator of an enclosing lambda, otherwise
+  /// lambdas are skipped when looking for an enclosing function.
+  NamedDecl *getCurFunctionOrMethodDecl(bool AllowLambda = false) const;
 
   /// Warn if we're implicitly casting from a _Nullable pointer type to a
   /// _Nonnull one.
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 46addea232b03..e38cd27190336 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1660,8 +1660,8 @@ ObjCMethodDecl *Sema::getCurMethodDecl() {
   return dyn_cast<ObjCMethodDecl>(DC);
 }
 
-NamedDecl *Sema::getCurFunctionOrMethodDecl() const {
-  DeclContext *DC = getFunctionLevelDeclContext();
+NamedDecl *Sema::getCurFunctionOrMethodDecl(bool AllowLambda) const {
+  DeclContext *DC = getFunctionLevelDeclContext(AllowLambda);
   if (isa<ObjCMethodDecl>(DC) || isa<FunctionDecl>(DC))
     return cast<NamedDecl>(DC);
   return nullptr;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index a60548dcd4061..ff6413e5c9d3f 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1141,6 +1141,53 @@ static bool ProcessFormatStringLiteral(const Expr 
*FormatExpr,
   return false;
 }
 
+/// Returns true if:
+/// - The sanitizers are enabled.
+/// - `Decl` does not have attributes preventing sanitizer instrumentation.
+/// - `Decl` or its location is not included in the no-sanitize list.
+static bool isSanitizationEnabledForDecl(ASTContext &Context,
+                                         const NamedDecl *Decl,
+                                         SanitizerMask TheSanitizerMask) {
+  // Check that the sanitizer is enabled globally.
+  const SanitizerMask EnabledSanitizerMask =
+      Context.getLangOpts().Sanitize.Mask;
+  if (!(EnabledSanitizerMask & TheSanitizerMask))
+    return false;
+
+  // Check that the source file is not included in the no sanitize list.
+  const auto &NoSanitizeList = Context.getNoSanitizeList();
+  if (NoSanitizeList.containsLocation(TheSanitizerMask,
+                                      Decl->getSourceRange().getBegin()))
+    return false;
+
+  // Check that the declaration name is not included in the no sanitize list.
+  // NB no-sanitize lists use mangled names.
+  std::unique_ptr<MangleContext> MC(Context.createMangleContext());
+  std::string MangledName;
+  if (MC->shouldMangleDeclName(Decl)) {
+    llvm::raw_string_ostream S = llvm::raw_string_ostream(MangledName);
+    MC->mangleName(Decl, S);
+  } else {
+    MangledName = Decl->getName();
+  }
+  if (NoSanitizeList.containsFunction(TheSanitizerMask, MangledName))
+    return false;
+
+  // Check that the declaration does not have the
+  // "disable_sanitizer_instrumentation" attribute.
+  if (Decl->hasAttr<DisableSanitizerInstrumentationAttr>())
+    return false;
+
+  // Check that the declaration does not have a "no_sanitize" attribute 
matching
+  // this sanitizer mask.
+  for (const NoSanitizeAttr *Attr : Decl->specific_attrs<NoSanitizeAttr>()) {
+    if (Attr->getMask() & TheSanitizerMask)
+      return false;
+  }
+
+  return true;
+}
+
 void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
                                                CallExpr *TheCall) {
   if (TheCall->isValueDependent() || TheCall->isTypeDependent() ||
@@ -9921,53 +9968,11 @@ void Sema::CheckUseOfAtomicThreadFenceWithTSan(const 
CallExpr *Call,
   // leading to false positives. Example issue:
   // https://github.com/llvm/llvm-project/issues/52942
 
-  if (!Call || !FDecl)
-    return;
-
-  if (!IsStdFunction(FDecl, "atomic_thread_fence"))
-    return;
-
-  // Check that TSan is enabled in this context
-  const auto EnabledTSanMask =
-      Context.getLangOpts().Sanitize.Mask & (SanitizerKind::Thread);
-  if (!EnabledTSanMask)
+  if (!Call || !FDecl || !IsStdFunction(FDecl, "atomic_thread_fence"))
     return;
 
-  // Check that the file isn't in the no-sanitize list
-  const auto &NoSanitizeList = Context.getNoSanitizeList();
-  if (NoSanitizeList.containsLocation(EnabledTSanMask,
-                                      Call->getSourceRange().getBegin()))
-    return;
-
-  std::unique_ptr<MangleContext> MC(Context.createMangleContext());
-
-  // Check that the calling function or lambda:
-  //  - Does not have any attributes preventing TSan checking
-  //  - Is not in the ignore list
-  auto IsNotSanitized = [&](NamedDecl *Decl) {
-    const auto SpecificAttrs = Decl->specific_attrs<NoSanitizeAttr>();
-    const auto IsNoSanitizeThreadAttr = [](NoSanitizeAttr *Attr) {
-      return static_cast<bool>(Attr->getMask() & SanitizerKind::Thread);
-    };
-
-    // Get mangled name for ignorelist lookup
-    std::string MangledName;
-    if (MC->shouldMangleDeclName(Decl)) {
-      llvm::raw_string_ostream S = llvm::raw_string_ostream(MangledName);
-      MC->mangleName(Decl, S);
-    } else {
-      MangledName = Decl->getName();
-    }
-
-    return Decl &&
-           (Decl->hasAttr<DisableSanitizerInstrumentationAttr>() ||
-            std::any_of(SpecificAttrs.begin(), SpecificAttrs.end(),
-                        IsNoSanitizeThreadAttr) ||
-            NoSanitizeList.containsFunction(EnabledTSanMask, MangledName));
-  };
-  if (IsNotSanitized(getCurFunctionOrMethodDecl()))
-    return;
-  if (IsNotSanitized(getCurFunctionDecl(/*AllowLambdas*/ true)))
+  const NamedDecl *Caller = getCurFunctionOrMethodDecl(/*AllowLambda=*/true);
+  if (!isSanitizationEnabledForDecl(Context, Caller, SanitizerKind::Thread))
     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 a7db3958696db..9cfc0a8082d18 100644
--- a/clang/test/SemaCXX/warn-tsan-atomic-fence.cpp
+++ b/clang/test/SemaCXX/warn-tsan-atomic-fence.cpp
@@ -1,21 +1,25 @@
 // No warnings in regular compile
-// RUN: %clang_cc1 -verify=no-tsan %s
+// RUN: %clang_cc1 -verify=no-warnings %s
 
-// Emits warning with `-fsanitize=thread`
-// RUN: %clang_cc1 -verify=with-tsan -fsanitize=thread %s
+// Emits warnings with `-fsanitize=thread`
+// RUN: %clang_cc1 -verify=with-tsan,warn-global-function,warn-member-function 
-fsanitize=thread %s
 
 // No warnings if `-Wno-tsan` is passed
-// RUN: %clang_cc1 -verify=no-tsan -fsanitize=thread -Wno-tsan %s
-
-// Ignoring func1
-// RUN: echo "fun:*func1*" > %t
-// RUN: %clang_cc1 -verify=no-tsan -fsanitize=thread -fsanitize-ignorelist=%t 
%s
+// RUN: %clang_cc1 -verify=no-warnings -fsanitize=thread -Wno-tsan %s
 
 // Ignoring source file
 // RUN: echo "src:%s" > %t
-// RUN: %clang_cc1 -verify=no-tsan -fsanitize=thread -fsanitize-ignorelist=%t 
%s
+// RUN: %clang_cc1 -verify=no-warnings -fsanitize=thread 
-fsanitize-ignorelist=%t %s
+
+// Ignoring global function
+// RUN: echo "fun:*global_function_to_maybe_ignore*" > %t
+// RUN: %clang_cc1 -verify=with-tsan,warn-member-function -fsanitize=thread 
-fsanitize-ignorelist=%t %s
 
-// no-tsan-no-diagnostics
+// Ignoring "S::member_function"
+// RUN: echo "fun:_ZN1S15member_functionEv" > %t
+// RUN: %clang_cc1 -triple=%itanium_abi_triple 
-verify=with-tsan,warn-global-function -fsanitize=thread 
-fsanitize-ignorelist=%t %s
+
+// no-warnings-no-diagnostics
 
 namespace std {
   enum memory_order {
@@ -29,26 +33,38 @@ namespace std {
   void atomic_thread_fence(memory_order) {}
 };
 
-void func1() { // extern "C" to stop name mangling
-  std::atomic_thread_fence(std::memory_order_relaxed); // with-tsan-warning 
{{'std::atomic_thread_fence' is not supported with '-fsanitize=thread'}}
-
-  auto lam = []() __attribute__((no_sanitize("thread"))) {
-    std::atomic_thread_fence(std::memory_order_relaxed);
-  };
+void global_function_to_maybe_ignore() {
+  std::atomic_thread_fence(std::memory_order_relaxed); // 
warn-global-function-warning {{'std::atomic_thread_fence' is not supported with 
'-fsanitize=thread'}}
 }
 
 __attribute__((no_sanitize("thread")))
-void func2() {
+void no_sanitize_1() {
   std::atomic_thread_fence(std::memory_order_relaxed);
 
   auto lam = []() {
-    std::atomic_thread_fence(std::memory_order_relaxed);
+    std::atomic_thread_fence(std::memory_order_relaxed); // with-tsan-warning 
{{'std::atomic_thread_fence' is not supported with '-fsanitize=thread'}}
   };
 }
 
 __attribute__((no_sanitize_thread))
-void func3() {
+void no_sanitize_2() {
   std::atomic_thread_fence(std::memory_order_relaxed);
 }
 
-int main() {}
+__attribute__((disable_sanitizer_instrumentation))
+void no_sanitize_3() {
+  std::atomic_thread_fence(std::memory_order_relaxed);
+}
+
+void no_sanitize_lambda() {
+  auto lam = [] () __attribute__((no_sanitize("thread"))) {
+    std::atomic_thread_fence(std::memory_order_relaxed);
+  };
+}
+
+struct S {
+public:
+  void member_function() {
+    std::atomic_thread_fence(std::memory_order_relaxed); // 
warn-member-function-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