Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -192,6 +192,15 @@ return true; return this->emitNull(classifyPrim(CE->getType()), CE); + case CK_PointerToIntegral: { + // TODO: Discard handling. + if (!this->visit(SubExpr)) + return false; + + PrimType T = classifyPrim(CE->getType()); + return this->emitCastPointerIntegral(T, CE); + } + case CK_ArrayToPointerDecay: case CK_AtomicToNonAtomic: case CK_ConstructorConversion: Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -108,6 +108,10 @@ /// Checks that all fields are initialized after a constructor call. bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This); +/// Checks if reinterpret casts are legal in the current context. +bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC, + const Pointer &Ptr); + /// Checks if the shift operation is legal. template bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, @@ -1571,6 +1575,17 @@ } } +template ::T> +bool CastPointerIntegral(InterpState &S, CodePtr OpPC) { + const Pointer &Ptr = S.Stk.pop(); + + if (!CheckPotentialReinterpretCast(S, OpPC, Ptr)) + return false; + + S.Stk.push(T::from(Ptr.getIntegerRepresentation())); + return true; +} + //===----------------------------------------------------------------------===// // Zero, Nullptr //===----------------------------------------------------------------------===// Index: clang/lib/AST/Interp/Interp.cpp =================================================================== --- clang/lib/AST/Interp/Interp.cpp +++ clang/lib/AST/Interp/Interp.cpp @@ -519,6 +519,17 @@ return true; } +bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC, + const Pointer &Ptr) { + if (!S.inConstantContext()) + return true; + + const SourceInfo &E = S.Current->getSource(OpPC); + S.CCEDiag(E, diag::note_constexpr_invalid_cast) + << 2 << S.getLangOpts().CPlusPlus; + return false; +} + bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM) { Floating F = S.Stk.pop(); Index: clang/lib/AST/Interp/Opcodes.td =================================================================== --- clang/lib/AST/Interp/Opcodes.td +++ clang/lib/AST/Interp/Opcodes.td @@ -590,6 +590,12 @@ let HasGroup = 1; } +def CastPointerIntegral : Opcode { + let Types = [AluTypeClass]; + let Args = []; + let HasGroup = 1; +} + //===----------------------------------------------------------------------===// // Comparison opcodes. //===----------------------------------------------------------------------===// Index: clang/lib/AST/Interp/Pointer.h =================================================================== --- clang/lib/AST/Interp/Pointer.h +++ clang/lib/AST/Interp/Pointer.h @@ -82,6 +82,10 @@ /// Converts the pointer to a string usable in diagnostics. std::string toDiagnosticString(const ASTContext &Ctx) const; + unsigned getIntegerRepresentation() const { + return reinterpret_cast(Pointee) + Offset; + } + /// Converts the pointer to an APValue that is an rvalue. APValue toRValue(const Context &Ctx) const; Index: clang/test/AST/Interp/literals.cpp =================================================================== --- clang/test/AST/Interp/literals.cpp +++ clang/test/AST/Interp/literals.cpp @@ -6,6 +6,8 @@ #define INT_MIN (~__INT_MAX__) #define INT_MAX __INT_MAX__ +typedef __INTPTR_TYPE__ intptr_t; + static_assert(true, ""); static_assert(false, ""); // expected-error{{failed}} ref-error{{failed}} @@ -1008,3 +1010,15 @@ static_assert(heh(2) == 'h', ""); #endif } + +namespace PointerCasts { + constexpr int M = 10; + constexpr const int *P = &M; + constexpr intptr_t A = (intptr_t)P; // ref-error {{must be initialized by a constant expression}} \ + // ref-note {{cast that performs the conversions of a reinterpret_cast}} \ + // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{cast that performs the conversions of a reinterpret_cast}} + + int array[(long)(char*)0]; // ref-warning {{variable length array folded to constant array}} \ + // expected-warning {{variable length array folded to constant array}} +}