Skip to content

Conversation

frederick-vs-ja
Copy link
Contributor

@frederick-vs-ja frederick-vs-ja commented Sep 26, 2025

This patch renames comparators

  • from std::equal_to<llvm::rdf::RegisterRef> to llvm::rdf::RegisterRefEqualTo, and
  • from std::less<llvm::rdf::RegisterRef> to llvm::rdf::RegisterRefLess.

The original specializations don't satisfy the requirements for the original std templates by being stateful and non-default-constructible, so they make the program have UB due to C++17 [namespace.std]/2, C++20/23 [namespace.std]/5.

A program may explicitly instantiate a class template defined in the standard library only if the declaration

  • depends on the name of at least one program-defined type, and
  • the instantiation meets the standard library requirements for the original template.

Fixes #160684.

@llvmbot
Copy link
Member

llvmbot commented Sep 26, 2025

@llvm/pr-subscribers-backend-hexagon

Author: A. Jiang (frederick-vs-ja)

Changes

This patch renames comparators

  • from std::equal_to&lt;llvm::rdf::RegisterRef&gt; to llvm::rdf::RegisterRefEqualTo, and
  • from std::less&lt;llvm::rdf::RegisterRef&gt; to llvm::rdf::RegisterRefLess.

The original specializations don't satisfy the requirements for the original std templates, so they make the program have UB due to [namespace.std]/5.

Fixes #160684.


Full diff: https://github.com/llvm/llvm-project/pull/160804.diff

6 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/RDFGraph.h (+1-1)
  • (modified) llvm/include/llvm/CodeGen/RDFRegisters.h (+28-26)
  • (modified) llvm/lib/CodeGen/RDFLiveness.cpp (+5-4)
  • (modified) llvm/lib/Target/Hexagon/RDFCopy.cpp (+1-1)
  • (modified) llvm/lib/Target/Hexagon/RDFCopy.h (+4-4)
  • (modified) llvm/unittests/CodeGen/TypeTraitsTest.cpp (+29)
diff --git a/llvm/include/llvm/CodeGen/RDFGraph.h b/llvm/include/llvm/CodeGen/RDFGraph.h
index 8a93afbcb5491..6bb6033a8a2f2 100644
--- a/llvm/include/llvm/CodeGen/RDFGraph.h
+++ b/llvm/include/llvm/CodeGen/RDFGraph.h
@@ -447,7 +447,7 @@ struct NodeAllocator {
   AllocatorTy MemPool;
 };
 
