arphaman created this revision.
Clang's `DiagnosticOr` type mimics the `Expected` type from LLVM. It either
stores a partial diagnostic and its location or a value. I'll be using in
https://reviews.llvm.org/D36075.
Repository:
rL LLVM
https://reviews.llvm.org/D36969
Files:
include/clang/Basic/DiagnosticOr.h
unittests/Basic/DiagnosticTest.cpp
Index: unittests/Basic/DiagnosticTest.cpp
===================================================================
--- unittests/Basic/DiagnosticTest.cpp
+++ unittests/Basic/DiagnosticTest.cpp
@@ -9,6 +9,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/DiagnosticOr.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -72,4 +73,21 @@
}
}
+TEST(DiagnosticTest, diagnosticOr) {
+ DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions,
+ new IgnoringDiagConsumer());
+ PartialDiagnostic::StorageAllocator Alloc;
+ DiagnosticOr<std::pair<int, int>> Value = PartialDiagnosticAt(
+ SourceLocation(), PartialDiagnostic(diag::err_cannot_open_file, Alloc)
+ << "file"
+ << "error");
+ EXPECT_TRUE(!Value);
+ EXPECT_EQ(Value.getDiagnostic().first, SourceLocation());
+ EXPECT_EQ(Value.getDiagnostic().second.getDiagID(),
+ diag::err_cannot_open_file);
+ Value = std::make_pair(20, 1);
+ EXPECT_FALSE(!Value);
+ EXPECT_EQ(*Value, std::make_pair(20, 1));
+ EXPECT_EQ(Value->first, 20);
+}
}
Index: include/clang/Basic/DiagnosticOr.h
===================================================================
--- /dev/null
+++ include/clang/Basic/DiagnosticOr.h
@@ -0,0 +1,131 @@
+//===--- DiagnosticOr.h - A partial diagnostic or a value -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Implements a DiagnosticOr variant that stores either a value or a
+/// partial diagnostic and its location.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_DIAGNOSTIC_OR_H
+#define LLVM_CLANG_BASIC_DIAGNOSTIC_OR_H
+
+#include "clang/Basic/PartialDiagnostic.h"
+#include "llvm/Support/AlignOf.h"
+
+namespace clang {
+
+/// Tagged union holding either a T or a PartialDiagnosticAt.
+///
+/// This class parallels llvm::Expected, but replaces Error with
+/// PartialDiagnosticAt.
+template <class T> class LLVM_NODISCARD DiagnosticOr {
+private:
+ using storage_type = T;
+ using reference = T &;
+ using const_reference = const T &;
+ using pointer = T *;
+ using const_pointer = const T *;
+
+public:
+ /// Create an DiagnosticOr<T> diagnostic value from the given partial
+ /// diagnostic.
+ DiagnosticOr(PartialDiagnosticAt Diagnostic) : HasDiagnostic(true) {
+ new (getDiagnosticStorage()) PartialDiagnosticAt(std::move(Diagnostic));
+ }
+
+ /// Create an DiagnosticOr<T> success value from the given OtherT value, which
+ /// must be convertible to T.
+ template <typename OtherT>
+ DiagnosticOr(
+ OtherT &&Val,
+ typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
+ nullptr)
+ : HasDiagnostic(false) {
+ new (getStorage()) storage_type(std::forward<OtherT>(Val));
+ }
+
+ DiagnosticOr(DiagnosticOr<T> &&Other) { moveConstruct(std::move(Other)); }
+
+ DiagnosticOr<T> &operator=(DiagnosticOr<T> &&Other) {
+ moveAssign(std::move(Other));
+ return *this;
+ }
+
+ ~DiagnosticOr() {
+ if (!HasDiagnostic)
+ getStorage()->~storage_type();
+ else
+ getDiagnosticStorage()->~PartialDiagnosticAt();
+ }
+
+ /// Returns false if there is a diagnostic.
+ explicit operator bool() { return !HasDiagnostic; }
+
+ PartialDiagnosticAt &getDiagnostic() { return *getDiagnosticStorage(); }
+
+ const PartialDiagnosticAt &getDiagnostic() const {
+ return *getDiagnosticStorage();
+ }
+
+ pointer operator->() { return getStorage(); }
+
+ const_pointer operator->() const { return getStorage(); }
+
+ reference operator*() { return *getStorage(); }
+
+ const_reference operator*() const { return *getStorage(); }
+
+private:
+ void moveConstruct(DiagnosticOr<T> &&Other) {
+ HasDiagnostic = Other.HasDiagnostic;
+
+ if (!HasDiagnostic)
+ new (getStorage()) storage_type(std::move(*Other.getStorage()));
+ else
+ new (getDiagnosticStorage())
+ PartialDiagnosticAt(std::move(*Other.getDiagnosticStorage()));
+ }
+
+ void moveAssign(DiagnosticOr<T> &&Other) {
+ this->~DiagnosticOr();
+ new (this) DiagnosticOr<T>(std::move(Other));
+ }
+
+ storage_type *getStorage() {
+ assert(!HasDiagnostic && "Cannot get value when a diagnostic exists!");
+ return reinterpret_cast<storage_type *>(TStorage.buffer);
+ }
+
+ const storage_type *getStorage() const {
+ assert(!HasDiagnostic && "Cannot get value when a diagnostic exists!");
+ return reinterpret_cast<const storage_type *>(TStorage.buffer);
+ }
+
+ PartialDiagnosticAt *getDiagnosticStorage() {
+ assert(HasDiagnostic && "Cannot get diagnostic when a value exists!");
+ return reinterpret_cast<PartialDiagnosticAt *>(DiagnosticStorage.buffer);
+ }
+
+ const PartialDiagnosticAt *getDiagnosticStorage() const {
+ assert(HasDiagnostic && "Cannot get diagnostic when a value exists!");
+ return reinterpret_cast<const PartialDiagnosticAt *>(
+ DiagnosticStorage.buffer);
+ }
+
+ union {
+ llvm::AlignedCharArrayUnion<storage_type> TStorage;
+ llvm::AlignedCharArrayUnion<PartialDiagnosticAt> DiagnosticStorage;
+ };
+ bool HasDiagnostic : 1;
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_BASIC_DIAGNOSTIC_OR_H
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits