Index: include/lldb/Symbol/CompilerType.h =================================================================== --- include/lldb/Symbol/CompilerType.h +++ include/lldb/Symbol/CompilerType.h @@ -21,6 +21,7 @@ #include "lldb/Core/ClangForward.h" #include "lldb/lldb-private.h" #include "llvm/ADT/APSInt.h" +#include "llvm/Support/Error.h" namespace lldb_private { @@ -441,6 +442,23 @@ CompilerType type; }; +/// A force-checked error used to describe type construction failures. +class InvalidTypeError : public llvm::ErrorInfo { +public: + static char ID; + std::string Reason; + + InvalidTypeError(llvm::StringRef Reason) : Reason(Reason) {} + + void log(llvm::raw_ostream &OS) const override { + OS << "Invalid type: " << Reason; + } + + std::error_code convertToErrorCode() const override { + return std::make_error_code(std::errc::invalid_argument); + } +}; + } // namespace lldb_private #endif // liblldb_CompilerType_h_ Index: include/lldb/Utility/Log.h =================================================================== --- include/lldb/Utility/Log.h +++ include/lldb/Utility/Log.h @@ -212,6 +212,23 @@ void operator=(const Log &) = delete; }; +// Helper utilities for macros which consume and log errors. These are not +// meant to be used directly. +template +void _takeAndLogError(const char *file, const char *func, llvm::Error E, + Log *log, Args &&... args) { + if (E && log) + log->FormatError(std::move(E), file, func, std::forward(args)...); + else + llvm::consumeError(std::move(E)); +} +template +void _takeAndLogError(const char *file, const char *func, llvm::Error E, + uint32_t log_categories, Args &&... args) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(log_categories)); + _takeAndLogError(file, func, std::move(E), log, std::forward(args)...); +} + } // namespace lldb_private #define LLDB_LOG(log, ...) \ @@ -230,15 +247,26 @@ // Write message to log, if error is set. In the log message refer to the error // with {0}. Error is cleared regardless of whether logging is enabled. +// +// For convenience, log may either be a Log instance or an unsigned value +// specifying log categories in the "lldb" log channel. #define LLDB_LOG_ERROR(log, error, ...) \ + ::lldb_private::_takeAndLogError(__FILE__, __func__, error, log, __VA_ARGS__) + +// If item contains an unexpected result, log the error and return the given +// return value. +// +// For convenience, log may either be a Log instance or an unsigned value +// specifying log categories in the "lldb" log channel. +// +// To set a breakpoint on the failure case, break on the constructor of the +// appropriate ErrorInfo. Set a breakpoint on ErrorInfoBase to catch all errors. +#define RETURN_IF_UNEXPECTED(item, ret_val, log) \ do { \ - ::lldb_private::Log *log_private = (log); \ - ::llvm::Error error_private = (error); \ - if (log_private && error_private) { \ - log_private->FormatError(::std::move(error_private), __FILE__, __func__, \ - __VA_ARGS__); \ - } else \ - ::llvm::consumeError(::std::move(error_private)); \ + if (::llvm::Error error_private = (item).takeError()) { \ + LLDB_LOG_ERROR(log, std::move(error_private), "{0}"); \ + return ret_val; \ + } \ } while (0) #endif // LLDB_UTILITY_LOG_H Index: source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h =================================================================== --- source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -625,10 +625,11 @@ /// The type as it appears in the source context. /// /// @return - /// Returns the moved type, or an empty type if there was a problem. + /// Returns the moved type, or an error. //------------------------------------------------------------------ - TypeFromUser DeportType(ClangASTContext &target, ClangASTContext &source, - TypeFromParser parser_type); + llvm::Expected DeportType(ClangASTContext &target, + ClangASTContext &source, + TypeFromParser parser_type); ClangASTContext *GetClangASTContext(); }; Index: source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp =================================================================== --- source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -277,9 +277,10 @@ return ret; } -TypeFromUser ClangExpressionDeclMap::DeportType(ClangASTContext &target, - ClangASTContext &source, - TypeFromParser parser_type) { +llvm::Expected +ClangExpressionDeclMap::DeportType(ClangASTContext &target, + ClangASTContext &source, + TypeFromParser parser_type) { assert (&target == m_target->GetScratchClangASTContext()); assert ((TypeSystem*)&source == parser_type.GetTypeSystem()); assert (source.getASTContext() == m_ast_context); @@ -302,10 +303,10 @@ source_file, clang::QualType::getFromOpaquePtr(parser_type.GetOpaqueQualType())); return TypeFromUser(exported_type.getAsOpaquePtr(), &target); - } else { - lldbassert(0 && "No mechanism for deporting a type!"); - return TypeFromUser(); } + + lldbassert(0 && "No mechanism for deporting a type!"); + return llvm::make_error("Could not deport type"); } bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, @@ -328,8 +329,12 @@ if (target == nullptr) return false; - TypeFromUser user_type = + llvm::Expected user_type_or_err = DeportType(*target->GetScratchClangASTContext(), *ast, parser_type); + RETURN_IF_UNEXPECTED(user_type_or_err, false, LIBLLDB_LOG_EXPRESSIONS); + TypeFromUser &user_type = *user_type_or_err; + assert(user_type.IsValid() && + "Persistent variable's type wasn't copied successfully"); uint32_t offset = m_parser_vars->m_materializer->AddResultVariable( user_type, is_lvalue, m_keep_result_in_memory, m_result_delegate, err); @@ -366,13 +371,12 @@ ClangASTContext *context(target->GetScratchClangASTContext()); - TypeFromUser user_type = DeportType(*context, *ast, parser_type); - - if (!user_type.GetOpaqueQualType()) { - if (log) - log->Printf("Persistent variable's type wasn't copied successfully"); - return false; - } + llvm::Expected user_type_or_err = + DeportType(*context, *ast, parser_type); + RETURN_IF_UNEXPECTED(user_type_or_err, false, log); + TypeFromUser &user_type = *user_type_or_err; + assert(user_type.IsValid() && + "Persistent variable's type wasn't copied successfully"); if (!m_parser_vars->m_target_info.IsValid()) return false; Index: source/Symbol/CompilerType.cpp =================================================================== --- source/Symbol/CompilerType.cpp +++ source/Symbol/CompilerType.cpp @@ -1080,3 +1080,5 @@ return lhs.GetTypeSystem() != rhs.GetTypeSystem() || lhs.GetOpaqueQualType() != rhs.GetOpaqueQualType(); } + +char lldb_private::InvalidTypeError::ID;