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/3] [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/3] [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/3] 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
 ^^^^^^^^^^^^^^^^^^^^^^^^^

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

Reply via email to