Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions include/cpp2util.h
Original file line number Diff line number Diff line change
Expand Up @@ -1488,11 +1488,15 @@ class deferred_init {
auto destroy() -> void { if (init) { t().~T(); } init = false; }

public:
using value_type = T;

constexpr deferred_init() noexcept { }
constexpr ~deferred_init() noexcept { destroy(); }
constexpr auto value() noexcept -> T& { cpp2_default.enforce(init); return t(); }

constexpr auto construct(auto&& ...args) -> void { cpp2_default.enforce(!init); new (&data) T{CPP2_FORWARD(args)...}; init = true; }

constexpr auto construct_from(auto&& factory) -> void { cpp2_default.enforce(!init); new (&data) T(CPP2_FORWARD(factory)()); init = true; }
};


Expand All @@ -1512,6 +1516,8 @@ class out {
bool called_construct_ = false;

public:
using value_type = T;

constexpr out(T* t_) noexcept : t{ t_}, has_t{true} { cpp2_default.enforce( t); }
constexpr out(deferred_init<T>* dt_) noexcept : dt{dt_}, has_t{false} { cpp2_default.enforce(dt); }
constexpr out(out<T>* ot_) noexcept : ot{ot_}, has_t{ot_->has_t} { cpp2_default.enforce(ot);
Expand Down Expand Up @@ -1561,6 +1567,33 @@ class out {
}
}

constexpr auto construct_from(auto&& factory) -> void {
if (has_t || called_construct()) {
if constexpr (requires { *t = CPP2_FORWARD(factory)(); }) {
cpp2_default.enforce( t );
*t = CPP2_FORWARD(factory)();
}
else {
cpp2_default.report_violation("attempted to copy assign, but copy assignment is not available");
}
}
else {
cpp2_default.enforce( dt );
if (dt->init) {
if constexpr (requires { dt->value() = CPP2_FORWARD(factory)(); }) {
dt->value() = CPP2_FORWARD(factory)();
}
else {
cpp2_default.report_violation("attempted to copy assign, but copy assignment is not available");
}
}
else {
dt->construct_from(CPP2_FORWARD(factory));
called_construct() = true;
}
}
}

constexpr auto value() noexcept -> T& {
if (has_t) {
cpp2_default.enforce( t );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include <cstdint>

struct S {
std::int8_t x;
std::int8_t y;
};

struct Nested {
S left;
S right;
};

inline constexpr std::int16_t constexpr_i16 = 100;
inline constexpr std::int8_t constexpr_i8 = 8;

main: () -> int = {
runtime_i8: i8 = 8;

s_good0: S = (constexpr_i16, runtime_i8);
s_good: S;
s_good = (constexpr_i16, runtime_i8);

s_reverse0: S = (runtime_i8, constexpr_i16);
s_reverse: S;
s_reverse = (runtime_i8, constexpr_i16);

s_constexpr0: S = (constexpr_i16, constexpr_i16);
s_constexpr: S;
s_constexpr = (constexpr_i16, constexpr_i16);

s_runtime0: S = (runtime_i8, runtime_i8);
s_runtime: S;
s_runtime = (runtime_i8, runtime_i8);

nested0: Nested = (
:S = (constexpr_i16, runtime_i8),
:S = (constexpr_i8, runtime_i8)
);
nested: Nested;
nested = (
:S = (constexpr_i16, runtime_i8),
:S = (constexpr_i8, runtime_i8)
);

assert(s_good0.x == 100 && s_good.y == 8);
assert(s_reverse0.x == 8 && s_reverse.y == 100);
assert(s_constexpr0.x == 100 && s_constexpr.y == 100);
assert(s_runtime0.x == 8 && s_runtime.y == 8);
assert(nested0.left.x == 100 && nested.right.y == 8);

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
value: i32 == 20;

foo: () -> i32 == 20;

add: (x: i32, y: i32) -> i32 == x + y;

main: () -> int = {
a0: i8 = value + 100;
a: i8;
a = value + 100;

b0: i8 = foo() + 100;
b: i8;
b = foo() + 100;

c0: i16 = add(value, foo()) + 100;
c: i16;
c = add(value, foo()) + 100;

local: i32 == 10;

d0: i16 = add(local, foo()) * 2 + value;
d: i16;
d = add(local, foo()) * 2 + value;

e0: std::array<i8, 3> = (value + 100, foo() + 100, add(local, foo()));
e: std::array<i8, 3>;
e = (value + 100, foo() + 100, add(local, foo()));

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
main: () -> int = {
a0: u8 = 'a';
a: u8;
a = 'a';

b0: i8 = 1;
b: i8;
b = 1;

c0: u8 = 2;
c: u8;
c = 2;

d0: i16 = 3;
d: i16;
d = 3;

e0: u16 = 4;
e: u16;
e = 4;

f0: std::array<i8, 3> = (5, 6, 7);
f: std::array<i8, 3>;
f = (5, 6, 7);

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Target type is {i8, i8}. We try every pair from:
// ce_i8, ce_i16, rt_i8, rt_i16
// = 4 x 4 = 16 combinations.
//
// Constexpr sources must appear by name in the initializer, otherwise they
// stop being constant expressions and every i16 case would fail.

ce_i8: i8 == 8;
ce_i16: i16 == 8;

try_all_combinations: (rt_i8: i8, rt_i16: i16) = {
a00: std::array<i8, 2>;
a00 = (ce_i8, ce_i8);
a01: std::array<i8, 2>;
a01 = (ce_i8, ce_i16);
a02: std::array<i8, 2>;
a02 = (ce_i8, rt_i8);
a03: std::array<i8, 2>;
a03 = (ce_i8, rt_i16); // fail: runtime i16 -> i8

a10: std::array<i8, 2>;
a10 = (ce_i16, ce_i8);
a11: std::array<i8, 2>;
a11 = (ce_i16, ce_i16);
a12: std::array<i8, 2>;
a12 = (ce_i16, rt_i8);
a13: std::array<i8, 2>;
a13 = (ce_i16, rt_i16); // fail: runtime i16 -> i8

a20: std::array<i8, 2>;
a20 = (rt_i8, ce_i8);
a21: std::array<i8, 2>;
a21 = (rt_i8, ce_i16);
a22: std::array<i8, 2>;
a22 = (rt_i8, rt_i8);
a23: std::array<i8, 2>;
a23 = (rt_i8, rt_i16); // fail: runtime i16 -> i8

a30: std::array<i8, 2>;
a30 = (rt_i16, ce_i8); // fail: runtime i16 -> i8
a31: std::array<i8, 2>;
a31 = (rt_i16, ce_i16); // fail: runtime i16 -> i8
a32: std::array<i8, 2>;
a32 = (rt_i16, rt_i8); // fail: runtime i16 -> i8
a33: std::array<i8, 2>;
a33 = (rt_i16, rt_i16); // fail: runtime i16 -> i8
}

main: () -> int = {
rt_i8: i8 = 8;
rt_i16: i16 = 8;
try_all_combinations(rt_i8, rt_i16);
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
main: () -> int = {
a0: i8 = -1;
a: i8;
a = -1;

b0: i16 = -2;
b: i16;
b = -2;

c0: std::array<i8, 3> = (-3, -4, -5);
c: std::array<i8, 3>;
c = (-3, -4, -5);

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:19:125: error: non-constant-expression cannot be narrowed from type 'cpp2::impl::in<cpp2::i16>' (aka 'const short') to 'signed char' in initializer list [-Wc++11-narrowing]
19 | a03.construct_from([&]() -> typename CPP2_TYPEOF(a03)::value_type { return typename CPP2_TYPEOF(a03)::value_type{ce_i8, rt_i16}; });// fail: runtime i16 -> i8
| ^~~~~~
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:19:125: note: insert an explicit cast to silence this issue
19 | a03.construct_from([&]() -> typename CPP2_TYPEOF(a03)::value_type { return typename CPP2_TYPEOF(a03)::value_type{ce_i8, rt_i16}; });// fail: runtime i16 -> i8
| ^~~~~~
| static_cast<signed char>( )
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:28:126: error: non-constant-expression cannot be narrowed from type 'cpp2::impl::in<cpp2::i16>' (aka 'const short') to 'signed char' in initializer list [-Wc++11-narrowing]
28 | a13.construct_from([&]() -> typename CPP2_TYPEOF(a13)::value_type { return typename CPP2_TYPEOF(a13)::value_type{ce_i16, rt_i16}; });// fail: runtime i16 -> i8
| ^~~~~~
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:28:126: note: insert an explicit cast to silence this issue
28 | a13.construct_from([&]() -> typename CPP2_TYPEOF(a13)::value_type { return typename CPP2_TYPEOF(a13)::value_type{ce_i16, rt_i16}; });// fail: runtime i16 -> i8
| ^~~~~~
| static_cast<signed char>( )
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:37:125: error: non-constant-expression cannot be narrowed from type 'cpp2::impl::in<cpp2::i16>' (aka 'const short') to 'signed char' in initializer list [-Wc++11-narrowing]
37 | a23.construct_from([&]() -> typename CPP2_TYPEOF(a23)::value_type { return typename CPP2_TYPEOF(a23)::value_type{rt_i8, rt_i16}; });// fail: runtime i16 -> i8
| ^~~~~~
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:37:125: note: insert an explicit cast to silence this issue
37 | a23.construct_from([&]() -> typename CPP2_TYPEOF(a23)::value_type { return typename CPP2_TYPEOF(a23)::value_type{rt_i8, rt_i16}; });// fail: runtime i16 -> i8
| ^~~~~~
| static_cast<signed char>( )
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:40:118: error: non-constant-expression cannot be narrowed from type 'cpp2::impl::in<cpp2::i16>' (aka 'const short') to 'signed char' in initializer list [-Wc++11-narrowing]
40 | a30.construct_from([&]() -> typename CPP2_TYPEOF(a30)::value_type { return typename CPP2_TYPEOF(a30)::value_type{rt_i16, ce_i8}; });// fail: runtime i16 -> i8
| ^~~~~~
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:40:118: note: insert an explicit cast to silence this issue
40 | a30.construct_from([&]() -> typename CPP2_TYPEOF(a30)::value_type { return typename CPP2_TYPEOF(a30)::value_type{rt_i16, ce_i8}; });// fail: runtime i16 -> i8
| ^~~~~~
| static_cast<signed char>( )
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:42:118: error: non-constant-expression cannot be narrowed from type 'cpp2::impl::in<cpp2::i16>' (aka 'const short') to 'signed char' in initializer list [-Wc++11-narrowing]
42 | a31.construct_from([&]() -> typename CPP2_TYPEOF(a31)::value_type { return typename CPP2_TYPEOF(a31)::value_type{rt_i16, ce_i16}; });// fail: runtime i16 -> i8
| ^~~~~~
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:42:118: note: insert an explicit cast to silence this issue
42 | a31.construct_from([&]() -> typename CPP2_TYPEOF(a31)::value_type { return typename CPP2_TYPEOF(a31)::value_type{rt_i16, ce_i16}; });// fail: runtime i16 -> i8
| ^~~~~~
| static_cast<signed char>( )
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:44:118: error: non-constant-expression cannot be narrowed from type 'cpp2::impl::in<cpp2::i16>' (aka 'const short') to 'signed char' in initializer list [-Wc++11-narrowing]
44 | a32.construct_from([&]() -> typename CPP2_TYPEOF(a32)::value_type { return typename CPP2_TYPEOF(a32)::value_type{rt_i16, rt_i8}; });// fail: runtime i16 -> i8
| ^~~~~~
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:44:118: note: insert an explicit cast to silence this issue
44 | a32.construct_from([&]() -> typename CPP2_TYPEOF(a32)::value_type { return typename CPP2_TYPEOF(a32)::value_type{rt_i16, rt_i8}; });// fail: runtime i16 -> i8
| ^~~~~~
| static_cast<signed char>( )
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:46:118: error: non-constant-expression cannot be narrowed from type 'cpp2::impl::in<cpp2::i16>' (aka 'const short') to 'signed char' in initializer list [-Wc++11-narrowing]
46 | a33.construct_from([&]() -> typename CPP2_TYPEOF(a33)::value_type { return typename CPP2_TYPEOF(a33)::value_type{rt_i16, rt_i16}; });// fail: runtime i16 -> i8
| ^~~~~~
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:46:118: note: insert an explicit cast to silence this issue
46 | a33.construct_from([&]() -> typename CPP2_TYPEOF(a33)::value_type { return typename CPP2_TYPEOF(a33)::value_type{rt_i16, rt_i16}; });// fail: runtime i16 -> i8
| ^~~~~~
| static_cast<signed char>( )
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:46:126: error: non-constant-expression cannot be narrowed from type 'cpp2::impl::in<cpp2::i16>' (aka 'const short') to 'signed char' in initializer list [-Wc++11-narrowing]
46 | a33.construct_from([&]() -> typename CPP2_TYPEOF(a33)::value_type { return typename CPP2_TYPEOF(a33)::value_type{rt_i16, rt_i16}; });// fail: runtime i16 -> i8
| ^~~~~~
pure2-bugfix-for-deferred-init-narrowing-matrix-error.cpp2:46:126: note: insert an explicit cast to silence this issue
46 | a33.construct_from([&]() -> typename CPP2_TYPEOF(a33)::value_type { return typename CPP2_TYPEOF(a33)::value_type{rt_i16, rt_i16}; });// fail: runtime i16 -> i8
| ^~~~~~
| static_cast<signed char>( )
8 errors generated.
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ bool flip_a_coin() {

// ... more code ...
if (flip_a_coin()) {
p.construct(&y);
p.construct_from([&]() -> typename CPP2_TYPEOF(p)::value_type { return typename CPP2_TYPEOF(p)::value_type{&y}; });
}
else {
p.construct(&x);
p.construct_from([&]() -> typename CPP2_TYPEOF(p)::value_type { return typename CPP2_TYPEOF(p)::value_type{&x}; });
}

print_and_decorate(*cpp2::impl::assert_not_null(cpp2::move(p.value())));
Expand Down
Loading