Skip to content

Commit 3c779e7

Browse files
committed
[Macros] Ensure that name lookup can find uniquely-generated macro names
While a Swift program cannot directly utter one of the unique names produced by the macro expansion context outside of the macro itself, utilities such as type reconstruction require the ability to look up these names. Note that various kinds of macros can introduce unique names, and update the name lookup facilities for macro-generated names to account for them. Fixes rdar://106053984.
1 parent 8b63ce8 commit 3c779e7

File tree

5 files changed

+83
-5
lines changed

5 files changed

+83
-5
lines changed

include/swift/AST/Decl.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8476,6 +8476,22 @@ class MacroDecl : public GenericContext, public ValueDecl {
84768476
return DeclName();
84778477
}
84788478

8479+
/// Returns a DeclName that acts as a stand-in for all unique names that
8480+
/// are manufactured by the macro expansion context's `makeUniqueName`.
8481+
static DeclName getUniqueNamePlaceholder(ASTContext &ctx);
8482+
8483+
/// Determine whether the given name is the unique-name placeholder
8484+
/// produced by `getUniqueNamePlaceholder`.
8485+
static bool isUniqueNamePlaceholder(DeclName name);
8486+
8487+
/// Determine whether the given name is one of the unique names manufactured
8488+
/// by the macro expansion context's `makeUniqueName`.
8489+
static bool isUniqueMacroName(StringRef name);
8490+
8491+
/// Determine whether the given name is one of the unique names manufactured
8492+
/// by the macro expansion context's `makeUniqueName`.
8493+
static bool isUniqueMacroName(DeclBaseName name);
8494+
84798495
/// Retrieve the definition of this macro.
84808496
MacroDefinition getDefinition() const;
84818497

lib/AST/Decl.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10073,6 +10073,39 @@ const MacroRoleAttr *MacroDecl::getMacroRoleAttr(MacroRole role) const {
1007310073
return nullptr;
1007410074
}
1007510075

10076+
DeclName MacroDecl::getUniqueNamePlaceholder(ASTContext &ctx) {
10077+
return ctx.getIdentifier("$");
10078+
}
10079+
10080+
bool MacroDecl::isUniqueNamePlaceholder(DeclName name) {
10081+
return name.getBaseName().userFacingName() == "$";
10082+
}
10083+
10084+
bool MacroDecl::isUniqueMacroName(StringRef name) {
10085+
// Unique macro names are mangled names, which always start with "$s".
10086+
if (!name.startswith("$s"))
10087+
return false;
10088+
10089+
// Unique macro names end with fMu<digits>_. Match that.
10090+
10091+
// Strip off the trailing _.
10092+
if (name.back() != '_')
10093+
return false;
10094+
name = name.drop_back();
10095+
10096+
// Strip off trailing digits. This is the discriminator.
10097+
while (isdigit(name.back()))
10098+
name = name.drop_back();
10099+
10100+
// Check for fMu.
10101+
return name.endswith("fMu");
10102+
}
10103+
10104+
bool MacroDecl::isUniqueMacroName(DeclBaseName name) {
10105+
return isUniqueMacroName(name.userFacingName());
10106+
}
10107+
10108+
1007610109
void MacroDecl::getIntroducedNames(MacroRole role, ValueDecl *attachedTo,
1007710110
SmallVectorImpl<DeclName> &names) const {
1007810111
ASTContext &ctx = getASTContext();
@@ -10134,6 +10167,21 @@ void MacroDecl::getIntroducedNames(MacroRole role, ValueDecl *attachedTo,
1013410167
break;
1013510168
}
1013610169
}
10170+
10171+
// Add the unique name, if the macro can introduce declarations anywhere.
10172+
switch (role) {
10173+
case MacroRole::Expression:
10174+
case MacroRole::Declaration:
10175+
case MacroRole::Member:
10176+
case MacroRole::Peer:
10177+
names.push_back(MacroDecl::getUniqueNamePlaceholder(getASTContext()));
10178+
break;
10179+
10180+
case MacroRole::Accessor:
10181+
case MacroRole::Conformance:
10182+
case MacroRole::MemberAttribute:
10183+
break;
10184+
}
1013710185
}
1013810186

