https://github.com/code-pankaj updated 
https://github.com/llvm/llvm-project/pull/172001

>From e627d929cb8bc01dad82610219fbb362635b6f00 Mon Sep 17 00:00:00 2001
From: code-pankaj <[email protected]>
Date: Fri, 12 Dec 2025 18:02:34 +0530
Subject: [PATCH 1/9] [Clang] Fix crash on malformed std::partial_ordering
 static members

This fixes a crash (segmentation fault) when the standard library 
implementation of comparison categories (like `std::partial_ordering`) is 
malformed.

Specifically, if the static members (like `equivalent`) are defined as a 
primitive type (e.g., `int`) instead of the comparison category type itself, 
the compiler previously attempted to process them incorrectly, leading to a 
crash.

This patch adds strict type checking in 
`ComparisonCategoryInfo::lookupValueInfo`. If the found static member does not 
match the record type, it is rejected safely, triggering a diagnostic error 
instead of a crash.

Fixes #170015
---
 clang/docs/ReleaseNotes.rst                   |  1 +
 clang/lib/AST/ComparisonCategories.cpp        | 11 ++++++--
 .../SemaCXX/cxx2a-three-way-comparison.cpp    | 25 +++++++++++++++++++
 3 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 22ca79d6adc28..702903bd0225a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -602,6 +602,7 @@ Bug Fixes to C++ Support
 - Fixed an issue where templates prevented nested anonymous records from 
checking the deletion of special members. (#GH167217)
 - Fixed spurious diagnoses of certain nested lambda expressions. (#GH149121) 
(#GH156579)
 - Fix the result of ``__is_pointer_interconvertible_base_of`` when arguments 
are qualified and passed via template parameters. (#GH135273)
+- - Fixed a crash when standard comparison categories (e.g. 
``std::partial_ordering``) are defined with incorrect static member types. 
(#GH170015)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/AST/ComparisonCategories.cpp 
b/clang/lib/AST/ComparisonCategories.cpp
index 1b9c938e2ace3..afa662dccab00 100644
--- a/clang/lib/AST/ComparisonCategories.cpp
+++ b/clang/lib/AST/ComparisonCategories.cpp
@@ -49,7 +49,7 @@ bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() 
const {
   // Before we attempt to get the value of the first field, ensure that we
   // actually have one (and only one) field.
   const auto *Record = VD->getType()->getAsCXXRecordDecl();
-  if (Record->getNumFields() != 1 ||
+  if (!Record || Record->getNumFields() != 1 ||
       !Record->field_begin()->getType()->isIntegralOrEnumerationType())
     return false;
 
@@ -83,7 +83,14 @@ ComparisonCategoryInfo::ValueInfo 
*ComparisonCategoryInfo::lookupValueInfo(
       &Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind)));
   if (Lookup.empty() || !isa<VarDecl>(Lookup.front()))
     return nullptr;
-  Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front()));
+  // The static member must have the same type as the comparison category class
+  // itself (e.g., std::partial_ordering::less must be of type 
partial_ordering).
+  VarDecl *ValueDecl = cast<VarDecl>(Lookup.front());
+  const CXXRecordDecl *ValueDeclRecord = 
ValueDecl->getType()->getAsCXXRecordDecl();
+  if (!ValueDeclRecord || ValueDeclRecord->getCanonicalDecl() != 
Record->getCanonicalDecl())
+    return nullptr;
+
+  Objects.emplace_back(ValueKind, ValueDecl);
   return &Objects.back();
 }
 
diff --git a/clang/test/SemaCXX/cxx2a-three-way-comparison.cpp 
b/clang/test/SemaCXX/cxx2a-three-way-comparison.cpp
index 76007ff3913dd..31b6f367e9cce 100644
--- a/clang/test/SemaCXX/cxx2a-three-way-comparison.cpp
+++ b/clang/test/SemaCXX/cxx2a-three-way-comparison.cpp
@@ -67,3 +67,28 @@ struct comparable_t {
                                                                   
expected-note {{defaulted 'operator<=>' is implicitly deleted because defaulted 
comparison of vector types is not supported}}
 };
 } // namespace GH137452
