aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/diagnostics.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/diagnostics.hxx')
-rw-r--r--libbuild2/diagnostics.hxx141
1 files changed, 79 insertions, 62 deletions
diff --git a/libbuild2/diagnostics.hxx b/libbuild2/diagnostics.hxx
index f3d9db4..c6c4344 100644
--- a/libbuild2/diagnostics.hxx
+++ b/libbuild2/diagnostics.hxx
@@ -14,7 +14,7 @@
namespace build2
{
- using butl::diag_record;
+ struct diag_record;
// Throw this exception to terminate the build. The handler should
// assume that the diagnostics has already been issued.
@@ -190,79 +190,97 @@ namespace build2
: stderr_term && verb >= 1 && verb <= max_verb;
}
- // Diagnostic facility, base infrastructure.
+ // Diagnostic facility.
+ //
+ // Note that this is the "complex" case we we derive from (rather than
+ // alias) a number of butl::diag_* types and provide custom operator<<
+ // "overrides" in order to make ADL look in the build2 rather than butl
+ // namespace.
//
using butl::diag_stream_lock;
using butl::diag_stream;
using butl::diag_epilogue;
+ using butl::diag_frame;
- // Diagnostics stack. Each frame is "applied" to the fail/error/warn/info
- // diag record.
- //
- // Unfortunately most of our use-cases don't fit into the 2-pointer small
- // object optimization of std::function. So we have to complicate things
- // a bit here.
- //
- struct LIBBUILD2_SYMEXPORT diag_frame
+ template <typename> struct diag_prologue;
+ template <typename> struct diag_mark;
+
+ struct diag_record: butl::diag_record
{
- explicit
- diag_frame (void (*f) (const diag_frame&, const diag_record&))
- : func_ (f)
+ template <typename T>
+ const diag_record&
+ operator<< (const T& x) const
{
- if (func_ != nullptr)
- prev_ = stack (this);
+ os << x;
+ return *this;
}
- diag_frame (diag_frame&& x)
- : func_ (x.func_)
- {
- if (func_ != nullptr)
- {
- prev_ = x.prev_;
- stack (this);
+ diag_record () = default;
- x.func_ = nullptr;
- }
- }
+ template <typename B>
+ explicit
+ diag_record (const diag_prologue<B>& p): diag_record () { *this << p;}
- diag_frame& operator= (diag_frame&&) = delete;
+ template <typename B>
+ explicit
+ diag_record (const diag_mark<B>& m): diag_record () { *this << m;}
+ };
- diag_frame (const diag_frame&) = delete;
- diag_frame& operator= (const diag_frame&) = delete;
+ template <typename B>
+ struct diag_prologue: butl::diag_prologue<B>
+ {
+ using butl::diag_prologue<B>::diag_prologue;
- ~diag_frame ()
+ template <typename T>
+ diag_record
+ operator<< (const T& x) const
{
- if (func_ != nullptr )
- stack (prev_);
+ diag_record r;
+ r.append (this->indent, this->epilogue);
+ B::operator() (r);
+ r << x;
+ return r;
}
- static void
- apply (const diag_record& r)
+ friend const diag_record&
+ operator<< (const diag_record& r, const diag_prologue& p)
{
- for (const diag_frame* f (stack ()); f != nullptr; f = f->prev_)
- f->func_ (*f, r);
+ r.append (p.indent, p.epilogue);
+ p (r);
+ return r;
}
+ };
- // Tip of the stack.
- //
- static const diag_frame*
- stack () noexcept;
+ template <typename B>
+ struct diag_mark: butl::diag_mark<B>
+ {
+ using butl::diag_mark<B>::diag_mark;
- // Set the new and return the previous tip of the stack.
- //
- static const diag_frame*
- stack (const diag_frame*) noexcept;
+ template <typename T>
+ diag_record
+ operator<< (const T& x) const
+ {
+ return B::operator() () << x;
+ }
- struct stack_guard
+ friend const diag_record&
+ operator<< (const diag_record& r, const diag_mark& m)
{
- explicit stack_guard (const diag_frame* s): s_ (stack (s)) {}
- ~stack_guard () {stack (s_);}
- const diag_frame* s_;
- };
+ return r << m ();
+ }
+ };
- private:
- void (*func_) (const diag_frame&, const diag_record&);
- const diag_frame* prev_;
+ template <typename B>
+ struct diag_noreturn_end: butl::diag_noreturn_end<B>
+ {
+ using butl::diag_noreturn_end<B>::diag_noreturn_end;
+
+ [[noreturn]] friend void
+ operator<< (const diag_record& r, const diag_noreturn_end& e)
+ {
+ assert (r.full ());
+ e.B::operator() (r);
+ }
};
template <typename F>
@@ -273,9 +291,10 @@ namespace build2
private:
static void
- thunk (const diag_frame& f, const diag_record& r)
+ thunk (const diag_frame& f, const butl::diag_record& r)
{
- static_cast<const diag_frame_impl&> (f).func_ (r);
+ static_cast<const diag_frame_impl&> (f).func_ (
+ static_cast<const diag_record&> (r));
}
const F func_;
@@ -288,8 +307,6 @@ namespace build2
return diag_frame_impl<F> (move (f));
}
- // Diagnostic facility, project specifics.
- //
struct LIBBUILD2_SYMEXPORT simple_prologue_base
{
explicit
@@ -352,8 +369,8 @@ namespace build2
struct basic_mark_base
{
- using simple_prologue = butl::diag_prologue<simple_prologue_base>;
- using location_prologue = butl::diag_prologue<location_prologue_base>;
+ using simple_prologue = diag_prologue<simple_prologue_base>;
+ using location_prologue = diag_prologue<location_prologue_base>;
explicit
basic_mark_base (const char* type,
@@ -427,7 +444,7 @@ namespace build2
const void* data_;
diag_epilogue* const epilogue_;
};
- using basic_mark = butl::diag_mark<basic_mark_base>;
+ using basic_mark = diag_mark<basic_mark_base>;
LIBBUILD2_SYMEXPORT extern const basic_mark error;
LIBBUILD2_SYMEXPORT extern const basic_mark warn;
@@ -452,7 +469,7 @@ namespace build2
mod,
name) {}
};
- using trace_mark = butl::diag_mark<trace_mark_base>;
+ using trace_mark = diag_mark<trace_mark_base>;
using tracer = trace_mark;
// fail
@@ -464,7 +481,7 @@ namespace build2
const void* data = nullptr)
: basic_mark_base (type,
data,
- [](const diag_record& r)
+ [](const butl::diag_record& r)
{
diag_frame::apply (r);
r.flush ();
@@ -474,7 +491,7 @@ namespace build2
nullptr,
nullptr) {}
};
- using fail_mark = butl::diag_mark<fail_mark_base>;
+ using fail_mark = diag_mark<fail_mark_base>;
struct fail_end_base
{
@@ -488,7 +505,7 @@ namespace build2
throw failed ();
}
};
- using fail_end = butl::diag_noreturn_end<fail_end_base>;
+ using fail_end = diag_noreturn_end<fail_end_base>;
LIBBUILD2_SYMEXPORT extern const fail_mark fail;
LIBBUILD2_SYMEXPORT extern const fail_end endf;