diff --git a/llvm/include/llvm/Support/Error.h b/llvm/include/llvm/Support/Error.h --- a/llvm/include/llvm/Support/Error.h +++ b/llvm/include/llvm/Support/Error.h @@ -57,6 +57,10 @@ std::string Msg; raw_string_ostream OS(Msg); log(OS); +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (File) + OS << " at " << File << ":" << Line; +#endif return OS.str(); } @@ -83,10 +87,21 @@ return isA(ErrorInfoT::classID()); } +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + void setSourceLocation(const char *file, unsigned line) { + File = file; + Line = line; + } +#endif + private: virtual void anchor(); static char ID; +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + const char *File = nullptr; + unsigned Line = 0; +#endif }; /// Lightweight error class with error context and mandatory checking. @@ -331,6 +346,36 @@ return Error(std::make_unique(std::forward(Args)...)); } +#if LLVM_ENABLE_ABI_BREAKING_CHECKS +namespace detail { + +/// Builder class for creating Errors with source locations. +class SlocErrorBuilder { +public: + SlocErrorBuilder(const char *File, unsigned Line) : File(File), Line(Line) { + assert(File && "File cannot be nullptr"); + } + + /// Make a Error instance representing failure using the given error info + /// type with source location. + template Error make_error(ArgTs &&... Args) { + auto Err = std::make_unique(std::forward(Args)...); + Err->setSourceLocation(File, Line); + return Error(std::move(Err)); + } + +private: + const char *File; + unsigned Line; +}; +} // namespace detail + +#define llvm_make_error \ + ::llvm::detail::SlocErrorBuilder(__FILE__, __LINE__).make_error +#else +#define llvm_make_error ::llvm::make_error +#endif + /// Base class for user error types. Users should declare their error types /// like: /// diff --git a/llvm/unittests/Support/ErrorTest.cpp b/llvm/unittests/Support/ErrorTest.cpp --- a/llvm/unittests/Support/ErrorTest.cpp +++ b/llvm/unittests/Support/ErrorTest.cpp @@ -906,6 +906,24 @@ 0); } +TEST(Error, SourceLocationErrorTest) { + std::string ErrStr; + raw_string_ostream OS(ErrStr); + +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + // __FILE__ and __LINE__ added + int Line = __LINE__; + OS << "^CustomError \\{1\\} at " << __FILE__ << ":" << (Line + 2) << "$"; + auto E = llvm_make_error(1); + EXPECT_THAT(toString(std::move(E)), ::testing::ContainsRegex(OS.str())); +#else + // __FILE__ and __LINE_ not added + OS << "^CustomError \\{1\\}$"; + auto E = llvm_make_error(1); + EXPECT_THAT(toString(std::move(FE1)), ::testing::ContainsRegex(OS.str())); +#endif +} + enum class test_error_code { unspecified = 1, error_1,