+
+namespace GH170015 {
+// This test ensures that the compiler enforces strict type checking on the 
+// static members of comparison category types.
+// Previously, a mismatch (e.g., equivalent being an int) could crash the 
compiler.
+}
+
+namespace std {
+  struct partial_ordering {
+    // Malformed: 'equivalent' should be of type 'partial_ordering', not 'int'.
+    static constexpr int equivalent = 0; 
+    static constexpr int less = -1;
+    static constexpr int greater = 1;
+    static constexpr int unordered = 2;
+  };
+}
+
+namespace GH170015 {
+  void f() {
+    float a = 0.0f, b = 0.0f;
+    // We expect the compiler to complain that the type form is wrong 
+    // (because the static members are ints, not objects).
+    auto res = a <=> b; // expected-error {{standard library implementation of 
'std::partial_ordering' is not supported; the type does not have the expected 
form}}
+  }
+}
\ No newline at end of file

>From cd04c2274c377aaf83b272b1d0bc5e8ab4167845 Mon Sep 17 00:00:00 2001
From: code-pankaj <[email protected]>
Date: Sat, 13 Dec 2025 14:23:26 +0530
Subject: [PATCH 2/9] [Clang] Update regression tests for GH170015

Moved the regression test to a dedicated file (clang/test/SemaCXX/PR172001.cpp) 
to cover all requested edge cases, including typedefs and forward declarations. 
Reverted changes to clang/test/SemaCXX/cxx2a-three-way-comparison.cpp.
---
 clang/lib/AST/ComparisonCategories.cpp        |  9 ++--
 clang/test/SemaCXX/PR172001.cpp               | 41 +++++++++++++++++++
 .../SemaCXX/cxx2a-three-way-comparison.cpp    | 25 -----------
 3 files changed, 47 insertions(+), 28 deletions(-)
 create mode 100644 clang/test/SemaCXX/PR172001.cpp

diff --git a/clang/lib/AST/ComparisonCategories.cpp 
b/clang/lib/AST/ComparisonCategories.cpp
index afa662dccab00..c6093c50af7fe 100644
--- a/clang/lib/AST/ComparisonCategories.cpp
+++ b/clang/lib/AST/ComparisonCategories.cpp
@@ -84,10 +84,13 @@ ComparisonCategoryInfo::ValueInfo 
*ComparisonCategoryInfo::lookupValueInfo(
   if (Lookup.empty() || !isa<VarDecl>(Lookup.front()))
     return nullptr;
   // The static member must have the same type as the comparison category class
-  // itself (e.g., std::partial_ordering::less must be of type 
partial_ordering).
+  // itself (e.g., std::partial_ordering::less must be of type
+  // partial_ordering).
   VarDecl *ValueDecl = cast<VarDecl>(Lookup.front());
-  const CXXRecordDecl *ValueDeclRecord = 
ValueDecl->getType()->getAsCXXRecordDecl();
-  if (!ValueDeclRecord || ValueDeclRecord->getCanonicalDecl() != 
Record->getCanonicalDecl())
+  const CXXRecordDecl *ValueDeclRecord =
+      ValueDecl->getType()->getAsCXXRecordDecl();
+  if (!ValueDeclRecord ||
+      ValueDeclRecord->getCanonicalDecl() != Record->getCanonicalDecl())
     return nullptr;
 
   Objects.emplace_back(ValueKind, ValueDecl);
