Skip to content

Commit d762dd5

Browse files
committed
Stop parsing into IfConfiDecl nodes in the C++ parser
When parsing #if...#endif regions, parse the active clause directly into place in the AST without ever producing an IfConfigDecl instance.
1 parent 4bb9a58 commit d762dd5

File tree

11 files changed

+105
-115
lines changed

11 files changed

+105
-115
lines changed

include/swift/Parse/Parser.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -977,10 +977,10 @@ class Parser {
977977

978978
void consumeDecl(ParserPosition BeginParserPosition, bool IsTopLevel);
979979

980-
ParserResult<Decl> parseDecl(bool IsAtStartOfLineOrPreviousHadSemi,
981-
bool IfConfigsAreDeclAttrs,
982-
llvm::function_ref<void(Decl *)> Handler,
983-
bool fromASTGen = false);
980+
ParserStatus parseDecl(bool IsAtStartOfLineOrPreviousHadSemi,
981+
bool IfConfigsAreDeclAttrs,
982+
llvm::function_ref<void(Decl *)> Handler,
983+
bool fromASTGen = false);
984984

985985
std::pair<std::vector<Decl *>, std::optional<Fingerprint>>
986986
parseDeclListDelayed(IterableDeclContext *IDC);
@@ -1018,9 +1018,9 @@ class Parser {
10181018

10191019
/// Parse a #if ... #endif directive.
10201020
/// Delegate callback function to parse elements in the blocks.
1021-
ParserResult<IfConfigDecl> parseIfConfig(
1021+
ParserStatus parseIfConfig(
10221022
IfConfigContext ifConfigContext,
1023-
llvm::function_ref<void(SmallVectorImpl<ASTNode> &, bool)> parseElements);
1023+
llvm::function_ref<void(bool)> parseElements);
10241024

10251025
/// Parse an #if ... #endif containing only attributes.
10261026
ParserStatus parseIfConfigDeclAttributes(

lib/Parse/ParseBridging.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ BridgedExpr BridgedLegacyParser_parseExpr(BridgedLegacyParser p,
3535
return result.getPtrOrNull();
3636
}
3737

38+
// FIXME: We need to be able to return multiple declarations here.
3839
BridgedDecl BridgedLegacyParser_parseDecl(BridgedLegacyParser p,
3940
BridgedSourceLoc loc,
4041
BridgedDeclContext DC) {
@@ -47,11 +48,16 @@ BridgedDecl BridgedLegacyParser_parseDecl(BridgedLegacyParser p,
4748
// FIXME: IsAtStartOfLineOrPreviousHadSemi should be passed in from ASTGen.
4849
// IfConfigsAreDeclAttrs: true because ASTGen thinks the current location is
4950
// a start of a decl.
50-
ParserResult<Decl> result = P.parseDecl(
51+
Decl *resultDecl = nullptr;
52+
P.parseDecl(
5153
/*IsAtStartOfLineOrPreviousHadSemi=*/true,
52-
/*IfConfigsAreDeclAttrs=*/true, [&](Decl *decl) {},
54+
/*IfConfigsAreDeclAttrs=*/true, [&](Decl *decl) {
55+
// FIXME: We need to capture all of these declarations, not just
56+
// the last one.
57+
resultDecl = decl;
58+
},
5359
/*fromASTGen=*/true);
54-
return result.getPtrOrNull();
60+
return resultDecl;
5561
}
5662

5763
BridgedStmt BridgedLegacyParser_parseStmt(BridgedLegacyParser p,

lib/Parse/ParseDecl.cpp

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6247,13 +6247,17 @@ static Parser::ParseDeclOptions getParseDeclOptions(DeclContext *DC) {
62476247
///
62486248
/// \param fromASTGen If true , this function in called from ASTGen as the
62496249
/// fallback, so do not attempt a callback to ASTGen.
6250-
ParserResult<Decl> Parser::parseDecl(bool IsAtStartOfLineOrPreviousHadSemi,
6251-
bool IfConfigsAreDeclAttrs,
6252-
llvm::function_ref<void(Decl *)> Handler,
6253-
bool fromASTGen) {
6250+
ParserStatus Parser::parseDecl(bool IsAtStartOfLineOrPreviousHadSemi,
6251+
bool IfConfigsAreDeclAttrs,
6252+
llvm::function_ref<void(Decl *)> Handler,
6253+
bool fromASTGen) {
62546254
#if SWIFT_BUILD_SWIFT_SYNTAX
6255-
if (IsForASTGen && !fromASTGen)
6256-
return parseDeclFromSyntaxTree();
6255+
if (IsForASTGen && !fromASTGen) {
6256+
auto result = parseDeclFromSyntaxTree();
6257+
if (auto resultDecl = result.getPtrOrNull())
6258+
Handler(resultDecl);
6259+
return result;
6260+
}
62576261
#endif
62586262
ParseDeclOptions Flags = getParseDeclOptions(CurDeclContext);
62596263
ParserPosition BeginParserPosition;
@@ -6263,33 +6267,25 @@ ParserResult<Decl> Parser::parseDecl(bool IsAtStartOfLineOrPreviousHadSemi,
62636267
if (Tok.is(tok::pound_if) && !ifConfigContainsOnlyAttributes()) {
62646268
auto IfConfigResult = parseIfConfig(
62656269
IfConfigContext::DeclItems,
6266-
[&](SmallVectorImpl<ASTNode> &Decls, bool IsActive) {
6270+
[&](bool IsActive) {
62676271
ParserStatus Status;
62686272
bool PreviousHadSemi = true;
62696273
while (Tok.isNot(tok::pound_else, tok::pound_endif, tok::pound_elseif,
62706274
tok::r_brace, tok::eof)) {
62716275
Status |= parseDeclItem(PreviousHadSemi,
6272-
[&](Decl *D) { Decls.emplace_back(D); });
6276+
[&](Decl *D) {
6277+
if (IsActive) {
6278+
Handler(D);
6279+
}
6280+
});
62736281
}
62746282
});
62756283
if (IfConfigResult.hasCodeCompletion() && isIDEInspectionFirstPass()) {
62766284
consumeDecl(BeginParserPosition, CurDeclContext->isModuleScopeContext());
62776285
return makeParserError();
62786286
}
62796287

6280-
if (auto ICD = IfConfigResult.getPtrOrNull()) {
6281-
// The IfConfigDecl is ahead of its members in source order.
6282-
Handler(ICD);
6283-
// Copy the active members into the entries list.
6284-
for (auto activeMember : ICD->getActiveClauseElements()) {
6285-
auto *D = activeMember.get<Decl*>();
6286-
if (isa<IfConfigDecl>(D))
6287-
// Don't hoist nested '#if'.
6288-
continue;
6289-
Handler(D);
6290-
}
6291-
}
6292-
return IfConfigResult;
6288+
return makeParserSuccess();
62936289
}
62946290
if (Tok.isAny(tok::pound_warning, tok::pound_error)) {
62956291
auto Result = parseDeclPoundDiagnostic();
@@ -7050,15 +7046,19 @@ ParserStatus Parser::parseDeclItem(bool &PreviousHadSemi,
70507046
return LineDirectiveStatus;
70517047
}
70527048

7053-
ParserResult<Decl> Result =
7049+
Decl *LastResultDecl = nullptr;
7050+
ParserStatus Result =
70547051
parseDecl(IsAtStartOfLineOrPreviousHadSemi,
7055-
/* IfConfigsAreDeclAttrs=*/false, handler);
7056-
if (Result.isParseErrorOrHasCompletion())
7052+
/* IfConfigsAreDeclAttrs=*/false, [&](Decl *decl) {
7053+
handler(decl);
7054+
LastResultDecl = decl;
7055+
});
7056+
if (Result.isErrorOrHasCompletion())
70577057
skipUntilDeclRBrace(tok::semi, tok::pound_endif);
70587058
SourceLoc SemiLoc;
70597059
PreviousHadSemi = consumeIf(tok::semi, SemiLoc);
7060-
if (PreviousHadSemi && Result.isNonNull())
7061-
Result.get()->TrailingSemiLoc = SemiLoc;
7060+
if (PreviousHadSemi && LastResultDecl)
7061+
LastResultDecl->TrailingSemiLoc = SemiLoc;
70627062
return Result;
70637063
}
70647064

lib/Parse/ParseExpr.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,10 +1478,11 @@ Parser::parseExprPostfixSuffix(ParserResult<Expr> Result, bool isExprBasic,
14781478
.fixItInsert(getEndOfPreviousLoc(), "\n");
14791479
}
14801480

1481+
llvm::TinyPtrVector<ASTNode> activeElements;
14811482
llvm::SmallPtrSet<Expr *, 4> exprsWithBindOptional;
14821483
auto ICD = parseIfConfig(
14831484
IfConfigContext::PostfixExpr,
1484-
[&](SmallVectorImpl<ASTNode> &elements, bool isActive) {
1485+
[&](bool isActive) {
14851486
// Although we know the '#if' body starts with period,
14861487
// '#elseif'/'#else' bodies might start with invalid tokens.
14871488
if (isAtStartOfPostfixExprSuffix() || Tok.is(tok::pound_if)) {
@@ -1491,13 +1492,14 @@ Parser::parseExprPostfixSuffix(ParserResult<Expr> Result, bool isExprBasic,
14911492
exprHasBindOptional);
14921493
if (exprHasBindOptional)
14931494
exprsWithBindOptional.insert(expr.get());
1494-
elements.push_back(expr.get());
1495+
1496+
if (isActive)
1497+
activeElements.push_back(expr.get());
14951498
}
14961499
});
1497-
if (ICD.isNull())
1500+
if (ICD.isErrorOrHasCompletion())
14981501
break;
14991502

1500-
auto activeElements = ICD.get()->getActiveClauseElements();
15011503
if (activeElements.empty())
15021504
// There's no active clause, or it was empty. Keep the current result.
15031505
continue;

lib/Parse/ParseIfConfig.cpp

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -972,31 +972,22 @@ Result Parser::parseIfConfigRaw(
972972
return finish(EndLoc, HadMissingEnd);
973973
}
974974

975-
/// Parse and populate a #if ... #endif directive.
975+
// Parse and populate a #if ... #endif directive.
976976
/// Delegate callback function to parse elements in the blocks.
977-
ParserResult<IfConfigDecl> Parser::parseIfConfig(
977+
ParserStatus Parser::parseIfConfig(
978978
IfConfigContext ifConfigContext,
979-
llvm::function_ref<void(SmallVectorImpl<ASTNode> &, bool)> parseElements) {
980-
SmallVector<IfConfigClause, 4> clauses;
981-
return parseIfConfigRaw<ParserResult<IfConfigDecl>>(
979+
llvm::function_ref<void(bool)> parseElements) {
980+
ParserStatus status = makeParserSuccess();
981+
return parseIfConfigRaw<ParserStatus>(
982982
ifConfigContext,
983983
[&](SourceLoc clauseLoc, Expr *condition, bool isActive,
984984
IfConfigElementsRole role) {
985-
SmallVector<ASTNode, 16> elements;
986985
if (role != IfConfigElementsRole::Skipped)
987-
parseElements(elements, isActive);
988-
if (role == IfConfigElementsRole::SyntaxOnly)
989-
elements.clear();
990-
991-
clauses.emplace_back(
992-
clauseLoc, condition, Context.AllocateCopy(elements), isActive);
986+
parseElements(isActive);
993987
},
994988
[&](SourceLoc endLoc, bool hadMissingEnd) {
995-
auto *ICD = new (Context) IfConfigDecl(CurDeclContext,
996-
Context.AllocateCopy(clauses),
997-
endLoc, hadMissingEnd);
998-
return makeParserResult(ICD);
999-
});
989+
return status;
990+
});
1000991
}
1001992

1002993
ParserStatus Parser::parseIfConfigDeclAttributes(

lib/Parse/ParseStmt.cpp

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -369,35 +369,31 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
369369
// Parse the decl, stmt, or expression.
370370
PreviousHadSemi = false;
371371
if (Tok.is(tok::pound_if) && !isStartOfSwiftDecl()) {
372+
SmallVector<ASTNode, 16> activeElements;
372373
auto IfConfigResult = parseIfConfig(
373374
IfConfigContext::BraceItems,
374-
[&](SmallVectorImpl<ASTNode> &Elements, bool IsActive) {
375-
parseBraceItems(Elements, Kind,
375+
[&](bool IsActive) {
376+
SmallVector<ASTNode, 16> elements;
377+
parseBraceItems(elements, Kind,
376378
IsActive
377379
? BraceItemListKind::ActiveConditionalBlock
378380
: BraceItemListKind::InactiveConditionalBlock,
379381
IsFollowingGuard);
382+
383+
if (IsActive)
384+
activeElements = std::move(elements);
380385
});
381386
if (IfConfigResult.hasCodeCompletion() && isIDEInspectionFirstPass()) {
382387
consumeDecl(BeginParserPosition, IsTopLevel);
383388
return IfConfigResult;
384389
}
385390
BraceItemsStatus |= IfConfigResult;
386-
if (auto ICD = IfConfigResult.getPtrOrNull()) {
387-
Result = ICD;
388-
// Add the #if block itself
389-
Entries.push_back(ICD);
390-
391-
for (auto &Entry : ICD->getActiveClauseElements()) {
392-
if (Entry.is<Decl *>() && isa<IfConfigDecl>(Entry.get<Decl *>()))
393-
// Don't hoist nested '#if'.
394-
continue;
395-
Entries.push_back(Entry);
396-
}
397-
} else {
391+
if (IfConfigResult.isError()) {
398392
NeedParseErrorRecovery = true;
399393
continue;
400394
}
395+
396+
Entries.append(activeElements);
401397
} else if (Tok.is(tok::pound_line)) {
402398
ParserStatus Status = parseLineDirective(true);
403399
BraceItemsStatus |= Status;
@@ -408,7 +404,7 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
408404
NeedParseErrorRecovery = Status.isErrorOrHasCompletion();
409405
} else if (isStartOfSwiftDecl()) {
410406
SmallVector<Decl*, 8> TmpDecls;
411-
ParserResult<Decl> DeclResult =
407+
ParserStatus DeclResult =
412408
parseDecl(IsAtStartOfLineOrPreviousHadSemi,
413409
/*IfConfigsAreDeclAttrs=*/true, [&](Decl *D) {
414410
TmpDecls.push_back(D);
@@ -423,16 +419,22 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
423419
FD->setHasTopLevelLocalContextCaptures();
424420
});
425421
BraceItemsStatus |= DeclResult;
426-
if (DeclResult.isParseErrorOrHasCompletion()) {
422+
if (DeclResult.isErrorOrHasCompletion()) {
427423
NeedParseErrorRecovery = true;
428424
if (DeclResult.hasCodeCompletion() && IsTopLevel &&
429425
isIDEInspectionFirstPass()) {
430426
consumeDecl(BeginParserPosition, IsTopLevel);
431427
return DeclResult;
432428
}
433429
}
434-
Result = DeclResult.getPtrOrNull();
435430
Entries.append(TmpDecls.begin(), TmpDecls.end());
431+
432+
// HACK: If any declarations were parsed, make the last one the "result".
433+
// We should know whether this was in an #if or not.
434+
if (!TmpDecls.empty()) {
435+
Result = TmpDecls.back();
436+
}
437+
436438
} else if (IsTopLevel) {
437439
// If this is a statement or expression at the top level of the module,
438440
// Parse it as a child of a TopLevelCodeDecl.
@@ -2661,25 +2663,15 @@ Parser::parseStmtCases(SmallVectorImpl<ASTNode> &cases, bool IsActive) {
26612663
// clauses.
26622664
auto IfConfigResult =
26632665
parseIfConfig(IfConfigContext::SwitchStmt,
2664-
[&](SmallVectorImpl<ASTNode> &Elements, bool IsActive) {
2665-
parseStmtCases(Elements, IsActive);
2666+
[&](bool IsActive) {
2667+
SmallVector<ASTNode, 16> elements;
2668+
parseStmtCases(elements, IsActive);
2669+
2670+
if (IsActive) {
2671+
cases.append(elements);
2672+
}
26662673
});
26672674
Status |= IfConfigResult;
2668-
if (auto ICD = IfConfigResult.getPtrOrNull()) {
2669-
cases.emplace_back(ICD);
2670-
2671-
for (auto &Entry : ICD->getActiveClauseElements()) {
2672-
if (Entry.is<Decl*>() &&
2673-
(isa<IfConfigDecl>(Entry.get<Decl*>())))
2674-
// Don't hoist nested '#if'.
2675-
continue;
2676-
2677-
assert((Entry.is<Stmt*>() && isa<CaseStmt>(Entry.get<Stmt*>())) ||
2678-
(Entry.is<Decl*>() &&
2679-
isa<PoundDiagnosticDecl>(Entry.get<Decl*>())));
2680-
cases.push_back(Entry);
2681-
}
2682-
}
26832675
} else if (Tok.is(tok::pound_warning) || Tok.is(tok::pound_error)) {
26842676
auto PoundDiagnosticResult = parseDeclPoundDiagnostic();
26852677
Status |= PoundDiagnosticResult;

lib/Parse/Parser.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -822,9 +822,11 @@ bool Parser::parseEndIfDirective(SourceLoc &Loc) {
822822
Loc = PreviousLoc;
823823
skipUntilConditionalBlockClose();
824824
return true;
825-
} else if (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof))
825+
} else if (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) {
826826
diagnose(Tok.getLoc(),
827827
diag::extra_tokens_conditional_compilation_directive);
828+
skipUntilTokenOrEndOfLine(tok::NUM_TOKENS);
829+
}
828830
return false;
829831
}
830832

test/Frontend/dump-parse.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func bar() {
3131
// CHECK-LABEL: (enum_decl{{.*}}trailing_semi "TrailingSemi"
3232
enum TrailingSemi {
3333

34-
// CHECK-LABEL: (enum_case_decl{{.*}}trailing_semi
34+
// CHECK-LABEL: (enum_case_decl
3535
// CHECK-NOT: (enum_element_decl{{.*}}trailing_semi
3636
// CHECK: (enum_element_decl{{.*}}"A")
3737
// CHECK: (enum_element_decl{{.*}}"B")
@@ -41,7 +41,7 @@ enum TrailingSemi {
4141
// CHECK-NOT: (func_decl{{.*}}trailing_semi <anonymous @ 0x{{[0-9a-f]+}}> get for="subscript(_:)"
4242
// CHECK: (accessor_decl{{.*}} <anonymous @ 0x{{[0-9a-f]+}}> get for="subscript(_:)"
4343
subscript(x: Int) -> Int {
44-
// CHECK-LABEL: (pattern_binding_decl{{.*}}trailing_semi
44+
// CHECK-LABEL: (pattern_binding_decl{{.*}}
4545
// CHECK-NOT: (var_decl{{.*}}trailing_semi "y"
4646
// CHECK: (var_decl{{.*}}"y"
4747
var y = 1;

test/IDE/print_source_file_interface_1.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33

44
// More blah blah.
55

6-
#if FOO
76
import Swift
87

8+
#if FOO
99
class FooEnabled {}
1010

1111
typealias MyN = Int
1212
#else
13-
import Swift
14-
1513
class FooDisabled {}
1614

1715
typealias MyN = Int

0 commit comments

Comments
 (0)