Skip to content

Commit a8042b8

Browse files
committed
[Modules] Record whether VarDecl initializers contain side effects
Calling `DeclMustBeEmitted` should not lead to more deserialization, as it may occur before previous deserialization has finished. When passed a `VarDecl` with an initializer however, `DeclMustBeEmitted` needs to know whether that initializer contains side effects. When the `VarDecl` is deserialized but the initializer is not, this triggers deserialization of the initializer. To avoid this we add a bit to the serialization format for `VarDecl`s, indicating whether its initializer contains side effects or not, so that the `ASTReader` can query this information directly without deserializing the initializer. rdar://153085264
1 parent 93705c3 commit a8042b8

File tree

7 files changed

+41
-2
lines changed

7 files changed

+41
-2
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,11 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
13511351
return const_cast<VarDecl *>(this)->getInitializingDeclaration();
13521352
}
13531353

1354+
/// Checks whether this declaration has an initializer with side effects,
1355+
/// without triggering deserialization if the initializer is not yet
1356+
/// deserialized.
1357+
bool hasInitWithSideEffects() const;
1358+
13541359
/// Determine whether this variable's value might be usable in a
13551360
/// constant expression, according to the relevant language standard.
13561361
/// This only checks properties of the declaration, and does not check

clang/include/clang/AST/ExternalASTSource.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class RecordDecl;
5151
class Selector;
5252
class Stmt;
5353
class TagDecl;
54+
class VarDecl;
5455

5556
/// Abstract interface for external sources of AST nodes.
5657
///
@@ -195,6 +196,10 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
195196
/// module.
196197
virtual bool wasThisDeclarationADefinition(const FunctionDecl *FD);
197198

199+
virtual bool hasInitializerWithSideEffects(const VarDecl *VD) const {
200+
return false;
201+
}
202+
198203
/// Finds all declarations lexically contained within the given
199204
/// DeclContext, after applying an optional filter predicate.
200205
///

clang/include/clang/Serialization/ASTReader.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,6 +1442,10 @@ class ASTReader
14421442
const StringRef &operator*() && = delete;
14431443
};
14441444

1445+
/// VarDecls with initializers containing side effects must be emitted,
1446+
/// but DeclMustBeEmitted is not allowed to deserialize the intializer.
1447+
llvm::SmallPtrSet<Decl*, 16> InitSideEffectVars;
1448+
14451449
public:
14461450
/// Get the buffer for resolving paths.
14471451
SmallString<0> &getPathBuf() { return PathBuf; }
@@ -2392,6 +2396,8 @@ class ASTReader
23922396

23932397
bool wasThisDeclarationADefinition(const FunctionDecl *FD) override;
23942398

2399+
bool hasInitializerWithSideEffects(const VarDecl *VD) const override;
2400+
23952401
/// Retrieve a selector from the given module with its local ID
23962402
/// number.
23972403
Selector getLocalSelector(ModuleFile &M, unsigned LocalID);

clang/lib/AST/Decl.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2434,6 +2434,22 @@ VarDecl *VarDecl::getInitializingDeclaration() {
24342434
return Def;
24352435
}
24362436

2437+
bool VarDecl::hasInitWithSideEffects() const {
2438+
if (!hasInit())
2439+
return false;
2440+
2441+
if (auto *S = dyn_cast<Stmt *>(Init)) {
2442+
const Expr *E = cast<Expr>(S);
2443+
return E->HasSideEffects(getASTContext()) &&
2444+
// We can get a value-dependent initializer during error recovery.
2445+
(E->isValueDependent() || !evaluateValue());
2446+
}
2447+
2448+
// ASTReader tracks this without having to deserialize the initializer
2449+
return getASTContext().getExternalSource()->hasInitializerWithSideEffects(
2450+
this);
2451+
}
2452+
24372453
bool VarDecl::isOutOfLine() const {
24382454
if (Decl::isOutOfLine())
24392455
return true;

clang/lib/Serialization/ASTReader.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8310,8 +8310,6 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
83108310
Error(std::move(Err));
83118311
return nullptr;
83128312
}
8313-
assert(NumCurrentElementsDeserializing == 0 &&
8314-
"should not be called while already deserializing");
83158313
Deserializing D(this);
83168314
return ReadStmtFromStream(*Loc.F);
83178315
}
@@ -9712,6 +9710,10 @@ bool ASTReader::wasThisDeclarationADefinition(const FunctionDecl *FD) {
97129710
return ThisDeclarationWasADefinitionSet.contains(FD);
97139711
}
97149712

9713+
bool ASTReader::hasInitializerWithSideEffects(const VarDecl *VD) const {
9714+
return InitSideEffectVars.count(VD);
9715+
}
9716+
97159717
Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) {
97169718
return DecodeSelector(getGlobalSelectorID(M, LocalID));
97179719
}

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,6 +1632,10 @@ RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
16321632
VD->NonParmVarDeclBits.PreviousDeclInSameBlockScope =
16331633
VarDeclBits.getNextBit();
16341634

1635+
bool hasInitWithSideEffect = VarDeclBits.getNextBit();
1636+
if (hasInitWithSideEffect)
1637+
Reader.InitSideEffectVars.insert(VD);
1638+
16351639
VD->NonParmVarDeclBits.EscapingByref = VarDeclBits.getNextBit();
16361640
HasDeducedType = VarDeclBits.getNextBit();
16371641
VD->NonParmVarDeclBits.ImplicitParamKind =

clang/lib/Serialization/ASTWriterDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
12591259
VarDeclBits.addBit(D->isConstexpr());
12601260
VarDeclBits.addBit(D->isInitCapture());
12611261
VarDeclBits.addBit(D->isPreviousDeclInSameBlockScope());
1262+
VarDeclBits.addBit(D->hasInitWithSideEffects());
12621263

12631264
VarDeclBits.addBit(D->isEscapingByref());
12641265
HasDeducedType = D->getType()->getContainedDeducedType();

0 commit comments

Comments
 (0)