-using RegisterSet = std::set<RegisterRef>;
+using RegisterSet = std::set<RegisterRef, RegisterRefLess>;
 
 struct TargetOperandInfo {
   TargetOperandInfo(const TargetInstrInfo &tii) : TII(tii) {}
diff --git a/llvm/include/llvm/CodeGen/RDFRegisters.h b/llvm/include/llvm/CodeGen/RDFRegisters.h
index 4a9a4063c9e83..82027cad53bdb 100644
--- a/llvm/include/llvm/CodeGen/RDFRegisters.h
+++ b/llvm/include/llvm/CodeGen/RDFRegisters.h
@@ -199,6 +199,33 @@ struct PhysicalRegisterInfo {
   std::vector<AliasInfo> AliasInfos;
 };
 
+struct RegisterRefEqualTo {
+  constexpr RegisterRefEqualTo(const llvm::rdf::PhysicalRegisterInfo &pri)
+      : PRI(&pri) {}
+
+  bool operator()(llvm::rdf::RegisterRef A, llvm::rdf::RegisterRef B) const {
+    return PRI->equal_to(A, B);
+  }
+
+private:
+  // Make it a pointer just in case. See comment in `RegisterRefLess` below.
+  const llvm::rdf::PhysicalRegisterInfo *PRI;
+};
+
+struct RegisterRefLess {
+  constexpr RegisterRefLess(const llvm::rdf::PhysicalRegisterInfo &pri)
+      : PRI(&pri) {}
+
+  bool operator()(llvm::rdf::RegisterRef A, llvm::rdf::RegisterRef B) const {
+    return PRI->less(A, B);
+  }
+
+private:
+  // Make it a pointer because apparently some versions of MSVC use std::swap
+  // on the comparator object.
+  const llvm::rdf::PhysicalRegisterInfo *PRI;
+};
+
 struct RegisterAggr {
   RegisterAggr(const PhysicalRegisterInfo &pri)
       : Units(pri.getTRI().getNumRegUnits()), PRI(pri) {}
@@ -334,18 +361,6 @@ template <> struct hash<llvm::rdf::RegisterAggr> {
   }
 };
 
-template <> struct equal_to<llvm::rdf::RegisterRef> {
-  constexpr equal_to(const llvm::rdf::PhysicalRegisterInfo &pri) : PRI(&pri) {}
-
-  bool operator()(llvm::rdf::RegisterRef A, llvm::rdf::RegisterRef B) const {
-    return PRI->equal_to(A, B);
-  }
-
-private:
-  // Make it a pointer just in case. See comment in `less` below.
-  const llvm::rdf::PhysicalRegisterInfo *PRI;
-};
-
 template <> struct equal_to<llvm::rdf::RegisterAggr> {
   bool operator()(const llvm::rdf::RegisterAggr &A,
                   const llvm::rdf::RegisterAggr &B) const {
@@ -353,23 +368,10 @@ template <> struct equal_to<llvm::rdf::RegisterAggr> {
   }
 };
 
-template <> struct less<llvm::rdf::RegisterRef> {
-  constexpr less(const llvm::rdf::PhysicalRegisterInfo &pri) : PRI(&pri) {}
-
-  bool operator()(llvm::rdf::RegisterRef A, llvm::rdf::RegisterRef B) const {
-    return PRI->less(A, B);
-  }
-
-private:
-  // Make it a pointer because apparently some versions of MSVC use std::swap
-  // on the std::less specialization.
-  const llvm::rdf::PhysicalRegisterInfo *PRI;
-};
-
 } // namespace std
 
 namespace llvm::rdf {
-using RegisterSet = std::set<RegisterRef, std::less<RegisterRef>>;
+using RegisterSet = std::set<RegisterRef, RegisterRefLess>;
 } // namespace llvm::rdf
 
 #endif // LLVM_CODEGEN_RDFREGISTERS_H
diff --git a/llvm/lib/CodeGen/RDFLiveness.cpp b/llvm/lib/CodeGen/RDFLiveness.cpp
index 318422b46e811..f6afe80422dda 100644
--- a/llvm/lib/CodeGen/RDFLiveness.cpp
+++ b/llvm/lib/CodeGen/RDFLiveness.cpp
@@ -652,8 +652,9 @@ void Liveness::computePhiInfo() {
   // defs, cache the result of subtracting these defs from a given register
   // ref.
   using RefHash = std::hash<RegisterRef>;
-  using RefEqual = std::equal_to<RegisterRef>;
-  using SubMap = std::unordered_map<RegisterRef, RegisterRef>;
+  using RefEqual = RegisterRefEqualTo;
+  using SubMap = std::unordered_map<RegisterRef, RegisterRef,
+                                    std::hash<RefEqual>, RefEqual>;
   std::unordered_map<RegisterAggr, SubMap> Subs;
   auto ClearIn = [](RegisterRef RR, const RegisterAggr &Mid, SubMap &SM) {
     if (Mid.empty())
@@ -868,7 +869,7 @@ void Liveness::computeLiveIns() {
       std::vector<RegisterRef> LV;
       for (const MachineBasicBlock::RegisterMaskPair &LI : B.liveins())
         LV.push_back(RegisterRef(LI.PhysReg, LI.LaneMask));
-      llvm::sort(LV, std::less<RegisterRef>(PRI));
+      llvm::sort(LV, RegisterRefLess(PRI));
       dbgs() << printMBBReference(B) << "\t rec = {";
       for (auto I : LV)
         dbgs() << ' ' << Print(I, DFG);
@@ -878,7 +879,7 @@ void Liveness::computeLiveIns() {
       LV.clear();
       for (RegisterRef RR : LiveMap[&B].refs())
         LV.push_back(RR);
-      llvm::sort(LV, std::less<RegisterRef>(PRI));
+      llvm::sort(LV, RegisterRefLess(PRI));
       dbgs() << "\tcomp = {";
       for (auto I : LV)
         dbgs() << ' ' << Print(I, DFG);
diff --git a/llvm/lib/Target/Hexagon/RDFCopy.cpp b/llvm/lib/Target/Hexagon/RDFCopy.cpp
index fafdad08909dd..3b1d3bd89680b 100644
--- a/llvm/lib/Target/Hexagon/RDFCopy.cpp
+++ b/llvm/lib/Target/Hexagon/RDFCopy.cpp
@@ -108,7 +108,7 @@ bool CopyPropagation::scanBlock(MachineBasicBlock *B) {
   for (NodeAddr<InstrNode*> IA : BA.Addr->members(DFG)) {
     if (DFG.IsCode<NodeAttrs::Stmt>(IA)) {
       NodeAddr<StmtNode*> SA = IA;
-      EqualityMap EM(std::less<RegisterRef>(DFG.getPRI()));
+      EqualityMap EM(RegisterRefLess(DFG.getPRI()));
       if (interpretAsCopy(SA.Addr->getCode(), EM))
         recordCopy(SA, EM);
     }
diff --git a/llvm/lib/Target/Hexagon/RDFCopy.h b/llvm/lib/Target/Hexagon/RDFCopy.h
index e4fb89892831d..92b2c65982655 100644
--- a/llvm/lib/Target/Hexagon/RDFCopy.h
+++ b/llvm/lib/Target/Hexagon/RDFCopy.h
@@ -25,8 +25,8 @@ class MachineInstr;
 namespace rdf {
 
   struct CopyPropagation {
-    CopyPropagation(DataFlowGraph &dfg) : MDT(dfg.getDT()), DFG(dfg),
-        RDefMap(std::less<RegisterRef>(DFG.getPRI())) {}
+    CopyPropagation(DataFlowGraph &dfg)
+        : MDT(dfg.getDT()), DFG(dfg), RDefMap(RegisterRefLess(DFG.getPRI())) {}
 
     virtual ~CopyPropagation() = default;
 
@@ -35,7 +35,7 @@ namespace rdf {
     bool trace() const { return Trace; }
     DataFlowGraph &getDFG() { return DFG; }
 
-    using EqualityMap = std::map<RegisterRef, RegisterRef>;
+    using EqualityMap = std::map<RegisterRef, RegisterRef, RegisterRefLess>;
     virtual bool interpretAsCopy(const MachineInstr *MI, EqualityMap &EM);
 
   private:
@@ -45,7 +45,7 @@ namespace rdf {
     bool Trace = false;
 
     // map: register -> (map: stmt -> reaching def)
-    std::map<RegisterRef,std::map<NodeId,NodeId>> RDefMap;
+    std::map<RegisterRef, std::map<NodeId, NodeId>, RegisterRefLess> RDefMap;
     // map: statement -> (map: dst reg -> src reg)
     std::map<NodeId, EqualityMap> CopyMap;
     std::vector<NodeId> Copies;
diff --git a/llvm/unittests/CodeGen/TypeTraitsTest.cpp b/llvm/unittests/CodeGen/TypeTraitsTest.cpp
index dde86280cff6a..5c0a74d3e2c0f 100644
--- a/llvm/unittests/CodeGen/TypeTraitsTest.cpp
+++ b/llvm/unittests/CodeGen/TypeTraitsTest.cpp
@@ -6,13 +6,16 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/CodeGen/RDFRegisters.h"
 #include "llvm/CodeGen/RegisterPressure.h"
 #include "llvm/CodeGen/ScheduleDAG.h"
 #include "llvm/CodeGen/SelectionDAGNodes.h"
 #include "llvm/CodeGen/SlotIndexes.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
 #include "gtest/gtest.h"
+#include <functional>
 #include <type_traits>
+#include <utility>
 
 using namespace llvm;
 
@@ -23,3 +26,29 @@ static_assert(std::is_trivially_copyable_v<SDValue>, "trivially copyable");
 static_assert(std::is_trivially_copyable_v<SlotIndex>, "trivially copyable");
 static_assert(std::is_trivially_copyable_v<IdentifyingPassPtr>,
               "trivially copyable");
+
+// https://llvm.org/PR105169
+// Verify that we won't accidently specialize std::less and std::equal_to in a
+// wrong way. See also [namespace.std]/5.
+template <class Fn> constexpr bool CheckStdCmpRequirements() {
+  // std::less and std::equal_to are literal, default constructible, and
+  // copyable classes.
+  Fn f1;
+  auto f2 = f1;
+  auto f3 = std::move(f2);
+  f2 = f3;
+  f2 = std::move(f3);
+
+  // Properties held on all known implementations, although not guaranteed by
+  // the standard.
+  static_assert(std::is_empty_v<Fn>);
+  static_assert(std::is_trivially_default_constructible_v<Fn>);
+  static_assert(std::is_trivially_copyable_v<Fn>);
+
+  return true;
+}
+
+static_assert(CheckStdCmpRequirements<std::less<rdf::RegisterRef>>(),
+              "same as the original template");
+static_assert(CheckStdCmpRequirements<std::equal_to<rdf::RegisterRef>>(),
+              "same as the original template");

Comment on lines 364 to 369
template <> struct equal_to<llvm::rdf::RegisterAggr> {
bool operator()(const llvm::rdf::RegisterAggr &A,
const llvm::rdf::RegisterAggr &B) const {
return A == B;
}
};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This full specialization is correct but probably meaningless. Perhaps we should remove it in a later PR.

@androm3da
Copy link
Member

This change makes sense to me.

@iajbar or @aankit-quic please take a look.

@YexuanXiao
Copy link
Contributor

I approve this change. The stateful specialization of std::less<> affects all downstream users who expect it to behave like the primary template, so it should be avoided.

@kparzysz
Copy link
Contributor

kparzysz commented Sep 26, 2025

You should clarify which requirement is violated.

Edit:
C++17 doesn't have [namespace.std]/5, and in C++20/23 [namespace.std]/5 talks about explicit instantiation and only says that the requirements need to be met (plus that the instantiation has to depend on a user-defined type).

This change is ok to me, but I'd like to know what the current code violates.

This patch renames comparators
- from `std::equal_to<llvm::rdf::RegisterRef>` to `llvm::rdf::RegisterRefEqualTo`, and
- from `std::less<llvm::rdf::RegisterRef>` to `llvm::rdf::RegisterRefLess`.

The original specializations don't satisfy the requirements for the
original `std` templates being stateful and non-default-constructible,
so they make the program have UB due to C++17 [namespace.std]/2,
C++20/23 [namespace.std]/5.

> A program may explicitly instantiate a class template defined in the standard library only if the declaration
> - depends on the name of at least one program-defined type, and
> - the instantiation meets the standard library requirements for the original template.
@frederick-vs-ja
Copy link
Contributor Author

@kparzysz Thanks. The requirements was in [namespace.std]/2 in C++17. I've updated the PR message and comments to make the reason of changes clearer.

@frederick-vs-ja frederick-vs-ja merged commit a558d65 into llvm:main Sep 28, 2025
9 checks passed
@frederick-vs-ja frederick-vs-ja deleted the llvm-no-cmp-spec branch September 28, 2025 13:36
@llvm-ci
Copy link
Collaborator

llvm-ci commented Sep 28, 2025

LLVM Buildbot has detected a new failure on builder openmp-offload-sles-build-only running on rocm-worker-hw-04-sles while building llvm at step 9 "Add check check-llvm".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/140/builds/31501

Here is the relevant piece of the build log for the reference
Step 9 (Add check check-llvm) failure: test (failure)
...
[723/738] Linking CXX executable unittests/DebugInfo/DWARF/DebugInfoDWARFTests
[724/738] Linking CXX executable unittests/DebugInfo/LogicalView/DebugInfoLogicalViewTests
[725/738] Linking CXX executable unittests/Target/X86/X86Tests
[726/738] Linking CXX executable unittests/MIR/MIRTests
[727/738] Linking CXX executable unittests/Passes/Plugins/PluginsTests
[728/738] Linking CXX executable unittests/ExecutionEngine/MCJIT/MCJITTests
[729/738] Linking CXX executable unittests/MI/MITests
[730/738] Linking CXX executable unittests/tools/llvm-mca/LLVMMCATests
[731/738] Linking CXX executable unittests/tools/llvm-exegesis/LLVMExegesisTests
[732/738] Building CXX object unittests/CodeGen/CMakeFiles/CodeGenTests.dir/TypeTraitsTest.cpp.o
FAILED: unittests/CodeGen/CMakeFiles/CodeGenTests.dir/TypeTraitsTest.cpp.o 
ccache /usr/bin/c++ -DGTEST_HAS_RTTI=0 -DLLVM_BUILD_STATIC -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Iunittests/CodeGen -I/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/unittests/CodeGen -Iinclude -I/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/include -I/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/third-party/unittest/googletest/include -I/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/third-party/unittest/googlemock/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wno-missing-field-initializers -pedantic -Wno-long-long -Wimplicit-fallthrough -Wno-uninitialized -Wno-nonnull -Wno-array-bounds -Wno-noexcept-type -Wdelete-non-virtual-dtor -Wno-comment -Wno-misleading-indentation -fdiagnostics-color -ffunction-sections -fdata-sections -O3 -DNDEBUG  -Wno-dangling-else -Wno-variadic-macros -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -Wno-suggest-override -std=c++1z -MD -MT unittests/CodeGen/CMakeFiles/CodeGenTests.dir/TypeTraitsTest.cpp.o -MF unittests/CodeGen/CMakeFiles/CodeGenTests.dir/TypeTraitsTest.cpp.o.d -o unittests/CodeGen/CMakeFiles/CodeGenTests.dir/TypeTraitsTest.cpp.o -c /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/unittests/CodeGen/TypeTraitsTest.cpp
In file included from /home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:11:0:
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/include/llvm/CodeGen/ScheduleDAG.h:321:40: warning: ‘llvm::SUnit::SchedulingPref’ is too small to hold all values of ‘enum llvm::Sched::Preference’
     Sched::Preference SchedulingPref : 4; ///< Scheduling preference.
                                        ^
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:57:1: error: non-constant condition for static assertion
 static_assert(CheckStdCmpRequirements<std::less<rdf::RegisterRef>>(),
 ^~~~~~~~~~~~~
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:57:67: error: ‘constexpr bool CheckStdCmpRequirements() [with Fn = std::less<llvm::rdf::RegisterRef>]’ called in a constant expression
 static_assert(CheckStdCmpRequirements<std::less<rdf::RegisterRef>>(),
               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:39:36: note: ‘constexpr bool CheckStdCmpRequirements() [with Fn = std::less<llvm::rdf::RegisterRef>]’ is not usable as a constexpr function because:
 template <class Fn> constexpr bool CheckStdCmpRequirements() {
                                    ^~~~~~~~~~~~~~~~~~~~~~~
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:42:6: error: uninitialized variable ‘f1’ in ‘constexpr’ function
   Fn f1;
      ^~
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:59:1: error: non-constant condition for static assertion
 static_assert(CheckStdCmpRequirements<std::equal_to<rdf::RegisterRef>>(),
 ^~~~~~~~~~~~~
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:59:71: error: ‘constexpr bool CheckStdCmpRequirements() [with Fn = std::equal_to<llvm::rdf::RegisterRef>]’ called in a constant expression
 static_assert(CheckStdCmpRequirements<std::equal_to<rdf::RegisterRef>>(),
               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:39:36: note: ‘constexpr bool CheckStdCmpRequirements() [with Fn = std::equal_to<llvm::rdf::RegisterRef>]’ is not usable as a constexpr function because:
 template <class Fn> constexpr bool CheckStdCmpRequirements() {
                                    ^~~~~~~~~~~~~~~~~~~~~~~
/home/botworker/bbot/builds/openmp-offload-sles-build/llvm.src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:42:6: error: uninitialized variable ‘f1’ in ‘constexpr’ function
   Fn f1;
      ^~
[733/738] Linking CXX executable unittests/CodeGen/CGPluginTest/CGPluginTest
[734/738] Linking CXX executable unittests/Transforms/Scalar/ScalarTests
[735/738] Linking CXX executable unittests/Target/TargetMachineCTests
[736/738] Linking CXX executable unittests/Target/AMDGPU/AMDGPUTests
ninja: build stopped: subcommand failed.

@llvm-ci
Copy link
Collaborator

llvm-ci commented Sep 28, 2025

LLVM Buildbot has detected a new failure on builder clang-ppc64le-linux-test-suite running on ppc64le-clang-test-suite while building llvm at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/95/builds/18471

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'LeakSanitizer-Standalone-powerpc64le :: TestCases/create_thread_leak.cpp' FAILED ********************
Exit Code: 2

Command Output (stderr):
--
/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/build/./bin/clang  --driver-mode=g++ -O0  -m64 -fno-function-sections  -gline-tables-only -fsanitize=leak -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/llvm-project/compiler-rt/test/lsan/../ -pthread /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/llvm-project/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp -o /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/build/runtimes/runtimes-bins/compiler-rt/test/lsan/POWERPC64LELsanConfig/TestCases/Output/create_thread_leak.cpp.tmp # RUN: at line 3
+ /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/build/./bin/clang --driver-mode=g++ -O0 -m64 -fno-function-sections -gline-tables-only -fsanitize=leak -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/llvm-project/compiler-rt/test/lsan/../ -pthread /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/llvm-project/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp -o /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/build/runtimes/runtimes-bins/compiler-rt/test/lsan/POWERPC64LELsanConfig/TestCases/Output/create_thread_leak.cpp.tmp
not  /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/build/runtimes/runtimes-bins/compiler-rt/test/lsan/POWERPC64LELsanConfig/TestCases/Output/create_thread_leak.cpp.tmp 10 1 0 0 2>&1 | FileCheck /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/llvm-project/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp --check-prefixes=LEAK,LEAK123 # RUN: at line 4
+ FileCheck /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/llvm-project/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp --check-prefixes=LEAK,LEAK123
+ not /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/build/runtimes/runtimes-bins/compiler-rt/test/lsan/POWERPC64LELsanConfig/TestCases/Output/create_thread_leak.cpp.tmp 10 1 0 0
not  /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/build/runtimes/runtimes-bins/compiler-rt/test/lsan/POWERPC64LELsanConfig/TestCases/Output/create_thread_leak.cpp.tmp 10 0 1 0 2>&1 | FileCheck /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/llvm-project/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp --check-prefixes=LEAK,LEAK234 # RUN: at line 5
+ not /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/build/runtimes/runtimes-bins/compiler-rt/test/lsan/POWERPC64LELsanConfig/TestCases/Output/create_thread_leak.cpp.tmp 10 0 1 0
+ FileCheck /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/llvm-project/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp --check-prefixes=LEAK,LEAK234
not  /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/build/runtimes/runtimes-bins/compiler-rt/test/lsan/POWERPC64LELsanConfig/TestCases/Output/create_thread_leak.cpp.tmp 10 0 0 1 2>&1 | FileCheck /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/llvm-project/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp --check-prefixes=LEAK,LEAK234 # RUN: at line 6
+ FileCheck /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/llvm-project/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp --check-prefixes=LEAK,LEAK234
+ not /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/build/runtimes/runtimes-bins/compiler-rt/test/lsan/POWERPC64LELsanConfig/TestCases/Output/create_thread_leak.cpp.tmp 10 0 0 1
FileCheck error: '<stdin>' is empty.
FileCheck command line:  FileCheck /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-test-suite/clang-ppc64le-test-suite/llvm-project/compiler-rt/test/lsan/TestCases/create_thread_leak.cpp --check-prefixes=LEAK,LEAK234

--

********************


@pawosm-arm
Copy link
Contributor

Sadly, it fails in our CI:

[2025-09-29T11:25:35.281Z] In file included from /workspace/src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:11:0:
[2025-09-29T11:25:35.281Z] /workspace/src/llvm/include/llvm/CodeGen/ScheduleDAG.h:321:40: warning: 'llvm::SUnit::SchedulingPref' is too small to hold all values of 'enum llvm::Sched::Preference'
[2025-09-29T11:25:35.281Z]      Sched::Preference SchedulingPref : 4; ///< Scheduling preference.
[2025-09-29T11:25:35.281Z]                                         ^
[2025-09-29T11:25:35.281Z] /workspace/src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:57:1: error: non-constant condition for static assertion
[2025-09-29T11:25:35.281Z]  static_assert(CheckStdCmpRequirements<std::less<rdf::RegisterRef>>(),
[2025-09-29T11:25:35.281Z]  ^~~~~~~~~~~~~
[2025-09-29T11:25:35.281Z] /workspace/src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:57:67: error: 'constexpr bool CheckStdCmpRequirements() [with Fn = std::less<llvm::rdf::RegisterRef>]' called in a constant expression
[2025-09-29T11:25:35.281Z]  static_assert(CheckStdCmpRequirements<std::less<rdf::RegisterRef>>(),
[2025-09-29T11:25:35.281Z]                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
[2025-09-29T11:25:35.281Z] /workspace/src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:39:36: note: 'constexpr bool CheckStdCmpRequirements() [with Fn = std::less<llvm::rdf::RegisterRef>]' is not usable as a constexpr function because:
[2025-09-29T11:25:35.281Z]  template <class Fn> constexpr bool CheckStdCmpRequirements() {
[2025-09-29T11:25:35.281Z]                                     ^~~~~~~~~~~~~~~~~~~~~~~
[2025-09-29T11:25:35.281Z] /workspace/src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:42:6: error: uninitialized variable 'f1' in 'constexpr' function
[2025-09-29T11:25:35.281Z]    Fn f1;
[2025-09-29T11:25:35.281Z]       ^~
[2025-09-29T11:25:35.281Z] /workspace/src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:59:1: error: non-constant condition for static assertion
[2025-09-29T11:25:35.281Z]  static_assert(CheckStdCmpRequirements<std::equal_to<rdf::RegisterRef>>(),
[2025-09-29T11:25:35.281Z]  ^~~~~~~~~~~~~
[2025-09-29T11:25:35.281Z] /workspace/src/llvm/unittests/CodeGen/TypeTraitsTest.cpp:59:71: error: 'constexpr bool CheckStdCmpRequirements() [with Fn = std::equal_to<llvm::rdf::RegisterRef>]' called in a constant expression

@frederick-vs-ja
Copy link
Contributor Author

@pawosm-arm #161085 Should have fixed CI failure due to uninitialized variables.

@pawosm-arm
Copy link
Contributor

@pawosm-arm #161085 Should have fixed CI failure due to uninitialized variables.

Yup, it just passed through it and no sign of failure.

mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Oct 3, 2025
…60804)

This patch renames comparators
- from `std::equal_to<llvm::rdf::RegisterRef>` to
`llvm::rdf::RegisterRefEqualTo`, and
- from `std::less<llvm::rdf::RegisterRef>` to
`llvm::rdf::RegisterRefLess`.

The original specializations don't satisfy the requirements for the
original `std` templates by being stateful and
non-default-constructible, so they make the program have UB due to C++17
[namespace.std]/2, C++20/23 [namespace.std]/5.

> A program may explicitly instantiate a class template defined in the
standard library only if the declaration
> - depends on the name of at least one program-defined type, and
> - the instantiation meets the standard library requirements for the
original template.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[CodeGen] std::less<llvm::rdf::RegisterRef> and std::equal_to<llvm::rdf::RegisterRef> full specializations don't satisfy the standard requirements
7 participants