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
