aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/AST/ByteCode/Compiler.cpp
diff options
context:
space:
mode:
authorTimm Baeder <tbaeder@redhat.com>2025-05-19 11:49:27 +0200
committerGitHub <noreply@github.com>2025-05-19 11:49:27 +0200
commitbca39f4e8f79c84b66a51a87d7ae8ecc4b0fe436 (patch)
treed9a881e4b74de343c3eb5e760017cbda3fa6821d /clang/lib/AST/ByteCode/Compiler.cpp
parent1b711b27d20500639e42fb866e3a20ef8d39326c (diff)
downloadllvm-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.cpp117
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>