Skip to content

Commit eeeb73a

Browse files
committed
[PrintAsClang] Ensure that all macro-generated decls get printed.
Some macro-generated declarations are not being printed in the Obj-C/C++ generated header. Members introduced by attached `member` macros on a type appear to be fine, but those introduced by a attached `peer` or freestanding `declaration` macros don't show up. This change updates the header writer to call `getAllMembers` throughout instead of `getMembers`, which makes sure that everything gets collected. Likewise, we update the top-level logic from `getTopLevelDecls` to `getTopLevelDeclsWithAuxiliaryDecls` to pick up freestanding decls introduced at file scope. Fixes #68170.
1 parent 62993ff commit eeeb73a

File tree

5 files changed

+270
-32
lines changed

5 files changed

+270
-32
lines changed

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ class DeclAndTypePrinter::Implementation
188188
}
189189

190190
bool isEmptyExtensionDecl(const ExtensionDecl *ED) {
191-
auto members = ED->getMembers();
191+
auto members = ED->getAllMembers();
192192
auto hasMembers = std::any_of(members.begin(), members.end(),
193193
[this](const Decl *D) -> bool {
194194
if (auto VD = dyn_cast<ValueDecl>(D))
@@ -349,7 +349,7 @@ class DeclAndTypePrinter::Implementation
349349
if (outputLang == OutputLanguageMode::Cxx) {
350350
// FIXME: Non objc class.
351351
ClangClassTypePrinter(os).printClassTypeDecl(
352-
CD, [&]() { printMembers(CD->getMembers()); }, owningPrinter);
352+
CD, [&]() { printMembers(CD->getAllMembers()); }, owningPrinter);
353353
recordEmittedDeclInCurrentCxxLexicalScope(CD);
354354
return;
355355
}
@@ -389,7 +389,7 @@ class DeclAndTypePrinter::Implementation
389389
os << " : " << getNameForObjC(superDecl);
390390
printProtocols(CD->getLocalProtocols(ConformanceLookupKind::OnlyExplicit));
391391
os << "\n";
392-
printMembers(CD->getMembers());
392+
printMembers(CD->getAllMembers());
393393
os << "@end\n";
394394
}
395395

@@ -402,13 +402,13 @@ class DeclAndTypePrinter::Implementation
402402
printer.printValueTypeDecl(
403403
SD, /*bodyPrinter=*/
404404
[&]() {
405-
printMembers(SD->getMembers());
405+
printMembers(SD->getAllMembers());
406406
for (const auto *ed :
407407
owningPrinter.interopContext.getExtensionsForNominalType(SD)) {
408408
if (!cxx_translation::isExposableToCxx(ed->getGenericSignature()))
409409
continue;
410410

411-
printMembers(ed->getMembers());
411+
printMembers(ed->getAllMembers());
412412
}
413413
},
414414
owningPrinter);
@@ -428,7 +428,7 @@ class DeclAndTypePrinter::Implementation
428428
os << " (SWIFT_EXTENSION(" << ED->getModuleContext()->getName() << "))";
429429
printProtocols(ED->getLocalProtocols(ConformanceLookupKind::OnlyExplicit));
430430
os << "\n";
431-
printMembers(ED->getMembers());
431+
printMembers(ED->getAllMembers());
432432
os << "@end\n";
433433
}
434434

@@ -449,7 +449,7 @@ class DeclAndTypePrinter::Implementation
449449

450450
printProtocols(PD->getInheritedProtocols());
451451
os << "\n";
452-
printMembers(PD->getMembers());
452+
printMembers(PD->getAllMembers());
453453
os << "@end\n";
454454
}
455455

@@ -884,14 +884,14 @@ class DeclAndTypePrinter::Implementation
884884
os << " }\n"; // operator cases()'s closing bracket
885885
os << "\n";
886886

887-
printMembers(ED->getMembers());
887+
printMembers(ED->getAllMembers());
888888

889889
for (const auto *ext :
890890
owningPrinter.interopContext.getExtensionsForNominalType(ED)) {
891891
if (!cxx_translation::isExposableToCxx(ext->getGenericSignature()))
892892
continue;
893893

894-
printMembers(ext->getMembers());
894+
printMembers(ext->getAllMembers());
895895
}
896896
},
897897
owningPrinter);

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ class ModuleWriter {
350350
}
351351
}
352352

