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

>From a8d749e89a2120035be91c6f61727ef7199e3a5d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Fri, 29 May 2026 11:59:16 +0200
Subject: [PATCH] [clang][bytecode] Reject dynamic_cast on constexpr-unknown
 pointers

---
 clang/lib/AST/ByteCode/Compiler.cpp               |  8 +++++++-
 clang/lib/AST/ByteCode/Interp.cpp                 | 15 +++++++++++++++
 clang/lib/AST/ByteCode/Interp.h                   |  1 +
 clang/lib/AST/ByteCode/Opcodes.td                 |  2 ++
 clang/test/AST/ByteCode/cxx23.cpp                 | 14 ++++++++++++++
 .../test/SemaCXX/constant-expression-p2280r4.cpp  |  8 +++-----
 6 files changed, 42 insertions(+), 6 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp 
b/clang/lib/AST/ByteCode/Compiler.cpp
index f339d9a41ac2e..799acc48641e6 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -3549,9 +3549,15 @@ bool Compiler<Emitter>::VisitCXXDynamicCastExpr(const 
CXXDynamicCastExpr *E) {
   if (!Ctx.getLangOpts().CPlusPlus20) {
     if (!this->emitInvalidCast(CastKind::Dynamic, /*Fatal=*/false, E))
       return false;
+    return this->VisitCastExpr(E);
   }
 
-  return this->VisitCastExpr(E);
+  if (!this->visit(E->getSubExpr()))
+    return false;
+  if (!this->emitCheckDynamicCast(E))
+    return false;
+
+  return true;
 }
 
 template <class Emitter>
diff --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index abeda62773dde..6bcebf3ee892b 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1912,6 +1912,21 @@ static bool getDynamicDecl(InterpState &S, CodePtr OpPC, 
Pointer TypePtr,
   return DynamicDecl != nullptr;
 }
 
+bool CheckDynamicCast(InterpState &S, CodePtr OpPC) {
+  const auto &Ptr = S.Stk.peek<Pointer>();
+
+  if (!Ptr.isConstexprUnknown())
+    return true;
+
+  QualType T = Ptr.getType();
+  const Expr *E = S.Current->getExpr(OpPC);
+  APValue V = Ptr.toAPValue(S.getASTContext());
+  QualType TT = S.getASTContext().getLValueReferenceType(T);
+  S.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
+      << AK_DynamicCast << V.getAsString(S.getASTContext(), TT);
+  return false;
+}
+
 bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
               uint32_t VarArgSize) {
   assert(Func->hasThisPointer());
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index a255a1fdf6f16..1ad1c5376701a 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -143,6 +143,7 @@ bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
 bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I);
 bool isConstexprUnknown(const Pointer &P);
 bool isConstexprUnknown(const Block *B);
+bool CheckDynamicCast(InterpState &S, CodePtr OpPC);
 
 enum class ShiftDir { Left, Right };
 
diff --git a/clang/lib/AST/ByteCode/Opcodes.td 
b/clang/lib/AST/ByteCode/Opcodes.td
index 505c7896a0a32..4bd61cdce658d 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -849,6 +849,8 @@ def SideEffect : Opcode {}
 def InvalidCast : Opcode {
   let Args = [ArgCastKind, ArgBool];
 }
+def CheckDynamicCast : Opcode {}
+
 def InvalidStore : Opcode { let Args = [ArgTypePtr]; }
 def CheckPseudoDtor : Opcode {}
 
diff --git a/clang/test/AST/ByteCode/cxx23.cpp 
b/clang/test/AST/ByteCode/cxx23.cpp
index f4e30c0c31b34..7b2d1c6e7e1e1 100644
--- a/clang/test/AST/ByteCode/cxx23.cpp
+++ b/clang/test/AST/ByteCode/cxx23.cpp
@@ -628,3 +628,17 @@ namespace VariadicOperator {
   constexpr S s;
   static_assert(s() == 42);
 }
+
+namespace DynamicCast {
+
+  struct A {virtual ~A();};
+  struct B : A {};
+  void f(A& a) { // all20-note 2{{declared here}}
+    constexpr B* b = dynamic_cast<B*>(&a); // all-error {{must be initialized 
by a constant expression}} \
+                                           // all23-note {{dynamic_cast 
applied to object 'a' whose dynamic type is not constant}} \
+                                           // all20-note {{function parameter 
'a' with unknown value cannot be used in a constant expression}}
+    constexpr void* b2 = dynamic_cast<void*>(&a); // all-error {{must be 
initialized by a constant expression}} \
+                                                  // all23-note {{dynamic_cast 
applied to object 'a' whose dynamic type is not constant}} \
+                                                  // all20-note {{function 
parameter 'a' with unknown value cannot be used in a constant expression}}
+  }
+}
diff --git a/clang/test/SemaCXX/constant-expression-p2280r4.cpp 
b/clang/test/SemaCXX/constant-expression-p2280r4.cpp
index 319c6c842e8f8..649ed41ca58c4 100644
--- a/clang/test/SemaCXX/constant-expression-p2280r4.cpp
+++ b/clang/test/SemaCXX/constant-expression-p2280r4.cpp
@@ -273,13 +273,11 @@ namespace dropped_note {
 namespace dynamic {
   struct A {virtual ~A();};
   struct B : A {};
-  void f(A& a) { // interpreter-note 2{{declared here}}
+  void f(A& a) {
     constexpr B* b = dynamic_cast<B*>(&a); // expected-error {{must be 
initialized by a constant expression}} \
-                                           // nointerpreter-note 
{{dynamic_cast applied to object 'a' whose dynamic type is not constant}} \
-                                           // interpreter-note {{pointer to 
'a' is not a constant expression}}
+                                           // expected-note {{dynamic_cast 
applied to object 'a' whose dynamic type is not constant}}
     constexpr void* b2 = dynamic_cast<void*>(&a); // expected-error {{must be 
initialized by a constant expression}} \
-                                                  // nointerpreter-note 
{{dynamic_cast applied to object 'a' whose dynamic type is not constant}} \
-                                                  // interpreter-note 
{{pointer to 'a' is not a constant expression}}
+                                                  // expected-note 
{{dynamic_cast applied to object 'a' whose dynamic type is not constant}}
   }
 }
 

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

Reply via email to