Skip to content

Commit 8df508c

Browse files
authored
Merge pull request #67105 from DougGregor/freestanding-macro-global-scope-in-scripts
2 parents 438c067 + 939376b commit 8df508c

File tree

8 files changed

+207
-76
lines changed

8 files changed

+207
-76
lines changed

include/swift/AST/Decl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8449,7 +8449,7 @@ class MissingDecl : public Decl {
84498449
/// \c unexpandedMacro contains the macro reference and the base declaration
84508450
/// where the macro expansion applies.
84518451
struct {
8452-
llvm::PointerUnion<MacroExpansionDecl *, CustomAttr *> macroRef;
8452+
llvm::PointerUnion<FreestandingMacroExpansion *, CustomAttr *> macroRef;
84538453
Decl *baseDecl;
84548454
} unexpandedMacro;
84558455

@@ -8473,7 +8473,7 @@ class MissingDecl : public Decl {
84738473

84748474
static MissingDecl *
84758475
forUnexpandedMacro(
8476-
llvm::PointerUnion<MacroExpansionDecl *, CustomAttr *> macroRef,
8476+
llvm::PointerUnion<FreestandingMacroExpansion *, CustomAttr *> macroRef,
84778477
Decl *baseDecl) {
84788478
auto &ctx = baseDecl->getASTContext();
84798479
auto *dc = baseDecl->getDeclContext();

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7245,9 +7245,6 @@ ERROR(literal_type_in_macro_expansion,none,
72457245
ERROR(invalid_macro_introduced_name,none,
72467246
"declaration name %0 is not covered by macro %1",
72477247
(DeclName, DeclName))
7248-
ERROR(global_freestanding_macro_script,none,
7249-
"global freestanding macros not yet supported in script mode",
7250-
())
72517248
ERROR(invalid_macro_role_for_macro_syntax,none,
72527249
"invalid macro role for %{a freestanding|an attached}0 macro",
72537250
(unsigned))

lib/AST/Decl.cpp

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,25 @@ void Decl::visitAuxiliaryDecls(
408408
}
409409

410410
if (visitFreestandingExpanded) {
411-
if (auto *med = dyn_cast<MacroExpansionDecl>(mutableThis)) {
411+
Decl *thisDecl = mutableThis;
412+
413+
// If this is a top-level code decl consisting of a macro expansion
414+
// expression that substituted with a macro expansion declaration, use
415+
// that instead.
416+
if (auto *tlcd = dyn_cast<TopLevelCodeDecl>(thisDecl)) {
417+
if (auto body = tlcd->getBody()) {
418+
if (body->getNumElements() == 1) {
419+
if (auto expr = body->getFirstElement().dyn_cast<Expr *>()) {
420+
if (auto expansion = dyn_cast<MacroExpansionExpr>(expr)) {
421+
if (auto substitute = expansion->getSubstituteDecl())
422+
thisDecl = substitute;
423+
}
424+
}
425+
}
426+
}
427+
}
428+
429+
if (auto *med = dyn_cast<MacroExpansionDecl>(thisDecl)) {
412430
if (auto bufferID = evaluateOrDefault(
413431
ctx.evaluator, ExpandMacroExpansionDeclRequest{med}, {})) {
414432
auto startLoc = sourceMgr.getLocForBufferStart(*bufferID);
@@ -10492,6 +10510,45 @@ bool swift::isMacroSupported(MacroRole role, ASTContext &ctx) {
1049210510
void MissingDecl::forEachMacroExpandedDecl(MacroExpandedDeclCallback callback) {
1049310511
auto macroRef = unexpandedMacro.macroRef;
1049410512
auto *baseDecl = unexpandedMacro.baseDecl;
10513+
10514+
// If the macro itself is a macro expansion expression, it should come with
10515+
// a top-level code declaration that we can use for resolution. For such
10516+
// cases, resolve the macro to determine whether it is a declaration or
10517+
// code-item macro, meaning that it can produce declarations. In such cases,
10518+
// expand the macro and use its substituted declaration (a MacroExpansionDecl)
10519+
// instead.
10520+
if (auto freestanding = macroRef.dyn_cast<FreestandingMacroExpansion *>()) {
10521+
if (auto expr = dyn_cast<MacroExpansionExpr>(freestanding)) {
10522+
bool replacedWithDecl = false;
10523+
if (auto tlcd = dyn_cast_or_null<TopLevelCodeDecl>(baseDecl)) {
10524+
ASTContext &ctx = tlcd->getASTContext();
10525+
if (auto macro = evaluateOrDefault(
10526+
ctx.evaluator,
10527+
ResolveMacroRequest{macroRef, tlcd->getDeclContext()},
10528+
nullptr)) {
10529+
auto macroDecl = cast<MacroDecl>(macro.getDecl());
10530+
auto roles = macroDecl->getMacroRoles();
10531+
if (roles.contains(MacroRole::Declaration) ||
10532+
roles.contains(MacroRole::CodeItem)) {
10533+
(void)evaluateOrDefault(ctx.evaluator,
10534+
ExpandMacroExpansionExprRequest{expr},
10535+
llvm::None);
10536+
if (auto substituted = expr->getSubstituteDecl()) {
10537+
macroRef = substituted;
10538+
baseDecl = substituted;
10539+
replacedWithDecl = true;
10540+
}
10541+
}
10542+
}
10543+
}
10544+
10545+
// If we didn't end up replacing the macro expansion expression with
10546+
// a declaration, we're done.
10547+
if (!replacedWithDecl)
10548+
return;
10549+
}
10550+
}
10551+
1049510552
if (!macroRef || !baseDecl)
1049610553
return;
1049710554
auto *module = getModuleContext();
@@ -10502,9 +10559,12 @@ void MissingDecl::forEachMacroExpandedDecl(MacroExpandedDeclCallback callback) {
1050210559
: auxiliaryDecl->getInnermostDeclContext()->getParentSourceFile();
1050310560
// We only visit auxiliary decls that are macro expansions associated with
1050410561
// this macro reference.
10505-
if (auto *med = macroRef.dyn_cast<MacroExpansionDecl *>()) {
10506-
if (med != sf->getMacroExpansion().dyn_cast<Decl *>())
10507-
return;
10562+
if (auto *med = macroRef.dyn_cast<FreestandingMacroExpansion *>()) {
10563+
auto medAsDecl = dyn_cast<MacroExpansionDecl>(med);
10564+
auto medAsExpr = dyn_cast<MacroExpansionExpr>(med);
10565+
if ((!medAsDecl || medAsDecl != sf->getMacroExpansion().dyn_cast<Decl *>()) &&
10566+
(!medAsExpr || medAsExpr != sf->getMacroExpansion().dyn_cast<Expr *>()))
10567+
return;
1050810568
} else if (auto *attr = macroRef.dyn_cast<CustomAttr *>()) {
1050910569
if (attr != sf->getAttachedMacroAttribute())
1051010570
return;

lib/AST/Module.cpp

Lines changed: 118 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,9 @@ class swift::SourceLookupCache {
179179
/// Top-level macros that produce arbitrary names.
180180
SmallVector<MissingDecl *, 4> TopLevelArbitraryMacros;
181181

182-
SmallVector<Decl *, 4> MayHaveAuxiliaryDecls;
182+
SmallVector<llvm::PointerUnion<Decl *, MacroExpansionExpr *>, 4>
183+
MayHaveAuxiliaryDecls;
183184
void populateAuxiliaryDeclCache();
184-
185185
SourceLookupCache(ASTContext &ctx);
186186

187187
public:
@@ -238,10 +238,30 @@ SourceLookupCache &SourceFile::getCache() const {
238238
return *Cache;
239239
}
240240

241+
static Expr *getAsExpr(Decl *decl) { return nullptr; }
242+
static Decl *getAsDecl(Decl *decl) { return decl; }
243+
244+
static Expr *getAsExpr(ASTNode node) { return node.dyn_cast<Expr *>(); }
245+
static Decl *getAsDecl(ASTNode node) { return node.dyn_cast<Decl *>(); }
246+
241247
template<typename Range>
242-
void SourceLookupCache::addToUnqualifiedLookupCache(Range decls,
248+
void SourceLookupCache::addToUnqualifiedLookupCache(Range items,
243249
bool onlyOperators) {
244-
for (Decl *D : decls) {
250+
for (auto item : items) {
251+
// In script mode, we'll see macro expansion expressions for freestanding
252+
// macros.
253+
if (Expr *E = getAsExpr(item)) {
254+
if (auto MEE = dyn_cast<MacroExpansionExpr>(E)) {
255+
if (!onlyOperators)
256+
MayHaveAuxiliaryDecls.push_back(MEE);
257+
}
258+
continue;
259+
}
260+
261+
Decl *D = getAsDecl(item);
262+
if (!D)
263+
continue;
264+
245265
if (auto *VD = dyn_cast<ValueDecl>(D)) {
246266
if (onlyOperators ? VD->isOperator() : VD->hasName()) {
247267
// Cache the value under both its compound name and its full name.
@@ -280,6 +300,10 @@ void SourceLookupCache::addToUnqualifiedLookupCache(Range decls,
280300
else if (auto *MED = dyn_cast<MacroExpansionDecl>(D)) {
281301
if (!onlyOperators)
282302
MayHaveAuxiliaryDecls.push_back(MED);
303+
} else if (auto TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
304+
if (auto body = TLCD->getBody()){
305+
addToUnqualifiedLookupCache(body->getElements(), onlyOperators);
306+
}
283307
}
284308
}
285309
}
@@ -335,75 +359,113 @@ void SourceLookupCache::addToMemberCache(Range decls) {
335359
}
336360

337361
void SourceLookupCache::populateAuxiliaryDeclCache() {
338-
using MacroRef = llvm::PointerUnion<MacroExpansionDecl *, CustomAttr *>;
339-
for (auto *decl : MayHaveAuxiliaryDecls) {
362+
using MacroRef = llvm::PointerUnion<FreestandingMacroExpansion *, CustomAttr *>;
363+
for (auto item : MayHaveAuxiliaryDecls) {
364+
TopLevelCodeDecl *topLevelCodeDecl = nullptr;
365+
340366
// Gather macro-introduced peer names.
341367
llvm::SmallDenseMap<MacroRef, llvm::SmallVector<DeclName, 2>>
342368
introducedNames;
343369

344-
// This code deliberately avoids `forEachAttachedMacro`, because it
345-
// will perform overload resolution and possibly invoke unqualified
346-
// lookup for macro arguments, which will recursively populate the
347-
// auxiliary decl cache and cause request cycles.
348-
//
349-
// We do not need a fully resolved macro until expansion. Instead, we
350-
// conservatively consider peer names for all macro declarations with a
351-
// custom attribute name. Unqualified lookup for that name will later
352-
// invoke expansion of the macro, and will yield no results if the resolved
353-
// macro does not produce the requested name, so the only impact is possibly
354-
// expanding earlier than needed / unnecessarily looking in the top-level
355-
// auxiliary decl cache.
356-
for (auto attrConst : decl->getAttrs().getAttributes<CustomAttr>()) {
357-
auto *attr = const_cast<CustomAttr *>(attrConst);
358-
UnresolvedMacroReference macroRef(attr);
359-
bool introducesArbitraryNames = false;
360-
namelookup::forEachPotentialResolvedMacro(
361-
decl->getDeclContext()->getModuleScopeContext(),
362-
macroRef.getMacroName(), MacroRole::Peer,
363-
[&](MacroDecl *macro, const MacroRoleAttr *roleAttr) {
364-
// First check for arbitrary names.
365-
if (roleAttr->hasNameKind(MacroIntroducedDeclNameKind::Arbitrary)) {
366-
introducesArbitraryNames = true;
367-
}
370+
/// Introduce names for a freestanding macro.
371+
auto introduceNamesForFreestandingMacro =
372+
[&](FreestandingMacroExpansion *macroRef, Decl *decl, MacroRole role) {
373+
bool introducesArbitraryNames = false;
374+
namelookup::forEachPotentialResolvedMacro(
375+
decl->getDeclContext()->getModuleScopeContext(),
376+
macroRef->getMacroName(), role,
377+
[&](MacroDecl *macro, const MacroRoleAttr *roleAttr) {
378+
// First check for arbitrary names.
379+
if (roleAttr->hasNameKind(MacroIntroducedDeclNameKind::Arbitrary)) {
380+
introducesArbitraryNames = true;
381+
}
368382

369-
macro->getIntroducedNames(MacroRole::Peer,
370-
dyn_cast<ValueDecl>(decl),
371-
introducedNames[attr]);
372-
});
383+
macro->getIntroducedNames(role,
384+
/*attachedTo*/ nullptr,
385+
introducedNames[macroRef]);
386+
});
373387

374-
// Record this macro where appropriate.
375-
if (introducesArbitraryNames)
376-
TopLevelArbitraryMacros.push_back(MissingDecl::forUnexpandedMacro(attr, decl));
388+
return introducesArbitraryNames;
389+
};
390+
391+
// Handle macro expansion expressions, which show up in when we have
392+
// freestanding macros in "script" mode.
393+
if (auto expr = item.dyn_cast<MacroExpansionExpr *>()) {
394+
topLevelCodeDecl = dyn_cast<TopLevelCodeDecl>(expr->getDeclContext());
395+
if (topLevelCodeDecl) {
396+
bool introducesArbitraryNames = false;
397+
if (introduceNamesForFreestandingMacro(
398+
expr, topLevelCodeDecl, MacroRole::Declaration))
399+
introducesArbitraryNames = true;
400+
401+
if (introduceNamesForFreestandingMacro(
402+
expr, topLevelCodeDecl, MacroRole::CodeItem))
403+
introducesArbitraryNames = true;
404+
405+
// Record this macro if it introduces arbitrary names.
406+
if (introducesArbitraryNames) {
407+
TopLevelArbitraryMacros.push_back(
408+
MissingDecl::forUnexpandedMacro(expr, topLevelCodeDecl));
409+
}
410+
}
377411
}
378412

379-
if (auto *med = dyn_cast<MacroExpansionDecl>(decl)) {
380-
UnresolvedMacroReference macroRef(med);
381-
bool introducesArbitraryNames = false;
382-
namelookup::forEachPotentialResolvedMacro(
383-
decl->getDeclContext()->getModuleScopeContext(),
384-
macroRef.getMacroName(), MacroRole::Declaration,
385-
[&](MacroDecl *macro, const MacroRoleAttr *roleAttr) {
386-
// First check for arbitrary names.
387-
if (roleAttr->hasNameKind(MacroIntroducedDeclNameKind::Arbitrary)) {
388-
introducesArbitraryNames = true;
389-
}
413+
auto *decl = item.dyn_cast<Decl *>();
414+
if (decl) {
415+
// This code deliberately avoids `forEachAttachedMacro`, because it
416+
// will perform overload resolution and possibly invoke unqualified
417+
// lookup for macro arguments, which will recursively populate the
418+
// auxiliary decl cache and cause request cycles.
419+
//
420+
// We do not need a fully resolved macro until expansion. Instead, we
421+
// conservatively consider peer names for all macro declarations with a
422+
// custom attribute name. Unqualified lookup for that name will later
423+
// invoke expansion of the macro, and will yield no results if the resolved
424+
// macro does not produce the requested name, so the only impact is possibly
425+
// expanding earlier than needed / unnecessarily looking in the top-level
426+
// auxiliary decl cache.
427+
for (auto attrConst : decl->getAttrs().getAttributes<CustomAttr>()) {
428+
auto *attr = const_cast<CustomAttr *>(attrConst);
429+
UnresolvedMacroReference macroRef(attr);
430+
bool introducesArbitraryNames = false;
431+
namelookup::forEachPotentialResolvedMacro(
432+
decl->getDeclContext()->getModuleScopeContext(),
433+
macroRef.getMacroName(), MacroRole::Peer,
434+
[&](MacroDecl *macro, const MacroRoleAttr *roleAttr) {
435+
// First check for arbitrary names.
436+
if (roleAttr->hasNameKind(
437+
MacroIntroducedDeclNameKind::Arbitrary)) {
438+
introducesArbitraryNames = true;
439+
}
440+
441+
macro->getIntroducedNames(MacroRole::Peer,
442+
dyn_cast<ValueDecl>(decl),
443+
introducedNames[attr]);
444+
});
445+
446+
// Record this macro where appropriate.
447+
if (introducesArbitraryNames)
448+
TopLevelArbitraryMacros.push_back(
449+
MissingDecl::forUnexpandedMacro(attr, decl));
450+
}
451+
}
390452

391-
macro->getIntroducedNames(MacroRole::Declaration,
392-
/*attachedTo*/ nullptr,
393-
introducedNames[med]);
394-
});
453+
if (auto *med = dyn_cast_or_null<MacroExpansionDecl>(decl)) {
454+
bool introducesArbitraryNames =
455+
introduceNamesForFreestandingMacro(med, decl, MacroRole::Declaration);
395456

396-
// Record this macro where appropriate.
457+
// Note whether this macro produces arbitrary names.
397458
if (introducesArbitraryNames)
398459
TopLevelArbitraryMacros.push_back(MissingDecl::forUnexpandedMacro(med, decl));
399460
}
400461

401462
// Add macro-introduced names to the top-level auxiliary decl cache as
402463
// unexpanded decls represented by a MissingDecl.
464+
auto anchorDecl = decl ? decl : topLevelCodeDecl;
403465
for (auto macroNames : introducedNames) {
404466
auto macroRef = macroNames.getFirst();
405467
for (auto name : macroNames.getSecond()) {
406-
auto *placeholder = MissingDecl::forUnexpandedMacro(macroRef, decl);
468+
auto *placeholder = MissingDecl::forUnexpandedMacro(macroRef, anchorDecl);
407469
name.addToLookupTable(TopLevelAuxiliaryDecls, placeholder);
408470
}
409471
}
@@ -421,7 +483,7 @@ SourceLookupCache::SourceLookupCache(const SourceFile &SF)
421483
{
422484
FrontendStatsTracer tracer(SF.getASTContext().Stats,
423485
"source-file-populate-cache");
424-
addToUnqualifiedLookupCache(SF.getTopLevelDecls(), false);
486+
addToUnqualifiedLookupCache(SF.getTopLevelItems(), false);
425487
addToUnqualifiedLookupCache(SF.getHoistedDecls(), false);
426488
}
427489

@@ -432,7 +494,7 @@ SourceLookupCache::SourceLookupCache(const ModuleDecl &M)
432494
"module-populate-cache");
433495
for (const FileUnit *file : M.getFiles()) {
434496
auto *SF = cast<SourceFile>(file);
435-
addToUnqualifiedLookupCache(SF->getTopLevelDecls(), false);
497+
addToUnqualifiedLookupCache(SF->getTopLevelItems(), false);
436498
addToUnqualifiedLookupCache(SF->getHoistedDecls(), false);
437499

438500
if (auto *SFU = file->getSynthesizedFile()) {

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3934,11 +3934,5 @@ ExpandMacroExpansionDeclRequest::evaluate(Evaluator &evaluator,
39343934
!roles.contains(MacroRole::CodeItem))
39353935
return llvm::None;
39363936

3937-
// For now, restrict global freestanding macros in script mode.
3938-
if (dc->isModuleScopeContext() &&
3939-
dc->getParentSourceFile()->isScriptMode()) {
3940-
MED->diagnose(diag::global_freestanding_macro_script);
3941-
}
3942-
39433937
return expandFreestandingMacro(MED);
39443938
}

lib/Sema/TypeCheckMacros.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -471,8 +471,7 @@ ExpandMacroExpansionExprRequest::evaluate(Evaluator &evaluator,
471471
else if (macro->getMacroRoles().contains(MacroRole::Declaration) ||
472472
macro->getMacroRoles().contains(MacroRole::CodeItem)) {
473473
if (!mee->getSubstituteDecl()) {
474-
auto *med = mee->createSubstituteDecl();
475-
TypeChecker::typeCheckDecl(med);
474+
(void)mee->createSubstituteDecl();
476475
}
477476
// Return the expanded buffer ID.
478477
return evaluateOrDefault(

0 commit comments

Comments
 (0)