diff options
Diffstat (limited to 'clang/lib/AST/ByteCode/Compiler.cpp')
| -rw-r--r-- | clang/lib/AST/ByteCode/Compiler.cpp | 211 |
1 files changed, 112 insertions, 99 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 |
