Skip to content

Commit 626b61c

Browse files
committed
[Macros] Code item macros
Add support for declaring and expanding code item macros.
1 parent 21701ac commit 626b61c

21 files changed

+180
-20
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,8 +2049,8 @@ ERROR(macro_role_attr_expected_kind,PointsToFirstBadToken,
20492049
"expected %select{a freestanding|an attached}0 macro role such as "
20502050
"%select{'expression'|'accessor'}0", (bool))
20512051
ERROR(macro_role_syntax_mismatch,PointsToFirstBadToken,
2052-
"expected %select{a freestanding|an attached}0 macro cannot have "
2053-
"the %1 role", (bool, Identifier))
2052+
"%select{a freestanding|an attached}0 macro cannot have the %1 role",
2053+
(bool, Identifier))
20542054
ERROR(macro_attribute_unknown_label,PointsToFirstBadToken,
20552055
"@%select{freestanding|attached}0 has no argument with label %1",
20562056
(bool, Identifier))

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6982,6 +6982,11 @@ ERROR(invalid_macro_introduced_name,none,
69826982
ERROR(global_freestanding_macro_script,none,
69836983
"global freestanding macros not yet supported in script mode",
69846984
())
6985+
ERROR(invalid_macro_role_for_macro_syntax,none,
6986+
"invalid macro role for %{a freestanding|an attached}0 macro",
6987+
(unsigned))
6988+
ERROR(macro_cannot_introduce_names,none,
6989+
"'%0' macros are not allowed to introduce names", (StringRef))
69856990

69866991
//------------------------------------------------------------------------------
69876992
// MARK: Move Only Errors

include/swift/AST/MacroDeclaration.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ enum class MacroRole: uint32_t {
5555
/// An attached macro that adds conformances to the declaration the
5656
/// macro is attached to.
5757
Conformance = 0x40,
58+
/// A freestanding macro that expands to expressions, statements and
59+
/// declarations in a code block.
60+
CodeItem = 0x80,
5861
};
5962

6063
/// The contexts in which a particular macro declaration can be used.

lib/AST/ASTMangler.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3963,6 +3963,7 @@ void ASTMangler::appendMacroExpansionOperator(
39633963
switch (role) {
39643964
case MacroRole::Expression:
39653965
case MacroRole::Declaration:
3966+
case MacroRole::CodeItem:
39663967
appendOperator("fMf", Index(discriminator));
39673968
break;
39683969

lib/AST/ASTScopeCreation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ ASTSourceFileScope::ASTSourceFileScope(SourceFile *SF,
260260
switch (*macroRole) {
261261
case MacroRole::Expression:
262262
case MacroRole::Declaration:
263+
case MacroRole::CodeItem:
263264
case MacroRole::Accessor:
264265
case MacroRole::MemberAttribute:
265266
case MacroRole::Peer:

lib/AST/ASTWalker.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,9 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
430430
}
431431

432432
bool visitMacroExpansionDecl(MacroExpansionDecl *MED) {
433+
#ifndef NDEBUG
434+
PrettyStackTraceDecl debugStack("walking into", MED);
435+
#endif
433436
bool shouldWalkArguments, shouldWalkExpansion;
434437
std::tie(shouldWalkArguments, shouldWalkExpansion) =
435438
Walker.shouldWalkMacroArgumentsAndExpansion();
@@ -1329,6 +1332,10 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
13291332
std::tie(shouldWalkArguments, shouldWalkExpansion) =
13301333
Walker.shouldWalkMacroArgumentsAndExpansion();
13311334

1335+
if (auto *substituteDecl = E->getSubstituteDecl())
1336+
if (doIt(substituteDecl))
1337+
return nullptr;
1338+
13321339
if (shouldWalkArguments && E->getArgs()) {
13331340
ArgumentList *args = doIt(E->getArgs());
13341341
if (!args) return nullptr;
@@ -1343,6 +1350,7 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
13431350
}
13441351
E->setRewritten(rewritten);
13451352
}
1353+
13461354
return E;
13471355
}
13481356

lib/AST/Decl.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10044,6 +10044,9 @@ StringRef swift::getMacroRoleString(MacroRole role) {
1004410044

1004510045
case MacroRole::Conformance:
1004610046
return "conformance";
10047+
10048+
case MacroRole::CodeItem:
10049+
return "codeItem";
1004710050
}
1004810051
}
1004910052

@@ -10085,7 +10088,8 @@ StringRef swift::getMacroIntroducedDeclNameString(
1008510088
static MacroRoles freestandingMacroRoles =
1008610089
(MacroRoles() |
1008710090
MacroRole::Expression |
10088-
MacroRole::Declaration);
10091+
MacroRole::Declaration |
10092+
MacroRole::CodeItem);
1008910093
static MacroRoles attachedMacroRoles = (MacroRoles() |
1009010094
MacroRole::Accessor |
1009110095
MacroRole::MemberAttribute |
@@ -10291,6 +10295,7 @@ void MacroDecl::getIntroducedNames(MacroRole role, ValueDecl *attachedTo,
1029110295
case MacroRole::Declaration:
1029210296
case MacroRole::Member:
1029310297
case MacroRole::Peer:
10298+
case MacroRole::CodeItem:
1029410299
names.push_back(MacroDecl::getUniqueNamePlaceholder(getASTContext()));
1029510300
break;
1029610301

lib/ASTGen/Sources/ASTGen/Macros.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,29 @@ func expandFreestandingMacroInProcess(
369369
evaluatedSyntax = Syntax(CodeBlockItemListSyntax(
370370
decls.map { CodeBlockItemSyntax(item: .decl($0)) }))
371371

372+
case let codeItemMacro as CodeItemMacro.Type:
373+
guard let parentExpansion = macroSyntax.asProtocol(
374+
FreestandingMacroExpansionSyntax.self
375+
) else {
376+
print("not on a macro expansion decl: \(macroSyntax.recursiveDescription)")
377+
return nil
378+
}
379+
macroName = parentExpansion.macro.text
380+
381+
func expandDeclarationMacro<Node: FreestandingMacroExpansionSyntax>(
382+
_ node: Node
383+
) throws -> [CodeBlockItemSyntax] {
384+
return try codeItemMacro.expansion(
385+
of: sourceManager.detach(
386+
node,
387+
foldingWith: OperatorTable.standardOperators
388+
),
389+
in: context
390+
)
391+
}
392+
let items = try _openExistential(parentExpansion, do: expandDeclarationMacro)
393+
evaluatedSyntax = Syntax(CodeBlockItemListSyntax(items))
394+
372395
default:
373396
print("not an expression macro or a declaration macro")
374397
return nil

lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2189,6 +2189,7 @@ static Optional<MacroRole> getMacroRole(
21892189
auto role = llvm::StringSwitch<Optional<MacroRole>>(roleName->str())
21902190
.Case("declaration", MacroRole::Declaration)
21912191
.Case("expression", MacroRole::Expression)
2192+
.Case("codeItem", MacroRole::CodeItem)
21922193
.Case("accessor", MacroRole::Accessor)
21932194
.Case("memberAttribute", MacroRole::MemberAttribute)
21942195
.Case("member", MacroRole::Member)

lib/SILGen/SILGenExpr.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6169,10 +6169,18 @@ RValue RValueEmitter::visitMacroExpansionExpr(MacroExpansionExpr *E,
61696169
MacroScope scope(SGF, CleanupLocation(rewritten), E, name.str(),
61706170
E->getMacroRef().getDecl());
61716171
return visit(rewritten, C);
6172-
} else {
6173-
assert(E->getSubstituteDecl());
6172+
}
6173+
else if (auto *MED = E->getSubstituteDecl()) {
6174+
Mangle::ASTMangler mangler;
6175+
MED->forEachExpandedExprOrStmt([&](ASTNode node) {
6176+
if (auto *expr = node.dyn_cast<Expr *>())
6177+
visit(expr, C);
6178+
else if (auto *stmt = node.dyn_cast<Stmt *>())
6179+
SGF.emitStmt(stmt);
6180+
});
61746181
return RValue();
61756182
}
6183+
return RValue();
61766184
}
61776185

61786186
RValue SILGenFunction::emitRValue(Expr *E, SGFContext C) {

lib/Sema/CSApply.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5393,7 +5393,8 @@ namespace {
53935393
}
53945394
}
53955395
// For a non-expression macro, expand it as a declaration.
5396-
else if (macro->getMacroRoles().contains(MacroRole::Declaration)) {
5396+
else if (macro->getMacroRoles().contains(MacroRole::Declaration) ||
5397+
macro->getMacroRoles().contains(MacroRole::CodeItem)) {
53975398
if (!E->getSubstituteDecl()) {
53985399
auto *med = E->createSubstituteDecl();
53995400
E->setSubstituteDecl(med);
@@ -5405,7 +5406,7 @@ namespace {
54055406
SmallVector<Argument, 4> newArguments;
54065407
for (auto arg : *E->getArgs()) {
54075408
arg.setExpr(new (cs.getASTContext()) OpaqueValueExpr(
5408-
arg.getSourceRange(), cs.getType(arg.getExpr())));
5409+
arg.getSourceRange(), arg.getExpr()->getType()));
54095410
newArguments.push_back(arg);
54105411
}
54115412
auto newArgList = ArgumentList::create(

lib/Sema/TypeCheckAttr.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
160160
IGNORED_ATTR(Preconcurrency)
161161
IGNORED_ATTR(BackDeployed)
162162
IGNORED_ATTR(Documentation)
163-
IGNORED_ATTR(MacroRole)
164163
IGNORED_ATTR(LexicalLifetimes)
165164
#undef IGNORED_ATTR
166165

@@ -342,6 +341,8 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
342341
void visitSendableAttr(SendableAttr *attr);
343342

344343
void visitRuntimeMetadataAttr(RuntimeMetadataAttr *attr);
344+
345+
void visitMacroRoleAttr(MacroRoleAttr *attr);
345346
};
346347

347348
} // end anonymous namespace
@@ -6955,6 +6956,57 @@ void AttributeChecker::visitRuntimeMetadataAttr(RuntimeMetadataAttr *attr) {
69556956
}
69566957
}
69576958

6959+
void AttributeChecker::visitMacroRoleAttr(MacroRoleAttr *attr) {
6960+
switch (attr->getMacroSyntax()) {
6961+
case MacroSyntax::Freestanding: {
6962+
switch (attr->getMacroRole()) {
6963+
case MacroRole::Expression:
6964+
if (!attr->getNames().empty())
6965+
diagnoseAndRemoveAttr(attr, diag::macro_cannot_introduce_names,
6966+
getMacroRoleString(attr->getMacroRole()));
6967+
break;
6968+
case MacroRole::Declaration:
6969+
// TODO: Check names
6970+
break;
6971+
case MacroRole::CodeItem:
6972+
if (!attr->getNames().empty())
6973+
diagnoseAndRemoveAttr(attr, diag::macro_cannot_introduce_names,
6974+
getMacroRoleString(attr->getMacroRole()));
6975+
break;
6976+
default:
6977+
diagnoseAndRemoveAttr(attr, diag::invalid_macro_role_for_macro_syntax,
6978+
/*freestanding*/0);
6979+
break;
6980+
}
6981+
break;
6982+
}
6983+
case MacroSyntax::Attached: {
6984+
switch (attr->getMacroRole()) {
6985+
case MacroRole::Accessor:
6986+
// TODO: Check property observer names?
6987+
break;
6988+
case MacroRole::MemberAttribute:
6989+
diagnoseAndRemoveAttr(attr, diag::macro_cannot_introduce_names,
6990+
getMacroRoleString(attr->getMacroRole()));
6991+
break;
6992+
case MacroRole::Member:
6993+
break;
6994+
case MacroRole::Peer:
6995+
break;
6996+
case MacroRole::Conformance:
6997+
diagnoseAndRemoveAttr(attr, diag::macro_cannot_introduce_names,
6998+
getMacroRoleString(attr->getMacroRole()));
6999+
break;
7000+
default:
7001+
diagnoseAndRemoveAttr(attr, diag::invalid_macro_role_for_macro_syntax,
7002+
/*attached*/1);
7003+
break;
7004+
}
7005+
break;
7006+
}
7007+
}
7008+
}
7009+
69587010
namespace {
69597011

69607012
class ClosureAttributeChecker

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2063,7 +2063,10 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
20632063
void visitMacroExpansionDecl(MacroExpansionDecl *MED) {
20642064
// Assign a discriminator.
20652065
(void)MED->getDiscriminator();
2066-
// Expansion already visited as auxiliary decls.
2066+
// Decls in expansion already visited as auxiliary decls.
2067+
MED->forEachExpandedExprOrStmt([&](ASTNode node) {
2068+
TypeChecker::typeCheckASTNode(node, MED->getDeclContext());
2069+
});
20672070
}
20682071

20692072
void visitBoundVariable(VarDecl *VD) {
@@ -3804,12 +3807,10 @@ ExpandMacroExpansionDeclRequest::evaluate(Evaluator &evaluator,
38043807
// If it's not a declaration macro or a code item macro, it must have been
38053808
// parsed as an expression macro, and this decl is just its substitute decl.
38063809
// So there's no thing to be done here.
3807-
if (!roles.contains(MacroRole::Declaration))
3810+
if (!roles.contains(MacroRole::Declaration) &&
3811+
!roles.contains(MacroRole::CodeItem))
38083812
return None;
38093813

3810-
// Otherwise, we treat it as a declaration macro.
3811-
assert(roles.contains(MacroRole::Declaration));
3812-
38133814
// For now, restrict global freestanding macros in script mode.
38143815
if (dc->isModuleScopeContext() &&
38153816
dc->getParentSourceFile()->isScriptMode()) {

lib/Sema/TypeCheckEffects.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,8 @@ class EffectsHandlingWalker : public ASTWalker {
413413
} else if (auto patternBinding = dyn_cast<PatternBindingDecl>(D)) {
414414
if (patternBinding->isAsyncLet())
415415
recurse = asImpl().checkAsyncLet(patternBinding);
416+
} else if (auto macroExpansionDecl = dyn_cast<MacroExpansionDecl>(D)) {
417+
recurse = ShouldRecurse;
416418
} else {
417419
recurse = ShouldNotRecurse;
418420
}
@@ -444,6 +446,8 @@ class EffectsHandlingWalker : public ASTWalker {
444446
recurse = asImpl().checkDeclRef(declRef);
445447
} else if (auto interpolated = dyn_cast<InterpolatedStringLiteralExpr>(E)) {
446448
recurse = asImpl().checkInterpolatedStringLiteral(interpolated);
449+
} else if (auto macroExpansionExpr = dyn_cast<MacroExpansionExpr>(E)) {
450+
recurse = ShouldRecurse;
447451
}
448452
// Error handling validation (via checkTopLevelEffects) happens after
449453
// type checking. If an unchecked expression is still around, the code was

lib/Sema/TypeCheckMacros.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -824,10 +824,13 @@ swift::expandFreestandingMacro(MacroExpansionDecl *med) {
824824
NullTerminatedStringRef evaluatedSource;
825825

826826
MacroDecl *macro = cast<MacroDecl>(med->getMacroRef().getDecl());
827-
assert(macro->getMacroRoles().contains(MacroRole::Declaration));
827+
auto macroRoles = macro->getMacroRoles();
828+
assert(macroRoles.contains(MacroRole::Declaration) ||
829+
macroRoles.contains(MacroRole::CodeItem));
828830

829831
if (isFromExpansionOfMacro(sourceFile, macro, MacroRole::Expression) ||
830-
isFromExpansionOfMacro(sourceFile, macro, MacroRole::Declaration)) {
832+
isFromExpansionOfMacro(sourceFile, macro, MacroRole::Declaration) ||
833+
isFromExpansionOfMacro(sourceFile, macro, MacroRole::CodeItem)) {
831834
med->diagnose(diag::macro_recursive, macro->getName());
832835
return None;
833836
}
@@ -1205,6 +1208,7 @@ evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, CustomAttr *attr,
12051208

12061209
case MacroRole::Expression:
12071210
case MacroRole::Declaration:
1211+
case MacroRole::CodeItem:
12081212
llvm_unreachable("freestanding macro in attached macro evaluation");
12091213
}
12101214

lib/Serialization/Deserialization.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2670,6 +2670,7 @@ getActualMacroRole(uint8_t context) {
26702670
CASE(Member)
26712671
CASE(Peer)
26722672
CASE(Conformance)
2673+
CASE(CodeItem)
26732674
#undef CASE
26742675
}
26752676
return None;

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,7 @@ enum class MacroRole : uint8_t {
619619
Member,
620620
Peer,
621621
Conformance,
622+
CodeItem,
622623
};
623624
using MacroRoleField = BCFixed<3>;
624625

lib/Serialization/Serialization.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2239,6 +2239,7 @@ static uint8_t getRawStableMacroRole(swift::MacroRole context) {
22392239
CASE(Member)
22402240
CASE(Peer)
22412241
CASE(Conformance)
2242+
CASE(CodeItem)
22422243
}
22432244
#undef CASE
22442245
llvm_unreachable("bad result declaration macro kind");

0 commit comments

Comments
 (0)