diff options
author | NAKAMURA Takumi <geek4civic@gmail.com> | 2025-01-09 18:15:55 +0900 |
---|---|---|
committer | NAKAMURA Takumi <geek4civic@gmail.com> | 2025-01-09 18:15:55 +0900 |
commit | bdcf47e4bcb92889665825654bb80a8bbe30379e (patch) | |
tree | 4de1d6b4ddc69f4f32daabb11ad5c71ab0cf895e /clang/lib/AST/ByteCode | |
parent | e7fd5cd25334048980ea207a9eff72698724721a (diff) | |
parent | fea7da1b00cc97d742faede2df96c7d327950f49 (diff) | |
download | llvm-users/chapuni/cov/single/base.zip llvm-users/chapuni/cov/single/base.tar.gz llvm-users/chapuni/cov/single/base.tar.bz2 |
Merge branch 'users/chapuni/cov/single/nextcount' into users/chapuni/cov/single/baseusers/chapuni/cov/single/base
Diffstat (limited to 'clang/lib/AST/ByteCode')
-rw-r--r-- | clang/lib/AST/ByteCode/Compiler.cpp | 32 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Compiler.h | 1 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Interp.cpp | 82 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Interp.h | 63 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/InterpBuiltin.cpp | 71 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp | 2 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Opcodes.td | 4 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Pointer.cpp | 17 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Pointer.h | 25 |
9 files changed, 216 insertions, 81 deletions
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 68c75b0..036f960 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -3427,6 +3427,38 @@ bool Compiler<Emitter>::VisitBlockExpr(const BlockExpr *E) { } template <class Emitter> +bool Compiler<Emitter>::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { + const Type *TypeInfoType = E->getType().getTypePtr(); + + if (!E->isPotentiallyEvaluated()) { + if (DiscardResult) + return true; + + if (E->isTypeOperand()) + return this->emitGetTypeid( + E->getTypeOperand(Ctx.getASTContext()).getTypePtr(), TypeInfoType, E); + return this->emitGetTypeid(E->getExprOperand()->getType().getTypePtr(), + TypeInfoType, E); + } + + // Otherwise, we need to evaluate the expression operand. + assert(E->getExprOperand()); + assert(E->getExprOperand()->isLValue()); + + if (!Ctx.getLangOpts().CPlusPlus20 && !this->emitDiagTypeid(E)) + return false; + + if (!this->visit(E->getExprOperand())) + return false; + + if (!this->emitGetTypeidPtr(TypeInfoType, E)) + return false; + if (DiscardResult) + return this->emitPopPtr(E); + return true; +} + +template <class Emitter> bool Compiler<Emitter>::VisitExpressionTraitExpr(const ExpressionTraitExpr *E) { assert(Ctx.getLangOpts().CPlusPlus); return this->emitConstBool(E->getValue(), E); diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index 2a94f5e..71765b1 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -205,6 +205,7 @@ public: bool VisitCXXNewExpr(const CXXNewExpr *E); bool VisitCXXDeleteExpr(const CXXDeleteExpr *E); bool VisitBlockExpr(const BlockExpr *E); + bool VisitCXXTypeidExpr(const CXXTypeidExpr *E); // Statements. bool visitCompoundStmt(const CompoundStmt *S); diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 7c77520..cb0ce886 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1154,6 +1154,53 @@ bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) { return false; } +static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + uint32_t Off) { + if (S.getLangOpts().CPlusPlus && S.inConstantContext() && + !CheckNull(S, OpPC, Ptr, CSK_Field)) + return false; + + if (!CheckExtern(S, OpPC, Ptr)) + return false; + if (!CheckRange(S, OpPC, Ptr, CSK_Field)) + return false; + if (!CheckArray(S, OpPC, Ptr)) + return false; + if (!CheckSubobject(S, OpPC, Ptr, CSK_Field)) + return false; + + if (Ptr.isIntegralPointer()) { + S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off)); + return true; + } + + if (!Ptr.isBlockPointer()) { + // FIXME: The only time we (seem to) get here is when trying to access a + // field of a typeid pointer. In that case, we're supposed to diagnose e.g. + // `typeid(int).name`, but we currently diagnose `&typeid(int)`. + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_access_unreadable_object) + << AK_Read << Ptr.toDiagnosticString(S.getASTContext()); + return false; + } + + if (Off > Ptr.block()->getSize()) + return false; + + S.Stk.push<Pointer>(Ptr.atField(Off)); + return true; +} + +bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) { + const auto &Ptr = S.Stk.peek<Pointer>(); + return getField(S, OpPC, Ptr, Off); +} + +bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) { + const auto &Ptr = S.Stk.pop<Pointer>(); + return getField(S, OpPC, Ptr, Off); +} + static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func, const Pointer &ThisPtr) { assert(Func->isConstructor()); @@ -1595,6 +1642,41 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, return false; } +bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr, + const Type *TypeInfoType) { + S.Stk.push<Pointer>(TypePtr, TypeInfoType); + return true; +} + +bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) { + const auto &P = S.Stk.pop<Pointer>(); + + if (!P.isBlockPointer()) + return false; + + if (P.isDummy()) { + QualType StarThisType = + S.getASTContext().getLValueReferenceType(P.getType()); + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_polymorphic_unknown_dynamic_type) + << AK_TypeId + << P.toAPValue(S.getASTContext()) + .getAsString(S.getASTContext(), StarThisType); + return false; + } + + S.Stk.push<Pointer>(P.getType().getTypePtr(), TypeInfoType); + return true; +} + +bool DiagTypeid(InterpState &S, CodePtr OpPC) { + const auto *E = cast<CXXTypeidExpr>(S.Current->getExpr(OpPC)); + S.CCEDiag(E, diag::note_constexpr_typeid_polymorphic) + << E->getExprOperand()->getType() + << E->getExprOperand()->getSourceRange(); + return false; +} + // https://github.com/llvm/llvm-project/issues/102513 #if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG) #pragma optimize("", off) diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 8461d1e..d2aec69 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -1526,61 +1526,8 @@ inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { /// 1) Peeks a Pointer /// 2) Pushes Pointer.atField(Off) on the stack -inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) { - const Pointer &Ptr = S.Stk.peek<Pointer>(); - - if (S.getLangOpts().CPlusPlus && S.inConstantContext() && - !CheckNull(S, OpPC, Ptr, CSK_Field)) - return false; - - if (!CheckExtern(S, OpPC, Ptr)) - return false; - if (!CheckRange(S, OpPC, Ptr, CSK_Field)) - return false; - if (!CheckArray(S, OpPC, Ptr)) - return false; - if (!CheckSubobject(S, OpPC, Ptr, CSK_Field)) - return false; - - if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize()) - return false; - - if (Ptr.isIntegralPointer()) { - S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off)); - return true; - } - - S.Stk.push<Pointer>(Ptr.atField(Off)); - return true; -} - -inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) { - const Pointer &Ptr = S.Stk.pop<Pointer>(); - - if (S.getLangOpts().CPlusPlus && S.inConstantContext() && - !CheckNull(S, OpPC, Ptr, CSK_Field)) - return false; - - if (!CheckExtern(S, OpPC, Ptr)) - return false; - if (!CheckRange(S, OpPC, Ptr, CSK_Field)) - return false; - if (!CheckArray(S, OpPC, Ptr)) - return false; - if (!CheckSubobject(S, OpPC, Ptr, CSK_Field)) - return false; - - if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize()) - return false; - - if (Ptr.isIntegralPointer()) { - S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off)); - return true; - } - - S.Stk.push<Pointer>(Ptr.atField(Off)); - return true; -} +bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off); +bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off); inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) { if (S.checkingPotentialConstantExpression()) @@ -3087,6 +3034,12 @@ inline bool BitCast(InterpState &S, CodePtr OpPC) { return true; } +/// Typeid support. +bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr, + const Type *TypeInfoType); +bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType); +bool DiagTypeid(InterpState &S, CodePtr OpPC); + //===----------------------------------------------------------------------===// // Read opcode arguments //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 2ae91fe..0d52083 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -17,6 +17,7 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/SipHash.h" namespace clang { @@ -154,7 +155,7 @@ static void diagnoseNonConstexprBuiltin(InterpState &S, CodePtr OpPC, if (S.getLangOpts().CPlusPlus11) S.CCEDiag(Loc, diag::note_constexpr_invalid_function) << /*isConstexpr=*/0 << /*isConstructor=*/0 - << ("'" + S.getASTContext().BuiltinInfo.getName(ID) + "'").str(); + << S.getASTContext().BuiltinInfo.getQuotedName(ID); else S.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr); } @@ -1543,9 +1544,10 @@ static bool interp__builtin_constant_p(InterpState &S, CodePtr OpPC, if (Res.isInvalid()) { C.cleanup(); Stk.clear(); + return returnInt(false); } - if (!Res.isInvalid() && !Res.empty()) { + if (!Res.empty()) { const APValue &LV = Res.toAPValue(); if (LV.isLValue()) { APValue::LValueBase Base = LV.getLValueBase(); @@ -1837,6 +1839,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, assert(Call->getNumArgs() == 3); unsigned ID = Func->getBuiltinID(); Pointer DestPtr = getParam<Pointer>(Frame, 0); + const ASTContext &ASTCtx = S.getASTContext(); const Pointer &SrcPtr = getParam<Pointer>(Frame, 1); const APSInt &Size = peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2))); @@ -1857,34 +1860,63 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, Pointer DiagPtr = (SrcPtr.isZero() ? SrcPtr : DestPtr); S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_null) << /*IsMove=*/Move << /*IsWchar=*/false << !SrcPtr.isZero() - << DiagPtr.toDiagnosticString(S.getASTContext()); + << DiagPtr.toDiagnosticString(ASTCtx); return false; } - QualType ElemType; - if (DestPtr.getFieldDesc()->isArray()) - ElemType = DestPtr.getFieldDesc()->getElemQualType(); - else - ElemType = DestPtr.getType(); + // Can't read from dummy pointers. + if (DestPtr.isDummy() || SrcPtr.isDummy()) + return false; - unsigned ElemSize = - S.getASTContext().getTypeSizeInChars(ElemType).getQuantity(); - if (Size.urem(ElemSize) != 0) { + QualType DestElemType; + size_t RemainingDestElems; + if (DestPtr.getFieldDesc()->isArray()) { + DestElemType = DestPtr.getFieldDesc()->getElemQualType(); + RemainingDestElems = DestPtr.isUnknownSizeArray() + ? 0 + : (DestPtr.getNumElems() - DestPtr.getIndex()); + } else { + DestElemType = DestPtr.getType(); + RemainingDestElems = 1; + } + unsigned DestElemSize = ASTCtx.getTypeSizeInChars(DestElemType).getQuantity(); + + if (Size.urem(DestElemSize) != 0) { S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_unsupported) - << Move << /*IsWchar=*/false << 0 << ElemType << Size << ElemSize; + << Move << /*IsWchar=*/false << 0 << DestElemType << Size + << DestElemSize; return false; } QualType SrcElemType; - if (SrcPtr.getFieldDesc()->isArray()) + size_t RemainingSrcElems; + if (SrcPtr.getFieldDesc()->isArray()) { SrcElemType = SrcPtr.getFieldDesc()->getElemQualType(); - else + RemainingSrcElems = SrcPtr.isUnknownSizeArray() + ? 0 + : (SrcPtr.getNumElems() - SrcPtr.getIndex()); + } else { SrcElemType = SrcPtr.getType(); + RemainingSrcElems = 1; + } + unsigned SrcElemSize = ASTCtx.getTypeSizeInChars(SrcElemType).getQuantity(); - if (!S.getASTContext().hasSameUnqualifiedType(ElemType, SrcElemType)) { + if (!ASTCtx.hasSameUnqualifiedType(DestElemType, SrcElemType)) { S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_type_pun) - << Move << SrcElemType << ElemType; + << Move << SrcElemType << DestElemType; + return false; + } + + // Check if we have enough elements to read from and write to/ + size_t RemainingDestBytes = RemainingDestElems * DestElemSize; + size_t RemainingSrcBytes = RemainingSrcElems * SrcElemSize; + if (Size.ugt(RemainingDestBytes) || Size.ugt(RemainingSrcBytes)) { + APInt N = Size.udiv(DestElemSize); + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_memcpy_unsupported) + << Move << /*IsWChar*/ false << (Size.ugt(RemainingSrcBytes) ? 1 : 2) + << DestElemType << toString(N, 10, /*Signed=*/false); return false; } @@ -1902,10 +1934,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, } } - // As a last resort, reject dummy pointers. - if (DestPtr.isDummy() || SrcPtr.isDummy()) - return false; - assert(Size.getZExtValue() % ElemSize == 0); + assert(Size.getZExtValue() % DestElemSize == 0); if (!DoMemcpy(S, OpPC, SrcPtr, DestPtr, Bytes(Size.getZExtValue()).toBits())) return false; @@ -1948,7 +1977,7 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC, !isOneByteCharacterType(PtrB.getType()))) { S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcmp_unsupported) - << ("'" + ASTCtx.BuiltinInfo.getName(ID) + "'").str() << PtrA.getType() + << ASTCtx.BuiltinInfo.getQuotedName(ID) << PtrA.getType() << PtrB.getType(); return false; } diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp index 0fc94e1..57c1fab 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp @@ -110,7 +110,7 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset, if (FieldDesc->isCompositeArray()) { QualType ElemType = FieldDesc->getElemQualType(); Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType)); - for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) { + for (unsigned I = P.getIndex(); I != FieldDesc->getNumElems(); ++I) { enumerateData(P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F); Offset += ElemSize; if (Offset >= BitsToRead) diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 123c21f..4b0c902 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -850,3 +850,7 @@ def BitCastPrim : Opcode { } def BitCast : Opcode; + +def GetTypeid : Opcode { let Args = [ArgTypePtr, ArgTypePtr]; } +def GetTypeidPtr : Opcode { let Args = [ArgTypePtr]; } +def DiagTypeid : Opcode; diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 01e6423..ec4756f 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -96,6 +96,8 @@ void Pointer::operator=(const Pointer &P) { PointeeStorage.Int = P.PointeeStorage.Int; } else if (P.isFunctionPointer()) { PointeeStorage.Fn = P.PointeeStorage.Fn; + } else if (P.isTypeidPointer()) { + PointeeStorage.Typeid = P.PointeeStorage.Typeid; } else { assert(false && "Unhandled storage kind"); } @@ -132,6 +134,8 @@ void Pointer::operator=(Pointer &&P) { PointeeStorage.Int = P.PointeeStorage.Int; } else if (P.isFunctionPointer()) { PointeeStorage.Fn = P.PointeeStorage.Fn; + } else if (P.isTypeidPointer()) { + PointeeStorage.Typeid = P.PointeeStorage.Typeid; } else { assert(false && "Unhandled storage kind"); } @@ -151,6 +155,14 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { if (isFunctionPointer()) return asFunctionPointer().toAPValue(ASTCtx); + if (isTypeidPointer()) { + TypeInfoLValue TypeInfo(PointeeStorage.Typeid.TypePtr); + return APValue( + APValue::LValueBase::getTypeInfo( + TypeInfo, QualType(PointeeStorage.Typeid.TypeInfoType, 0)), + CharUnits::Zero(), APValue::NoLValuePath{}); + } + // Build the lvalue base from the block. const Descriptor *Desc = getDeclDesc(); APValue::LValueBase Base; @@ -304,6 +316,9 @@ void Pointer::print(llvm::raw_ostream &OS) const { case Storage::Fn: OS << "(Fn) { " << asFunctionPointer().getFunction() << " + " << Offset << " }"; + break; + case Storage::Typeid: + OS << "(Typeid)"; } } @@ -450,6 +465,8 @@ bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) { return true; if (A.isFunctionPointer() && B.isFunctionPointer()) return true; + if (A.isTypeidPointer() && B.isTypeidPointer()) + return true; if (A.isIntegralPointer() || B.isIntegralPointer()) return A.getSource() == B.getSource(); diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index 0d467c2..ef03c12 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -49,7 +49,12 @@ struct IntPointer { IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const; }; -enum class Storage { Block, Int, Fn }; +struct TypeidPointer { + const Type *TypePtr; + const Type *TypeInfoType; +}; + +enum class Storage { Block, Int, Fn, Typeid }; /// A pointer to a memory block, live or dead. /// @@ -107,6 +112,11 @@ public: : Offset(Offset), StorageKind(Storage::Fn) { PointeeStorage.Fn = FunctionPointer(F); } + Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset = 0) + : Offset(Offset), StorageKind(Storage::Typeid) { + PointeeStorage.Typeid.TypePtr = TypePtr; + PointeeStorage.Typeid.TypeInfoType = TypeInfoType; + } Pointer(Block *Pointee, unsigned Base, uint64_t Offset); ~Pointer(); @@ -263,6 +273,8 @@ public: return asBlockPointer().Pointee == nullptr; if (isFunctionPointer()) return asFunctionPointer().isZero(); + if (isTypeidPointer()) + return false; assert(isIntegralPointer()); return asIntPointer().Value == 0 && Offset == 0; } @@ -284,7 +296,7 @@ public: const Descriptor *getDeclDesc() const { if (isIntegralPointer()) return asIntPointer().Desc; - if (isFunctionPointer()) + if (isFunctionPointer() || isTypeidPointer()) return nullptr; assert(isBlockPointer()); @@ -337,6 +349,9 @@ public: /// Returns the type of the innermost field. QualType getType() const { + if (isTypeidPointer()) + return QualType(PointeeStorage.Typeid.TypeInfoType, 0); + if (inPrimitiveArray() && Offset != asBlockPointer().Base) { // Unfortunately, complex and vector types are not array types in clang, // but they are for us. @@ -437,7 +452,7 @@ public: } /// Pointer points directly to a block. bool isRoot() const { - if (isZero() || isIntegralPointer()) + if (isZero() || !isBlockPointer()) return true; return (asBlockPointer().Base == asBlockPointer().Pointee->getDescriptor()->getMetadataSize() || @@ -467,6 +482,7 @@ public: bool isBlockPointer() const { return StorageKind == Storage::Block; } bool isIntegralPointer() const { return StorageKind == Storage::Int; } bool isFunctionPointer() const { return StorageKind == Storage::Fn; } + bool isTypeidPointer() const { return StorageKind == Storage::Typeid; } /// Returns the record descriptor of a class. const Record *getRecord() const { return getFieldDesc()->ElemRecord; } @@ -605,7 +621,7 @@ public: /// Checks if the index is one past end. bool isOnePastEnd() const { - if (isIntegralPointer() || isFunctionPointer()) + if (!isBlockPointer()) return false; if (!asBlockPointer().Pointee) @@ -746,6 +762,7 @@ private: BlockPointer BS; IntPointer Int; FunctionPointer Fn; + TypeidPointer Typeid; } PointeeStorage; Storage StorageKind = Storage::Int; }; |