diff --git a/clang/test/SemaCXX/PR172001.cpp b/clang/test/SemaCXX/PR172001.cpp
new file mode 100644
index 0000000000000..a493d9114b205
--- /dev/null
+++ b/clang/test/SemaCXX/PR172001.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c++20 -verify=test1 -DTEST1 %s
+// RUN: %clang_cc1 -std=c++20 -verify=test2 -DTEST2 %s
+// RUN: %clang_cc1 -std=c++20 -verify=test3 -DTEST3 %s
+// RUN: %clang_cc1 -std=c++20 -verify=test4 -DTEST4 %s
+
+namespace std {
+#ifdef TEST1
+  // Case 1: Malformed struct (static members are wrong type)
+  // This triggered the original crash (GH170015).
+  struct partial_ordering {
+    static constexpr int equivalent = 0;
+    static constexpr int less = -1;
+    static constexpr int greater = 1;
+    static constexpr int unordered = 2;
+  };
+#elif defined(TEST2)
+  // Case 2: partial_ordering is a typedef to int
+  using partial_ordering = int;
+#elif defined(TEST3)
+  // Case 3: partial_ordering is a forward declaration
+  struct partial_ordering; // test3-note {{forward declaration of 
'std::partial_ordering'}}
+#elif defined(TEST4)
+  // Case 4: partial_ordering is a template (Paranoia check)
+  template <class> struct partial_ordering {
+    static const partial_ordering less;
+    static const partial_ordering equivalent;
+    static const partial_ordering greater;
+    static const partial_ordering unordered;
+  };
+#endif
+}
+
+void f() {
+  float a = 0.0f, b = 0.0f;
+  auto res = a <=> b; 
+  // test1-error@-1 {{standard library implementation of 
'std::partial_ordering' is not supported; the type does not have the expected 
form}}
+  // test2-error@-2 {{cannot use builtin operator '<=>' because type 
'std::partial_ordering' was not found; include <compare>}}
+  // test3-error@-3 {{incomplete type 'std::partial_ordering' where a complete 
type is required}}
+  // test4-error@-4 {{cannot use builtin operator '<=>' because type 
'std::partial_ordering' was not found; include <compare>}}
+}
+ 
\ No newline at end of file
diff --git a/clang/test/SemaCXX/cxx2a-three-way-comparison.cpp 
b/clang/test/SemaCXX/cxx2a-three-way-comparison.cpp
index 31b6f367e9cce..76007ff3913dd 100644
--- a/clang/test/SemaCXX/cxx2a-three-way-comparison.cpp
+++ b/clang/test/SemaCXX/cxx2a-three-way-comparison.cpp
@@ -67,28 +67,3 @@ struct comparable_t {
                                                                   
expected-note {{defaulted 'operator<=>' is implicitly deleted because defaulted 
comparison of vector types is not supported}}
 };
 } // namespace GH137452
-
-namespace GH170015 {
-// This test ensures that the compiler enforces strict type checking on the 
-// static members of comparison category types.
-// Previously, a mismatch (e.g., equivalent being an int) could crash the 
compiler.
-}
-
-namespace std {
-  struct partial_ordering {
-    // Malformed: 'equivalent' should be of type 'partial_ordering', not 'int'.
-    static constexpr int equivalent = 0; 
-    static constexpr int less = -1;
-    static constexpr int greater = 1;
-    static constexpr int unordered = 2;
-  };
-}
-
-namespace GH170015 {
-  void f() {
-    float a = 0.0f, b = 0.0f;
-    // We expect the compiler to complain that the type form is wrong 
-    // (because the static members are ints, not objects).
-    auto res = a <=> b; // expected-error {{standard library implementation of 
'std::partial_ordering' is not supported; the type does not have the expected 
form}}
-  }
-}
\ No newline at end of file

>From ebc36721bbe13a76ba74fb31aed92cfd00a7d93d Mon Sep 17 00:00:00 2001
From: Pankaj <[email protected]>
Date: Sat, 13 Dec 2025 14:36:10 +0530
Subject: [PATCH 3/9] removed extra hyphen

---
 clang/docs/ReleaseNotes.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 702903bd0225a..477e6ca67c818 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -602,7 +602,7 @@ Bug Fixes to C++ Support
 - Fixed an issue where templates prevented nested anonymous records from 