1013910187
MacroDefinition MacroDecl::getDefinition() const {

lib/AST/Module.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ class swift::SourceLookupCache {
160160
ValueDeclMap TopLevelValues;
161161
ValueDeclMap ClassMembers;
162162
bool MemberCachePopulated = false;
163+
DeclName UniqueMacroNamePlaceholder;
163164

164165
template<typename T>
165166
using OperatorMap = llvm::DenseMap<Identifier, TinyPtrVector<T *>>;
@@ -179,6 +180,8 @@ class swift::SourceLookupCache {
179180
SmallVector<Decl *, 4> MayHaveAuxiliaryDecls;
180181
void populateAuxiliaryDeclCache();
181182

183+
SourceLookupCache(ASTContext &ctx);
184+
182185
public:
183186
SourceLookupCache(const SourceFile &SF);
184187
SourceLookupCache(const ModuleDecl &Mod);
@@ -392,15 +395,22 @@ void SourceLookupCache::populateAuxiliaryDeclCache() {
392395
MayHaveAuxiliaryDecls.clear();
393396
}
394397

398+
SourceLookupCache::SourceLookupCache(ASTContext &ctx)
399+
: UniqueMacroNamePlaceholder(MacroDecl::getUniqueNamePlaceholder(ctx)) { }
400+
395401
/// Populate our cache on the first name lookup.
396-
SourceLookupCache::SourceLookupCache(const SourceFile &SF) {
402+
SourceLookupCache::SourceLookupCache(const SourceFile &SF)
403+
: SourceLookupCache(SF.getASTContext())
404+
{
397405
FrontendStatsTracer tracer(SF.getASTContext().Stats,
398406
"source-file-populate-cache");
399407
addToUnqualifiedLookupCache(SF.getTopLevelDecls(), false);
400408
addToUnqualifiedLookupCache(SF.getHoistedDecls(), false);
401409
}
402410

403-
SourceLookupCache::SourceLookupCache(const ModuleDecl &M) {
411+
SourceLookupCache::SourceLookupCache(const ModuleDecl &M)
412+
: SourceLookupCache(M.getASTContext())
413+
{
404414
FrontendStatsTracer tracer(M.getASTContext().Stats,
405415
"module-populate-cache");
406416
for (const FileUnit *file : M.getFiles()) {
@@ -428,7 +438,10 @@ void SourceLookupCache::lookupValue(DeclName Name, NLKind LookupKind,
428438
// FIXME: We need to not consider auxiliary decls if we're doing lookup
429439
// from inside a macro argument at module scope.
430440
populateAuxiliaryDeclCache();
431-
auto auxDecls = TopLevelAuxiliaryDecls.find(Name);
441+
DeclName keyName = MacroDecl::isUniqueMacroName(Name.getBaseName())
442+
? UniqueMacroNamePlaceholder
443+
: Name;
444+
auto auxDecls = TopLevelAuxiliaryDecls.find(keyName);
432445
if (auxDecls == TopLevelAuxiliaryDecls.end())
433446
return;
434447

lib/Serialization/Serialization.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6137,7 +6137,8 @@ void Serializer::writeAST(ModuleOrSourceFile DC) {
61376137

61386138
for (auto D : fileDecls) {
61396139
if (isa<ImportDecl>(D) || isa<IfConfigDecl>(D) ||
6140-
isa<PoundDiagnosticDecl>(D) || isa<TopLevelCodeDecl>(D)) {
6140+
isa<PoundDiagnosticDecl>(D) || isa<TopLevelCodeDecl>(D) ||
6141+
isa<MacroExpansionDecl>(D)) {
61416142
continue;
61426143
}
61436144

test/Macros/top_level_freestanding.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// RUN: %target-build-swift -swift-version 5 -parse-as-library -enable-experimental-feature FreestandingMacros -I %swift-host-lib-dir -L %swift-host-lib-dir -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath
33
// RUNx: %target-swift-frontend -enable-experimental-feature FreestandingMacros -parse-as-library -emit-sil -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir %s -module-name MacroUser 2>&1 | %FileCheck --check-prefix CHECK-SIL %s
44
// RUN: %target-typecheck-verify-swift -swift-version 5 -enable-experimental-feature FreestandingMacros -parse-as-library -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir -module-name MacroUser -DTEST_DIAGNOSTICS -swift-version 5
5-
// RUN: %target-build-swift -swift-version 5 -enable-experimental-feature FreestandingMacros -parse-as-library -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir -L %swift-host-lib-dir %s -o %t/main -module-name MacroUser -swift-version 5
5+
// RUN: %target-build-swift -g -swift-version 5 -enable-experimental-feature FreestandingMacros -parse-as-library -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir -L %swift-host-lib-dir %s -o %t/main -module-name MacroUser -swift-version 5
66
// RUN: %target-run %t/main | %FileCheck %s
77
// REQUIRES: executable_test
88

0 commit comments

Comments
 (0)