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

>From 8fd11880c12b38452adbca1d8f249d98d9cb8b46 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Thu, 11 Jun 2026 09:49:34 +0200
Subject: [PATCH] asdf

---
 clang/lib/AST/ByteCode/Compiler.cpp      |  21 +-
 clang/lib/AST/ByteCode/Interp.cpp        | 214 +++++++++++++++-
 clang/lib/AST/ByteCode/Interp.h          |   3 +-
 clang/lib/AST/ByteCode/InterpState.h     |   2 +
 clang/lib/AST/ByteCode/Opcodes.td        |   4 +-
 clang/lib/AST/ByteCode/Pointer.h         |   1 +
 clang/test/AST/ByteCode/dynamic-cast.cpp | 296 +++++++++++++++++++++++
 7 files changed, 522 insertions(+), 19 deletions(-)
 create mode 100644 clang/test/AST/ByteCode/dynamic-cast.cpp

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp 
b/clang/lib/AST/ByteCode/Compiler.cpp
index 8ea42fea03bee..638e6ecafb295 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -823,9 +823,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
     return discard(SubExpr);
 
   case CK_Dynamic:
-    // This initially goes through VisitCXXDynamicCastExpr, where we emit
-    // a diagnostic if appropriate.
-    return this->delegate(SubExpr);
+    llvm_unreachable("CXXDynamicCastExpr has its own function");
 
   case CK_LValueBitCast:
     if (!this->emitInvalidCast(CastKind::ReinterpretLike, /*Fatal=*/false, E))