checking the deletion of special members. (#GH167217)
 - Fixed spurious diagnoses of certain nested lambda expressions. (#GH149121) 
(#GH156579)
 - Fix the result of ``__is_pointer_interconvertible_base_of`` when arguments 
are qualified and passed via template parameters. (#GH135273)
-- - Fixed a crash when standard comparison categories (e.g. 
``std::partial_ordering``) are defined with incorrect static member types. 
(#GH170015)
+- Fixed a crash when standard comparison categories (e.g. 
``std::partial_ordering``) are defined with incorrect static member types. 
(#GH170015)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^

>From 49c3c40875344b6cef4e211a9e865328ef460ec0 Mon Sep 17 00:00:00 2001
From: Pankaj <[email protected]>
Date: Sat, 13 Dec 2025 18:07:18 +0530
Subject: [PATCH 4/9] added new line

---
 clang/test/SemaCXX/PR172001.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/test/SemaCXX/PR172001.cpp b/clang/test/SemaCXX/PR172001.cpp
index a493d9114b205..20ac0fe8d8e30 100644
--- a/clang/test/SemaCXX/PR172001.cpp
+++ b/clang/test/SemaCXX/PR172001.cpp
@@ -38,4 +38,6 @@ void f() {
   // test3-error@-3 {{incomplete type 'std::partial_ordering' where a complete 
type is required}}
   // test4-error@-4 {{cannot use builtin operator '<=>' because type 
'std::partial_ordering' was not found; include <compare>}}
 }
+
+
  
\ No newline at end of file

>From ed2e848d2bdbd42f799443b25874fa14ccf454a0 Mon Sep 17 00:00:00 2001
From: Pankaj <[email protected]>
Date: Sat, 13 Dec 2025 18:14:44 +0530
Subject: [PATCH 5/9] new line fix

---
 clang/test/SemaCXX/PR172001.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/clang/test/SemaCXX/PR172001.cpp b/clang/test/SemaCXX/PR172001.cpp
index 20ac0fe8d8e30..ba5f8e68707e9 100644
--- a/clang/test/SemaCXX/PR172001.cpp
+++ b/clang/test/SemaCXX/PR172001.cpp
@@ -39,5 +39,3 @@ void f() {
   // test4-error@-4 {{cannot use builtin operator '<=>' because type 
'std::partial_ordering' was not found; include <compare>}}
 }
 
-
- 
\ No newline at end of file

>From 309dad480029f69653d260d9a183c5ec5016f854 Mon Sep 17 00:00:00 2001
From: code-pankaj <[email protected]>
Date: Tue, 16 Dec 2025 13:23:10 +0530
Subject: [PATCH 6/9] renamed ValueDecl to VD and ValueDeclRecord to VDRecord

---
 clang/lib/AST/ComparisonCategories.cpp | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang/lib/AST/ComparisonCategories.cpp 
b/clang/lib/AST/ComparisonCategories.cpp
index c6093c50af7fe..355123f6a90ec 100644
--- a/clang/lib/AST/ComparisonCategories.cpp
+++ b/clang/lib/AST/ComparisonCategories.cpp
@@ -86,14 +86,14 @@ ComparisonCategoryInfo::ValueInfo 
*ComparisonCategoryInfo::lookupValueInfo(
   // The static member must have the same type as the comparison category class
   // itself (e.g., std::partial_ordering::less must be of type
   // partial_ordering).
-  VarDecl *ValueDecl = cast<VarDecl>(Lookup.front());
-  const CXXRecordDecl *ValueDeclRecord =
-      ValueDecl->getType()->getAsCXXRecordDecl();
-  if (!ValueDeclRecord ||
-      ValueDeclRecord->getCanonicalDecl() != Record->getCanonicalDecl())
+  VarDecl *VD = cast<VarDecl>(Lookup.front());
+  const CXXRecordDecl *VDRecord =
+      VD->getType()->getAsCXXRecordDecl();
+  if (!VDRecord ||
+      VDRecord->getCanonicalDecl() != Record->getCanonicalDecl())
     return nullptr;
 
-  Objects.emplace_back(ValueKind, ValueDecl);
+  Objects.emplace_back(ValueKind, VD);
   return &Objects.back();
 }
 

>From ea1df6609cd369e8c06b3a28706b6fc96c8228a9 Mon Sep 17 00:00:00 2001
From: code-pankaj <[email protected]>
Date: Tue, 16 Dec 2025 13:34:03 +0530
Subject: [PATCH 7/9] added strong ordering testcase for issue 56571

---
 clang/test/SemaCXX/PR172001.cpp | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/clang/test/SemaCXX/PR172001.cpp b/clang/test/SemaCXX/PR172001.cpp
index ba5f8e68707e9..1378727da789b 100644
--- a/clang/test/SemaCXX/PR172001.cpp
+++ b/clang/test/SemaCXX/PR172001.cpp
@@ -2,6 +2,7 @@
 // RUN: %clang_cc1 -std=c++20 -verify=test2 -DTEST2 %s
 // RUN: %clang_cc1 -std=c++20 -verify=test3 -DTEST3 %s
 // RUN: %clang_cc1 -std=c++20 -verify=test4 -DTEST4 %s
