Skip to content

Commit 782863c

Browse files
authored
Merge pull request #33795 from slavapestov/hoisted-decls-for-lldb
Re-implement DebuggerContextChange using a new mechanism
2 parents ca72167 + f3e7963 commit 782863c

File tree

11 files changed

+105
-83
lines changed

11 files changed

+105
-83
lines changed

include/swift/AST/Decl.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ class alignas(1 << DeclAlignInBits) Decl {
284284
protected:
285285
union { uint64_t OpaqueBits;
286286

287-
SWIFT_INLINE_BITFIELD_BASE(Decl, bitmax(NumDeclKindBits,8)+1+1+1+1,
287+
SWIFT_INLINE_BITFIELD_BASE(Decl, bitmax(NumDeclKindBits,8)+1+1+1+1+1,
288288
Kind : bitmax(NumDeclKindBits,8),
289289

290290
/// Whether this declaration is invalid.
@@ -301,7 +301,13 @@ class alignas(1 << DeclAlignInBits) Decl {
301301

302302
/// Whether this declaration was added to the surrounding
303303
/// DeclContext of an active #if config clause.
304-
EscapedFromIfConfig : 1
304+
EscapedFromIfConfig : 1,
305+
306+
/// Whether this declaration is syntactically scoped inside of
307+
/// a local context, but should behave like a top-level
308+
/// declaration for name lookup purposes. This is used by
309+
/// lldb.
310+
Hoisted : 1
305311
);
306312

307313
SWIFT_INLINE_BITFIELD_FULL(PatternBindingDecl, Decl, 1+2+16,
@@ -690,6 +696,7 @@ class alignas(1 << DeclAlignInBits) Decl {
690696
Bits.Decl.Implicit = false;
691697
Bits.Decl.FromClang = false;
692698
Bits.Decl.EscapedFromIfConfig = false;
699+
Bits.Decl.Hoisted = false;
693700
}
694701

695702
/// Get the Clang node associated with this declaration.
@@ -837,6 +844,16 @@ class alignas(1 << DeclAlignInBits) Decl {
837844
/// Mark this declaration as implicit.
838845
void setImplicit(bool implicit = true) { Bits.Decl.Implicit = implicit; }
839846

847+
/// Determine whether this declaration is syntactically scoped inside of
848+
/// a local context, but should behave like a top-level declaration
849+
/// for name lookup purposes. This is used by lldb.
850+
bool isHoisted() const { return Bits.Decl.Hoisted; }
851+
852+
/// Set whether this declaration should be syntactically scoped inside
853+
/// of a local context, but should behave like a top-level declaration,
854+
/// but should behave like a top-level declaration. This is used by lldb.
855+
void setHoisted(bool hoisted = true) { Bits.Decl.Hoisted = hoisted; }
856+
840857
public:
841858
bool escapedFromIfConfig() const {
842859
return Bits.Decl.EscapedFromIfConfig;

include/swift/AST/SourceFile.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ class SourceFile final : public FileUnit {
187187
/// have been removed, this can become an optional ArrayRef.
188188
Optional<std::vector<Decl *>> Decls;
189189

190+
/// The list of hoisted declarations. See Decl::isHoisted().
191+
/// This is only used by lldb.
192+
std::vector<Decl *> Hoisted;
193+
190194
using SeparatelyImportedOverlayMap =
191195
llvm::SmallDenseMap<ModuleDecl *, llvm::SmallPtrSet<ModuleDecl *, 1>>;
192196

@@ -231,9 +235,18 @@ class SourceFile final : public FileUnit {
231235
Decls->insert(Decls->begin(), d);
232236
}
233237

238+
/// Add a hoisted declaration. See Decl::isHoisted().
239+
void addHoistedDecl(Decl *d) {
240+
Hoisted.push_back(d);
241+
}
242+
234243
/// Retrieves an immutable view of the list of top-level decls in this file.
235244
ArrayRef<Decl *> getTopLevelDecls() const;
236245

246+
/// Retrieves an immutable view of the list of hoisted decls in this file.
247+
/// See Decl::isHoisted().
248+
ArrayRef<Decl *> getHoistedDecls() const;
249+
237250
/// Retrieves an immutable view of the top-level decls if they have already
238251
/// been parsed, or \c None if they haven't. Should only be used for dumping.
239252
Optional<ArrayRef<Decl *>> getCachedTopLevelDecls() const {

include/swift/Parse/Parser.h

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,6 @@ class Parser {
125125
CodeCompletionCallbacks *CodeCompletion = nullptr;
126126
std::vector<Located<std::vector<ParamDecl*>>> AnonClosureVars;
127127

128-
/// Tracks parsed decls that LLDB requires to be inserted at the top-level.
129-
std::vector<Decl *> ContextSwitchedTopLevelDecls;
130-
131128
/// The current token hash, or \c None if the parser isn't computing a hash
132129
/// for the token stream.
133130
Optional<llvm::MD5> CurrentTokenHash;
@@ -146,7 +143,6 @@ class Parser {
146143
ArrayRef<VarDecl *> DisabledVars;
147144
Diag<> DisabledVarReason;
148145

149-
llvm::SmallPtrSet<Decl *, 2> AlreadyHandledDecls;
150146
enum {
151147
/// InVarOrLetPattern has this value when not parsing a pattern.
152148
IVOLP_NotInVarOrLet,
@@ -930,14 +926,8 @@ class Parser {
930926
void consumeDecl(ParserPosition BeginParserPosition, ParseDeclOptions Flags,
931927
bool IsTopLevel);
932928

933-
// When compiling for the Debugger, some Decl's need to be moved from the
934-
// current scope. In which case although the Decl will be returned in the
935-
// ParserResult, it should not be inserted into the Decl list for the current
936-
// context. markWasHandled asserts that the Decl is already where it
937-
// belongs, and declWasHandledAlready is used to check this assertion.
938-
// To keep the handled decl array small, we remove the Decl when it is
939-
// checked, so you can only call declWasAlreadyHandled once for a given
940-
// decl.
929+
/// FIXME: Remove this, it's vestigial.
930+
llvm::SmallPtrSet<Decl *, 2> AlreadyHandledDecls;
941931

942932
void markWasHandled(Decl *D) {
943933
AlreadyHandledDecls.insert(D);

lib/AST/ASTDumper.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,9 @@ namespace {
585585
if (D->isImplicit())
586586
PrintWithColorRAII(OS, DeclModifierColor) << " implicit";
587587

588+
if (D->isHoisted())
589+
PrintWithColorRAII(OS, DeclModifierColor) << " hoisted";
590+
588591
auto R = D->getSourceRange();
589592
if (R.isValid()) {
590593
PrintWithColorRAII(OS, RangeColor) << " range=";

lib/AST/Module.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ SourceLookupCache::SourceLookupCache(const SourceFile &SF) {
312312
FrontendStatsTracer tracer(SF.getASTContext().Stats,
313313
"source-file-populate-cache");
314314
addToUnqualifiedLookupCache(SF.getTopLevelDecls(), false);
315+
addToUnqualifiedLookupCache(SF.getHoistedDecls(), false);
315316
}
316317

317318
SourceLookupCache::SourceLookupCache(const ModuleDecl &M) {
@@ -322,8 +323,9 @@ SourceLookupCache::SourceLookupCache(const ModuleDecl &M) {
322323
addToUnqualifiedLookupCache(SFU->getTopLevelDecls(), false);
323324
continue;
324325
}
325-
auto &SF = *cast<SourceFile>(file);
326-
addToUnqualifiedLookupCache(SF.getTopLevelDecls(), false);
326+
auto *SF = cast<SourceFile>(file);
327+
addToUnqualifiedLookupCache(SF->getTopLevelDecls(), false);
328+
addToUnqualifiedLookupCache(SF->getHoistedDecls(), false);
327329
}
328330
}
329331

@@ -2342,6 +2344,10 @@ ArrayRef<Decl *> SourceFile::getTopLevelDecls() const {
23422344
{}).TopLevelDecls;
23432345
}
23442346

2347+
ArrayRef<Decl *> SourceFile::getHoistedDecls() const {
2348+
return Hoisted;
2349+
}
2350+
23452351
bool FileUnit::walk(ASTWalker &walker) {
23462352
SmallVector<Decl *, 64> Decls;
23472353
getTopLevelDecls(Decls);

lib/IRGen/GenDecl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,13 +449,15 @@ void IRGenModule::emitSourceFile(SourceFile &SF) {
449449
// Emit types and other global decls.
450450
for (auto *decl : SF.getTopLevelDecls())
451451
emitGlobalDecl(decl);
452+
for (auto *decl : SF.getHoistedDecls())
453+
emitGlobalDecl(decl);
452454
for (auto *localDecl : SF.LocalTypeDecls)
453455
emitGlobalDecl(localDecl);
454456
for (auto *opaqueDecl : SF.getOpaqueReturnTypeDecls())
455457
maybeEmitOpaqueTypeDecl(opaqueDecl);
456458

457459
SF.collectLinkLibraries([this](LinkLibrary linkLib) {
458-
this->addLinkLibrary(linkLib);
460+
this->addLinkLibrary(linkLib);
459461
});
460462

461463
if (ObjCInterop)

lib/Parse/ParseDecl.cpp

Lines changed: 33 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -60,48 +60,34 @@ namespace {
6060
/// file scope level so it will be set up correctly for this purpose.
6161
///
6262
/// Creating an instance of this object will cause it to figure out
63-
/// whether we are in the debugger function, whether it needs to swap
63+
/// whether we are in the debugger function, and whether it needs to swap
6464
/// the Decl that is currently being parsed.
65-
/// If you have created the object, instead of returning the result
66-
/// with makeParserResult, use the object's fixupParserResult. If
67-
/// no swap has occurred, these methods will work the same.
68-
/// If the decl has been moved, then Parser::markWasHandled will be
69-
/// called on the Decl, and you should call declWasHandledAlready
70-
/// before you consume the Decl to see if you actually need to
71-
/// consume it.
65+
///
7266
/// If you are making one of these objects to address issue 1, call
7367
/// the constructor that only takes a DeclKind, and it will be moved
7468
/// unconditionally. Otherwise pass in the Name and DeclKind and the
7569
/// DebuggerClient will be asked whether to move it or not.
7670
class DebuggerContextChange {
7771
protected:
7872
Parser &P;
79-
Identifier Name;
80-
SourceFile *SF;
8173
Optional<Parser::ContextChange> CC;
74+
SourceFile *SF;
8275
public:
83-
DebuggerContextChange (Parser &P)
84-
: P(P), SF(nullptr) {
76+
DebuggerContextChange(Parser &P) : P(P), SF(nullptr) {
8577
if (!inDebuggerContext())
8678
return;
87-
else
88-
switchContext();
79+
80+
switchContext();
8981
}
9082

91-
DebuggerContextChange (Parser &P, Identifier &Name, DeclKind Kind)
92-
: P(P), Name(Name), SF(nullptr) {
83+
DebuggerContextChange(Parser &P, Identifier Name, DeclKind Kind)
84+
: P(P), SF(nullptr) {
9385
if (!inDebuggerContext())
9486
return;
95-
bool globalize = false;
96-
97-
DebuggerClient *debug_client = getDebuggerClient();
98-
if (!debug_client)
99-
return;
100-
101-
globalize = debug_client->shouldGlobalize(Name, Kind);
102-
103-
if (globalize)
104-
switchContext();
87+
88+
if (auto *client = getDebuggerClient())
89+
if (client->shouldGlobalize(Name, Kind))
90+
switchContext();
10591
}
10692

10793
bool movedToTopLevel() {
@@ -118,19 +104,21 @@ namespace {
118104
template <typename T>
119105
ParserResult<T>
120106
fixupParserResult(T *D) {
121-
if (CC.hasValue()) {
122-
swapDecl(D);
107+
if (movedToTopLevel()) {
108+
D->setHoisted();
109+
SF->addHoistedDecl(D);
110+
getDebuggerClient()->didGlobalize(D);
123111
}
124112
return ParserResult<T>(D);
125113
}
126114

127115
template <typename T>
128116
ParserResult<T>
129117
fixupParserResult(ParserStatus Status, T *D) {
130-
if (CC.hasValue() && !Status.isError()) {
131-
// If there is an error, don't do our splicing trick,
132-
// just return the Decl and the status for reporting.
133-
swapDecl(D);
118+
if (movedToTopLevel()) {
119+
D->setHoisted();
120+
SF->addHoistedDecl(D);
121+
getDebuggerClient()->didGlobalize(D);
134122
}
135123
return makeParserResult(Status, D);
136124
}
@@ -140,43 +128,29 @@ namespace {
140128
~DebuggerContextChange () {}
141129
protected:
142130

143-
DebuggerClient *getDebuggerClient()
144-
{
145-
ModuleDecl *PM = P.CurDeclContext->getParentModule();
146-
if (!PM)
147-
return nullptr;
148-
else
149-
return PM->getDebugClient();
131+
DebuggerClient *getDebuggerClient() {
132+
ModuleDecl *M = P.CurDeclContext->getParentModule();
133+
return M->getDebugClient();
150134
}
151135

152136
bool inDebuggerContext() {
153137
if (!P.Context.LangOpts.DebuggerSupport)
154138
return false;
155139
if (!P.CurDeclContext)
156140
return false;
157-
auto *func_decl = dyn_cast<FuncDecl>(P.CurDeclContext);
158-
if (!func_decl)
141+
auto *func = dyn_cast<FuncDecl>(P.CurDeclContext);
142+
if (!func)
159143
return false;
160-
161-
if (!func_decl->getAttrs().hasAttribute<LLDBDebuggerFunctionAttr>())
144+
145+
if (!func->getAttrs().hasAttribute<LLDBDebuggerFunctionAttr>())
162146
return false;
163-
147+
164148
return true;
165149
}
166150

167-
void switchContext () {
151+
void switchContext() {
168152
SF = P.CurDeclContext->getParentSourceFile();
169-
CC.emplace (P, SF);
170-
}
171-
172-
void swapDecl (Decl *D)
173-
{
174-
assert (SF);
175-
DebuggerClient *debug_client = getDebuggerClient();
176-
assert (debug_client);
177-
debug_client->didGlobalize(D);
178-
P.ContextSwitchedTopLevelDecls.push_back(D);
179-
P.markWasHandled(D);
153+
CC.emplace(P, SF);
180154
}
181155
};
182156
} // end anonymous namespace
@@ -225,10 +199,6 @@ void Parser::parseTopLevel(SmallVectorImpl<Decl *> &decls) {
225199
}
226200
}
227201

228-
// First append any decls that LLDB requires be inserted at the top-level.
229-
decls.append(ContextSwitchedTopLevelDecls.begin(),
230-
ContextSwitchedTopLevelDecls.end());
231-
232202
// Then append the top-level decls we parsed.
233203
for (auto item : items) {
234204
auto *decl = item.get<Decl *>();
@@ -7726,8 +7696,9 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags,
77267696
SourceLoc precedenceGroupLoc = consumeToken(tok::kw_precedencegroup);
77277697
DebuggerContextChange DCC (*this);
77287698

7729-
if (!CodeCompletion && !DCC.movedToTopLevel() && !(flags & PD_AllowTopLevel))
7730-
{
7699+
if (!CodeCompletion &&
7700+
!DCC.movedToTopLevel() &&
7701+
!(flags & PD_AllowTopLevel)) {
77317702
diagnose(precedenceGroupLoc, diag::decl_inner_scope);
77327703
return nullptr;
77337704
}

lib/SILGen/SILGen.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1889,6 +1889,12 @@ class SILGenModuleRAII {
18891889
SGM.visit(D);
18901890
}
18911891

1892+
for (Decl *D : sf->getHoistedDecls()) {
1893+
FrontendStatsTracer StatsTracer(SGM.getASTContext().Stats,
1894+
"SILgen-decl", D);
1895+
SGM.visit(D);
1896+
}
1897+
18921898
for (TypeDecl *TD : sf->LocalTypeDecls) {
18931899
FrontendStatsTracer StatsTracer(SGM.getASTContext().Stats,
18941900
"SILgen-tydecl", TD);

lib/SILGen/SILGenStmt.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,13 @@ void StmtEmitter::visitBraceStmt(BraceStmt *S) {
346346
} else if (auto *E = ESD.dyn_cast<Expr*>()) {
347347
SGF.emitIgnoredExpr(E);
348348
} else {
349-
SGF.visit(ESD.get<Decl*>());
349+
auto *D = ESD.get<Decl*>();
350+
351+
// Hoisted declarations are emitted at the top level by emitSourceFile().
352+
if (D->isHoisted())
353+
continue;
354+
355+
SGF.visit(D);
350356
}
351357
}
352358
}

lib/Sema/ImportResolution.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,8 @@ void swift::performImportResolution(SourceFile &SF) {
298298
// Resolve each import declaration.
299299
for (auto D : SF.getTopLevelDecls())
300300
resolver.visit(D);
301+
for (auto D : SF.getHoistedDecls())
302+
resolver.visit(D);
301303

302304
SF.setImports(resolver.getFinishedImports());
303305

lib/Sema/TypeChecker.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,11 +215,17 @@ void swift::bindExtensions(ModuleDecl &mod) {
215215
if (!SF)
216216
continue;
217217

218-
for (auto D : SF->getTopLevelDecls()) {
218+
auto visitTopLevelDecl = [&](Decl *D) {
219219
if (auto ED = dyn_cast<ExtensionDecl>(D))
220220
if (!tryBindExtension(ED))
221-
worklist.push_back(ED);
222-
}
221+
worklist.push_back(ED);;
222+
};
223+
224+
for (auto *D : SF->getTopLevelDecls())
225+
visitTopLevelDecl(D);
226+
227+
for (auto *D : SF->getHoistedDecls())
228+
visitTopLevelDecl(D);
223229
}
224230

225231
// Phase 2 - repeatedly go through the worklist and attempt to bind each

0 commit comments

Comments
 (0)