Skip to content

Commit 0eb71d1

Browse files
authored
Merge pull request #70034 from DougGregor/function-body-macros
Function body macros
2 parents fd63387 + 380bad4 commit 0eb71d1

30 files changed

+614
-18
lines changed

docs/ABI/Mangling.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,9 @@ Entities
407407
macro-expansion-operator ::= decl-name identifier 'fMm' // attached member macro
408408
macro-expansion-operator ::= decl-name identifier 'fMp' // attached peer macro
409409
macro-expansion-operator ::= decl-name identifier 'fMc' // attached conformance macro
410+
macro-expansion-operator ::= decl-name identifier 'fMe' // attached extension macro
411+
macro-expansion-operator ::= decl-name identifier 'fMq' // attached preamble macro
412+
macro-expansion-operator ::= decl-name identifier 'fMb' // attached body macro
410413
macro-expansion-operator ::= decl-name identifier 'fMu' // uniquely-named entity
411414

412415
file-discriminator ::= identifier 'Ll' // anonymous file-discriminated declaration

include/swift/AST/Decl.h

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,13 +464,16 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
464464
SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2,
465465
StaticSpelling : 2
466466
);
467-
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+2+2+8+1+1+1+1+1+1+1,
467+
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+2+2+2+8+1+1+1+1+1+1+1,
468468
/// \see AbstractFunctionDecl::BodyKind
469469
BodyKind : 3,
470470

471471
/// \see AbstractFunctionDecl::BodySkippedStatus
472472
BodySkippedStatus : 2,
473473

474+
/// \see AbstractFunctionDecl::BodyExpandedStatus
475+
BodyExpandedStatus : 2,
476+
474477
/// \see AbstractFunctionDecl::SILSynthesizeKind
475478
SILSynthesizeKind : 2,
476479

@@ -7003,6 +7006,19 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
70037006
// This enum needs to fit in a 2-bit bitfield.
70047007
};
70057008

7009+
enum class BodyExpandedStatus {
7010+
/// We haven't tried to expand any body macros.
7011+
NotExpanded,
7012+
7013+
/// We tried to expand body macros, and there weren't any.
7014+
NoMacros,
7015+
7016+
/// The body was expanded from a body macro.
7017+
Expanded,
7018+
7019+
// This enum needs to fit in a 2-bit bitfield.
7020+
};
7021+
70067022
BodyKind getBodyKind() const {
70077023
return BodyKind(Bits.AbstractFunctionDecl.BodyKind);
70087024
}
@@ -7089,6 +7105,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
70897105
ValueDecl(Kind, Parent, Name, NameLoc), BodyAndFP(), AsyncLoc(AsyncLoc),
70907106
ThrowsLoc(ThrowsLoc), ThrownType(ThrownTy) {
70917107
setBodyKind(BodyKind::None);
7108+
setBodyExpandedStatus(BodyExpandedStatus::NotExpanded);
70927109
Bits.AbstractFunctionDecl.HasImplicitSelfDecl = HasImplicitSelfDecl;
70937110
Bits.AbstractFunctionDecl.Overridden = false;
70947111
Bits.AbstractFunctionDecl.Async = Async;
@@ -7110,6 +7127,14 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
71107127
Bits.AbstractFunctionDecl.BodySkippedStatus = unsigned(status);
71117128
}
71127129

7130+
BodyExpandedStatus getBodyExpandedStatus() const {
7131+
return BodyExpandedStatus(Bits.AbstractFunctionDecl.BodyExpandedStatus);
7132+
}
7133+
7134+
void setBodyExpandedStatus(BodyExpandedStatus status) {
7135+
Bits.AbstractFunctionDecl.BodyExpandedStatus = unsigned(status);
7136+
}
7137+
71137138
void setSILSynthesizeKind(SILSynthesizeKind K) {
71147139
Bits.AbstractFunctionDecl.SILSynthesizeKind = unsigned(K);
71157140
}
@@ -7258,6 +7283,10 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
72587283
/// \sa hasBody()
72597284
BraceStmt *getBody(bool canSynthesize = true) const;
72607285

