Skip to content

Commit 2d53ae0

Browse files
authored
Merge pull request #66527 from DougGregor/freestanding-macro-cleanups-5.9
2 parents 66a38a1 + c72f379 commit 2d53ae0

17 files changed

+181
-24
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7052,6 +7052,16 @@ ERROR(macro_in_nested,none,
70527052
ERROR(macro_without_role,none,
70537053
"macro %0 must declare its applicable roles via '@freestanding' or @attached'",
70547054
(DeclName))
7055+
ERROR(macro_result_type_cannot_be_used,none,
7056+
"only a freestanding expression macro can produce a result of type %0",
7057+
(Type))
7058+
NOTE(macro_remove_result_type,none,
7059+
"remove the result type if the macro does not produce a value",
7060+
())
7061+
NOTE(macro_make_freestanding_expression,none,
7062+
"make this macro a freestanding expression macro", ())
7063+
ERROR(macro_multiple_freestanding_roles,none,
7064+
"macro can only have a single freestanding role", ())
70557065
ERROR(macro_expansion_missing_pound,none,
70567066
"expansion of macro %0 requires leading '#'", (DeclName))
70577067
ERROR(macro_expansion_missing_arguments,none,

lib/AST/ASTPrinter.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4780,16 +4780,14 @@ void PrintAST::visitMacroDecl(MacroDecl *decl) {
47804780
}
47814781
);
47824782

4783-
{
4783+
if (decl->resultType.getTypeRepr() ||
4784+
!decl->getResultInterfaceType()->isVoid()) {
47844785
Printer.printStructurePre(PrintStructureKind::DeclResultTypeClause);
47854786
SWIFT_DEFER {
47864787
Printer.printStructurePost(PrintStructureKind::DeclResultTypeClause);
47874788
};
47884789

4789-
if (decl->parameterList)
4790-
Printer << " -> ";
4791-
else
4792-
Printer << ": ";
4790+
Printer << " -> ";
47934791

47944792
TypeLoc resultTypeLoc(
47954793
decl->resultType.getTypeRepr(), decl->getResultInterfaceType());

lib/AST/Decl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3357,12 +3357,18 @@ TypeRepr *ValueDecl::getResultTypeRepr() const {
33573357
returnRepr = FD->getResultTypeRepr();
33583358
} else if (auto *SD = dyn_cast<SubscriptDecl>(this)) {
33593359
returnRepr = SD->getElementTypeRepr();
3360+
} else if (auto *MD = dyn_cast<MacroDecl>(this)) {
3361+
returnRepr = MD->resultType.getTypeRepr();
33603362
}
33613363

33623364
return returnRepr;
33633365
}
33643366

33653367
TypeRepr *ValueDecl::getOpaqueResultTypeRepr() const {
3368+
// FIXME: Macros don't allow opaque result types yet.
3369+
if (isa<MacroDecl>(this))
3370+
return nullptr;
3371+
33663372
auto *returnRepr = this->getResultTypeRepr();
33673373

33683374
auto *dc = getDeclContext();

lib/ASTGen/Sources/ASTGen/Macros.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ extension MacroRole {
6767
case 0x10: self = .member
6868
case 0x20: self = .peer
6969
case 0x40: self = .conformance
70+
case 0x80: self = .codeItem
71+
7072
default: fatalError("unknown macro role")
7173
}
7274
}
@@ -414,6 +416,7 @@ func expandFreestandingMacro(
414416
macroKind: UInt8,
415417
discriminatorText: UnsafePointer<UInt8>,
416418
discriminatorTextLength: Int,
419+
rawMacroRole: UInt8,
417420
sourceFilePtr: UnsafeRawPointer,
418421
sourceLocationPtr: UnsafePointer<UInt8>?,
419422
expandedSourcePointer: UnsafeMutablePointer<UnsafePointer<UInt8>?>,
@@ -446,18 +449,21 @@ func expandFreestandingMacro(
446449
)
447450
let discriminator = String(decoding: discriminatorBuffer, as: UTF8.self)
448451

452+
let macroRole = MacroRole(rawMacroRole: rawMacroRole)
449453
let expandedSource: String?
450454
switch MacroPluginKind(rawValue: macroKind)! {
451455
case .InProcess:
452456
expandedSource = expandFreestandingMacroInProcess(
453457
macroPtr: macroPtr,
458+
macroRole: macroRole,
454459
diagEnginePtr: diagEnginePtr,
455460
expansionSyntax: expansion,
456461
sourceFilePtr: sourceFilePtr,
457462
discriminator: discriminator)
458463
case .Executable:
459464
expandedSource = expandFreestandingMacroIPC(
460465
macroPtr: macroPtr,
466+
macroRole: macroRole,
461467
diagEnginePtr: diagEnginePtr,
462468
expansionSyntax: expansion,
463469
sourceFilePtr: sourceFilePtr,
@@ -485,6 +491,7 @@ func expandFreestandingMacro(
485491

486492
func expandFreestandingMacroIPC(
487493
macroPtr: UnsafeRawPointer,
494+
macroRole: MacroRole,
488495
diagEnginePtr: UnsafeMutablePointer<UInt8>,
489496
expansionSyntax: FreestandingMacroExpansionSyntax,
490497
sourceFilePtr: UnsafePointer<ExportedSourceFile>,
@@ -502,9 +509,21 @@ func expandFreestandingMacroIPC(
502509

503510
let macro = macroPtr.assumingMemoryBound(to: ExportedExecutableMacro.self).pointee
504511

512+
// Map the macro role.
513+
let pluginMacroRole: PluginMessage.MacroRole
514+
switch macroRole {
515+
case .accessor, .member, .memberAttribute, .peer, .conformance:
516+
preconditionFailure("unhandled macro role for freestanding macro")
517+
518+
case .expression: pluginMacroRole = .expression
519+
case .declaration: pluginMacroRole = .freeStandingDeclaration
520+
case .codeItem: pluginMacroRole = .codeItem
521+
}
522+
505523
// Send the message.
506524
let message = HostToPluginMessage.expandFreestandingMacro(
507525
macro: .init(moduleName: macro.moduleName, typeName: macro.typeName, name: macroName),
526+
macroRole: pluginMacroRole,
508527
discriminator: discriminator,
509528
syntax: PluginMessage.Syntax(syntax: Syntax(expansionSyntax), in: sourceFilePtr)!)
510529
do {
@@ -541,6 +560,7 @@ func expandFreestandingMacroIPC(
541560

542561
func expandFreestandingMacroInProcess(
543562
macroPtr: UnsafeRawPointer,
563+
macroRole: MacroRole,
544564
diagEnginePtr: UnsafeMutablePointer<UInt8>,
545565
expansionSyntax: FreestandingMacroExpansionSyntax,
546566
sourceFilePtr: UnsafePointer<ExportedSourceFile>,
@@ -580,6 +600,7 @@ func expandFreestandingMacroInProcess(
580600

581601
return SwiftSyntaxMacroExpansion.expandFreestandingMacro(
582602
definition: macro,
603+
macroRole: macroRole,
583604
node: node,
584605
in: context
585606
)

lib/ASTGen/Sources/ASTGen/PluginMessages.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ internal enum HostToPluginMessage: Codable {
2020
/// Expand a '@freestanding' macro.
2121
case expandFreestandingMacro(
2222
macro: PluginMessage.MacroReference,
23+
macroRole: PluginMessage.MacroRole? = nil,
2324
discriminator: String,
2425
syntax: PluginMessage.Syntax
2526
)
@@ -91,6 +92,7 @@ internal enum PluginToHostMessage: Codable {
9192
case member
9293
case peer
9394
case conformance
95+
case codeItem
9496
}
9597

9698
struct SourceLocation: Codable {

lib/IDETool/SyntacticMacroExpansion.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ void SyntacticMacroExpansionInstance::expand(
412412
SourceFile *SF, const MacroExpansionSpecifier &expansion,
413413
SourceEditConsumer &consumer) {
414414

415-
// Find the expansion at 'expantion.offset'.
415+
// Find the expansion at 'expansion.offset'.
416416
MacroExpansionFinder expansionFinder(
417417
SourceMgr,
418418
SourceMgr.getLocForOffset(*SF->getBufferID(), expansion.offset));

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2018,6 +2018,17 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
20182018
llvm_unreachable("should always be type-checked already");
20192019
}
20202020

2021+
/// Determine the number of bits set.
2022+
static unsigned numBitsSet(uint64_t value) {
2023+
unsigned count = 0;
2024+
for (uint64_t i : range(0, 63)) {
2025+
if (value & (uint64_t(1) << i))
2026+
++count;
2027+
}
2028+
2029+
return count;
2030+
}
2031+
20212032
void visitMacroDecl(MacroDecl *MD) {
20222033
TypeChecker::checkDeclAttributes(MD);
20232034
checkAccessControl(MD);
@@ -2061,6 +2072,40 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
20612072
break;
20622073
}
20632074
}
2075+
2076+
// If the macro has a result type, it must have the freestanding
2077+
// expression role. Other roles cannot have result types.
2078+
if (auto resultTypeRepr = MD->getResultTypeRepr()) {
2079+
if (!MD->getMacroRoles().contains(MacroRole::Expression)) {
2080+
auto resultType = MD->getResultInterfaceType(); {
2081+
auto diag = Ctx.Diags.diagnose(
2082+
MD->arrowLoc, diag::macro_result_type_cannot_be_used, resultType);
2083+
diag.highlight(resultTypeRepr->getSourceRange());
2084+
2085+
// In a .swiftinterface file, downgrade this diagnostic to a warning.
2086+
// This allows the compiler to process existing .swiftinterface
2087+
// files that contain this issue.
2088+
if (resultType->isVoid()) {
2089+
if (auto sourceFile = MD->getParentSourceFile())
2090+
if (sourceFile->Kind == SourceFileKind::Interface)
2091+
diag.limitBehavior(DiagnosticBehavior::Warning);
2092+
}
2093+
}
2094+
2095+
Ctx.Diags.diagnose(MD->arrowLoc, diag::macro_make_freestanding_expression)
2096+
.fixItInsert(MD->getAttributeInsertionLoc(false),
2097+
"@freestanding(expression)\n");
2098+
Ctx.Diags.diagnose(MD->arrowLoc, diag::macro_remove_result_type)
2099+
.fixItRemove(SourceRange(MD->arrowLoc, resultTypeRepr->getEndLoc()));
2100+
}
2101+
}
2102+
2103+
// A macro can only have a single freestanding macro role.
2104+
MacroRoles freestandingRolesInhabited =
2105+
MD->getMacroRoles() & getFreestandingMacroRoles();
2106+
if (numBitsSet(freestandingRolesInhabited.toRaw()) > 1) {
2107+
MD->diagnose(diag::macro_multiple_freestanding_roles);
2108+
}
20642109
}
20652110

20662111
void visitMacroExpansionDecl(MacroExpansionDecl *MED) {

lib/Sema/TypeCheckMacros.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ extern "C" ptrdiff_t swift_ASTGen_checkMacroDefinition(
6666

6767
extern "C" ptrdiff_t swift_ASTGen_expandFreestandingMacro(
6868
void *diagEngine, void *macro, uint8_t externalKind,
69-
const char *discriminator, ptrdiff_t discriminatorLength, void *sourceFile,
69+
const char *discriminator, ptrdiff_t discriminatorLength,
70+
uint8_t rawMacroRole, void *sourceFile,
7071
const void *sourceLocation, const char **evaluatedSource,
7172
ptrdiff_t *evaluatedSourceLength);
7273

@@ -901,6 +902,13 @@ evaluateFreestandingMacro(FreestandingMacroExpansion *expansion,
901902
#endif
902903
});
903904

905+
// Only one freestanding macro role is permitted, so look at the roles to
906+
// figure out which one to use.
907+
MacroRole macroRole =
908+
macroRoles.contains(MacroRole::Expression) ? MacroRole::Expression
909+
: macroRoles.contains(MacroRole::Declaration) ? MacroRole::Declaration
910+
: MacroRole::CodeItem;
911+
904912
auto macroDef = macro->getDefinition();
905913
switch (macroDef.kind) {
906914
case MacroDefinition::Kind::Undefined:
@@ -961,7 +969,8 @@ evaluateFreestandingMacro(FreestandingMacroExpansion *expansion,
961969
swift_ASTGen_expandFreestandingMacro(
962970
&ctx.Diags, externalDef->opaqueHandle,
963971
static_cast<uint32_t>(externalDef->kind), discriminator->data(),
964-
discriminator->size(), astGenSourceFile,
972+
discriminator->size(),
973+
static_cast<uint32_t>(macroRole), astGenSourceFile,
965974
expansion->getSourceRange().Start.getOpaquePointerValue(),
966975
&evaluatedSourceAddress, &evaluatedSourceLength);
967976
if (!evaluatedSourceAddress)

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,26 @@ public struct StringifyMacro: ExpressionMacro {
7373
}
7474
}
7575

76+
public struct ExprAndDeclMacro: ExpressionMacro, DeclarationMacro {
77+
public static func expansion(
78+
of macro: some FreestandingMacroExpansionSyntax,
79+
in context: some MacroExpansionContext
80+
) -> ExprSyntax {
81+
guard let argument = macro.argumentList.first?.expression else {
82+
fatalError("boom")
83+
}
84+
85+
return "(\(argument), \(StringLiteralExprSyntax(content: argument.description)))"
86+
}
87+
88+
public static func expansion(
89+
of macro: some FreestandingMacroExpansionSyntax,
90+
in context: some MacroExpansionContext
91+
) -> [DeclSyntax] {
92+
return []
93+
}
94+
}
95+
7696
public struct StringifyAndTryMacro: ExpressionMacro {
7797
public static func expansion(
7898
of macro: some FreestandingMacroExpansionSyntax,

test/Macros/attached_macros_diags.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@
66
// expected-warning@-1{{external macro implementation type 'MyMacros.Macro1' could not be found for macro 'm1()'}}
77
// expected-note@-2{{'m1()' declared here}}
88

9-
@attached(accessor) macro m2(_: Int) -> Void = #externalMacro(module: "MyMacros", type: "Macro2")
9+
@attached(accessor) macro m2(_: Int) = #externalMacro(module: "MyMacros", type: "Macro2")
1010
// expected-warning@-1{{external macro implementation type 'MyMacros.Macro2' could not be found for macro 'm2'}}
1111
// expected-note@-2{{candidate has partially matching parameter list (Int)}}
1212
// expected-note@-3{{candidate expects value of type 'Int' for parameter #1 (got 'String')}}
1313

14-
@attached(accessor) macro m2(_: Double) -> Void = #externalMacro(module: "MyMacros", type: "Macro2")
14+
@attached(accessor) macro m2(_: Double) = #externalMacro(module: "MyMacros", type: "Macro2")
1515
// expected-warning@-1{{external macro implementation type 'MyMacros.Macro2' could not be found for macro 'm2'}}
1616
// expected-note@-2{{candidate has partially matching parameter list (Double)}}
1717
// expected-note@-3{{candidate expects value of type 'Double' for parameter #1 (got 'String')}}
1818

19-
@attached(accessor) macro m3(message: String) -> Void = #externalMacro(module: "MyMacros", type: "Macro3")
19+
@attached(accessor) macro m3(message: String) = #externalMacro(module: "MyMacros", type: "Macro3")
2020
// expected-warning@-1{{external macro implementation type 'MyMacros.Macro3' could not be found for macro 'm3(message:)'}}
2121

2222
@freestanding(expression) macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MyMacros", type: "StringifyMacro")

0 commit comments

Comments
 (0)