Skip to content

Commit 9d85221

Browse files
committed
Parse: Save and restore InFreestandingMacroArgument when delayed parsing
Closures appearing in freestanding macro arguments don't have discriminators assigned, since we don't actually emit them. Similarly we skip recording opaque return types that appear in macro arguments, since they don't get emitted. However this logic didn't take delayed parsing into account, which must save and restore the InFreestandingMacroArgument bit correctly. As a result, if the freestanding macro argument contained a closure which contained a local function with a declaration that has an opaque return type, we would crash in serialization from attempting to mangle an opaque return type nested inside of a closure without a discriminator. Fixes rdar://135445004
1 parent 5190d98 commit 9d85221

File tree

4 files changed

+40
-2
lines changed

4 files changed

+40
-2
lines changed

include/swift/AST/DeclContext.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,10 @@ class IterableDeclContext {
798798
/// while skipping the body of this context.
799799
unsigned HasNestedClassDeclarations : 1;
800800

801+
/// Whether we were inside a freestanding macro argument when we were parsed.
802+
/// We must restore this when delayed parsing the body.
803+
unsigned InFreestandingMacroArgument : 1;
804+
801805
template<class A, class B, class C>
802806
friend struct ::llvm::CastInfo;
803807

@@ -814,6 +818,7 @@ class IterableDeclContext {
814818
AddedParsedMembers = 0;
815819
HasOperatorDeclarations = 0;
816820
HasNestedClassDeclarations = 0;
821+
InFreestandingMacroArgument = 0;
817822
}
818823

819824
/// Determine the kind of iterable context we have.
@@ -841,6 +846,15 @@ class IterableDeclContext {
841846
HasNestedClassDeclarations = 1;
842847
}
843848

849+
bool inFreestandingMacroArgument() const {
850+
return InFreestandingMacroArgument;
851+
}
852+
853+
void setInFreestandingMacroArgument() {
854+
assert(hasUnparsedMembers());
855+
InFreestandingMacroArgument = 1;
856+
}
857+
844858
/// Retrieve the current set of members in this context.
845859
///
846860
/// NOTE: This operation is an alias of \c getCurrentMembers() that is considered

lib/Parse/ParseDecl.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7031,15 +7031,17 @@ bool Parser::parseMemberDeclList(SourceLoc &LBLoc, SourceLoc &RBLoc,
70317031
llvm::SaveAndRestore<std::optional<StableHasher>> T(CurrentTokenHash,
70327032
std::nullopt);
70337033

7034-
bool HasOperatorDeclarations;
7035-
bool HasNestedClassDeclarations;
7034+
bool HasOperatorDeclarations = false;
7035+
bool HasNestedClassDeclarations = false;
70367036

70377037
if (canDelayMemberDeclParsing(HasOperatorDeclarations,
70387038
HasNestedClassDeclarations)) {
70397039
if (HasOperatorDeclarations)
70407040
IDC->setMaybeHasOperatorDeclarations();
70417041
if (HasNestedClassDeclarations)
70427042
IDC->setMaybeHasNestedClassDeclarations();
7043+
if (InFreestandingMacroArgument)
7044+
IDC->setInFreestandingMacroArgument();
70437045

70447046
if (delayParsingDeclList(LBLoc, RBLoc, IDC))
70457047
return true;

lib/Parse/ParseRequests.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ ParseMembersRequest::evaluate(Evaluator &evaluator,
7575
// Lexer diagnostics have been emitted during skipping, so we disable lexer's
7676
// diagnostic engine here.
7777
Parser parser(bufferID, *sf, /*No Lexer Diags*/nullptr, nullptr, nullptr);
78+
parser.InFreestandingMacroArgument = idc->inFreestandingMacroArgument();
79+
7880
auto declsAndHash = parser.parseDeclListDelayed(idc);
7981
FingerprintAndMembers fingerprintAndMembers = {declsAndHash.second,
8082
declsAndHash.first};

test/Macros/delayed_parsing.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// REQUIRES: swift_swift_parser
2+
//
3+
// RUN: %empty-directory(%t)
4+
// RUN: %host-build-swift -swift-version 5 -parse-as-library -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath
5+
6+
// Type check testing
7+
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/delayed_parsing.swiftmodule -experimental-skip-non-inlinable-function-bodies-without-types -swift-version 5 -parse-as-library -load-plugin-library %t/%target-library-name(MacroDefinition) %s
8+
9+
@freestanding(declaration)
10+
macro freestandingWithClosure<T>(_ value: T, body: (T) -> T) = #externalMacro(module: "MacroDefinition", type: "EmptyDeclarationMacro")
11+
12+
#freestandingWithClosure(0) { (x: Int) in
13+
struct LocalStruct {
14+
func opaqueReturn() -> some Any {
15+
return 3
16+
}
17+
}
18+
19+
return x
20+
}

0 commit comments

Comments
 (0)