Skip to content

Commit d3a25d9

Browse files
committed
Restore the per-module scratch context fallback mechanism.
This feature has been accidentally disabled when introducing TypeSystemSwiftTypeRefForExpressions and thanks to how good TypeSystemSwiftTypeRef has become, all of the tests for the feature were still passing.
1 parent 44f63b8 commit d3a25d9

File tree

14 files changed

+189
-64
lines changed

14 files changed

+189
-64
lines changed

lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,15 +1206,12 @@ struct SwiftASTContextError : public llvm::ErrorInfo<SwiftASTContextError> {
12061206
struct ModuleImportError : public llvm::ErrorInfo<ModuleImportError> {
12071207
static char ID;
12081208
std::string msg;
1209-
bool is_explicit;
1209+
bool is_new_dylib;
12101210

1211-
ModuleImportError(llvm::Twine message, bool is_explicit = false)
1212-
: msg(message.str()), is_explicit(is_explicit) {}
1211+
ModuleImportError(llvm::Twine message, bool is_new_dylib = false)
1212+
: msg(message.str()), is_new_dylib(is_new_dylib) {}
12131213
void log(llvm::raw_ostream &OS) const override {
1214-
if (is_explicit)
1215-
OS << "error while processing import statement:";
1216-
else
1217-
OS << "error while importing implicit dependency:";
1214+
OS << "error while processing module import: ";
12181215
OS << msg;
12191216
}
12201217
std::error_code convertToErrorCode() const override {
@@ -1406,7 +1403,9 @@ static llvm::Expected<ParsedExpression> ParseAndImport(
14061403
swift::performImportResolution(*source_file);
14071404

14081405
if (swift_ast_context.HasErrors())
1409-
return make_error<SwiftASTContextError>();
1406+
return make_error<ModuleImportError>(
1407+
swift_ast_context.GetAllErrors().AsCString(
1408+
"Explicit module import error"));
14101409

14111410
std::unique_ptr<SwiftASTManipulator> code_manipulator;
14121411
if (repl || !playground) {
@@ -1471,9 +1470,14 @@ static llvm::Expected<ParsedExpression> ParseAndImport(
14711470
process_sp, *source_file,
14721471
auto_import_error)) {
14731472
const char *msg = auto_import_error.AsCString();
1474-
if (!msg)
1475-
msg = "error status positive, but import still failed";
1476-
return make_error<ModuleImportError>(msg, /*explicit=*/true);
1473+
if (!msg) {
1474+
// The import itself succeeded, but the AST context is in a
1475+
// fatal error state. One way this can happen is if the import
1476+
// triggered a dylib import, in which case the context is
1477+
// purposefully poisoned.
1478+
msg = "import may have triggered a dylib import";
1479+
}
1480+
return make_error<ModuleImportError>(msg, /*is_new_dylib=*/true);
14771481
}
14781482
}
14791483

@@ -1523,43 +1527,43 @@ unsigned SwiftExpressionParser::Parse(DiagnosticManager &diagnostic_manager,
15231527
*this, m_stack_frame_wp, m_sc, *m_exe_scope, m_options, repl, playground);
15241528

15251529
if (!parsed_expr) {
1526-
bool user_import = false;
15271530
bool retry = false;
1528-
handleAllErrors(parsed_expr.takeError(),
1529-
[&](const ModuleImportError &MIE) {
1530-
if (MIE.is_explicit) {
1531-
// A new dylib may have poisoned the context.
1532-
retry = true;
1533-
user_import = true;
1534-
}
1535-
if (m_swift_ast_ctx.GetClangImporter())
1536-
// Already on backup power.
1537-
diagnostic_manager.PutString(eDiagnosticSeverityError,
1538-
MIE.message());
1539-
else
1540-
// Discard the shared scratch context and retry.
1541-
retry = true;
1542-
},
1543-
[&](const SwiftASTContextError &SACE) {
1544-
DiagnoseSwiftASTContextError();
1545-
},
1546-
[&](const StringError &SE) {
1547-
diagnostic_manager.PutString(eDiagnosticSeverityError,
1548-
SE.getMessage());
1549-
},
1550-
[](const PropagatedError &P) {});
1551-
1552-
// Unrecoverable error?
1553-
if (!retry)
1554-
return 1;
1531+
handleAllErrors(
1532+
parsed_expr.takeError(),
1533+
[&](const ModuleImportError &MIE) {
1534+
diagnostic_manager.PutString(eDiagnosticSeverityError, MIE.message());
1535+
// There are no fallback contexts in REPL and playgrounds.
1536+
if (repl || playground || MIE.is_new_dylib) {
1537+
retry = true;
1538+
return;
1539+
}
1540+
if (!m_sc.target_sp->UseScratchTypesystemPerModule()) {
1541+
// This, together with the fatal error forces
1542+
// a per-module scratch to be instantiated on
1543+
// retry.
1544+
m_sc.target_sp->SetUseScratchTypesystemPerModule(true);
1545+
m_swift_ast_ctx.RaiseFatalError(MIE.message());
1546+
retry = true;
1547+
}
1548+
},
1549+
[&](const SwiftASTContextError &SACE) {
1550+
DiagnoseSwiftASTContextError();
1551+
},
1552+
[&](const StringError &SE) {
1553+
diagnostic_manager.PutString(eDiagnosticSeverityError,
1554+
SE.getMessage());
1555+
},
1556+
[](const PropagatedError &P) {});
15551557

15561558
// Signal that we want to retry the expression exactly once with a
15571559
// fresh SwiftASTContext initialized with the flags from the
15581560
// current lldb::Module / Swift dylib to avoid header search
15591561
// mismatches.
1560-
if (!user_import)
1561-
m_sc.target_sp->SetUseScratchTypesystemPerModule(true);
1562-
return 2;
1562+
if (retry)
1563+
return 2;
1564+
1565+
// Unrecoverable error.
1566+
return 1;
15631567
}
15641568

15651569
swift::bindExtensions(parsed_expr->module);

lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -302,10 +302,7 @@ bool SwiftUserExpression::Parse(DiagnosticManager &diagnostic_manager,
302302
return false;
303303
}
304304

305-
ExecutionContext target_scope(*target);
306-
m_swift_scratch_ctx = target->GetSwiftScratchContext(
307-
m_err, /* FIXME: should be exe_scope */ *target_scope
308-
.GetBestExecutionContextScope());
305+
m_swift_scratch_ctx = target->GetSwiftScratchContext(m_err, *exe_scope);
309306
if (!m_swift_scratch_ctx) {
310307
LLDB_LOG(log, "no scratch context", m_err.AsCString());
311308
return false;
@@ -314,7 +311,12 @@ bool SwiftUserExpression::Parse(DiagnosticManager &diagnostic_manager,
314311
m_swift_scratch_ctx->get()->GetSwiftASTContext());
315312

316313
if (!m_swift_ast_ctx) {
317-
LLDB_LOG(log, "no Swift AST Context");
314+
LLDB_LOG(log, "no Swift AST context");
315+
return false;
316+
}
317+
318+
if (m_swift_ast_ctx->HasFatalErrors()) {
319+
LLDB_LOG(log, "Swift AST context is in a fatal error state");
318320
return false;
319321
}
320322

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

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2154,18 +2154,23 @@ Status SwiftASTContext::IsCompatible() { return GetFatalErrors(); }
21542154

21552155
Status SwiftASTContext::GetFatalErrors() const {
21562156
Status error;
2157-
if (HasFatalErrors()) {
2158-
error = m_fatal_errors;
2159-
if (error.Success()) {
2160-
// Retrieve the error message from the DiagnosticConsumer.
2161-
DiagnosticManager diagnostic_manager;
2162-
PrintDiagnostics(diagnostic_manager);
2163-
error.SetErrorString(diagnostic_manager.GetString());
2164-
}
2157+
if (HasFatalErrors())
2158+
error = GetAllErrors();
2159+
return error;
2160+
}
2161+
2162+
Status SwiftASTContext::GetAllErrors() const {
2163+
Status error = m_fatal_errors;
2164+
if (error.Success()) {
2165+
// Retrieve the error message from the DiagnosticConsumer.
2166+
DiagnosticManager diagnostic_manager;
2167+
PrintDiagnostics(diagnostic_manager);
2168+
error.SetErrorString(diagnostic_manager.GetString());
21652169
}
21662170
return error;
21672171
}
21682172

2173+
21692174
void SwiftASTContext::LogFatalErrors() const {
21702175
// Avoid spamming the health log with redundant copies of the fatal error.
21712176
if (m_logged_fatal_error) {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,12 +437,13 @@ class SwiftASTContext : public TypeSystemSwift {
437437

438438
const SwiftModuleMap &GetModuleCache() { return m_swift_module_cache; }
439439

440+
void RaiseFatalError(std::string msg) { m_fatal_errors.SetErrorString(msg); }
440441
static bool HasFatalErrors(swift::ASTContext *ast_context);
441-
442442
bool HasFatalErrors() const {
443443
return m_fatal_errors.Fail() || HasFatalErrors(m_ast_context_ap.get());
444444
}
445445

446+
Status GetAllErrors() const;
446447
Status GetFatalErrors() const;
447448
void DiagnoseWarnings(Process &process, Module &module) const override;
448449
void LogFatalErrors() const;

lldb/source/Target/Target.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,8 +2352,9 @@ Target::GetScratchTypeSystemForLanguage(lldb::LanguageType language,
23522352
}
23532353

23542354
if (m_cant_make_scratch_type_system.count(language))
2355-
return llvm::make_error<llvm::StringError>("unable to construct scratch type system",
2356-
llvm::inconvertibleErrorCode());
2355+
return llvm::make_error<llvm::StringError>(
2356+
"unable to construct scratch type system",
2357+
llvm::inconvertibleErrorCode());
23572358

23582359
auto type_system_or_err = m_scratch_type_system_map.GetTypeSystemForLanguage(
23592360
language, this, create_on_demand, compiler_options);
@@ -2587,7 +2588,7 @@ Target::CreateUtilityFunction(std::string expression, std::string name,
25872588
#ifdef LLDB_ENABLE_SWIFT
25882589
llvm::Optional<SwiftScratchContextReader> Target::GetSwiftScratchContext(
25892590
Status &error, ExecutionContextScope &exe_scope, bool create_on_demand) {
2590-
Log *log = GetLog(LLDBLog::Target);
2591+
Log *log = GetLog(LLDBLog::Target | LLDBLog::Types | LLDBLog::Expressions);
25912592
LLDB_SCOPED_TIMER();
25922593

25932594
Module *lldb_module = nullptr;
@@ -2624,20 +2625,29 @@ llvm::Optional<SwiftScratchContextReader> Target::GetSwiftScratchContext(
26242625
return cached_ts;
26252626
}
26262627

2627-
if (!create_on_demand || !GetSwiftScratchContextLock().try_lock())
2628+
if (!create_on_demand) {
2629+
if (log)
2630+
log->Printf("not allowed to create a new context\n");
26282631
return nullptr;
2632+
}
2633+
if (!GetSwiftScratchContextLock().try_lock()) {
2634+
if (log)
2635+
log->Printf("couldn't acquire scratch context lock\n");
2636+
return nullptr;
2637+
}
26292638

26302639
auto unlock = llvm::make_scope_exit(
26312640
[this] { GetSwiftScratchContextLock().unlock(); });
26322641

2633-
auto type_system_or_err = GetScratchTypeSystemForLanguage(eLanguageTypeSwift, false);
2642+
auto type_system_or_err =
2643+
GetScratchTypeSystemForLanguage(eLanguageTypeSwift, false);
26342644
if (!type_system_or_err) {
26352645
llvm::consumeError(type_system_or_err.takeError());
26362646
return nullptr;
26372647
}
26382648

26392649
if (auto *global_scratch_ctx =
2640-
llvm::cast_or_null<SwiftASTContextForExpressions>(
2650+
llvm::cast_or_null<TypeSystemSwiftTypeRefForExpressions>(
26412651
&*type_system_or_err))
26422652
if (auto *swift_ast_ctx =
26432653
llvm::dyn_cast_or_null<SwiftASTContextForExpressions>(
@@ -2676,7 +2686,8 @@ llvm::Optional<SwiftScratchContextReader> Target::GetSwiftScratchContext(
26762686

26772687
if (!swift_scratch_ctx)
26782688
return llvm::None;
2679-
return SwiftScratchContextReader(GetSwiftScratchContextLock(), *swift_scratch_ctx);
2689+
return SwiftScratchContextReader(GetSwiftScratchContextLock(),
2690+
*swift_scratch_ctx);
26802691
}
26812692

26822693
static SharedMutex *
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
MACRO Bar {
2+
int i;
3+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module Bar {
2+
header "Bar.h"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
struct Foo {
2+
MACRO j;
3+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module Foo {
2+
header "Foo.h"
3+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@_implementationOnly import Foo
2+
3+
func use<T>(_ t: T) {}
4+
5+
public func f() {
6+
let foo = Foo(j: 23)
7+
use(foo) // break here
8+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
SWIFT_SOURCES = main.swift
2+
SWIFT_OBJC_INTEROP := 1
3+
4+
all: Framework.framework a.out
5+
6+
include Makefile.rules
7+
BAR_FLAGS= -Xcc -I$(SRCDIR)/Bar -Xcc -DMACRO=struct
8+
FOO_FLAGS= -Xcc -I$(SRCDIR)/Foo -Xcc -DMACRO=int
9+
SWIFTFLAGS_EXTRAS=$(BAR_FLAGS) \
10+
-F$(BUILDDIR) -framework Framework -L$(BUILDDIR) \
11+
-Xlinker -rpath -Xlinker $(BUILDDIR)
12+
13+
Framework.framework: Framework.swift
14+
$(MAKE) -f $(MAKEFILE_RULES) -C $(BUILDDIR) VPATH=$(VPATH) \
15+
MAKE_DSYM=NO CC=$(CC) SWIFTC=$(SWIFTC) \
16+
ARCH=$(ARCH) DSYMUTIL=$(DSYMUTIL) \
17+
DYLIB_NAME=$(shell basename $< .swift) \
18+
DYLIB_ONLY=YES DYLIB_SWIFT_SOURCES=Framework.swift \
19+
SWIFT_OBJC_INTEROP=1 \
20+
SWIFTFLAGS_EXTRAS="$(FOO_FLAGS)" \
21+
FRAMEWORK=Framework
22+
rm -f $(BUILDDIR)/Framework.swiftmodule
23+
ln -s $(BUILDDIR)/Framework.framework/Framework $(BUILDDIR)/Framework # FIXME
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import lldb
2+
from lldbsuite.test.lldbtest import *
3+
from lldbsuite.test.decorators import *
4+
import lldbsuite.test.lldbutil as lldbutil
5+
import os
6+
import unittest2
7+
import shutil
8+
9+
class TestSwiftHardMacroConflict(TestBase):
10+
11+
def setUp(self):
12+
TestBase.setUp(self)
13+
14+
NO_DEBUG_INFO_TESTCASE = True
15+
16+
# Don't run ClangImporter tests if Clangimporter is disabled.
17+
@skipIf(setting=('symbols.use-swift-clangimporter', 'false'))
18+
@skipUnlessDarwin
19+
@swiftTest
20+
def test(self):
21+
self.runCmd("settings set symbols.use-swift-dwarfimporter false")
22+
self.build()
23+
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
24+
self, 'break here', lldb.SBFileSpec('main.swift'),
25+
extra_images=['Framework.framework'])
26+
b_breakpoint = target.BreakpointCreateBySourceRegex(
27+
'break here', lldb.SBFileSpec('Framework.swift'))
28+
log = self.getBuildArtifact("types.log")
29+
self.runCmd('log enable lldb types -f "%s"' % log)
30+
31+
# This is expected to succeed because ClangImporter was set up
32+
# with the flags from the main executable.
33+
self.expect("expr bar", "expected result", substrs=["42"])
34+
35+
process.Continue()
36+
threads = lldbutil.get_threads_stopped_at_breakpoint(
37+
process, b_breakpoint)
38+
self.expect("p foo", error=True)
39+
40+
per_module_fallback = 0
41+
import io
42+
with open(log, "r", encoding='utf-8') as logfile:
43+
for line in logfile:
44+
if 'SwiftASTContextForExpressions("Framework")' in line:
45+
per_module_fallback += 1
46+
self.assertGreater(per_module_fallback, 0,
47+
"failed to create per-module scratch context")
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Bar
2+
import Framework
3+
4+
func use<T>(_ t: T) {}
5+
6+
func main() {
7+
let bar = Bar(i: 42)
8+
f() // break here
9+
use(bar)
10+
}
11+
12+
main()

lldb/test/API/lang/swift/lazy_framework/TestSwiftLazyFramework.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def test_system_framework(self):
2020
self.expect("settings set target.swift-auto-import-frameworks true")
2121
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
2222
self, 'break here', lldb.SBFileSpec('main.swift'))
23-
23+
2424
# Verify that lazy is not linked in.
2525
self.runCmd("image list")
2626
output = self.res.GetOutput()

0 commit comments

Comments
 (0)