llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) <details> <summary>Changes</summary> This adds a `MemberPointer` class along with a `PT_MemberPtr` primitive type. A `MemberPointer` has a `Pointer` Base as well as a `Decl*` (could be `ValueDecl*`?) decl it points to. For the actual logic, this mainly changes the way we handle `PtrMemOp`s in `VisitBinaryOperator`. --- Patch is 39.59 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/91303.diff 26 Files Affected: - (modified) clang/lib/AST/CMakeLists.txt (+1) - (modified) clang/lib/AST/Interp/ByteCodeExprGen.cpp (+93-10) - (modified) clang/lib/AST/Interp/Context.cpp (+9-6) - (modified) clang/lib/AST/Interp/Context.h (+2) - (modified) clang/lib/AST/Interp/Descriptor.cpp (+1) - (modified) clang/lib/AST/Interp/Disasm.cpp (+3) - (modified) clang/lib/AST/Interp/Interp.cpp (+26-4) - (modified) clang/lib/AST/Interp/Interp.h (+99) - (modified) clang/lib/AST/Interp/InterpFrame.cpp (+1) - (modified) clang/lib/AST/Interp/InterpStack.cpp (+1) - (modified) clang/lib/AST/Interp/InterpStack.h (+3) - (added) clang/lib/AST/Interp/MemberPointer.cpp (+80) - (added) clang/lib/AST/Interp/MemberPointer.h (+112) - (modified) clang/lib/AST/Interp/Opcodes.td (+16-2) - (modified) clang/lib/AST/Interp/Pointer.cpp (+1) - (modified) clang/lib/AST/Interp/Pointer.h (+1) - (modified) clang/lib/AST/Interp/PrimType.cpp (+1) - (modified) clang/lib/AST/Interp/PrimType.h (+7-1) - (modified) clang/test/AST/Interp/eval-order.cpp (+2-2) - (modified) clang/test/AST/Interp/literals.cpp (+6-1) - (added) clang/test/AST/Interp/memberpointers.cpp (+184) - (modified) clang/test/CodeGenCXX/mangle-ms-templates-memptrs.cpp (+1-1) - (modified) clang/test/CodeGenCXX/pointers-to-data-members.cpp (+1-1) - (modified) clang/test/SemaCXX/attr-weak.cpp (+1) - (modified) clang/test/SemaCXX/nullptr_in_arithmetic_ops.cpp (+1-1) - (modified) clang/unittests/AST/Interp/toAPValue.cpp (+46) ``````````diff diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt index 3faefb54f599fb..a5d3dacfc1a84e 100644 --- a/clang/lib/AST/CMakeLists.txt +++ b/clang/lib/AST/CMakeLists.txt @@ -87,6 +87,7 @@ add_clang_library(clangAST Interp/Record.cpp Interp/Source.cpp Interp/State.cpp + Interp/MemberPointer.cpp Interp/InterpShared.cpp ItaniumCXXABI.cpp ItaniumMangle.cpp diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 630fdb60c35182..326eb6bf5d5c61 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -100,6 +100,35 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) { return this->emitMemcpy(CE); } + case CK_DerivedToBaseMemberPointer: { + assert(classifyPrim(CE->getType()) == PT_MemberPtr); + assert(classifyPrim(SubExpr->getType()) == PT_MemberPtr); + const auto *FromMP = SubExpr->getType()->getAs<MemberPointerType>(); + const auto *ToMP = CE->getType()->getAs<MemberPointerType>(); + + unsigned DerivedOffset = collectBaseOffset(QualType(ToMP->getClass(), 0), + QualType(FromMP->getClass(), 0)); + + if (!this->visit(SubExpr)) + return false; + + return this->emitGetMemberPtrBasePop(DerivedOffset, CE); + } + + case CK_BaseToDerivedMemberPointer: { + assert(classifyPrim(CE) == PT_MemberPtr); + assert(classifyPrim(SubExpr) == PT_MemberPtr); + const auto *FromMP = SubExpr->getType()->getAs<MemberPointerType>(); + const auto *ToMP = CE->getType()->getAs<MemberPointerType>(); + + unsigned DerivedOffset = collectBaseOffset(QualType(FromMP->getClass(), 0), + QualType(ToMP->getClass(), 0)); + + if (!this->visit(SubExpr)) + return false; + return this->emitGetMemberPtrBasePop(-DerivedOffset, CE); + } + case CK_UncheckedDerivedToBase: case CK_DerivedToBase: { if (!this->visit(SubExpr)) @@ -187,7 +216,8 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) { return this->emitCastFloatingIntegral(*ToT, CE); } - case CK_NullToPointer: { + case CK_NullToPointer: + case CK_NullToMemberPointer: { if (DiscardResult) return true; @@ -326,7 +356,8 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) { return this->emitCast(*FromT, *ToT, CE); } - case CK_PointerToBoolean: { + case CK_PointerToBoolean: + case CK_MemberPointerToBoolean: { PrimType PtrT = classifyPrim(SubExpr->getType()); // Just emit p != nullptr for this. @@ -534,8 +565,23 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) { BO->isComparisonOp()) return this->emitComplexComparison(LHS, RHS, BO); - if (BO->isPtrMemOp()) - return this->visit(RHS); + if (BO->isPtrMemOp()) { + if (!this->visit(LHS)) + return false; + + if (!this->visit(RHS)) + return false; + + if (!this->emitToMemberPtr(BO)) + return false; + + if (classifyPrim(BO) == PT_MemberPtr) + return true; + + if (!this->emitCastMemberPtrPtr(BO)) + return false; + return DiscardResult ? this->emitPopPtr(BO) : true; + } // Typecheck the args. std::optional<PrimType> LT = classify(LHS->getType()); @@ -2599,6 +2645,8 @@ bool ByteCodeExprGen<Emitter>::visitZeroInitializer(PrimType T, QualType QT, return this->emitNullPtr(nullptr, E); case PT_FnPtr: return this->emitNullFnPtr(nullptr, E); + case PT_MemberPtr: + return this->emitNullMemberPtr(nullptr, E); case PT_Float: { return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E); } @@ -2701,6 +2749,7 @@ bool ByteCodeExprGen<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) { return this->emitConstBool(Value, E); case PT_Ptr: case PT_FnPtr: + case PT_MemberPtr: case PT_Float: case PT_IntAP: case PT_IntAPS: @@ -3123,10 +3172,28 @@ bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) { } } + std::optional<unsigned> CalleeOffset; // Add the (optional, implicit) This pointer. if (const auto *MC = dyn_cast<CXXMemberCallExpr>(E)) { - if (!this->visit(MC->getImplicitObjectArgument())) - return false; + if (!FuncDecl && classifyPrim(E->getCallee()) == PT_MemberPtr) { + // If we end up creating a CallPtr op for this, we need the base of the + // member pointer as the instance pointer, and later extract the function + // decl as the function pointer. + const Expr *Callee = E->getCallee(); + CalleeOffset = + this->allocateLocalPrimitive(Callee, PT_MemberPtr, true, false); + if (!this->visit(Callee)) + return false; + if (!this->emitSetLocal(PT_MemberPtr, *CalleeOffset, E)) + return false; + if (!this->emitGetLocal(PT_MemberPtr, *CalleeOffset, E)) + return false; + if (!this->emitGetMemberPtrBase(E)) + return false; + } else { + if (!this->visit(MC->getImplicitObjectArgument())) + return false; + } } llvm::BitVector NonNullArgs = collectNonNullArgs(FuncDecl, Args); @@ -3194,11 +3261,22 @@ bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) { for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) ArgSize += align(primSize(classify(E->getArg(I)).value_or(PT_Ptr))); - if (!this->visit(E->getCallee())) - return false; + // Get the callee, either from a member pointer saved in CalleeOffset, + // or by just visiting the Callee expr. + if (CalleeOffset) { + if (!this->emitGetLocal(PT_MemberPtr, *CalleeOffset, E)) + return false; + if (!this->emitGetMemberPtrDecl(E)) + return false; + if (!this->emitCallPtr(ArgSize, E, E)) + return false; + } else { + if (!this->visit(E->getCallee())) + return false; - if (!this->emitCallPtr(ArgSize, E, E)) - return false; + if (!this->emitCallPtr(ArgSize, E, E)) + return false; + } } // Cleanup for discarded return values. @@ -3425,6 +3503,11 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { return false; return DiscardResult ? this->emitPop(*T, E) : true; case UO_AddrOf: // &x + if (E->getType()->isMemberPointerType()) { + // C++11 [expr.unary.op]p3 has very strict rules on how the address of a + // member can be formed. + return this->emitGetMemberPtr(cast<DeclRefExpr>(SubExpr)->getDecl(), E); + } // We should already have a pointer when we get here. return this->delegate(SubExpr); case UO_Deref: // *x diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp index d51a57e5e92eae..a4561cb1c9595e 100644 --- a/clang/lib/AST/Interp/Context.cpp +++ b/clang/lib/AST/Interp/Context.cpp @@ -160,8 +160,12 @@ std::optional<PrimType> Context::classify(QualType T) const { if (T->isFloatingType()) return PT_Float; + if (T->isSpecificBuiltinType(BuiltinType::BoundMember) || + T->isMemberPointerType()) + return PT_MemberPtr; + if (T->isFunctionPointerType() || T->isFunctionReferenceType() || - T->isFunctionType() || T->isSpecificBuiltinType(BuiltinType::BoundMember)) + T->isFunctionType()) return PT_FnPtr; if (T->isReferenceType() || T->isPointerType()) @@ -173,9 +177,6 @@ std::optional<PrimType> Context::classify(QualType T) const { if (const auto *DT = dyn_cast<DecltypeType>(T)) return classify(DT->getUnderlyingType()); - if (const auto *DT = dyn_cast<MemberPointerType>(T)) - return classify(DT->getPointeeType()); - return std::nullopt; } @@ -288,10 +289,12 @@ unsigned Context::collectBaseOffset(const RecordDecl *BaseDecl, } if (CurDecl == FinalDecl) break; - - // break; } assert(OffsetSum > 0); return OffsetSum; } + +const Record *Context::getRecord(const RecordDecl *D) const { + return P->getOrCreateRecord(D); +} diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h index 360e9499d08440..c78dc9a2a471eb 100644 --- a/clang/lib/AST/Interp/Context.h +++ b/clang/lib/AST/Interp/Context.h @@ -107,6 +107,8 @@ class Context final { unsigned collectBaseOffset(const RecordDecl *BaseDecl, const RecordDecl *DerivedDecl) const; + const Record *getRecord(const RecordDecl *D) const; + private: /// Runs a function. bool Run(State &Parent, const Function *Func, APValue &Result); diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp index 954c58c8cb3716..726e53ce7e0287 100644 --- a/clang/lib/AST/Interp/Descriptor.cpp +++ b/clang/lib/AST/Interp/Descriptor.cpp @@ -11,6 +11,7 @@ #include "Floating.h" #include "FunctionPointer.h" #include "IntegralAP.h" +#include "MemberPointer.h" #include "Pointer.h" #include "PrimType.h" #include "Record.h" diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index ccdc96a79436da..e3d1657532a392 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -17,6 +17,7 @@ #include "Integral.h" #include "IntegralAP.h" #include "InterpFrame.h" +#include "MemberPointer.h" #include "Opcode.h" #include "PrimType.h" #include "Program.h" @@ -120,6 +121,8 @@ static const char *primTypeToString(PrimType T) { return "Ptr"; case PT_FnPtr: return "FnPtr"; + case PT_MemberPtr: + return "MemberPtr"; } llvm_unreachable("Unhandled PrimType"); } diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 2607e074325167..417b903acd2256 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -370,6 +370,26 @@ bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, return false; } +bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + uint32_t Offset) { + uint32_t MinOffset = Ptr.getDeclDesc()->getMetadataSize(); + uint32_t PtrOffset = Ptr.getByteOffset(); + + // We subtract Offset from PtrOffset. The result must be at least + // MinOffset. + if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset) + return true; + + const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC)); + QualType TargetQT = E->getType()->getPointeeType(); + QualType MostDerivedQT = Ptr.getDeclPtr().getType(); + + S.CCEDiag(E, diag::note_constexpr_invalid_downcast) + << MostDerivedQT << TargetQT; + + return false; +} + bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { assert(Ptr.isLive() && "Pointer is not live"); if (!Ptr.isConst()) @@ -490,10 +510,12 @@ bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!CheckLive(S, OpPC, Ptr, AK_MemberCall)) return false; - if (!CheckExtern(S, OpPC, Ptr)) - return false; - if (!CheckRange(S, OpPC, Ptr, AK_MemberCall)) - return false; + if (!Ptr.isDummy()) { + if (!CheckExtern(S, OpPC, Ptr)) + return false; + if (!CheckRange(S, OpPC, Ptr, AK_MemberCall)) + return false; + } return true; } diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 66d30cc3fbaaba..2b3dc6959dba8a 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -20,6 +20,7 @@ #include "InterpFrame.h" #include "InterpStack.h" #include "InterpState.h" +#include "MemberPointer.h" #include "Opcode.h" #include "PrimType.h" #include "Program.h" @@ -74,6 +75,11 @@ bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK); +/// Checks if the dowcast using the given offset is possible with the given +/// pointer. +bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + uint32_t Offset); + /// Checks if a pointer points to const storage. bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr); @@ -724,6 +730,9 @@ using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>; template <typename T> bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) { + assert((!std::is_same_v<T, MemberPointer>) && + "Non-equality comparisons on member pointer types should already be " + "rejected in Sema."); using BoolT = PrimConv<PT_Bool>::T; const T &RHS = S.Stk.pop<T>(); const T &LHS = S.Stk.pop<T>(); @@ -833,6 +842,47 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { } } +template <> +inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC, + CompareFn Fn) { + const auto &RHS = S.Stk.pop<MemberPointer>(); + const auto &LHS = S.Stk.pop<MemberPointer>(); + + // If either operand is a pointer to a weak function, the comparison is not + // constant. + for (const auto &MP : {LHS, RHS}) { + if (const CXXMethodDecl *MD = MP.getMemberFunction(); MD && MD->isWeak()) { + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison) << MD; + return false; + } + } + + // C++11 [expr.eq]p2: + // If both operands are null, they compare equal. Otherwise if only one is + // null, they compare unequal. + if (LHS.isZero() && RHS.isZero()) { + S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Equal)); + return true; + } + if (LHS.isZero() || RHS.isZero()) { + S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Unordered)); + return true; + } + + // We cannot compare against virtual declarations at compile time. + for (const auto &MP : {LHS, RHS}) { + if (const CXXMethodDecl *MD = MP.getMemberFunction(); + MD && MD->isVirtual()) { + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD; + } + } + + S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS)))); + return true; +} + template <PrimType Name, class T = typename PrimConv<Name>::T> bool EQ(InterpState &S, CodePtr OpPC) { return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) { @@ -1295,6 +1345,9 @@ inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) { return false; if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived)) return false; + if (!CheckDowncast(S, OpPC, Ptr, Off)) + return false; + S.Stk.push<Pointer>(Ptr.atFieldSub(Off)); return true; } @@ -1319,6 +1372,12 @@ inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) { return true; } +inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) { + const auto &Ptr = S.Stk.pop<MemberPointer>(); + S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off)); + return true; +} + inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) { if (S.checkingPotentialConstantExpression()) return false; @@ -1527,6 +1586,24 @@ inline bool Memcpy(InterpState &S, CodePtr OpPC) { return DoMemcpy(S, OpPC, Src, Dest); } +inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) { + const auto &Member = S.Stk.pop<MemberPointer>(); + const auto &Base = S.Stk.pop<Pointer>(); + + S.Stk.push<MemberPointer>(Member.takeInstance(Base)); + return true; +} + +inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) { + const auto &MP = S.Stk.pop<MemberPointer>(); + + if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) { + S.Stk.push<Pointer>(*Ptr); + return true; + } + return false; +} + //===----------------------------------------------------------------------===// // AddOffset, SubOffset //===----------------------------------------------------------------------===// @@ -2332,6 +2409,28 @@ inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { return true; } +inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D) { + S.Stk.push<MemberPointer>(D); + return true; +} + +inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) { + const auto &MP = S.Stk.pop<MemberPointer>(); + + S.Stk.push<Pointer>(MP.getBase()); + return true; +} + +inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) { + const auto &MP = S.Stk.pop<MemberPointer>(); + + const auto *FD = cast<FunctionDecl>(MP.getDecl()); + const auto *Func = S.getContext().getOrCreateFunction(FD); + + S.Stk.push<FunctionPointer>(Func); + return true; +} + /// Just emit a diagnostic. The expression that caused emission of this /// op is not valid in a constant context. inline bool Invalid(InterpState &S, CodePtr OpPC) { diff --git a/clang/lib/AST/Interp/InterpFrame.cpp b/clang/lib/AST/Interp/InterpFrame.cpp index 51b0bd5c155159..54ccf9034c7a7d 100644 --- a/clang/lib/AST/Interp/InterpFrame.cpp +++ b/clang/lib/AST/Interp/InterpFrame.cpp @@ -12,6 +12,7 @@ #include "Function.h" #include "InterpStack.h" #include "InterpState.h" +#include "MemberPointer.h" #include "Pointer.h" #include "PrimType.h" #include "Program.h" diff --git a/clang/lib/AST/Interp/InterpStack.cpp b/clang/lib/AST/Interp/InterpStack.cpp index 91fe40feb7671b..c7024740d322ef 100644 --- a/clang/lib/AST/Interp/InterpStack.cpp +++ b/clang/lib/AST/Interp/InterpStack.cpp @@ -10,6 +10,7 @@ #include "Boolean.h" #include "Floating.h" #include "Integral.h" +#include "MemberPointer.h" #include "Pointer.h" #include <cassert> #include <cstdlib> diff --git a/clang/lib/AST/Interp/InterpStack.h b/clang/lib/AST/Interp/InterpStack.h index 3fd0f63c781fc7..9d85503b851be1 100644 --- a/clang/lib/AST/Interp/InterpStack.h +++ b/clang/lib/AST/Interp/InterpStack.h @@ -15,6 +15,7 @@ #include "FunctionPointer.h" #include "IntegralAP.h" +#include "MemberPointer.h" #include "PrimType.h" #include <memory> #include <vector> @@ -188,6 +189,8 @@ class InterpStack final { return PT_IntAP; else if constexpr (std::is_same_v<T, IntegralAP<false>>) return PT_IntAP; + else if constexpr (std::is_same_v<T, MemberPointer>) + return PT_MemberPtr; llvm_unreachable("unknown type push()'ed into InterpStack"); } diff --git a/clang/lib/AST/Interp/MemberPointer.cpp b/clang/lib/AST/Interp/MemberPointer.cpp new file mode 100644 index 00000000000000..f72feb23fc24da --- /dev/null +++ b/clang/lib/AST/Interp/MemberPointer.cpp @@ -0,0 +1,80 @@ + + +#include "MemberPointer.h" +#include "Context.h" +#include "FunctionPointer.h" +#include "Program.h" +#include "Record.h" + +namespace clang { +namespace interp { + +std::optional<Pointer> MemberPointer::toPointer(const Context &Ctx) const { + if (!Dcl || isa<FunctionDecl>(Dcl)) + return Base; + const FieldDecl *FD = cast<FieldDecl>(Dcl); + assert(FD); + + Pointer CastedBase = + (PtrOffset < 0 ? Base.atField(-PtrOffset) : Base.atFieldSub(PtrOffset)); + + // FIXME: The Base Pointer might be a dummy pointer. In that case, we can + // still do all of this and return yet another dummy pointer, but with the + // Base/Offset adjusted. However, right now we don't have the necessary type + // information for dummy pointers. + if (CastedBase.isDummy()) + return std::nullopt; + + const Record *BaseRecord = CastedBase.getRecord(); + assert(BaseRecord); + + if (FD->getParent() == BaseRecord->getDecl()) + return CastedBase.atField(BaseRecord->getField(FD)->Offset); + + unsigned Offset; + const RecordDecl *FieldParent = FD->getParent(); + const Record *FieldRecord = Ctx.getRecord(FieldParent); + + Offset = 0; + Offset += FieldRecord->getField(FD)->Offset; + Offset += CastedBase.block()->getDescriptor()->getMetadataSize(); + + if (Offset > CastedBase.block()->getSize()) + return std::nullopt; + + unsigned O = 0; + if (Base.getDeclPtr().getRecord()->getDecl() != FieldParent) { + O = Ctx.collectBaseOffset(FieldParent, + Pointer(const_cast<Block *>(Base.block()), 16, 16) + .getRecord() + ->getDecl()); + Offset += O; + } + + if (Offset > CastedBase.block()->getSize()) + return std::nullopt; + + assert(Offset <= CastedBase.block()->getSize()); + Pointer Result; + Result = Pointer(const_cast<Block *>(Base.block()), Offset, Offset); + return Result; +} + +FunctionPointer MemberPointer::toFunctionPointer(const Context &Ctx) const { + return ... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/91303 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits