1 // Copyright (C) 2018-2021 Free Software Foundation, Inc.
2 //
3 // This file is part of the GNU ISO C++ Library.  This library is free
4 // software; you can redistribute it and/or modify it under the
5 // terms of the GNU General Public License as published by the
6 // Free Software Foundation; either version 3, or (at your option)
7 // any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 
14 // You should have received a copy of the GNU General Public License along
15 // with this library; see the file COPYING3.  If not see
16 // <http://www.gnu.org/licenses/>.
17 
18 // { dg-do run { target c++11 } }
19 
20 #include <fstream>
21 #include <locale>
22 #include <testsuite_hooks.h>
23 
24 struct E : std::runtime_error
25 {
EE26   E() : runtime_error("") { }
27 };
28 
29 struct Cvt : std::codecvt<wchar_t, char, std::mbstate_t>
30 {
CvtCvt31   explicit Cvt(size_t refs) : codecvt(refs) { }
32 
33   mutable int exceptions_thrown = 0;
34 
35 private:
36   int
do_encodingCvt37   do_encoding() const noexcept override
38   { return -1; }
39 
40   bool
do_always_noconvCvt41   do_always_noconv() const noexcept override
42   { return false; }
43 
44   result
do_unshiftCvt45   do_unshift(state_type&, char*, char*, char*&) const override
46   {
47     ++exceptions_thrown;
48     throw E();
49   }
50 };
51 
52 struct filebuf : std::basic_filebuf<wchar_t>
53 {
filebuffilebuf54   explicit filebuf(Cvt* c)
55   {
56     std::locale loc(std::locale::classic(), c);
57     imbue(loc);
58   }
59 };
60 
61 void
test01()62 test01()
63 {
64   // This facet needs to still be valid when ~basic_filebuf runs:
65   Cvt conv{1};
66   {
67     filebuf fb(&conv);
68     fb.open("output.txt", std::wios::out);
69     fb.sputn(L"x", 1);
70 
71     bool caught = false;
72     try
73     {
74       /* [filebuf.members] p7: If one of these calls throws an exception,
75        * the exception is caught and rethrown after closing the file.  */
76       fb.close();
77     }
78     catch (const E&)
79     {
80       caught = true;
81     }
82     VERIFY( conv.exceptions_thrown == 1 );
83     VERIFY( caught );
84   }
85   VERIFY( conv.exceptions_thrown == 1 );
86 }
87 
88 void
test02()89 test02()
90 {
91   // This facet needs to still be valid when ~basic_filebuf runs:
92   Cvt conv{1};
93   {
94     filebuf fb(&conv);
95     fb.open("output.txt", std::wios::out);
96     fb.sputn(L"x", 1);
97     /* [filebuf.cons] p5: If an exception occurs during the destruction
98      * of the object, including the call to close(), the exception is
99      * caught but not rethrown.  */
100   }
101   VERIFY( conv.exceptions_thrown == 1 );
102 }
103 
104 int
main()105 main()
106 {
107   test01();
108   test02();
109 }
110