diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 29069ba10bb86..9f17ba1d7aa05 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -127,6 +127,15 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { 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: diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 4917f43f9512e..4d49c75799637 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -462,6 +462,17 @@ bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This) { return CheckArrayInitialized(S, OpPC, This, CAT); } +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 CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status) { // In a constant context, assume that any dynamic rounding mode or FP // exception state matches the default floating-point environment. diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 33ab0cdedeae4..ee3b953bb69cc 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -104,6 +104,10 @@ bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD); /// 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, @@ -1493,6 +1497,17 @@ bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) { } } +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 //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index 6d12823990cf2..0f494c530b256 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -565,6 +565,12 @@ def CastFloatingIntegral : Opcode { let HasGroup = 1; } +def CastPointerIntegral : Opcode { + let Types = [AluTypeClass]; + let Args = []; + let HasGroup = 1; +} + //===----------------------------------------------------------------------===// // Comparison opcodes. //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index f795466f1db4c..a5e7ad8af8189 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -77,6 +77,13 @@ class Pointer { /// Converts the pointer to an APValue. APValue toAPValue() const; + /// Converts the pointer to a string usable in diagnostics. + std::string toDiagnosticString(const ASTContext &Ctx) const; + + unsigned getIntegerRepresentation() const { + return reinterpret_cast(Pointee) + Offset; + } + /// Offsets a pointer inside an array. Pointer atIndex(unsigned Idx) const { if (Base == RootPtrMark) diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index 5a645621e2d75..c6f293886f90d 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/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}} @@ -932,3 +934,15 @@ namespace NE { static_assert(a() == 0, ""); #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}} +}