353-
bool forwardDeclareMemberTypes(DeclRange members, const Decl *container) {
353+
bool forwardDeclareMemberTypes(ArrayRef<Decl *> members,
354+
const Decl *container) {
354355
PrettyStackTraceDecl
355356
entry("printing forward declarations needed by members of", container);
356357
switch (container->getKind()) {
@@ -480,7 +481,7 @@ class ModuleWriter {
480481
if (!allRequirementsSatisfied)
481482
return false;
482483

483-
(void)forwardDeclareMemberTypes(CD->getMembers(), CD);
484+
(void)forwardDeclareMemberTypes(CD->getAllMembers(), CD);
484485
auto [it, inserted] =
485486
seenTypes.try_emplace(CD, EmissionState::NotYetDefined, false);
486487
if (outputLangMode == OutputLanguageMode::Cxx &&
@@ -515,10 +516,10 @@ class ModuleWriter {
515516
if (addImport(SD))
516517
return true;
517518
if (outputLangMode == OutputLanguageMode::Cxx) {
518-
(void)forwardDeclareMemberTypes(SD->getMembers(), SD);
519+
(void)forwardDeclareMemberTypes(SD->getAllMembers(), SD);
519520
for (const auto *ed :
520521
printer.getInteropContext().getExtensionsForNominalType(SD)) {
521-
(void)forwardDeclareMemberTypes(ed->getMembers(), SD);
522+
(void)forwardDeclareMemberTypes(ed->getAllMembers(), SD);
522523
}
523524
forwardDeclareCxxValueTypeIfNeeded(SD);
524525
}
@@ -545,7 +546,7 @@ class ModuleWriter {
545546
if (!allRequirementsSatisfied)
546547
return false;
547548

548-
if (!forwardDeclareMemberTypes(PD->getMembers(), PD))
549+
if (!forwardDeclareMemberTypes(PD->getAllMembers(), PD))
549550
return false;
550551

551552
seenTypes[PD] = { EmissionState::Defined, true };
@@ -572,7 +573,7 @@ class ModuleWriter {
572573
// This isn't rolled up into the previous set of requirements because
573574
// it /also/ prints forward declarations, and the header is a little
574575
// prettier if those are as close as possible to the necessary extension.
575-
if (!forwardDeclareMemberTypes(ED->getMembers(), ED))
576+
if (!forwardDeclareMemberTypes(ED->getAllMembers(), ED))
576577
return false;
577578

578579
os << '\n';
@@ -585,7 +586,7 @@ class ModuleWriter {
585586
return true;
586587

587588
if (outputLangMode == OutputLanguageMode::Cxx) {
588-
forwardDeclareMemberTypes(ED->getMembers(), ED);
589+
forwardDeclareMemberTypes(ED->getAllMembers(), ED);
589590
forwardDeclareCxxValueTypeIfNeeded(ED);
590591
}
591592

@@ -617,7 +618,7 @@ class ModuleWriter {
617618

618619
void write() {
619620
SmallVector<Decl *, 64> decls;
620-
M.getTopLevelDecls(decls);
621+
M.getTopLevelDeclsWithAuxiliaryDecls(decls);
621622
llvm::DenseSet<const ValueDecl *> removedValueDecls;
622623

623624
auto newEnd =
@@ -649,7 +650,7 @@ class ModuleWriter {
649650
if (!ext ||
650651
ext->getExtendedNominal() != M.getASTContext().getStringDecl())
651652
continue;
652-
for (auto *m : ext->getMembers()) {
653+
for (auto *m : ext->getAllMembers()) {
653654
if (auto *sd = dyn_cast<StructDecl>(m)) {
654655
if (sd->getBaseIdentifier().str() == "UTF8View" ||
655656
sd->getBaseIdentifier().str() == "Index") {
@@ -761,8 +762,8 @@ class ModuleWriter {
761762
// Break ties in extensions by putting smaller extensions last (in reverse
762763
// order).
763764
// FIXME: This will end up taking linear time.
764-
auto lhsMembers = cast<ExtensionDecl>(*lhs)->getMembers();
765-
auto rhsMembers = cast<ExtensionDecl>(*rhs)->getMembers();
765+
auto lhsMembers = cast<ExtensionDecl>(*lhs)->getAllMembers();
766+
auto rhsMembers = cast<ExtensionDecl>(*rhs)->getAllMembers();
766767
unsigned numLHSMembers = std::distance(lhsMembers.begin(),
767768
lhsMembers.end());
768769
unsigned numRHSMembers = std::distance(rhsMembers.begin(),
@@ -794,18 +795,19 @@ class ModuleWriter {
794795
// Still nothing? Fine, we'll pick the one with the alphabetically first
795796
// member instead.
796797
{
797-
auto mismatch =
798-
std::mismatch(cast<ExtensionDecl>(*lhs)->getMembers().begin(),
799-
cast<ExtensionDecl>(*lhs)->getMembers().end(),
800-
cast<ExtensionDecl>(*rhs)->getMembers().begin(),
801-
[] (const Decl *nextLHSDecl, const Decl *nextRHSDecl) {
802-
if (isa<ValueDecl>(nextLHSDecl) && isa<ValueDecl>(nextRHSDecl)) {
803-
return cast<ValueDecl>(nextLHSDecl)->getName() !=
804-
cast<ValueDecl>(nextRHSDecl)->getName();
805-
}
806-
return isa<ValueDecl>(nextLHSDecl) != isa<ValueDecl>(nextRHSDecl);
807-
});
808-
if (mismatch.first != cast<ExtensionDecl>(*lhs)->getMembers().end()) {
798+
auto mismatch = std::mismatch(
799+
cast<ExtensionDecl>(*lhs)->getAllMembers().begin(),
800+
cast<ExtensionDecl>(*lhs)->getAllMembers().end(),
801+
cast<ExtensionDecl>(*rhs)->getAllMembers().begin(),
802+
[](const Decl *nextLHSDecl, const Decl *nextRHSDecl) {
803+
if (isa<ValueDecl>(nextLHSDecl) && isa<ValueDecl>(nextRHSDecl)) {
804+
return cast<ValueDecl>(nextLHSDecl)->getName() !=
805+
cast<ValueDecl>(nextRHSDecl)->getName();
806+
}
807+
return isa<ValueDecl>(nextLHSDecl) != isa<ValueDecl>(nextRHSDecl);
808+
});
809+
if (mismatch.first !=
810+
cast<ExtensionDecl>(*lhs)->getAllMembers().end()) {
809811
auto *lhsMember = dyn_cast<ValueDecl>(*mismatch.first),
810812
*rhsMember = dyn_cast<ValueDecl>(*mismatch.second);
811813
if (!rhsMember && lhsMember)
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import SwiftParser
2+
import SwiftSyntax
3+
import SwiftSyntaxBuilder
4+
import SwiftSyntaxMacros
5+
6+
struct ObjCMemberFuncMacro: MemberMacro {
7+
static func expansion(
8+
of node: AttributeSyntax,
9+
providingMembersOf declaration: some DeclGroupSyntax,
10+
conformingTo protocols: [TypeSyntax],
11+
in context: some MacroExpansionContext
12+
) throws -> [DeclSyntax] {
13+
guard let decl = declaration.asProtocol(NamedDeclSyntax.self) else {
14+
return []
15+
}
16+
return ["@objc public func member_\(raw: decl.name.text)() {}"]
17+
}
18+
}
19+
20+
struct ObjCPeerFuncMacro: PeerMacro {
21+
static func expansion(
22+
of node: AttributeSyntax,
23+
providingPeersOf declaration: some DeclSyntaxProtocol,
24+
in context: some MacroExpansionContext
25+
) throws -> [DeclSyntax] {
26+
guard let decl = declaration.asProtocol(NamedDeclSyntax.self) else {
27+
return []
28+
}
29+
return ["@objc public func peer_\(raw: decl.name.text)() {}"]
30+
}
31+
}
32+
33+
struct ObjCFreestandingFuncMacro: DeclarationMacro {
34+
static func expansion(
35+
of node: some FreestandingMacroExpansionSyntax,
36+
in context: some MacroExpansionContext
37+
) throws -> [DeclSyntax] {
38+
return ["@objc public func member_freestanding() {}"]
39+
}
40+
}
41+
42+
struct ObjCFreestandingClassMacro: DeclarationMacro {
43+
static func expansion(
44+
of node: some FreestandingMacroExpansionSyntax,
45+
in context: some MacroExpansionContext
46+
) throws -> [DeclSyntax] {
47+
return ["""
48+
@objc public class MacroExpandedObjCClass: NSObject {
49+
@objc public func member() {}
50+
}
51+
"""]
52+
}
53+
}
54+
55+
struct CDeclFreestandingFuncMacro: DeclarationMacro {
56+
static func expansion(
57+
of node: some FreestandingMacroExpansionSyntax,
58+
in context: some MacroExpansionContext
59+
) throws -> [DeclSyntax] {
60+
return [#"@_cdecl("c_freestanding") public func cFreestanding() {}"#]
61+
}
62+
}
63+
64+
struct ObjCExtensionMacro: ExtensionMacro {
65+
static func expansion(
66+
of node: AttributeSyntax,
67+
attachedTo declaration: some DeclGroupSyntax,
68+
providingExtensionsOf type: some TypeSyntaxProtocol,
69+
conformingTo protocols: [TypeSyntax],
70+
in context: some MacroExpansionContext
71+
) throws -> [ExtensionDeclSyntax] {
72+
let decl: DeclSyntax = """
73+
extension \(type): MyObjCProtocol {
74+
public func objcRequirement() {}
75+
}
76+
"""
77+
return [decl.as(ExtensionDeclSyntax.self)!]
78+
}
79+
}
80+
81+
struct MemberFuncMacro: MemberMacro {
82+
static func expansion(
83+
of node: AttributeSyntax,
84+
providingMembersOf declaration: some DeclGroupSyntax,
85+
conformingTo protocols: [TypeSyntax],
86+
in context: some MacroExpansionContext
87+
) throws -> [DeclSyntax] {
88+
guard let decl = declaration.asProtocol(NamedDeclSyntax.self) else {
89+
return []
90+
}
91+
return ["public func member_\(raw: decl.name.text)() {}"]
92+
}
93+
}
94+
95+
struct PeerFuncMacro: PeerMacro {
96+
static func expansion(
97+
of node: AttributeSyntax,
98+
providingPeersOf declaration: some DeclSyntaxProtocol,
99+
in context: some MacroExpansionContext
100+
) throws -> [DeclSyntax] {
101+
guard let decl = declaration.asProtocol(NamedDeclSyntax.self) else {
102+
return []
103+
}
104+
return ["public func peer_\(raw: decl.name.text)() {}"]
105+
}
106+
}
107+
108+
struct CxxFreestandingFuncMacro: DeclarationMacro {
109+
static func expansion(
110+
of node: some FreestandingMacroExpansionSyntax,
111+
in context: some MacroExpansionContext
112+
) throws -> [DeclSyntax] {
113+
return ["public func cxxFreestanding() {}"]
114+
}
115+
}
116+
117+
struct CxxFreestandingStructMacro: DeclarationMacro {
118+
static func expansion(
119+
of node: some FreestandingMacroExpansionSyntax,
120+
in context: some MacroExpansionContext
121+
) throws -> [DeclSyntax] {
122+
return ["""
123+
public struct MacroExpandedStruct {
124+
private let x: Int = 0
125+
public func member() {}
126+
}
127+
"""]
128+
}
129+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// REQUIRES: swift_swift_parser
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/objc_cxx_macro_definitions.swift -g -no-toolchain-stdlib-rpath
5+
// RUN: %target-build-swift -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) %s -o %t/main -module-name MacroUser -swift-version 5
6+
// RUN: %target-codesign %t/main
7+
8+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk) -typecheck -swift-version 5 -parse-as-library -clang-header-expose-decls=all-public -emit-clang-header-path %t/MacroUser.h -load-plugin-library %t/%target-library-name(MacroDefinition) %s -module-name MacroUser
9+
// RUN: %FileCheck --check-prefix CHECK %s < %t/MacroUser.h
10+
11+
@attached(member, names: prefixed(member_))
12+
public macro MemberFunc() = #externalMacro(module: "MacroDefinition", type: "MemberFuncMacro")
13+
14+
@attached(peer, names: prefixed(peer_))
15+
public macro PeerFunc() = #externalMacro(module: "MacroDefinition", type: "PeerFuncMacro")
16+
17+
@freestanding(declaration, names: named(cxxFreestanding))
18+
public macro CxxFreestandingFunc() = #externalMacro(module: "MacroDefinition", type: "CxxFreestandingFuncMacro")
19+
20+
@freestanding(declaration, names: named(MacroExpandedStruct))
21+
public macro CxxFreestandingStruct() = #externalMacro(module: "MacroDefinition", type: "CxxFreestandingStructMacro")
22+
23+
// ---
24+
25+
// CHECK: class SWIFT_SYMBOL("s:9MacroUser0A14ExpandedStructV") MacroExpandedStruct final {
26+
// CHECK-DAG: SWIFT_INLINE_THUNK void member() const SWIFT_SYMBOL("s:9MacroUser0A14ExpandedStructV6memberyyF");
27+
#CxxFreestandingStruct
28+
29+
// CHECK: class SWIFT_SYMBOL("s:9MacroUser10SomeStructV") SomeStruct final {
30+
@MemberFunc
31+
public struct SomeStruct {
32+
private var someProperty: Int = 0
33+
34+
@PeerFunc
35+
public func someMethod() {}
36+
37+
#CxxFreestandingFunc
38+
39+
// CHECK-DAG: SWIFT_INLINE_THUNK void peer_someMethod() const SWIFT_SYMBOL("s:9MacroUser10SomeStructV15peer_someMethodyyF");
40+
// CHECK-DAG: SWIFT_INLINE_THUNK void someMethod() const SWIFT_SYMBOL("s:9MacroUser10SomeStructV10someMethodyyF");
41+
// CHECK-DAG: SWIFT_INLINE_THUNK void cxxFreestanding() const SWIFT_SYMBOL("s:9MacroUser10SomeStructV15cxxFreestandingyyF");
42+
// CHECK-DAG: SWIFT_INLINE_THUNK void member_SomeStruct() const SWIFT_SYMBOL("s:9MacroUser10SomeStructV07member_cD0yyF");
43+
}

0 commit comments

Comments
 (0)