diff options
author | Timm Baeder <tbaeder@redhat.com> | 2025-05-19 11:49:27 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-05-19 11:49:27 +0200 |
commit | bca39f4e8f79c84b66a51a87d7ae8ecc4b0fe436 (patch) | |
tree | d9a881e4b74de343c3eb5e760017cbda3fa6821d /clang/lib/AST/ByteCode/Compiler.cpp | |
parent | 1b711b27d20500639e42fb866e3a20ef8d39326c (diff) | |
download | llvm-bca39f4e8f79c84b66a51a87d7ae8ecc4b0fe436.zip llvm-bca39f4e8f79c84b66a51a87d7ae8ecc4b0fe436.tar.gz llvm-bca39f4e8f79c84b66a51a87d7ae8ecc4b0fe436.tar.bz2 |
[clang][bytecode] Add a scope to function calls (#140441)
We need a place to destroy the temporaries created for call arguments.
Diffstat (limited to 'clang/lib/AST/ByteCode/Compiler.cpp')
-rw-r--r-- | clang/lib/AST/ByteCode/Compiler.cpp | 117 |
1 files changed, 70 insertions, 47 deletions
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 5017c9b..aa8f009 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -45,10 +45,6 @@ public: Ctx->InitStack.push_back(InitLink::Decl(VD)); } - void addExtended(const Scope::Local &Local) override { - return this->addLocal(Local); - } - ~DeclScope() { this->Ctx->InitializingDecl = OldInitializingDecl; this->Ctx->InitStack.pop_back(); @@ -2022,6 +2018,45 @@ bool Compiler<Emitter>::visitArrayElemInit(unsigned ElemIndex, const Expr *Init, } template <class Emitter> +bool Compiler<Emitter>::visitCallArgs(ArrayRef<const Expr *> Args, + const FunctionDecl *FuncDecl) { + assert(VarScope->getKind() == ScopeKind::Call); + llvm::BitVector NonNullArgs = collectNonNullArgs(FuncDecl, Args); + + unsigned ArgIndex = 0; + for (const Expr *Arg : Args) { + if (std::optional<PrimType> T = classify(Arg)) { + if (!this->visit(Arg)) + return false; + } else { + + std::optional<unsigned> LocalIndex = allocateLocal( + Arg, Arg->getType(), /*ExtendingDecl=*/nullptr, ScopeKind::Call); + if (!LocalIndex) + return false; + + if (!this->emitGetPtrLocal(*LocalIndex, Arg)) + return false; + InitLinkScope<Emitter> ILS(this, InitLink::Temp(*LocalIndex)); + if (!this->visitInitializer(Arg)) + return false; + } + + if (FuncDecl && NonNullArgs[ArgIndex]) { + PrimType ArgT = classify(Arg).value_or(PT_Ptr); + if (ArgT == PT_Ptr) { + if (!this->emitCheckNonNullArg(ArgT, Arg)) + return false; + } + } + + ++ArgIndex; + } + + return true; +} + +template <class Emitter> bool Compiler<Emitter>::VisitInitListExpr(const InitListExpr *E) { return this->visitInitList(E->inits(), E->getArrayFiller(), E); } @@ -4343,7 +4378,7 @@ bool Compiler<Emitter>::emitConst(const APSInt &Value, const Expr *E) { template <class Emitter> unsigned Compiler<Emitter>::allocateLocalPrimitive( DeclTy &&Src, PrimType Ty, bool IsConst, const ValueDecl *ExtendingDecl, - bool IsConstexprUnknown) { + ScopeKind SC, bool IsConstexprUnknown) { // Make sure we don't accidentally register the same decl twice. if (const auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) { @@ -4364,14 +4399,14 @@ unsigned Compiler<Emitter>::allocateLocalPrimitive( if (ExtendingDecl) VarScope->addExtended(Local, ExtendingDecl); else - VarScope->add(Local, false); + VarScope->addForScopeKind(Local, SC); return Local.Offset; } template <class Emitter> std::optional<unsigned> Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty, - const ValueDecl *ExtendingDecl, + const ValueDecl *ExtendingDecl, ScopeKind SC, bool IsConstexprUnknown) { // Make sure we don't accidentally register the same decl twice. if ([[maybe_unused]] const auto *VD = @@ -4409,7 +4444,7 @@ Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty, if (ExtendingDecl) VarScope->addExtended(Local, ExtendingDecl); else - VarScope->add(Local, false); + VarScope->addForScopeKind(Local, SC); return Local.Offset; } @@ -4676,7 +4711,7 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, if (VarT) { unsigned Offset = this->allocateLocalPrimitive( VD, *VarT, VD->getType().isConstQualified(), nullptr, - IsConstexprUnknown); + ScopeKind::Block, IsConstexprUnknown); if (Init) { // If this is a toplevel declaration, create a scope for the // initializer. @@ -4692,8 +4727,9 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, } } } else { - if (std::optional<unsigned> Offset = this->allocateLocal( - VD, VD->getType(), nullptr, IsConstexprUnknown)) { + if (std::optional<unsigned> Offset = + this->allocateLocal(VD, VD->getType(), nullptr, ScopeKind::Block, + IsConstexprUnknown)) { if (!Init) return true; @@ -4881,26 +4917,28 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { if (FuncDecl) { if (unsigned BuiltinID = FuncDecl->getBuiltinID()) return VisitBuiltinCallExpr(E, BuiltinID); - } - // Calls to replaceable operator new/operator delete. - if (FuncDecl && - FuncDecl->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) { - if (FuncDecl->getDeclName().isAnyOperatorNew()) { - return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_new); - } else { - assert(FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Delete); - return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_delete); + // Calls to replaceable operator new/operator delete. + if (FuncDecl->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) { + if (FuncDecl->getDeclName().isAnyOperatorNew()) { + return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_new); + } else { + assert(FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Delete); + return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_delete); + } + } + + // Explicit calls to trivial destructors + if (const auto *DD = dyn_cast<CXXDestructorDecl>(FuncDecl); + DD && DD->isTrivial()) { + const auto *MemberCall = cast<CXXMemberCallExpr>(E); + if (!this->visit(MemberCall->getImplicitObjectArgument())) + return false; + return this->emitCheckDestruction(E) && this->emitPopPtr(E); } } - // Explicit calls to trivial destructors - if (const auto *DD = dyn_cast_if_present<CXXDestructorDecl>(FuncDecl); - DD && DD->isTrivial()) { - const auto *MemberCall = cast<CXXMemberCallExpr>(E); - if (!this->visit(MemberCall->getImplicitObjectArgument())) - return false; - return this->emitCheckDestruction(E) && this->emitPopPtr(E); - } + + BlockScope<Emitter> CallScope(this, ScopeKind::Call); QualType ReturnType = E->getCallReturnType(Ctx.getASTContext()); std::optional<PrimType> T = classify(ReturnType); @@ -4996,23 +5034,8 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { return false; } - llvm::BitVector NonNullArgs = collectNonNullArgs(FuncDecl, Args); - // Put arguments on the stack. - unsigned ArgIndex = 0; - for (const auto *Arg : Args) { - if (!this->visit(Arg)) - return false; - - // If we know the callee already, check the known parametrs for nullability. - if (FuncDecl && NonNullArgs[ArgIndex]) { - PrimType ArgT = classify(Arg).value_or(PT_Ptr); - if (ArgT == PT_Ptr) { - if (!this->emitCheckNonNullArg(ArgT, Arg)) - return false; - } - } - ++ArgIndex; - } + if (!this->visitCallArgs(Args, FuncDecl)) + return false; // Undo the argument reversal we did earlier. if (IsAssignmentOperatorCall) { @@ -5088,9 +5111,9 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { // Cleanup for discarded return values. if (DiscardResult && !ReturnType->isVoidType() && T) - return this->emitPop(*T, E); + return this->emitPop(*T, E) && CallScope.destroyLocals(); - return true; + return CallScope.destroyLocals(); } template <class Emitter> |