Skip to content

Commit 4266f36

Browse files
committed
Apply the @_alwaysEmitConformanceMetadata semantics to conformances originating from macro-expanded declarations and extensions
Existing code does not visit such declarations and does not mark them to be preserved in the binary even if not public and used. Resolves rdar://127903662
1 parent 459fc38 commit 4266f36

File tree

3 files changed

+127
-1
lines changed

3 files changed

+127
-1
lines changed

lib/SILOptimizer/Mandatory/AlwaysEmitConformanceMetadataPreservation.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ class AlwaysEmitMetadataConformanceCollector : public ASTWalker {
7373
AlwaysEmitMetadataConformanceDecls.push_back(ETD->getExtendedNominal());
7474
}
7575

76+
// Visit peers expanded from macros
77+
D->visitAuxiliaryDecls([&](Decl *decl) { decl->walk(*this); },
78+
/*visitFreestandingExpanded=*/false);
79+
7680
return Action::Continue();
7781
}
7882
};
@@ -90,8 +94,12 @@ class AlwaysEmitConformanceMetadataPreservation : public SILModuleTransform {
9094
for (const auto File : M.getSwiftModule()->getFiles())
9195
File->getTopLevelDecls(TopLevelDecls);
9296
} else {
93-
for (const auto Primary : M.getSwiftModule()->getPrimarySourceFiles())
97+
for (const auto Primary : M.getSwiftModule()->getPrimarySourceFiles()) {
9498
Primary->getTopLevelDecls(TopLevelDecls);
99+
// Visit macro expanded extensions
100+
if (auto *synthesizedPrimary = Primary->getSynthesizedFile())
101+
synthesizedPrimary->getTopLevelDecls(TopLevelDecls);
102+
}
95103
}
96104
}
97105
for (auto *TLD : TopLevelDecls)

test/Reflection/Inputs/Macros.swift

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import SwiftDiagnostics
2+
import SwiftOperators
3+
import SwiftSyntax
4+
import SwiftSyntaxBuilder
5+
import SwiftSyntaxMacros
6+
7+
public struct AddStructDeclMacro: DeclarationMacro {
8+
public static func expansion(
9+
of node: some FreestandingMacroExpansionSyntax,
10+
in context: some MacroExpansionContext
11+
) throws -> [DeclSyntax] {
12+
return [
13+
"""
14+
struct MacroAddedStruct : TestEntity {}
15+
"""
16+
]
17+
}
18+
}
19+
20+
public struct AddPeerStructMacro: PeerMacro {
21+
public static func expansion(
22+
of node: AttributeSyntax,
23+
providingPeersOf declaration: some DeclSyntaxProtocol,
24+
in context: some MacroExpansionContext
25+
) throws -> [DeclSyntax] {
26+
let name = declaration.declName
27+
return [
28+
"""
29+
struct _Peer_\(name) : TestEntity {}
30+
"""
31+
]
32+
}
33+
}
34+
35+
public struct AddExtensionMacro: ExtensionMacro {
36+
public static func expansion(
37+
of node: AttributeSyntax,
38+
attachedTo declaration: some DeclGroupSyntax,
39+
providingExtensionsOf type: some TypeSyntaxProtocol,
40+
conformingTo protocols: [TypeSyntax],
41+
in context: some MacroExpansionContext
42+
) throws -> [ExtensionDeclSyntax] {
43+
let typeName = declaration.declGroupName
44+
return protocols.map {
45+
("""
46+
extension \(typeName): \($0) {
47+
struct _Extension_\($0): \($0) {}
48+
}
49+
""" as DeclSyntax)
50+
.cast(ExtensionDeclSyntax.self)
51+
}
52+
}
53+
}
54+
55+
extension DeclSyntaxProtocol {
56+
var declName: TokenSyntax {
57+
if let varDecl = self.as(VariableDeclSyntax.self),
58+
let first = varDecl.bindings.first,
59+
let pattern = first.pattern.as(IdentifierPatternSyntax.self) {
60+
return pattern.identifier.trimmed
61+
} else if let funcDecl = self.as(FunctionDeclSyntax.self) {
62+
return funcDecl.name.trimmed
63+
} else if let structDecl = self.as(StructDeclSyntax.self) {
64+
return structDecl.name.trimmed
65+
}
66+
fatalError("Not implemented")
67+
}
68+
}
69+
70+
extension DeclGroupSyntax {
71+
var declGroupName: TokenSyntax {
72+
if let structDecl = self.as(StructDeclSyntax.self) {
73+
return structDecl.name.trimmed
74+
}
75+
fatalError("Not implemented")
76+
}
77+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// REQUIRES: objc_interop
2+
// RUN: %empty-directory(%t)
3+
// RUN: %empty-directory(%t/includes)
4+
5+
// Build support Protocols module
6+
// RUN: %target-build-swift %S/Inputs/PreservedConformanceProtocols.swift -parse-as-library -emit-module -emit-library -module-name PreservedConformanceProtocols -o %t/includes/PreservedConformanceProtocols.o
7+
8+
// Build the macro library
9+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/Macros.swift -g -no-toolchain-stdlib-rpath
10+
11+
// Build the test into a binary
12+
// RUN: %target-build-swift %s -parse-as-library -emit-module -emit-library -module-name PreservedConformances -O -whole-module-optimization -I %t/includes -o %t/PreservedConformances -Xlinker %t/includes/PreservedConformanceProtocols.o -load-plugin-library %t/%target-library-name(MacroDefinition)
13+
14+
// RUN: %target-swift-reflection-dump %t/PreservedConformances | %FileCheck %s
15+
16+
import PreservedConformanceProtocols
17+
18+
@freestanding(declaration, names: named(MacroAddedStruct))
19+
macro AddMacroAddedStruct() = #externalMacro(module: "MacroDefinition", type: "AddStructDeclMacro")
20+
21+
@attached(peer, names: prefixed(_Peer_))
22+
macro AddPeerStruct() = #externalMacro(module: "MacroDefinition", type: "AddPeerStructMacro")
23+
24+
@attached(extension, conformances: TestEntity, names: prefixed(_extension_), named(_Extension_TestEntity))
25+
macro AddExtension() = #externalMacro(module: "MacroDefinition", type: "AddExtensionMacro")
26+
27+
#AddMacroAddedStruct
28+
29+
struct internalTestEntity : TestEntity {}
30+
public struct publicTestEntity : TestEntity {}
31+
@AddPeerStruct
32+
struct internalMacroAidedEntityHelper {}
33+
@AddExtension
34+
struct internalMacroExtensionAidedEntityHelper {}
35+
// CHECK: CONFORMANCES:
36+
// CHECK: =============
37+
// CHECK-DAG: 21PreservedConformances16publicTestEntityV (PreservedConformances.publicTestEntity) : PreservedConformanceProtocols.TestEntity
38+
// CHECK-DAG: 21PreservedConformances18internalTestEntityV (PreservedConformances.internalTestEntity) : PreservedConformanceProtocols.TestEntity
39+
// CHECK-DAG: 21PreservedConformances16MacroAddedStructV (PreservedConformances.MacroAddedStruct) : PreservedConformanceProtocols.TestEntity
40+
// CHECK-DAG: 21PreservedConformances36_Peer_internalMacroAidedEntityHelperV (PreservedConformances._Peer_internalMacroAidedEntityHelper) : PreservedConformanceProtocols.TestEntity
41+
// CHECK-DAG: 21PreservedConformances39internalMacroExtensionAidedEntityHelperV (PreservedConformances.internalMacroExtensionAidedEntityHelper) : PreservedConformanceProtocols.TestEntity

0 commit comments

Comments
 (0)