Skip to content

Commit c205842

Browse files
Merge pull request #5308 from adrian-prantl/restore-fallback
Restore the per-module scratch context fallback mechanism.
2 parents 91744b3 + d3a25d9 commit c205842

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)