[clang][bytecode] Diagnose dynamic_cast before C++20 (#137442)

Emit a CCE diagnostic.
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index fd306c0..58fe2c1 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -3012,6 +3012,17 @@
 }
 
 template <class Emitter>
+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);
+}
+
+template <class Emitter>
 bool Compiler<Emitter>::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
   assert(E->getType()->isBooleanType());
 
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index a3090a8..0febbac 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -180,6 +180,7 @@
   bool VisitPredefinedExpr(const PredefinedExpr *E);
   bool VisitCXXThrowExpr(const CXXThrowExpr *E);
   bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E);
+  bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E);
   bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
   bool VisitCXXConstructExpr(const CXXConstructExpr *E);
   bool VisitSourceLocExpr(const SourceLocExpr *E);
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 91864ba..e2f2e73 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2935,6 +2935,11 @@
       S.FFDiag(E);
 
     return false;
+  } else if (Kind == CastKind::Dynamic) {
+    assert(!S.getLangOpts().CPlusPlus20);
+    S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
+        << diag::ConstexprInvalidCastKind::Dynamic;
+    return true;
   }
 
   return false;
diff --git a/clang/lib/AST/ByteCode/PrimType.h b/clang/lib/AST/ByteCode/PrimType.h
index c6145d4..6152fbf 100644
--- a/clang/lib/AST/ByteCode/PrimType.h
+++ b/clang/lib/AST/ByteCode/PrimType.h
@@ -56,6 +56,7 @@
 enum class CastKind : uint8_t {
   Reinterpret,
   Volatile,
+  Dynamic,
 };
 
 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
@@ -67,6 +68,9 @@
   case interp::CastKind::Volatile:
     OS << "volatile";
     break;
+  case interp::CastKind::Dynamic:
+    OS << "dynamic";
+    break;
   }
   return OS;
 }
diff --git a/clang/test/AST/ByteCode/cxx11-pedantic.cpp b/clang/test/AST/ByteCode/cxx11-pedantic.cpp
index 8779a28..a73f20e 100644
--- a/clang/test/AST/ByteCode/cxx11-pedantic.cpp
+++ b/clang/test/AST/ByteCode/cxx11-pedantic.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected -std=c++11 -triple x86_64-linux -pedantic %s
-// RUN: %clang_cc1 -verify=both,ref -std=c++11 -triple x86_64-linux -pedantic %s
+// RUN: %clang_cc1 -verify=both,expected -std=c++11 -triple x86_64-linux -pedantic %s -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -verify=both,ref      -std=c++11 -triple x86_64-linux -pedantic %s
 
 struct T { int n; };
 const T t = { 42 }; // both-note 2{{declared here}}
@@ -11,3 +11,12 @@
 
 static_assert(t.n == 42, ""); // both-error {{expression is not an integral constant expression}} \
                               // both-note {{read of non-constexpr variable 't' is not allowed}}
+
+namespace DynamicCast {
+  struct S { int n; };
+  constexpr S s { 16 };
+  struct T {
+    int n : dynamic_cast<const S*>(&s)->n; // both-warning {{constant expression}} \
+                                           // both-note {{dynamic_cast}}
+  };
+}