1 /*=============================================================================
2     Copyright (c) 2005-2007 Dan Marsden
3     Copyright (c) 2005-2007 Joel de Guzman
4     Copyright (c) 2015      John Fletcher
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 
10 #include <stdexcept>
11 #include <string>
12 
13 #include <boost/phoenix/core.hpp>
14 #include <boost/phoenix/operator.hpp>
15 #include <boost/phoenix/statement.hpp>
16 #include <boost/phoenix/scope/local_variable.hpp>
17 #include <boost/phoenix/bind/bind_member_function.hpp>
18 
19 #include <boost/detail/lightweight_test.hpp>
20 
21 struct base_exception : std::exception
22 {
23     explicit
base_exceptionbase_exception24     base_exception(char const *msg)
25         : _sliced(true), _what(msg)
26     {}
27 
base_exceptionbase_exception28     base_exception(base_exception const &other)
29         : _sliced(true), _what(other._what)
30     {
31     }
32 
whatbase_exception33     char const *what() const BOOST_NOEXCEPT_OR_NOTHROW
34     {
35         if (_sliced) { return "sliced ..."; }
36         return _what;
37     }
38 
39     bool        _sliced;
40     char const *_what;
41 };
42 
43 struct extended_exception : base_exception
44 {
45     explicit
extended_exceptionextended_exception46     extended_exception(char const *msg)
47         : base_exception(msg)
48     {
49         // mark as not sliced
50         _sliced = false;
51     }
52 
extended_exceptionextended_exception53     extended_exception(extended_exception const &other)
54         : base_exception(other)
55     {
56         // mark as not sliced
57         _sliced = false;
58     }
59 };
60 
main()61 int main()
62 {
63     using boost::phoenix::throw_;
64     using boost::phoenix::try_;
65     using boost::phoenix::ref;
66     using boost::phoenix::local_names::_e;
67     using boost::phoenix::bind;
68     using std::exception;
69     using std::string;
70     using std::runtime_error;
71     namespace phx = boost::phoenix;
72 
73     {
74         try
75         {
76             throw_(runtime_error("error"))();
77             BOOST_ERROR("exception should have been thrown");
78         }
79         catch(runtime_error& err)
80         {
81             BOOST_TEST(err.what() == string("error"));
82         }
83     }
84 
85     {
86         try
87         {
88             try
89             {
90                 throw runtime_error("error");
91             }
92             catch(exception&)
93             {
94                 throw_()();
95                 BOOST_ERROR("exception should have been rethrown");
96             }
97         }
98         catch(exception& err)
99         {
100             BOOST_TEST(err.what() == string("error"));
101         }
102     }
103 
104     {
105         bool caught_exception = false;
106 
107         try_
108         [ throw_(runtime_error("error")) ]
109         .catch_<exception>(_e) // captured but unused
110         [
111             ref(caught_exception) = true
112         ]();
113 
114         BOOST_TEST(caught_exception);
115     }
116 
117     {
118         bool caught_exception = false;
119         string what;
120 
121         try_
122         [ throw_(runtime_error("error")) ]
123         .catch_<exception>(_e)
124         [
125             ref(caught_exception) = true
126             // ambiguous with std::ref
127           , phx::ref(what) = phx::bind(&exception::what, _e)
128         ]();
129 
130         BOOST_TEST(caught_exception);
131         BOOST_TEST(what == string("error"));
132     }
133 
134     {
135         bool caught_exception = false;
136         string what;
137 
138         try_
139         [ throw_(extended_exception("error")) ]
140         .catch_<base_exception>(_e) // A thrown object should not be copied due to slicing.
141         [
142             ref(caught_exception) = true
143             // ambiguous with std::ref
144           , phx::ref(what) = phx::bind(&exception::what, _e)
145         ]();
146 
147         BOOST_TEST(caught_exception);
148         BOOST_TEST(what == string("error"));
149     }
150 
151     {
152         bool caught_exception = false;
153 
154         try_
155         [ throw_(runtime_error("error")) ]
156         .catch_all
157         [ ref(caught_exception) = true ]();
158         BOOST_TEST(caught_exception);
159     }
160 
161     {
162         bool caught_correct_exception = false;
163         string what;
164 
165         try_
166             [ throw_(runtime_error("error")) ]
167         .catch_<string>()
168             [ ref(caught_correct_exception) = false ]
169         .catch_<exception>(_e)
170         [
171             ref(caught_correct_exception) = true
172             // ambiguous with std::ref
173           , phx::ref(what) = phx::bind(&exception::what, _e)
174         ]();
175 
176         BOOST_TEST(caught_correct_exception);
177         BOOST_TEST(what == string("error"));
178     }
179 
180     {
181         bool caught_correct_exception = false;
182 
183         try_
184             [ throw_(runtime_error("error")) ]
185         .catch_<string>()
186             [ ref(caught_correct_exception) = false ]
187         .catch_all
188             [ ref(caught_correct_exception) = true]();
189 
190         BOOST_TEST(caught_correct_exception);
191     }
192 
193     return boost::report_errors();
194 }
195