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

Reply via email to