Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 40 additions & 31 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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 &&
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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>().
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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)
Expand All @@ -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;

Expand Down Expand Up @@ -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
Expand All @@ -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()))
Expand Down Expand Up @@ -5736,6 +5742,9 @@ template <class Emitter> bool Compiler<Emitter>::visitIfStmt(const IfStmt *IS) {
this->emitLabel(LabelEnd);
}

if (!IfScope.destroyLocals())
return false;

return true;
}

Expand Down Expand Up @@ -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()) {
Expand Down
37 changes: 5 additions & 32 deletions clang/lib/AST/ByteCode/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -523,6 +498,7 @@ template <class Emitter> class VariableScope {
if (!P)
break;
}

// Add to this scope.
this->addLocal(Local);
}
Expand All @@ -542,17 +518,14 @@ template <class Emitter> class VariableScope {
Compiler<Emitter> *Ctx;
/// Link to the parent scope.
VariableScope *Parent;
const ValueDecl *ValDecl = nullptr;
ScopeKind Kind;
};

/// Generic scope for local variables.
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 {
Expand Down
Loading