[clang] Add check in SemaChecking for multiple unsequenced volatile accesses (PR #180955)

via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 11 06:51:06 PST 2026


https://github.com/Seraphimt created https://github.com/llvm/llvm-project/pull/180955

According to standards volatile accesses is sideeffects and multiple unsequenced volatile accesses same variable is UB.

>From 8411b532a145c3b5a39a3785a1ab6c3dbaf446e8 Mon Sep 17 00:00:00 2001
From: Seraphimt <svet58585 at mail.ru>
Date: Wed, 11 Feb 2026 12:18:06 +0300
Subject: [PATCH 1/2] Add warning to Sema for multi unseq use volatile.

---
 clang/lib/Sema/SemaChecking.cpp         | 42 ++++++++++++++++++-------
 clang/test/SemaCXX/warn-unsequenced.cpp | 26 +++++++++++++++
 2 files changed, 56 insertions(+), 12 deletions(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 89171246d0bcb..b9d1ae9240923 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -14015,7 +14015,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
   };
 
   /// An object for which we can track unsequenced uses.
-  using Object = const NamedDecl *;
+  using Object = const ValueDecl *;
 
   /// Different flavors of object usage which we track. We only track the
   /// least-sequenced usage of each kind.
@@ -14034,6 +14034,12 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
     UK_Count = UK_ModAsSideEffect + 1
   };
 
+  enum WarningKind {
+    WK_UseAndMod,
+    WK_ModAndMod,
+    WK_Volatile_UseAndUse
+  };
+
   /// Bundle together a sequencing region and the expression corresponding
   /// to a specific usage. One Usage is stored for each usage kind in UsageInfo.
   struct Usage {
@@ -14179,7 +14185,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
   /// \p IsModMod is true when we are checking for a mod-mod unsequenced
   /// usage and false we are checking for a mod-use unsequenced usage.
   void checkUsage(Object O, UsageInfo &UI, const Expr *UsageExpr,
-                  UsageKind OtherKind, bool IsModMod) {
+                  UsageKind OtherKind, WarningKind WarnKind) {
     if (UI.Diagnosed)
       return;
 
@@ -14192,11 +14198,22 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
     if (OtherKind == UK_Use)
       std::swap(Mod, ModOrUse);
 
+    unsigned DiagID = 0;
+    switch (WarnKind) {
+    case WK_UseAndMod:
+      DiagID = diag::warn_unsequenced_mod_use;
+      break;
+    case WK_ModAndMod: 
+      DiagID = diag::warn_unsequenced_mod_mod;
+      break;
+    case WK_Volatile_UseAndUse:
+      DiagID = diag::warn_unsequenced_use_use_volatile;
+      break;
+    }
+
     SemaRef.DiagRuntimeBehavior(
         Mod->getExprLoc(), {Mod, ModOrUse},
-        SemaRef.PDiag(IsModMod ? diag::warn_unsequenced_mod_mod
-                               : diag::warn_unsequenced_mod_use)
-            << O << SourceRange(ModOrUse->getExprLoc()));
+        SemaRef.PDiag(DiagID)<< O << SourceRange(ModOrUse->getExprLoc()));
     UI.Diagnosed = true;
   }
 
@@ -14229,27 +14246,28 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
   void notePreUse(Object O, const Expr *UseExpr) {
     UsageInfo &UI = UsageMap[O];
     // Uses conflict with other modifications.
-    checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/false);
+    checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsValue, WK_UseAndMod);
+    // Volatile uses conflict with other uses.
+    if (O->getType().isVolatileQualified())
+      checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_Use, WK_Volatile_UseAndUse);
   }
 
   void notePostUse(Object O, const Expr *UseExpr) {
     UsageInfo &UI = UsageMap[O];
-    checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsSideEffect,
-               /*IsModMod=*/false);
+    checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsSideEffect, WK_UseAndMod);
     addUsage(O, UI, UseExpr, /*UsageKind=*/UK_Use);
   }
 
   void notePreMod(Object O, const Expr *ModExpr) {
     UsageInfo &UI = UsageMap[O];
     // Modifications conflict with other modifications and with uses.
-    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/true);
-    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_Use, /*IsModMod=*/false);
+    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsValue, WK_ModAndMod);
+    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_Use, WK_UseAndMod);
   }
 
   void notePostMod(Object O, const Expr *ModExpr, UsageKind UK) {
     UsageInfo &UI = UsageMap[O];
-    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsSideEffect,
-               /*IsModMod=*/true);
+    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsSideEffect, WK_ModAndMod);
     addUsage(O, UI, ModExpr, /*UsageKind=*/UK);
   }
 
diff --git a/clang/test/SemaCXX/warn-unsequenced.cpp b/clang/test/SemaCXX/warn-unsequenced.cpp
index 50dde8f3a5789..6019eb3929304 100644
--- a/clang/test/SemaCXX/warn-unsequenced.cpp
+++ b/clang/test/SemaCXX/warn-unsequenced.cpp
@@ -815,3 +815,29 @@ void test_var() {
 }
 
 } // namespace templates
+
+namespace muliple_read_volatile {
+  volatile int v1;
+  
+  void PositiveTest(){
+    int x = 0;
+    int y = 0;
+    x = v1 + v1;        // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
+                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
+    v1 = v1 * v1;       // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
+                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
+    x = v1 + (y++, v1); // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
+                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
+    x = v1 + y || y;    // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
+                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
+  }
+  
+  void NegativeTest(){
+    int x = 0;
+    int y = 0;
+    x = v1 + y;   // no-warning
+    v1 = v1 * y;  // no-warning
+    x = (v1, v1); // no-warning
+    x = v1 || v1; // no-warning
+  }
+} // namespace volatiles
\ No newline at end of file

>From 4889b198e22806080f7b602b29526858135f4f02 Mon Sep 17 00:00:00 2001
From: Seraphimt <svet58585 at mail.ru>
Date: Wed, 11 Feb 2026 15:58:17 +0300
Subject: [PATCH 2/2] Minor fix.

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 ++
 clang/test/SemaCXX/warn-unsequenced.cpp          | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f12677ac11600..defd168b2c629 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2581,6 +2581,8 @@ def warn_unsequenced_mod_mod : Warning<
   "multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
 def warn_unsequenced_mod_use : Warning<
   "unsequenced modification and access to %0">, InGroup<Unsequenced>;
+def warn_unsequenced_use_use_volatile : Warning<
+  "unsequenced volatile accesses to %0">, InGroup<Unsequenced>;
 
 def select_initialized_entity_kind : TextSubstitution<
   "%select{copying variable|copying parameter|initializing template parameter|"
diff --git a/clang/test/SemaCXX/warn-unsequenced.cpp b/clang/test/SemaCXX/warn-unsequenced.cpp
index 6019eb3929304..3b4a8ec9380d0 100644
--- a/clang/test/SemaCXX/warn-unsequenced.cpp
+++ b/clang/test/SemaCXX/warn-unsequenced.cpp
@@ -828,7 +828,7 @@ namespace muliple_read_volatile {
                         // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
     x = v1 + (y++, v1); // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
                         // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
-    x = v1 + y || y;    // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
+    x = v1 + v1 || y;   // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
                         // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
   }
   
@@ -840,4 +840,4 @@ namespace muliple_read_volatile {
     x = (v1, v1); // no-warning
     x = v1 || v1; // no-warning
   }
-} // namespace volatiles
\ No newline at end of file
+} // namespace muliple_read_volatile
\ No newline at end of file



More information about the cfe-commits mailing list