https://github.com/tbaederr updated 
https://github.com/llvm/llvm-project/pull/201588

>From 2a1e7afd9cbf0b1be39b7cb85f151116c1cd8235 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               | 23 +++++++++++++--
 clang/lib/AST/ByteCode/Pointer.cpp            |  7 ++++-
 clang/test/AST/ByteCode/cxx11.cpp             | 29 +++++++++++++++++++
 .../SemaCXX/constant-expression-p2280r4.cpp   |  4 +--
 4 files changed, 57 insertions(+), 6 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index fa77e19afce66..d131d11dd88dd 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1228,6 +1228,11 @@ inline bool CmpHelper<Pointer>(InterpState &S, CodePtr 
OpPC, CompareFn Fn) {
     return false;
   }
 
+  if (LHS == RHS) {
+    S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
+    return true;
+  }
+
   if (!Pointer::hasSameBase(LHS, RHS)) {
     const SourceInfo &Loc = S.Current->getSource(OpPC);
     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
@@ -1236,13 +1241,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..5d217f0bdd6cc 100644
--- a/clang/test/AST/ByteCode/cxx11.cpp
+++ b/clang/test/AST/ByteCode/cxx11.cpp
@@ -445,3 +445,32 @@ 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, "");
+  static_assert(!(&s[0] < &s[0]), "");
+
+  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
+}
diff --git a/clang/test/SemaCXX/constant-expression-p2280r4.cpp 
b/clang/test/SemaCXX/constant-expression-p2280r4.cpp
index 8b768f42d1260..13d727f33e123 100644
--- a/clang/test/SemaCXX/constant-expression-p2280r4.cpp
+++ b/clang/test/SemaCXX/constant-expression-p2280r4.cpp
@@ -376,8 +376,8 @@ namespace GH150015 {
   struct Y {};
   struct Z : X, Y {};
   extern Z &z;
-  constexpr int bases = (void*)(X*)&z <= (Y*)&z; // nointerpreter-error 
{{constexpr variable 'bases' must be initialized by a constant expression}} \
-                                                 // nointerpreter-note 
{{comparison of addresses of subobjects of different base classes has 
unspecified value}}
+  constexpr int bases = (void*)(X*)&z <= (Y*)&z; // expected-error {{constexpr 
variable 'bases' must be initialized by a constant expression}} \
+                                                 // expected-note {{comparison 
of addresses of subobjects of different base classes has unspecified value}}
 }
 
 namespace InvalidConstexprFn {

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

Reply via email to