aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-11-22 12:10:03 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-11-22 12:10:03 +0200
commit557269660c1d9796a7cf9e911efb9262f645e359 (patch)
tree0323bcb5a90c339fe87fcd193cf71bdcb3431c91
parentfae6cd2235c907e077dad7b5d8dc9b6d90a78a37 (diff)
Use diagnostics facility from libbutl
-rw-r--r--build2/algorithm.cxx2
-rw-r--r--build2/cc/compile.cxx3
-rw-r--r--build2/cc/guess.cxx20
-rw-r--r--build2/diagnostics213
-rw-r--r--build2/diagnostics.cxx36
-rw-r--r--build2/file.cxx9
-rw-r--r--build2/filesystem.cxx18
-rw-r--r--build2/function6
-rw-r--r--build2/function.cxx71
-rw-r--r--build2/functions-path.cxx3
-rw-r--r--build2/lexer31
-rw-r--r--build2/lexer.cxx7
-rw-r--r--build2/parser4
-rw-r--r--build2/parser.cxx3
-rw-r--r--build2/test/rule.cxx12
-rw-r--r--build2/test/script/parser.cxx21
-rw-r--r--build2/test/script/runner.cxx3
-rw-r--r--build2/types25
-rw-r--r--build2/utility46
-rw-r--r--build2/utility.cxx36
-rw-r--r--build2/variable.txx42
-rw-r--r--unit-tests/function/driver.cxx2
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;};