Skip to content

Commit e265863

Browse files
[Macro] Fix bugs in macro dependency scanning
Fix few issues from previous implementation from explicit module build with macros and accurate macro dependency scanning in swiftlang#73421. First, there is a crash when propagating the macro dependencies. It turns out that the current macro plugin implementation doesn't need the downstream users to know about the plugin search path from the upstream dependencies. Secondly, fix a bug that the swiftinterface that has macro usage won't build because the build command doesn't inherit the plugin search path option. Finally, add JSON output for macro dependencies so it is easier to debug the macro dependencies. rdar://131214106
1 parent 4e4d547 commit e265863

File tree

9 files changed

+252
-16
lines changed

9 files changed

+252
-16
lines changed

include/swift-c/DependencyScan/DependencyScan.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ typedef struct swiftscan_dependency_info_s *swiftscan_dependency_info_t;
4949
/// Opaque container to a link library info.
5050
typedef struct swiftscan_link_library_info_s *swiftscan_link_library_info_t;
5151

52+
/// Opaque container to a macro dependency.
53+
typedef struct swiftscan_macro_dependency_s *swiftscan_macro_dependency_t;
54+
5255
/// Opaque container to an overall result of a dependency scan.
5356
typedef struct swiftscan_dependency_graph_s *swiftscan_dependency_graph_t;
5457

@@ -73,6 +76,12 @@ typedef struct {
7376
size_t count;
7477
} swiftscan_link_library_set_t;
7578

79+
/// Set of macro dependency
80+
typedef struct {
81+
swiftscan_macro_dependency_t *macro_dependencies;
82+
size_t count;
83+
} swiftscan_macro_dependency_set_t;
84+
7685
typedef enum {
7786
SWIFTSCAN_DIAGNOSTIC_SEVERITY_ERROR = 0,
7887
SWIFTSCAN_DIAGNOSTIC_SEVERITY_WARNING = 1,

include/swift/AST/ModuleDependencies.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ struct CommonSwiftTextualModuleDependencyDetails {
253253
std::vector<std::string> bridgingModuleDependencies;
254254

255255
/// The macro dependencies.
256-
llvm::StringMap<MacroPluginDependency> macroDependencies;
256+
std::map<std::string, MacroPluginDependency> macroDependencies;
257257

258258
/// The Swift frontend invocation arguments to build the Swift module from the
259259
/// interface.
@@ -324,7 +324,7 @@ class SwiftInterfaceModuleDependenciesStorage
324324
void addMacroDependency(StringRef macroModuleName, StringRef libraryPath,
325325
StringRef executablePath) {
326326
textualModuleDetails.macroDependencies.insert(
327-
{macroModuleName, {libraryPath.str(), executablePath.str()}});
327+
{macroModuleName.str(), {libraryPath.str(), executablePath.str()}});
328328
}
329329
};
330330

@@ -380,7 +380,7 @@ class SwiftSourceModuleDependenciesStorage
380380
void addMacroDependency(StringRef macroModuleName, StringRef libraryPath,
381381
StringRef executablePath) {
382382
textualModuleDetails.macroDependencies.insert(
383-
{macroModuleName, {libraryPath.str(), executablePath.str()}});
383+
{macroModuleName.str(), {libraryPath.str(), executablePath.str()}});
384384
}
385385
};
386386

@@ -796,7 +796,7 @@ class ModuleDependencyInfo {
796796
/// For a Source dependency, register a `Testable` import
797797
void addTestableImport(ImportPath::Module module);
798798

799-
/// For a Source dependency, register a macro dependency.
799+
/// For a Source/Textual dependency, register a macro dependency.
800800
void addMacroDependency(StringRef macroModuleName, StringRef libraryPath,
801801
StringRef executablePath);
802802

include/swift/DependencyScan/DependencyScanImpl.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ struct swiftscan_link_library_info_s {
7373
bool forceLoad;
7474
};
7575

76+
struct swiftscan_macro_dependency_s {
77+
swiftscan_string_ref_t moduleName;
78+
swiftscan_string_ref_t libraryPath;
79+
swiftscan_string_ref_t executablePath;
80+
};
81+
7682
/// Swift modules to be built from a module interface, may have a bridging
7783
/// header.
7884
typedef struct {
@@ -123,6 +129,9 @@ typedef struct {
123129

124130
/// ModuleCacheKey
125131
swiftscan_string_ref_t module_cache_key;
132+
133+
/// Macro dependecies.
134+
swiftscan_macro_dependency_set_t *macro_dependencies;
126135
} swiftscan_swift_textual_details_t;
127136

128137
/// Swift modules with only a binary module file.

lib/DependencyScan/DependencyScanJSON.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,49 @@ void writeLinkLibraries(llvm::raw_ostream &out,
243243
out << "\n";
244244
}
245245

246+
static void
247+
writeMacroDependencies(llvm::raw_ostream &out,
248+
const swiftscan_macro_dependency_set_t *macro_deps,
249+
unsigned indentLevel, bool trailingComma) {
250+
if (macro_deps->count == 0)
251+
return;
252+
253+
out.indent(indentLevel * 2);
254+
out << "\"macroDependencies\": ";
255+
out << "[\n";
256+
for (size_t i = 0; i < macro_deps->count; ++i) {
257+
const auto &macroInfo = *macro_deps->macro_dependencies[i];
258+
out.indent((indentLevel + 1) * 2);
259+
out << "{\n";
260+
auto entryIndentLevel = ((indentLevel + 2) * 2);
261+
out.indent(entryIndentLevel);
262+
out << "\"moduleName\": ";
263+
writeJSONValue(out, macroInfo.moduleName, indentLevel);
264+
out << ",\n";
265+
out.indent(entryIndentLevel);
266+
out << "\"libraryPath\": ";
267+
writeJSONValue(out, macroInfo.libraryPath, entryIndentLevel);
268+
out << ",\n";
269+
out.indent(entryIndentLevel);
270+
out << "\"executablePath\": ";
271+
writeJSONValue(out, macroInfo.executablePath, entryIndentLevel);
272+
out << "\n";
273+
out.indent((indentLevel + 1) * 2);
274+
out << "}";
275+
if (i != macro_deps->count - 1) {
276+
out << ",";
277+
}
278+
out << "\n";
279+
}
280+
281+
out.indent(indentLevel * 2);
282+
out << "]";
283+
284+
if (trailingComma)
285+
out << ",";
286+
out << "\n";
287+
}
288+
246289
static const swiftscan_swift_textual_details_t *
247290
getAsTextualDependencyModule(swiftscan_module_details_t details) {
248291
if (details->kind == SWIFTSCAN_DEPENDENCY_INFO_SWIFT_TEXTUAL)
@@ -413,6 +456,8 @@ void writeJSON(llvm::raw_ostream &out,
413456
swiftTextualDeps->module_cache_key, 5,
414457
/*trailingComma=*/true);
415458
}
459+
writeMacroDependencies(out, swiftTextualDeps->macro_dependencies, 5,
460+
/*trailingComma=*/true);
416461
writeJSONSingleField(out, "isFramework", swiftTextualDeps->is_framework,
417462
5, commaAfterFramework);
418463
if (swiftTextualDeps->extra_pcm_args->count != 0) {

lib/DependencyScan/ModuleDependencyCacheSerialization.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi
305305
if (!moduleCacheKeyID)
306306
llvm::report_fatal_error("Bad moduleCacheKey");
307307

308-
// TODO: LinkLibraries
308+
// TODO: LinkLibraries, MacroDependencies
309309
// Form the dependencies storage object
310310
auto moduleDep = ModuleDependencyInfo::forSwiftInterfaceModule(
311311
outputModulePath.value(), optionalSwiftInterfaceFile.value(),

lib/DependencyScan/ScanDependencies.cpp

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "swift-c/DependencyScan/DependencyScan.h"
1314
#include "swift/Basic/PrettyStackTrace.h"
1415

1516
#include "swift/AST/ASTContext.h"
@@ -256,14 +257,6 @@ static llvm::Error resolveExplicitModuleInputs(
256257
: interfaceDepDetails->moduleCacheKey;
257258
commandLine.push_back("-swift-module-file=" + depModuleID.ModuleName + "=" +
258259
path);
259-
// Add the exported macro from interface into current module.
260-
llvm::for_each(
261-
interfaceDepDetails->textualModuleDetails.macroDependencies,
262-
[&](const auto &entry) {
263-
dependencyInfoCopy.addMacroDependency(entry.first(),
264-
entry.second.LibraryPath,
265-
entry.second.ExecutablePath);
266-
});
267260
} break;
268261
case swift::ModuleDependencyKind::SwiftBinary: {
269262
auto binaryDepDetails = depInfo.getAsSwiftBinaryModule();
@@ -282,7 +275,7 @@ static llvm::Error resolveExplicitModuleInputs(
282275
{bridgingHeaderDepName, ModuleDependencyKind::Clang});
283276
const auto bridgingHeaderDepModuleDetails =
284277
optionalBridgingHeaderDepModuleInfo.getAsClangModule();
285-
commandLine.push_back("-Xcc");
278+
commandLine.push_back("-Xcc");
286279
commandLine.push_back(
287280
"-fmodule-map-file=" +
288281
remapPath(bridgingHeaderDepModuleDetails->moduleMapFile));
@@ -372,6 +365,10 @@ static llvm::Error resolveExplicitModuleInputs(
372365
llvm::for_each(
373366
textualDep->auxiliaryFiles,
374367
[&tracker](const std::string &file) { tracker->trackFile(file); });
368+
llvm::for_each(textualDep->textualModuleDetails.macroDependencies,
369+
[&tracker](const auto &entry) {
370+
tracker->trackFile(entry.second.LibraryPath);
371+
});
375372
auto root = tracker->createTreeFromDependencies();
376373
if (!root)
377374
return root.takeError();
@@ -642,6 +639,28 @@ static swiftscan_diagnostic_set_t *mapCollectedDiagnosticsForOutput(
642639
return diagnosticOutput;
643640
}
644641

642+
static swiftscan_macro_dependency_set_t *createMacroDependencySet(
643+
const std::map<std::string, MacroPluginDependency> &macroDeps) {
644+
swiftscan_macro_dependency_set_t *set = new swiftscan_macro_dependency_set_t;
645+
if (macroDeps.empty()) {
646+
set->count = 0;
647+
set->macro_dependencies = nullptr;
648+
return set;
649+
}
650+
set->count = macroDeps.size();
651+
set->macro_dependencies = new swiftscan_macro_dependency_t[set->count];
652+
unsigned SI = 0;
653+
for (auto &entry : macroDeps) {
654+
set->macro_dependencies[SI] = new swiftscan_macro_dependency_s;
655+
set->macro_dependencies[SI]->moduleName = create_clone(entry.first.c_str());
656+
set->macro_dependencies[SI]->libraryPath =
657+
create_clone(entry.second.LibraryPath.c_str());
658+
set->macro_dependencies[SI]->executablePath =
659+
create_clone(entry.second.ExecutablePath.c_str());
660+
}
661+
return set;
662+
}
663+
645664
static swiftscan_dependency_graph_t
646665
generateFullDependencyGraph(const CompilerInstance &instance,
647666
const DependencyScanDiagnosticCollector *diagnosticCollector,
@@ -732,7 +751,9 @@ generateFullDependencyGraph(const CompilerInstance &instance,
732751
.CASFileSystemRootID.c_str()),
733752
create_clone(swiftTextualDeps->textualModuleDetails
734753
.CASBridgingHeaderIncludeTreeRootID.c_str()),
735-
create_clone(swiftTextualDeps->moduleCacheKey.c_str())};
754+
create_clone(swiftTextualDeps->moduleCacheKey.c_str()),
755+
createMacroDependencySet(
756+
swiftTextualDeps->textualModuleDetails.macroDependencies)};
736757
} else if (swiftSourceDeps) {
737758
swiftscan_string_ref_t moduleInterfacePath = create_null();
738759
swiftscan_string_ref_t bridgingHeaderPath =
@@ -767,7 +788,9 @@ generateFullDependencyGraph(const CompilerInstance &instance,
767788
/*IncludeTree*/
768789
create_clone(swiftSourceDeps->textualModuleDetails
769790
.CASBridgingHeaderIncludeTreeRootID.c_str()),
770-
/*CacheKey*/ create_clone("")};
791+
/*CacheKey*/ create_clone(""),
792+
createMacroDependencySet(
793+
swiftSourceDeps->textualModuleDetails.macroDependencies)};
771794
} else if (swiftPlaceholderDeps) {
772795
details->kind = SWIFTSCAN_DEPENDENCY_INFO_SWIFT_PLACEHOLDER;
773796
details->swift_placeholder_details = {

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/AST/DiagnosticsSema.h"
2020
#include "swift/AST/FileSystem.h"
2121
#include "swift/AST/Module.h"
22+
#include "swift/AST/SearchPathOptions.h"
2223
#include "swift/Basic/Assertions.h"
2324
#include "swift/Basic/Platform.h"
2425
#include "swift/Basic/StringExtras.h"
@@ -1697,6 +1698,39 @@ void InterfaceSubContextDelegateImpl::inheritOptionsForBuildingInterface(
16971698
genericSubInvocation.setPlatformAvailabilityInheritanceMapPath(*SearchPathOpts.PlatformAvailabilityInheritanceMapPath);
16981699
}
16991700

1701+
for (auto &entry : SearchPathOpts.PluginSearchOpts) {
1702+
switch (entry.getKind()) {
1703+
case PluginSearchOption::Kind::LoadPluginLibrary: {
1704+
auto &val = entry.get<PluginSearchOption::LoadPluginLibrary>();
1705+
GenericArgs.push_back("-load-plugin-library");
1706+
GenericArgs.push_back(ArgSaver.save(val.LibraryPath));
1707+
break;
1708+
}
1709+
case PluginSearchOption::Kind::LoadPluginExecutable: {
1710+
auto &val = entry.get<PluginSearchOption::LoadPluginExecutable>();
1711+
for (auto &moduleName : val.ModuleNames) {
1712+
GenericArgs.push_back("-load-plugin-executable");
1713+
GenericArgs.push_back(
1714+
ArgSaver.save(val.ExecutablePath + "#" + moduleName));
1715+
}
1716+
break;
1717+
}
1718+
case PluginSearchOption::Kind::PluginPath: {
1719+
auto &val = entry.get<PluginSearchOption::PluginPath>();
1720+
GenericArgs.push_back("-plugin-library");
1721+
GenericArgs.push_back(ArgSaver.save(val.SearchPath));
1722+
break;
1723+
}
1724+
case PluginSearchOption::Kind::ExternalPluginPath: {
1725+
auto &val = entry.get<PluginSearchOption::ExternalPluginPath>();
1726+
GenericArgs.push_back("-external-plugin-path");
1727+
GenericArgs.push_back(
1728+
ArgSaver.save(val.SearchPath + "#" + val.ServerPath));
1729+
break;
1730+
}
1731+
}
1732+
}
1733+
17001734
genericSubInvocation.getFrontendOptions().InputMode
17011735
= FrontendOptions::ParseInputMode::SwiftModuleInterface;
17021736
if (!SearchPathOpts.RuntimeResourcePath.empty()) {

test/CAS/macro_deps.swift

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// REQUIRES: swift_swift_parser
2+
3+
/// Test loading dependencies that has macros.
4+
// RUN: %empty-directory(%t)
5+
// RUN: split-file %s %t
6+
7+
/// Build macros.
8+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroOne) -module-name=MacroOne %t/macro-1.swift
9+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroTwo) -module-name=MacroTwo %t/macro-2.swift
10+
11+
/// Build binary module that depends on textual module that uses macro.
12+
// RUN: %target-swift-frontend -emit-module -module-cache-path %t/clang-module-cache %t/test.swift -module-name Test -o %t/include/Test.swiftmodule -I %t/include \
13+
// RUN: -O -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -swift-version 5 -external-plugin-path %t#%swift-plugin-server
14+
15+
// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-serialized -module-name MyApp -module-cache-path %t/clang-module-cache -O \
16+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -I %t/include \
17+
// RUN: %t/main.swift -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas -external-plugin-path %t#%swift-plugin-server
18+
19+
// RUN: %{python} %S/Inputs/SwiftDepsExtractor.py %t/deps.json Foo macroDependencies | %FileCheck %s --check-prefix=FOO-DEPS
20+
// FOO-DEPS: MacroOne
21+
// FOO-DEPS-NOT: MacroTwo
22+
23+
// RUN: %{python} %S/Inputs/SwiftDepsExtractor.py %t/deps.json MyApp macroDependencies | %FileCheck %s --check-prefix=APP-DEPS
24+
// APP-DEPS: MacroTwo
25+
// APP-DEPS-NOT: MacroOne
26+
27+
/// Build all dependencies.
28+
// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:SwiftShims > %t/SwiftShims.cmd
29+
// RUN: %swift_frontend_plain @%t/SwiftShims.cmd
30+
// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json Foo > %t/Foo.cmd
31+
// RUN: %swift_frontend_plain @%t/Foo.cmd
32+
33+
// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json MyApp > %t/MyApp.cmd
34+
// RUN: %{python} %S/Inputs/GenerateExplicitModuleMap.py %t/deps.json > %t/map.json
35+
// RUN: llvm-cas --cas %t/cas --make-blob --data %t/map.json > %t/map.casid
36+
37+
// RUN: %target-swift-frontend -diagnostic-style=swift \
38+
// RUN: -emit-module -o %t/Test.swiftmodule -cache-compile-job -cas-path %t/cas \
39+
// RUN: -swift-version 5 -disable-implicit-swift-modules \
40+
// RUN: -external-plugin-path %t#%swift-plugin-server \
41+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
42+
// RUN: -module-name MyApp -explicit-swift-module-map-file @%t/map.casid -O \
43+
// RUN: %t/main.swift @%t/MyApp.cmd
44+
45+
//--- macro-1.swift
46+
import SwiftSyntax
47+
@_spi(ExperimentalLanguageFeature) import SwiftSyntaxMacros
48+
49+
public struct AssertMacro: ExpressionMacro {
50+
public static func expansion(
51+
of macro: some FreestandingMacroExpansionSyntax,
52+
in context: some MacroExpansionContext
53+
) -> ExprSyntax {
54+
guard let argument = macro.arguments.first?.expression else {
55+
fatalError("boom")
56+
}
57+
58+
return "assert(\(argument))"
59+
}
60+
}
61+
62+
//--- macro-2.swift
63+
import SwiftSyntax
64+
@_spi(ExperimentalLanguageFeature) import SwiftSyntaxMacros
65+
66+
public struct StringifyMacro: ExpressionMacro {
67+
public static func expansion(
68+
of macro: some FreestandingMacroExpansionSyntax,
69+
in context: some MacroExpansionContext
70+
) -> ExprSyntax {
71+
guard let argument = macro.arguments.first?.expression else {
72+
fatalError("boom")
73+
}
74+
75+
return "(\(argument), \(StringLiteralExprSyntax(content: argument.description)))"
76+
}
77+
}
78+
79+
//--- include/Foo.swiftinterface
80+
// swift-interface-format-version: 1.0
81+
// swift-module-flags: -enable-library-evolution -swift-version 5 -O -module-name Foo -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import
82+
import Swift
83+
public func foo()
84+
@freestanding(expression) public macro assert(_: Bool) = #externalMacro(module: "MacroOne", type: "AssertMacro")
85+
@inlinable
86+
public func assertFalse() {
87+
#assert(false)
88+
}
89+
90+
//--- test.swift
91+
import Foo
92+
@inlinable
93+
public func test() {
94+
#assert(true)
95+
}
96+
97+
//--- main.swift
98+
import Test
99+
@freestanding(expression) macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MacroTwo", type: "StringifyMacro")
100+
101+
func appTest() {
102+
let str = #stringify("test")
103+
test()
104+
}

0 commit comments

Comments
 (0)