https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/201588
Diagnose comparisons between base classes as well as base classes and fields. Also add some test cases for things that currently fail because we compute the wrong offset. >From de03ecb74afc45db932c6fce7d5fb561c4b66e31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]> Date: Thu, 4 Jun 2026 14:28:40 +0200 Subject: [PATCH] base cmp --- clang/lib/AST/ByteCode/Interp.h | 18 +++++++++++++++--- clang/lib/AST/ByteCode/Pointer.cpp | 7 ++++++- clang/test/AST/ByteCode/cxx11.cpp | 28 ++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index fa77e19afce66..7a4b527975e68 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -1236,13 +1236,25 @@ inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { return false; } - // Diagnose comparisons between fields with different access specifiers. + // Diagnose comparisons between fields with different access specifiers, + // comparisons between bases and bases+fields. if (std::optional<std::pair<Pointer, Pointer>> Split = Pointer::computeSplitPoint(LHS, RHS)) { const FieldDecl *LF = Split->first.getField(); const FieldDecl *RF = Split->second.getField(); - if (LF && RF && !LF->getParent()->isUnion() && - LF->getAccess() != RF->getAccess()) { + if (!LF && !RF) + S.CCEDiag(S.Current->getSource(OpPC), + diag::note_constexpr_pointer_comparison_base_classes); + else if (!LF) + S.CCEDiag(S.Current->getSource(OpPC), + diag::note_constexpr_pointer_comparison_base_field) + << Split->first.getRecord()->getDecl() << RF->getParent() << RF; + else if (!RF) + S.CCEDiag(S.Current->getSource(OpPC), + diag::note_constexpr_pointer_comparison_base_field) + << Split->second.getRecord()->getDecl() << LF->getParent() << LF; + else if (!LF->getParent()->isUnion() && + LF->getAccess() != RF->getAccess()) { S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_pointer_comparison_differing_access) << LF << LF->getAccess() << RF << RF->getAccess() << LF->getParent(); diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 96409faeb6929..af6e728f72a05 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -789,8 +789,13 @@ Pointer::computeSplitPoint(const Pointer &A, const Pointer &B) { IterB = getBase(IterB); } - if (IterA == IterB) + if (IterA == IterB) { + // If the Iter is an array, CurA and CurB are both elements of the same + // array. That is fine, so return nullopt. + if (IterA.getFieldDesc()->isArray()) + return std::nullopt; return std::make_pair(CurA, CurB); + } if (IterA.isRoot() && IterB.isRoot()) return std::nullopt; diff --git a/clang/test/AST/ByteCode/cxx11.cpp b/clang/test/AST/ByteCode/cxx11.cpp index b58088096e377..aa1dff417b7dc 100644 --- a/clang/test/AST/ByteCode/cxx11.cpp +++ b/clang/test/AST/ByteCode/cxx11.cpp @@ -445,3 +445,31 @@ namespace AddSubMulNonNumber { a:b:return; } } + +namespace SubobjectCompare { + struct S { + int i; + }; + constexpr S s[2] = {}; + static_assert(&s[0].i < &s[1].i, ""); + static_assert(&s[0].i != &s[1].i, ""); + + class A { public: int a; }; + class B : public A { public: int b; }; + class C : public B { }; + constexpr C c{}; + static_assert(&c.a < &c.b, ""); // both-error {{not an integral constant expression}} \ + // both-note {{comparison of address of base class subobject 'A' of class 'B' to field 'b' has unspecified value}} + static_assert(&c.a != &c.b, ""); + + class X { public: int x; }; + class Y { public: int y; }; + class Z : public X, public Y {}; + constexpr Z z{}; + static_assert(&z.x < &z.y, ""); // both-error {{not an integral constant expression}} \ + // both-note {{comparison of addresses of subobjects of different base classes has unspecified value}} + static_assert(&z.x != &z.y, ""); // expected-error {{failed}} FIXME + static_assert((void*)(X*)&z < (void*)(Y*)&z, ""); // both-error {{not an integral constant expression}} \ + // both-note {{comparison of addresses of subobjects of different base classes has unspecified value}} + static_assert((void*)(X*)&z != (void*)(Y*)&z, ""); // expected-error {{failed}} FIXME +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
