Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++] Fix UB in <expected> related to "has value" flag (#68552) #68733

Merged
merged 28 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6944e5f
[libc++] Fix UB in <expected> related to "has value" flag (#68552)
jiixyj Oct 10, 2023
2757d11
replace home-grown constructor tags with standard ones
jiixyj Oct 15, 2023
7f1c6c7
replace use of ternary operator by explicit if/else
jiixyj Oct 15, 2023
fec6013
add a short description to the tests
jiixyj Oct 15, 2023
9977183
remove comment about memset being UB here
jiixyj Oct 15, 2023
54db802
add constructors to __union_t from expected parts and refactor
jiixyj Oct 17, 2023
6411556
put new expected<void> test into appropriate folder
jiixyj Oct 17, 2023
cd1a2b8
disable new tests on compilers that cannot build them
jiixyj Oct 17, 2023
b31c8ef
make comment in libcxx/test/std/utilities/expected/types.h more general
jiixyj Oct 17, 2023
49f59a5
spell out full path to corresponding test file
jiixyj Oct 17, 2023
84a61da
directly construct into union member instead of trying to delegate to…
jiixyj Oct 17, 2023
5f70208
remove unneeded '__empty_t' in union of non-void expected
jiixyj Oct 17, 2023
1ab8ff9
make lambdas automatic variables
jiixyj Oct 18, 2023
58c523c
rename template parameter from "c" to "constant"
jiixyj Oct 20, 2023
de8a4b4
fix build
jiixyj Oct 20, 2023
07e0258
add TailClobberer tests for expected.expected
jiixyj Oct 21, 2023
4471615
add some missing checks
jiixyj Oct 21, 2023
dd7b119
add tests for expected<void>
jiixyj Oct 21, 2023
5f5fab0
fix compile errors
jiixyj Oct 22, 2023
ebaccf9
remove declaration of local Except struct
jiixyj Oct 22, 2023
c54292e
remove more declarations of local Except structs
jiixyj Oct 22, 2023
737f6dd
just return a reference to the union value in emplace()
jiixyj Oct 27, 2023
63e4c45
use LIBCPP_STATIC_ASSERT to check size of std::expected containing a …
jiixyj Oct 27, 2023
d5c5626
add swap tests involving TailClobberer
jiixyj Oct 30, 2023
8e866c6
drive by fix: these should be free swaps
jiixyj Oct 30, 2023
c637421
make both member.swap.pass.cpp files clang-format friendly
jiixyj Oct 30, 2023
19cfd8a
try to avoid -Werror=terminate error on GCC
jiixyj Oct 30, 2023
05f7c85
use if constexpr
jiixyj Oct 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
177 changes: 82 additions & 95 deletions libcxx/include/__expected/expected.h

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ constexpr bool test() {
assert(e.value().i == 10);
}

// TailClobberer
{
std::expected<TailClobberer<0>, bool> e(std::unexpect);
auto list = {4, 5, 6};
e.emplace(list);
assert(e.has_value());
}

return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ constexpr bool test() {
assert(e.value() == 10);
}

// TailClobberer
{
std::expected<TailClobberer<0>, bool> e(std::unexpect);
e.emplace();
assert(e.has_value());
}

return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include <utility>

#include "test_macros.h"
#include "../../types.h"

// Test Constraints:
template <class T1, class Err1, class T2, class Err2>
Expand Down Expand Up @@ -161,13 +162,19 @@ constexpr bool test() {
assert(e1.error() == 5);
}

// convert TailClobberer
{
const std::expected<TailClobbererNonTrivialMove<0>, char> e1;
std::expected<TailClobberer<0>, char> e2 = e1;
assert(e2.has_value());
assert(e1.has_value());
}

return true;
}

void testException() {
#ifndef TEST_HAS_NO_EXCEPTIONS
struct Except {};

struct ThrowingInt {
ThrowingInt(int) { throw Except{}; }
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@

#include "MoveOnly.h"
#include "test_macros.h"
#include "../../types.h"

// Test Constraints:
template <class T1, class Err1, class T2, class Err2>
Expand Down Expand Up @@ -160,13 +161,19 @@ constexpr bool test() {
assert(e1.error().get() == 0);
}

// convert TailClobberer
{
std::expected<TailClobbererNonTrivialMove<0>, char> e1;
std::expected<TailClobberer<0>, char> e2 = std::move(e1);
assert(e2.has_value());
assert(e1.has_value());
}

return true;
}

void testException() {
#ifndef TEST_HAS_NO_EXCEPTIONS
struct Except {};

struct ThrowingInt {
ThrowingInt(int) { throw Except{}; }
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <utility>

#include "test_macros.h"
#include "../../types.h"

struct NonCopyable {
NonCopyable(const NonCopyable&) = delete;
Expand Down Expand Up @@ -93,13 +94,26 @@ constexpr bool test() {
assert(!e2.has_value());
assert(e2.error() == 5);
}

// copy TailClobberer as value
{
const std::expected<TailClobberer<0>, bool> e1;
auto e2 = e1;
assert(e2.has_value());
}

// copy TailClobberer as error
{
const std::expected<bool, TailClobberer<1>> e1(std::unexpect);
auto e2 = e1;
assert(!e2.has_value());
}

return true;
}

void testException() {
#ifndef TEST_HAS_NO_EXCEPTIONS
struct Except {};

struct Throwing {
Throwing() = default;
Throwing(const Throwing&) { throw Except{}; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <type_traits>

#include "test_macros.h"
#include "../../types.h"

struct NoDedefaultCtor {
NoDedefaultCtor() = delete;
Expand All @@ -45,20 +46,20 @@ constexpr void testDefaultCtor() {

template <class T>
constexpr void testTypes() {
testDefaultCtor<T, bool>();
testDefaultCtor<T, int>();
testDefaultCtor<T, NoDedefaultCtor>();
}

constexpr bool test() {
testTypes<int>();
testTypes<MyInt>();
testTypes<TailClobberer<0>>();
return true;
}

void testException() {
#ifndef TEST_HAS_NO_EXCEPTIONS
struct Except {};

struct Throwing {
Throwing() { throw Except{}; };
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include "MoveOnly.h"
#include "test_macros.h"
#include "../../types.h"

// Test Constraints:
static_assert(std::is_constructible_v<std::expected<int, int>, std::in_place_t>);
Expand Down Expand Up @@ -54,24 +55,24 @@ struct CopyOnly {
friend constexpr bool operator==(const CopyOnly& mi, int ii) { return mi.i == ii; }
};

template <class T>
template <class T, class E = int>
constexpr void testInt() {
std::expected<T, int> e(std::in_place, 5);
std::expected<T, E> e(std::in_place, 5);
assert(e.has_value());
assert(e.value() == 5);
}

template <class T>
template <class T, class E = int>
constexpr void testLValue() {
T t(5);
std::expected<T, int> e(std::in_place, t);
std::expected<T, E> e(std::in_place, t);
assert(e.has_value());
assert(e.value() == 5);
}

template <class T>
template <class T, class E = int>
constexpr void testRValue() {
std::expected<T, int> e(std::in_place, T(5));
std::expected<T, E> e(std::in_place, T(5));
assert(e.has_value());
assert(e.value() == 5);
}
Expand All @@ -80,10 +81,13 @@ constexpr bool test() {
testInt<int>();
testInt<CopyOnly>();
testInt<MoveOnly>();
testInt<TailClobberer<0>, bool>();
testLValue<int>();
testLValue<CopyOnly>();
testLValue<TailClobberer<0>, bool>();
testRValue<int>();
testRValue<MoveOnly>();
testRValue<TailClobberer<0>, bool>();

// no arg
{
Expand Down Expand Up @@ -111,8 +115,6 @@ constexpr bool test() {

void testException() {
#ifndef TEST_HAS_NO_EXCEPTIONS
struct Except {};

struct Throwing {
Throwing(int) { throw Except{}; };
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include "MoveOnly.h"
#include "test_macros.h"
#include "../../types.h"

// Test Constraints:
static_assert(
Expand Down Expand Up @@ -90,13 +91,17 @@ constexpr bool test() {
assert(m.get() == 0);
}

// TailClobberer
{
std::expected<TailClobberer<0>, bool> e(std::in_place, {1, 2, 3});
assert(e.has_value());
}

return true;
}

void testException() {
#ifndef TEST_HAS_NO_EXCEPTIONS
struct Except {};

struct Throwing {
Throwing(std::initializer_list<int>, int) { throw Except{}; };
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <utility>

#include "test_macros.h"
#include "../../types.h"

struct NonMovable {
NonMovable(NonMovable&&) = delete;
Expand Down Expand Up @@ -112,13 +113,28 @@ constexpr bool test() {
assert(e2.error() == 5);
assert(!e1.has_value());
}

// move TailClobbererNonTrivialMove as value
{
std::expected<TailClobbererNonTrivialMove<0>, bool> e1;
auto e2 = std::move(e1);
assert(e2.has_value());
assert(e1.has_value());
}

// move TailClobbererNonTrivialMove as error
{
std::expected<bool, TailClobbererNonTrivialMove<1>> e1(std::unexpect);
auto e2 = std::move(e1);
assert(!e2.has_value());
assert(!e1.has_value());
}

return true;
}

void testException() {
#ifndef TEST_HAS_NO_EXCEPTIONS
struct Except {};

struct Throwing {
Throwing() = default;
Throwing(Throwing&&) { throw Except{}; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

#include "MoveOnly.h"
#include "test_macros.h"
#include "../../types.h"

// Test Constraints:
static_assert(std::is_constructible_v<std::expected<int, int>, int>);
Expand Down Expand Up @@ -70,24 +71,24 @@ struct CopyOnly {
struct BaseError {};
struct DerivedError : BaseError {};

template <class T>
template <class T, class E = int>
constexpr void testInt() {
std::expected<T, int> e(5);
std::expected<T, E> e(5);
assert(e.has_value());
assert(e.value() == 5);
}

template <class T>
template <class T, class E = int>
constexpr void testLValue() {
T t(5);
std::expected<T, int> e(t);
std::expected<T, E> e(t);
assert(e.has_value());
assert(e.value() == 5);
}

template <class T>
template <class T, class E = int>
constexpr void testRValue() {
std::expected<T, int> e(T(5));
std::expected<T, E> e(T(5));
assert(e.has_value());
assert(e.value() == 5);
}
Expand All @@ -96,10 +97,13 @@ constexpr bool test() {
testInt<int>();
testInt<CopyOnly>();
testInt<MoveOnly>();
testInt<TailClobberer<0>, bool>();
testLValue<int>();
testLValue<CopyOnly>();
testLValue<TailClobberer<0>, bool>();
testRValue<int>();
testRValue<MoveOnly>();
testRValue<TailClobberer<0>, bool>();

// Test default template argument.
// Without it, the template parameter cannot be deduced from an initializer list
Expand Down Expand Up @@ -153,8 +157,6 @@ constexpr bool test() {

void testException() {
#ifndef TEST_HAS_NO_EXCEPTIONS
struct Except {};

struct Throwing {
Throwing(int) { throw Except{}; };
};
Expand Down