From d930b5205e277b522c2a7fe4a7c0e08c5a8afee1 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 2 Feb 2022 08:59:22 +0200 Subject: Redo diagnostics without operator<< in namespace std --- libbuild2/cc/lexer.test.cxx | 1 + libbuild2/cc/types.hxx | 4 ++ libbuild2/diagnostics.cxx | 24 -------- libbuild2/diagnostics.hxx | 141 +++++++++++++++++++++++++------------------- libbuild2/script/script.hxx | 4 ++ libbuild2/types.hxx | 33 ++++------- libbuild2/utility.cxx | 9 +-- 7 files changed, 103 insertions(+), 113 deletions(-) diff --git a/libbuild2/cc/lexer.test.cxx b/libbuild2/cc/lexer.test.cxx index 0d7d12f..39e4279 100644 --- a/libbuild2/cc/lexer.test.cxx +++ b/libbuild2/cc/lexer.test.cxx @@ -6,6 +6,7 @@ #include #include +#include #include #undef NDEBUG diff --git a/libbuild2/cc/types.hxx b/libbuild2/cc/types.hxx index c5b35f5..93f31bc 100644 --- a/libbuild2/cc/types.hxx +++ b/libbuild2/cc/types.hxx @@ -175,6 +175,10 @@ namespace build2 const target_type& bmi; const target_type& hbmi; }; + + // "Unhide" operator<< from the build2 namespace. + // + using build2::operator<<; } } diff --git a/libbuild2/diagnostics.cxx b/libbuild2/diagnostics.cxx index 4d2d7ce..a2a8444 100644 --- a/libbuild2/diagnostics.cxx +++ b/libbuild2/diagnostics.cxx @@ -77,30 +77,6 @@ namespace build2 dr << butl::process_args {args, n}; } - // Diagnostics stack. - // - static -#ifdef __cpp_thread_local - thread_local -#else - __thread -#endif - const diag_frame* diag_frame_stack = nullptr; - - const diag_frame* diag_frame:: - stack () noexcept - { - return diag_frame_stack; - } - - const diag_frame* diag_frame:: - stack (const diag_frame* f) noexcept - { - const diag_frame* r (diag_frame_stack); - diag_frame_stack = f; - return r; - } - // Diagnostic facility, project specifics. // 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 struct diag_prologue; + template struct diag_mark; + + struct diag_record: butl::diag_record { - explicit - diag_frame (void (*f) (const diag_frame&, const diag_record&)) - : func_ (f) + template + 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 + explicit + diag_record (const diag_prologue& p): diag_record () { *this << p;} - diag_frame& operator= (diag_frame&&) = delete; + template + explicit + diag_record (const diag_mark& m): diag_record () { *this << m;} + }; - diag_frame (const diag_frame&) = delete; - diag_frame& operator= (const diag_frame&) = delete; + template + struct diag_prologue: butl::diag_prologue + { + using butl::diag_prologue::diag_prologue; - ~diag_frame () + template + 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 + struct diag_mark: butl::diag_mark + { + using butl::diag_mark::diag_mark; - // Set the new and return the previous tip of the stack. - // - static const diag_frame* - stack (const diag_frame*) noexcept; + template + 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 + struct diag_noreturn_end: butl::diag_noreturn_end + { + using butl::diag_noreturn_end::diag_noreturn_end; + + [[noreturn]] friend void + operator<< (const diag_record& r, const diag_noreturn_end& e) + { + assert (r.full ()); + e.B::operator() (r); + } }; template @@ -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 (f).func_ (r); + static_cast (f).func_ ( + static_cast (r)); } const F func_; @@ -288,8 +307,6 @@ namespace build2 return diag_frame_impl (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; - using location_prologue = butl::diag_prologue; + using simple_prologue = diag_prologue; + using location_prologue = diag_prologue; 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; + using basic_mark = diag_mark; 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; + using trace_mark = diag_mark; 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; + using fail_mark = diag_mark; struct fail_end_base { @@ -488,7 +505,7 @@ namespace build2 throw failed (); } }; - using fail_end = butl::diag_noreturn_end; + using fail_end = diag_noreturn_end; LIBBUILD2_SYMEXPORT extern const fail_mark fail; LIBBUILD2_SYMEXPORT extern const fail_end endf; diff --git a/libbuild2/script/script.hxx b/libbuild2/script/script.hxx index 81bc13c..5a39659 100644 --- a/libbuild2/script/script.hxx +++ b/libbuild2/script/script.hxx @@ -585,6 +585,10 @@ namespace build2 verify_environment_var_assignment (const string&, const char* prefix, const location&); + + // "Unhide" operator<< from the build2 namespace. + // + using build2::operator<<; } } diff --git a/libbuild2/types.hxx b/libbuild2/types.hxx index af1a4de..7bc6b32 100644 --- a/libbuild2/types.hxx +++ b/libbuild2/types.hxx @@ -317,6 +317,14 @@ namespace build2 using paths = std::vector; using dir_paths = std::vector; + // Path printing potentially relative with trailing slash for directories. + // + LIBBUILD2_SYMEXPORT ostream& + operator<< (ostream&, const ::butl::path&); // utility.cxx + + LIBBUILD2_SYMEXPORT ostream& + operator<< (ostream&, const ::butl::path_name_view&); // utility.cxx + // // using butl::system_clock; @@ -381,6 +389,11 @@ namespace build2 process_path_ex () = default; }; + // Print as recall[@effect]. + // + LIBBUILD2_SYMEXPORT ostream& + operator<< (ostream&, const ::butl::process_path&); // utility.cxx + // // using butl::auto_fd; @@ -478,26 +491,6 @@ namespace build2 operator<< (ostream&, run_phase); // utility.cxx } -// In order to be found (via ADL) these have to be either in std:: or in -// butl::. The latter is a bad idea since libbutl includes the default -// implementation. They are defined in utility.cxx. -// -namespace std -{ - // Path printing potentially relative with trailing slash for directories. - // - LIBBUILD2_SYMEXPORT ostream& - operator<< (ostream&, const ::butl::path&); - - LIBBUILD2_SYMEXPORT ostream& - operator<< (ostream&, const ::butl::path_name_view&); - - // Print as recall[@effect]. - // - LIBBUILD2_SYMEXPORT ostream& - operator<< (ostream&, const ::butl::process_path&); -} - // // #include diff --git a/libbuild2/utility.cxx b/libbuild2/utility.cxx index f7f3d41..3f89def 100644 --- a/libbuild2/utility.cxx +++ b/libbuild2/utility.cxx @@ -19,7 +19,6 @@ using namespace std; using namespace butl; -// // // namespace build2 @@ -31,10 +30,7 @@ namespace build2 { return os << run_phase_[static_cast (p)]; } -} -namespace std -{ ostream& operator<< (ostream& os, const ::butl::path& p) { @@ -76,11 +72,10 @@ namespace std } } +// +// namespace build2 { - // - // - // void (*terminate) (bool); process_path argv0; -- cgit v1.1