7286+
/// Retrieve the body after macro expansion, which might also have been
7287+
/// type-checked.
7288+
BraceStmt *getMacroExpandedBody() const;
7289+
72617290
/// Retrieve the type-checked body of the given function, or \c nullptr if
72627291
/// there's no body available.
72637292
BraceStmt *getTypecheckedBody() const;

include/swift/AST/TypeCheckRequests.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4397,6 +4397,44 @@ class ExpandPeerMacroRequest
43974397
void noteCycleStep(DiagnosticEngine &diags) const;
43984398
};
43994399

4400+
class ExpandPreambleMacroRequest
4401+
: public SimpleRequest<ExpandPreambleMacroRequest,
4402+
ArrayRef<unsigned>(AbstractFunctionDecl *),
4403+
RequestFlags::Cached> {
4404+
public:
4405+
using SimpleRequest::SimpleRequest;
4406+
4407+
private:
4408+
friend SimpleRequest;
4409+
4410+
ArrayRef<unsigned> evaluate(
4411+
Evaluator &evaluator, AbstractFunctionDecl *fn) const;
4412+
4413+
public:
4414+
bool isCached() const { return true; }
4415+
void diagnoseCycle(DiagnosticEngine &diags) const;
4416+
void noteCycleStep(DiagnosticEngine &diags) const;
4417+
};
4418+
4419+
class ExpandBodyMacroRequest
4420+
: public SimpleRequest<ExpandBodyMacroRequest,
4421+
llvm::Optional<unsigned>(AbstractFunctionDecl *),
4422+
RequestFlags::Cached> {
4423+
public:
4424+
using SimpleRequest::SimpleRequest;
4425+
4426+
private:
4427+
friend SimpleRequest;
4428+
4429+
llvm::Optional<unsigned> evaluate(
4430+
Evaluator &evaluator, AbstractFunctionDecl *fn) const;
4431+
4432+
public:
4433+
bool isCached() const { return true; }
4434+
void diagnoseCycle(DiagnosticEngine &diags) const;
4435+
void noteCycleStep(DiagnosticEngine &diags) const;
4436+
};
4437+
44004438
/// Resolve an external macro given its module and type name.
44014439
class ExternalMacroDefinitionRequest
44024440
: public SimpleRequest<ExternalMacroDefinitionRequest,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,12 @@ SWIFT_REQUEST(TypeChecker, ExpandSynthesizedMemberMacroRequest,
493493
SWIFT_REQUEST(TypeChecker, ExpandPeerMacroRequest,
494494
ArrayRef<unsigned>(Decl *),
495495
Cached, NoLocationInfo)
496+
SWIFT_REQUEST(TypeChecker, ExpandPreambleMacroRequest,
497+
ArrayRef<unsigned>(AbstractFunctionDecl *),
498+
Cached, NoLocationInfo)
499+
SWIFT_REQUEST(TypeChecker, ExpandBodyMacroRequest,
500+
llvm::Optional<unsigned>(AbstractFunctionDecl *),
501+
Cached, NoLocationInfo)
496502
SWIFT_REQUEST(TypeChecker, LocalDiscriminatorsRequest,
497503
unsigned(DeclContext *),
498504
Cached, NoLocationInfo)

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ EXPERIMENTAL_FEATURE(StaticAssert, false)
126126
EXPERIMENTAL_FEATURE(NamedOpaqueTypes, false)
127127
EXPERIMENTAL_FEATURE(FlowSensitiveConcurrencyCaptures, false)
128128
EXPERIMENTAL_FEATURE(CodeItemMacros, false)
129+
EXPERIMENTAL_FEATURE(BodyMacros, true)
129130
EXPERIMENTAL_FEATURE(TupleConformances, false)
130131

131132
SUPPRESSIBLE_LANGUAGE_FEATURE(ExtensionMacroAttr, 0, "@attached(extension)", true)

include/swift/Basic/MacroRoles.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ EXPERIMENTAL_FREESTANDING_MACRO_ROLE(CodeItem, "codeItem", CodeItemMacros)
6969
/// macro is attached to.
7070
ATTACHED_MACRO_ROLE(Extension, "extension", "e")
7171

72+
/// An attached macro that expands to a preamble to a function.
73+
EXPERIMENTAL_ATTACHED_MACRO_ROLE(Preamble, "preamble", "q", BodyMacros)
74+
75+
/// An attached macro that expands to a function body.
76+
EXPERIMENTAL_ATTACHED_MACRO_ROLE(Body, "body", "b", BodyMacros)
77+
7278
#undef ATTACHED_MACRO_ROLE
7379
#undef FREESTANDING_MACRO_ROLE
7480
#undef EXPERIMENTAL_ATTACHED_MACRO_ROLE

include/swift/Demangling/DemangleNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ NODE(AccessorAttachedMacroExpansion)
3636
NODE(AssociatedTypeWitnessTableAccessor)
3737
NODE(BaseWitnessTableAccessor)
3838
NODE(AutoClosureType)
39+
NODE(BodyAttachedMacroExpansion)
3940
NODE(BoundGenericClass)
4041
NODE(BoundGenericEnum)
4142
NODE(BoundGenericStructure)
@@ -189,6 +190,7 @@ NODE(PartialApplyForwarder)
189190
NODE(PartialApplyObjCForwarder)
190191
NODE(PeerAttachedMacroExpansion)
191192
NODE(PostfixOperator)
193+
NODE(PreambleAttachedMacroExpansion)
192194
NODE(PrefixOperator)
193195
NODE(PrivateDeclName)
194196
NODE(PropertyDescriptor)

lib/AST/ASTContext.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6133,6 +6133,7 @@ void AbstractFunctionDecl::keepOriginalBodySourceRange() {
61336133
auto result =
61346134
impl.OriginalBodySourceRanges.insert({this, getBodySourceRange()});
61356135
assert((!result.second ||
6136+
result.first->getSecond().isInvalid() ||
61366137
isSourceLocInOrignalBuffer(this, result.first->getSecond().Start)) &&
61376138
"This function must be called before setting new body range");
61386139
(void)result;

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2940,6 +2940,10 @@ static bool usesFeatureExtensionMacros(Decl *decl) {
29402940
return macro->getMacroRoles().contains(MacroRole::Extension);
29412941
}
29422942

2943+
static bool usesFeatureBodyMacros(Decl *decl) {
2944+
return false;
2945+
}
2946+
29432947
static bool usesFeatureExtensionMacroAttr(Decl *decl) {
29442948
return usesFeatureExtensionMacros(decl);
29452949
}

lib/AST/ASTScopeCreation.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ ASTSourceFileScope::ASTSourceFileScope(SourceFile *SF,
266266
auto expansion = SF->getMacroExpansion();
267267

268268
// Determine the parent source location based on the macro role.
269+
AbstractFunctionDecl *bodyForDecl = nullptr;
269270
switch (*macroRole) {
270271
case MacroRole::Expression:
271272
case MacroRole::Declaration:
@@ -276,6 +277,16 @@ ASTSourceFileScope::ASTSourceFileScope(SourceFile *SF,
276277
case MacroRole::Extension:
277278
parentLoc = expansion.getStartLoc();
278279
break;
280+
case MacroRole::Preamble: {
281+
// Preamble macro roles start at the beginning of the macro body.
282+
auto func = cast<AbstractFunctionDecl>(expansion.get<Decl *>());
283+
parentLoc = func->getMacroExpandedBody()->getStartLoc();
284+
break;
285+
}
286+
case MacroRole::Body:
287+
parentLoc = expansion.getEndLoc();
288+
bodyForDecl = cast<AbstractFunctionDecl>(expansion.get<Decl *>());
289+
break;
279290
case MacroRole::Peer: {
280291
ASTContext &ctx = SF->getASTContext();
281292
SourceManager &sourceMgr = ctx.SourceMgr;
@@ -297,6 +308,12 @@ ASTSourceFileScope::ASTSourceFileScope(SourceFile *SF,
297308
}
298309

299310
if (auto parentScope = findStartingScopeForLookup(enclosingSF, parentLoc)) {
311+
if (bodyForDecl) {
312+
auto bodyScope = new (bodyForDecl->getASTContext()) FunctionBodyScope(bodyForDecl);
313+
bodyScope->parentAndWasExpanded.setPointer(const_cast<ASTScopeImpl *>(parentScope));
314+
parentScope = bodyScope;
315+
}
316+
300317
parentAndWasExpanded.setPointer(const_cast<ASTScopeImpl *>(parentScope));
301318
}
302319
}
@@ -986,7 +1003,7 @@ void AbstractFunctionDeclScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
9861003
// Create scope for the body.
9871004
// We create body scopes when there is no body for source kit to complete
9881005
// erroneous code in bodies.
989-
if (decl->getBodySourceRange().isValid()) {
1006+
if (decl->getOriginalBodySourceRange().isValid()) {
9901007
scopeCreator.constructExpandAndInsert<FunctionBodyScope>(leaf, decl);
9911008
}
9921009
}

lib/AST/ASTScopeSourceRange.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@ SourceRange DifferentiableAttributeScope::getSourceRangeOfThisASTNode(
125125

126126
SourceRange FunctionBodyScope::getSourceRangeOfThisASTNode(
127127
const bool omitAssertions) const {
128+
// If this function body scope is synthesized for a body macro, use the
129+
// real source range.
130+
if (getChildren().size() == 1 &&
131+
getChildren()[0]->getClassName() == "ASTSourceFileScope") {
132+
return decl->getBodySourceRange();
133+
}
134+
128135
return decl->getOriginalBodySourceRange();
129136
}
130137

lib/AST/ASTVerifier.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,13 @@ class Verifier : public ASTWalker {
258258
abort();
259259
}
260260

261+
ModuleDecl *getModuleContext() const {
262+
if (auto sourceFile = M.dyn_cast<SourceFile *>())
263+
return sourceFile->getParentModule();
264+
265+
return M.get<ModuleDecl *>();
266+
}
267+
261268
public:
262269
Verifier(ModuleDecl *M, DeclContext *DC)
263270
: Verifier(PointerUnion<ModuleDecl *, SourceFile *>(M), DC) {}
@@ -3813,7 +3820,17 @@ class Verifier : public ASTWalker {
38133820
} else {
38143821
llvm_unreachable("impossible parent node");
38153822
}
3816-
3823+
3824+
if (AltEnclosing.isInvalid()) {
3825+
// A preamble macro introduces child nodes directly into the tree.
3826+
auto *sourceFile =
3827+
getModuleContext()->getSourceFileContainingLocation(Current.Start);
3828+
if (sourceFile &&
3829+
sourceFile->getFulfilledMacroRole() == MacroRole::Preamble) {
3830+
AltEnclosing = Current;
3831+
}
3832+
}
3833+
38173834
if (!Ctx.SourceMgr.rangeContains(Enclosing, Current) &&
38183835
!(AltEnclosing.isValid() &&
38193836
Ctx.SourceMgr.rangeContains(AltEnclosing, Current))) {

lib/AST/Decl.cpp

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1029,7 +1029,7 @@ Expr *AbstractFunctionDecl::getSingleExpressionBody() const {
10291029

10301030
void AbstractFunctionDecl::setSingleExpressionBody(Expr *NewBody) {
10311031
assert(hasSingleExpressionBody() && "Not a single-expression body");
1032-
auto body = getBody()->getLastElement();
1032+
auto body = getBody(/*canSynthesize=*/false)->getLastElement();
10331033
if (auto *stmt = body.dyn_cast<Stmt *>()) {
10341034
if (auto *returnStmt = dyn_cast<ReturnStmt>(stmt)) {
10351035
returnStmt->setResult(NewBody);
@@ -9118,6 +9118,63 @@ bool AbstractFunctionDecl::hasBody() const {
91189118
}
91199119

91209120

9121+
static BraceStmt *expandBodyMacro(AbstractFunctionDecl *fn) {
9122+
ASTContext &ctx = fn->getASTContext();
9123+
9124+
auto bufferID = evaluateOrDefault(
9125+
ctx.evaluator, ExpandBodyMacroRequest{fn}, llvm::None);
9126+
if (!bufferID) {
9127+
return nullptr;
9128+
}
9129+
9130+
CharSourceRange bufferRange = ctx.SourceMgr.getRangeForBuffer(*bufferID);
9131+
auto bufferStart = bufferRange.getStart();
9132+
auto module = fn->getParentModule();
9133+
auto macroSourceFile = module->getSourceFileContainingLocation(bufferStart);
9134+
9135+
return BraceStmt::create(
9136+
ctx, bufferRange.getStart(), macroSourceFile->getTopLevelItems(),
9137+
bufferRange.getEnd());
9138+
}
9139+
9140+
BraceStmt *AbstractFunctionDecl::getMacroExpandedBody() const {
9141+
auto mutableThis = const_cast<AbstractFunctionDecl *>(this);
9142+
switch (getBodyKind()) {
9143+
case BodyKind::None:
9144+
case BodyKind::Unparsed:
9145+
case BodyKind::Parsed:
9146+
switch (getBodyExpandedStatus()) {
9147+
case BodyExpandedStatus::NotExpanded:
9148+
if (auto expandedBody = expandBodyMacro(mutableThis)) {
9149+
// Save the original body's source range.
9150+
mutableThis->keepOriginalBodySourceRange();
9151+
9152+
// Cache the expanded macro body as the parsed body of the function.
9153+
mutableThis->setBodyExpandedStatus(BodyExpandedStatus::Expanded);
9154+
mutableThis->setBodyParsed(expandedBody);
9155+
9156+
return expandedBody;
9157+
}
9158+
9159+
mutableThis->setBodyExpandedStatus(BodyExpandedStatus::NoMacros);
9160+
break;
9161+
9162+
case BodyExpandedStatus::NoMacros:
9163+
case BodyExpandedStatus::Expanded:
9164+
break;
9165+
}
9166+
9167+
// Fall through to get the body.
9168+
LLVM_FALLTHROUGH;
9169+
9170+
case BodyKind::Synthesize:
9171+
case BodyKind::TypeChecked:
9172+
case BodyKind::SILSynthesize:
9173+
case BodyKind::Deserialized:
9174+
return getBody(/*canSynthesize=*/true);
9175+
}
9176+
}
9177+
91219178
BraceStmt *AbstractFunctionDecl::getBody(bool canSynthesize) const {
91229179
if ((getBodyKind() == BodyKind::Synthesize ||
91239180
getBodyKind() == BodyKind::Unparsed) &&
@@ -11325,6 +11382,8 @@ void MacroDecl::getIntroducedNames(MacroRole role, ValueDecl *attachedTo,
1132511382
case MacroRole::Accessor:
1132611383
case MacroRole::Conformance:
1132711384
case MacroRole::MemberAttribute:
11385+
case MacroRole::Preamble:
11386+
case MacroRole::Body:
1132811387
break;
1132911388
}
1133011389
}

lib/AST/Module.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,6 @@ SourceFile *ModuleDecl::getSourceFileContainingLocation(SourceLoc loc) {
851851
if (loc.isInvalid())
852852
return nullptr;
853853

854-
855854
// Check whether this location is in a "replaced" range, in which case
856855
// we want to use the original source file.
857856
auto &sourceMgr = getASTContext().SourceMgr;
@@ -1210,11 +1209,12 @@ llvm::Optional<MacroRole> SourceFile::getFulfilledMacroRole() const {
12101209
}
12111210

12121211
SourceFile *SourceFile::getEnclosingSourceFile() const {
1213-
auto macroExpansion = getMacroExpansion();
1214-
if (!macroExpansion)
1212+
if (Kind != SourceFileKind::MacroExpansion)
12151213
return nullptr;
12161214

1217-
auto sourceLoc = macroExpansion.getStartLoc();
1215+
auto genInfo =
1216+
*getASTContext().SourceMgr.getGeneratedSourceInfo(*getBufferID());
1217+
auto sourceLoc = genInfo.originalSourceRange.getStart();
12181218
return getParentModule()->getSourceFileContainingLocation(sourceLoc);
12191219
}
12201220

0 commit comments

Comments
 (0)