Skip to content

Commit d3b9f2c

Browse files
[lldb] Fix clang importer for swift caching debugging (attempt #2)
Further improve how lldb constructing clang importer to utilize explicit modules: * Add logics to initialize the swift ASTContext from direct cc1 arguments embedded in the swiftmodule * Make sure the direct cc1 arguments are not repeated constructed. It should only be constructed as a fresh invocation * Make sure the lldb doesn't overwrite the explicit module build settings when filter arguments. This ensures the already built explicit modules are used. * Use the newly added clang option that ignore CAS info when loading PCMs. This allows lldb to load CAS enabled PCM directly from disk. rdar://135611011
1 parent ec2c548 commit d3b9f2c

File tree

11 files changed

+197
-31
lines changed

11 files changed

+197
-31
lines changed

lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp

Lines changed: 103 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include "clang/Basic/TargetOptions.h"
5858
#include "clang/Driver/Driver.h"
5959
#include "clang/Frontend/CompilerInstance.h"
60+
#include "clang/Frontend/TextDiagnosticPrinter.h"
6061
#include "clang/Lex/Preprocessor.h"
6162

6263
#include "clang/Lex/PreprocessorOptions.h"
@@ -1573,21 +1574,7 @@ bool ShouldUnique(StringRef arg) {
15731574

15741575
// static
15751576
void SwiftASTContext::AddExtraClangArgs(const std::vector<std::string> &source,
1576-
std::vector<std::string> &dest,
1577-
bool cc1) {
1578-
// FIXME: Support for cc1 flags isn't complete. The uniquing
1579-
// algortihm below does not work for cc1 flags. Since cc1 flags are
1580-
// not stable it's not feasible to keep a list of all multi-arg
1581-
// flags, for example. It also makes it difficult to correctly
1582-
// identify where workng directories and path remappings should
1583-
// applied. For all these reasons, using cc1 flags for anything but
1584-
// a local build with explicit modules and precise compiler
1585-
// invocations isn't supported yet.
1586-
if (cc1) {
1587-
dest.insert(dest.end(), source.begin(), source.end());
1588-
return;
1589-
}
1590-
1577+
std::vector<std::string> &dest) {
15911578
llvm::StringSet<> unique_flags;
15921579
for (auto &arg : dest)
15931580
unique_flags.insert(arg);
@@ -1764,23 +1751,37 @@ static void applyOverrideOptions(std::vector<std::string> &args,
17641751

17651752
void SwiftASTContext::AddExtraClangArgs(
17661753
const std::vector<std::string> &ExtraArgs, StringRef overrideOpts) {
1754+
if (ExtraArgs.empty())
1755+
return;
1756+
17671757
swift::ClangImporterOptions &importer_options = GetClangImporterOptions();
17681758

17691759
// Detect cc1 flags. When DirectClangCC1ModuleBuild is on then the
17701760
// clang arguments in the serialized invocation are clang cc1 flags,
17711761
// which are very specific to one compiler version and cannot
17721762
// be merged with driver options.
17731763
bool fresh_invocation = importer_options.ExtraArgs.empty();
1774-
if (fresh_invocation && !ExtraArgs.empty() && ExtraArgs.front() == "-cc1")
1775-
importer_options.DirectClangCC1ModuleBuild = true;
1776-
if (!importer_options.DirectClangCC1ModuleBuild && !ExtraArgs.empty() &&
1777-
ExtraArgs.front() == "-cc1")
1764+
bool invocation_direct_cc1 = ExtraArgs.front() == "-cc1";
1765+
1766+
// If it is not a fresh invocation, make sure the cc1 option matches.
1767+
if (!fresh_invocation &&
1768+
(importer_options.DirectClangCC1ModuleBuild != invocation_direct_cc1))
17781769
AddDiagnostic(
17791770
eSeverityWarning,
17801771
"Mixing and matching of driver and cc1 Clang options detected");
17811772

1782-
AddExtraClangArgs(ExtraArgs, importer_options.ExtraArgs,
1783-
importer_options.DirectClangCC1ModuleBuild);
1773+
importer_options.DirectClangCC1ModuleBuild = invocation_direct_cc1;
1774+
1775+
// If using direct cc1 flags, compute the arguments and return.
1776+
// Since this is cc1 flags, override options are driver flags and don't apply.
1777+
if (importer_options.DirectClangCC1ModuleBuild) {
1778+
if (!fresh_invocation)
1779+
importer_options.ExtraArgs.clear();
1780+
AddExtraClangCC1Args(ExtraArgs, importer_options.ExtraArgs);
1781+
return;
1782+
}
1783+
1784+
AddExtraClangArgs(ExtraArgs, importer_options.ExtraArgs);
17841785
applyOverrideOptions(importer_options.ExtraArgs, overrideOpts);
17851786
if (HasNonexistentExplicitModule(importer_options.ExtraArgs))
17861787
RemoveExplicitModules(importer_options.ExtraArgs);
@@ -1792,6 +1793,78 @@ void SwiftASTContext::AddExtraClangArgs(
17921793
});
17931794
}
17941795

1796+
void SwiftASTContext::AddExtraClangCC1Args(
1797+
const std::vector<std::string> &source, std::vector<std::string> &dest) {
1798+
clang::CompilerInvocation invocation;
1799+
llvm::SmallVector<const char *> clangArgs;
1800+
clangArgs.reserve(source.size());
1801+
llvm::for_each(source, [&](const std::string &Arg) {
1802+
// Workaround for the extra driver argument embedded in the swiftmodule by
1803+
// some swift compiler version. It always starts with `--target=` and it is
1804+
// not a valid cc1 option.
1805+
if (!StringRef(Arg).starts_with("--target="))
1806+
clangArgs.push_back(Arg.c_str());
1807+
});
1808+
1809+
std::string diags;
1810+
llvm::raw_string_ostream os(diags);
1811+
auto diagOpts = llvm::makeIntrusiveRefCnt<clang::DiagnosticOptions>();
1812+
clang::DiagnosticsEngine clangDiags(
1813+
new clang::DiagnosticIDs(), diagOpts,
1814+
new clang::TextDiagnosticPrinter(os, diagOpts.get()));
1815+
1816+
if (!clang::CompilerInvocation::CreateFromArgs(invocation, clangArgs,
1817+
clangDiags)) {
1818+
// If cc1 arguments failed to parse, report diagnostics and return
1819+
// immediately.
1820+
AddDiagnostic(eSeverityError, diags);
1821+
// Disable direct-cc1 build as fallback.
1822+
GetClangImporterOptions().DirectClangCC1ModuleBuild = false;
1823+
return;
1824+
}
1825+
1826+
// Clear module cache key and other CAS options to load modules from disk
1827+
// directly.
1828+
invocation.getFrontendOpts().ModuleCacheKeys.clear();
1829+
invocation.getCASOpts() = clang::CASOptions();
1830+
1831+
// Ignore CAS info inside modules when loading.
1832+
invocation.getFrontendOpts().ModuleLoadIgnoreCAS = true;
1833+
1834+
// Remove non-existing modules in a systematic way.
1835+
bool module_missing = false;
1836+
auto CheckFileExists = [&](const char *file) {
1837+
if (!llvm::sys::fs::exists(file)) {
1838+
std::string warn;
1839+
llvm::raw_string_ostream(warn)
1840+
<< "Nonexistent explicit module file " << file;
1841+
AddDiagnostic(eSeverityWarning, warn);
1842+
module_missing = true;
1843+
}
1844+
};
1845+
llvm::for_each(invocation.getHeaderSearchOpts().PrebuiltModuleFiles,
1846+
[&](const auto &mod) { CheckFileExists(mod.second.c_str()); });
1847+
llvm::for_each(invocation.getFrontendOpts().ModuleFiles,
1848+
[&](const auto &mod) { CheckFileExists(mod.c_str()); });
1849+
1850+
// If missing, clear all the prebuilt module options and switch to implicit
1851+
// modules build.
1852+
if (module_missing) {
1853+
invocation.getHeaderSearchOpts().PrebuiltModuleFiles.clear();
1854+
invocation.getFrontendOpts().ModuleFiles.clear();
1855+
invocation.getLangOpts().ImplicitModules = true;
1856+
invocation.getHeaderSearchOpts().ImplicitModuleMaps = true;
1857+
}
1858+
1859+
invocation.generateCC1CommandLine(
1860+
[&](const llvm::Twine &arg) { dest.push_back(arg.str()); });
1861+
1862+
// If cc1 arguments are parsed and generated correctly, set explicitly-built
1863+
// module since only explicit module build can use direct cc1 mode.
1864+
m_has_explicit_modules = true;
1865+
return;
1866+
}
1867+
17951868
void SwiftASTContext::AddUserClangArgs(TargetProperties &props) {
17961869
Args args(props.GetSwiftExtraClangFlags());
17971870
std::vector<std::string> user_clang_flags;
@@ -1883,6 +1956,10 @@ void SwiftASTContext::RemapClangImporterOptions(
18831956

18841957
void SwiftASTContext::FilterClangImporterOptions(
18851958
std::vector<std::string> &extra_args, SwiftASTContext *ctx) {
1959+
// The direct cc1 mode do not need any extra audit.
1960+
if (ctx && ctx->GetClangImporterOptions().DirectClangCC1ModuleBuild)
1961+
return;
1962+
18861963
std::string ivfs_arg;
18871964
// Copy back a filtered version of ExtraArgs.
18881965
std::vector<std::string> orig_args(std::move(extra_args));
@@ -1893,11 +1970,6 @@ void SwiftASTContext::FilterClangImporterOptions(
18931970
arg_sr == "-fno-implicit-module-maps")
18941971
continue;
18951972

1896-
// This is not a cc1 option.
1897-
if (arg_sr.starts_with("--target=") && ctx &&
1898-
ctx->GetClangImporterOptions().DirectClangCC1ModuleBuild)
1899-
continue;
1900-
19011973
// The VFS options turn into fatal errors when the referenced file
19021974
// is not found. Since the Xcode build system tends to create a
19031975
// lot of VFS overlays by default, stat them and emit a warning if
@@ -2184,6 +2256,11 @@ ProcessModule(Module &module, std::string m_description,
21842256
for (auto path : opts.getFrameworkSearchPaths())
21852257
framework_search_paths.push_back({path.Path, path.IsSystem});
21862258
auto &clang_opts = invocation.getClangImporterOptions().ExtraArgs;
2259+
// If the args embedded are cc1 args, they are not compatible with existing
2260+
// setting. Clear the previous args.
2261+
if (!clang_opts.empty() && clang_opts.front() == "-cc1")
2262+
extra_clang_args.clear();
2263+
21872264
for (const std::string &arg : clang_opts) {
21882265
extra_clang_args.push_back(arg);
21892266
LOG_VERBOSE_PRINTF(GetLog(LLDBLog::Types), "adding Clang argument \"%s\".",

lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,10 @@ class SwiftASTContext : public TypeSystemSwift {
278278
/// apply the working directory to any relative paths.
279279
void AddExtraClangArgs(const std::vector<std::string> &ExtraArgs,
280280
llvm::StringRef overrideOpts = "");
281+
void AddExtraClangCC1Args(const std::vector<std::string>& source,
282+
std::vector<std::string>& dest);
281283
static void AddExtraClangArgs(const std::vector<std::string>& source,
282-
std::vector<std::string>& dest, bool cc1);
284+
std::vector<std::string>& dest);
283285
static std::string GetPluginServer(llvm::StringRef plugin_library_path);
284286
/// Removes nonexisting VFS overlay options.
285287
static void FilterClangImporterOptions(std::vector<std::string> &extra_args,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
SWIFT_SOURCES := main.swift
2+
SWIFT_ENABLE_EXPLICIT_MODULES := YES
3+
SWIFTFLAGS_EXTRAS = -I$(SRCDIR) -cache-compile-job -cas-path $(BUILDDIR)/cas
4+
5+
include Makefile.rules
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import lldb
2+
from lldbsuite.test.lldbtest import *
3+
from lldbsuite.test.decorators import *
4+
import lldbsuite.test.lldbutil as lldbutil
5+
import unittest2
6+
7+
class TestSwiftClangImporterCaching(TestBase):
8+
9+
NO_DEBUG_INFO_TESTCASE = True
10+
11+
# Don't run ClangImporter tests if Clangimporter is disabled.
12+
@skipIf(setting=('symbols.use-swift-clangimporter', 'false'))
13+
@skipIf(setting=('symbols.swift-precise-compiler-invocation', 'false'))
14+
@skipIf(setting=('plugin.typesystem.clang.experimental-redecl-completion', 'true'), bugnumber='rdar://128094135')
15+
@skipUnlessDarwin
16+
@swiftTest
17+
def test(self):
18+
"""
19+
Test flipping on/off implicit modules.
20+
"""
21+
self.build()
22+
lldbutil.run_to_source_breakpoint(self, "break here",
23+
lldb.SBFileSpec('main.swift'))
24+
log = self.getBuildArtifact("types.log")
25+
self.expect('log enable lldb types -f "%s"' % log)
26+
self.expect("expression obj", DATA_TYPES_DISPLAYED_CORRECTLY,
27+
substrs=["b ="])
28+
self.filecheck('platform shell cat "%s"' % log, __file__)
29+
### -cc1 should be round-tripped so there is no more `-cc1` in the extra args. Look for `-triple` which is a cc1 flag.
30+
# CHECK: SwiftASTContextForExpressions(module: "a", cu: "main.swift")::LogConfiguration() -- -triple
31+
# CHECK: SwiftASTContextForExpressions(module: "a", cu: "main.swift") Module import remark: loaded module 'ClangA'
32+
# CHECK-NOT: -cc1
33+
# CHECK-NOT: -fmodule-file-cache-key
34+
# CHECK-NOT: Clang error:
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include "b.h"
2+
3+
struct A {
4+
struct B b;
5+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
struct B {};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import ClangA
2+
let obj = A()
3+
print("break here \(obj)")
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module ClangA {
2+
header "a.h"
3+
}
4+
5+
module ClangB {
6+
header "b.h"
7+
}

lldb/test/API/lang/swift/clangimporter/explicit_cc1/TestSwiftClangImporterExplicitCC1.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,6 @@ def test(self):
2626
self.expect("expression obj", DATA_TYPES_DISPLAYED_CORRECTLY,
2727
substrs=["b ="])
2828
self.filecheck('platform shell cat "%s"' % log, __file__)
29-
# CHECK: SwiftASTContextForExpressions(module: "a", cu: "main.swift")::LogConfiguration() -- -cc1
29+
### -cc1 should be round-tripped so there is no more `-cc1` in the extra args. Look for `-triple` which is a cc1 flag.
30+
# CHECK: SwiftASTContextForExpressions(module: "a", cu: "main.swift")::LogConfiguration() -- -triple
31+
# CHECK-NOT: -cc1

lldb/test/Shell/Swift/caching.test

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# REQUIRES: swift
2+
# REQUIRES: system-darwin
3+
4+
# RUN: rm -rf %t && mkdir %t
5+
# RUN: split-file %s %t
6+
# RUN: %target-swiftc -g -Onone -save-temps \
7+
# RUN: -module-cache-path %t/cache %t/main.swift \
8+
# RUN: -cache-compile-job -cas-path %t/cas -explicit-module-build \
9+
# RUN: -module-name main -o %t/main
10+
11+
# RUN: %lldb %t/main -s %t/lldb.script 2>&1 | FileCheck %s
12+
# CHECK: LogConfiguration() -- Extra clang arguments
13+
# CHECK-COUNT-1: LogConfiguration() -- -triple
14+
# CHECK: (Int) ${{.*}} = 1
15+
16+
//--- main.swift
17+
func test() {
18+
print("break here")
19+
}
20+
test()
21+
22+
//--- lldb.script
23+
# Force loading from interface to simulate no binary module available.
24+
settings set symbols.swift-module-loading-mode prefer-interface
25+
log enable lldb types
26+
b test
27+
run
28+
# Create a SwiftASTContext
29+
expr 1
30+
quit

lldb/unittests/Symbol/TestSwiftASTContext.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,15 +234,15 @@ const std::vector<std::string> uniqued_flags = {
234234
TEST_F(ClangArgs, UniquingCollisionWithExistingFlags) {
235235
const std::vector<std::string> source = duplicated_flags;
236236
std::vector<std::string> dest = uniqued_flags;
237-
SwiftASTContext::AddExtraClangArgs(source, dest, false);
237+
SwiftASTContext::AddExtraClangArgs(source, dest);
238238

239239
EXPECT_EQ(dest, uniqued_flags);
240240
}
241241

242242
TEST_F(ClangArgs, UniquingCollisionWithAddedFlags) {
243243
const std::vector<std::string> source = duplicated_flags;
244244
std::vector<std::string> dest;
245-
SwiftASTContext::AddExtraClangArgs(source, dest, false);
245+
SwiftASTContext::AddExtraClangArgs(source, dest);
246246

247247
EXPECT_EQ(dest, uniqued_flags);
248248
}
@@ -251,7 +251,7 @@ TEST_F(ClangArgs, DoubleDash) {
251251
// -v with all currently ignored arguments following.
252252
const std::vector<std::string> source{"-v", "--", "-Werror", ""};
253253
std::vector<std::string> dest;
254-
SwiftASTContext::AddExtraClangArgs(source, dest, false);
254+
SwiftASTContext::AddExtraClangArgs(source, dest);
255255

256256
// Check that all ignored arguments got removed.
257257
EXPECT_EQ(dest, std::vector<std::string>({"-v"}));

0 commit comments

Comments
 (0)