Skip to content

Commit f3e7963

Browse files
committed
Parse: Mark declarations as hoisted in DebuggerContextChange
Expression evaluation in lldb wraps the entire user-written expression in a new function body, which puts any new declarations written by the user in local context. There is a mechanism where declarations can get moved to the top level, if they're only valid at the top level (imports, extensions etc), or if the name of the declaration begins with '$'. This mechanism used to actually add the declaration to the SourceFile's TopLevelDecls list, which would break ASTScope invariants about source ranges being monotonically increasing and non-overlapping. Instead, we use the new 'hoisted' flag to mark the declarations as hoisted, which leaves them syntactically in their original location in the AST, but treats them as top level in SILGen and IRGen. Part of <rdar://problem/53971116>.
1 parent 0bedd20 commit f3e7963

File tree

2 files changed

+35
-74
lines changed

2 files changed

+35
-74
lines changed

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/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
}

0 commit comments

Comments
 (0)