[clang] [clang][Interp] Handle virtual calls with covariant return types (PR #101218)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 30 23:19:29 PDT 2024


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

>From 78961fbfbd791844b1622aa305664199e3451260 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 30 Jul 2024 20:11:37 +0200
Subject: [PATCH] [clang][Interp] Handle virtual calls with covariant return
 types

---
 clang/lib/AST/Interp/Interp.h   | 24 +++++++++++++++++++++++-
 clang/test/AST/Interp/cxx2a.cpp | 21 +++++++++++++++++++++
 2 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index d128988a480e1..63e9966b831db 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -2628,7 +2628,29 @@ inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
     }
   }
 
-  return Call(S, OpPC, Func, VarArgSize);
+  if (!Call(S, OpPC, Func, VarArgSize))
+    return false;
+
+  // Covariant return types. The return type of Overrider is a pointer
+  // or reference to a class type.
+  if (Overrider != InitialFunction &&
+      Overrider->getReturnType()->isPointerOrReferenceType() &&
+      InitialFunction->getReturnType()->isPointerOrReferenceType()) {
+    QualType OverriderPointeeType =
+        Overrider->getReturnType()->getPointeeType();
+    QualType InitialPointeeType =
+        InitialFunction->getReturnType()->getPointeeType();
+    // We've called Overrider above, but calling code expects us to return what
+    // InitialFunction returned. According to the rules for covariant return
+    // types, what InitialFunction returns needs to be a base class of what
+    // Overrider returns. So, we need to do an upcast here.
+    unsigned Offset = S.getContext().collectBaseOffset(
+        InitialPointeeType->getAsRecordDecl(),
+        OverriderPointeeType->getAsRecordDecl());
+    return GetPtrBasePop(S, OpPC, Offset);
+  }
+
+  return true;
 }
 
 inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
diff --git a/clang/test/AST/Interp/cxx2a.cpp b/clang/test/AST/Interp/cxx2a.cpp
index 27d1aa1a27f75..ad021b30cfd3c 100644
--- a/clang/test/AST/Interp/cxx2a.cpp
+++ b/clang/test/AST/Interp/cxx2a.cpp
@@ -13,3 +13,24 @@ consteval int aConstevalFunction() { // both-error {{consteval function never pr
   return 0;
 }
 /// We're NOT calling the above function. The diagnostics should appear anyway.
+
+namespace Covariant {
+  struct A {
+    virtual constexpr char f() const { return 'Z'; }
+    char a = f();
+  };
+
+  struct D : A {};
+  struct Covariant1 {
+    D d;
+    virtual const A *f() const;
+  };
+
+  struct Covariant3 : Covariant1 {
+    constexpr virtual const D *f() const { return &this->d; }
+  };
+
+  constexpr Covariant3 cb;
+  constexpr const Covariant1 *cb1 = &cb;
+  static_assert(cb1->f()->a == 'Z');
+}



More information about the cfe-commits mailing list