[clang] 5b2eb0d - [clang][bytecode][NFC] Add FullExpression scopes (#170705)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Dec 5 01:22:41 PST 2025
Author: Timm Baeder
Date: 2025-12-05T10:22:37+01:00
New Revision: 5b2eb0dcb717c7218f691e2a10f76b60ed039ecd
URL: https://github.com/llvm/llvm-project/commit/5b2eb0dcb717c7218f691e2a10f76b60ed039ecd
DIFF: https://github.com/llvm/llvm-project/commit/5b2eb0dcb717c7218f691e2a10f76b60ed039ecd.diff
LOG: [clang][bytecode][NFC] Add FullExpression scopes (#170705)
And use them instead of the extending decl. This is close to what the
current interpreter is doing.
This is NFC right now but fixes a problem I encountered while looking
into the expansion statement stuff.
Added:
Modified:
clang/lib/AST/ByteCode/Compiler.cpp
clang/lib/AST/ByteCode/Compiler.h
Removed:
################################################################################
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 58e84ef70abb7..14b6bb7bf61d5 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -40,7 +40,7 @@ static std::optional<bool> getBoolValue(const Expr *E) {
template <class Emitter> class DeclScope final : public LocalScope<Emitter> {
public:
DeclScope(Compiler<Emitter> *Ctx, const ValueDecl *VD)
- : LocalScope<Emitter>(Ctx, VD), Scope(Ctx->P),
+ : LocalScope<Emitter>(Ctx), Scope(Ctx->P),
OldInitializingDecl(Ctx->InitializingDecl) {
Ctx->InitializingDecl = VD;
Ctx->InitStack.push_back(InitLink::Decl(VD));
@@ -2137,8 +2137,7 @@ bool Compiler<Emitter>::visitCallArgs(ArrayRef<const Expr *> Args,
}
UnsignedOrNone LocalIndex =
- allocateLocal(std::move(Source), Arg->getType(),
- /*ExtendingDecl=*/nullptr, ScopeKind::Call);
+ allocateLocal(std::move(Source), Arg->getType(), ScopeKind::Call);
if (!LocalIndex)
return false;
@@ -2451,7 +2450,7 @@ bool Compiler<Emitter>::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
// and the RHS is our SubExpr.
for (size_t I = 0; I != Size; ++I) {
ArrayIndexScope<Emitter> IndexScope(this, I);
- LocalScope<Emitter> BS(this);
+ LocalScope<Emitter> BS(this, ScopeKind::FullExpression);
if (!this->visitArrayElemInit(I, SubExpr, SubExprT))
return false;
@@ -2903,7 +2902,7 @@ bool Compiler<Emitter>::VisitCompoundAssignOperator(
template <class Emitter>
bool Compiler<Emitter>::VisitExprWithCleanups(const ExprWithCleanups *E) {
- LocalScope<Emitter> ES(this);
+ LocalScope<Emitter> ES(this, ScopeKind::FullExpression);
const Expr *SubExpr = E->getSubExpr();
return this->delegate(SubExpr) && ES.destroyLocals(E);
@@ -2926,9 +2925,7 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(
// When we're initializing a global variable *or* the storage duration of
// the temporary is explicitly static, create a global variable.
OptPrimType SubExprT = classify(SubExpr);
- bool IsStatic = E->getStorageDuration() == SD_Static;
- if (IsStatic) {
-
+ if (E->getStorageDuration() == SD_Static) {
UnsignedOrNone GlobalIndex = P.createGlobal(E);
if (!GlobalIndex)
return false;
@@ -2955,12 +2952,16 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(
return this->emitInitGlobalTempComp(TempDecl, E);
}
+ ScopeKind VarScope = E->getStorageDuration() == SD_FullExpression
+ ? ScopeKind::FullExpression
+ : ScopeKind::Block;
+
// For everyhing else, use local variables.
if (SubExprT) {
bool IsConst = SubExpr->getType().isConstQualified();
bool IsVolatile = SubExpr->getType().isVolatileQualified();
- unsigned LocalIndex = allocateLocalPrimitive(
- E, *SubExprT, IsConst, IsVolatile, E->getExtendingDecl());
+ unsigned LocalIndex =
+ allocateLocalPrimitive(E, *SubExprT, IsConst, IsVolatile, VarScope);
if (!this->VarScope->LocalsAlwaysEnabled &&
!this->emitEnableLocal(LocalIndex, E))
return false;
@@ -2975,9 +2976,10 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(
if (!this->checkLiteralType(SubExpr))
return false;
+
const Expr *Inner = E->getSubExpr()->skipRValueSubobjectAdjustments();
if (UnsignedOrNone LocalIndex =
- allocateLocal(E, Inner->getType(), E->getExtendingDecl())) {
+ allocateLocal(E, Inner->getType(), VarScope)) {
InitLinkScope<Emitter> ILS(this, InitLink::Temp(*LocalIndex));
if (!this->VarScope->LocalsAlwaysEnabled &&
@@ -4269,7 +4271,8 @@ template <class Emitter> bool Compiler<Emitter>::visit(const Expr *E) {
// Create local variable to hold the return value.
if (!E->isGLValue() && !canClassify(E->getType())) {
- UnsignedOrNone LocalIndex = allocateLocal(stripDerivedToBaseCasts(E));
+ UnsignedOrNone LocalIndex = allocateLocal(
+ stripDerivedToBaseCasts(E), QualType(), ScopeKind::FullExpression);
if (!LocalIndex)
return false;
@@ -4626,9 +4629,11 @@ bool Compiler<Emitter>::emitConst(const APSInt &Value, const Expr *E) {
}
template <class Emitter>
-unsigned Compiler<Emitter>::allocateLocalPrimitive(
- DeclTy &&Src, PrimType Ty, bool IsConst, bool IsVolatile,
- const ValueDecl *ExtendingDecl, ScopeKind SC, bool IsConstexprUnknown) {
+unsigned Compiler<Emitter>::allocateLocalPrimitive(DeclTy &&Src, PrimType Ty,
+ bool IsConst,
+ bool IsVolatile,
+ ScopeKind SC,
+ bool IsConstexprUnknown) {
// FIXME: There are cases where Src.is<Expr*>() is wrong, e.g.
// (int){12} in C. Consider using Expr::isTemporaryObject() instead
// or isa<MaterializeTemporaryExpr>().
@@ -4639,16 +4644,12 @@ unsigned Compiler<Emitter>::allocateLocalPrimitive(
Scope::Local Local = this->createLocal(D);
if (auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>()))
Locals.insert({VD, Local});
- if (ExtendingDecl)
- VarScope->addExtended(Local, ExtendingDecl);
- else
- VarScope->addForScopeKind(Local, SC);
+ VarScope->addForScopeKind(Local, SC);
return Local.Offset;
}
template <class Emitter>
UnsignedOrNone Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty,
- const ValueDecl *ExtendingDecl,
ScopeKind SC,
bool IsConstexprUnknown) {
const ValueDecl *Key = nullptr;
@@ -4676,10 +4677,7 @@ UnsignedOrNone Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty,
Scope::Local Local = this->createLocal(D);
if (Key)
Locals.insert({Key, Local});
- if (ExtendingDecl)
- VarScope->addExtended(Local, ExtendingDecl);
- else
- VarScope->addForScopeKind(Local, SC);
+ VarScope->addForScopeKind(Local, SC);
return Local.Offset;
}
@@ -4731,7 +4729,7 @@ const Function *Compiler<Emitter>::getFunction(const FunctionDecl *FD) {
template <class Emitter>
bool Compiler<Emitter>::visitExpr(const Expr *E, bool DestroyToplevelScope) {
- LocalScope<Emitter> RootScope(this);
+ LocalScope<Emitter> RootScope(this, ScopeKind::FullExpression);
// If we won't destroy the toplevel scope, check for memory leaks first.
if (!DestroyToplevelScope) {
@@ -4825,7 +4823,7 @@ bool Compiler<Emitter>::visitDeclAndReturn(const VarDecl *VD, const Expr *Init,
LS.destroyLocals() && this->emitCheckAllocations(VD);
}
- LocalScope<Emitter> VDScope(this, VD);
+ LocalScope<Emitter> VDScope(this);
if (!this->visitVarDecl(VD, Init, /*Toplevel=*/true))
return false;
@@ -4936,7 +4934,7 @@ Compiler<Emitter>::visitVarDecl(const VarDecl *VD, const Expr *Init,
if (VarT) {
unsigned Offset = this->allocateLocalPrimitive(
VD, *VarT, VD->getType().isConstQualified(),
- VD->getType().isVolatileQualified(), nullptr, ScopeKind::Block,
+ VD->getType().isVolatileQualified(), ScopeKind::Block,
IsConstexprUnknown);
if (!Init)
@@ -4956,7 +4954,7 @@ Compiler<Emitter>::visitVarDecl(const VarDecl *VD, const Expr *Init,
}
// Local composite variables.
if (UnsignedOrNone Offset = this->allocateLocal(
- VD, VD->getType(), nullptr, ScopeKind::Block, IsConstexprUnknown)) {
+ VD, VD->getType(), ScopeKind::Block, IsConstexprUnknown)) {
if (!Init)
return true;
@@ -5671,19 +5669,24 @@ bool Compiler<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
}
template <class Emitter> bool Compiler<Emitter>::visitIfStmt(const IfStmt *IS) {
+ LocalScope<Emitter> IfScope(this);
+
auto visitChildStmt = [&](const Stmt *S) -> bool {
LocalScope<Emitter> SScope(this);
if (!visitStmt(S))
return false;
return SScope.destroyLocals();
};
- if (auto *CondInit = IS->getInit())
+
+ if (auto *CondInit = IS->getInit()) {
if (!visitStmt(CondInit))
return false;
+ }
- if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt())
+ if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt()) {
if (!visitDeclStmt(CondDecl))
return false;
+ }
// Save ourselves compiling some code and the jumps, etc. if the condition is
// stataically known to be either true or false. We could look at more cases
@@ -5707,8 +5710,11 @@ template <class Emitter> bool Compiler<Emitter>::visitIfStmt(const IfStmt *IS) {
if (!this->emitInv(IS))
return false;
} else {
+ LocalScope<Emitter> CondScope(this, ScopeKind::FullExpression);
if (!this->visitBool(IS->getCond()))
return false;
+ if (!CondScope.destroyLocals())
+ return false;
}
if (!this->maybeEmitDeferredVarInit(IS->getConditionVariable()))
@@ -5736,6 +5742,9 @@ template <class Emitter> bool Compiler<Emitter>::visitIfStmt(const IfStmt *IS) {
this->emitLabel(LabelEnd);
}
+ if (!IfScope.destroyLocals())
+ return false;
+
return true;
}
@@ -6333,7 +6342,7 @@ bool Compiler<Emitter>::compileConstructor(const CXXConstructorDecl *Ctor) {
InitLinkScope<Emitter> InitScope(this, InitLink::This());
for (const auto *Init : Ctor->inits()) {
// Scope needed for the initializers.
- LocalScope<Emitter> Scope(this);
+ LocalScope<Emitter> Scope(this, ScopeKind::FullExpression);
const Expr *InitExpr = Init->getInit();
if (const FieldDecl *Member = Init->getMember()) {
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 54d39bbc25952..c641af52c2811 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -104,7 +104,7 @@ struct VarCreationState {
bool notCreated() const { return !S; }
};
-enum class ScopeKind { Call, Block };
+enum class ScopeKind { Block, FullExpression, Call };
/// Compilation context for expressions.
template <class Emitter>
@@ -330,13 +330,11 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
/// Creates a local primitive value.
unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst,
bool IsVolatile = false,
- const ValueDecl *ExtendingDecl = nullptr,
ScopeKind SC = ScopeKind::Block,
bool IsConstexprUnknown = false);
/// Allocates a space storing a local given its type.
UnsignedOrNone allocateLocal(DeclTy &&Decl, QualType Ty = QualType(),
- const ValueDecl *ExtendingDecl = nullptr,
ScopeKind = ScopeKind::Block,
bool IsConstexprUnknown = false);
UnsignedOrNone allocateTemporary(const Expr *E);
@@ -476,9 +474,8 @@ extern template class Compiler<EvalEmitter>;
/// Scope chain managing the variable lifetimes.
template <class Emitter> class VariableScope {
public:
- VariableScope(Compiler<Emitter> *Ctx, const ValueDecl *VD,
- ScopeKind Kind = ScopeKind::Block)
- : Ctx(Ctx), Parent(Ctx->VarScope), ValDecl(VD), Kind(Kind) {
+ VariableScope(Compiler<Emitter> *Ctx, ScopeKind Kind = ScopeKind::Block)
+ : Ctx(Ctx), Parent(Ctx->VarScope), Kind(Kind) {
if (Parent)
this->LocalsAlwaysEnabled = Parent->LocalsAlwaysEnabled;
Ctx->VarScope = this;
@@ -489,28 +486,6 @@ template <class Emitter> class VariableScope {
virtual void addLocal(Scope::Local Local) {
llvm_unreachable("Shouldn't be called");
}
-
- void addExtended(const Scope::Local &Local, const ValueDecl *ExtendingDecl) {
- // Walk up the chain of scopes until we find the one for ExtendingDecl.
- // If there is no such scope, attach it to the parent one.
- VariableScope *P = this;
- while (P) {
- if (P->ValDecl == ExtendingDecl) {
- P->addLocal(Local);
- return;
- }
- P = P->Parent;
- if (!P)
- break;
- }
-
- // Use the parent scope.
- if (this->Parent)
- this->Parent->addLocal(Local);
- else
- this->addLocal(Local);
- }
-
/// Like addExtended, but adds to the nearest scope of the given kind.
void addForScopeKind(const Scope::Local &Local, ScopeKind Kind) {
VariableScope *P = this;
@@ -523,6 +498,7 @@ template <class Emitter> class VariableScope {
if (!P)
break;
}
+
// Add to this scope.
this->addLocal(Local);
}
@@ -542,7 +518,6 @@ template <class Emitter> class VariableScope {
Compiler<Emitter> *Ctx;
/// Link to the parent scope.
VariableScope *Parent;
- const ValueDecl *ValDecl = nullptr;
ScopeKind Kind;
};
@@ -550,9 +525,7 @@ template <class Emitter> class VariableScope {
template <class Emitter> class LocalScope : public VariableScope<Emitter> {
public:
LocalScope(Compiler<Emitter> *Ctx, ScopeKind Kind = ScopeKind::Block)
- : VariableScope<Emitter>(Ctx, nullptr, Kind) {}
- LocalScope(Compiler<Emitter> *Ctx, const ValueDecl *VD)
- : VariableScope<Emitter>(Ctx, VD) {}
+ : VariableScope<Emitter>(Ctx, Kind) {}
/// Emit a Destroy op for this scope.
~LocalScope() override {
More information about the cfe-commits
mailing list