Index: cfe/trunk/include/clang/Basic/DiagnosticError.h =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticError.h +++ cfe/trunk/include/clang/Basic/DiagnosticError.h @@ -0,0 +1,61 @@ +//===--- DiagnosticError.h - Diagnostic payload for llvm::Error -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_DIAGNOSTIC_ERROR_H +#define LLVM_CLANG_BASIC_DIAGNOSTIC_ERROR_H + +#include "clang/Basic/PartialDiagnostic.h" +#include "llvm/Support/Error.h" + +namespace clang { + +/// \brief Carries a Clang diagnostic in an llvm::Error. +/// +/// Users should emit the stored diagnostic using the DiagnosticsEngine. +class DiagnosticError : public llvm::ErrorInfo { +public: + DiagnosticError(PartialDiagnosticAt Diag) : Diag(std::move(Diag)) {} + + void log(raw_ostream &OS) const override { OS << "clang diagnostic"; } + + PartialDiagnosticAt &getDiagnostic() { return Diag; } + const PartialDiagnosticAt &getDiagnostic() const { return Diag; } + + /// Creates a new \c DiagnosticError that contains the given diagnostic at + /// the given location. + static llvm::Error create(SourceLocation Loc, PartialDiagnostic Diag) { + return llvm::make_error( + PartialDiagnosticAt(Loc, std::move(Diag))); + } + + /// Extracts and returns the diagnostic payload from the given \c Error if + /// the error is a \c DiagnosticError. Returns none if the given error is not + /// a \c DiagnosticError. + static Optional take(llvm::Error &Err) { + Optional Result; + Err = llvm::handleErrors(std::move(Err), [&](DiagnosticError &E) { + Result = std::move(E.getDiagnostic()); + }); + return Result; + } + + static char ID; + +private: + // Users are not expected to use error_code. + std::error_code convertToErrorCode() const override { + return llvm::inconvertibleErrorCode(); + } + + PartialDiagnosticAt Diag; +}; + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_DIAGNOSTIC_ERROR_H Index: cfe/trunk/lib/Basic/Diagnostic.cpp =================================================================== --- cfe/trunk/lib/Basic/Diagnostic.cpp +++ cfe/trunk/lib/Basic/Diagnostic.cpp @@ -11,8 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/DiagnosticError.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/PartialDiagnostic.h" @@ -1050,3 +1051,5 @@ llvm::CrashRecoveryContext::isRecoveringFromCrash()) && "A partial is on the lam"); } + +char DiagnosticError::ID; Index: cfe/trunk/unittests/Basic/DiagnosticTest.cpp =================================================================== --- cfe/trunk/unittests/Basic/DiagnosticTest.cpp +++ cfe/trunk/unittests/Basic/DiagnosticTest.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticError.h" #include "clang/Basic/DiagnosticIDs.h" #include "gtest/gtest.h" @@ -72,4 +73,25 @@ } } +TEST(DiagnosticTest, diagnosticError) { + DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions, + new IgnoringDiagConsumer()); + PartialDiagnostic::StorageAllocator Alloc; + llvm::Expected> Value = DiagnosticError::create( + SourceLocation(), PartialDiagnostic(diag::err_cannot_open_file, Alloc) + << "file" + << "error"); + ASSERT_TRUE(!Value); + llvm::Error Err = Value.takeError(); + Optional ErrDiag = DiagnosticError::take(Err); + llvm::cantFail(std::move(Err)); + ASSERT_FALSE(!ErrDiag); + EXPECT_EQ(ErrDiag->first, SourceLocation()); + EXPECT_EQ(ErrDiag->second.getDiagID(), diag::err_cannot_open_file); + + Value = std::make_pair(20, 1); + ASSERT_FALSE(!Value); + EXPECT_EQ(*Value, std::make_pair(20, 1)); + EXPECT_EQ(Value->first, 20); +} }