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
