diff options
-rw-r--r-- | build2/algorithm.cxx | 2 | ||||
-rw-r--r-- | build2/cc/compile.cxx | 3 | ||||
-rw-r--r-- | build2/cc/guess.cxx | 20 | ||||
-rw-r--r-- | build2/diagnostics | 213 | ||||
-rw-r--r-- | build2/diagnostics.cxx | 36 | ||||
-rw-r--r-- | build2/file.cxx | 9 | ||||
-rw-r--r-- | build2/filesystem.cxx | 18 | ||||
-rw-r--r-- | build2/function | 6 | ||||
-rw-r--r-- | build2/function.cxx | 71 | ||||
-rw-r--r-- | build2/functions-path.cxx | 3 | ||||
-rw-r--r-- | build2/lexer | 31 | ||||
-rw-r--r-- | build2/lexer.cxx | 7 | ||||
-rw-r--r-- | build2/parser | 4 | ||||
-rw-r--r-- | build2/parser.cxx | 3 | ||||
-rw-r--r-- | build2/test/rule.cxx | 12 | ||||
-rw-r--r-- | build2/test/script/parser.cxx | 21 | ||||
-rw-r--r-- | build2/test/script/runner.cxx | 3 | ||||
-rw-r--r-- | build2/types | 25 | ||||
-rw-r--r-- | build2/utility | 46 | ||||
-rw-r--r-- | build2/utility.cxx | 36 | ||||
-rw-r--r-- | build2/variable.txx | 42 | ||||
-rw-r--r-- | unit-tests/function/driver.cxx | 2 |
22 files changed, 194 insertions, 419 deletions
diff --git a/build2/algorithm.cxx b/build2/algorithm.cxx index 5d0e010..245e7ad 100644 --- a/build2/algorithm.cxx +++ b/build2/algorithm.cxx @@ -236,7 +236,7 @@ namespace build2 if (verb < 4) dr << info << "re-run with --verbose 4 for more information"; - return r; + dr << endf; } group_view diff --git a/build2/cc/compile.cxx b/build2/cc/compile.cxx index 45a0aff..37cd7d7 100644 --- a/build2/cc/compile.cxx +++ b/build2/cc/compile.cxx @@ -703,8 +703,7 @@ namespace build2 } } - error << "unable to parse /showIncludes include error line"; - throw failed (); + fail << "unable to parse /showIncludes include error line" << endf; } else { diff --git a/build2/cc/guess.cxx b/build2/cc/guess.cxx index f23a175..b153cc1 100644 --- a/build2/cc/guess.cxx +++ b/build2/cc/guess.cxx @@ -421,9 +421,8 @@ namespace build2 catch (const invalid_argument&) {} catch (const out_of_range&) {} - error << "unable to extract gcc " << m << " version from '" - << string (s, b, e - b) << "'"; - throw failed (); + fail << "unable to extract gcc " << m << " version from '" + << string (s, b, e - b) << "'" << endf; }; v.major = next ("major"); @@ -561,9 +560,8 @@ namespace build2 catch (const invalid_argument&) {} catch (const out_of_range&) {} - error << "unable to extract clang " << m << " version from '" - << string (s, b, e - b) << "'"; - throw failed (); + fail << "unable to extract clang " << m << " version from '" + << string (s, b, e - b) << "'" << endf; }; v.major = next ("major", false); @@ -718,9 +716,8 @@ namespace build2 catch (const invalid_argument&) {} catch (const out_of_range&) {} - error << "unable to extract icc " << m << " version from '" - << string (s, b, e - b) << "'"; - throw failed (); + fail << "unable to extract icc " << m << " version from '" + << string (s, b, e - b) << "'" << endf; }; v.major = next ("major", false); @@ -920,9 +917,8 @@ namespace build2 catch (const invalid_argument&) {} catch (const out_of_range&) {} - error << "unable to extract msvc " << m << " version from '" - << string (s, b, e - b) << "'"; - throw failed (); + fail << "unable to extract msvc " << m << " version from '" + << string (s, b, e - b) << "'" << endf; }; v.major = next ("major"); diff --git a/build2/diagnostics b/build2/diagnostics index 6b89903..a58e9c7 100644 --- a/build2/diagnostics +++ b/build2/diagnostics @@ -5,15 +5,14 @@ #ifndef BUILD2_DIAGNOSTICS #define BUILD2_DIAGNOSTICS -#include <sstream> -#include <type_traits> +#include <butl/diagnostics> #include <build2/types> #include <build2/utility> namespace build2 { - struct diag_record; + using butl::diag_record; // Throw this exception to terminate the build. The handler should // assume that the diagnostics has already been issued. @@ -109,150 +108,10 @@ namespace build2 os.iword (stream_verb_index) = static_cast<long> (v + 1); } - // Diagnostic facility, base infrastructure (potentially reusable). + // Diagnostic facility, base infrastructure. // - extern ostream* diag_stream; - - template <typename> struct diag_prologue; - template <typename> struct diag_mark; - - typedef void (*diag_epilogue) (const diag_record&); - - struct diag_record - { - template <typename T> - friend const diag_record& - operator<< (const diag_record& r, const T& x) - { - r.os << x; - return r; - } - - diag_record (): empty_ (true), epilogue_ (nullptr) {} - - template <typename B> - explicit - diag_record (const diag_prologue<B>& p) - : empty_ (true), epilogue_ (nullptr) { *this << p;} - - template <typename B> - explicit - diag_record (const diag_mark<B>& m) - : empty_ (true), epilogue_ (nullptr) { *this << m;} - - ~diag_record () noexcept (false); - - void - append (diag_epilogue e) const - { - if (e != nullptr) - { - assert (epilogue_ == nullptr); // No multiple epilogues support. - epilogue_ = e; - } - - if (empty_) - empty_ = false; - else - os << "\n "; - } - - // Move constructible-only type. - // - // Older versions of libstdc++ don't have the ostringstream move support - // and accuratly detecting its version is non-trivial. So we always use - // the pessimized implementation with libstdc++. Luckily, GCC doesn't seem - // to be needing move due to copy/move elision. - // - diag_record (diag_record&& r) -#ifndef __GLIBCXX__ - : os (move (r.os)) -#endif - { - empty_ = r.empty_; - epilogue_ = r.epilogue_; - - if (!empty_) - { -#ifdef __GLIBCXX__ - stream_verb (os, stream_verb (r.os)); - os << r.os.str (); -#endif - r.empty_ = true; - r.epilogue_ = nullptr; - } - } - - diag_record& operator= (diag_record&&) = delete; - - diag_record (const diag_record&) = delete; - diag_record& operator= (const diag_record&) = delete; - - public: - mutable std::ostringstream os; - - private: - mutable bool empty_; - mutable diag_epilogue epilogue_; - }; - - template <typename B> - struct diag_prologue: B - { - diag_prologue (diag_epilogue e = nullptr): B (), epilogue_ (e) {} - - template <typename... A> - diag_prologue (A&&... a) - : B (forward<A> (a)...), epilogue_ (nullptr) {} - - template <typename... A> - diag_prologue (diag_epilogue e, A&&... a) - : B (forward<A> (a)...), epilogue_ (e) {} - - template <typename T> - diag_record - operator<< (const T& x) const - { - diag_record r; - r.append (epilogue_); - B::operator() (r); - r << x; - return r; - } - - friend const diag_record& - operator<< (const diag_record& r, const diag_prologue& p) - { - r.append (p.epilogue_); - p (r); - return r; - } - - private: - diag_epilogue epilogue_; - }; - - template <typename B> - struct diag_mark: B - { - diag_mark (): B () {} - - template <typename... A> - diag_mark (A&&... a): B (forward<A> (a)...) {} - - template <typename T> - diag_record - operator<< (const T& x) const - { - return B::operator() () << x; - } - - friend const diag_record& - operator<< (const diag_record& r, const diag_mark& m) - { - return r << m (); - } - }; + using butl::diag_stream; + using butl::diag_epilogue; // Diagnostic facility, project specifics. // @@ -274,7 +133,6 @@ namespace build2 const char* name_; const uint16_t sverb_; }; - typedef diag_prologue<simple_prologue_base> simple_prologue; class location { @@ -313,17 +171,19 @@ namespace build2 const location loc_; const uint16_t sverb_; }; - typedef diag_prologue<location_prologue_base> location_prologue; struct basic_mark_base { + using simple_prologue = butl::diag_prologue<simple_prologue_base>; + using location_prologue = butl::diag_prologue<location_prologue_base>; + explicit - basic_mark_base (uint16_t (*sverb) (), - const char* type, + basic_mark_base (const char* type, + uint16_t (*sverb) () = &stream_verb_map, const char* mod = nullptr, const char* name = nullptr, const void* data = nullptr, - diag_epilogue epilogue = nullptr) + diag_epilogue* epilogue = nullptr) : sverb_ (sverb), type_ (type), mod_ (mod), name_ (name), data_ (data), epilogue_ (epilogue) {} @@ -354,9 +214,9 @@ namespace build2 const char* mod_; const char* name_; const void* data_; - const diag_epilogue epilogue_; + diag_epilogue* const epilogue_; }; - typedef diag_mark<basic_mark_base> basic_mark; + using basic_mark = butl::diag_mark<basic_mark_base>; extern const basic_mark error; extern const basic_mark warn; @@ -374,36 +234,47 @@ namespace build2 trace_mark_base (const char* mod, const char* name, const void* data = nullptr) - : basic_mark_base ([]() {return stream_verb_max;}, - "trace", - mod, name, + : basic_mark_base ("trace", + []() {return stream_verb_max;}, + mod, + name, data) {} }; - typedef diag_mark<trace_mark_base> trace_mark; - - typedef trace_mark tracer; + using trace_mark = butl::diag_mark<trace_mark_base>; + using tracer = trace_mark; // fail // - template <typename E> struct fail_mark_base: basic_mark_base { explicit - fail_mark_base (const void* data = nullptr) - : basic_mark_base (&stream_verb_map, - "error", - nullptr, nullptr, + fail_mark_base (const char* type, + const void* data = nullptr) + : basic_mark_base (type, + &stream_verb_map, + nullptr, + nullptr, data, - &epilogue) {} - - static void - epilogue (const diag_record&) {throw E ();} + [](const diag_record&) {throw failed ();}) {} }; + using fail_mark = butl::diag_mark<fail_mark_base>; - template <typename E> - using fail_mark = diag_mark<fail_mark_base<E>>; + struct fail_end_base + { + [[noreturn]] void + operator() (const diag_record& r) const + { + // If we just throw then the record's destructor will see an active + // exception and will not flush the record. + // + r.flush (); + throw failed (); + } + }; + using fail_end = butl::diag_noreturn_end<fail_end_base>; - extern const fail_mark<failed> fail; + extern const fail_mark fail; + extern const fail_end endf; } #endif // BUILD2_DIAGNOSTICS diff --git a/build2/diagnostics.cxx b/build2/diagnostics.cxx index dfd792e..0009ff7 100644 --- a/build2/diagnostics.cxx +++ b/build2/diagnostics.cxx @@ -5,7 +5,6 @@ #include <build2/diagnostics> #include <cstring> // strchr() -#include <iostream> using namespace std; @@ -45,29 +44,6 @@ namespace build2 // uint16_t verb; - // Diagnostic facility, base infrastructure. - // - ostream* diag_stream = &cerr; - - diag_record:: - ~diag_record () noexcept(false) - { - // Don't flush the record if this destructor was called as part of - // the stack unwinding. Right now this means we cannot use this - // mechanism in destructors, which is not a big deal, except for - // one place: exception_guard. So for now we are going to have - // this ugly special check which we will be able to get rid of - // once C++17 uncaught_exceptions() becomes available. - // - if (!empty_ && (!std::uncaught_exception () || exception_unwinding_dtor)) - { - *diag_stream << os.str () << endl; - - if (epilogue_ != nullptr) - epilogue_ (*this); // Can throw. - } - } - // Diagnostic facility, project specifics. // @@ -117,10 +93,10 @@ namespace build2 r << name_ << ": "; } - const basic_mark error (&stream_verb_map, "error"); - const basic_mark warn (&stream_verb_map, "warning"); - const basic_mark info (&stream_verb_map, "info"); - const basic_mark text (&stream_verb_map, nullptr); - - const fail_mark<failed> fail; + const basic_mark error ("error"); + const basic_mark warn ("warning"); + const basic_mark info ("info"); + const basic_mark text (nullptr); + const fail_mark fail ("error"); + const fail_end endf; } diff --git a/build2/file.cxx b/build2/file.cxx index ce9571d..b049590 100644 --- a/build2/file.cxx +++ b/build2/file.cxx @@ -306,8 +306,7 @@ namespace build2 } catch (const io_error& e) { - error << "unable to read buildfile " << bf << ": " << e.what (); - throw failed (); + fail << "unable to read buildfile " << bf << ": " << e.what () << endf; } // Never reached. @@ -1050,12 +1049,10 @@ namespace build2 if (!p.empty ()) fail << "unable to import target " << pk << info << "consider explicitly specifying its project out_root via the " - << "config.import." << p << " command line variable"; + << "config.import." << p << " command line variable" << endf; else fail << "unable to import target " << pk << info << "consider adding its installation location" << - info << "or explicitly specifying its project name"; - - throw failed (); // No return. + info << "or explicitly specifying its project name" << endf; } } diff --git a/build2/filesystem.cxx b/build2/filesystem.cxx index c71d2da..5090b77 100644 --- a/build2/filesystem.cxx +++ b/build2/filesystem.cxx @@ -28,8 +28,7 @@ namespace build2 if (verb >= v) text << "mkdir " << d; - error << "unable to create directory " << d << ": " << e.what (); - throw failed (); + fail << "unable to create directory " << d << ": " << e.what () << endf; } if (ms == mkdir_status::success) @@ -58,8 +57,7 @@ namespace build2 if (verb >= v) text << "mkdir -p " << d; - error << "unable to create directory " << d << ": " << e.what (); - throw failed (); + fail << "unable to create directory " << d << ": " << e.what () << endf; } if (ms == mkdir_status::success) @@ -106,8 +104,7 @@ namespace build2 } catch (const system_error& e) { - error << "unable to stat path " << f << ": " << e.what (); - throw failed (); + fail << "unable to stat path " << f << ": " << e.what () << endf; } } @@ -120,8 +117,7 @@ namespace build2 } catch (const system_error& e) { - error << "unable to stat path " << d << ": " << e.what (); - throw failed (); + fail << "unable to stat path " << d << ": " << e.what () << endf; } } @@ -134,8 +130,7 @@ namespace build2 } catch (const system_error& e) { - error << "unable to stat path " << p << ": " << e.what (); - throw failed (); + fail << "unable to stat path " << p << ": " << e.what () << endf; } } @@ -148,8 +143,7 @@ namespace build2 } catch (const system_error& e) { - error << "unable to scan directory " << d << ": " << e.what (); - throw failed (); + fail << "unable to scan directory " << d << ": " << e.what () << endf; } } } diff --git a/build2/function b/build2/function index 32914dd..68edcde 100644 --- a/build2/function +++ b/build2/function @@ -115,9 +115,11 @@ namespace build2 D d) : function_overload (an, mi, ma, move (ts), im) { - // std::is_pod appears to be broken in VC15. + // std::is_pod appears to be broken in VC14 and also in GCC up to + // 5 (pointers to members). // -#if !defined(_MSC_VER) || _MSC_VER > 1900 +#if !((defined(_MSC_VER) && _MSC_VER <= 1900) || \ + (defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5)) static_assert (std::is_pod<D>::value, "type is not POD"); #endif static_assert (sizeof (D) <= data_size, "insufficient space"); diff --git a/build2/function.cxx b/build2/function.cxx index 720a5c2..46dc403 100644 --- a/build2/function.cxx +++ b/build2/function.cxx @@ -177,54 +177,49 @@ namespace build2 { // No match. // - { - diag_record dr (error (loc)); + diag_record dr; + + dr << fail (loc) << "unmatched call to "; print_call (dr.os); - dr << "unmatched call to "; print_call (dr.os); + for (auto i (ip.first); i != ip.second; ++i) + dr << info << "candidate: " << i->second; - for (auto i (ip.first); i != ip.second; ++i) - dr << info << "candidate: " << i->second; + // If this is an unqualified name, then also print qualified + // functions that end with this name. But skip functions that we + // have already printed in the previous loop. + // + if (name.find ('.') == string::npos) + { + size_t n (name.size ()); - // If this is an unqualified name, then also print qualified - // functions that end with this name. But skip functions that we - // have already printed in the previous loop. - // - if (name.find ('.') == string::npos) + for (auto i (functions.begin ()); i != functions.end (); ++i) { - size_t n (name.size ()); + const string& q (i->first); + const function_overload& f (i->second); - for (auto i (functions.begin ()); i != functions.end (); ++i) + if ((f.alt_name == nullptr || f.alt_name != name) && + q.size () > n) { - const string& q (i->first); - const function_overload& f (i->second); - - if ((f.alt_name == nullptr || f.alt_name != name) && - q.size () > n) - { - size_t p (q.size () - n); - if (q[p - 1] == '.' && q.compare (p, n, name) == 0) - dr << info << "candidate: " << i->second; - } + size_t p (q.size () - n); + if (q[p - 1] == '.' && q.compare (p, n, name) == 0) + dr << info << "candidate: " << i->second; } } } - throw failed (); + dr << endf; } default: { // Ambigous match. // - { - diag_record dr (error (loc)); - - dr << "ambiguous call to "; print_call (dr.os); + diag_record dr; + dr << fail (loc) << "ambiguous call to "; print_call (dr.os); - for (auto f: r) - dr << info << "candidate: " << *f; - } + for (auto f: r) + dr << info << "candidate: " << *f; - throw failed (); + dr << endf; } } } @@ -245,16 +240,14 @@ namespace build2 } catch (const invalid_argument& e) { - { - diag_record dr (error); - dr << "invalid argument"; + diag_record dr (fail); + dr << "invalid argument"; - const char* w (e.what ()); - if (*w != '\0') - dr << ": " << w; - } + const char* w (e.what ()); + if (*w != '\0') + dr << ": " << w; - throw failed (); + dr << endf; } #if !defined(_MSC_VER) || _MSC_VER > 1900 diff --git a/build2/functions-path.cxx b/build2/functions-path.cxx index b76b277..c97518c 100644 --- a/build2/functions-path.cxx +++ b/build2/functions-path.cxx @@ -17,8 +17,7 @@ namespace build2 } catch (const invalid_path& e) { - error << "invalid path: '" << e.path << "'"; - throw failed (); + fail << "invalid path: '" << e.path << "'" << endf; } void diff --git a/build2/lexer b/build2/lexer index a539c2d..59150a9 100644 --- a/build2/lexer +++ b/build2/lexer @@ -79,7 +79,7 @@ namespace build2 : lexer (is, name, escapes, processor, true) {} const path& - name () const {return fail.name_;} + name () const {return name_;} // Note: sets mode for the next token. The second argument can be used to // specifythe pair separator character (if the mode supports pairs). @@ -157,17 +157,6 @@ namespace build2 // Diagnostics. // protected: - struct fail_mark_base: build2::fail_mark_base<failed> - { - fail_mark_base (const path& n): name_ (n) {} - - location_prologue - operator() (const xchar&) const; - - path name_; - }; - typedef diag_mark<fail_mark_base> fail_mark; - fail_mark fail; // Lexer state. @@ -179,7 +168,8 @@ namespace build2 void (*p) (token&, const lexer&), bool sm) : char_scanner (is), - fail (n), + fail ("error", &name_), + name_ (n), escapes_ (e), processor_ (p), sep_ (false) @@ -188,6 +178,7 @@ namespace build2 mode (lexer_mode::normal, '@'); } + const path name_; const char* escapes_; void (*processor_) (token&, const lexer&); @@ -197,4 +188,18 @@ namespace build2 }; } +// Diagnostics plumbing. +// +namespace butl // ADL +{ + inline build2::location + get_location (const butl::char_scanner::xchar& c, const void* data) + { + using namespace build2; + + assert (data != nullptr); // E.g., must be &lexer::name_. + return location (static_cast<const path*> (data), c.line, c.column); + } +} + #endif // BUILD2_LEXER diff --git a/build2/lexer.cxx b/build2/lexer.cxx index 2c728d6..cf8a789 100644 --- a/build2/lexer.cxx +++ b/build2/lexer.cxx @@ -573,11 +573,4 @@ namespace build2 return r; } - - location_prologue lexer::fail_mark_base:: - operator() (const xchar& c) const - { - return build2::fail_mark_base<failed>::operator() ( - location (&name_, c.line, c.column)); - } } diff --git a/build2/parser b/build2/parser index 954a706..a2a046b 100644 --- a/build2/parser +++ b/build2/parser @@ -27,7 +27,7 @@ namespace build2 // If boot is true, then we are parsing bootstrap.build and modules // should only be bootstrapped. // - parser (bool boot = false): fail (&path_), boot_ (boot) {} + parser (bool boot = false): fail ("error", &path_), boot_ (boot) {} // Issue diagnostics and throw failed in case of an error. // @@ -477,7 +477,7 @@ namespace build2 // Diagnostics. // protected: - const fail_mark<failed> fail; + const fail_mark fail; protected: bool pre_parse_ = false; diff --git a/build2/parser.cxx b/build2/parser.cxx index 4d2b933..2ebb6fb 100644 --- a/build2/parser.cxx +++ b/build2/parser.cxx @@ -1211,8 +1211,7 @@ namespace build2 try {iv = to_version (v);} catch (const invalid_argument& e) { - error (l) << "invalid version '" << v << "': " << e.what (); - throw failed (); + fail (l) << "invalid version '" << v << "': " << e.what () << endf; } if (iv > BUILD2_VERSION) diff --git a/build2/test/rule.cxx b/build2/test/rule.cxx index 6eb3551..e8a31cb 100644 --- a/build2/test/rule.cxx +++ b/build2/test/rule.cxx @@ -582,14 +582,12 @@ namespace build2 else if (verb) text << "test " << t; + diag_record dr; + if (!run_test (t, dr, args.data ())) { - diag_record dr; - - if (!run_test (t, dr, args.data ())) - { - dr << info << "test command line: "; - print_process (dr, args); - } + dr << info << "test command line: "; + print_process (dr, args); + dr << endf; // return } return target_state::changed; diff --git a/build2/test/script/parser.cxx b/build2/test/script/parser.cxx index 438e1f2..5730647 100644 --- a/build2/test/script/parser.cxx +++ b/build2/test/script/parser.cxx @@ -47,8 +47,8 @@ namespace build2 } catch (const io_error& e) { - error << "unable to read testscript " << p << ": " << e.what (); - throw failed (); + fail << "unable to read testscript " << p << ": " << e.what () + << endf; } } @@ -986,11 +986,9 @@ namespace build2 } catch (const invalid_path&) {} // Fall through. - { - diag_record dr (fail (dl)); - dr << "invalid testscript include path "; - to_stream (dr.os, n, true); // Quote. - } + diag_record dr (fail (dl)); + dr << "invalid testscript include path "; + to_stream (dr.os, n, true); // Quote. } } @@ -1311,14 +1309,12 @@ namespace build2 return p; } - error (l) << "empty " << what; + fail (l) << "empty " << what << endf; } catch (const invalid_path& e) { - error (l) << "invalid " << what << " '" << e.path << "'"; + fail (l) << "invalid " << what << " '" << e.path << "'" << endf; } - - throw failed (); }; auto add_file = [&app, &parse_path] (redirect& r, int fd, string&& w) @@ -2630,8 +2626,7 @@ namespace build2 } catch (const exception&) { - error (loc) << "invalid $* index " << var.name; - throw failed (); + fail (loc) << "invalid $* index " << var.name << endf; } const strings& s (cast<strings> (v)); diff --git a/build2/test/script/runner.cxx b/build2/test/script/runner.cxx index aa35612..ef086f5 100644 --- a/build2/test/script/runner.cxx +++ b/build2/test/script/runner.cxx @@ -41,8 +41,7 @@ namespace build2 // executed let's add the location anyway to ease the // troubleshooting. And let's stick to that principle down the road. // - error (ll) << "unable to read " << p << ": " << e.what (); - throw failed (); + fail (ll) << "unable to read " << p << ": " << e.what () << endf; } } diff --git a/build2/types b/build2/types index b4488bb..c73da73 100644 --- a/build2/types +++ b/build2/types @@ -112,11 +112,6 @@ namespace build2 using paths = std::vector<path>; using dir_paths = std::vector<dir_path>; - // Path printing with trailing slash for directories (utility.cxx). - // - ostream& - operator<< (ostream&, const path&); - // <butl/timestamp> // using butl::system_clock; @@ -137,14 +132,28 @@ namespace build2 using butl::process_path; using butl::process_error; - ostream& - operator<< (ostream&, const process_path&); // Print as recall[@effect]. - using butl::auto_fd; using butl::ifdstream; using butl::ofdstream; } +// In order to be found (via ADL) these have to be either in std:: or in +// butl::. The latter is bad idea since libbutl includes the default +// implementation. They are defined in utility.cxx. +// +namespace std +{ + // Path printing with trailing slash for directories. + // + ostream& + operator<< (ostream&, const ::butl::path&); + + // Print as recall[@effect]. + // + ostream& + operator<< (ostream&, const ::butl::process_path&); +} + // <build2/name> // #include <build2/name> diff --git a/build2/utility b/build2/utility index 4b83844..a0d040a 100644 --- a/build2/utility +++ b/build2/utility @@ -14,9 +14,8 @@ #include <functional> // ref(), cref() #include <butl/utility> // combine_hash(), reverse_iterate(), casecmp(), - // lcase() + // lcase(), etc -#include <exception> // uncaught_exception() #include <unordered_set> #include <build2/types> @@ -54,6 +53,9 @@ namespace build2 using butl::alnum; using butl::digit; + using butl::exception_guard; + using butl::make_exception_guard; + // Basic string utilities. // @@ -434,46 +436,6 @@ namespace build2 unsigned int to_version (const string&); - // Call a function if there is an exception. - // - - // Means we are in the body of a destructor that is being called - // as part of the exception stack unwindining. Used to compensate - // for the deficiencies of uncaught_exception() until C++17 - // uncaught_exceptions() becomes available. - // - // @@ MT: will have to be TLS. - // - extern bool exception_unwinding_dtor; - - template <typename F> - struct exception_guard; - - template <typename F> - inline exception_guard<F> - make_exception_guard (F f) - { - return exception_guard<F> (move (f)); - } - - template <typename F> - struct exception_guard - { - exception_guard (F f): f_ (move (f)) {} - ~exception_guard () - { - if (std::uncaught_exception ()) - { - exception_unwinding_dtor = true; - f_ (); - exception_unwinding_dtor = false; - } - } - - private: - F f_; - }; - // Pools (@@ perhaps move into a separate header). // struct string_pool: std::unordered_set<std::string> diff --git a/build2/utility.cxx b/build2/utility.cxx index 5d65f7b..e4b5254 100644 --- a/build2/utility.cxx +++ b/build2/utility.cxx @@ -15,23 +15,27 @@ using namespace std; -namespace build2 -{ - // - // <build2/types> - // +// +// <build2/types> +// +namespace std +{ ostream& - operator<< (ostream& os, const path& p) + operator<< (ostream& os, const ::butl::path& p) { + using namespace build2; + return os << (stream_verb (os) < 2 ? diag_relative (p) : p.representation ()); } ostream& - operator<< (ostream& os, const process_path& p) + operator<< (ostream& os, const ::butl::process_path& p) { + using namespace build2; + if (p.empty ()) os << "<empty>"; else @@ -47,7 +51,10 @@ namespace build2 return os; } +} +namespace build2 +{ // // <build2/utility> // @@ -153,8 +160,7 @@ namespace build2 } catch (const process_error& e) { - error << "unable to execute " << args0 << ": " << e.what (); - throw failed (); + fail << "unable to execute " << args0 << ": " << e.what () << endf; } process_path @@ -165,8 +171,7 @@ namespace build2 } catch (const process_error& e) { - error << "unable to execute " << f << ": " << e.what (); - throw failed (); + fail << "unable to execute " << f << ": " << e.what () << endf; } process @@ -191,9 +196,7 @@ namespace build2 exit (1); } else - error << "unable to execute " << args[0] << ": " << e.what (); - - throw failed (); + fail << "unable to execute " << args[0] << ": " << e.what () << endf; } } @@ -222,8 +225,7 @@ namespace build2 } catch (const process_error& e) { - error << "unable to execute " << args[0] << ": " << e.what (); - throw failed (); + fail << "unable to execute " << args[0] << ": " << e.what () << endf; } const string empty_string; @@ -504,8 +506,6 @@ namespace build2 return r; } - bool exception_unwinding_dtor = false; - void init (const char* a0, uint16_t v) { diff --git a/build2/variable.txx b/build2/variable.txx index 7bb30e9..7d16408 100644 --- a/build2/variable.txx +++ b/build2/variable.txx @@ -63,17 +63,13 @@ namespace build2 catch (const invalid_argument&) {} // Fall through. } - { - diag_record dr (error); - - dr << "invalid " << value_traits<T>::value_type.name - << " value '" << ns << "'"; + diag_record dr (fail); - if (var != nullptr) - dr << " in variable " << var->name; - } + dr << "invalid " << value_traits<T>::value_type.name + << " value '" << ns << "'"; - throw failed (); + if (var != nullptr) + dr << " in variable " << var->name; } template <typename T, bool empty> @@ -97,17 +93,13 @@ namespace build2 catch (const invalid_argument&) {} // Fall through. } - { - diag_record dr (error); + diag_record dr (fail); - dr << "invalid " << value_traits<T>::value_type.name - << " value '" << ns << "'"; + dr << "invalid " << value_traits<T>::value_type.name + << " value '" << ns << "'"; - if (var != nullptr) - dr << " in variable " << var->name; - } - - throw failed (); + if (var != nullptr) + dr << " in variable " << var->name; } template <typename T, bool empty> @@ -131,17 +123,13 @@ namespace build2 catch (const invalid_argument&) {} // Fall through. } - { - diag_record dr (error); - - dr << "invalid " << value_traits<T>::value_type.name - << " value '" << ns << "'"; + diag_record dr (fail); - if (var != nullptr) - dr << " in variable " << var->name; - } + dr << "invalid " << value_traits<T>::value_type.name + << " value '" << ns << "'"; - throw failed (); + if (var != nullptr) + dr << " in variable " << var->name; } template <typename T> diff --git a/unit-tests/function/driver.cxx b/unit-tests/function/driver.cxx index 192b954..6677c24 100644 --- a/unit-tests/function/driver.cxx +++ b/unit-tests/function/driver.cxx @@ -30,7 +30,7 @@ namespace build2 function_family f ("dummy"); - f["fail"] = []() {error << "failed"; throw failed ();}; + f["fail"] = []() {fail << "failed" << endf;}; f["fail_arg"] = [](names a) {return convert<uint64_t> (move (a[0]));}; f["null"] = [](names* a) {return a == nullptr;}; |