summaryrefslogtreecommitdiff
path: root/clang/lib/AST/ByteCode
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST/ByteCode')
-rw-r--r--clang/lib/AST/ByteCode/Compiler.cpp211
-rw-r--r--clang/lib/AST/ByteCode/Compiler.h8
-rw-r--r--clang/lib/AST/ByteCode/Context.cpp9
-rw-r--r--clang/lib/AST/ByteCode/Descriptor.cpp108
-rw-r--r--clang/lib/AST/ByteCode/Disasm.cpp55
-rw-r--r--clang/lib/AST/ByteCode/EvalEmitter.cpp17
-rw-r--r--clang/lib/AST/ByteCode/EvaluationResult.cpp58
-rw-r--r--clang/lib/AST/ByteCode/EvaluationResult.h57
-rw-r--r--clang/lib/AST/ByteCode/Integral.h5
-rw-r--r--clang/lib/AST/ByteCode/Interp.cpp32
-rw-r--r--clang/lib/AST/ByteCode/Interp.h10
-rw-r--r--clang/lib/AST/ByteCode/InterpBuiltin.cpp427
-rw-r--r--clang/lib/AST/ByteCode/InterpFrame.cpp6
-rw-r--r--clang/lib/AST/ByteCode/InterpFrame.h2
-rw-r--r--clang/lib/AST/ByteCode/InterpState.cpp38
-rw-r--r--clang/lib/AST/ByteCode/InterpState.h24
-rw-r--r--clang/lib/AST/ByteCode/Pointer.cpp75
-rw-r--r--clang/lib/AST/ByteCode/Pointer.h217
-rw-r--r--clang/lib/AST/ByteCode/PrimType.h10
-rw-r--r--clang/lib/AST/ByteCode/Program.cpp39
-rw-r--r--clang/lib/AST/ByteCode/Program.h18
-rw-r--r--clang/lib/AST/ByteCode/Record.cpp11
-rw-r--r--clang/lib/AST/ByteCode/Record.h4
-rw-r--r--clang/lib/AST/ByteCode/State.h25
24 files changed, 863 insertions, 603 deletions
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index e3235d34e230..a21358338250 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -62,7 +62,7 @@ public:
OptionScope(Compiler<Emitter> *Ctx, bool NewDiscardResult,
bool NewInitializing, bool NewToLValue)
: Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
- OldInitializing(Ctx->Initializing), OldToLValue(NewToLValue) {
+ OldInitializing(Ctx->Initializing), OldToLValue(Ctx->ToLValue) {
Ctx->DiscardResult = NewDiscardResult;
Ctx->Initializing = NewInitializing;
Ctx->ToLValue = NewToLValue;
@@ -559,8 +559,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
// Possibly diagnose casts to enum types if the target type does not
// have a fixed size.
if (Ctx.getLangOpts().CPlusPlus && CE->getType()->isEnumeralType()) {
- const auto *ET = CE->getType().getCanonicalType()->castAs<EnumType>();
- const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *ED = CE->getType()->castAsEnumDecl();
if (!ED->isFixed()) {
if (!this->emitCheckEnumValue(*FromT, ED, CE))
return false;
@@ -943,7 +942,7 @@ bool Compiler<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
if (!Result)
return false;
if (DiscardResult)
- return this->emitPop(*T, BO);
+ return this->emitPopBool(BO);
if (T != PT_Bool)
return this->emitCast(PT_Bool, *T, BO);
return true;
@@ -1377,14 +1376,20 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
template <class Emitter>
bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) {
+ const Expr *LHS = E->getLHS();
+ const Expr *RHS = E->getRHS();
assert(!E->isCommaOp() &&
"Comma op should be handled in VisitBinaryOperator");
assert(E->getType()->isVectorType());
- assert(E->getLHS()->getType()->isVectorType());
- assert(E->getRHS()->getType()->isVectorType());
+ assert(LHS->getType()->isVectorType());
+ assert(RHS->getType()->isVectorType());
+
+ // We can only handle vectors with primitive element types.
+ if (!canClassify(LHS->getType()->castAs<VectorType>()->getElementType()))
+ return false;
// Prepare storage for result.
- if (!Initializing && !E->isCompoundAssignmentOp()) {
+ if (!Initializing && !E->isCompoundAssignmentOp() && !E->isAssignmentOp()) {
UnsignedOrNone LocalIndex = allocateTemporary(E);
if (!LocalIndex)
return false;
@@ -1392,8 +1397,6 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) {
return false;
}
- const Expr *LHS = E->getLHS();
- const Expr *RHS = E->getRHS();
const auto *VecTy = E->getType()->getAs<VectorType>();
auto Op = E->isCompoundAssignmentOp()
? BinaryOperator::getOpForCompoundAssignment(E->getOpcode())
@@ -1403,6 +1406,21 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) {
PrimType RHSElemT = this->classifyVectorElementType(RHS->getType());
PrimType ResultElemT = this->classifyVectorElementType(E->getType());
+ if (E->getOpcode() == BO_Assign) {
+ assert(Ctx.getASTContext().hasSameUnqualifiedType(
+ LHS->getType()->castAs<VectorType>()->getElementType(),
+ RHS->getType()->castAs<VectorType>()->getElementType()));
+ if (!this->visit(LHS))
+ return false;
+ if (!this->visit(RHS))
+ return false;
+ if (!this->emitCopyArray(ElemT, 0, 0, VecTy->getNumElements(), E))
+ return false;
+ if (DiscardResult)
+ return this->emitPopPtr(E);
+ return true;
+ }
+
// Evaluate LHS and save value to LHSOffset.
unsigned LHSOffset =
this->allocateLocalPrimitive(LHS, PT_Ptr, /*IsConst=*/true);
@@ -2248,7 +2266,9 @@ bool Compiler<Emitter>::VisitUnaryExprOrTypeTraitExpr(
assert(VAT);
if (VAT->getElementType()->isArrayType()) {
std::optional<APSInt> Res =
- VAT->getSizeExpr()->getIntegerConstantExpr(ASTCtx);
+ VAT->getSizeExpr()
+ ? VAT->getSizeExpr()->getIntegerConstantExpr(ASTCtx)
+ : std::nullopt;
if (Res) {
if (DiscardResult)
return true;
@@ -2892,25 +2912,20 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(
OptPrimType SubExprT = classify(SubExpr);
bool IsStatic = E->getStorageDuration() == SD_Static;
if (IsStatic) {
- std::optional<unsigned> GlobalIndex = P.createGlobal(E);
+
+ UnsignedOrNone GlobalIndex = P.createGlobal(E);
if (!GlobalIndex)
return false;
const LifetimeExtendedTemporaryDecl *TempDecl =
E->getLifetimeExtendedTemporaryDecl();
- if (IsStatic)
- assert(TempDecl);
+ assert(TempDecl);
if (SubExprT) {
if (!this->visit(SubExpr))
return false;
- if (IsStatic) {
- if (!this->emitInitGlobalTemp(*SubExprT, *GlobalIndex, TempDecl, E))
- return false;
- } else {
- if (!this->emitInitGlobal(*SubExprT, *GlobalIndex, E))
- return false;
- }
+ if (!this->emitInitGlobalTemp(*SubExprT, *GlobalIndex, TempDecl, E))
+ return false;
return this->emitGetPtrGlobal(*GlobalIndex, E);
}
@@ -2921,9 +2936,7 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(
return false;
if (!this->visitInitializer(SubExpr))
return false;
- if (IsStatic)
- return this->emitInitGlobalTempComp(TempDecl, E);
- return true;
+ return this->emitInitGlobalTempComp(TempDecl, E);
}
// For everyhing else, use local variables.
@@ -2989,7 +3002,7 @@ bool Compiler<Emitter>::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
if (T && !E->isLValue())
return this->delegate(Init);
- std::optional<unsigned> GlobalIndex = P.createGlobal(E);
+ UnsignedOrNone GlobalIndex = P.createGlobal(E);
if (!GlobalIndex)
return false;
@@ -3333,7 +3346,7 @@ bool Compiler<Emitter>::VisitSourceLocExpr(const SourceLocExpr *E) {
auto *UGCD = cast<UnnamedGlobalConstantDecl>(BaseDecl);
- std::optional<unsigned> GlobalIndex = P.getOrCreateGlobal(UGCD);
+ UnsignedOrNone GlobalIndex = P.getOrCreateGlobal(UGCD);
if (!GlobalIndex)
return false;
@@ -3856,7 +3869,7 @@ bool Compiler<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
if (!RD->isCompleteDefinition())
return this->emitDummyPtr(GuidDecl, E);
- std::optional<unsigned> GlobalIndex = P.getOrCreateGlobal(GuidDecl);
+ UnsignedOrNone GlobalIndex = P.getOrCreateGlobal(GuidDecl);
if (!GlobalIndex)
return false;
if (!this->emitGetPtrGlobal(*GlobalIndex, E))
@@ -3879,6 +3892,8 @@ bool Compiler<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
template <class Emitter>
bool Compiler<Emitter>::VisitRequiresExpr(const RequiresExpr *E) {
assert(classifyPrim(E->getType()) == PT_Bool);
+ if (E->isValueDependent())
+ return false;
if (DiscardResult)
return true;
return this->emitConstBool(E->isSatisfied(), E);
@@ -4169,6 +4184,31 @@ template <class Emitter> bool Compiler<Emitter>::delegate(const Expr *E) {
return this->Visit(E);
}
+static const Expr *stripCheckedDerivedToBaseCasts(const Expr *E) {
+ if (const auto *PE = dyn_cast<ParenExpr>(E))
+ return stripCheckedDerivedToBaseCasts(PE->getSubExpr());
+
+ if (const auto *CE = dyn_cast<CastExpr>(E);
+ CE &&
+ (CE->getCastKind() == CK_DerivedToBase || CE->getCastKind() == CK_NoOp))
+ return stripCheckedDerivedToBaseCasts(CE->getSubExpr());
+
+ return E;
+}
+
+static const Expr *stripDerivedToBaseCasts(const Expr *E) {
+ if (const auto *PE = dyn_cast<ParenExpr>(E))
+ return stripDerivedToBaseCasts(PE->getSubExpr());
+
+ if (const auto *CE = dyn_cast<CastExpr>(E);
+ CE && (CE->getCastKind() == CK_DerivedToBase ||
+ CE->getCastKind() == CK_UncheckedDerivedToBase ||
+ CE->getCastKind() == CK_NoOp))
+ return stripDerivedToBaseCasts(CE->getSubExpr());
+
+ return E;
+}
+
template <class Emitter> bool Compiler<Emitter>::visit(const Expr *E) {
if (E->getType().isNull())
return false;
@@ -4177,9 +4217,8 @@ template <class Emitter> bool Compiler<Emitter>::visit(const Expr *E) {
return this->discard(E);
// Create local variable to hold the return value.
- if (!E->isGLValue() && !E->getType()->isAnyComplexType() &&
- !canClassify(E->getType())) {
- UnsignedOrNone LocalIndex = allocateLocal(E);
+ if (!E->isGLValue() && !canClassify(E->getType())) {
+ UnsignedOrNone LocalIndex = allocateLocal(stripDerivedToBaseCasts(E));
if (!LocalIndex)
return false;
@@ -4608,8 +4647,8 @@ UnsignedOrNone Compiler<Emitter>::allocateTemporary(const Expr *E) {
template <class Emitter>
const RecordType *Compiler<Emitter>::getRecordTy(QualType Ty) {
if (const PointerType *PT = dyn_cast<PointerType>(Ty))
- return PT->getPointeeType()->getAs<RecordType>();
- return Ty->getAs<RecordType>();
+ return PT->getPointeeType()->getAsCanonical<RecordType>();
+ return Ty->getAsCanonical<RecordType>();
}
template <class Emitter> Record *Compiler<Emitter>::getRecord(QualType Ty) {
@@ -4822,7 +4861,7 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
DeclScope<Emitter> LocalScope(this, VD);
// We've already seen and initialized this global.
- if (std::optional<unsigned> GlobalIndex = P.getGlobal(VD)) {
+ if (UnsignedOrNone GlobalIndex = P.getGlobal(VD)) {
if (P.getPtrGlobal(*GlobalIndex).isInitialized())
return checkDecl();
@@ -4831,7 +4870,7 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
return Init && checkDecl() && initGlobal(*GlobalIndex);
}
- std::optional<unsigned> GlobalIndex = P.createGlobal(VD, Init);
+ UnsignedOrNone GlobalIndex = P.createGlobal(VD, Init);
if (!GlobalIndex)
return false;
@@ -5057,18 +5096,6 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E,
return true;
}
-static const Expr *stripDerivedToBaseCasts(const Expr *E) {
- if (const auto *PE = dyn_cast<ParenExpr>(E))
- return stripDerivedToBaseCasts(PE->getSubExpr());
-
- if (const auto *CE = dyn_cast<CastExpr>(E);
- CE &&
- (CE->getCastKind() == CK_DerivedToBase || CE->getCastKind() == CK_NoOp))
- return stripDerivedToBaseCasts(CE->getSubExpr());
-
- return E;
-}
-
template <class Emitter>
bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
const FunctionDecl *FuncDecl = E->getDirectCallee();
@@ -5173,7 +5200,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
const auto *InstancePtr = MC->getImplicitObjectArgument();
if (isa_and_nonnull<CXXDestructorDecl>(CompilingFunction) ||
isa_and_nonnull<CXXConstructorDecl>(CompilingFunction)) {
- const auto *Stripped = stripDerivedToBaseCasts(InstancePtr);
+ const auto *Stripped = stripCheckedDerivedToBaseCasts(InstancePtr);
if (isa<CXXThisExpr>(Stripped)) {
FuncDecl =
cast<CXXMethodDecl>(FuncDecl)->getCorrespondingMethodInClass(
@@ -5228,6 +5255,12 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
const Function *Func = getFunction(FuncDecl);
if (!Func)
return false;
+
+ // In error cases, the function may be called with fewer arguments than
+ // parameters.
+ if (E->getNumArgs() < Func->getNumWrittenParams())
+ return false;
+
assert(HasRVO == Func->hasRVO());
bool HasQualifier = false;
@@ -6244,26 +6277,21 @@ bool Compiler<Emitter>::compileDestructor(const CXXDestructorDecl *Dtor) {
// First, destroy all fields.
for (const Record::Field &Field : llvm::reverse(R->fields())) {
const Descriptor *D = Field.Desc;
- if (!D->isPrimitive() && !D->isPrimitiveArray()) {
- if (!this->emitGetPtrField(Field.Offset, SourceInfo{}))
- return false;
- if (!this->emitDestruction(D, SourceInfo{}))
- return false;
- if (!this->emitPopPtr(SourceInfo{}))
- return false;
- }
+ if (D->hasTrivialDtor())
+ continue;
+ if (!this->emitGetPtrField(Field.Offset, SourceInfo{}))
+ return false;
+ if (!this->emitDestructionPop(D, SourceInfo{}))
+ return false;
}
}
for (const Record::Base &Base : llvm::reverse(R->bases())) {
- if (Base.R->isAnonymousUnion())
+ if (Base.R->hasTrivialDtor())
continue;
-
if (!this->emitGetPtrBase(Base.Offset, SourceInfo{}))
return false;
- if (!this->emitRecordDestruction(Base.R, {}))
- return false;
- if (!this->emitPopPtr(SourceInfo{}))
+ if (!this->emitRecordDestructionPop(Base.R, {}))
return false;
}
@@ -6775,7 +6803,7 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
return F && this->emitGetFnPtr(F, E);
}
if (const auto *TPOD = dyn_cast<TemplateParamObjectDecl>(D)) {
- if (std::optional<unsigned> Index = P.getOrCreateGlobal(D)) {
+ if (UnsignedOrNone Index = P.getOrCreateGlobal(D)) {
if (!this->emitGetPtrGlobal(*Index, E))
return false;
if (OptPrimType T = classify(E->getType())) {
@@ -7160,71 +7188,56 @@ bool Compiler<Emitter>::emitComplexComparison(const Expr *LHS, const Expr *RHS,
/// on the stack.
/// Emit destruction of record types (or arrays of record types).
template <class Emitter>
-bool Compiler<Emitter>::emitRecordDestruction(const Record *R, SourceInfo Loc) {
+bool Compiler<Emitter>::emitRecordDestructionPop(const Record *R,
+ SourceInfo Loc) {
assert(R);
- assert(!R->isAnonymousUnion());
+ assert(!R->hasTrivialDtor());
const CXXDestructorDecl *Dtor = R->getDestructor();
- if (!Dtor || Dtor->isTrivial())
- return true;
-
assert(Dtor);
const Function *DtorFunc = getFunction(Dtor);
if (!DtorFunc)
return false;
assert(DtorFunc->hasThisPointer());
assert(DtorFunc->getNumParams() == 1);
- if (!this->emitDupPtr(Loc))
- return false;
return this->emitCall(DtorFunc, 0, Loc);
}
/// When calling this, we have a pointer of the local-to-destroy
/// on the stack.
/// Emit destruction of record types (or arrays of record types).
template <class Emitter>
-bool Compiler<Emitter>::emitDestruction(const Descriptor *Desc,
- SourceInfo Loc) {
+bool Compiler<Emitter>::emitDestructionPop(const Descriptor *Desc,
+ SourceInfo Loc) {
assert(Desc);
- assert(!Desc->isPrimitive());
- assert(!Desc->isPrimitiveArray());
+ assert(!Desc->hasTrivialDtor());
// Arrays.
if (Desc->isArray()) {
const Descriptor *ElemDesc = Desc->ElemDesc;
assert(ElemDesc);
- // Don't need to do anything for these.
- if (ElemDesc->isPrimitiveArray())
- return true;
+ unsigned N = Desc->getNumElems();
+ if (N == 0)
+ return this->emitPopPtr(Loc);
- // If this is an array of record types, check if we need
- // to call the element destructors at all. If not, try
- // to save the work.
- if (const Record *ElemRecord = ElemDesc->ElemRecord) {
- if (const CXXDestructorDecl *Dtor = ElemRecord->getDestructor();
- !Dtor || Dtor->isTrivial())
- return true;
- }
-
- if (unsigned N = Desc->getNumElems()) {
- for (ssize_t I = N - 1; I >= 0; --I) {
- if (!this->emitConstUint64(I, Loc))
- return false;
- if (!this->emitArrayElemPtrUint64(Loc))
- return false;
- if (!this->emitDestruction(ElemDesc, Loc))
- return false;
- if (!this->emitPopPtr(Loc))
- return false;
- }
+ for (ssize_t I = N - 1; I >= 1; --I) {
+ if (!this->emitConstUint64(I, Loc))
+ return false;
+ if (!this->emitArrayElemPtrUint64(Loc))
+ return false;
+ if (!this->emitDestructionPop(ElemDesc, Loc))
+ return false;
}
- return true;
+ // Last iteration, removes the instance pointer from the stack.
+ if (!this->emitConstUint64(0, Loc))
+ return false;
+ if (!this->emitArrayElemPtrPopUint64(Loc))
+ return false;
+ return this->emitDestructionPop(ElemDesc, Loc);
}
assert(Desc->ElemRecord);
- if (Desc->ElemRecord->isAnonymousUnion())
- return true;
-
- return this->emitRecordDestruction(Desc->ElemRecord, Loc);
+ assert(!Desc->ElemRecord->hasTrivialDtor());
+ return this->emitRecordDestructionPop(Desc->ElemRecord, Loc);
}
/// Create a dummy pointer for the given decl (or expr) and
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 475faee4d3fd..bb8c66042731 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -391,8 +391,8 @@ private:
bool emitComplexBoolCast(const Expr *E);
bool emitComplexComparison(const Expr *LHS, const Expr *RHS,
const BinaryOperator *E);
- bool emitRecordDestruction(const Record *R, SourceInfo Loc);
- bool emitDestruction(const Descriptor *Desc, SourceInfo Loc);
+ bool emitRecordDestructionPop(const Record *R, SourceInfo Loc);
+ bool emitDestructionPop(const Descriptor *Desc, SourceInfo Loc);
bool emitDummyPtr(const DeclTy &D, const Expr *E);
bool emitFloat(const APFloat &F, const Expr *E);
unsigned collectBaseOffset(const QualType BaseType,
@@ -587,11 +587,9 @@ public:
if (!this->Ctx->emitGetPtrLocal(Local.Offset, E))
return false;
- if (!this->Ctx->emitDestruction(Local.Desc, Local.Desc->getLoc()))
+ if (!this->Ctx->emitDestructionPop(Local.Desc, Local.Desc->getLoc()))
return false;
- if (!this->Ctx->emitPopPtr(E))
- return false;
removeIfStoredOpaqueValue(Local);
}
return true;
diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp
index 36eb7607e70b..859899668146 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -91,7 +91,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
#endif
}
- Result = Res.toAPValue();
+ Result = Res.stealAPValue();
return true;
}
@@ -121,7 +121,7 @@ bool Context::evaluate(State &Parent, const Expr *E, APValue &Result,
#endif
}
- Result = Res.toAPValue();
+ Result = Res.stealAPValue();
return true;
}
@@ -153,7 +153,7 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
#endif
}
- Result = Res.toAPValue();
+ Result = Res.stealAPValue();
return true;
}
@@ -364,8 +364,7 @@ OptPrimType Context::classify(QualType T) const {
return integralTypeToPrimTypeU(BT->getNumBits());
}
- if (const auto *ET = T->getAs<EnumType>()) {
- const auto *D = ET->getOriginalDecl()->getDefinitionOrSelf();
+ if (const auto *D = T->getAsEnumDecl()) {
if (!D->isComplete())
return std::nullopt;
return classify(D->getIntegerType());
diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp
index 9ecc7b673cf2..0a819599287e 100644
--- a/clang/lib/AST/ByteCode/Descriptor.cpp
+++ b/clang/lib/AST/ByteCode/Descriptor.cpp
@@ -50,14 +50,6 @@ static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {
}
template <typename T>
-static void moveTy(Block *, std::byte *Src, std::byte *Dst,
- const Descriptor *) {
- auto *SrcPtr = reinterpret_cast<T *>(Src);
- auto *DstPtr = reinterpret_cast<T *>(Dst);
- new (DstPtr) T(std::move(*SrcPtr));
-}
-
-template <typename T>
static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
const Descriptor *D) {
new (Ptr) InitMapPtr(std::nullopt);
@@ -85,28 +77,6 @@ static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
}
}
-template <typename T>
-static void moveArrayTy(Block *, std::byte *Src, std::byte *Dst,
- const Descriptor *D) {
- InitMapPtr &SrcIMP = *reinterpret_cast<InitMapPtr *>(Src);
- if (SrcIMP) {
- // We only ever invoke the moveFunc when moving block contents to a
- // DeadBlock. DeadBlocks don't need InitMaps, so we destroy them here.
- SrcIMP = std::nullopt;
- }
- Src += sizeof(InitMapPtr);
- Dst += sizeof(InitMapPtr);
- if constexpr (!needsCtor<T>()) {
- std::memcpy(Dst, Src, D->getNumElems() * D->getElemSize());
- } else {
- for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
- auto *SrcPtr = &reinterpret_cast<T *>(Src)[I];
- auto *DstPtr = &reinterpret_cast<T *>(Dst)[I];
- new (DstPtr) T(std::move(*SrcPtr));
- }
- }
-}
-
static void ctorArrayDesc(Block *B, std::byte *Ptr, bool IsConst,
bool IsMutable, bool IsVolatile, bool IsActive,
bool InUnion, const Descriptor *D) {
@@ -144,12 +114,14 @@ static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D) {
D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
unsigned ElemOffset = 0;
- for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
+ auto Dtor = D->ElemDesc->DtorFn;
+ assert(Dtor &&
+ "a composite array without an elem dtor shouldn't have a dtor itself");
+ for (unsigned I = 0; I != NumElems; ++I, ElemOffset += ElemSize) {
auto *ElemPtr = Ptr + ElemOffset;
auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);
- if (auto Fn = D->ElemDesc->DtorFn)
- Fn(B, ElemLoc, D->ElemDesc);
+ Dtor(B, ElemLoc, D->ElemDesc);
}
}
@@ -246,34 +218,59 @@ static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {
destroyBase(B, Ptr, F.Desc, F.Offset);
}
-static BlockCtorFn getCtorPrim(PrimType Type) {
- // Floating types are special. They are primitives, but need their
- // constructor called.
- if (Type == PT_Float)
+/// Whether a record needs its descriptor dtor function called.
+static bool needsRecordDtor(const Record *R) {
+ for (const auto &B : R->bases()) {
+ if (B.Desc->DtorFn)
+ return true;
+ }
+
+ for (const auto &F : R->fields()) {
+ if (F.Desc->DtorFn)
+ return true;
+ }
+
+ for (const auto &V : R->virtual_bases()) {
+ if (V.Desc->DtorFn)
+ return true;
+ }
+ return false;
+}
+
+static BlockCtorFn getCtorPrim(PrimType T) {
+ switch (T) {
+ case PT_Float:
return ctorTy<PrimConv<PT_Float>::T>;
- if (Type == PT_IntAP)
+ case PT_IntAP:
return ctorTy<PrimConv<PT_IntAP>::T>;
- if (Type == PT_IntAPS)
+ case PT_IntAPS:
return ctorTy<PrimConv<PT_IntAPS>::T>;
- if (Type == PT_MemberPtr)
+ case PT_Ptr:
+ return ctorTy<PrimConv<PT_Ptr>::T>;
+ case PT_MemberPtr:
return ctorTy<PrimConv<PT_MemberPtr>::T>;
-
- COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);
+ default:
+ return nullptr;
+ }
+ llvm_unreachable("Unhandled PrimType");
}
-static BlockDtorFn getDtorPrim(PrimType Type) {
- // Floating types are special. They are primitives, but need their
- // destructor called, since they might allocate memory.
- if (Type == PT_Float)
+static BlockDtorFn getDtorPrim(PrimType T) {
+ switch (T) {
+ case PT_Float:
return dtorTy<PrimConv<PT_Float>::T>;
- if (Type == PT_IntAP)
+ case PT_IntAP:
return dtorTy<PrimConv<PT_IntAP>::T>;
- if (Type == PT_IntAPS)
+ case PT_IntAPS:
return dtorTy<PrimConv<PT_IntAPS>::T>;
- if (Type == PT_MemberPtr)
+ case PT_Ptr:
+ return dtorTy<PrimConv<PT_Ptr>::T>;
+ case PT_MemberPtr:
return dtorTy<PrimConv<PT_MemberPtr>::T>;
-
- COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);
+ default:
+ return nullptr;
+ }
+ llvm_unreachable("Unhandled PrimType");
}
static BlockCtorFn getCtorArrayPrim(PrimType Type) {
@@ -336,7 +333,7 @@ Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy,
AllocSize(std::max<size_t>(alignof(void *), Size) + MDSize),
ElemDesc(Elem), IsConst(IsConst), IsMutable(IsMutable),
IsTemporary(IsTemporary), IsArray(true), CtorFn(ctorArrayDesc),
- DtorFn(dtorArrayDesc) {
+ DtorFn(Elem->DtorFn ? dtorArrayDesc : nullptr) {
assert(Source && "Missing source");
}
@@ -347,7 +344,7 @@ Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
Size(UnknownSizeMark), MDSize(MD.value_or(0)),
AllocSize(MDSize + alignof(void *)), ElemDesc(Elem), IsConst(true),
IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
- CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc) {
+ CtorFn(ctorArrayDesc), DtorFn(Elem->DtorFn ? dtorArrayDesc : nullptr) {
assert(Source && "Missing source");
}
@@ -359,7 +356,7 @@ Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD,
Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),
ElemRecord(R), IsConst(IsConst), IsMutable(IsMutable),
IsTemporary(IsTemporary), IsVolatile(IsVolatile), CtorFn(ctorRecord),
- DtorFn(dtorRecord) {
+ DtorFn(needsRecordDtor(R) ? dtorRecord : nullptr) {
assert(Source && "Missing source");
}
@@ -460,8 +457,7 @@ bool Descriptor::hasTrivialDtor() const {
if (isRecord()) {
assert(ElemRecord);
- const CXXDestructorDecl *Dtor = ElemRecord->getDestructor();
- return !Dtor || Dtor->isTrivial();
+ return ElemRecord->hasTrivialDtor();
}
if (!ElemDesc)
diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp
index 58e6d1a722af..ab3b9f7c3b1d 100644
--- a/clang/lib/AST/ByteCode/Disasm.cpp
+++ b/clang/lib/AST/ByteCode/Disasm.cpp
@@ -44,7 +44,20 @@ inline static std::string printArg(Program &P, CodePtr &OpPC) {
std::string Result;
llvm::raw_string_ostream SS(Result);
auto Arg = OpPC.read<T>();
- SS << Arg;
+ // Make sure we print the integral value of chars.
+ if constexpr (std::is_integral_v<T>) {
+ if constexpr (sizeof(T) == 1) {
+ if constexpr (std::is_signed_v<T>)
+ SS << static_cast<int32_t>(Arg);
+ else
+ SS << static_cast<uint32_t>(Arg);
+ } else {
+ SS << Arg;
+ }
+ } else {
+ SS << Arg;
+ }
+
return Result;
}
}
@@ -549,41 +562,17 @@ LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
}
LLVM_DUMP_METHOD void EvaluationResult::dump() const {
- assert(Ctx);
auto &OS = llvm::errs();
- const ASTContext &ASTCtx = Ctx->getASTContext();
- switch (Kind) {
- case Empty:
+ if (empty()) {
OS << "Empty\n";
- break;
- case RValue:
- OS << "RValue: ";
- std::get<APValue>(Value).dump(OS, ASTCtx);
- break;
- case LValue: {
- assert(Source);
- QualType SourceType;
- if (const auto *D = dyn_cast<const Decl *>(Source)) {
- if (const auto *VD = dyn_cast<ValueDecl>(D))
- SourceType = VD->getType();
- } else if (const auto *E = dyn_cast<const Expr *>(Source)) {
- SourceType = E->getType();
- }
-
- OS << "LValue: ";
- if (const auto *P = std::get_if<Pointer>(&Value))
- P->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);
- else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
- FP->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);
- OS << "\n";
- break;
- }
- case Invalid:
+ } else if (isInvalid()) {
OS << "Invalid\n";
- break;
- case Valid:
- OS << "Valid\n";
- break;
+ } else {
+ OS << "Value: ";
+#ifndef NDEBUG
+ assert(Ctx);
+ Value.dump(OS, Ctx->getASTContext());
+#endif
}
}
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp
index 1ebadae811bd..d0aa8d8df236 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.cpp
+++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp
@@ -184,7 +184,7 @@ template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
return true;
using T = typename PrimConv<OpType>::T;
- EvalResult.setValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext()));
+ EvalResult.takeValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext()));
return true;
}
@@ -195,7 +195,7 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (Ptr.isFunctionPointer()) {
- EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext()));
+ EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));
return true;
}
@@ -213,6 +213,9 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
if (!Ptr.isZero() && !Ptr.isDereferencable())
return false;
+ if (Ptr.pointsToStringLiteral() && Ptr.isArrayRoot())
+ return false;
+
if (!Ptr.isZero() && !CheckFinalLoad(S, OpPC, Ptr))
return false;
@@ -224,7 +227,7 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
if (std::optional<APValue> V =
Ptr.toRValue(Ctx, EvalResult.getSourceType())) {
- EvalResult.setValue(*V);
+ EvalResult.takeValue(std::move(*V));
} else {
return false;
}
@@ -233,14 +236,14 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
// the result, even if the pointer is dead.
// This will later be diagnosed by CheckLValueConstantExpression.
if (Ptr.isBlockPointer() && !Ptr.block()->isStatic()) {
- EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext()));
+ EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));
return true;
}
if (!Ptr.isLive() && !Ptr.isTemporary())
return false;
- EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext()));
+ EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));
}
return true;
@@ -261,7 +264,7 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
if (std::optional<APValue> APV =
Ptr.toRValue(S.getASTContext(), EvalResult.getSourceType())) {
- EvalResult.setValue(*APV);
+ EvalResult.takeValue(std::move(*APV));
return true;
}
@@ -328,7 +331,7 @@ bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) {
/// This is what we do here.
void EvalEmitter::updateGlobalTemporaries() {
for (const auto &[E, Temp] : S.SeenGlobalTemporaries) {
- if (std::optional<unsigned> GlobalIndex = P.getGlobal(E)) {
+ if (UnsignedOrNone GlobalIndex = P.getGlobal(E)) {
const Pointer &Ptr = P.getPtrGlobal(*GlobalIndex);
APValue *Cached = Temp->getOrCreateValue(true);
diff --git a/clang/lib/AST/ByteCode/EvaluationResult.cpp b/clang/lib/AST/ByteCode/EvaluationResult.cpp
index b11531f4296a..ba818788d702 100644
--- a/clang/lib/AST/ByteCode/EvaluationResult.cpp
+++ b/clang/lib/AST/ByteCode/EvaluationResult.cpp
@@ -8,6 +8,7 @@
#include "EvaluationResult.h"
#include "InterpState.h"
+#include "Pointer.h"
#include "Record.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
@@ -16,41 +17,6 @@
namespace clang {
namespace interp {
-APValue EvaluationResult::toAPValue() const {
- assert(!empty());
- switch (Kind) {
- case LValue:
- // Either a pointer or a function pointer.
- if (const auto *P = std::get_if<Pointer>(&Value))
- return P->toAPValue(Ctx->getASTContext());
- else if (const auto *FP = std::get_if<FunctionPointer>(&Value))
- return FP->toAPValue(Ctx->getASTContext());
- else
- llvm_unreachable("Unhandled LValue type");
- break;
- case RValue:
- return std::get<APValue>(Value);
- case Valid:
- return APValue();
- default:
- llvm_unreachable("Unhandled result kind?");
- }
-}
-
-std::optional<APValue> EvaluationResult::toRValue() const {
- if (Kind == RValue)
- return toAPValue();
-
- assert(Kind == LValue);
-
- // We have a pointer and want an RValue.
- if (const auto *P = std::get_if<Pointer>(&Value))
- return P->toRValue(*Ctx, getSourceType());
- else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
- return FP->toAPValue(Ctx->getASTContext());
- llvm_unreachable("Unhandled lvalue kind");
-}
-
static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc,
const FieldDecl *SubObjDecl) {
assert(SubObjDecl && "Subobject declaration does not exist");
@@ -66,8 +32,12 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
const Pointer &BasePtr,
const ConstantArrayType *CAT) {
- bool Result = true;
size_t NumElems = CAT->getZExtSize();
+
+ if (NumElems == 0)
+ return true;
+
+ bool Result = true;
QualType ElemType = CAT->getElementType();
if (ElemType->isRecordType()) {
@@ -82,8 +52,18 @@ static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT);
}
} else {
+ // Primitive arrays.
+ if (S.getContext().canClassify(ElemType)) {
+ if (BasePtr.allElementsInitialized()) {
+ return true;
+ } else {
+ DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
+ return false;
+ }
+ }
+
for (size_t I = 0; I != NumElems; ++I) {
- if (!BasePtr.atIndex(I).isInitialized()) {
+ if (!BasePtr.isElementInitialized(I)) {
DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
Result = false;
}
@@ -178,8 +158,8 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S,
static void collectBlocks(const Pointer &Ptr,
llvm::SetVector<const Block *> &Blocks) {
auto isUsefulPtr = [](const Pointer &P) -> bool {
- return P.isLive() && !P.isZero() && !P.isDummy() && P.isDereferencable() &&
- !P.isUnknownSizeArray() && !P.isOnePastEnd();
+ return P.isLive() && P.isBlockPointer() && !P.isZero() && !P.isDummy() &&
+ P.isDereferencable() && !P.isUnknownSizeArray() && !P.isOnePastEnd();
};
if (!isUsefulPtr(Ptr))
diff --git a/clang/lib/AST/ByteCode/EvaluationResult.h b/clang/lib/AST/ByteCode/EvaluationResult.h
index 3b6c65eff1ef..c296cc98ca37 100644
--- a/clang/lib/AST/ByteCode/EvaluationResult.h
+++ b/clang/lib/AST/ByteCode/EvaluationResult.h
@@ -9,23 +9,22 @@
#ifndef LLVM_CLANG_AST_INTERP_EVALUATION_RESULT_H
#define LLVM_CLANG_AST_INTERP_EVALUATION_RESULT_H
-#include "FunctionPointer.h"
-#include "Pointer.h"
#include "clang/AST/APValue.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
-#include <optional>
-#include <variant>
namespace clang {
namespace interp {
class EvalEmitter;
class Context;
+class Pointer;
+class SourceInfo;
+class InterpState;
/// Defines the result of an evaluation.
///
-/// The result might be in different forms--one of the pointer types,
-/// an APValue, or nothing.
+/// The Kind defined if the evaluation was invalid, valid (but empty, e.g. for
+/// void expressions) or if we have a valid evaluation result.
///
/// We use this class to inspect and diagnose the result, as well as
/// convert it to the requested form.
@@ -33,8 +32,6 @@ class EvaluationResult final {
public:
enum ResultKind {
Empty, // Initial state.
- LValue, // Result is an lvalue/pointer.
- RValue, // Result is an rvalue.
Invalid, // Result is invalid.
Valid, // Result is valid and empty.
};
@@ -42,29 +39,18 @@ public:
using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;
private:
+#ifndef NDEBUG
const Context *Ctx = nullptr;
- std::variant<std::monostate, Pointer, FunctionPointer, APValue> Value;
+#endif
+ APValue Value;
ResultKind Kind = Empty;
- DeclTy Source = nullptr; // Currently only needed for dump().
-
- EvaluationResult(ResultKind Kind) : Kind(Kind) {
- // Leave everything empty. Can be used as an
- // error marker or for void return values.
- assert(Kind == Valid || Kind == Invalid);
- }
+ DeclTy Source = nullptr;
void setSource(DeclTy D) { Source = D; }
- void setValue(const APValue &V) {
- // V could still be an LValue.
+ void takeValue(APValue &&V) {
assert(empty());
Value = std::move(V);
- Kind = RValue;
- }
- void setFunctionPointer(const FunctionPointer &P) {
- assert(empty());
- Value = P;
- Kind = LValue;
}
void setInvalid() {
// We are NOT asserting empty() here, since setting it to invalid
@@ -77,22 +63,23 @@ private:
}
public:
+#ifndef NDEBUG
EvaluationResult(const Context *Ctx) : Ctx(Ctx) {}
+#else
+ EvaluationResult(const Context *Ctx) {}
+#endif
bool empty() const { return Kind == Empty; }
bool isInvalid() const { return Kind == Invalid; }
- bool isLValue() const { return Kind == LValue; }
- bool isRValue() const { return Kind == RValue; }
- bool isPointer() const { return std::holds_alternative<Pointer>(Value); }
- /// Returns an APValue for the evaluation result. The returned
- /// APValue might be an LValue or RValue.
- APValue toAPValue() const;
+ /// Returns an APValue for the evaluation result.
+ APValue toAPValue() const {
+ assert(!empty());
+ assert(!isInvalid());
+ return Value;
+ }
- /// If the result is an LValue, convert that to an RValue
- /// and return it. This may fail, e.g. if the result is an
- /// LValue and we can't read from it.
- std::optional<APValue> toRValue() const;
+ APValue stealAPValue() { return std::move(Value); }
/// Check that all subobjects of the given pointer have been initialized.
bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const;
@@ -105,7 +92,7 @@ public:
if (const auto *D =
dyn_cast_if_present<ValueDecl>(Source.dyn_cast<const Decl *>()))
return D->getType();
- else if (const auto *E = Source.dyn_cast<const Expr *>())
+ if (const auto *E = Source.dyn_cast<const Expr *>())
return E->getType();
return QualType();
}
diff --git a/clang/lib/AST/ByteCode/Integral.h b/clang/lib/AST/ByteCode/Integral.h
index af5cd2d13ecc..131802439f0c 100644
--- a/clang/lib/AST/ByteCode/Integral.h
+++ b/clang/lib/AST/ByteCode/Integral.h
@@ -318,6 +318,11 @@ private:
template <typename T> static bool CheckMulUB(T A, T B, T &R) {
if constexpr (std::is_signed_v<T>) {
return llvm::MulOverflow<T>(A, B, R);
+ } else if constexpr (sizeof(T) < sizeof(int)) {
+ // Silly integer promotion rules will convert both A and B to int,
+ // even it T is unsigned. Prevent that by manually casting to uint first.
+ R = static_cast<T>(static_cast<unsigned>(A) * static_cast<unsigned>(B));
+ return false;
} else {
R = A * B;
return false;
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 796c24e9071e..b64ed8c2fb49 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -792,6 +792,7 @@ bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B) {
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK) {
+ // Block pointers are the only ones we can actually read from.
if (!Ptr.isBlockPointer()) {
if (Ptr.isZero()) {
const auto &Src = S.Current->getSource(OpPC);
@@ -804,7 +805,6 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
}
- // Block pointers are the only ones we can actually read from.
if (!Ptr.block()->isAccessible()) {
if (!CheckLive(S, OpPC, Ptr, AK))
return false;
@@ -812,8 +812,7 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
if (!CheckDummy(S, OpPC, Ptr.block(), AK))
return false;
- if (!CheckWeak(S, OpPC, Ptr.block()))
- return false;
+ return CheckWeak(S, OpPC, Ptr.block());
}
if (!CheckConstant(S, OpPC, Ptr))
@@ -870,7 +869,7 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
}
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
- if (!Ptr.isBlockPointer())
+ if (!Ptr.isBlockPointer() || Ptr.isZero())
return false;
if (!Ptr.block()->isAccessible()) {
@@ -1207,17 +1206,15 @@ static bool runRecordDestructor(InterpState &S, CodePtr OpPC,
}
// Destructor of this record.
- if (const CXXDestructorDecl *Dtor = R->getDestructor();
- Dtor && !Dtor->isTrivial()) {
- const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);
- if (!DtorFunc)
- return false;
+ const CXXDestructorDecl *Dtor = R->getDestructor();
+ assert(Dtor);
+ assert(!Dtor->isTrivial());
+ const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);
+ if (!DtorFunc)
+ return false;
- S.Stk.push<Pointer>(BasePtr);
- if (!Call(S, OpPC, DtorFunc, 0))
- return false;
- }
- return true;
+ S.Stk.push<Pointer>(BasePtr);
+ return Call(S, OpPC, DtorFunc, 0);
}
static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) {
@@ -1229,6 +1226,9 @@ static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) {
assert(Desc->isRecord() || Desc->isCompositeArray());
+ if (Desc->hasTrivialDtor())
+ return true;
+
if (Desc->isCompositeArray()) {
unsigned N = Desc->getNumElems();
if (N == 0)
@@ -2117,8 +2117,8 @@ bool DiagTypeid(InterpState &S, CodePtr OpPC) {
bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,
const Pointer &RHS) {
- unsigned LHSOffset = LHS.getIndex();
- unsigned RHSOffset = RHS.getIndex();
+ unsigned LHSOffset = LHS.isOnePastEnd() ? LHS.getNumElems() : LHS.getIndex();
+ unsigned RHSOffset = RHS.isOnePastEnd() ? RHS.getNumElems() : RHS.getIndex();
unsigned LHSLength = (LHS.getNumElems() - 1) * LHS.elemSize();
unsigned RHSLength = (RHS.getNumElems() - 1) * RHS.elemSize();
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 92e60b6b88e6..2da220237803 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -3490,7 +3490,15 @@ inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
S.Stk.push<Pointer>(0, nullptr);
return true;
}
- assert(NumElements.isPositive());
+ if (NumElements.isNegative()) {
+ if (!IsNoThrow) {
+ S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_negative)
+ << NumElements.toDiagnosticString(S.getASTContext());
+ return false;
+ }
+ S.Stk.push<Pointer>(0, nullptr);
+ return true;
+ }
if (!CheckArraySize(S, OpPC, static_cast<uint64_t>(NumElements)))
return false;
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 2e28814abfdd..d418e0ac5d09 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -141,6 +141,22 @@ static void diagnoseNonConstexprBuiltin(InterpState &S, CodePtr OpPC,
S.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
}
+static llvm::APSInt convertBoolVectorToInt(const Pointer &Val) {
+ assert(Val.getFieldDesc()->isPrimitiveArray() &&
+ Val.getFieldDesc()->getElemQualType()->isBooleanType() &&
+ "Not a boolean vector");
+ unsigned NumElems = Val.getNumElems();
+
+ // Each element is one bit, so create an integer with NumElts bits.
+ llvm::APSInt Result(NumElems, 0);
+ for (unsigned I = 0; I != NumElems; ++I) {
+ if (Val.elem<bool>(I))
+ Result.setBit(I);
+ }
+
+ return Result;
+}
+
static bool interp__builtin_is_constant_evaluated(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call) {
@@ -643,8 +659,14 @@ static bool interp__builtin_abs(InterpState &S, CodePtr OpPC,
static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call) {
- PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
- APSInt Val = popToAPSInt(S.Stk, ArgT);
+ APSInt Val;
+ if (Call->getArg(0)->getType()->isExtVectorBoolType()) {
+ const Pointer &Arg = S.Stk.pop<Pointer>();
+ Val = convertBoolVectorToInt(Arg);
+ } else {
+ PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
+ Val = popToAPSInt(S.Stk, ArgT);
+ }
pushInteger(S, Val.popcount(), Call->getType());
return true;
}
@@ -940,8 +962,14 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
PrimType FallbackT = *S.getContext().classify(Call->getArg(1));
Fallback = popToAPSInt(S.Stk, FallbackT);
}
- PrimType ValT = *S.getContext().classify(Call->getArg(0));
- const APSInt &Val = popToAPSInt(S.Stk, ValT);
+ APSInt Val;
+ if (Call->getArg(0)->getType()->isExtVectorBoolType()) {
+ const Pointer &Arg = S.Stk.pop<Pointer>();
+ Val = convertBoolVectorToInt(Arg);
+ } else {
+ PrimType ValT = *S.getContext().classify(Call->getArg(0));
+ Val = popToAPSInt(S.Stk, ValT);
+ }
// When the argument is 0, the result of GCC builtins is undefined, whereas
// for Microsoft intrinsics, the result is the bit-width of the argument.
@@ -971,8 +999,14 @@ static bool interp__builtin_ctz(InterpState &S, CodePtr OpPC,
PrimType FallbackT = *S.getContext().classify(Call->getArg(1));
Fallback = popToAPSInt(S.Stk, FallbackT);
}
- PrimType ValT = *S.getContext().classify(Call->getArg(0));
- const APSInt &Val = popToAPSInt(S.Stk, ValT);
+ APSInt Val;
+ if (Call->getArg(0)->getType()->isExtVectorBoolType()) {
+ const Pointer &Arg = S.Stk.pop<Pointer>();
+ Val = convertBoolVectorToInt(Arg);
+ } else {
+ PrimType ValT = *S.getContext().classify(Call->getArg(0));
+ Val = popToAPSInt(S.Stk, ValT);
+ }
if (Val == 0) {
if (Fallback) {
@@ -2505,12 +2539,8 @@ static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC,
}
// Check if we're currently running an initializer.
- for (InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) {
- if (const Function *F = Frame->getFunction();
- F && F->isConstructor() && Frame->getThis().block() == Ptr.block()) {
- return Error(2);
- }
- }
+ if (llvm::is_contained(S.InitializingBlocks, Ptr.block()))
+ return Error(2);
if (S.EvaluatingDecl && Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl)
return Error(2);
@@ -2518,9 +2548,9 @@ static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC,
return true;
}
-static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC,
- const CallExpr *Call,
- unsigned BuiltinID) {
+static bool interp__builtin_elementwise_int_binop(
+ InterpState &S, CodePtr OpPC, const CallExpr *Call,
+ llvm::function_ref<APInt(const APSInt &, const APSInt &)> Fn) {
assert(Call->getNumArgs() == 2);
// Single integer case.
@@ -2530,23 +2560,39 @@ static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC,
S.Stk, *S.getContext().classify(Call->getArg(1)->getType()));
APSInt LHS = popToAPSInt(
S.Stk, *S.getContext().classify(Call->getArg(0)->getType()));
- APInt Result;
- if (BuiltinID == Builtin::BI__builtin_elementwise_add_sat) {
- Result = LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS);
- } else if (BuiltinID == Builtin::BI__builtin_elementwise_sub_sat) {
- Result = LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS);
- } else {
- llvm_unreachable("Wrong builtin ID");
- }
-
+ APInt Result = Fn(LHS, RHS);
pushInteger(S, APSInt(std::move(Result), !LHS.isSigned()), Call->getType());
return true;
}
+ const auto *VT = Call->getArg(0)->getType()->castAs<VectorType>();
+ assert(VT->getElementType()->isIntegralOrEnumerationType());
+ PrimType ElemT = *S.getContext().classify(VT->getElementType());
+ unsigned NumElems = VT->getNumElements();
+ bool DestUnsigned = Call->getType()->isUnsignedIntegerOrEnumerationType();
+
+ // Vector + Scalar case.
+ if (!Call->getArg(1)->getType()->isVectorType()) {
+ assert(Call->getArg(1)->getType()->isIntegralOrEnumerationType());
+
+ APSInt RHS = popToAPSInt(
+ S.Stk, *S.getContext().classify(Call->getArg(1)->getType()));
+ const Pointer &LHS = S.Stk.pop<Pointer>();
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+
+ for (unsigned I = 0; I != NumElems; ++I) {
+ INT_TYPE_SWITCH_NO_BOOL(ElemT, {
+ Dst.elem<T>(I) = static_cast<T>(
+ APSInt(Fn(LHS.elem<T>(I).toAPSInt(), RHS), DestUnsigned));
+ });
+ }
+ Dst.initializeAllElements();
+ return true;
+ }
+
// Vector case.
assert(Call->getArg(0)->getType()->isVectorType() &&
Call->getArg(1)->getType()->isVectorType());
- const auto *VT = Call->getArg(0)->getType()->castAs<VectorType>();
assert(VT->getElementType() ==
Call->getArg(1)->getType()->castAs<VectorType>()->getElementType());
assert(VT->getNumElements() ==
@@ -2556,46 +2602,12 @@ static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC,
const Pointer &RHS = S.Stk.pop<Pointer>();
const Pointer &LHS = S.Stk.pop<Pointer>();
const Pointer &Dst = S.Stk.peek<Pointer>();
- PrimType ElemT = *S.getContext().classify(VT->getElementType());
- unsigned NumElems = VT->getNumElements();
for (unsigned I = 0; I != NumElems; ++I) {
- APSInt Elem1;
- APSInt Elem2;
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
- Elem1 = LHS.elem<T>(I).toAPSInt();
- Elem2 = RHS.elem<T>(I).toAPSInt();
+ APSInt Elem1 = LHS.elem<T>(I).toAPSInt();
+ APSInt Elem2 = RHS.elem<T>(I).toAPSInt();
+ Dst.elem<T>(I) = static_cast<T>(APSInt(Fn(Elem1, Elem2), DestUnsigned));
});
-
- APSInt Result;
- switch (BuiltinID) {
- case Builtin::BI__builtin_elementwise_add_sat:
- Result = APSInt(Elem1.isSigned() ? Elem1.sadd_sat(Elem2)
- : Elem1.uadd_sat(Elem2),
- Call->getType()->isUnsignedIntegerOrEnumerationType());
- break;
- case Builtin::BI__builtin_elementwise_sub_sat:
- Result = APSInt(Elem1.isSigned() ? Elem1.ssub_sat(Elem2)
- : Elem1.usub_sat(Elem2),
- Call->getType()->isUnsignedIntegerOrEnumerationType());
- break;
- case clang::X86::BI__builtin_ia32_pmulhuw128:
- case clang::X86::BI__builtin_ia32_pmulhuw256:
- case clang::X86::BI__builtin_ia32_pmulhuw512:
- Result = APSInt(llvm::APIntOps::mulhu(Elem1, Elem2),
- /*isUnsigned=*/true);
- break;
- case clang::X86::BI__builtin_ia32_pmulhw128:
- case clang::X86::BI__builtin_ia32_pmulhw256:
- case clang::X86::BI__builtin_ia32_pmulhw512:
- Result = APSInt(llvm::APIntOps::mulhs(Elem1, Elem2),
- /*isUnsigned=*/false);
- break;
- default:
- llvm_unreachable("Wrong builtin ID");
- }
-
- INT_TYPE_SWITCH_NO_BOOL(ElemT,
- { Dst.elem<T>(I) = static_cast<T>(Result); });
}
Dst.initializeAllElements();
@@ -2724,8 +2736,11 @@ static bool interp__builtin_ia32_pmul(InterpState &S, CodePtr OpPC,
return true;
}
-static bool interp__builtin_elementwise_fma(InterpState &S, CodePtr OpPC,
- const CallExpr *Call) {
+static bool interp__builtin_elementwise_triop_fp(
+ InterpState &S, CodePtr OpPC, const CallExpr *Call,
+ llvm::function_ref<APFloat(const APFloat &, const APFloat &,
+ const APFloat &, llvm::RoundingMode)>
+ Fn) {
assert(Call->getNumArgs() == 3);
FPOptions FPO = Call->getFPFeaturesInEffect(S.Ctx.getLangOpts());
@@ -2744,8 +2759,7 @@ static bool interp__builtin_elementwise_fma(InterpState &S, CodePtr OpPC,
const Floating &Z = S.Stk.pop<Floating>();
const Floating &Y = S.Stk.pop<Floating>();
const Floating &X = S.Stk.pop<Floating>();
- APFloat F = X.getAPFloat();
- F.fusedMultiplyAdd(Y.getAPFloat(), Z.getAPFloat(), RM);
+ APFloat F = Fn(X.getAPFloat(), Y.getAPFloat(), Z.getAPFloat(), RM);
Floating Result = S.allocFloat(X.getSemantics());
Result.copy(F);
S.Stk.push<Floating>(Result);
@@ -2776,8 +2790,8 @@ static bool interp__builtin_elementwise_fma(InterpState &S, CodePtr OpPC,
APFloat X = VX.elem<T>(I).getAPFloat();
APFloat Y = VY.elem<T>(I).getAPFloat();
APFloat Z = VZ.elem<T>(I).getAPFloat();
- (void)X.fusedMultiplyAdd(Y, Z, RM);
- Dst.elem<Floating>(I) = Floating(X);
+ APFloat F = Fn(X, Y, Z, RM);
+ Dst.elem<Floating>(I) = Floating(F);
}
Dst.initializeAllElements();
return true;
@@ -2817,6 +2831,72 @@ static bool interp__builtin_select(InterpState &S, CodePtr OpPC,
return true;
}
+static bool interp__builtin_elementwise_triop(
+ InterpState &S, CodePtr OpPC, const CallExpr *Call,
+ llvm::function_ref<APInt(const APSInt &, const APSInt &, const APSInt &)>
+ Fn) {
+ assert(Call->getNumArgs() == 3);
+
+ QualType Arg0Type = Call->getArg(0)->getType();
+ QualType Arg1Type = Call->getArg(1)->getType();
+ QualType Arg2Type = Call->getArg(2)->getType();
+
+ // Non-vector integer types.
+ if (!Arg0Type->isVectorType()) {
+ const APSInt &Op2 = popToAPSInt(S.Stk, *S.getContext().classify(Arg2Type));
+ const APSInt &Op1 = popToAPSInt(S.Stk, *S.getContext().classify(Arg1Type));
+ const APSInt &Op0 = popToAPSInt(S.Stk, *S.getContext().classify(Arg0Type));
+ APSInt Result = APSInt(Fn(Op0, Op1, Op2), Op0.isUnsigned());
+ pushInteger(S, Result, Call->getType());
+ return true;
+ }
+
+ const auto *VecT = Arg0Type->castAs<VectorType>();
+ const PrimType &ElemT = *S.getContext().classify(VecT->getElementType());
+ unsigned NumElems = VecT->getNumElements();
+ bool DestUnsigned = Call->getType()->isUnsignedIntegerOrEnumerationType();
+
+ // Vector + Vector + Scalar case.
+ if (!Arg2Type->isVectorType()) {
+ APSInt Op2 = popToAPSInt(
+ S.Stk, *S.getContext().classify(Call->getArg(2)->getType()));
+
+ const Pointer &Op1 = S.Stk.pop<Pointer>();
+ const Pointer &Op0 = S.Stk.pop<Pointer>();
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+ for (unsigned I = 0; I != NumElems; ++I) {
+ INT_TYPE_SWITCH_NO_BOOL(ElemT, {
+ Dst.elem<T>(I) = static_cast<T>(APSInt(
+ Fn(Op0.elem<T>(I).toAPSInt(), Op1.elem<T>(I).toAPSInt(), Op2),
+ DestUnsigned));
+ });
+ }
+ Dst.initializeAllElements();
+
+ return true;
+ }
+
+ // Vector type.
+ const Pointer &Op2 = S.Stk.pop<Pointer>();
+ const Pointer &Op1 = S.Stk.pop<Pointer>();
+ const Pointer &Op0 = S.Stk.pop<Pointer>();
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+ for (unsigned I = 0; I != NumElems; ++I) {
+ APSInt Val0, Val1, Val2;
+ INT_TYPE_SWITCH_NO_BOOL(ElemT, {
+ Val0 = Op0.elem<T>(I).toAPSInt();
+ Val1 = Op1.elem<T>(I).toAPSInt();
+ Val2 = Op2.elem<T>(I).toAPSInt();
+ });
+ APSInt Result = APSInt(Fn(Val0, Val1, Val2), Val0.isUnsigned());
+ INT_TYPE_SWITCH_NO_BOOL(ElemT,
+ { Dst.elem<T>(I) = static_cast<T>(Result); });
+ }
+ Dst.initializeAllElements();
+
+ return true;
+}
+
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
uint32_t BuiltinID) {
if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID))
@@ -3229,14 +3309,139 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
return interp__builtin_is_within_lifetime(S, OpPC, Call);
case Builtin::BI__builtin_elementwise_add_sat:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) {
+ return LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS);
+ });
+
case Builtin::BI__builtin_elementwise_sub_sat:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) {
+ return LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS);
+ });
+
+ case clang::X86::BI__builtin_ia32_pavgb128:
+ case clang::X86::BI__builtin_ia32_pavgw128:
+ case clang::X86::BI__builtin_ia32_pavgb256:
+ case clang::X86::BI__builtin_ia32_pavgw256:
+ case clang::X86::BI__builtin_ia32_pavgb512:
+ case clang::X86::BI__builtin_ia32_pavgw512:
+ return interp__builtin_elementwise_int_binop(S, OpPC, Call,
+ llvm::APIntOps::avgCeilU);
+
case clang::X86::BI__builtin_ia32_pmulhuw128:
case clang::X86::BI__builtin_ia32_pmulhuw256:
case clang::X86::BI__builtin_ia32_pmulhuw512:
+ return interp__builtin_elementwise_int_binop(S, OpPC, Call,
+ llvm::APIntOps::mulhu);
+
case clang::X86::BI__builtin_ia32_pmulhw128:
case clang::X86::BI__builtin_ia32_pmulhw256:
case clang::X86::BI__builtin_ia32_pmulhw512:
- return interp__builtin_elementwise_sat(S, OpPC, Call, BuiltinID);
+ return interp__builtin_elementwise_int_binop(S, OpPC, Call,
+ llvm::APIntOps::mulhs);
+
+ case clang::X86::BI__builtin_ia32_psllv2di:
+ case clang::X86::BI__builtin_ia32_psllv4di:
+ case clang::X86::BI__builtin_ia32_psllv4si:
+ case clang::X86::BI__builtin_ia32_psllv8di:
+ case clang::X86::BI__builtin_ia32_psllv8hi:
+ case clang::X86::BI__builtin_ia32_psllv8si:
+ case clang::X86::BI__builtin_ia32_psllv16hi:
+ case clang::X86::BI__builtin_ia32_psllv16si:
+ case clang::X86::BI__builtin_ia32_psllv32hi:
+ case clang::X86::BI__builtin_ia32_psllwi128:
+ case clang::X86::BI__builtin_ia32_psllwi256:
+ case clang::X86::BI__builtin_ia32_psllwi512:
+ case clang::X86::BI__builtin_ia32_pslldi128:
+ case clang::X86::BI__builtin_ia32_pslldi256:
+ case clang::X86::BI__builtin_ia32_pslldi512:
+ case clang::X86::BI__builtin_ia32_psllqi128:
+ case clang::X86::BI__builtin_ia32_psllqi256:
+ case clang::X86::BI__builtin_ia32_psllqi512:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) {
+ if (RHS.uge(LHS.getBitWidth())) {
+ return APInt::getZero(LHS.getBitWidth());
+ }
+ return LHS.shl(RHS.getZExtValue());
+ });
+
+ case clang::X86::BI__builtin_ia32_psrav4si:
+ case clang::X86::BI__builtin_ia32_psrav8di:
+ case clang::X86::BI__builtin_ia32_psrav8hi:
+ case clang::X86::BI__builtin_ia32_psrav8si:
+ case clang::X86::BI__builtin_ia32_psrav16hi:
+ case clang::X86::BI__builtin_ia32_psrav16si:
+ case clang::X86::BI__builtin_ia32_psrav32hi:
+ case clang::X86::BI__builtin_ia32_psravq128:
+ case clang::X86::BI__builtin_ia32_psravq256:
+ case clang::X86::BI__builtin_ia32_psrawi128:
+ case clang::X86::BI__builtin_ia32_psrawi256:
+ case clang::X86::BI__builtin_ia32_psrawi512:
+ case clang::X86::BI__builtin_ia32_psradi128:
+ case clang::X86::BI__builtin_ia32_psradi256:
+ case clang::X86::BI__builtin_ia32_psradi512:
+ case clang::X86::BI__builtin_ia32_psraqi128:
+ case clang::X86::BI__builtin_ia32_psraqi256:
+ case clang::X86::BI__builtin_ia32_psraqi512:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) {
+ if (RHS.uge(LHS.getBitWidth())) {
+ return LHS.ashr(LHS.getBitWidth() - 1);
+ }
+ return LHS.ashr(RHS.getZExtValue());
+ });
+
+ case clang::X86::BI__builtin_ia32_psrlv2di:
+ case clang::X86::BI__builtin_ia32_psrlv4di:
+ case clang::X86::BI__builtin_ia32_psrlv4si:
+ case clang::X86::BI__builtin_ia32_psrlv8di:
+ case clang::X86::BI__builtin_ia32_psrlv8hi:
+ case clang::X86::BI__builtin_ia32_psrlv8si:
+ case clang::X86::BI__builtin_ia32_psrlv16hi:
+ case clang::X86::BI__builtin_ia32_psrlv16si:
+ case clang::X86::BI__builtin_ia32_psrlv32hi:
+ case clang::X86::BI__builtin_ia32_psrlwi128:
+ case clang::X86::BI__builtin_ia32_psrlwi256:
+ case clang::X86::BI__builtin_ia32_psrlwi512:
+ case clang::X86::BI__builtin_ia32_psrldi128:
+ case clang::X86::BI__builtin_ia32_psrldi256:
+ case clang::X86::BI__builtin_ia32_psrldi512:
+ case clang::X86::BI__builtin_ia32_psrlqi128:
+ case clang::X86::BI__builtin_ia32_psrlqi256:
+ case clang::X86::BI__builtin_ia32_psrlqi512:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) {
+ if (RHS.uge(LHS.getBitWidth())) {
+ return APInt::getZero(LHS.getBitWidth());
+ }
+ return LHS.lshr(RHS.getZExtValue());
+ });
+
+ case clang::X86::BI__builtin_ia32_vprotbi:
+ case clang::X86::BI__builtin_ia32_vprotdi:
+ case clang::X86::BI__builtin_ia32_vprotqi:
+ case clang::X86::BI__builtin_ia32_vprotwi:
+ case clang::X86::BI__builtin_ia32_prold128:
+ case clang::X86::BI__builtin_ia32_prold256:
+ case clang::X86::BI__builtin_ia32_prold512:
+ case clang::X86::BI__builtin_ia32_prolq128:
+ case clang::X86::BI__builtin_ia32_prolq256:
+ case clang::X86::BI__builtin_ia32_prolq512:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call,
+ [](const APSInt &LHS, const APSInt &RHS) { return LHS.rotl(RHS); });
+
+ case clang::X86::BI__builtin_ia32_prord128:
+ case clang::X86::BI__builtin_ia32_prord256:
+ case clang::X86::BI__builtin_ia32_prord512:
+ case clang::X86::BI__builtin_ia32_prorq128:
+ case clang::X86::BI__builtin_ia32_prorq256:
+ case clang::X86::BI__builtin_ia32_prorq512:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call,
+ [](const APSInt &LHS, const APSInt &RHS) { return LHS.rotr(RHS); });
case Builtin::BI__builtin_elementwise_max:
case Builtin::BI__builtin_elementwise_min:
@@ -3251,7 +3456,61 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
return interp__builtin_ia32_pmul(S, OpPC, Call, BuiltinID);
case Builtin::BI__builtin_elementwise_fma:
- return interp__builtin_elementwise_fma(S, OpPC, Call);
+ return interp__builtin_elementwise_triop_fp(
+ S, OpPC, Call,
+ [](const APFloat &X, const APFloat &Y, const APFloat &Z,
+ llvm::RoundingMode RM) {
+ APFloat F = X;
+ F.fusedMultiplyAdd(Y, Z, RM);
+ return F;
+ });
+
+ case X86::BI__builtin_ia32_vpshldd128:
+ case X86::BI__builtin_ia32_vpshldd256:
+ case X86::BI__builtin_ia32_vpshldd512:
+ case X86::BI__builtin_ia32_vpshldq128:
+ case X86::BI__builtin_ia32_vpshldq256:
+ case X86::BI__builtin_ia32_vpshldq512:
+ case X86::BI__builtin_ia32_vpshldw128:
+ case X86::BI__builtin_ia32_vpshldw256:
+ case X86::BI__builtin_ia32_vpshldw512:
+ return interp__builtin_elementwise_triop(
+ S, OpPC, Call,
+ [](const APSInt &Hi, const APSInt &Lo, const APSInt &Amt) {
+ return llvm::APIntOps::fshl(Hi, Lo, Amt);
+ });
+
+ case X86::BI__builtin_ia32_vpshrdd128:
+ case X86::BI__builtin_ia32_vpshrdd256:
+ case X86::BI__builtin_ia32_vpshrdd512:
+ case X86::BI__builtin_ia32_vpshrdq128:
+ case X86::BI__builtin_ia32_vpshrdq256:
+ case X86::BI__builtin_ia32_vpshrdq512:
+ case X86::BI__builtin_ia32_vpshrdw128:
+ case X86::BI__builtin_ia32_vpshrdw256:
+ case X86::BI__builtin_ia32_vpshrdw512:
+ // NOTE: Reversed Hi/Lo operands.
+ return interp__builtin_elementwise_triop(
+ S, OpPC, Call,
+ [](const APSInt &Lo, const APSInt &Hi, const APSInt &Amt) {
+ return llvm::APIntOps::fshr(Hi, Lo, Amt);
+ });
+
+ case clang::X86::BI__builtin_ia32_blendvpd:
+ case clang::X86::BI__builtin_ia32_blendvpd256:
+ case clang::X86::BI__builtin_ia32_blendvps:
+ case clang::X86::BI__builtin_ia32_blendvps256:
+ return interp__builtin_elementwise_triop_fp(
+ S, OpPC, Call,
+ [](const APFloat &F, const APFloat &T, const APFloat &C,
+ llvm::RoundingMode) { return C.isNegative() ? T : F; });
+
+ case clang::X86::BI__builtin_ia32_pblendvb128:
+ case clang::X86::BI__builtin_ia32_pblendvb256:
+ return interp__builtin_elementwise_triop(
+ S, OpPC, Call, [](const APSInt &F, const APSInt &T, const APSInt &C) {
+ return ((APInt)C).isNegative() ? T : F;
+ });
case X86::BI__builtin_ia32_selectb_128:
case X86::BI__builtin_ia32_selectb_256:
@@ -3279,6 +3538,13 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
case X86::BI__builtin_ia32_selectpd_512:
return interp__builtin_select(S, OpPC, Call);
+ case Builtin::BI__builtin_elementwise_fshl:
+ return interp__builtin_elementwise_triop(S, OpPC, Call,
+ llvm::APIntOps::fshl);
+ case Builtin::BI__builtin_elementwise_fshr:
+ return interp__builtin_elementwise_triop(S, OpPC, Call,
+ llvm::APIntOps::fshr);
+
default:
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_invalid_subexpr_in_const_expr)
@@ -3303,11 +3569,8 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
switch (Node.getKind()) {
case OffsetOfNode::Field: {
const FieldDecl *MemberDecl = Node.getField();
- const RecordType *RT = CurrentType->getAs<RecordType>();
- if (!RT)
- return false;
- const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
- if (RD->isInvalidDecl())
+ const auto *RD = CurrentType->getAsRecordDecl();
+ if (!RD || RD->isInvalidDecl())
return false;
const ASTRecordLayout &RL = S.getASTContext().getASTRecordLayout(RD);
unsigned FieldIndex = MemberDecl->getFieldIndex();
@@ -3336,23 +3599,19 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
return false;
// Find the layout of the class whose base we are looking into.
- const RecordType *RT = CurrentType->getAs<RecordType>();
- if (!RT)
- return false;
- const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
- if (RD->isInvalidDecl())
+ const auto *RD = CurrentType->getAsCXXRecordDecl();
+ if (!RD || RD->isInvalidDecl())
return false;
const ASTRecordLayout &RL = S.getASTContext().getASTRecordLayout(RD);
// Find the base class itself.
CurrentType = BaseSpec->getType();
- const RecordType *BaseRT = CurrentType->getAs<RecordType>();
- if (!BaseRT)
+ const auto *BaseRD = CurrentType->getAsCXXRecordDecl();
+ if (!BaseRD)
return false;
// Add the offset to the base.
- Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(
- BaseRT->getOriginalDecl()->getDefinitionOrSelf()));
+ Result += RL.getBaseClassOffset(BaseRD);
break;
}
case OffsetOfNode::Identifier:
diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp
index 18400b10c47b..b9dc2aed2311 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.cpp
+++ b/clang/lib/AST/ByteCode/InterpFrame.cpp
@@ -195,12 +195,6 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
OS << ")";
}
-Frame *InterpFrame::getCaller() const {
- if (Caller->Caller)
- return Caller;
- return S.getSplitFrame();
-}
-
SourceRange InterpFrame::getCallRange() const {
if (!Caller->Func) {
if (SourceRange NullRange = S.getRange(nullptr, {}); NullRange.isValid())
diff --git a/clang/lib/AST/ByteCode/InterpFrame.h b/clang/lib/AST/ByteCode/InterpFrame.h
index 4be53911b615..cf4d27d341e9 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.h
+++ b/clang/lib/AST/ByteCode/InterpFrame.h
@@ -59,7 +59,7 @@ public:
void describe(llvm::raw_ostream &OS) const override;
/// Returns the parent frame object.
- Frame *getCaller() const override;
+ Frame *getCaller() const override { return Caller; }
/// Returns the location of the call to the frame.
SourceRange getCallRange() const override;
diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp
index f89967759ff9..1ec4191d2ba3 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -20,19 +20,29 @@ using namespace clang::interp;
InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
Context &Ctx, SourceMapper *M)
: Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), BottomFrame(*this),
- Current(&BottomFrame) {}
+ Current(&BottomFrame) {
+ InConstantContext = Parent.InConstantContext;
+ CheckingPotentialConstantExpression =
+ Parent.CheckingPotentialConstantExpression;
+ CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior;
+}
InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
Context &Ctx, const Function *Func)
: Parent(Parent), M(nullptr), P(P), Stk(Stk), Ctx(Ctx),
BottomFrame(*this, Func, nullptr, CodePtr(), Func->getArgSize()),
- Current(&BottomFrame) {}
+ Current(&BottomFrame) {
+ InConstantContext = Parent.InConstantContext;
+ CheckingPotentialConstantExpression =
+ Parent.CheckingPotentialConstantExpression;
+ CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior;
+}
bool InterpState::inConstantContext() const {
if (ConstantContextOverride)
return *ConstantContextOverride;
- return Parent.InConstantContext;
+ return InConstantContext;
}
InterpState::~InterpState() {
@@ -59,20 +69,11 @@ InterpState::~InterpState() {
void InterpState::cleanup() {
// As a last resort, make sure all pointers still pointing to a dead block
// don't point to it anymore.
- Alloc.cleanup();
-}
-
-Frame *InterpState::getCurrentFrame() {
- if (Current && Current->Caller)
- return Current;
- return Parent.getCurrentFrame();
+ if (Alloc)
+ Alloc->cleanup();
}
-bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) {
- QualType Type = E->getType();
- CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
- return noteUndefinedBehavior();
-}
+Frame *InterpState::getCurrentFrame() { return Current; }
void InterpState::deallocate(Block *B) {
assert(B);
@@ -103,10 +104,13 @@ void InterpState::deallocate(Block *B) {
}
bool InterpState::maybeDiagnoseDanglingAllocations() {
- bool NoAllocationsLeft = !Alloc.hasAllocations();
+ if (!Alloc)
+ return true;
+
+ bool NoAllocationsLeft = !Alloc->hasAllocations();
if (!checkingPotentialConstantExpression()) {
- for (const auto &[Source, Site] : Alloc.allocation_sites()) {
+ for (const auto &[Source, Site] : Alloc->allocation_sites()) {
assert(!Site.empty());
CCEDiag(Source->getExprLoc(), diag::note_constexpr_memory_leak)
diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h
index 861e4c38049a..e095908bce98 100644
--- a/clang/lib/AST/ByteCode/InterpState.h
+++ b/clang/lib/AST/ByteCode/InterpState.h
@@ -57,14 +57,11 @@ public:
bool diagnosing() const { return getEvalStatus().Diag != nullptr; }
// Stack frame accessors.
- Frame *getSplitFrame() { return Parent.getCurrentFrame(); }
Frame *getCurrentFrame() override;
unsigned getCallStackDepth() override {
return Current ? (Current->getDepth() + 1) : 1;
}
- const Frame *getBottomFrame() const override {
- return Parent.getBottomFrame();
- }
+ const Frame *getBottomFrame() const override { return &BottomFrame; }
// Access objects from the walker context.
Expr::EvalStatus &getEvalStatus() const override {
@@ -73,18 +70,12 @@ public:
ASTContext &getASTContext() const override { return Parent.getASTContext(); }
// Forward status checks and updates to the walker.
- bool checkingForUndefinedBehavior() const override {
- return Parent.checkingForUndefinedBehavior();
- }
bool keepEvaluatingAfterFailure() const override {
return Parent.keepEvaluatingAfterFailure();
}
bool keepEvaluatingAfterSideEffect() const override {
return Parent.keepEvaluatingAfterSideEffect();
}
- bool checkingPotentialConstantExpression() const override {
- return Parent.checkingPotentialConstantExpression();
- }
bool noteUndefinedBehavior() override {
return Parent.noteUndefinedBehavior();
}
@@ -99,9 +90,6 @@ public:
bool hasPriorDiagnostic() override { return Parent.hasPriorDiagnostic(); }
bool noteSideEffect() override { return Parent.noteSideEffect(); }
- /// Reports overflow and return true if evaluation should continue.
- bool reportOverflow(const Expr *E, const llvm::APSInt &Value);
-
/// Deallocates a pointer.
void deallocate(Block *B);
@@ -118,7 +106,13 @@ public:
void setEvalLocation(SourceLocation SL) { this->EvalLocation = SL; }
- DynamicAllocator &getAllocator() { return Alloc; }
+ DynamicAllocator &getAllocator() {
+ if (!Alloc) {
+ Alloc = std::make_unique<DynamicAllocator>();
+ }
+
+ return *Alloc.get();
+ }
/// Diagnose any dynamic allocations that haven't been freed yet.
/// Will return \c false if there were any allocations to diagnose,
@@ -164,7 +158,7 @@ private:
/// Reference to the offset-source mapping.
SourceMapper *M;
/// Allocator used for dynamic allocations performed via the program.
- DynamicAllocator Alloc;
+ std::unique_ptr<DynamicAllocator> Alloc;
public:
/// Reference to the module containing all bytecode.
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index 38856ad256a6..ef75b0ded4f1 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -442,26 +442,42 @@ bool Pointer::isInitialized() const {
assert(BS.Pointee && "Cannot check if null pointer was initialized");
const Descriptor *Desc = getFieldDesc();
assert(Desc);
- if (Desc->isPrimitiveArray()) {
- if (isStatic() && BS.Base == 0)
- return true;
+ if (Desc->isPrimitiveArray())
+ return isElementInitialized(getIndex());
- InitMapPtr &IM = getInitMap();
+ if (asBlockPointer().Base == 0)
+ return true;
+ // Field has its bit in an inline descriptor.
+ return getInlineDesc()->IsInitialized;
+}
+
+bool Pointer::isElementInitialized(unsigned Index) const {
+ if (!isBlockPointer())
+ return true;
+ const Descriptor *Desc = getFieldDesc();
+ assert(Desc);
+
+ if (isStatic() && BS.Base == 0)
+ return true;
+
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
+ const GlobalInlineDescriptor &GD =
+ *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
+ return GD.InitState == GlobalInitState::Initialized;
+ }
+
+ if (Desc->isPrimitiveArray()) {
+ InitMapPtr &IM = getInitMap();
if (!IM)
return false;
if (IM->first)
return true;
- return IM->second->isElementInitialized(getIndex());
+ return IM->second->isElementInitialized(Index);
}
-
- if (asBlockPointer().Base == 0)
- return true;
-
- // Field has its bit in an inline descriptor.
- return getInlineDesc()->IsInitialized;
+ return isInitialized();
}
void Pointer::initialize() const {
@@ -524,6 +540,23 @@ void Pointer::initializeAllElements() const {
}
}
+bool Pointer::allElementsInitialized() const {
+ assert(getFieldDesc()->isPrimitiveArray());
+ assert(isArrayRoot());
+
+ if (isStatic() && BS.Base == 0)
+ return true;
+
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
+ const GlobalInlineDescriptor &GD =
+ *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
+ return GD.InitState == GlobalInitState::Initialized;
+ }
+
+ InitMapPtr &IM = getInitMap();
+ return IM && IM->first;
+}
+
void Pointer::activate() const {
// Field has its bit in an inline descriptor.
assert(BS.Base != 0 && "Only composite fields can be activated");
@@ -594,9 +627,6 @@ bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
if (A.isTypeidPointer() && B.isTypeidPointer())
return true;
- if (A.isIntegralPointer() || B.isIntegralPointer())
- return A.getSource() == B.getSource();
-
if (A.StorageKind != B.StorageKind)
return false;
@@ -700,7 +730,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
return true;
}
- if (const auto *RT = Ty->getAs<RecordType>()) {
+ if (const auto *RT = Ty->getAsCanonical<RecordType>()) {
const auto *Record = Ptr.getRecord();
assert(Record && "Missing record descriptor");
@@ -771,13 +801,13 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
R = APValue(APValue::UninitArray{}, NumElems, NumElems);
bool Ok = true;
- for (unsigned I = 0; I < NumElems; ++I) {
+ OptPrimType ElemT = Ctx.classify(ElemTy);
+ for (unsigned I = 0; I != NumElems; ++I) {
APValue &Slot = R.getArrayInitializedElt(I);
- const Pointer &EP = Ptr.atIndex(I);
- if (OptPrimType T = Ctx.classify(ElemTy)) {
- TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx));
+ if (ElemT) {
+ TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
} else {
- Ok &= Composite(ElemTy, EP.narrow(), Slot);
+ Ok &= Composite(ElemTy, Ptr.atIndex(I).narrow(), Slot);
}
}
return Ok;
@@ -785,8 +815,11 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
// Complex types.
if (const auto *CT = Ty->getAs<ComplexType>()) {
- QualType ElemTy = CT->getElementType();
+ // Can happen via C casts.
+ if (!Ptr.getFieldDesc()->isPrimitiveArray())
+ return false;
+ QualType ElemTy = CT->getElementType();
if (ElemTy->isIntegerType()) {
OptPrimType ElemT = Ctx.classify(ElemTy);
assert(ElemT);
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 0ce54ab0a17d..49d701c3e27b 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -103,9 +103,7 @@ public:
Pointer(uint64_t Address, const Descriptor *Desc, uint64_t Offset = 0)
: Offset(Offset), StorageKind(Storage::Int), Int{Desc, Address} {}
Pointer(const Function *F, uint64_t Offset = 0)
- : Offset(Offset), StorageKind(Storage::Fn), Fn(F) {
- Fn = FunctionPointer(F);
- }
+ : Offset(Offset), StorageKind(Storage::Fn), Fn(F) {}
Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset = 0)
: Offset(Offset), StorageKind(Storage::Typeid) {
Typeid.TypePtr = TypePtr;
@@ -122,17 +120,14 @@ public:
if (P.StorageKind != StorageKind)
return false;
if (isIntegralPointer())
- return P.asIntPointer().Value == asIntPointer().Value &&
- P.asIntPointer().Desc == asIntPointer().Desc && P.Offset == Offset;
+ return P.Int.Value == Int.Value && P.Int.Desc == Int.Desc &&
+ P.Offset == Offset;
if (isFunctionPointer())
- return P.asFunctionPointer().getFunction() ==
- asFunctionPointer().getFunction() &&
- P.Offset == Offset;
+ return P.Fn.getFunction() == Fn.getFunction() && P.Offset == Offset;
assert(isBlockPointer());
- return P.asBlockPointer().Pointee == asBlockPointer().Pointee &&
- P.asBlockPointer().Base == asBlockPointer().Base &&
+ return P.BS.Pointee == BS.Pointee && P.BS.Base == BS.Base &&
P.Offset == Offset;
}
@@ -146,10 +141,10 @@ public:
uint64_t getIntegerRepresentation() const {
if (isIntegralPointer())
- return asIntPointer().Value + (Offset * elemSize());
+ return Int.Value + (Offset * elemSize());
if (isFunctionPointer())
- return asFunctionPointer().getIntegerRepresentation() + Offset;
- return reinterpret_cast<uint64_t>(asBlockPointer().Pointee) + Offset;
+ return Fn.getIntegerRepresentation() + Offset;
+ return reinterpret_cast<uint64_t>(BS.Pointee) + Offset;
}
/// Converts the pointer to an APValue that is an rvalue.
@@ -159,27 +154,25 @@ public:
/// Offsets a pointer inside an array.
[[nodiscard]] Pointer atIndex(uint64_t Idx) const {
if (isIntegralPointer())
- return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx);
+ return Pointer(Int.Value, Int.Desc, Idx);
if (isFunctionPointer())
- return Pointer(asFunctionPointer().getFunction(), Idx);
+ return Pointer(Fn.getFunction(), Idx);
- if (asBlockPointer().Base == RootPtrMark)
- return Pointer(asBlockPointer().Pointee, RootPtrMark,
- getDeclDesc()->getSize());
+ if (BS.Base == RootPtrMark)
+ return Pointer(BS.Pointee, RootPtrMark, getDeclDesc()->getSize());
uint64_t Off = Idx * elemSize();
if (getFieldDesc()->ElemDesc)
Off += sizeof(InlineDescriptor);
else
Off += sizeof(InitMapPtr);
- return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
- asBlockPointer().Base + Off);
+ return Pointer(BS.Pointee, BS.Base, BS.Base + Off);
}
/// Creates a pointer to a field.
[[nodiscard]] Pointer atField(unsigned Off) const {
assert(isBlockPointer());
unsigned Field = Offset + Off;
- return Pointer(asBlockPointer().Pointee, Field, Field);
+ return Pointer(BS.Pointee, Field, Field);
}
/// Subtract the given offset from the current Base and Offset
@@ -187,7 +180,7 @@ public:
[[nodiscard]] Pointer atFieldSub(unsigned Off) const {
assert(Offset >= Off);
unsigned O = Offset - Off;
- return Pointer(asBlockPointer().Pointee, O, O);
+ return Pointer(BS.Pointee, O, O);
}
/// Restricts the scope of an array element pointer.
@@ -199,15 +192,15 @@ public:
if (isZero() || isUnknownSizeArray())
return *this;
- unsigned Base = asBlockPointer().Base;
+ unsigned Base = BS.Base;
// Pointer to an array of base types - enter block.
if (Base == RootPtrMark)
- return Pointer(asBlockPointer().Pointee, sizeof(InlineDescriptor),
+ return Pointer(BS.Pointee, sizeof(InlineDescriptor),
Offset == 0 ? Offset : PastEndMark);
// Pointer is one past end - magic offset marks that.
if (isOnePastEnd())
- return Pointer(asBlockPointer().Pointee, Base, PastEndMark);
+ return Pointer(BS.Pointee, Base, PastEndMark);
if (Offset != Base) {
// If we're pointing to a primitive array element, there's nothing to do.
@@ -215,7 +208,7 @@ public:
return *this;
// Pointer is to a composite array element - enter it.
if (Offset != Base)
- return Pointer(asBlockPointer().Pointee, Offset, Offset);
+ return Pointer(BS.Pointee, Offset, Offset);
}
// Otherwise, we're pointing to a non-array element or
@@ -226,7 +219,7 @@ public:
/// Expands a pointer to the containing array, undoing narrowing.
[[nodiscard]] Pointer expand() const {
assert(isBlockPointer());
- Block *Pointee = asBlockPointer().Pointee;
+ Block *Pointee = BS.Pointee;
if (isElementPastEnd()) {
// Revert to an outer one-past-end pointer.
@@ -235,19 +228,18 @@ public:
Adjust = sizeof(InitMapPtr);
else
Adjust = sizeof(InlineDescriptor);
- return Pointer(Pointee, asBlockPointer().Base,
- asBlockPointer().Base + getSize() + Adjust);
+ return Pointer(Pointee, BS.Base, BS.Base + getSize() + Adjust);
}
// Do not step out of array elements.
- if (asBlockPointer().Base != Offset)
+ if (BS.Base != Offset)
return *this;
if (isRoot())
- return Pointer(Pointee, asBlockPointer().Base, asBlockPointer().Base);
+ return Pointer(Pointee, BS.Base, BS.Base);
// Step into the containing array, if inside one.
- unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset;
+ unsigned Next = BS.Base - getInlineDesc()->Offset;
const Descriptor *Desc =
(Next == Pointee->getDescriptor()->getMetadataSize())
? getDeclDesc()
@@ -260,19 +252,19 @@ public:
/// Checks if the pointer is null.
bool isZero() const {
if (isBlockPointer())
- return asBlockPointer().Pointee == nullptr;
+ return BS.Pointee == nullptr;
if (isFunctionPointer())
- return asFunctionPointer().isZero();
+ return Fn.isZero();
if (isTypeidPointer())
return false;
assert(isIntegralPointer());
- return asIntPointer().Value == 0 && Offset == 0;
+ return Int.Value == 0 && Offset == 0;
}
/// Checks if the pointer is live.
bool isLive() const {
if (!isBlockPointer())
return true;
- return asBlockPointer().Pointee && !asBlockPointer().Pointee->isDead();
+ return BS.Pointee && !BS.Pointee->isDead();
}
/// Checks if the item is a field in an object.
bool isField() const {
@@ -285,13 +277,13 @@ public:
/// Accessor for information about the declaration site.
const Descriptor *getDeclDesc() const {
if (isIntegralPointer())
- return asIntPointer().Desc;
+ return Int.Desc;
if (isFunctionPointer() || isTypeidPointer())
return nullptr;
assert(isBlockPointer());
- assert(asBlockPointer().Pointee);
- return asBlockPointer().Pointee->Desc;
+ assert(BS.Pointee);
+ return BS.Pointee->Desc;
}
SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); }
@@ -300,37 +292,36 @@ public:
if (isBlockPointer())
return getDeclDesc()->getSource();
if (isFunctionPointer()) {
- const Function *F = asFunctionPointer().getFunction();
+ const Function *F = Fn.getFunction();
return F ? F->getDecl() : DeclTy();
}
assert(isIntegralPointer());
- return asIntPointer().Desc ? asIntPointer().Desc->getSource() : DeclTy();
+ return Int.Desc ? Int.Desc->getSource() : DeclTy();
}
/// Returns a pointer to the object of which this pointer is a field.
[[nodiscard]] Pointer getBase() const {
- if (asBlockPointer().Base == RootPtrMark) {
+ if (BS.Base == RootPtrMark) {
assert(Offset == PastEndMark && "cannot get base of a block");
- return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0);
+ return Pointer(BS.Pointee, BS.Base, 0);
}
- unsigned NewBase = asBlockPointer().Base - getInlineDesc()->Offset;
- return Pointer(asBlockPointer().Pointee, NewBase, NewBase);
+ unsigned NewBase = BS.Base - getInlineDesc()->Offset;
+ return Pointer(BS.Pointee, NewBase, NewBase);
}
/// Returns the parent array.
[[nodiscard]] Pointer getArray() const {
- if (asBlockPointer().Base == RootPtrMark) {
+ if (BS.Base == RootPtrMark) {
assert(Offset != 0 && Offset != PastEndMark && "not an array element");
- return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0);
+ return Pointer(BS.Pointee, BS.Base, 0);
}
- assert(Offset != asBlockPointer().Base && "not an array element");
- return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
- asBlockPointer().Base);
+ assert(Offset != BS.Base && "not an array element");
+ return Pointer(BS.Pointee, BS.Base, BS.Base);
}
/// Accessors for information about the innermost field.
const Descriptor *getFieldDesc() const {
if (isIntegralPointer())
- return asIntPointer().Desc;
+ return Int.Desc;
if (isRoot())
return getDeclDesc();
@@ -342,9 +333,9 @@ public:
if (isTypeidPointer())
return QualType(Typeid.TypeInfoType, 0);
if (isFunctionPointer())
- return asFunctionPointer().getFunction()->getDecl()->getType();
+ return Fn.getFunction()->getDecl()->getType();
- if (inPrimitiveArray() && Offset != asBlockPointer().Base) {
+ if (inPrimitiveArray() && Offset != BS.Base) {
// Unfortunately, complex and vector types are not array types in clang,
// but they are for us.
if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe())
@@ -357,19 +348,17 @@ public:
return getFieldDesc()->getType();
}
- [[nodiscard]] Pointer getDeclPtr() const {
- return Pointer(asBlockPointer().Pointee);
- }
+ [[nodiscard]] Pointer getDeclPtr() const { return Pointer(BS.Pointee); }
/// Returns the element size of the innermost field.
size_t elemSize() const {
if (isIntegralPointer()) {
- if (!asIntPointer().Desc)
+ if (!Int.Desc)
return 1;
- return asIntPointer().Desc->getElemSize();
+ return Int.Desc->getElemSize();
}
- if (asBlockPointer().Base == RootPtrMark)
+ if (BS.Base == RootPtrMark)
return getDeclDesc()->getSize();
return getFieldDesc()->getElemSize();
}
@@ -383,24 +372,22 @@ public:
unsigned getOffset() const {
assert(Offset != PastEndMark && "invalid offset");
assert(isBlockPointer());
- if (asBlockPointer().Base == RootPtrMark)
+ if (BS.Base == RootPtrMark)
return Offset;
unsigned Adjust = 0;
- if (Offset != asBlockPointer().Base) {
+ if (Offset != BS.Base) {
if (getFieldDesc()->ElemDesc)
Adjust = sizeof(InlineDescriptor);
else
Adjust = sizeof(InitMapPtr);
}
- return Offset - asBlockPointer().Base - Adjust;
+ return Offset - BS.Base - Adjust;
}
/// Whether this array refers to an array, but not
/// to the first element.
- bool isArrayRoot() const {
- return inArray() && Offset == asBlockPointer().Base;
- }
+ bool isArrayRoot() const { return inArray() && Offset == BS.Base; }
/// Checks if the innermost field is an array.
bool inArray() const {
@@ -409,7 +396,7 @@ public:
return false;
}
bool inUnion() const {
- if (isBlockPointer() && asBlockPointer().Base >= sizeof(InlineDescriptor))
+ if (isBlockPointer() && BS.Base >= sizeof(InlineDescriptor))
return getInlineDesc()->InUnion;
return false;
};
@@ -431,7 +418,7 @@ public:
if (!isBlockPointer())
return false;
- const BlockPointer &BP = asBlockPointer();
+ const BlockPointer &BP = BS;
if (inArray() && BP.Base != Offset)
return true;
@@ -446,16 +433,15 @@ public:
bool isRoot() const {
if (isZero() || !isBlockPointer())
return true;
- return (asBlockPointer().Base ==
- asBlockPointer().Pointee->getDescriptor()->getMetadataSize() ||
- asBlockPointer().Base == 0);
+ return (BS.Base == BS.Pointee->getDescriptor()->getMetadataSize() ||
+ BS.Base == 0);
}
/// If this pointer has an InlineDescriptor we can use to initialize.
bool canBeInitialized() const {
if (!isBlockPointer())
return false;
- return asBlockPointer().Pointee && asBlockPointer().Base > 0;
+ return BS.Pointee && BS.Base > 0;
}
[[nodiscard]] const BlockPointer &asBlockPointer() const {
@@ -497,29 +483,29 @@ public:
/// Checks if the storage is extern.
bool isExtern() const {
if (isBlockPointer())
- return asBlockPointer().Pointee && asBlockPointer().Pointee->isExtern();
+ return BS.Pointee && BS.Pointee->isExtern();
return false;
}
/// Checks if the storage is static.
bool isStatic() const {
if (!isBlockPointer())
return true;
- assert(asBlockPointer().Pointee);
- return asBlockPointer().Pointee->isStatic();
+ assert(BS.Pointee);
+ return BS.Pointee->isStatic();
}
/// Checks if the storage is temporary.
bool isTemporary() const {
if (isBlockPointer()) {
- assert(asBlockPointer().Pointee);
- return asBlockPointer().Pointee->isTemporary();
+ assert(BS.Pointee);
+ return BS.Pointee->isTemporary();
}
return false;
}
/// Checks if the storage has been dynamically allocated.
bool isDynamic() const {
if (isBlockPointer()) {
- assert(asBlockPointer().Pointee);
- return asBlockPointer().Pointee->isDynamic();
+ assert(BS.Pointee);
+ return BS.Pointee->isDynamic();
}
return false;
}
@@ -535,15 +521,13 @@ public:
bool isWeak() const {
if (isFunctionPointer())
- return asFunctionPointer().isWeak();
+ return Fn.isWeak();
if (!isBlockPointer())
return false;
assert(isBlockPointer());
- return asBlockPointer().Pointee->isWeak();
+ return BS.Pointee->isWeak();
}
- /// Checks if an object was initialized.
- bool isInitialized() const;
/// Checks if the object is active.
bool isActive() const {
if (!isBlockPointer())
@@ -560,7 +544,7 @@ public:
if (!isBlockPointer())
return false;
- if (const Block *Pointee = asBlockPointer().Pointee)
+ if (const Block *Pointee = BS.Pointee)
return Pointee->isDummy();
return false;
}
@@ -587,8 +571,8 @@ public:
/// Returns the declaration ID.
UnsignedOrNone getDeclID() const {
if (isBlockPointer()) {
- assert(asBlockPointer().Pointee);
- return asBlockPointer().Pointee->getDeclID();
+ assert(BS.Pointee);
+ return BS.Pointee->getDeclID();
}
return std::nullopt;
}
@@ -596,9 +580,9 @@ public:
/// Returns the byte offset from the start.
uint64_t getByteOffset() const {
if (isIntegralPointer())
- return asIntPointer().Value + Offset;
+ return Int.Value + Offset;
if (isTypeidPointer())
- return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset;
+ return reinterpret_cast<uintptr_t>(Typeid.TypePtr) + Offset;
if (isOnePastEnd())
return PastEndMark;
return Offset;
@@ -611,13 +595,13 @@ public:
return getSize() / elemSize();
}
- const Block *block() const { return asBlockPointer().Pointee; }
+ const Block *block() const { return BS.Pointee; }
/// If backed by actual data (i.e. a block pointer), return
/// an address to that data.
const std::byte *getRawAddress() const {
assert(isBlockPointer());
- return asBlockPointer().Pointee->rawData() + Offset;
+ return BS.Pointee->rawData() + Offset;
}
/// Returns the index into an array.
@@ -629,8 +613,7 @@ public:
return 0;
// narrow()ed element in a composite array.
- if (asBlockPointer().Base > sizeof(InlineDescriptor) &&
- asBlockPointer().Base == Offset)
+ if (BS.Base > sizeof(InlineDescriptor) && BS.Base == Offset)
return 0;
if (auto ElemSize = elemSize())
@@ -643,7 +626,7 @@ public:
if (!isBlockPointer())
return false;
- if (!asBlockPointer().Pointee)
+ if (!BS.Pointee)
return false;
if (isUnknownSizeArray())
@@ -676,16 +659,15 @@ public:
template <typename T> T &deref() const {
assert(isLive() && "Invalid pointer");
assert(isBlockPointer());
- assert(asBlockPointer().Pointee);
+ assert(BS.Pointee);
assert(isDereferencable());
- assert(Offset + sizeof(T) <=
- asBlockPointer().Pointee->getDescriptor()->getAllocSize());
+ assert(Offset + sizeof(T) <= BS.Pointee->getDescriptor()->getAllocSize());
if (isArrayRoot())
- return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() +
- asBlockPointer().Base + sizeof(InitMapPtr));
+ return *reinterpret_cast<T *>(BS.Pointee->rawData() + BS.Base +
+ sizeof(InitMapPtr));
- return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset);
+ return *reinterpret_cast<T *>(BS.Pointee->rawData() + Offset);
}
/// Dereferences the element at index \p I.
@@ -693,18 +675,17 @@ public:
template <typename T> T &elem(unsigned I) const {
assert(isLive() && "Invalid pointer");
assert(isBlockPointer());
- assert(asBlockPointer().Pointee);
+ assert(BS.Pointee);
assert(isDereferencable());
assert(getFieldDesc()->isPrimitiveArray());
+ assert(I < getFieldDesc()->getNumElems());
unsigned ElemByteOffset = I * getFieldDesc()->getElemSize();
- if (isArrayRoot())
- return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() +
- asBlockPointer().Base + sizeof(InitMapPtr) +
- ElemByteOffset);
+ unsigned ReadOffset = BS.Base + sizeof(InitMapPtr) + ElemByteOffset;
+ assert(ReadOffset + sizeof(T) <=
+ BS.Pointee->getDescriptor()->getAllocSize());
- return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset +
- ElemByteOffset);
+ return *reinterpret_cast<T *>(BS.Pointee->rawData() + ReadOffset);
}
/// Whether this block can be read from at all. This is only true for
@@ -724,6 +705,11 @@ public:
/// used in situations where we *know* we have initialized *all* elements
/// of a primtive array.
void initializeAllElements() const;
+ /// Checks if an object was initialized.
+ bool isInitialized() const;
+ /// Like isInitialized(), but for primitive arrays.
+ bool isElementInitialized(unsigned Index) const;
+ bool allElementsInitialized() const;
/// Activats a field.
void activate() const;
/// Deactivates an entire strurcutre.
@@ -732,7 +718,7 @@ public:
Lifetime getLifetime() const {
if (!isBlockPointer())
return Lifetime::Started;
- if (asBlockPointer().Base < sizeof(InlineDescriptor))
+ if (BS.Base < sizeof(InlineDescriptor))
return Lifetime::Started;
return getInlineDesc()->LifeState;
}
@@ -740,7 +726,7 @@ public:
void endLifetime() const {
if (!isBlockPointer())
return;
- if (asBlockPointer().Base < sizeof(InlineDescriptor))
+ if (BS.Base < sizeof(InlineDescriptor))
return;
getInlineDesc()->LifeState = Lifetime::Ended;
}
@@ -748,7 +734,7 @@ public:
void startLifetime() const {
if (!isBlockPointer())
return;
- if (asBlockPointer().Base < sizeof(InlineDescriptor))
+ if (BS.Base < sizeof(InlineDescriptor))
return;
getInlineDesc()->LifeState = Lifetime::Started;
}
@@ -801,10 +787,10 @@ private:
/// Returns the embedded descriptor preceding a field.
InlineDescriptor *getInlineDesc() const {
assert(isBlockPointer());
- assert(asBlockPointer().Base != sizeof(GlobalInlineDescriptor));
- assert(asBlockPointer().Base <= asBlockPointer().Pointee->getSize());
- assert(asBlockPointer().Base >= sizeof(InlineDescriptor));
- return getDescriptor(asBlockPointer().Base);
+ assert(BS.Base != sizeof(GlobalInlineDescriptor));
+ assert(BS.Base <= BS.Pointee->getSize());
+ assert(BS.Base >= sizeof(InlineDescriptor));
+ return getDescriptor(BS.Base);
}
/// Returns a descriptor at a given offset.
@@ -812,8 +798,8 @@ private:
assert(Offset != 0 && "Not a nested pointer");
assert(isBlockPointer());
assert(!isZero());
- return reinterpret_cast<InlineDescriptor *>(
- asBlockPointer().Pointee->rawData() + Offset) -
+ return reinterpret_cast<InlineDescriptor *>(BS.Pointee->rawData() +
+ Offset) -
1;
}
@@ -821,8 +807,7 @@ private:
InitMapPtr &getInitMap() const {
assert(isBlockPointer());
assert(!isZero());
- return *reinterpret_cast<InitMapPtr *>(asBlockPointer().Pointee->rawData() +
- asBlockPointer().Base);
+ return *reinterpret_cast<InitMapPtr *>(BS.Pointee->rawData() + BS.Base);
}
/// Offset into the storage.
diff --git a/clang/lib/AST/ByteCode/PrimType.h b/clang/lib/AST/ByteCode/PrimType.h
index 6e3a49cadcbf..54fd39ac6fcc 100644
--- a/clang/lib/AST/ByteCode/PrimType.h
+++ b/clang/lib/AST/ByteCode/PrimType.h
@@ -272,14 +272,4 @@ static inline bool aligned(const void *P) {
} \
} while (0)
-#define COMPOSITE_TYPE_SWITCH(Expr, B, D) \
- do { \
- switch (Expr) { \
- TYPE_SWITCH_CASE(PT_Ptr, B) \
- default: { \
- D; \
- break; \
- } \
- } \
- } while (0)
#endif
diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp
index 5d72044af969..75bfd9fd2d8e 100644
--- a/clang/lib/AST/ByteCode/Program.cpp
+++ b/clang/lib/AST/ByteCode/Program.cpp
@@ -101,7 +101,7 @@ unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base) {
}
}
}
- Ptr.initialize();
+ Ptr.initializeAllElements();
return GlobalIndex;
}
@@ -111,7 +111,7 @@ Pointer Program::getPtrGlobal(unsigned Idx) const {
return Pointer(Globals[Idx]->block());
}
-std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
+UnsignedOrNone Program::getGlobal(const ValueDecl *VD) {
if (auto It = GlobalIndices.find(VD); It != GlobalIndices.end())
return It->second;
@@ -131,14 +131,14 @@ std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
return std::nullopt;
}
-std::optional<unsigned> Program::getGlobal(const Expr *E) {
+UnsignedOrNone Program::getGlobal(const Expr *E) {
if (auto It = GlobalIndices.find(E); It != GlobalIndices.end())
return It->second;
return std::nullopt;
}
-std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD,
- const Expr *Init) {
+UnsignedOrNone Program::getOrCreateGlobal(const ValueDecl *VD,
+ const Expr *Init) {
if (auto Idx = getGlobal(VD))
return Idx;
@@ -195,8 +195,7 @@ unsigned Program::getOrCreateDummy(const DeclTy &D) {
return I;
}
-std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
- const Expr *Init) {
+UnsignedOrNone Program::createGlobal(const ValueDecl *VD, const Expr *Init) {
bool IsStatic, IsExtern;
bool IsWeak = VD->isWeak();
if (const auto *Var = dyn_cast<VarDecl>(VD)) {
@@ -213,7 +212,7 @@ std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
// Register all previous declarations as well. For extern blocks, just replace
// the index with the new variable.
- std::optional<unsigned> Idx =
+ UnsignedOrNone Idx =
createGlobal(VD, VD->getType(), IsStatic, IsExtern, IsWeak, Init);
if (!Idx)
return std::nullopt;
@@ -240,7 +239,7 @@ std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
return *Idx;
}
-std::optional<unsigned> Program::createGlobal(const Expr *E) {
+UnsignedOrNone Program::createGlobal(const Expr *E) {
if (auto Idx = getGlobal(E))
return Idx;
if (auto Idx = createGlobal(E, E->getType(), /*isStatic=*/true,
@@ -251,9 +250,9 @@ std::optional<unsigned> Program::createGlobal(const Expr *E) {
return std::nullopt;
}
-std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
- bool IsStatic, bool IsExtern,
- bool IsWeak, const Expr *Init) {
+UnsignedOrNone Program::createGlobal(const DeclTy &D, QualType Ty,
+ bool IsStatic, bool IsExtern, bool IsWeak,
+ const Expr *Init) {
// Create a descriptor for the global.
Descriptor *Desc;
const bool IsConst = Ty.isConstQualified();
@@ -332,10 +331,9 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
continue;
// In error cases, the base might not be a RecordType.
- const auto *RT = Spec.getType()->getAs<RecordType>();
- if (!RT)
+ const auto *BD = Spec.getType()->getAsCXXRecordDecl();
+ if (!BD)
return nullptr;
- const RecordDecl *BD = RT->getOriginalDecl()->getDefinitionOrSelf();
const Record *BR = getOrCreateRecord(BD);
const Descriptor *Desc = GetBaseDesc(BD, BR);
@@ -348,11 +346,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
}
for (const CXXBaseSpecifier &Spec : CD->vbases()) {
- const auto *RT = Spec.getType()->getAs<RecordType>();
- if (!RT)
- return nullptr;
-
- const RecordDecl *BD = RT->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *BD = Spec.getType()->castAsCXXRecordDecl();
const Record *BR = getOrCreateRecord(BD);
const Descriptor *Desc = GetBaseDesc(BD, BR);
@@ -408,9 +402,8 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
const Expr *Init) {
// Classes and structures.
- if (const auto *RT = Ty->getAs<RecordType>()) {
- if (const auto *Record =
- getOrCreateRecord(RT->getOriginalDecl()->getDefinitionOrSelf()))
+ if (const auto *RD = Ty->getAsRecordDecl()) {
+ if (const auto *Record = getOrCreateRecord(RD))
return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary,
IsMutable, IsVolatile);
return allocateDescriptor(D, MDSize);
diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h
index 90b48ee5b669..28fcc97f5339 100644
--- a/clang/lib/AST/ByteCode/Program.h
+++ b/clang/lib/AST/ByteCode/Program.h
@@ -78,21 +78,21 @@ public:
}
/// Finds a global's index.
- std::optional<unsigned> getGlobal(const ValueDecl *VD);
- std::optional<unsigned> getGlobal(const Expr *E);
+ UnsignedOrNone getGlobal(const ValueDecl *VD);
+ UnsignedOrNone getGlobal(const Expr *E);
/// Returns or creates a global an creates an index to it.
- std::optional<unsigned> getOrCreateGlobal(const ValueDecl *VD,
- const Expr *Init = nullptr);
+ UnsignedOrNone getOrCreateGlobal(const ValueDecl *VD,
+ const Expr *Init = nullptr);
/// Returns or creates a dummy value for unknown declarations.
unsigned getOrCreateDummy(const DeclTy &D);
/// Creates a global and returns its index.
- std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *Init);
+ UnsignedOrNone createGlobal(const ValueDecl *VD, const Expr *Init);
/// Creates a global from a lifetime-extended temporary.
- std::optional<unsigned> createGlobal(const Expr *E);
+ UnsignedOrNone createGlobal(const Expr *E);
/// Creates a new function from a code range.
template <typename... Ts>
@@ -165,9 +165,9 @@ public:
private:
friend class DeclScope;
- std::optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
- bool IsStatic, bool IsExtern,
- bool IsWeak, const Expr *Init = nullptr);
+ UnsignedOrNone createGlobal(const DeclTy &D, QualType Ty, bool IsStatic,
+ bool IsExtern, bool IsWeak,
+ const Expr *Init = nullptr);
/// Reference to the VM context.
Context &Ctx;
diff --git a/clang/lib/AST/ByteCode/Record.cpp b/clang/lib/AST/ByteCode/Record.cpp
index a7934ccb4e55..ff5c82d24457 100644
--- a/clang/lib/AST/ByteCode/Record.cpp
+++ b/clang/lib/AST/ByteCode/Record.cpp
@@ -37,6 +37,13 @@ std::string Record::getName() const {
return Ret;
}
+bool Record::hasTrivialDtor() const {
+ if (isAnonymousUnion())
+ return true;
+ const CXXDestructorDecl *Dtor = getDestructor();
+ return !Dtor || Dtor->isTrivial();
+}
+
const Record::Field *Record::getField(const FieldDecl *FD) const {
auto It = FieldMap.find(FD->getFirstDecl());
assert(It != FieldMap.end() && "Missing field");
@@ -50,10 +57,8 @@ const Record::Base *Record::getBase(const RecordDecl *FD) const {
}
const Record::Base *Record::getBase(QualType T) const {
- if (auto *RT = T->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
+ if (auto *RD = T->getAsCXXRecordDecl())
return BaseMap.lookup(RD);
- }
return nullptr;
}
diff --git a/clang/lib/AST/ByteCode/Record.h b/clang/lib/AST/ByteCode/Record.h
index 93ca43046180..8245eeff2f20 100644
--- a/clang/lib/AST/ByteCode/Record.h
+++ b/clang/lib/AST/ByteCode/Record.h
@@ -76,6 +76,10 @@ public:
return nullptr;
}
+ /// Returns true for anonymous unions and records
+ /// with no destructor or for those with a trivial destructor.
+ bool hasTrivialDtor() const;
+
using const_field_iter = FieldList::const_iterator;
llvm::iterator_range<const_field_iter> fields() const {
return llvm::make_range(Fields.begin(), Fields.end());
diff --git a/clang/lib/AST/ByteCode/State.h b/clang/lib/AST/ByteCode/State.h
index 6fc33222ac95..387ce396a723 100644
--- a/clang/lib/AST/ByteCode/State.h
+++ b/clang/lib/AST/ByteCode/State.h
@@ -59,8 +59,6 @@ class State {
public:
virtual ~State();
- virtual bool checkingForUndefinedBehavior() const = 0;
- virtual bool checkingPotentialConstantExpression() const = 0;
virtual bool noteUndefinedBehavior() = 0;
virtual bool keepEvaluatingAfterFailure() const = 0;
virtual bool keepEvaluatingAfterSideEffect() const = 0;
@@ -75,6 +73,16 @@ public:
virtual unsigned getCallStackDepth() = 0;
virtual bool noteSideEffect() = 0;
+ /// Are we checking whether the expression is a potential constant
+ /// expression?
+ bool checkingPotentialConstantExpression() const {
+ return CheckingPotentialConstantExpression;
+ }
+ /// Are we checking an expression for overflow?
+ bool checkingForUndefinedBehavior() const {
+ return CheckingForUndefinedBehavior;
+ }
+
public:
State() = default;
/// Diagnose that the evaluation could not be folded (FF => FoldFailure)
@@ -128,6 +136,19 @@ public:
/// constant value.
bool InConstantContext = false;
+ /// Whether we're checking that an expression is a potential constant
+ /// expression. If so, do not fail on constructs that could become constant
+ /// later on (such as a use of an undefined global).
+ bool CheckingPotentialConstantExpression = false;
+
+ /// Whether we're checking for an expression that has undefined behavior.
+ /// If so, we will produce warnings if we encounter an operation that is
+ /// always undefined.
+ ///
+ /// Note that we still need to evaluate the expression normally when this
+ /// is set; this is used when evaluating ICEs in C.
+ bool CheckingForUndefinedBehavior = false;
+
private:
void addCallStack(unsigned Limit);