@@ -3543,16 +3541,29 @@ bool Compiler<Emitter>::VisitCXXReinterpretCastExpr(
 
 template <class Emitter>
 bool Compiler<Emitter>::VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) {
-
   if (!Ctx.getLangOpts().CPlusPlus20) {
     if (!this->emitInvalidCast(CastKind::Dynamic, /*Fatal=*/false, E))
       return false;
+  }
+
+  if (E->getCastKind() != CK_Dynamic)
     return this->VisitCastExpr(E);
+
+  QualType DestType = E->getType();
+  // "target type must be a reference or pointer type to a defined class"
+  if (DestType->isRecordType()) {
+    assert(E->isGLValue());
+  } else {
+    assert(DestType->isPointerOrReferenceType());
+    assert(DestType->isVoidPointerType() ||
+           DestType->getPointeeType()->isRecordType());
+    DestType = DestType->getPointeeType();
   }
 
   if (!this->visit(E->getSubExpr()))
     return false;
-  if (!this->emitCheckDynamicCast(E))
+  if (!this->emitDynamicCast(DestType.getTypePtr(),
+                             /*IsReferenceCast=*/E->isGLValue(), E))
     return false;
 
   if (DiscardResult)
diff --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index 0a4a84edd62a4..6b831cc69d819 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1843,8 +1843,10 @@ bool Call(InterpState &S, CodePtr OpPC, const Function 
*Func,
     if (Func->isDestructor() && !CheckDestructor(S, OpPC, ThisPtr))
       return false;
 
-    if (Func->isConstructor() || Func->isDestructor())
+    if (Func->isConstructor() || Func->isDestructor()) {
+      S.InitializingPtrs.push_back(ThisPtr.view());
       S.InitializingBlocks.push_back(ThisPtr.block());
+    }
   }
 
   if (!Func->isFullyCompiled())
@@ -1873,8 +1875,10 @@ bool Call(InterpState &S, CodePtr OpPC, const Function 
*Func,
   // have a caller set.
   bool Success = Interpret(S);
   // Remove initializing  block again.
-  if (Func->isConstructor() || Func->isDestructor())
+  if (Func->isConstructor() || Func->isDestructor()) {
     S.InitializingBlocks.pop_back();
+    S.InitializingPtrs.pop_back();
+  }
 
   if (!Success) {
     InterpFrame::free(NewFrame);
@@ -1917,19 +1921,205 @@ 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>();
+struct DynamicCastResult {
+  UnsignedOrNone Offset = std::nullopt;
+  bool Ambiguous = false;
+
+  bool valid() const { return !Ambiguous && Offset; }
+
+  void setOffset(unsigned O) {
+    if (!Offset)
+      Offset = O;
+    else {
+      Ambiguous = true;
+    }
+  }
+
+  void merge(DynamicCastResult C) {
+    Ambiguous |= C.Ambiguous;
+    if (C.Offset) {
+      if (!Offset)
+        Offset = C.Offset;
+      else
+        Ambiguous = true;
+    }
+  }
+};
+
+// Walk UP the type hierarchy, starting at the decl of R to find Needle.
+static DynamicCastResult findRecordBase(const ASTContext &Ctx, const Record *R,
+                                        QualType Needle) {
+  DynamicCastResult Res;
+
+  if (Ctx.hasSimilarType(Needle, Ctx.getCanonicalTagType(R->getDecl())))
+    Res.setOffset(0);
+
+  for (const Record::Base &B : R->bases()) {
+    auto N = findRecordBase(Ctx, B.R, Needle);
+    if (N.Offset)
+      N.Offset = *N.Offset + B.Offset;
+    Res.merge(N);
+  }
+
+  return Res;
+}
+
+bool DynamicCast(InterpState &S, CodePtr OpPC, const Type *DestTypePtr,
+                 bool IsReferenceCast) {
+  const auto &Ptr = S.Stk.pop<Pointer>();
+  QualType TargetType = QualType(DestTypePtr, 0);
+
+  if (Ptr.isConstexprUnknown()) {
+    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;
+  }
 
-  if (!Ptr.isConstexprUnknown())
+  // TODO: Other checks?
+  if (!Ptr.isBlockPointer())
+    return false;
+
+  // Our given pointer, limited by the base that's currently being initialized,
+  // if any.
+  PtrView LimitedPtr;
+  if (S.InitializingPtrs.empty()) {
+    LimitedPtr = Ptr.stripBaseCasts().view();
+  } else {
+    // FIXME: Is this always the correct block?
+    LimitedPtr = S.InitializingPtrs.back();
+    assert(LimitedPtr.block() == Ptr.block());
+  }
+  assert(LimitedPtr.getRecord());
+
+  // C++ [expr.dynamic.cast]p7:
+  //   If T is "pointer to cv void", then the result is a pointer to the most
+  //   derived object
+  if (TargetType->isVoidType()) {
+    S.Stk.push<Pointer>(LimitedPtr);
     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;
+  assert(!TargetType.isNull());
+  assert(!TargetType->isVoidType());
+  assert(TargetType->isRecordType());
+
+  // Helper lambdas.
+  auto typesMatch = [&](QualType A, QualType B) -> bool {
+    return S.getASTContext().hasSimilarType(A, B);
+  };
+  auto getRecord = [](PtrView P) -> const CXXRecordDecl * {
+    assert(P.getRecord());
+    return cast<CXXRecordDecl>(P.getRecord()->getDecl());
+  };
+
+  auto baseIsPrivate = [&](PtrView P) -> bool {
+    if (P.isRoot() || !P.isBaseClass())
+      return false;
+
+    CXXBasePaths Paths;
+    getRecord(P.getBase())->isDerivedFrom(getRecord(P), Paths);
+    assert(std::distance(Paths.begin(), Paths.end()) == 1);
+
+    return Paths.front().Access == AS_private;
+  };
+
+  enum {
+    DiagPrivateBase = 0,
+    DiagNoBase = 1,
+    DiagAmbiguous = 2,
+    DiagPrivateSibling = 3
+  };
+
+  auto diag = [&](int DiagKind, QualType ResultType) -> bool {
+    // Pointer casts return nullptr on failure.
+    if (!IsReferenceCast) {
+      S.Stk.push<Pointer>(0, DestTypePtr);
+      return true;
+    }
+    QualType DynamicType = LimitedPtr.getType()->getCanonicalTypeUnqualified();
+    S.FFDiag(S.Current->getSource(OpPC),
+             diag::note_constexpr_dynamic_cast_to_reference_failed)
+        << DiagKind << ResultType << DynamicType << TargetType;
+    return false;
+  };
+
+  // Check if Ptr's dynamic type is derived from our target type at all.
+  // If it isn't, diagnose this as "operand does not have base class of type
+  // [...]".
+  {
+    CXXBasePaths Paths;
+    getRecord(LimitedPtr)
+        ->isDerivedFrom(TargetType->getAsCXXRecordDecl(), Paths);
+    if (std::distance(Paths.begin(), Paths.end()) == 0 &&
+        !typesMatch(LimitedPtr.getType(), TargetType)) {
+      return diag(DiagNoBase, TargetType);
+    }
+  }
+
+  // Current base is already private.
+  if (baseIsPrivate(Ptr.view()))
+    return diag(DiagPrivateBase, Ptr.getType());
+
+  std::optional<PtrView> Result;
+  // First, check simple downcasts without ambiguities.
+  for (PtrView Iter = Ptr.view();;) {
+    if (typesMatch(TargetType, Iter.getType())) {
+      Result = Iter;
+      break;
+    }
+    // Moving DOWN the type hierarchy.
+    Iter = Iter.getBase();
+    if (Iter.isRoot() || !Iter.isBaseClass())
+      break;
+  }
+
+  // Simply walking down the type hierarchy has produced a valid result, use
+  // that.
+  if (Result) {
+    if (baseIsPrivate(*Result))
+      return diag(DiagPrivateBase, Result->getType());
+    S.Stk.push<Pointer>(*Result);
+    return true;
+  }
+
+  // Otherwise, we need to do a deep hierarchy check.
+  bool Ambiguous = false;
+  for (PtrView Iter = LimitedPtr;;) {
+    // If we can move up the hierarchy from this level and reach the target 
type
+    // unambiguously, we're fine.
+    auto R = findRecordBase(S.getASTContext(), Iter.getRecord(), TargetType);
+
+    if (R.valid()) {
+      Result = Iter.atField(*R.Offset);
+      break;
+    } else if (R.Ambiguous) {
+      Ambiguous = true;
+      break;
+    }
+
+    // This moves us DOWN the type hierarchy.
+    Iter = Iter.getBase();
+    if (Iter.isRoot() || !Iter.isBaseClass())
+      break;
+  }
+
+  if (Ambiguous)
+    return diag(DiagAmbiguous, TargetType);
+
+  if (Result) {
+    // Might still be invalid due to resulting in a private base though.
+    if (baseIsPrivate(*Result))
+      return diag(DiagPrivateSibling, TargetType);
+    S.Stk.push<Pointer>(*Result);
+    return true;
+  }
+
+  // We couldn't find the requested base.
+  return diag(DiagNoBase, TargetType);
 }
 
 bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index b6377e22f0db6..a062d43e23906 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -143,7 +143,8 @@ 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);
+bool DynamicCast(InterpState &S, CodePtr OpPC, const Type *DestType,
+                 bool IsReferenceCast);
 
 enum class ShiftDir { Left, Right };
 
diff --git a/clang/lib/AST/ByteCode/InterpState.h 
b/clang/lib/AST/ByteCode/InterpState.h
index b6ef985095907..345a12b49c867 100644
--- a/clang/lib/AST/ByteCode/InterpState.h
+++ b/clang/lib/AST/ByteCode/InterpState.h
@@ -175,6 +175,8 @@ class InterpState final : public State, public SourceMapper 
{
   /// List of blocks we're currently running either constructors or destructors
   /// for.
   llvm::SmallVector<const Block *> InitializingBlocks;
+  // FIXME: We clearly dont' need two lists here, just one is enough.
+  llvm::SmallVector<PtrView> InitializingPtrs;
 };
 
 class InterpStateCCOverride final {
diff --git a/clang/lib/AST/ByteCode/Opcodes.td 
b/clang/lib/AST/ByteCode/Opcodes.td
index 09c616aa2ff1d..d944c964cc919 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -849,7 +849,9 @@ def SideEffect : Opcode {}
 def InvalidCast : Opcode {
   let Args = [ArgCastKind, ArgBool];
 }
-def CheckDynamicCast : Opcode {}
+def DynamicCast : Opcode {
+  let Args = [ArgTypePtr, ArgBool];
+}
 
 def InvalidStore : Opcode { let Args = [ArgTypePtr]; }
 def CheckPseudoDtor : Opcode {}
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 4c7951979630a..0fd8082c73d69 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -53,6 +53,7 @@ struct PtrView {
   bool inUnion() const { return getInlineDesc()->InUnion; };
   bool inArray() const { return getFieldDesc()->IsArray; }
   bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); }
+  const Block *block() const { return Pointee; }
 
   unsigned getEvalID() { return Pointee->getEvalID(); }
 
diff --git a/clang/test/AST/ByteCode/dynamic-cast.cpp 
b/clang/test/AST/ByteCode/dynamic-cast.cpp
new file mode 100644
index 0000000000000..b782920eb8763
--- /dev/null
+++ b/clang/test/AST/ByteCode/dynamic-cast.cpp
@@ -0,0 +1,296 @@
+// RUN: %clang_cc1                                         -verify=ref,both    
  -std=c++26 %s
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter 
-verify=expected,both -std=c++26 %s
+
+namespace Simple {
+
+  struct S {};
+  constexpr S ss;
+  constexpr int foo = (dynamic_cast<const S &>(ss), 0);
+
+  struct S1 { virtual void a(); };
+  struct S2 : S1 {};
+  constexpr S2 s{};
+  static_assert(dynamic_cast<const S2*>(static_cast<const S1*>(&s)) == &s);
+}
+
+namespace Failing {
+}
+
+namespace NotSoSimple {
+  struct A2 { virtual void a2(); };
+  struct D {
+    virtual void d();
+  };
+  struct F : A2, D {
+    void *f = dynamic_cast<void*>( static_cast<D*>(this) );
+  };
+  constexpr F g;
+  static_assert(g.f == (void*)(F*)&g);
+
+  constexpr D* d = (D*)&g;
+  constexpr void* f = dynamic_cast<void*>(d);
+  static_assert(f == &g);
+}
+
+
+namespace Again {
+  struct A3 {};
+  struct A4 {};
+
+  struct A2 : A3, A4 { virtual void a2(); };
+  struct A : A2 { virtual void a(); };
+  struct C2 { virtual void c2(); };
+  struct C : A, C2 { A4 *c = dynamic_cast<A4*>(static_cast<C2*>(this)); };
+
+  struct D { virtual void d(); };
+
+  struct F : C, D{};
+  struct G : F {};
+  constexpr G g;
+  static_assert(g.c == (C*)&g);
+}
+
+namespace FailedReference {
+  struct A {};
+  struct K : A {};
+  struct P : A {};
+
+  struct L{virtual void p();};
+
+  struct S : P, K, L {
+    virtual void p();
+  };
+  constexpr S s{};
+  static_assert(&dynamic_cast<const A&>((L&)s) == nullptr); // both-error 
{{not an integral constant expression}} \
+                                                            // both-note 
{{reference dynamic_cast failed: 'A' is an ambiguous base class of dynamic type 
'FailedReference::S' of operand}}
+}
+
+namespace FailedReference2 {
+  struct A2 { virtual void a2(); };
+  struct A : A2 { virtual void a(); };
+  struct B : A {};
+  struct C2 { virtual void c2(); };
+  struct C : A, C2 { A *c = dynamic_cast<A*>(static_cast<C2*>(this)); };
+  struct D { virtual void d(); };
+  struct E { virtual void e(); };
+  struct F : B, C, D, private E { void *f = 
dynamic_cast<void*>(static_cast<D*>(this)); };
+  struct G : F {};
+
+  constexpr G g;
+  static_assert(&dynamic_cast<A&>((D&)g) == nullptr); // both-error {{not an 
integral constant expression}} \
+                                                      // both-note {{reference 
dynamic_cast failed: 'A' is an ambiguous base class of dynamic type 
'FailedReference2::G' of operand}}
+}
+
+namespace FailedPtr {
+  struct A  {};
+
+  struct B : A {};
+
+  struct C2 { virtual void c2(); };
+
+  struct C : A, C2 {};
+  struct F : B, C {};
+  constexpr F g;
+  static_assert(dynamic_cast<const A*>(static_cast<const C2*>(&g)) == nullptr);
+  static_assert(dynamic_cast<const B*>(static_cast<const C2*>(&g)) != nullptr);
+}
+
+namespace Initializing {
+  struct A2 { virtual void a2(); };
+  struct A : A2 { virtual void a(); };
+  struct B : A {};
+  struct C2 { virtual void c2(); };
+  struct C : A, C2 { A *c = dynamic_cast<A*>(static_cast<C2*>(this)); };
+
+  struct D { virtual void d(); };
+  struct E { virtual void e(); };
+  struct F : B, C, D {};
+  struct Padding { virtual void padding(); };
+  struct G : Padding, F {};
+
+  constexpr G g;
+
+  // During construction of C, A is unambiguous subobject of dynamic type C.
+  static_assert(g.c == (C*)&g);
+}
+
+namespace SimpleDowncast {
+  struct A2 { virtual void a2(); };
+  struct A : A2 { virtual void a(); };
+  struct B : A {};
+  struct C2 { virtual void c2(); };
+  struct C : A, C2 {};
+  struct D { virtual void d(); };
+  struct E { virtual void e(); };
+  struct F : B, C, D {};
+  struct Padding { virtual void padding(); };
+  struct G : Padding, F {};
+
+  constexpr G g;
+  // Can navigate from A2 to its A...
+  static_assert(&dynamic_cast<A&>((A2&)(B&)g) == &(A&)(B&)g);
+}
+
+namespace ActuallyADerived2BaseCast {
+  struct A2 { virtual void a2(); };
+  struct A : A2 { virtual void a(); };
+  struct B : A {};
+  struct C2 { virtual void c2(); };
+  struct C : A, C2 {};
+  struct D { virtual void d(); };
+  struct E { virtual void e(); };
+  struct F : B, C, D {};
+  struct Padding { virtual void padding(); };
+  struct G : Padding, F {};
+  constexpr G g;
+  // ... and from B to its A ...
+  static_assert(&dynamic_cast<A2&>((B&)g) == &(A2&)(B&)g);
+}
+
+namespace ProperLimitedPtrInVoidCast {
+  struct A2 { virtual void a2(); };
+  struct A : A2 { virtual void a(); };
+  struct B : A {};
+  struct C2 { virtual void c2(); };
+  struct C : A, C2 {};
+  struct D { virtual void d(); };
+  struct E { virtual void e(); };
+  struct F : B, C, D, private E { void *f = 
dynamic_cast<void*>(static_cast<D*>(this)); };
+  struct Padding { virtual void padding(); };
+  struct G : Padding, F {};
+
+  constexpr G g;
+  static_assert(g.f == (void*)(F*)&g);
+}
+
+namespace Unrelated {
+  struct A2 { virtual void a2(); };
+  struct A : A2 { virtual void a(); };
+  struct B : A {};
+  struct C2 { virtual void c2(); };
+  struct C : A, C2 {};
+  struct D { virtual void d(); };
+  struct E { virtual void e(); };
+  struct F : B, C, D, private E {};
+  struct Padding { virtual void padding(); };
+  struct G : Padding, F {};
+
+  constexpr G g;
+  struct Unrelated { virtual void unrelated(); };
+  constexpr int b_unrelated = (dynamic_cast<Unrelated&>((B&)g), 0); // 
both-error {{must be initialized by a constant expression}} \
+                                                                    // 
both-note {{reference dynamic_cast failed: dynamic type 'Unrelated::G' of 
operand does not have a base class of type 'Unrelated'}}
+  constexpr int e_unrelated = (dynamic_cast<Unrelated&>((E&)g), 0); // 
both-error {{must be initialized by a constant expression}} \
+                                                                    // 
both-note {{reference dynamic_cast failed: dynamic type 'Unrelated::G' of 
operand does not have a base class of type 'Unrelated'}}
+  static_assert(dynamic_cast<Unrelated*>((B*)&g) == nullptr);
+  static_assert(dynamic_cast<Unrelated*>((E*)&g) == nullptr);
+}
+
+namespace PrivateSibling {
+  struct A2 { virtual void a2(); };
+  struct A : A2 { virtual void a(); };
+  struct B : A {};
+  struct C2 { virtual void c2(); };
+  struct C : A, C2 {};
+  struct D { virtual void d(); };
+  struct E { virtual void e(); };
+  struct F : B, C, D, private E {};
+  struct Padding { virtual void padding(); };
+  struct G : Padding, F {};
+
+  constexpr G g;
+  // Cannot cast from B to private sibling E.
+  constexpr int b_e = (dynamic_cast<E&>((B&)g), 0); // both-error {{must be 
initialized by a constant expression}} \
+                                                    // both-note {{reference 
dynamic_cast failed: 'E' is a non-public base class of dynamic type 
'PrivateSibling::G' of operand}}
+  static_assert(dynamic_cast<E*>((B*)&g) == nullptr);
+}
+
+namespace Field {
+  struct X {
+    mutable int n = 0;
+    virtual constexpr ~X() {}
+  };
+  struct Y : X {
+  };
+  struct Z {
+    mutable Y y;
+  };
+  constexpr Z z;
+  constexpr const X *pz = &z.y;
+  constexpr const Y *qz = dynamic_cast<const Y*>(pz);
+  static_assert(qz != nullptr);
+}
+
+/// The entire DynamicCast test from constant-expression-cxx2a.cpp but the g 
variable is a field.
+namespace Field2 {
+  struct A2 { virtual void a2(); };
+  struct A : A2 { virtual void a(); };
+  struct B : A {};
+  struct C2 { virtual void c2(); };
+  struct C : A, C2 { A *c = dynamic_cast<A*>(static_cast<C2*>(this)); };
+  struct D { virtual void d(); };
+  struct E { virtual void e(); };
+  struct F : B, C, D, private E { void *f = 
dynamic_cast<void*>(static_cast<D*>(this)); };
+  struct Padding { virtual void padding(); };
+  struct G : Padding, F {};
+
+
+  struct SomeStruct {
+    int a;
+    int b;
+    G g;
+  };
+
+  constexpr SomeStruct ss{};
+
+  // During construction of C, A is unambiguous subobject of dynamic type C.
+  static_assert(ss.g.c == (C*)&ss.g);
+  // ... but in the complete object, the same is not true, so the runtime 
fails.
+  static_assert(dynamic_cast<const A*>(static_cast<const C2*>(&ss.g)) == 
nullptr);
+
+  // dynamic_cast<void*> produces a pointer to the object of the dynamic type.
+  static_assert(ss.g.f == (void*)(F*)&ss.g);
+  static_assert(dynamic_cast<const void*>(static_cast<const D*>(&ss.g)) == 
&ss.g);
+
+  // both-note@+1 {{reference dynamic_cast failed: 'A' is an ambiguous base 
class of dynamic type 'Field2::G' of operand}}
+  constexpr int d_a = (dynamic_cast<const A&>(static_cast<const D&>(ss.g)), 
0); // both-error {{}}
+
+  // Can navigate from A2 to its A...
+  static_assert(&dynamic_cast<A&>((A2&)(B&)ss.g) == &(A&)(B&)ss.g);
+  // ... and from B to its A ...
+  static_assert(&dynamic_cast<A&>((B&)ss.g) == &(A&)(B&)ss.g);
+  // ... but not from D.
+  // both-note@+1 {{reference dynamic_cast failed: 'A' is an ambiguous base 
class of dynamic type 'Field2::G' of operand}}
+  static_assert(&dynamic_cast<A&>((D&)ss.g) == &(A&)(B&)ss.g); // both-error 
{{}}
+
+  // Can cast from A2 to sibling class D.
+  static_assert(&dynamic_cast<D&>((A2&)(B&)ss.g) == &(D&)ss.g);
+
+  // Cannot cast from private base E to derived class F.
+  // both-note@+1 {{reference dynamic_cast failed: static type 'Field2::E' of 
operand is a non-public base class of dynamic type 'Field2::G'}}
+  constexpr int e_f = (dynamic_cast<F&>((E&)ss.g), 0); // both-error {{}}
+
+  // Cannot cast from B to private sibling E.
+  // both-note@+1 {{reference dynamic_cast failed: 'E' is a non-public base 
class of dynamic type 'Field2::G' of operand}}
+  constexpr int b_e = (dynamic_cast<E&>((B&)ss.g), 0); // both-error {{}}
+
+  struct Unrelated { virtual void unrelated(); };
+  // both-note@+1 {{reference dynamic_cast failed: dynamic type 'Field2::G' of 
operand does not have a base class of type 'Unrelated'}}
+  constexpr int b_unrelated = (dynamic_cast<Unrelated&>((B&)ss.g), 0); // 
both-error {{}}
+  // both-note@+1 {{reference dynamic_cast failed: dynamic type 'Field2::G' of 
operand does not have a base class of type 'Unrelated'}}
+  constexpr int e_unrelated = (dynamic_cast<Unrelated&>((E&)ss.g), 0); // 
both-error {{}}
+}
+
+namespace UnrelatedAndRootPtr{
+  struct A {
+    virtual void d() {}
+  };
+  struct B final : A { };
+  struct C { };
+
+  constexpr bool f() {
+    B b;
+    C *bb = dynamic_cast<C*>(&b);
+    return !bb;
+  }
+  static_assert(f());
+}

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

Reply via email to