aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/AST/ByteCode
diff options
context:
space:
mode:
authorNAKAMURA Takumi <geek4civic@gmail.com>2025-01-09 18:31:57 +0900
committerNAKAMURA Takumi <geek4civic@gmail.com>2025-01-09 18:33:27 +0900
commitdf025ebf872052c0761d44a3ef9b65e9675af8a8 (patch)
tree9b4e94583e2536546d6606270bcdf846c95e1ba2 /clang/lib/AST/ByteCode
parent4428c9d0b1344179f85a72e183a44796976521e3 (diff)
parentbdcf47e4bcb92889665825654bb80a8bbe30379e (diff)
downloadllvm-users/chapuni/cov/single/loop.zip
llvm-users/chapuni/cov/single/loop.tar.gz
llvm-users/chapuni/cov/single/loop.tar.bz2
Merge branch 'users/chapuni/cov/single/base' into users/chapuni/cov/single/loopusers/chapuni/cov/single/loop
Conflicts: clang/lib/CodeGen/CoverageMappingGen.cpp
Diffstat (limited to 'clang/lib/AST/ByteCode')
-rw-r--r--clang/lib/AST/ByteCode/Compiler.cpp32
-rw-r--r--clang/lib/AST/ByteCode/Compiler.h1
-rw-r--r--clang/lib/AST/ByteCode/Interp.cpp82
-rw-r--r--clang/lib/AST/ByteCode/Interp.h63
-rw-r--r--clang/lib/AST/ByteCode/InterpBuiltin.cpp71
-rw-r--r--clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp2
-rw-r--r--clang/lib/AST/ByteCode/Opcodes.td4
-rw-r--r--clang/lib/AST/ByteCode/Pointer.cpp17
-rw-r--r--clang/lib/AST/ByteCode/Pointer.h25
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;
};