Author: Timm Baeder Date: 2024-08-06T13:37:11+02:00 New Revision: 59e13666dd2e81e58253488a29635fb2992ed741
URL: https://github.com/llvm/llvm-project/commit/59e13666dd2e81e58253488a29635fb2992ed741 DIFF: https://github.com/llvm/llvm-project/commit/59e13666dd2e81e58253488a29635fb2992ed741.diff LOG: [clang][Interp] Fix getField() for integral pointers (#102120) Instead of just adding the Record::Field offset, instead get the FieldDecl offset in the RecordLayout. Unfortunately, the offset we pass to the ops here is not made to easily go back to a FieldDecl, so we have to iterate over the parent Record. Added: Modified: clang/lib/AST/Interp/Compiler.cpp clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Pointer.cpp clang/lib/AST/Interp/Pointer.h clang/test/AST/Interp/c.c Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index e5280491dfd73..02cbe38f5fb1f 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -335,6 +335,10 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { if (!PointeeType.isNull()) { if (std::optional<PrimType> T = classify(PointeeType)) Desc = P.createDescriptor(SubExpr, *T); + else + Desc = P.createDescriptor(SubExpr, PointeeType.getTypePtr(), + std::nullopt, true, false, + /*IsMutable=*/false, nullptr); } return this->emitNull(classifyPrim(CE->getType()), Desc, CE); } diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 04f88efdc0acf..2eed0d3d1f16b 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1504,6 +1504,12 @@ inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) { if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize()) return false; + + if (Ptr.isIntegralPointer()) { + S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getCtx(), Off)); + return true; + } + S.Stk.push<Pointer>(Ptr.atField(Off)); return true; } @@ -1527,6 +1533,11 @@ inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) { if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize()) return false; + if (Ptr.isIntegralPointer()) { + S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getCtx(), Off)); + return true; + } + S.Stk.push<Pointer>(Ptr.atField(Off)); return true; } diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index 2b1f8b460510c..ba9683a059e18 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -597,3 +597,30 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, return std::nullopt; return Result; } + +IntPointer IntPointer::atOffset(const ASTContext &ASTCtx, + unsigned Offset) const { + if (!this->Desc) + return *this; + const Record *R = this->Desc->ElemRecord; + if (!R) + return *this; + + const Record::Field *F = nullptr; + for (auto &It : R->fields()) { + if (It.Offset == Offset) { + F = &It; + break; + } + } + if (!F) + return *this; + + const FieldDecl *FD = F->Decl; + const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent()); + unsigned FieldIndex = FD->getFieldIndex(); + uint64_t FieldOffset = + ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex)) + .getQuantity(); + return IntPointer{this->Desc, FieldOffset}; +} diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index 6f6983458ab60..b7b4f82f16f66 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -44,6 +44,8 @@ struct BlockPointer { struct IntPointer { const Descriptor *Desc; uint64_t Value; + + IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const; }; enum class Storage { Block, Int, Fn }; @@ -88,6 +90,9 @@ class Pointer { PointeeStorage.Int.Value = 0; PointeeStorage.Int.Desc = nullptr; } + Pointer(IntPointer &&IntPtr) : StorageKind(Storage::Int) { + PointeeStorage.Int = std::move(IntPtr); + } Pointer(Block *B); Pointer(Block *B, uint64_t BaseAndOffset); Pointer(const Pointer &P); @@ -161,9 +166,8 @@ class Pointer { /// Creates a pointer to a field. [[nodiscard]] Pointer atField(unsigned Off) const { + assert(isBlockPointer()); unsigned Field = Offset + Off; - if (isIntegralPointer()) - return Pointer(asIntPointer().Value + Field, asIntPointer().Desc); return Pointer(asBlockPointer().Pointee, Field, Field); } diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c index 9ec305d59c68c..13a5e082a125f 100644 --- a/clang/test/AST/Interp/c.c +++ b/clang/test/AST/Interp/c.c @@ -101,8 +101,6 @@ int somefunc(int i) { // all-warning {{overflow in expression; result is 131'073 with type 'int'}} } -/// FIXME: The following test is incorrect in the new interpreter. -/// The null pointer returns 16 from its getIntegerRepresentation(). #pragma clang diagnostic ignored "-Wpointer-to-int-cast" struct ArrayStruct { char n[1]; @@ -111,10 +109,7 @@ char name2[(int)&((struct ArrayStruct*)0)->n]; // expected-warning {{folded to c // pedantic-expected-warning {{folded to constant array}} \ // ref-warning {{folded to constant array}} \ // pedantic-ref-warning {{folded to constant array}} -_Static_assert(sizeof(name2) == 0, ""); // expected-error {{failed}} \ - // expected-note {{evaluates to}} \ - // pedantic-expected-error {{failed}} \ - // pedantic-expected-note {{evaluates to}} +_Static_assert(sizeof(name2) == 0, ""); #ifdef __SIZEOF_INT128__ void *PR28739d = &(&PR28739d)[(__int128)(unsigned long)-1]; // all-warning {{refers past the last possible element}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits