Skip to content

Commit cec1fa2

Browse files
committed
[Macros] Terminate parsing expanded members if no progress is made
Resolves rdar://108563022.
1 parent 3368e71 commit cec1fa2

File tree

3 files changed

+46
-2
lines changed

3 files changed

+46
-2
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,10 +2072,10 @@ WARNING(macro_expression_attribute_removed,PointsToFirstBadToken,
20722072
"@expression has been removed in favor of @freestanding(expression)", ())
20732073

20742074
ERROR(unexpected_attribute_expansion,PointsToFirstBadToken,
2075-
"unexpected token '%0' in expanded attribute list'",
2075+
"unexpected token '%0' in expanded attribute list",
20762076
(StringRef))
20772077
ERROR(unexpected_member_expansion,PointsToFirstBadToken,
2078-
"unexpected token '%0' in expanded member list'",
2078+
"unexpected token '%0' in expanded member list",
20792079
(StringRef))
20802080

20812081
ERROR(parser_round_trip_error,none,

lib/Parse/ParseDecl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7251,10 +7251,14 @@ void Parser::parseExpandedMemberList(SmallVectorImpl<ASTNode> &items) {
72517251
auto *idc = dyn_cast<IterableDeclContext>(decl);
72527252
bool previousHadSemi = true;
72537253

7254+
SourceLoc startingLoc = Tok.getLoc();
72547255
while (!Tok.is(tok::eof)) {
72557256
parseDeclItem(previousHadSemi,
72567257
getMemberParseDeclOptions(idc),
72577258
[&](Decl *d) { items.push_back(d); });
7259+
7260+
if (Tok.getLoc() == startingLoc)
7261+
break;
72587262
}
72597263

72607264
// Consume remaining tokens.

test/Macros/macro_invalid.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// REQUIRES: swift_swift_parser
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: split-file --leading-lines %s %t
5+
6+
// Create the plugin
7+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroPlugin) -module-name=MacroPlugin %t/MacroPlugin.swift -g -no-toolchain-stdlib-rpath
8+
9+
// RUN: not %target-swift-frontend -typecheck -swift-version 5 -load-plugin-library %t/%target-library-name(MacroPlugin) -module-name TestModule %t/TestModule.swift 2>&1 | %FileCheck %s
10+
// CHECK: unexpected token '}' in expanded member list
11+
12+
//--- MacroPlugin.swift
13+
import SwiftSyntax
14+
import SwiftSyntaxBuilder
15+
import SwiftSyntaxMacros
16+
17+
public struct InvalidMemberMacro: MemberMacro {
18+
public static func expansion(
19+
of node: AttributeSyntax,
20+
providingMembersOf decl: some DeclGroupSyntax,
21+
in context: some MacroExpansionContext
22+
) throws -> [DeclSyntax] {
23+
let invalidMember: DeclSyntax =
24+
"""
25+
// no member here
26+
}
27+
"""
28+
29+
return [
30+
invalidMember
31+
]
32+
}
33+
}
34+
35+
//--- TestModule.swift
36+
@attached(member)
37+
public macro InvalidMember() = #externalMacro(module: "MacroPlugin", type: "InvalidMemberMacro")
38+
39+
@InvalidMember
40+
struct TestStruct { }

0 commit comments

Comments
 (0)