Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -164,6 +164,17 @@ return this->emitCastFloatingIntegral(*ToT, RM, CE); } + case CK_NullToPointer: + case CK_IntegralToPointer: { + if (isa(SubExpr)) + return this->visit(SubExpr); + + if (!this->visit(SubExpr)) + return false; + + return this->emitCastIntegralPointer(classifyPrim(SubExpr->getType()), CE); + } + case CK_ArrayToPointerDecay: case CK_AtomicToNonAtomic: case CK_ConstructorConversion: @@ -171,10 +182,14 @@ case CK_NonAtomicToAtomic: case CK_NoOp: case CK_UserDefinedConversion: - case CK_NullToPointer: return this->visit(SubExpr); case CK_IntegralToBoolean: + // == in C + if (const auto *BOP = dyn_cast(SubExpr); + BOP && BOP->isEqualityOp()) + return this->visit(SubExpr); + [[fallthrough]]; case CK_IntegralCast: { Optional FromT = classify(SubExpr->getType()); Optional ToT = classify(CE->getType()); Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -1249,6 +1249,13 @@ return CheckFloatResult(S, OpPC, Status); } +template ::T> +bool CastIntegralPointer(InterpState &S, CodePtr OpPC) { + const T &Src = S.Stk.pop(); + S.Stk.push(Pointer(static_cast(Src))); + return true; +} + //===----------------------------------------------------------------------===// // Zero, Nullptr //===----------------------------------------------------------------------===// Index: clang/lib/AST/Interp/Opcodes.td =================================================================== --- clang/lib/AST/Interp/Opcodes.td +++ clang/lib/AST/Interp/Opcodes.td @@ -522,6 +522,11 @@ let HasGroup = 1; } +def CastIntegralPointer : Opcode { + let Types = [AluTypeClass]; + let HasGroup = 1; +} + //===----------------------------------------------------------------------===// // Comparison opcodes. //===----------------------------------------------------------------------===// Index: clang/lib/AST/Interp/Pointer.h =================================================================== --- clang/lib/AST/Interp/Pointer.h +++ clang/lib/AST/Interp/Pointer.h @@ -67,6 +67,7 @@ Pointer() {} Pointer(Block *B); Pointer(Block *B, unsigned BaseAndOffset); + Pointer(unsigned Offset); Pointer(const Pointer &P); Pointer(Pointer &&P); ~Pointer(); @@ -79,6 +80,9 @@ /// Offsets a pointer inside an array. Pointer atIndex(unsigned Idx) const { + if (!Pointee) + return Pointer(nullptr, 0, + Offset + Idx); // Offset + Idx, 0);//Base + Idx); if (Base == RootPtrMark) return Pointer(Pointee, RootPtrMark, getDeclDesc()->getSize()); unsigned Off = Idx * elemSize(); @@ -160,14 +164,17 @@ } /// Checks if the pointer is null. - bool isZero() const { return Pointee == nullptr; } + bool isZero() const { return Pointee == nullptr && Offset == 0; } /// Checks if the pointer is live. bool isLive() const { return Pointee && !Pointee->IsDead; } /// Checks if the item is a field in an object. bool isField() const { return Base != 0 && Base != RootPtrMark; } /// Accessor for information about the declaration site. - Descriptor *getDeclDesc() const { return Pointee->Desc; } + Descriptor *getDeclDesc() const { + assert(Pointee); + return Pointee->Desc; + } SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); } /// Returns a pointer to the object of which this pointer is a field. @@ -232,12 +239,12 @@ } /// Checks if the innermost field is an array. - bool inArray() const { return getFieldDesc()->IsArray; } + bool inArray() const { return Pointee ? getFieldDesc()->IsArray : false; } /// Checks if the structure is a primitive array. bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); } /// Checks if the structure is an array of unknown size. bool isUnknownSizeArray() const { - return getFieldDesc()->isUnknownSizeArray(); + return Pointee ? getFieldDesc()->isUnknownSizeArray() : false; } /// Checks if the pointer points to an array. bool isArrayElement() const { return Base != Offset; } @@ -288,12 +295,20 @@ } /// Returns the number of elements. - unsigned getNumElems() const { return getSize() / elemSize(); } + unsigned getNumElems() const { + if (Pointee) + return getSize() / elemSize(); + + return std::numeric_limits::max(); + } Block *block() const { return Pointee; } /// Returns the index into an array. int64_t getIndex() const { + if (!Pointee) + return 0; + if (isElementPastEnd()) return 1; if (auto ElemSize = elemSize()) @@ -307,7 +322,7 @@ } /// Checks if the pointer is an out-of-bounds element pointer. - bool isElementPastEnd() const { return Offset == PastEndMark; } + bool isElementPastEnd() const { return Pointee && Offset == PastEndMark; } /// Dereferences the pointer, if it's live. template T &deref() const { Index: clang/lib/AST/Interp/Pointer.cpp =================================================================== --- clang/lib/AST/Interp/Pointer.cpp +++ clang/lib/AST/Interp/Pointer.cpp @@ -19,6 +19,8 @@ Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset) : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {} +Pointer::Pointer(unsigned Offset) : Pointer(nullptr, Offset, Offset) {} + Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {} Pointer::Pointer(Pointer &&P) Index: clang/test/Sema/const-eval-64.c =================================================================== --- clang/test/Sema/const-eval-64.c +++ clang/test/Sema/const-eval-64.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux -fexperimental-constant-interpreter %s #define EVAL_EXPR(testno, expr) int test##testno = sizeof(struct{char qq[expr];});