@@ -25,10 +25,10 @@ namespace clang {
25
25
namespace interp {
26
26
27
27
// / Scope used to handle temporaries in toplevel variable declarations.
28
- template <class Emitter > class DeclScope final : public VariableScope <Emitter> {
28
+ template <class Emitter > class DeclScope final : public LocalScope <Emitter> {
29
29
public:
30
30
DeclScope (Compiler<Emitter> *Ctx, const ValueDecl *VD)
31
- : VariableScope <Emitter>(Ctx, nullptr ), Scope(Ctx->P, VD),
31
+ : LocalScope <Emitter>(Ctx, VD ), Scope(Ctx->P, VD),
32
32
OldGlobalDecl (Ctx->GlobalDecl),
33
33
OldInitializingDecl (Ctx->InitializingDecl) {
34
34
Ctx->GlobalDecl = Context::shouldBeGloballyIndexed (VD);
@@ -3462,40 +3462,52 @@ template <class Emitter> bool Compiler<Emitter>::visitExpr(const Expr *E) {
3462
3462
return false ;
3463
3463
}
3464
3464
3465
- // / Toplevel visitDecl().
3465
+ template <class Emitter >
3466
+ VarCreationState Compiler<Emitter>::visitDecl(const VarDecl *VD) {
3467
+
3468
+ auto R = this ->visitVarDecl (VD, /* Toplevel=*/ true );
3469
+
3470
+ if (R.notCreated ())
3471
+ return R;
3472
+
3473
+ if (R)
3474
+ return true ;
3475
+
3476
+ if (!R && Context::shouldBeGloballyIndexed (VD)) {
3477
+ if (auto GlobalIndex = P.getGlobal (VD)) {
3478
+ Block *GlobalBlock = P.getGlobal (*GlobalIndex);
3479
+ GlobalInlineDescriptor &GD =
3480
+ *reinterpret_cast <GlobalInlineDescriptor *>(GlobalBlock->rawData ());
3481
+
3482
+ GD.InitState = GlobalInitState::InitializerFailed;
3483
+ GlobalBlock->invokeDtor ();
3484
+ }
3485
+ }
3486
+
3487
+ return R;
3488
+ }
3489
+
3490
+ // / Toplevel visitDeclAndReturn().
3466
3491
// / We get here from evaluateAsInitializer().
3467
3492
// / We need to evaluate the initializer and return its value.
3468
3493
template <class Emitter >
3469
- bool Compiler<Emitter>::visitDecl(const VarDecl *VD, bool ConstantContext) {
3470
- assert (!VD->isInvalidDecl () && " Trying to constant evaluate an invalid decl" );
3471
-
3494
+ bool Compiler<Emitter>::visitDeclAndReturn(const VarDecl *VD,
3495
+ bool ConstantContext) {
3472
3496
std::optional<PrimType> VarT = classify (VD->getType ());
3473
3497
3474
3498
// We only create variables if we're evaluating in a constant context.
3475
3499
// Otherwise, just evaluate the initializer and return it.
3476
3500
if (!ConstantContext) {
3477
- DeclScope<Emitter> LocalScope (this , VD);
3501
+ DeclScope<Emitter> LS (this , VD);
3478
3502
if (!this ->visit (VD->getAnyInitializer ()))
3479
3503
return false ;
3480
- return this ->emitRet (VarT.value_or (PT_Ptr), VD);
3481
- }
3482
-
3483
- // If we've seen the global variable already and the initializer failed,
3484
- // just return false immediately.
3485
- if (std::optional<unsigned > Index = P.getGlobal (VD)) {
3486
- const Pointer &Ptr = P.getPtrGlobal (*Index);
3487
- const GlobalInlineDescriptor &GD =
3488
- *reinterpret_cast <const GlobalInlineDescriptor *>(
3489
- Ptr.block ()->rawData ());
3490
- if (GD.InitState == GlobalInitState::InitializerFailed)
3491
- return false ;
3504
+ return this ->emitRet (VarT.value_or (PT_Ptr), VD) && LS.destroyLocals ();
3492
3505
}
3493
3506
3494
- // Create and initialize the variable.
3507
+ LocalScope<Emitter> VDScope ( this , VD);
3495
3508
if (!this ->visitVarDecl (VD, /* Toplevel=*/ true ))
3496
3509
return false ;
3497
3510
3498
- // Get a pointer to the variable
3499
3511
if (Context::shouldBeGloballyIndexed (VD)) {
3500
3512
auto GlobalIndex = P.getGlobal (VD);
3501
3513
assert (GlobalIndex); // visitVarDecl() didn't return false.
@@ -3535,7 +3547,7 @@ bool Compiler<Emitter>::visitDecl(const VarDecl *VD, bool ConstantContext) {
3535
3547
return false ;
3536
3548
}
3537
3549
3538
- return true ;
3550
+ return VDScope. destroyLocals () ;
3539
3551
}
3540
3552
3541
3553
template <class Emitter >
@@ -3589,26 +3601,34 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, bool Topleve
3589
3601
3590
3602
return !Init || (checkDecl () && initGlobal (*GlobalIndex));
3591
3603
} else {
3592
- VariableScope<Emitter> LocalScope (this , VD);
3593
3604
InitLinkScope<Emitter> ILS (this , InitLink::Decl (VD));
3594
3605
3595
3606
if (VarT) {
3596
3607
unsigned Offset = this ->allocateLocalPrimitive (
3597
3608
VD, *VarT, VD->getType ().isConstQualified ());
3598
3609
if (Init) {
3599
- // Compile the initializer in its own scope.
3600
- ExprScope<Emitter> Scope (this );
3601
- if (!this ->visit (Init))
3602
- return false ;
3603
-
3604
- return this ->emitSetLocal (*VarT, Offset, VD);
3610
+ // If this is a toplevel declaration, create a scope for the
3611
+ // initializer.
3612
+ if (Toplevel) {
3613
+ ExprScope<Emitter> Scope (this );
3614
+ if (!this ->visit (Init))
3615
+ return false ;
3616
+ return this ->emitSetLocal (*VarT, Offset, VD);
3617
+ } else {
3618
+ if (!this ->visit (Init))
3619
+ return false ;
3620
+ return this ->emitSetLocal (*VarT, Offset, VD);
3621
+ }
3605
3622
}
3606
3623
} else {
3607
- if (std::optional<unsigned > Offset = this ->allocateLocal (VD))
3608
- return !Init || this ->visitLocalInitializer (Init, *Offset);
3624
+ if (std::optional<unsigned > Offset = this ->allocateLocal (VD)) {
3625
+ if (!Init)
3626
+ return true ;
3627
+
3628
+ return this ->visitLocalInitializer (Init, *Offset);
3629
+ }
3609
3630
return false ;
3610
3631
}
3611
-
3612
3632
return true ;
3613
3633
}
3614
3634
@@ -4074,7 +4094,7 @@ bool Compiler<Emitter>::visitCompoundStmt(const CompoundStmt *S) {
4074
4094
for (const auto *InnerStmt : S->body ())
4075
4095
if (!visitStmt (InnerStmt))
4076
4096
return false ;
4077
- return true ;
4097
+ return Scope. destroyLocals () ;
4078
4098
}
4079
4099
4080
4100
template <class Emitter >
@@ -5010,6 +5030,18 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
5010
5030
}
5011
5031
}
5012
5032
5033
+ // In case we need to re-visit a declaration.
5034
+ auto revisit = [&](const VarDecl *VD) -> bool {
5035
+ auto VarState = this ->visitDecl (VD);
5036
+
5037
+ if (VarState.notCreated ())
5038
+ return true ;
5039
+ if (!VarState)
5040
+ return false ;
5041
+ // Retry.
5042
+ return this ->visitDeclRef (D, E);
5043
+ };
5044
+
5013
5045
// Handle lambda captures.
5014
5046
if (auto It = this ->LambdaCaptures .find (D);
5015
5047
It != this ->LambdaCaptures .end ()) {
@@ -5020,12 +5052,8 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
5020
5052
return this ->emitGetPtrThisField (Offset, E);
5021
5053
} else if (const auto *DRE = dyn_cast<DeclRefExpr>(E);
5022
5054
DRE && DRE->refersToEnclosingVariableOrCapture ()) {
5023
- if (const auto *VD = dyn_cast<VarDecl>(D); VD && VD->isInitCapture ()) {
5024
- if (!this ->visitVarDecl (cast<VarDecl>(D)))
5025
- return false ;
5026
- // Retry.
5027
- return this ->visitDeclRef (D, E);
5028
- }
5055
+ if (const auto *VD = dyn_cast<VarDecl>(D); VD && VD->isInitCapture ())
5056
+ return revisit (VD);
5029
5057
}
5030
5058
5031
5059
if (D != InitializingDecl) {
@@ -5044,28 +5072,14 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
5044
5072
// Visit local const variables like normal.
5045
5073
if ((VD->hasGlobalStorage () || VD->isLocalVarDecl () ||
5046
5074
VD->isStaticDataMember ()) &&
5047
- typeShouldBeVisited (VD->getType ())) {
5048
- auto VarState = this ->visitVarDecl (VD, true );
5049
- if (VarState.notCreated ())
5050
- return true ;
5051
- if (!VarState)
5052
- return false ;
5053
- // Retry.
5054
- return this ->visitDeclRef (VD, E);
5055
- }
5075
+ typeShouldBeVisited (VD->getType ()))
5076
+ return revisit (VD);
5056
5077
}
5057
5078
} else {
5058
5079
if (const auto *VD = dyn_cast<VarDecl>(D);
5059
5080
VD && VD->getAnyInitializer () &&
5060
- VD->getType ().isConstant (Ctx.getASTContext ()) && !VD->isWeak ()) {
5061
- auto VarState = this ->visitVarDecl (VD, true );
5062
- if (VarState.notCreated ())
5063
- return true ;
5064
- if (!VarState)
5065
- return false ;
5066
- // Retry.
5067
- return this ->visitDeclRef (VD, E);
5068
- }
5081
+ VD->getType ().isConstant (Ctx.getASTContext ()) && !VD->isWeak ())
5082
+ return revisit (VD);
5069
5083
}
5070
5084
}
5071
5085
0 commit comments