+// RUN: %clang_cc1 -std=c++20 -verify=test5 -DTEST5 %s
 
 namespace std {
 #ifdef TEST1
@@ -27,15 +28,24 @@ namespace std {
     static const partial_ordering greater;
     static const partial_ordering unordered;
   };
+#elif defined(TEST5)
+  // Case 5: strong_ordering is a typedef to int (covers GH56571)
+  using strong_ordering = int;
 #endif
 }
 
 void f() {
-  float a = 0.0f, b = 0.0f;
+#ifdef TEST5
+  int a = 0, b = 0; // int <=> int requires std::strong_ordering
+#else
+  float a = 0.0f, b = 0.0f; // float <=> float requires std::partial_ordering
+#endif
+
   auto res = a <=> b; 
-  // test1-error@-1 {{standard library implementation of 
'std::partial_ordering' is not supported; the type does not have the expected 
form}}
-  // test2-error@-2 {{cannot use builtin operator '<=>' because type 
'std::partial_ordering' was not found; include <compare>}}
-  // test3-error@-3 {{incomplete type 'std::partial_ordering' where a complete 
type is required}}
-  // test4-error@-4 {{cannot use builtin operator '<=>' because type 
'std::partial_ordering' was not found; include <compare>}}
-}
 
+  // test1-error@-2 {{standard library implementation of 
'std::partial_ordering' is not supported; the type does not have the expected 
form}}
+  // test2-error@-3 {{cannot use builtin operator '<=>' because type 
'std::partial_ordering' was not found; include <compare>}}
+  // test3-error@-4 {{incomplete type 'std::partial_ordering' where a complete 
type is required}}
+  // test4-error@-5 {{cannot use builtin operator '<=>' because type 
'std::partial_ordering' was not found; include <compare>}}
+  // test5-error@-6 {{cannot use builtin operator '<=>' because type 
'std::strong_ordering' was not found; include <compare>}}
+}

>From 23f59dc874d3009f3b460223101e5fbee0b25065 Mon Sep 17 00:00:00 2001
From: code-pankaj <[email protected]>
Date: Tue, 16 Dec 2025 13:49:17 +0530
Subject: [PATCH 8/9] Fix clang-format violations

---
 clang/lib/AST/ComparisonCategories.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/clang/lib/AST/ComparisonCategories.cpp 
b/clang/lib/AST/ComparisonCategories.cpp
index 355123f6a90ec..b2197bd385185 100644
--- a/clang/lib/AST/ComparisonCategories.cpp
+++ b/clang/lib/AST/ComparisonCategories.cpp
@@ -87,10 +87,8 @@ ComparisonCategoryInfo::ValueInfo 
*ComparisonCategoryInfo::lookupValueInfo(
   // itself (e.g., std::partial_ordering::less must be of type
   // partial_ordering).
   VarDecl *VD = cast<VarDecl>(Lookup.front());
-  const CXXRecordDecl *VDRecord =
-      VD->getType()->getAsCXXRecordDecl();
-  if (!VDRecord ||
-      VDRecord->getCanonicalDecl() != Record->getCanonicalDecl())
+  const CXXRecordDecl *VDRecord = VD->getType()->getAsCXXRecordDecl();
+  if (!VDRecord || VDRecord->getCanonicalDecl() != Record->getCanonicalDecl())
     return nullptr;
 
   Objects.emplace_back(ValueKind, VD);

>From 66ded995e0ee1cca3f012e0cf60b8fe22c9e78c6 Mon Sep 17 00:00:00 2001
From: code-pankaj <[email protected]>
Date: Tue, 16 Dec 2025 14:47:08 +0530
Subject: [PATCH 9/9] Update release notes to include GH56571

---
 clang/docs/ReleaseNotes.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ddc08076a0fb9..37100249058ef 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -608,7 +608,7 @@ Bug Fixes to C++ Support
 - Fixed an issue where templates prevented nested anonymous records from 
checking the deletion of special members. (#GH167217)
 - Fixed spurious diagnoses of certain nested lambda expressions. (#GH149121) 
(#GH156579)
 - Fix the result of ``__is_pointer_interconvertible_base_of`` when arguments 
are qualified and passed via template parameters. (#GH135273)
-- Fixed a crash when standard comparison categories (e.g. 
``std::partial_ordering``) are defined with incorrect static member types. 
(#GH170015)
+- Fixed a crash when standard comparison categories (e.g. 
``std::partial_ordering``) are defined with incorrect static member types. 
(#GH170015) (#GH56571)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^

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

Reply via email to