[libc++] Fix error flags and exceptions propagated from input stream operations

Summary:
Before this patch, we would only ever throw an exception if the badbit
was set on the stream. The Standard is currently very unclear on how
exceptions should be propagated and what error flags should be set by
the input stream operations. This commit changes libc++ to behave under
a different (but valid) interpretation of the Standard. This interpretation
of the Standard matches what other implementations are doing.

I will submit a paper in San Diego to clarify the Standard such that the
interpretation used in this commit (and other implementations) is the only
possible one.

PR21586
PR15949
rdar://problem/15347558

Reviewers: mclow.lists, EricWF

Subscribers: christof, dexonsmith, cfe-commits

Differential Revision: https://reviews.llvm.org/D49863

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@357531 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Louis Dionne
2019-04-02 21:43:07 +00:00
parent 5a9a7c3d4a
commit 59d894965e
42 changed files with 2505 additions and 558 deletions

View File

@@ -18,6 +18,7 @@
#include <cassert>
#include "min_allocator.h"
#include "test_macros.h"
int main(int, char**)
{
@@ -77,6 +78,85 @@ int main(int, char**)
assert(s == L" ghij");
}
#endif
#ifndef TEST_HAS_NO_EXCEPTIONS
{
std::basic_stringbuf<char> sb("hello");
std::basic_istream<char> is(&sb);
is.exceptions(std::ios_base::eofbit);
return 0;
std::basic_string<char> s;
bool threw = false;
try {
std::getline(is, s);
} catch (std::ios::failure const&) {
threw = true;
}
assert(!is.bad());
assert(!is.fail());
assert( is.eof());
assert(threw);
assert(s == "hello");
}
{
std::basic_stringbuf<wchar_t> sb(L"hello");
std::basic_istream<wchar_t> is(&sb);
is.exceptions(std::ios_base::eofbit);
std::basic_string<wchar_t> s;
bool threw = false;
try {
std::getline(is, s);
} catch (std::ios::failure const&) {
threw = true;
}
assert(!is.bad());
assert(!is.fail());
assert( is.eof());
assert(threw);
assert(s == L"hello");
}
{
std::basic_stringbuf<char> sb;
std::basic_istream<char> is(&sb);
is.exceptions(std::ios_base::failbit);
std::basic_string<char> s;
bool threw = false;
try {
std::getline(is, s);
} catch (std::ios::failure const&) {
threw = true;
}
assert(!is.bad());
assert( is.fail());
assert( is.eof());
assert(threw);
assert(s == "");
}
{
std::basic_stringbuf<wchar_t> sb;
std::basic_istream<wchar_t> is(&sb);
is.exceptions(std::ios_base::failbit);
std::basic_string<wchar_t> s;
bool threw = false;
try {
std::getline(is, s);
} catch (std::ios::failure const&) {
threw = true;
}
assert(!is.bad());
assert( is.fail());
assert( is.eof());
assert(threw);
assert(s == L"");
}
#endif // TEST_HAS_NO_EXCEPTIONS
return 0;
}

View File

@@ -18,6 +18,7 @@
#include <cassert>
#include "min_allocator.h"
#include "test_macros.h"
int main(int, char**)
{
@@ -89,6 +90,84 @@ int main(int, char**)
assert(s == L" ghij");
}
#endif
#ifndef TEST_HAS_NO_EXCEPTIONS
{
std::basic_stringbuf<char> sb("hello");
std::basic_istream<char> is(&sb);
is.exceptions(std::ios::eofbit);
return 0;
std::basic_string<char> s;
bool threw = false;
try {
std::getline(is, s, '\n');
} catch (std::ios::failure const&) {
threw = true;
}
assert(!is.bad());
assert(!is.fail());
assert( is.eof());
assert(threw);
assert(s == "hello");
}
{
std::basic_stringbuf<wchar_t> sb(L"hello");
std::basic_istream<wchar_t> is(&sb);
is.exceptions(std::ios::eofbit);
std::basic_string<wchar_t> s;
bool threw = false;
try {
std::getline(is, s, L'\n');
} catch (std::ios::failure const&) {
threw = true;
}
assert(!is.bad());
assert(!is.fail());
assert( is.eof());
assert(threw);
assert(s == L"hello");
}
{
std::basic_stringbuf<char> sb;
std::basic_istream<char> is(&sb);
is.exceptions(std::ios::failbit);
std::basic_string<char> s;
bool threw = false;
try {
std::getline(is, s, '\n');
} catch (std::ios::failure const&) {
threw = true;
}
assert(!is.bad());
assert( is.fail());
assert( is.eof());
assert(threw);
assert(s == "");
}
{
std::basic_stringbuf<wchar_t> sb;
std::basic_istream<wchar_t> is(&sb);
is.exceptions(std::ios::failbit);
std::basic_string<wchar_t> s;
bool threw = false;
try {
std::getline(is, s, L'\n');
} catch (std::ios::failure const&) {
threw = true;
}
assert(!is.bad());
assert( is.fail());
assert( is.eof());
assert(threw);
assert(s == L"");
}
#endif // TEST_HAS_NO_EXCEPTIONS
return 0;
}

View File

@@ -18,6 +18,7 @@
#include <cassert>
#include "min_allocator.h"
#include "test_macros.h"
int main(int, char**)
{
@@ -65,6 +66,44 @@ int main(int, char**)
in >> s;
assert(in.fail());
}
#ifndef TEST_HAS_NO_EXCEPTIONS
{
std::stringbuf sb;
std::istream is(&sb);
is.exceptions(std::ios::failbit);
bool threw = false;
try {
std::string s;
is >> s;
} catch (std::ios::failure const&) {
threw = true;
}
assert(!is.bad());
assert(is.fail());
assert(is.eof());
assert(threw);
}
{
std::stringbuf sb;
std::istream is(&sb);
is.exceptions(std::ios::eofbit);
bool threw = false;
try {
std::string s;
is >> s;
} catch (std::ios::failure const&) {
threw = true;
}
assert(!is.bad());
assert(is.fail());
assert(is.eof());
assert(threw);
}
#endif // TEST_HAS_NO_EXCEPTIONS
#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;