1 #ifndef BOOST_LEAF_ERROR_HPP_INCLUDED
2 #define BOOST_LEAF_ERROR_HPP_INCLUDED
3 
4 // Copyright (c) 2018-2020 Emil Dotchevski and Reverge Studios, Inc.
5 
6 // Distributed under the Boost Software License, Version 1.0. (See accompanying
7 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 
9 #ifndef BOOST_LEAF_ENABLE_WARNINGS
10 #   if defined(__clang__)
11 #       pragma clang system_header
12 #   elif (__GNUC__*100+__GNUC_MINOR__>301)
13 #       pragma GCC system_header
14 #   elif defined(_MSC_VER)
15 #       pragma warning(push,1)
16 #   endif
17 #endif
18 
19 #include <boost/leaf/detail/function_traits.hpp>
20 #include <boost/leaf/detail/print.hpp>
21 #include <system_error>
22 #include <type_traits>
23 #include <memory>
24 #include <string>
25 
26 #if BOOST_LEAF_DIAGNOSTICS
27 #   include <sstream>
28 #   include <set>
29 #endif
30 
31 #define BOOST_LEAF_TOKEN_PASTE(x, y) x ## y
32 #define BOOST_LEAF_TOKEN_PASTE2(x, y) BOOST_LEAF_TOKEN_PASTE(x, y)
33 #define BOOST_LEAF_TMP BOOST_LEAF_TOKEN_PASTE2(boost_leaf_tmp_, __LINE__)
34 
35 #define BOOST_LEAF_ASSIGN(v,r)\
36     static_assert(::boost::leaf::is_result_type<typename std::decay<decltype(r)>::type>::value, "The BOOST_LEAF_ASSIGN macro requires a result type as the second argument");\
37     auto && BOOST_LEAF_TMP = r;\
38     if( !BOOST_LEAF_TMP )\
39         return BOOST_LEAF_TMP.error();\
40     v = std::forward<decltype(BOOST_LEAF_TMP)>(BOOST_LEAF_TMP).value()
41 
42 #define BOOST_LEAF_AUTO(v, r)\
43     BOOST_LEAF_ASSIGN(auto v, r)
44 
45 #define BOOST_LEAF_CHECK(r)\
46     {\
47         static_assert(::boost::leaf::is_result_type<typename std::decay<decltype(r)>::type>::value, "BOOST_LEAF_CHECK requires a result type");\
48         auto && BOOST_LEAF_TMP = r;\
49         if( !BOOST_LEAF_TMP )\
50             return BOOST_LEAF_TMP.error();\
51     }
52 
53 #define BOOST_LEAF_NEW_ERROR ::leaf::leaf_detail::inject_loc{__FILE__,__LINE__,__FUNCTION__}+::boost::leaf::new_error
54 
55 namespace boost { namespace leaf {
56 
57     namespace leaf_detail
58     {
59         struct inject_loc
60         {
61             char const * const file;
62             int const line;
63             char const * const fn;
64 
65             template <class T>
operator +(inject_loc loc,T && x)66             friend T operator+( inject_loc loc, T && x ) noexcept
67             {
68                 x.load_source_location_(loc.file, loc.line, loc.fn);
69                 return std::move(x);
70             }
71         };
72     }
73 
74 } }
75 
76 ////////////////////////////////////////
77 
78 #ifdef BOOST_LEAF_NO_EXCEPTIONS
79 
80 namespace boost
81 {
82     BOOST_LEAF_NORETURN void throw_exception( std::exception const & ); // user defined
83 }
84 
85 namespace boost { namespace leaf {
86 
87     template <class T>
throw_exception(T const & e)88     BOOST_LEAF_NORETURN void throw_exception( T const & e )
89     {
90         ::boost::throw_exception(e);
91     }
92 
93 } }
94 
95 #else
96 
97 namespace boost { namespace leaf {
98 
99     template <class T>
throw_exception(T const & e)100     BOOST_LEAF_NORETURN void throw_exception( T const & e )
101     {
102         throw e;
103     }
104 
105 } }
106 
107 #endif
108 
109 ////////////////////////////////////////
110 
111 #ifdef BOOST_LEAF_NO_THREADS
112 
113 #   define BOOST_LEAF_THREAD_LOCAL
114     namespace boost { namespace leaf {
115         namespace leaf_detail
116         {
117             using atomic_unsigned_int = unsigned int;
118         }
119     } }
120 
121 #else
122 
123 #   include <atomic>
124 #   include <thread>
125 #   define BOOST_LEAF_THREAD_LOCAL thread_local
126     namespace boost { namespace leaf {
127         namespace leaf_detail
128         {
129             using atomic_unsigned_int = std::atomic<unsigned int>;
130         }
131     } }
132 
133 #endif
134 
135 ////////////////////////////////////////
136 
137 namespace boost { namespace leaf {
138 
139 #if BOOST_LEAF_DIAGNOSTICS
140 
141     namespace leaf_detail
142     {
143         class e_unexpected_count
144         {
145         public:
146 
147             char const * (*first_type)();
148             int count;
149 
e_unexpected_count(char const * (* first_type)())150             BOOST_LEAF_CONSTEXPR explicit e_unexpected_count(char const * (*first_type)()) noexcept:
151                 first_type(first_type),
152                 count(1)
153             {
154             }
155 
156             template <class CharT, class Traits>
print(std::basic_ostream<CharT,Traits> & os) const157             void print( std::basic_ostream<CharT, Traits> & os ) const
158             {
159                 BOOST_LEAF_ASSERT(first_type != 0);
160                 BOOST_LEAF_ASSERT(count>0);
161                 os << "Detected ";
162                 if( count==1 )
163                     os << "1 attempt to communicate an unexpected error object";
164                 else
165                     os << count << " attempts to communicate unexpected error objects, the first one";
166                 (os << " of type " << first_type() << '\n').flush();
167             }
168         };
169 
170         template <>
171         struct diagnostic<e_unexpected_count, false, false>
172         {
173             static constexpr bool is_invisible = true;
printboost::leaf::leaf_detail::diagnostic174             BOOST_LEAF_CONSTEXPR static void print(std::ostream &, e_unexpected_count const &) noexcept { }
175         };
176 
177         class e_unexpected_info
178         {
179             std::string s_;
180             std::set<char const *(*)()> already_;
181 
182         public:
183 
e_unexpected_info()184             e_unexpected_info() noexcept
185             {
186             }
187 
188             template <class E>
add(E && e)189             void add(E && e)
190             {
191                 if( !diagnostic<E>::is_invisible && already_.insert(&type<E>).second  )
192                 {
193                     std::stringstream s;
194                     diagnostic<E>::print(s,e);
195                     (s << '\n').flush();
196                     s_ += s.str();
197                 }
198             }
199 
200             template <class CharT, class Traits>
print(std::basic_ostream<CharT,Traits> & os) const201             void print( std::basic_ostream<CharT, Traits> & os ) const
202             {
203                 os << "Unhandled error objects:\n" << s_;
204             }
205         };
206 
207         template <>
208         struct diagnostic<e_unexpected_info, false, false>
209         {
210             static constexpr bool is_invisible = true;
printboost::leaf::leaf_detail::diagnostic211             BOOST_LEAF_CONSTEXPR static void print(std::ostream &, e_unexpected_info const &) noexcept { }
212         };
213 
214         template <class=void>
215         struct tl_unexpected_enabled
216         {
217             static BOOST_LEAF_THREAD_LOCAL int counter;
218         };
219 
220         template <class T>
221         BOOST_LEAF_THREAD_LOCAL int tl_unexpected_enabled<T>::counter;
222     }
223 
224 #endif
225 
226 } }
227 
228 ////////////////////////////////////////
229 
230 namespace boost { namespace leaf {
231 
232     struct e_source_location
233     {
234         char const * const file;
235         int const line;
236         char const * const function;
237 
238         template <class CharT, class Traits>
operator <<(std::basic_ostream<CharT,Traits> & os,e_source_location const & x)239         friend std::basic_ostream<CharT, Traits> & operator<<( std::basic_ostream<CharT, Traits> & os, e_source_location const & x )
240         {
241             return os << leaf::type<e_source_location>() << ": " << x.file << '(' << x.line << ") in function " << x.function;
242         }
243     };
244 
245     ////////////////////////////////////////
246 
247     namespace leaf_detail
248     {
249         template <class E>
250         class slot;
251 
252         template <class E>
253         struct tl_slot_ptr
254         {
255             static BOOST_LEAF_THREAD_LOCAL slot<E> * p;
256         };
257 
258         template <class E>
259         BOOST_LEAF_THREAD_LOCAL slot<E> * tl_slot_ptr<E>::p;
260 
261         template <class E>
262         class slot:
263             optional<E>
264         {
265             slot( slot const & ) = delete;
266             slot & operator=( slot const & ) = delete;
267 
268             using impl = optional<E>;
269             slot<E> * * top_;
270             slot<E> * prev_;
271 
272         public:
273 
slot()274             BOOST_LEAF_CONSTEXPR slot() noexcept:
275                 top_(0)
276             {
277             }
278 
slot(slot && x)279             BOOST_LEAF_CONSTEXPR slot( slot && x ) noexcept:
280                 optional<E>(std::move(x)),
281                 top_(0)
282             {
283                 BOOST_LEAF_ASSERT(x.top_==0);
284             }
285 
activate()286             BOOST_LEAF_CONSTEXPR void activate() noexcept
287             {
288                 BOOST_LEAF_ASSERT(top_==0 || *top_!=this);
289                 top_ = &tl_slot_ptr<E>::p;
290                 prev_ = *top_;
291                 *top_ = this;
292             }
293 
deactivate()294             BOOST_LEAF_CONSTEXPR void deactivate() noexcept
295             {
296                 BOOST_LEAF_ASSERT(top_!=0 && *top_==this);
297                 *top_ = prev_;
298             }
299 
300             BOOST_LEAF_CONSTEXPR void propagate() noexcept;
301 
302             template <class CharT, class Traits>
print(std::basic_ostream<CharT,Traits> & os,int key_to_print) const303             void print( std::basic_ostream<CharT, Traits> & os, int key_to_print ) const
304             {
305                 if( !diagnostic<E>::is_invisible )
306                     if( int k = this->key() )
307                     {
308                         if( key_to_print )
309                         {
310                             if( key_to_print!=k )
311                                 return;
312                         }
313                         else
314                             os << '[' << k << ']';
315                         diagnostic<E>::print(os, value(k));
316                         (os << '\n').flush();
317                     }
318             }
319 
320             using impl::put;
321             using impl::has_value;
322             using impl::value;
323         };
324 
325 #if BOOST_LEAF_DIAGNOSTICS
326 
327         template <class E>
load_unexpected_count(int err_id)328         BOOST_LEAF_CONSTEXPR inline void load_unexpected_count( int err_id ) noexcept
329         {
330             if( slot<e_unexpected_count> * sl = tl_slot_ptr<e_unexpected_count>::p )
331                 if( e_unexpected_count * unx = sl->has_value(err_id) )
332                     ++unx->count;
333                 else
334                     sl->put(err_id, e_unexpected_count(&type<E>));
335         }
336 
337         template <class E>
load_unexpected_info(int err_id,E && e)338         BOOST_LEAF_CONSTEXPR inline void load_unexpected_info( int err_id, E && e ) noexcept
339         {
340             if( slot<e_unexpected_info> * sl = tl_slot_ptr<e_unexpected_info>::p )
341                 if( e_unexpected_info * unx = sl->has_value(err_id) )
342                     unx->add(std::forward<E>(e));
343                 else
344                     sl->put(err_id, e_unexpected_info()).add(std::forward<E>(e));
345         }
346 
347         template <class E>
load_unexpected(int err_id,E && e)348         BOOST_LEAF_CONSTEXPR inline void load_unexpected( int err_id, E && e  ) noexcept
349         {
350             load_unexpected_count<E>(err_id);
351             load_unexpected_info(err_id, std::forward<E>(e));
352         }
353 
354 #endif
355 
356         template <class E>
propagate()357         BOOST_LEAF_CONSTEXPR inline void slot<E>::propagate() noexcept
358         {
359             BOOST_LEAF_ASSERT(top_!=0 && (*top_==prev_ || *top_==this));
360             if( prev_ )
361             {
362                 impl & that_ = *prev_;
363                 if( that_.empty() )
364                 {
365                     impl & this_ = *this;
366                     that_ = std::move(this_);
367                 }
368             }
369 #if BOOST_LEAF_DIAGNOSTICS
370             else
371             {
372                 int c = tl_unexpected_enabled<>::counter;
373                 BOOST_LEAF_ASSERT(c>=0);
374                 if( c )
375                     if( int err_id = impl::key() )
376                         load_unexpected(err_id, std::move(*this).value(err_id));
377             }
378 #endif
379         }
380 
381         template <class E>
load_slot(int err_id,E && e)382         BOOST_LEAF_CONSTEXPR inline int load_slot( int err_id, E && e ) noexcept
383         {
384             static_assert(!std::is_pointer<E>::value, "Error objects of pointer types are not allowed");
385             using T = typename std::decay<E>::type;
386             BOOST_LEAF_ASSERT((err_id&3)==1);
387             if( slot<T> * p = tl_slot_ptr<T>::p )
388                 (void) p->put(err_id, std::forward<E>(e));
389 #if BOOST_LEAF_DIAGNOSTICS
390             else
391             {
392                 int c = tl_unexpected_enabled<>::counter;
393                 BOOST_LEAF_ASSERT(c>=0);
394                 if( c )
395                     load_unexpected(err_id, std::forward<E>(e));
396             }
397 #endif
398             return 0;
399         }
400 
401         template <class F>
accumulate_slot(int err_id,F && f)402         BOOST_LEAF_CONSTEXPR inline int accumulate_slot( int err_id, F && f ) noexcept
403         {
404             static_assert(function_traits<F>::arity==1, "Lambdas passed to accumulate must take a single e-type argument by reference");
405             using E = typename std::decay<fn_arg_type<F,0>>::type;
406             static_assert(!std::is_pointer<E>::value, "Error objects of pointer types are not allowed");
407             BOOST_LEAF_ASSERT((err_id&3)==1);
408             if( auto sl = tl_slot_ptr<E>::p )
409                 if( auto v = sl->has_value(err_id) )
410                     (void) std::forward<F>(f)(*v);
411                 else
412                     (void) std::forward<F>(f)(sl->put(err_id,E()));
413             return 0;
414         }
415     }
416 
417     ////////////////////////////////////////
418 
419     namespace leaf_detail
420     {
421         template <class=void>
422         struct id_factory
423         {
424             static atomic_unsigned_int counter;
425             static BOOST_LEAF_THREAD_LOCAL unsigned current_id;
426 
generate_next_idboost::leaf::leaf_detail::id_factory427             BOOST_LEAF_CONSTEXPR static unsigned generate_next_id() noexcept
428             {
429                 auto id = (counter+=4);
430                 BOOST_LEAF_ASSERT((id&3)==1);
431                 return id;
432             }
433         };
434 
435         template <class T>
436         atomic_unsigned_int id_factory<T>::counter(-3);
437 
438         template <class T>
439         BOOST_LEAF_THREAD_LOCAL unsigned id_factory<T>::current_id(0);
440 
current_id()441         inline int current_id() noexcept
442         {
443             auto id = id_factory<>::current_id;
444             BOOST_LEAF_ASSERT(id==0 || (id&3)==1);
445             return id;
446         }
447 
new_id()448         inline int new_id() noexcept
449         {
450             auto id = id_factory<>::generate_next_id();
451             return id_factory<>::current_id = id;
452         }
453     }
454 
455     ////////////////////////////////////////
456 
457     namespace leaf_detail
458     {
459         template <class T, int Arity = function_traits<T>::arity>
460         struct load_item
461         {
462             static_assert(Arity==0 || Arity==1, "If a functions is passed to new_error or load, it must take zero or one argument");
463         };
464 
465         template <class E>
466         struct load_item<E, -1>
467         {
loadboost::leaf::leaf_detail::load_item468             BOOST_LEAF_CONSTEXPR static int load( int err_id, E && e ) noexcept
469             {
470                 return load_slot(err_id, std::forward<E>(e));
471             }
472         };
473 
474         template <class F>
475         struct load_item<F, 0>
476         {
loadboost::leaf::leaf_detail::load_item477             BOOST_LEAF_CONSTEXPR static int load( int err_id, F && f ) noexcept
478             {
479                 return load_slot(err_id, std::forward<F>(f)());
480             }
481         };
482 
483         template <class F>
484         struct load_item<F, 1>
485         {
loadboost::leaf::leaf_detail::load_item486             BOOST_LEAF_CONSTEXPR static int load( int err_id, F && f ) noexcept
487             {
488                 return accumulate_slot(err_id, std::forward<F>(f));
489             }
490         };
491     }
492 
493     ////////////////////////////////////////
494 
495     namespace leaf_detail
496     {
497         class leaf_category final: public std::error_category
498         {
equivalent(int,std::error_condition const &) const499             bool equivalent( int,  std::error_condition const & ) const noexcept final override { return false; }
equivalent(std::error_code const &,int) const500             bool equivalent( std::error_code const &, int ) const noexcept final override { return false; }
name() const501             char const * name() const noexcept final override { return "LEAF error"; }
message(int condition) const502             std::string message( int condition ) const final override { return name(); }
503         public:
~leaf_category()504             ~leaf_category() noexcept final override { }
505         };
506 
507         template <class=void>
508         struct get_error_category
509         {
510             static leaf_category cat;
511         };
512 
513         template <class T>
514         leaf_category get_error_category<T>::cat;
515 
import_error_code(std::error_code const & ec)516         inline int import_error_code( std::error_code const & ec ) noexcept
517         {
518             if( int err_id = ec.value() )
519             {
520                 std::error_category const & cat = get_error_category<>::cat;
521                 if( &ec.category()==&cat )
522                 {
523                     BOOST_LEAF_ASSERT((err_id&3)==1);
524                     return (err_id&~3)|1;
525                 }
526                 else
527                 {
528                     err_id = new_id();
529                     (void) load_slot(err_id, ec);
530                     return (err_id&~3)|1;
531                 }
532             }
533             else
534                 return 0;
535         }
536     }
537 
is_error_id(std::error_code const & ec)538     inline bool is_error_id( std::error_code const & ec ) noexcept
539     {
540         bool res = (&ec.category() == &leaf_detail::get_error_category<>::cat);
541         BOOST_LEAF_ASSERT(!res || !ec.value() || ((ec.value()&3)==1));
542         return res;
543     }
544 
545     ////////////////////////////////////////
546 
547     class error_id;
548 
549     namespace leaf_detail
550     {
551         BOOST_LEAF_CONSTEXPR error_id make_error_id(int) noexcept;
552     }
553 
554     class error_id
555     {
556         friend error_id BOOST_LEAF_CONSTEXPR leaf_detail::make_error_id(int) noexcept;
557 
558         int value_;
559 
error_id(int value)560         BOOST_LEAF_CONSTEXPR explicit error_id( int value ) noexcept:
561             value_(value)
562         {
563             BOOST_LEAF_ASSERT(value_==0 || ((value_&3)==1));
564         }
565 
566     public:
567 
error_id()568         BOOST_LEAF_CONSTEXPR error_id() noexcept:
569             value_(0)
570         {
571         }
572 
error_id(std::error_code const & ec)573         error_id( std::error_code const & ec ) noexcept:
574             value_(leaf_detail::import_error_code(ec))
575         {
576             BOOST_LEAF_ASSERT(!value_ || ((value_&3)==1));
577         }
578 
579         template <class Enum>
error_id(Enum e,typename std::enable_if<std::is_error_code_enum<Enum>::value,Enum>::type * =0)580         error_id( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, Enum>::type * = 0 ) noexcept:
581             value_(leaf_detail::import_error_code(e))
582         {
583         }
584 
load() const585         BOOST_LEAF_CONSTEXPR error_id load() const noexcept
586         {
587             return *this;
588         }
589 
590         template <class... Item>
load(Item &&...item) const591         BOOST_LEAF_CONSTEXPR error_id load( Item && ... item ) const noexcept
592         {
593             if( int err_id = value() )
594             {
595                 int const unused[ ] = { 42, leaf_detail::load_item<Item>::load(err_id, std::forward<Item>(item))... };
596                 (void) unused;
597             }
598             return *this;
599         }
600 
to_error_code() const601         std::error_code to_error_code() const noexcept
602         {
603             return std::error_code(value_, leaf_detail::get_error_category<>::cat);
604         }
605 
value() const606         BOOST_LEAF_CONSTEXPR int value() const noexcept
607         {
608             if( int v = value_ )
609             {
610                 BOOST_LEAF_ASSERT((v&3)==1);
611                 return (v&~3)|1;
612             }
613             else
614                 return 0;
615         }
616 
operator bool() const617         BOOST_LEAF_CONSTEXPR explicit operator bool() const noexcept
618         {
619             return value_ != 0;
620         }
621 
operator ==(error_id a,error_id b)622         BOOST_LEAF_CONSTEXPR friend bool operator==( error_id a, error_id b ) noexcept
623         {
624             return a.value_ == b.value_;
625         }
626 
operator !=(error_id a,error_id b)627         BOOST_LEAF_CONSTEXPR friend bool operator!=( error_id a, error_id b ) noexcept
628         {
629             return !(a == b);
630         }
631 
operator <(error_id a,error_id b)632         BOOST_LEAF_CONSTEXPR friend bool operator<( error_id a, error_id b ) noexcept
633         {
634             return a.value_ < b.value_;
635         }
636 
637         template <class CharT, class Traits>
operator <<(std::basic_ostream<CharT,Traits> & os,error_id x)638         friend std::basic_ostream<CharT, Traits> & operator<<( std::basic_ostream<CharT, Traits> & os, error_id x )
639         {
640             return os << x.value_;
641         }
642 
load_source_location_(char const * file,int line,char const * function) const643         BOOST_LEAF_CONSTEXPR void load_source_location_( char const * file, int line, char const * function ) const noexcept
644         {
645             BOOST_LEAF_ASSERT(file&&*file);
646             BOOST_LEAF_ASSERT(line>0);
647             BOOST_LEAF_ASSERT(function&&*function);
648             BOOST_LEAF_ASSERT(value_);
649             (void) load(e_source_location {file,line,function});
650         }
651     };
652 
653     namespace leaf_detail
654     {
make_error_id(int err_id)655         BOOST_LEAF_CONSTEXPR inline error_id make_error_id( int err_id ) noexcept
656         {
657             BOOST_LEAF_ASSERT(err_id==0 || (err_id&3)==1);
658             return error_id((err_id&~3)|1);
659         }
660     }
661 
new_error()662     inline error_id new_error() noexcept
663     {
664         return leaf_detail::make_error_id(leaf_detail::new_id());
665     }
666 
667     template <class... Item>
new_error(Item &&...item)668     inline error_id new_error( Item && ... item ) noexcept
669     {
670         return leaf_detail::make_error_id(leaf_detail::new_id()).load(std::forward<Item>(item)...);
671     }
672 
current_error()673     inline error_id current_error() noexcept
674     {
675         return leaf_detail::make_error_id(leaf_detail::current_id());
676     }
677 
678     ////////////////////////////////////////////
679 
680     class polymorphic_context
681     {
682     protected:
683 
684         polymorphic_context() noexcept = default;
685         ~polymorphic_context() noexcept = default;
686 
687     public:
688 
689         virtual error_id propagate_captured_errors() noexcept = 0;
690         virtual void activate() noexcept = 0;
691         virtual void deactivate() noexcept = 0;
692         virtual void propagate() noexcept = 0;
693         virtual bool is_active() const noexcept = 0;
694         virtual void print( std::ostream & ) const = 0;
695         error_id captured_id_;
696     };
697 
698     using context_ptr = std::shared_ptr<polymorphic_context>;
699 
700     ////////////////////////////////////////////
701 
702     template <class Ctx>
703     class context_activator
704     {
705         context_activator( context_activator const & ) = delete;
706         context_activator & operator=( context_activator const & ) = delete;
707 
708 #if !defined(BOOST_LEAF_NO_EXCEPTIONS) && BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS
709         int const uncaught_exceptions_;
710 #endif
711         Ctx * ctx_;
712 
713     public:
714 
context_activator(Ctx & ctx)715         explicit BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE context_activator(Ctx & ctx) noexcept:
716 #if !defined(BOOST_LEAF_NO_EXCEPTIONS) && BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS
717             uncaught_exceptions_(std::uncaught_exceptions()),
718 #endif
719             ctx_(ctx.is_active() ? 0 : &ctx)
720         {
721             if( ctx_ )
722                 ctx_->activate();
723         }
724 
context_activator(context_activator && x)725         BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE context_activator( context_activator && x ) noexcept:
726 #if !defined(BOOST_LEAF_NO_EXCEPTIONS) && BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS
727             uncaught_exceptions_(x.uncaught_exceptions_),
728 #endif
729             ctx_(x.ctx_)
730         {
731             x.ctx_ = 0;
732         }
733 
~context_activator()734         BOOST_LEAF_ALWAYS_INLINE ~context_activator() noexcept
735         {
736             if( !ctx_ )
737                 return;
738             if( ctx_->is_active() )
739                 ctx_->deactivate();
740 #ifndef BOOST_LEAF_NO_EXCEPTIONS
741 #   if BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS
742             if( std::uncaught_exceptions() > uncaught_exceptions_ )
743 #   else
744             if( std::uncaught_exception() )
745 #   endif
746                 ctx_->propagate();
747 #endif
748         }
749     };
750 
751     template <class Ctx>
activate_context(Ctx & ctx)752     BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE context_activator<Ctx> activate_context(Ctx & ctx) noexcept
753     {
754         return context_activator<Ctx>(ctx);
755     }
756 
757     ////////////////////////////////////////////
758 
759     template <class R>
760     struct is_result_type: std::false_type
761     {
762     };
763 
764     template <class R>
765     struct is_result_type<R const>: is_result_type<R>
766     {
767     };
768 
769 } }
770 
771 #undef BOOST_LEAF_THREAD_LOCAL
772 
773 #endif
774