From bca39f4e8f79c84b66a51a87d7ae8ecc4b0fe436 Mon Sep 17 00:00:00 2001 From: Timm Baeder Date: Mon, 19 May 2025 11:49:27 +0200 Subject: [clang][bytecode] Add a scope to function calls (#140441) We need a place to destroy the temporaries created for call arguments. --- clang/lib/AST/ByteCode/Compiler.cpp | 117 +++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 47 deletions(-) (limited to 'clang/lib/AST/ByteCode/Compiler.cpp') 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::visitArrayElemInit(unsigned ElemIndex, const Expr *Init, } template +bool Compiler::visitCallArgs(ArrayRef 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 T = classify(Arg)) { + if (!this->visit(Arg)) + return false; + } else { + + std::optional LocalIndex = allocateLocal( + Arg, Arg->getType(), /*ExtendingDecl=*/nullptr, ScopeKind::Call); + if (!LocalIndex) + return false; + + if (!this->emitGetPtrLocal(*LocalIndex, Arg)) + return false; + InitLinkScope 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 bool Compiler::VisitInitListExpr(const InitListExpr *E) { return this->visitInitList(E->inits(), E->getArrayFiller(), E); } @@ -4343,7 +4378,7 @@ bool Compiler::emitConst(const APSInt &Value, const Expr *E) { template unsigned Compiler::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(Src.dyn_cast())) { @@ -4364,14 +4399,14 @@ unsigned Compiler::allocateLocalPrimitive( if (ExtendingDecl) VarScope->addExtended(Local, ExtendingDecl); else - VarScope->add(Local, false); + VarScope->addForScopeKind(Local, SC); return Local.Offset; } template std::optional Compiler::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::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::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::visitVarDecl(const VarDecl *VD, } } } else { - if (std::optional Offset = this->allocateLocal( - VD, VD->getType(), nullptr, IsConstexprUnknown)) { + if (std::optional Offset = + this->allocateLocal(VD, VD->getType(), nullptr, ScopeKind::Block, + IsConstexprUnknown)) { if (!Init) return true; @@ -4881,26 +4917,28 @@ bool Compiler::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(FuncDecl); + DD && DD->isTrivial()) { + const auto *MemberCall = cast(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(FuncDecl); - DD && DD->isTrivial()) { - const auto *MemberCall = cast(E); - if (!this->visit(MemberCall->getImplicitObjectArgument())) - return false; - return this->emitCheckDestruction(E) && this->emitPopPtr(E); - } + + BlockScope CallScope(this, ScopeKind::Call); QualType ReturnType = E->getCallReturnType(Ctx.getASTContext()); std::optional T = classify(ReturnType); @@ -4996,23 +5034,8 @@ bool Compiler::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::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 -- cgit v1.1