[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}}
+ };
+}