Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
14 changes: 12 additions & 2 deletions clang/lib/AST/ComparisonCategories.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -83,7 +83,17 @@ 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();
Comment on lines +89 to +91
Copy link
Contributor

Choose a reason for hiding this comment

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

ValueDecl is already a class name. It would be nice to rename these variables.

if (!ValueDeclRecord ||
ValueDeclRecord->getCanonicalDecl() != Record->getCanonicalDecl())
return nullptr;

Objects.emplace_back(ValueKind, ValueDecl);
return &Objects.back();
}

Expand Down
41 changes: 41 additions & 0 deletions clang/test/SemaCXX/PR172001.cpp
Original file line number Diff line number Diff line change
@@ -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>}}
}