-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[lldb] Change the implementation of Status to store an llvm::Error (NFC) #106774
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-lldb Author: Adrian Prantl (adrian-prantl) Changes(based on a conversation I had with @labath yesterday in #106442) Most APIs that currently vend a Status would be better served by returning llvm::Expected<> instead. If possibles APIs should be refactored to avoid Status. The only legitimate long-term uses of Status are objects that need to store an error for a long time (which should be questioned as a design decision, too). This patch makes the transition to llvm::Error easier by making the places that cannot switch to llvm::Error explicit: They are marked with a call to Status::clone(). Every other API can and should be refactored to use llvm::Expected. In the end Status should only be used in very few places. Whenever an unchecked Error is dropped by Status it logs this to the verbose API channel. Implementation notes: This patch introduces two new kinds of error_category as well as new llvm::Error types. Here is the mapping of lldb::ErrorType to llvm::Errors:
Patch is 96.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/106774.diff 81 Files Affected:
diff --git a/lldb/bindings/python/python-swigsafecast.swig b/lldb/bindings/python/python-swigsafecast.swig
index 34f8c6f0ff8d35..c46c247da87278 100644
--- a/lldb/bindings/python/python-swigsafecast.swig
+++ b/lldb/bindings/python/python-swigsafecast.swig
@@ -34,7 +34,7 @@ PythonObject SWIGBridge::ToSWIGWrapper(lldb::BreakpointSP breakpoint_sp) {
}
PythonObject SWIGBridge::ToSWIGWrapper(const Status& status) {
- return ToSWIGHelper(new lldb::SBError(status), SWIGTYPE_p_lldb__SBError);
+ return ToSWIGHelper(new lldb::SBError(status.clone()), SWIGTYPE_p_lldb__SBError);
}
PythonObject SWIGBridge::ToSWIGWrapper(std::unique_ptr<lldb::SBStructuredData> data_sb) {
diff --git a/lldb/include/lldb/API/SBError.h b/lldb/include/lldb/API/SBError.h
index 17f2c6c3027af7..9f55f92131c06e 100644
--- a/lldb/include/lldb/API/SBError.h
+++ b/lldb/include/lldb/API/SBError.h
@@ -97,7 +97,7 @@ class LLDB_API SBError {
friend class lldb_private::ScriptInterpreter;
friend class lldb_private::python::SWIGBridge;
- SBError(const lldb_private::Status &error);
+ SBError(lldb_private::Status &&error);
lldb_private::Status *get();
@@ -107,7 +107,7 @@ class LLDB_API SBError {
lldb_private::Status &ref();
- void SetError(const lldb_private::Status &lldb_error);
+ void SetError(lldb_private::Status &&lldb_error);
private:
std::unique_ptr<lldb_private::Status> m_opaque_up;
diff --git a/lldb/include/lldb/API/SBValueList.h b/lldb/include/lldb/API/SBValueList.h
index a5017bccc50533..52a86f989e153a 100644
--- a/lldb/include/lldb/API/SBValueList.h
+++ b/lldb/include/lldb/API/SBValueList.h
@@ -96,7 +96,7 @@ class LLDB_API SBValueList {
std::unique_ptr<ValueListImpl> m_opaque_up;
- void SetError(const lldb_private::Status &status);
+ void SetError(lldb_private::Status &&status);
};
} // namespace lldb
diff --git a/lldb/include/lldb/Core/ValueObjectConstResult.h b/lldb/include/lldb/Core/ValueObjectConstResult.h
index d3b3362bd0e9ec..9c34617af71d0d 100644
--- a/lldb/include/lldb/Core/ValueObjectConstResult.h
+++ b/lldb/include/lldb/Core/ValueObjectConstResult.h
@@ -61,7 +61,7 @@ class ValueObjectConstResult : public ValueObject {
// When an expression fails to evaluate, we return an error
static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope,
- const Status &error);
+ Status &&error);
std::optional<uint64_t> GetByteSize() override;
@@ -146,7 +146,7 @@ class ValueObjectConstResult : public ValueObject {
ConstString name, Module *module = nullptr);
ValueObjectConstResult(ExecutionContextScope *exe_scope,
- ValueObjectManager &manager, const Status &error);
+ ValueObjectManager &manager, Status &&error);
ValueObject *CreateChildAtIndex(size_t idx) override {
return m_impl.CreateChildAtIndex(idx);
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index a7de991104434d..c66cfb2c245efd 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1296,8 +1296,6 @@ class Process : public std::enable_shared_from_this<Process>,
const EvaluateExpressionOptions &options,
DiagnosticManager &diagnostic_manager);
- static const char *ExecutionResultAsCString(lldb::ExpressionResults result);
-
void GetStatus(Stream &ostrm);
size_t GetThreadStatus(Stream &ostrm, bool only_threads_with_stop_reason,
diff --git a/lldb/include/lldb/Utility/Status.h b/lldb/include/lldb/Utility/Status.h
index b304291ffae00e..bd60fcf2885e07 100644
--- a/lldb/include/lldb/Utility/Status.h
+++ b/lldb/include/lldb/Utility/Status.h
@@ -26,6 +26,34 @@ class raw_ostream;
namespace lldb_private {
+class MachKernelError
+ : public llvm::ErrorInfo<MachKernelError, llvm::StringError> {
+public:
+ using llvm::ErrorInfo<MachKernelError, llvm::StringError>::ErrorInfo;
+ MachKernelError(std::error_code ec, const llvm::Twine &msg = {})
+ : ErrorInfo(msg, ec) {}
+ static char ID;
+};
+
+class Win32Error : public llvm::ErrorInfo<Win32Error, llvm::StringError> {
+public:
+ using llvm::ErrorInfo<Win32Error, llvm::StringError>::ErrorInfo;
+ Win32Error(std::error_code ec, const llvm::Twine &msg = {})
+ : ErrorInfo(msg, ec) {}
+ static char ID;
+};
+
+class ExpressionError
+ : public llvm::ErrorInfo<ExpressionError, llvm::StringError> {
+public:
+ using llvm::ErrorInfo<ExpressionError, llvm::StringError>::ErrorInfo;
+ ExpressionError(std::error_code ec, std::string msg = {})
+ : ErrorInfo(msg, ec) {}
+ static char ID;
+};
+
+const char *ExecutionResultAsCString(lldb::ExpressionResults result);
+
/// \class Status Status.h "lldb/Utility/Status.h" An error handling class.
///
/// This class is designed to be able to hold any error code that can be
@@ -41,13 +69,32 @@ namespace lldb_private {
/// of themselves for printing results and error codes. The string value will
/// be fetched on demand and its string value will be cached until the error
/// is cleared of the value of the error changes.
+///
+/// API design notes:
+///
+/// Most APIs that currently vend a Status would be better served by
+/// returning llvm::Expected<> instead. If possibles APIs should be
+/// refactored to avoid Status. The only legitimate long-term uses of
+/// Status are objects that need to store an error for a long time
+/// (which should be questioned as a design decision, too).
+///
+/// Implementation notes:
+///
+/// Internally, Status stores an llvm::Error.
+/// eErrorTypeInvalid
+/// eErrorTypeGeneric llvm::StringError
+/// eErrorTypePOSIX llvm::ECError
+/// eErrorTypeMachKernel MachKernelError
+/// eErrorTypeExpression llvm::ErrorList<ExpressionError>
+/// eErrorTypeWin32 Win32Error
+
class Status {
public:
- /// Every error value that this object can contain needs to be able to fit
/// into ValueType.
typedef uint32_t ValueType;
Status();
+ Status(Status &&other) = default;
/// Initialize the error object with a generic success value.
///
@@ -79,9 +126,7 @@ class Status {
}
static Status FromExpressionError(lldb::ExpressionResults result,
- std::string msg) {
- return Status(result, lldb::eErrorTypeExpression, msg);
- }
+ std::string msg);
/// Set the current error to errno.
///
@@ -91,10 +136,14 @@ class Status {
~Status();
- // llvm::Error support
- explicit Status(llvm::Error error) { *this = std::move(error); }
+ /// Try not to use this in new code. Migrate APIs to llvm::Expected instead.
+ static Status FromError(llvm::Error &&error);
const Status &operator=(llvm::Error error);
+ Status &operator=(Status &&);
+ /// FIXME: Replace this with a takeError() method.
llvm::Error ToError() const;
+ /// Don't call this function in new code. Redesign the API instead.
+ Status clone() const { return Status(ToError()); }
/// Get the error string associated with the current error.
//
@@ -145,10 +194,12 @@ class Status {
bool Success() const;
protected:
- /// Status code as an integer value.
- ValueType m_code = 0;
- /// The type of the above error code.
- lldb::ErrorType m_type = lldb::eErrorTypeInvalid;
+ Status(llvm::Error &&error) : m_error(std::move(error)) {}
+ mutable llvm::Error m_error;
+ // /// Status code as an integer value.
+ // ValueType m_code = 0;
+ // /// The type of the above error code.
+ // lldb::ErrorType m_type = lldb::eErrorTypeInvalid;
/// A string representation of the error code.
mutable std::string m_string;
};
diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp
index 3e9c01080588e5..b2ed034d19983c 100644
--- a/lldb/source/API/SBBreakpoint.cpp
+++ b/lldb/source/API/SBBreakpoint.cpp
@@ -622,7 +622,7 @@ SBError SBBreakpoint::SetScriptCallbackFunction(
callback_function_name,
extra_args.m_impl_up
->GetObjectSP());
- sb_error.SetError(error);
+ sb_error.SetError(std::move(error));
} else
sb_error = Status::FromErrorString("invalid breakpoint");
@@ -645,7 +645,7 @@ SBError SBBreakpoint::SetScriptCallbackBody(const char *callback_body_text) {
.GetScriptInterpreter()
->SetBreakpointCommandCallback(bp_options, callback_body_text,
/*is_callback=*/false);
- sb_error.SetError(error);
+ sb_error.SetError(std::move(error));
} else
sb_error = Status::FromErrorString("invalid breakpoint");
@@ -670,7 +670,7 @@ SBError SBBreakpoint::AddNameWithErrorHandling(const char *new_name) {
bkpt_sp->GetTarget().GetAPIMutex());
Status error;
bkpt_sp->GetTarget().AddNameToBreakpoint(bkpt_sp, new_name, error);
- status.SetError(error);
+ status.SetError(std::move(error));
} else {
status = Status::FromErrorString("invalid breakpoint");
}
diff --git a/lldb/source/API/SBBreakpointLocation.cpp b/lldb/source/API/SBBreakpointLocation.cpp
index e5c96b81e80904..b2d1da3927c6ea 100644
--- a/lldb/source/API/SBBreakpointLocation.cpp
+++ b/lldb/source/API/SBBreakpointLocation.cpp
@@ -239,7 +239,7 @@ SBError SBBreakpointLocation::SetScriptCallbackFunction(
callback_function_name,
extra_args.m_impl_up
->GetObjectSP());
- sb_error.SetError(error);
+ sb_error.SetError(std::move(error));
} else
sb_error = Status::FromErrorString("invalid breakpoint");
@@ -264,7 +264,7 @@ SBBreakpointLocation::SetScriptCallbackBody(const char *callback_body_text) {
.GetScriptInterpreter()
->SetBreakpointCommandCallback(bp_options, callback_body_text,
/*is_callback=*/false);
- sb_error.SetError(error);
+ sb_error.SetError(std::move(error));
} else
sb_error = Status::FromErrorString("invalid breakpoint");
diff --git a/lldb/source/API/SBBreakpointName.cpp b/lldb/source/API/SBBreakpointName.cpp
index 7dc8dee19f43d2..831260d44e8e7f 100644
--- a/lldb/source/API/SBBreakpointName.cpp
+++ b/lldb/source/API/SBBreakpointName.cpp
@@ -570,14 +570,13 @@ SBError SBBreakpointName::SetScriptCallbackFunction(
m_impl_up->GetTarget()->GetAPIMutex());
BreakpointOptions &bp_options = bp_name->GetOptions();
- Status error;
- error = m_impl_up->GetTarget()
- ->GetDebugger()
- .GetScriptInterpreter()
- ->SetBreakpointCommandCallbackFunction(
- bp_options, callback_function_name,
- extra_args.m_impl_up->GetObjectSP());
- sb_error.SetError(error);
+ Status error = m_impl_up->GetTarget()
+ ->GetDebugger()
+ .GetScriptInterpreter()
+ ->SetBreakpointCommandCallbackFunction(
+ bp_options, callback_function_name,
+ extra_args.m_impl_up->GetObjectSP());
+ sb_error.SetError(std::move(error));
UpdateName(*bp_name);
return sb_error;
}
@@ -600,7 +599,7 @@ SBBreakpointName::SetScriptCallbackBody(const char *callback_body_text) {
.GetScriptInterpreter()
->SetBreakpointCommandCallback(
bp_options, callback_body_text, /*is_callback=*/false);
- sb_error.SetError(error);
+ sb_error.SetError(std::move(error));
if (!sb_error.Fail())
UpdateName(*bp_name);
diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp
index 72501570320d57..b21d7e67290073 100644
--- a/lldb/source/API/SBDebugger.cpp
+++ b/lldb/source/API/SBDebugger.cpp
@@ -220,7 +220,7 @@ lldb::SBError SBDebugger::InitializeWithErrorHandling() {
SBError error;
if (auto e = g_debugger_lifetime->Initialize(
std::make_unique<SystemInitializerFull>(), LoadPlugin)) {
- error.SetError(Status(std::move(e)));
+ error.SetError(Status::FromError(std::move(e)));
}
return error;
}
@@ -1360,7 +1360,7 @@ SBError SBDebugger::SetInternalVariable(const char *var_name, const char *value,
"invalid debugger instance name '%s'", debugger_instance_name);
}
if (error.Fail())
- sb_error.SetError(error);
+ sb_error.SetError(std::move(error));
return sb_error;
}
diff --git a/lldb/source/API/SBError.cpp b/lldb/source/API/SBError.cpp
index 30d9ccc78ee376..287fa6c499dd2f 100644
--- a/lldb/source/API/SBError.cpp
+++ b/lldb/source/API/SBError.cpp
@@ -23,7 +23,8 @@ SBError::SBError() { LLDB_INSTRUMENT_VA(this); }
SBError::SBError(const SBError &rhs) {
LLDB_INSTRUMENT_VA(this, rhs);
- m_opaque_up = clone(rhs.m_opaque_up);
+ if (rhs.m_opaque_up)
+ m_opaque_up = std::make_unique<Status>(rhs.m_opaque_up->clone());
}
SBError::SBError(const char *message) {
@@ -32,8 +33,8 @@ SBError::SBError(const char *message) {
SetErrorString(message);
}
-SBError::SBError(const lldb_private::Status &status)
- : m_opaque_up(new Status(status)) {
+SBError::SBError(lldb_private::Status &&status)
+ : m_opaque_up(new Status(std::move(status))) {
LLDB_INSTRUMENT_VA(this, status);
}
@@ -43,7 +44,9 @@ const SBError &SBError::operator=(const SBError &rhs) {
LLDB_INSTRUMENT_VA(this, rhs);
if (this != &rhs)
- m_opaque_up = clone(rhs.m_opaque_up);
+ if (rhs.m_opaque_up)
+ m_opaque_up = std::make_unique<Status>(rhs.m_opaque_up->clone());
+
return *this;
}
@@ -111,9 +114,9 @@ void SBError::SetError(uint32_t err, ErrorType type) {
*m_opaque_up = Status(err, type);
}
-void SBError::SetError(const Status &lldb_error) {
+void SBError::SetError(Status &&lldb_error) {
CreateIfNeeded();
- *m_opaque_up = lldb_error;
+ *m_opaque_up = std::move(lldb_error);
}
void SBError::SetErrorToErrno() {
diff --git a/lldb/source/API/SBFile.cpp b/lldb/source/API/SBFile.cpp
index 623708780f4c67..2ae4b1481afbf2 100644
--- a/lldb/source/API/SBFile.cpp
+++ b/lldb/source/API/SBFile.cpp
@@ -62,8 +62,7 @@ SBError SBFile::Read(uint8_t *buf, size_t num_bytes, size_t *bytes_read) {
error = Status::FromErrorString("invalid SBFile");
*bytes_read = 0;
} else {
- Status status = m_opaque_sp->Read(buf, num_bytes);
- error.SetError(status);
+ error.SetError(m_opaque_sp->Read(buf, num_bytes));
*bytes_read = num_bytes;
}
return error;
@@ -78,8 +77,7 @@ SBError SBFile::Write(const uint8_t *buf, size_t num_bytes,
error = Status::FromErrorString("invalid SBFile");
*bytes_written = 0;
} else {
- Status status = m_opaque_sp->Write(buf, num_bytes);
- error.SetError(status);
+ error.SetError(m_opaque_sp->Write(buf, num_bytes));
*bytes_written = num_bytes;
}
return error;
@@ -92,8 +90,7 @@ SBError SBFile::Flush() {
if (!m_opaque_sp) {
error = Status::FromErrorString("invalid SBFile");
} else {
- Status status = m_opaque_sp->Flush();
- error.SetError(status);
+ error.SetError(m_opaque_sp->Flush());
}
return error;
}
@@ -106,10 +103,8 @@ bool SBFile::IsValid() const {
SBError SBFile::Close() {
LLDB_INSTRUMENT_VA(this);
SBError error;
- if (m_opaque_sp) {
- Status status = m_opaque_sp->Close();
- error.SetError(status);
- }
+ if (m_opaque_sp)
+ error.SetError(m_opaque_sp->Close());
return error;
}
diff --git a/lldb/source/API/SBFormat.cpp b/lldb/source/API/SBFormat.cpp
index 51cddceea0372e..080e219d64a362 100644
--- a/lldb/source/API/SBFormat.cpp
+++ b/lldb/source/API/SBFormat.cpp
@@ -36,7 +36,7 @@ SBFormat::SBFormat(const char *format, lldb::SBError &error) {
FormatEntrySP format_entry_sp = std::make_shared<FormatEntity::Entry>();
Status status = FormatEntity::Parse(format, *format_entry_sp);
- error.SetError(status);
+ error.SetError(std::move(status));
if (error.Success())
m_opaque_sp = format_entry_sp;
}
diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp
index b1360e88bcd3af..30c44b974988d0 100644
--- a/lldb/source/API/SBFrame.cpp
+++ b/lldb/source/API/SBFrame.cpp
@@ -809,7 +809,7 @@ SBValueList SBFrame::GetVariables(const lldb::SBVariablesOptions &options) {
Status var_error;
variable_list = frame->GetVariableList(true, &var_error);
if (var_error.Fail())
- value_list.SetError(var_error);
+ value_list.SetError(std::move(var_error));
if (variable_list) {
const size_t num_variables = variable_list->GetSize();
if (num_variables) {
@@ -1033,7 +1033,8 @@ SBValue SBFrame::EvaluateExpression(const char *expr) {
Status error;
error = Status::FromErrorString("can't evaluate expressions when the "
"process is running.");
- ValueObjectSP error_val_sp = ValueObjectConstResult::Create(nullptr, error);
+ ValueObjectSP error_val_sp =
+ ValueObjectConstResult::Create(nullptr, std::move(error));
result.SetSP(error_val_sp, false);
}
return result;
@@ -1129,13 +1130,13 @@ lldb::SBValue SBFrame::EvaluateExpression(const char *expr,
Status error;
error = Status::FromErrorString("can't evaluate expressions when the "
"process is running.");
- expr_value_sp = ValueObjectConstResult::Create(nullptr, error);
+ expr_value_sp = ValueObjectConstResult::Create(nullptr, std::move(error));
expr_result.SetSP(expr_value_sp, false);
}
} else {
Status error;
error = Status::FromErrorString("sbframe object is not valid.");
- expr_value_sp = ValueObjectConstResult::Create(nullptr, error);
+ expr_value_sp = ValueObjectConstResult::Create(nullptr, std::move(error));
expr_result.SetSP(expr_value_sp, false);
}
diff --git a/lldb/source/API/SBPlatform.cpp b/lldb/source/API/SBPlatform.cpp
index 2f0f925302f16e..10ed653500d9f8 100644
--- a/lldb/source/API/SBPlatform.cpp
+++ b/lldb/source/API/SBPlatform.cpp
@@ -586,7 +586,7 @@ SBProcess SBPlatform::Attach(SBAttachInfo &attach_info,
Status status;
ProcessSP process_sp = platform_sp->Attach(info, debugger.ref(),
target.GetSP().get(), status);
- error.SetError(status);
+ error.SetError(std::move(status));
return SBProcess(process_sp);
}
@@ -728,7 +728,7 @@ SBError SBPlatform::SetLocateModuleCallback(
symbol_file_spec = symbol_file_spec_sb.ref();
}
- return error.ref();
+ return error.ref().clone();
});
return SBError();
}
diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp
index 3eed51f0245f6f..9773144723c34c 100644
--- a/lldb/source/API/SBProcess.cpp
+++ b/lldb/source/API/SBProcess.cpp
@@ -1450,7 +1450,7 @@ lldb::SBError SBProcess::DeallocateMemory(lldb::addr_t ptr) {
std::lock_guard<std::recursive_mutex> guard(
process_sp->GetTarget().GetAPIMutex());
Status error = process_sp->DeallocateMemory(ptr);
- sb_error.SetError(error);
+ sb_error.SetError(std::move(error));
} else {
sb_error = Status::FromErrorString("process is running");
}
diff --git a/lldb/source/API/SBSaveCoreOptions.cpp b/lldb/source/API/SBSaveCoreOptions.cpp
index 2cd431611ef558..ef82b0253f1199 100644
--- a/lldb/source/API/SBSaveCoreOptions.cpp
+++ b/lldb/source/API/SBSaveCoreOptions.cpp
@@ -40,8 +40,7 @@ SBSaveCoreOptions::operator=(const SBSaveCoreOptions &rhs) {
SBError SBSaveCoreOptions::SetPluginName(const char *name) {
LLDB_INSTRUMENT_VA(this, name);
- lldb_private::Status error = m_opaque_up->SetPluginName(name);
- return SBError(error);
+ return SBError(m_opaque_up->SetPluginName(name));
}
void SBSaveCoreOptions::SetStyle(lldb::SaveCoreStyle style) {
diff --git a/lldb/source/API/SBStructuredData.cpp b/lldb/source/API/SBStructuredData.cpp
index 801ebf45e0e524..b891a34bd7c76a 100644
--- a/lldb/source/API/SBStructuredData.cpp
+++ b/lldb/source/API/SBStructuredData.cpp
@@ -133,7 +133,7 @@ lldb::SBError SBStructuredData::GetDescription(lldb::SBStream &stream) const {
Status error = m_impl_up->GetDescription(stream.ref());
SBError sb_error;
- sb_error.SetError(error);
...
[truncated]
|
1151a01
to
089f8e8
Compare
9a72770
to
01e0a8e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great! LGTM with comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two high-level comments:
- I think that the
FromError
/clone
changes would be better of as a separate patch(es). I have no problem with the changes themselves, but I think it'd be better to separate the meat of this patch from the mechanical renaming. The renames could be done either before an after the patch, as (AFAICT) the functions are just fancy names for (copy) constructors. - I think this class should accept an open class hierarchy (like llvm::Error) does and not assume that it can enumerate all the error subclasses. I think the only additional property that we need of the error classes is the ability to clone themselves, which we could achieve by providing a
ClonableErrorInfo
class with an abstractclone
method. We can still keep the code which converts all unclonable errors into a string error (but I'd only do it after a copy, not immediately during construction). The thing I want to avoid is the proliferation of very specific error types inside the base Status class -- the mach/windows error types should arguably be defined in the host library, and even the ExpressionError type might be better off inside the command interpreter or something. I'm not saying you have to do the refactor now, but I'd like to have the option to do so in the future.
lldb/source/Utility/Status.cpp
Outdated
if (ec.category() == std::generic_category() || | ||
ec.category() == generic_category() || | ||
ec.category() == expression_category()) | ||
result = ec.value(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about just returning ec.value()
regardless of the category?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This special case only exists because it otherwise breaks the GDBRemoteCommunicationServer unit test. Probably not worth preserving, but I didn't want to unnecessarily change this behavior either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the SendErrorResponse_StringError test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would actually prefer changing the code over there if it meant simplifying this. Would #108170 do the trick?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I incorporate the change. There's still some amount of compatibility-wrapping needed, but it got better.
992600a
to
3ffcc5e
Compare
I can do that.
It really looks like the need for cloneable errors and long-term storage of errors is the key insight that came out of this patch. I'll think a bit about this as I'm splitting this patch up further. |
3ffcc5e
to
cb45a87
Compare
Wasn't half as bad. @labath This update introduces a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am worried about the thread safety aspects of this, in particular for these "long term storage" errors. I don't know if we have any users like this, but I think it wouldn't be unreasonable for someone to expect that they can access these errors from multiple threads (concurrently). I'm not sure if the current implementation is safe in this respect, but I suspect it isn't because of the fiddling with the "checked" flag that the Error class does. If it is a problem, one way around it might be to store the Error in a "deconstructed" form -- as a list of ErrorInfoBase objects...
lldb/source/Utility/Status.cpp
Outdated
class ExpressionCategory : public std::error_category { | ||
const char *name() const override { return "LLDBExpressionCategory"; } | ||
std::string message(int __ev) const override { | ||
return ExecutionResultAsCString(static_cast<lldb::ExpressionResults>(__ev)); | ||
}; | ||
}; | ||
ExpressionCategory &expression_category() { | ||
static ExpressionCategory g_expression_category; | ||
return g_expression_category; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need this? My understanding was that the std::error_code conversion is for compatibility, and so we may not need it if we can ensure that everyone gets the error string via info->message()
rather than info->convertToErrorCode().message()
.
Since we did have this class up to this point, I don't think we have any instances of the second pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the time being, we do. I'm not opposed to get rid of this later, either. Right now expressions return an ExpressionResult enum, which is encoded as this custom ExpressionCategory error code in this patch.
A failing expression returns an
ErrorList({
ECError(ExpressionCategory, ExpressionResult),
ExpressionError(diagnostic1),
ExpressionError(diagnostic2),
...
})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose that's fine, although I'm wondering if an error list is the best way to represent these. If I were doing this, I might have a single "ExpressionError" which contains the ExpressionResult
enum and a list of compiler diagnostics (errors).
lldb/source/Utility/Status.cpp
Outdated
/// Creates a deep copy of all known errors and converts all other | ||
/// errors to a new llvm::StringError. | ||
static llvm::Error CloneError(llvm::Error &error) { | ||
std::vector<std::unique_ptr<llvm::ErrorInfoBase>> info; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could avoid the temporary vector by using llvm::joinErrors directly from the callback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ping. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that we then would need to delay initializing an llvm::Error variable. I could not find any code that makes this look any less ugly than what we have now. (I toyed with an optionalllvm::Error).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about this:
Error result = ErrorSuccess();
auto clone = [](const ErrorInfoBase &e) {
if (e.isA<CloneableError>())
return Error(static_cast<const CloneableError &>(e)->Clone());
return make_error<StringError>(e.message(), e.convertToErrorCode(), true);
};
visitErrors(r, [&](const ErrorInfoBase &e) {
result = joinErrors(std::move(result), clone(e));
});
return result;
lldb/source/Utility/Status.cpp
Outdated
if (ec.category() == std::generic_category() || | ||
ec.category() == generic_category() || | ||
ec.category() == expression_category()) | ||
result = ec.value(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
I think that's fine. We can do something about that, and at least it enables us to avoid adding new error types to this file. |
Also, some (unit) tests would be nice. |
6e4559f
to
12bf3fb
Compare
So I thought I had understood this because I had simulated the missing ip6 support on the bots inside of Socked::CreateSocket, but I still had failing unit tests at the end of the day so I reverted this again for now. |
…FC) (#106774) (based on a conversation I had with @labath yesterday in #106442) Most APIs that currently vend a Status would be better served by returning llvm::Expected<> instead. If possibles APIs should be refactored to avoid Status. The only legitimate long-term uses of Status are objects that need to store an error for a long time (which should be questioned as a design decision, too). This patch makes the transition to llvm::Error easier by making the places that cannot switch to llvm::Error explicit: They are marked with a call to Status::clone(). Every other API can and should be refactored to use llvm::Expected. In the end Status should only be used in very few places. Whenever an unchecked Error is dropped by Status it logs this to the verbose API channel. Implementation notes: This patch introduces two new kinds of error_category as well as new llvm::Error types. Here is the mapping of lldb::ErrorType to llvm::Errors: ``` (eErrorTypeInvalid) eErrorTypeGeneric llvm::StringError eErrorTypePOSIX llvm::ECError eErrorTypeMachKernel MachKernelError eErrorTypeExpression llvm::ErrorList<ExpressionError> eErrorTypeWin32 Win32Error ``` Relanding with built-in cloning support for llvm::ECError.
…FC) (llvm#106774) (based on a conversation I had with @labath yesterday in llvm#106442) Most APIs that currently vend a Status would be better served by returning llvm::Expected<> instead. If possibles APIs should be refactored to avoid Status. The only legitimate long-term uses of Status are objects that need to store an error for a long time (which should be questioned as a design decision, too). This patch makes the transition to llvm::Error easier by making the places that cannot switch to llvm::Error explicit: They are marked with a call to Status::clone(). Every other API can and should be refactored to use llvm::Expected. In the end Status should only be used in very few places. Whenever an unchecked Error is dropped by Status it logs this to the verbose API channel. Implementation notes: This patch introduces two new kinds of error_category as well as new llvm::Error types. Here is the mapping of lldb::ErrorType to llvm::Errors: ``` (eErrorTypeInvalid) eErrorTypeGeneric llvm::StringError eErrorTypePOSIX llvm::ECError eErrorTypeMachKernel MachKernelError eErrorTypeExpression llvm::ErrorList<ExpressionError> eErrorTypeWin32 Win32Error ```
…Error (NFC) (llvm#106774)" This reverts commit 06939fa.
…FC) (llvm#106774) (based on a conversation I had with @labath yesterday in llvm#106442) Most APIs that currently vend a Status would be better served by returning llvm::Expected<> instead. If possibles APIs should be refactored to avoid Status. The only legitimate long-term uses of Status are objects that need to store an error for a long time (which should be questioned as a design decision, too). This patch makes the transition to llvm::Error easier by making the places that cannot switch to llvm::Error explicit: They are marked with a call to Status::clone(). Every other API can and should be refactored to use llvm::Expected. In the end Status should only be used in very few places. Whenever an unchecked Error is dropped by Status it logs this to the verbose API channel. Implementation notes: This patch introduces two new kinds of error_category as well as new llvm::Error types. Here is the mapping of lldb::ErrorType to llvm::Errors: ``` (eErrorTypeInvalid) eErrorTypeGeneric llvm::StringError eErrorTypePOSIX llvm::ECError eErrorTypeMachKernel MachKernelError eErrorTypeExpression llvm::ErrorList<ExpressionError> eErrorTypeWin32 Win32Error ``` Relanding with built-in cloning support for llvm::ECError.
This is failing on Windows because we use an error code that means there was no error in one of the tests in
This now marks the status as a failure. https://lab.llvm.org/buildbot/#/builders/141/builds/2544 I would be tempted to remove the test but given that this is a Windows defined value, all sorts of APIs might return it and we don't want to be marking lots of things as failures when they aren't. |
…Error (NFC) (#106774)" This reverts commit 104b249 because it has caused 2 test failures on Windows: https://lab.llvm.org/buildbot/#/builders/141/builds/2544 Failed Tests (2): lldb-api :: functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py lldb-unit :: Utility/./UtilityTests.exe/StatusTest/ErrorWin32 I reckon the cause is the same, that we construct an error with the Win32 NO_ERROR value which means there was no error but we're assuming anything with an error code is a failure.
I've reverted this 1553714. I feel like the solution isn't that complicated but it's close to end of the work day for me and I'd like to see the bot green again. If you have a suggestion on how to handle this I can try it on Windows on Monday. |
Output from the 2 failures:
|
…FC) (#106774) (based on a conversation I had with @labath yesterday in #106442) Most APIs that currently vend a Status would be better served by returning llvm::Expected<> instead. If possibles APIs should be refactored to avoid Status. The only legitimate long-term uses of Status are objects that need to store an error for a long time (which should be questioned as a design decision, too). This patch makes the transition to llvm::Error easier by making the places that cannot switch to llvm::Error explicit: They are marked with a call to Status::clone(). Every other API can and should be refactored to use llvm::Expected. In the end Status should only be used in very few places. Whenever an unchecked Error is dropped by Status it logs this to the verbose API channel. Implementation notes: This patch introduces two new kinds of error_category as well as new llvm::Error types. Here is the mapping of lldb::ErrorType to llvm::Errors: ``` (eErrorTypeInvalid) eErrorTypeGeneric llvm::StringError eErrorTypePOSIX llvm::ECError eErrorTypeMachKernel MachKernelError eErrorTypeExpression llvm::ErrorList<ExpressionError> eErrorTypeWin32 Win32Error ``` Relanding with built-in cloning support for llvm::ECError, and support for initializing a Windows error with a NO_ERROR error code.
…FC) (#106774) (based on a conversation I had with @labath yesterday in #106442) Most APIs that currently vend a Status would be better served by returning llvm::Expected<> instead. If possibles APIs should be refactored to avoid Status. The only legitimate long-term uses of Status are objects that need to store an error for a long time (which should be questioned as a design decision, too). This patch makes the transition to llvm::Error easier by making the places that cannot switch to llvm::Error explicit: They are marked with a call to Status::clone(). Every other API can and should be refactored to use llvm::Expected. In the end Status should only be used in very few places. Whenever an unchecked Error is dropped by Status it logs this to the verbose API channel. Implementation notes: This patch introduces two new kinds of error_category as well as new llvm::Error types. Here is the mapping of lldb::ErrorType to llvm::Errors: ``` (eErrorTypeInvalid) eErrorTypeGeneric llvm::StringError eErrorTypePOSIX llvm::ECError eErrorTypeMachKernel MachKernelError eErrorTypeExpression llvm::ErrorList<ExpressionError> eErrorTypeWin32 Win32Error ``` Relanding with built-in cloning support for llvm::ECError, and support for initializing a Windows error with a NO_ERROR error code.
…FC) (#106774) (based on a conversation I had with @labath yesterday in #106442) Most APIs that currently vend a Status would be better served by returning llvm::Expected<> instead. If possibles APIs should be refactored to avoid Status. The only legitimate long-term uses of Status are objects that need to store an error for a long time (which should be questioned as a design decision, too). This patch makes the transition to llvm::Error easier by making the places that cannot switch to llvm::Error explicit: They are marked with a call to Status::clone(). Every other API can and should be refactored to use llvm::Expected. In the end Status should only be used in very few places. Whenever an unchecked Error is dropped by Status it logs this to the verbose API channel. Implementation notes: This patch introduces two new kinds of error_category as well as new llvm::Error types. Here is the mapping of lldb::ErrorType to llvm::Errors: ``` (eErrorTypeInvalid) eErrorTypeGeneric llvm::StringError eErrorTypePOSIX llvm::ECError eErrorTypeMachKernel MachKernelError eErrorTypeExpression llvm::ErrorList<ExpressionError> eErrorTypeWin32 Win32Error ``` Relanding with built-in cloning support for llvm::ECError, and support for initializing a Windows error with a NO_ERROR error code, and modifying TestGDBRemotePlatformFile.py to support different renderings of ENOSYS.
…FC) (llvm#106774) (based on a conversation I had with @labath yesterday in llvm#106442) Most APIs that currently vend a Status would be better served by returning llvm::Expected<> instead. If possibles APIs should be refactored to avoid Status. The only legitimate long-term uses of Status are objects that need to store an error for a long time (which should be questioned as a design decision, too). This patch makes the transition to llvm::Error easier by making the places that cannot switch to llvm::Error explicit: They are marked with a call to Status::clone(). Every other API can and should be refactored to use llvm::Expected. In the end Status should only be used in very few places. Whenever an unchecked Error is dropped by Status it logs this to the verbose API channel. Implementation notes: This patch introduces two new kinds of error_category as well as new llvm::Error types. Here is the mapping of lldb::ErrorType to llvm::Errors: ``` (eErrorTypeInvalid) eErrorTypeGeneric llvm::StringError eErrorTypePOSIX llvm::ECError eErrorTypeMachKernel MachKernelError eErrorTypeExpression llvm::ErrorList<ExpressionError> eErrorTypeWin32 Win32Error ``` Relanding with built-in cloning support for llvm::ECError, and support for initializing a Windows error with a NO_ERROR error code, and modifying TestGDBRemotePlatformFile.py to support different renderings of ENOSYS. (cherry picked from commit 1fae131)
…5170ac5f7 Local branch amd-gfx b625170 Merged main:76883932014bcce2efb57be062f901de26317707 into amd-gfx:888e970457a7 Remote branch main b44da24 [lldb] Change the implementation of Status to store an llvm::Error (NFC) (llvm#106774)
(based on a conversation I had with @labath yesterday in #106442)
Most APIs that currently vend a Status would be better served by returning llvm::Expected<> instead. If possibles APIs should be refactored to avoid Status. The only legitimate long-term uses of Status are objects that need to store an error for a long time (which should be questioned as a design decision, too).
This patch makes the transition to llvm::Error easier by making the places that cannot switch to llvm::Error explicit: They are marked with a call to Status::clone(). Every other API can and should be refactored to use llvm::Expected. In the end Status should only be used in very few places.
Whenever an unchecked Error is dropped by Status it logs this to the verbose API channel.
Implementation notes:
This patch introduces two new kinds of error_category as well as new llvm::Error types. Here is the mapping of lldb::ErrorType to llvm::Errors: