mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +00:00
Merge branch 'master' into polysat
This commit is contained in:
commit
1df749ad33
368 changed files with 12363 additions and 6152 deletions
|
@ -78,7 +78,7 @@ typedef std::pair<symbol, sort*> sorted_var;
|
|||
/**
|
||||
\brief Command abstract class.
|
||||
|
||||
Commands may have variable number of argumets.
|
||||
Commands may have variable number of arguments.
|
||||
*/
|
||||
class cmd {
|
||||
symbol m_name;
|
||||
|
@ -87,7 +87,7 @@ protected:
|
|||
int m_pos;
|
||||
public:
|
||||
cmd(char const * n):m_name(n), m_line(0), m_pos(0) {}
|
||||
virtual ~cmd() {}
|
||||
virtual ~cmd() = default;
|
||||
virtual void reset(cmd_context & ctx) {}
|
||||
virtual void finalize(cmd_context & ctx) {}
|
||||
virtual symbol get_name() const { return m_name; }
|
||||
|
|
|
@ -28,7 +28,10 @@ void env_params::updt_params() {
|
|||
enable_warning_messages(p.get_bool("warning", true));
|
||||
memory::set_max_size(megabytes_to_bytes(p.get_uint("memory_max_size", 0)));
|
||||
memory::set_max_alloc_count(p.get_uint("memory_max_alloc_count", 0));
|
||||
memory::set_high_watermark(megabytes_to_bytes(p.get_uint("memory_high_watermark", 0)));
|
||||
memory::set_high_watermark(p.get_uint("memory_high_watermark", 0));
|
||||
unsigned mb = p.get_uint("memory_high_watermark_mb", 0);
|
||||
if (mb > 0)
|
||||
memory::set_high_watermark(megabytes_to_bytes(mb));
|
||||
}
|
||||
|
||||
void env_params::collect_param_descrs(param_descrs & d) {
|
||||
|
@ -36,5 +39,6 @@ void env_params::collect_param_descrs(param_descrs & d) {
|
|||
d.insert("warning", CPK_BOOL, "enable/disable warning messages", "true");
|
||||
d.insert("memory_max_size", CPK_UINT, "set hard upper limit for memory consumption (in megabytes), if 0 then there is no limit", "0");
|
||||
d.insert("memory_max_alloc_count", CPK_UINT, "set hard upper limit for memory allocations, if 0 then there is no limit", "0");
|
||||
d.insert("memory_high_watermark", CPK_UINT, "set high watermark for memory consumption (in megabytes), if 0 then there is no limit", "0");
|
||||
d.insert("memory_high_watermark", CPK_UINT, "set high watermark for memory consumption (in bytes), if 0 then there is no limit", "0");
|
||||
d.insert("memory_high_watermark_mb", CPK_UINT, "set high watermark for memory consumption (in megabytes), if 0 then there is no limit", "0");
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ protected:
|
|||
event_handler_caller_t m_caller_id;
|
||||
public:
|
||||
event_handler(): m_caller_id(UNSET_EH_CALLER) {}
|
||||
virtual ~event_handler() {}
|
||||
virtual ~event_handler() = default;
|
||||
virtual void operator()(event_handler_caller_t caller_id) = 0;
|
||||
event_handler_caller_t caller_id() const { return m_caller_id; }
|
||||
};
|
||||
|
|
|
@ -533,6 +533,27 @@ public:
|
|||
out << "\n";
|
||||
d->display(out, 4, false);
|
||||
}
|
||||
void display_module_markdown(std::ostream & out, char const* module_name) {
|
||||
lock_guard lock(*gparams_mux);
|
||||
param_descrs * d = nullptr;
|
||||
|
||||
if (module_name == std::string("global")) {
|
||||
out << "\n## Global Parameters\n\n";
|
||||
get_param_descrs().display_markdown(out);
|
||||
return;
|
||||
}
|
||||
if (!get_module_param_descr(module_name, d)) {
|
||||
std::stringstream strm;
|
||||
strm << "unknown module '" << module_name << "'";
|
||||
throw exception(std::move(strm).str());
|
||||
}
|
||||
out << "\n## " << module_name << "\n\n";
|
||||
char const * descr = nullptr;
|
||||
if (get_module_descrs().find(module_name, descr))
|
||||
out << descr << "\n";
|
||||
out << "\n";
|
||||
d->display_markdown(out);
|
||||
}
|
||||
|
||||
param_descrs const& get_global_param_descrs() {
|
||||
lock_guard lock(*gparams_mux);
|
||||
|
@ -643,6 +664,11 @@ void gparams::display_module(std::ostream & out, char const * module_name) {
|
|||
g_imp->display_module(out, module_name);
|
||||
}
|
||||
|
||||
void gparams::display_module_markdown(std::ostream & out, char const * module_name) {
|
||||
SASSERT(g_imp);
|
||||
g_imp->display_module_markdown(out, module_name);
|
||||
}
|
||||
|
||||
void gparams::display_parameter(std::ostream & out, char const * name) {
|
||||
SASSERT(g_imp);
|
||||
g_imp->display_parameter(out, name);
|
||||
|
|
|
@ -119,6 +119,7 @@ public:
|
|||
// Auxiliary APIs for better command line support
|
||||
static void display_modules(std::ostream & out);
|
||||
static void display_module(std::ostream & out, char const * module_name);
|
||||
static void display_module_markdown(std::ostream & out, char const * module_name);
|
||||
static void display_parameter(std::ostream & out, char const * name);
|
||||
static param_descrs const& get_global_param_descrs();
|
||||
|
||||
|
|
|
@ -13,6 +13,11 @@ Copyright (c) 2015 Microsoft Corporation
|
|||
#include "util/error_codes.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/scoped_timer.h"
|
||||
#ifdef __GLIBC__
|
||||
# include <malloc.h>
|
||||
# define HAS_MALLOC_USABLE_SIZE
|
||||
#endif
|
||||
|
||||
// The following two function are automatically generated by the mk_make.py script.
|
||||
// The script collects ADD_INITIALIZER and ADD_FINALIZER commands in the .h files.
|
||||
// For example, rational.h contains
|
||||
|
@ -215,7 +220,7 @@ void * memory::allocate(char const* file, int line, char const* obj, size_t s) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#if !defined(SINGLE_THREAD)
|
||||
#ifndef SINGLE_THREAD
|
||||
// ==================================
|
||||
// ==================================
|
||||
// THREAD LOCAL VERSION
|
||||
|
@ -258,9 +263,14 @@ static void synchronize_counters(bool allocating) {
|
|||
}
|
||||
|
||||
void memory::deallocate(void * p) {
|
||||
#ifdef HAS_MALLOC_USABLE_SIZE
|
||||
size_t sz = malloc_usable_size(p);
|
||||
void * real_p = p;
|
||||
#else
|
||||
size_t * sz_p = reinterpret_cast<size_t*>(p) - 1;
|
||||
size_t sz = *sz_p;
|
||||
void * real_p = reinterpret_cast<void*>(sz_p);
|
||||
#endif
|
||||
g_memory_thread_alloc_size -= sz;
|
||||
free(real_p);
|
||||
if (g_memory_thread_alloc_size < -SYNCH_THRESHOLD) {
|
||||
|
@ -269,28 +279,41 @@ void memory::deallocate(void * p) {
|
|||
}
|
||||
|
||||
void * memory::allocate(size_t s) {
|
||||
#ifndef HAS_MALLOC_USABLE_SIZE
|
||||
s = s + sizeof(size_t); // we allocate an extra field!
|
||||
void * r = malloc(s);
|
||||
if (r == nullptr) {
|
||||
throw_out_of_memory();
|
||||
return nullptr;
|
||||
}
|
||||
*(static_cast<size_t*>(r)) = s;
|
||||
#endif
|
||||
g_memory_thread_alloc_size += s;
|
||||
g_memory_thread_alloc_count += 1;
|
||||
if (g_memory_thread_alloc_size > SYNCH_THRESHOLD) {
|
||||
synchronize_counters(true);
|
||||
}
|
||||
|
||||
void * r = malloc(s);
|
||||
if (r == nullptr) {
|
||||
throw_out_of_memory();
|
||||
return nullptr;
|
||||
}
|
||||
#ifdef HAS_MALLOC_USABLE_SIZE
|
||||
g_memory_thread_alloc_size += malloc_usable_size(r) - s;
|
||||
return r;
|
||||
#else
|
||||
*(static_cast<size_t*>(r)) = s;
|
||||
return static_cast<size_t*>(r) + 1; // we return a pointer to the location after the extra field
|
||||
#endif
|
||||
}
|
||||
|
||||
void* memory::reallocate(void *p, size_t s) {
|
||||
#ifdef HAS_MALLOC_USABLE_SIZE
|
||||
size_t sz = malloc_usable_size(p);
|
||||
void * real_p = p;
|
||||
// We may be lucky and malloc gave us enough space
|
||||
if (sz >= s)
|
||||
return p;
|
||||
#else
|
||||
size_t *sz_p = reinterpret_cast<size_t*>(p)-1;
|
||||
size_t sz = *sz_p;
|
||||
void *real_p = reinterpret_cast<void*>(sz_p);
|
||||
s = s + sizeof(size_t); // we allocate an extra field!
|
||||
|
||||
#endif
|
||||
g_memory_thread_alloc_size += s - sz;
|
||||
g_memory_thread_alloc_count += 1;
|
||||
if (g_memory_thread_alloc_size > SYNCH_THRESHOLD) {
|
||||
|
@ -302,74 +325,97 @@ void* memory::reallocate(void *p, size_t s) {
|
|||
throw_out_of_memory();
|
||||
return nullptr;
|
||||
}
|
||||
#ifdef HAS_MALLOC_USABLE_SIZE
|
||||
g_memory_thread_alloc_size += malloc_usable_size(r) - s;
|
||||
return r;
|
||||
#else
|
||||
*(static_cast<size_t*>(r)) = s;
|
||||
return static_cast<size_t*>(r) + 1; // we return a pointer to the location after the extra field
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
// ==================================
|
||||
// ==================================
|
||||
// NO THREAD LOCAL VERSION
|
||||
// SINGLE-THREAD MODE
|
||||
// ==================================
|
||||
// ==================================
|
||||
// allocate & deallocate without using thread local storage
|
||||
// allocate & deallocate without locking
|
||||
|
||||
void memory::deallocate(void * p) {
|
||||
#ifdef HAS_MALLOC_USABLE_SIZE
|
||||
size_t sz = malloc_usable_size(p);
|
||||
void * real_p = p;
|
||||
#else
|
||||
size_t * sz_p = reinterpret_cast<size_t*>(p) - 1;
|
||||
size_t sz = *sz_p;
|
||||
void * real_p = reinterpret_cast<void*>(sz_p);
|
||||
{
|
||||
lock_guard lock(*g_memory_mux);
|
||||
g_memory_alloc_size -= sz;
|
||||
}
|
||||
#endif
|
||||
g_memory_alloc_size -= sz;
|
||||
free(real_p);
|
||||
}
|
||||
|
||||
void * memory::allocate(size_t s) {
|
||||
#ifndef HAS_MALLOC_USABLE_SIZE
|
||||
s = s + sizeof(size_t); // we allocate an extra field!
|
||||
{
|
||||
lock_guard lock(*g_memory_mux);
|
||||
g_memory_alloc_size += s;
|
||||
g_memory_alloc_count += 1;
|
||||
if (g_memory_alloc_size > g_memory_max_used_size)
|
||||
g_memory_max_used_size = g_memory_alloc_size;
|
||||
if (g_memory_max_size != 0 && g_memory_alloc_size > g_memory_max_size)
|
||||
throw_out_of_memory();
|
||||
if (g_memory_max_alloc_count != 0 && g_memory_alloc_count > g_memory_max_alloc_count)
|
||||
throw_alloc_counts_exceeded();
|
||||
}
|
||||
#endif
|
||||
g_memory_alloc_size += s;
|
||||
g_memory_alloc_count += 1;
|
||||
if (g_memory_alloc_size > g_memory_max_used_size)
|
||||
g_memory_max_used_size = g_memory_alloc_size;
|
||||
if (g_memory_max_size != 0 && g_memory_alloc_size > g_memory_max_size)
|
||||
throw_out_of_memory();
|
||||
if (g_memory_max_alloc_count != 0 && g_memory_alloc_count > g_memory_max_alloc_count)
|
||||
throw_alloc_counts_exceeded();
|
||||
|
||||
void * r = malloc(s);
|
||||
if (r == nullptr) {
|
||||
throw_out_of_memory();
|
||||
return nullptr;
|
||||
}
|
||||
#ifdef HAS_MALLOC_USABLE_SIZE
|
||||
g_memory_alloc_size += malloc_usable_size(r) - s;
|
||||
return r;
|
||||
#else
|
||||
*(static_cast<size_t*>(r)) = s;
|
||||
return static_cast<size_t*>(r) + 1; // we return a pointer to the location after the extra field
|
||||
#endif
|
||||
}
|
||||
|
||||
void* memory::reallocate(void *p, size_t s) {
|
||||
#ifdef HAS_MALLOC_USABLE_SIZE
|
||||
size_t sz = malloc_usable_size(p);
|
||||
void * real_p = p;
|
||||
// We may be lucky and malloc gave us enough space
|
||||
if (sz >= s)
|
||||
return p;
|
||||
#else
|
||||
size_t * sz_p = reinterpret_cast<size_t*>(p) - 1;
|
||||
size_t sz = *sz_p;
|
||||
void * real_p = reinterpret_cast<void*>(sz_p);
|
||||
s = s + sizeof(size_t); // we allocate an extra field!
|
||||
{
|
||||
lock_guard lock(*g_memory_mux);
|
||||
g_memory_alloc_size += s - sz;
|
||||
g_memory_alloc_count += 1;
|
||||
if (g_memory_alloc_size > g_memory_max_used_size)
|
||||
g_memory_max_used_size = g_memory_alloc_size;
|
||||
if (g_memory_max_size != 0 && g_memory_alloc_size > g_memory_max_size)
|
||||
throw_out_of_memory();
|
||||
if (g_memory_max_alloc_count != 0 && g_memory_alloc_count > g_memory_max_alloc_count)
|
||||
throw_alloc_counts_exceeded();
|
||||
}
|
||||
#endif
|
||||
g_memory_alloc_size += s - sz;
|
||||
g_memory_alloc_count += 1;
|
||||
if (g_memory_alloc_size > g_memory_max_used_size)
|
||||
g_memory_max_used_size = g_memory_alloc_size;
|
||||
if (g_memory_max_size != 0 && g_memory_alloc_size > g_memory_max_size)
|
||||
throw_out_of_memory();
|
||||
if (g_memory_max_alloc_count != 0 && g_memory_alloc_count > g_memory_max_alloc_count)
|
||||
throw_alloc_counts_exceeded();
|
||||
|
||||
void *r = realloc(real_p, s);
|
||||
if (r == nullptr) {
|
||||
throw_out_of_memory();
|
||||
return nullptr;
|
||||
}
|
||||
#ifdef HAS_MALLOC_USABLE_SIZE
|
||||
g_memory_alloc_size += malloc_usable_size(r) - s;
|
||||
return r;
|
||||
#else
|
||||
*(static_cast<size_t*>(r)) = s;
|
||||
return static_cast<size_t*>(r) + 1; // we return a pointer to the location after the extra field
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,10 +20,6 @@ Revision History:
|
|||
#include "util/warning.h"
|
||||
#include "util/z3_exception.h"
|
||||
|
||||
template<bool SYNCH>
|
||||
mpq_manager<SYNCH>::mpq_manager() {
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
mpq_manager<SYNCH>::~mpq_manager() {
|
||||
del(m_tmp1);
|
||||
|
|
|
@ -115,7 +115,7 @@ public:
|
|||
static bool precise() { return true; }
|
||||
static bool field() { return true; }
|
||||
|
||||
mpq_manager();
|
||||
mpq_manager() = default;
|
||||
|
||||
~mpq_manager();
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@ Revision History:
|
|||
|
||||
#if defined(_MP_GMP)
|
||||
// Use LEHMER only if not using GMP
|
||||
// LEHMER assumes 32-bit digits, so it cannot be used with MSBIGNUM library + 64-bit binary
|
||||
#define EUCLID_GCD
|
||||
#else
|
||||
#define LEHMER_GCD
|
||||
|
@ -50,7 +49,7 @@ Revision History:
|
|||
|
||||
#if defined(__GNUC__)
|
||||
#define _trailing_zeros32(X) __builtin_ctz(X)
|
||||
#elif defined(_WINDOWS) && !defined(_M_ARM) && !defined(_M_ARM64) && !defined(__MINGW32__)
|
||||
#elif defined(_WINDOWS) && (defined(_M_X86) || (defined(_M_X64) && !defined(_M_ARM64EC)))
|
||||
// This is needed for _tzcnt_u32 and friends.
|
||||
#include <immintrin.h>
|
||||
#define _trailing_zeros32(X) _tzcnt_u32(X)
|
||||
|
@ -62,7 +61,7 @@ static uint32_t _trailing_zeros32(uint32_t x) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#if (defined(__LP64__) || defined(_WIN64)) && !defined(_M_ARM) && !defined(_M_ARM64)
|
||||
#if (defined(__LP64__) || defined(_WIN64)) && defined(_M_X64) && !defined(_M_ARM64EC)
|
||||
#if defined(__GNUC__)
|
||||
#define _trailing_zeros64(X) __builtin_ctzll(X)
|
||||
#else
|
||||
|
|
|
@ -161,12 +161,16 @@ struct param_descrs::imp {
|
|||
bool operator()(symbol const & s1, symbol const & s2) const { return ::lt(s1, s2); }
|
||||
};
|
||||
|
||||
void display(std::ostream & out, unsigned indent, bool smt2_style, bool include_descr) const {
|
||||
void display(std::ostream & out, unsigned indent, bool smt2_style, bool include_descr, bool markdown) const {
|
||||
svector<symbol> names;
|
||||
for (auto const& kv : m_info) {
|
||||
names.push_back(kv.m_key);
|
||||
}
|
||||
std::sort(names.begin(), names.end(), symlt());
|
||||
if (markdown) {
|
||||
out << " Parameter | Type | Description | Default\n";
|
||||
out << " ----------|------|-------------|--------\n";
|
||||
}
|
||||
for (symbol const& name : names) {
|
||||
for (unsigned i = 0; i < indent; i++) out << " ";
|
||||
if (smt2_style)
|
||||
|
@ -186,10 +190,30 @@ struct param_descrs::imp {
|
|||
info d;
|
||||
m_info.find(name, d);
|
||||
SASSERT(d.m_descr);
|
||||
out << " (" << d.m_kind << ")";
|
||||
if (include_descr)
|
||||
if (markdown)
|
||||
out << " | " << d.m_kind << " ";
|
||||
else
|
||||
out << " (" << d.m_kind << ")";
|
||||
if (markdown) {
|
||||
out << " | ";
|
||||
std::string desc;
|
||||
for (auto ch : std::string(d.m_descr)) {
|
||||
switch (ch) {
|
||||
case '<': desc += "<"; break;
|
||||
case '>': desc += ">"; break;
|
||||
default: desc.push_back(ch);
|
||||
}
|
||||
}
|
||||
out << " " << desc;
|
||||
}
|
||||
else if (include_descr)
|
||||
out << " " << d.m_descr;
|
||||
if (d.m_default != nullptr)
|
||||
if (markdown) {
|
||||
out << " | ";
|
||||
if (d.m_default)
|
||||
out << d.m_default;
|
||||
}
|
||||
else if (d.m_default != nullptr)
|
||||
out << " (default: " << d.m_default << ")";
|
||||
out << "\n";
|
||||
}
|
||||
|
@ -280,7 +304,11 @@ char const* param_descrs::get_module(symbol const& name) const {
|
|||
}
|
||||
|
||||
void param_descrs::display(std::ostream & out, unsigned indent, bool smt2_style, bool include_descr) const {
|
||||
return m_imp->display(out, indent, smt2_style, include_descr);
|
||||
return m_imp->display(out, indent, smt2_style, include_descr, false);
|
||||
}
|
||||
|
||||
void param_descrs::display_markdown(std::ostream & out, bool smt2_style, bool include_descr) const {
|
||||
return m_imp->display(out, 0, smt2_style, include_descr, true);
|
||||
}
|
||||
|
||||
void insert_max_memory(param_descrs & r) {
|
||||
|
|
|
@ -130,6 +130,7 @@ public:
|
|||
char const * get_default(char const * name) const;
|
||||
char const * get_default(symbol const & name) const;
|
||||
void display(std::ostream & out, unsigned indent = 0, bool smt2_style=false, bool include_descr=true) const;
|
||||
void display_markdown(std::ostream& out, bool smt2_style = false, bool include_descr = true) const;
|
||||
unsigned size() const;
|
||||
symbol get_param_name(unsigned idx) const;
|
||||
char const * get_module(symbol const& name) const;
|
||||
|
|
|
@ -138,21 +138,15 @@ public:
|
|||
m().set(m_val, r.m_val);
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
rational & operator=(bool) {
|
||||
UNREACHABLE(); return *this;
|
||||
}
|
||||
inline rational operator*(bool r1) const {
|
||||
UNREACHABLE();
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
rational & operator=(bool) = delete;
|
||||
rational operator*(bool r1) const = delete;
|
||||
|
||||
rational & operator=(int v) {
|
||||
m().set(m_val, v);
|
||||
return *this;
|
||||
}
|
||||
rational & operator=(double v) { UNREACHABLE(); return *this; }
|
||||
rational & operator=(double v) = delete;
|
||||
|
||||
friend inline rational numerator(rational const & r) { rational result; m().get_numerator(r.m_val, result.m_val); return result; }
|
||||
|
||||
|
|
|
@ -110,12 +110,10 @@ namespace sat {
|
|||
|
||||
inline void negate(literal_vector& ls) { for (unsigned i = 0; i < ls.size(); ++i) ls[i].neg(); }
|
||||
|
||||
typedef tracked_uint_set uint_set;
|
||||
|
||||
typedef uint_set bool_var_set;
|
||||
typedef tracked_uint_set bool_var_set;
|
||||
|
||||
class literal_set {
|
||||
uint_set m_set;
|
||||
tracked_uint_set m_set;
|
||||
public:
|
||||
literal_set(literal_vector const& v) {
|
||||
for (unsigned i = 0; i < v.size(); ++i) insert(v[i]);
|
||||
|
@ -141,9 +139,9 @@ namespace sat {
|
|||
void reset() { m_set.reset(); }
|
||||
void finalize() { m_set.finalize(); }
|
||||
class iterator {
|
||||
uint_set::iterator m_it;
|
||||
tracked_uint_set::iterator m_it;
|
||||
public:
|
||||
iterator(uint_set::iterator it):m_it(it) {}
|
||||
iterator(tracked_uint_set::iterator it):m_it(it) {}
|
||||
literal operator*() const { return to_literal(*m_it); }
|
||||
iterator& operator++() { ++m_it; return *this; }
|
||||
iterator operator++(int) { iterator tmp = *this; ++m_it; return tmp; }
|
||||
|
|
|
@ -26,7 +26,7 @@ Revision History:
|
|||
|
||||
class trail {
|
||||
public:
|
||||
virtual ~trail() {}
|
||||
virtual ~trail() = default;
|
||||
virtual void undo() = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -83,6 +83,10 @@ void set_warning_stream(std::ostream* strm) {
|
|||
g_warning_stream = strm;
|
||||
}
|
||||
|
||||
std::ostream* warning_stream() {
|
||||
return g_warning_stream;
|
||||
}
|
||||
|
||||
void format2ostream(std::ostream & out, char const* msg, va_list args) {
|
||||
svector<char> buff;
|
||||
BEGIN_ERR_HANDLER();
|
||||
|
|
|
@ -28,6 +28,8 @@ void set_error_stream(std::ostream* strm);
|
|||
|
||||
void set_warning_stream(std::ostream* strm);
|
||||
|
||||
std::ostream* warning_stream();
|
||||
|
||||
void warning_msg(const char * msg, ...);
|
||||
|
||||
void format2ostream(std::ostream& out, char const* fmt, va_list args);
|
||||
|
|
|
@ -22,7 +22,7 @@ Notes:
|
|||
|
||||
class z3_exception {
|
||||
public:
|
||||
virtual ~z3_exception() {}
|
||||
virtual ~z3_exception() = default;
|
||||
virtual char const * msg() const = 0;
|
||||
virtual unsigned error_code() const;
|
||||
bool has_error_code() const;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue