diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -98,6 +98,7 @@ bool VisitLambdaExpr(const LambdaExpr *E); bool VisitPredefinedExpr(const PredefinedExpr *E); bool VisitCXXThrowExpr(const CXXThrowExpr *E); + bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E); protected: bool visitExpr(const Expr *E) override; diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -997,6 +997,15 @@ return this->emitInvalid(E); } +template +bool ByteCodeExprGen::VisitCXXReinterpretCastExpr( + const CXXReinterpretCastExpr *E) { + if (!this->discard(E->getSubExpr())) + return false; + + return this->emitInvalidCast(CastKind::Reinterpret, E); +} + template bool ByteCodeExprGen::discard(const Expr *E) { if (E->containsErrors()) return false; diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -73,3 +73,12 @@ Anon->dump(); } } + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, interp::CastKind CK) { + switch (CK) { + case interp::CastKind::Reinterpret: + OS << "reinterpret_cast"; + break; + } + return OS; +} diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1754,6 +1754,14 @@ return false; } +/// Same here, but only for casts. +inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) { + const SourceLocation &Loc = S.Current->getLocation(OpPC); + S.FFDiag(Loc, diag::note_constexpr_invalid_cast) + << static_cast(Kind) << S.Current->getRange(OpPC); + return false; +} + //===----------------------------------------------------------------------===// // Read opcode arguments //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -51,6 +51,7 @@ def ArgFltSemantics : ArgType { let Name = "const llvm::fltSemantics *"; } def ArgRoundingMode : ArgType { let Name = "llvm::RoundingMode"; } def ArgLETD: ArgType { let Name = "const LifetimeExtendedTemporaryDecl *"; } +def ArgCastKind : ArgType { let Name = "CastKind"; } //===----------------------------------------------------------------------===// // Classes of types instructions operate on. @@ -604,3 +605,6 @@ // [] -> [] def Invalid : Opcode {} +def InvalidCast : Opcode { + let Args = [ArgCastKind]; +} diff --git a/clang/lib/AST/Interp/PrimType.h b/clang/lib/AST/Interp/PrimType.h --- a/clang/lib/AST/Interp/PrimType.h +++ b/clang/lib/AST/Interp/PrimType.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_AST_INTERP_TYPE_H #define LLVM_CLANG_AST_INTERP_TYPE_H +#include "llvm/Support/raw_ostream.h" #include #include #include @@ -42,6 +43,11 @@ PT_FnPtr, }; +enum class CastKind : uint8_t { + Reinterpret, +}; +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, interp::CastKind CK); + constexpr bool isIntegralType(PrimType T) { return T <= PT_Uint64; } /// Mapping from primitive types to their representation. diff --git a/clang/test/AST/Interp/unsupported.cpp b/clang/test/AST/Interp/unsupported.cpp --- a/clang/test/AST/Interp/unsupported.cpp +++ b/clang/test/AST/Interp/unsupported.cpp @@ -47,3 +47,11 @@ return 0; } } + +namespace Casts { + constexpr int a = reinterpret_cast(12); // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{reinterpret_cast is not allowed}} \ + // ref-error {{must be initialized by a constant expression}} \ + // ref-note {{reinterpret_cast is not allowed}} + +}