Skip to content

Commit

Permalink
Merge branch 'main' into function_expression_as_index
Browse files Browse the repository at this point in the history
Signed-off-by: Johel Ernesto Guerrero Peña <johelegp@gmail.com>
  • Loading branch information
JohelEGP authored Jul 10, 2023
2 parents 6ac6dca + 52a2798 commit cf6cb03
Show file tree
Hide file tree
Showing 221 changed files with 1,105 additions and 501 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ Finally, here is a roadmap diagram I made in 2016 that is still recognizably a r

![image](https://user-images.githubusercontent.com/1801526/189503047-0b0a4f0f-c5e7-42b2-a17d-37d80bef3970.png)

I haven't updated this roadmap diagram since 2016, but it shows many of the talks and papers that have come since then from this work, and it's still a pretty up-to-date roadmap of the major parts of Cpp2. As of this writing, cppfront implements much of the top part of this roadmap, and I plan for more to follow.
I haven't updated this roadmap diagram since 2016, but it shows many of the talks and papers that have come since then from this work, and it's still a pretty up-to-date roadmap of the major parts of Cpp2. As of spring 2023, cppfront implements most of this roadmap.

I hope you enjoy reading about this personal experiment, and I hope that it might at least start a conversation about what could be possible _**within C++**_'s own evolution to make C++ 10x simpler, safer, and more toolable.

101 changes: 52 additions & 49 deletions include/cpp2util.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@
#include <type_traits>
#include <new>
#include <memory>
#include <tuple>
#include <string>
#include <string_view>
#include <vector>
Expand All @@ -216,6 +217,7 @@
#include <compare>
#include <iterator>
#include <concepts>
#include <system_error>

#ifndef CPP2_NO_EXCEPTIONS
#include <exception>
Expand Down Expand Up @@ -324,8 +326,8 @@ class contract_group {
using handler = void (*)(CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM);

constexpr contract_group (handler h = {}) : reporter(h) { }
constexpr auto set_handler(handler h) -> handler;
constexpr auto get_handler() const -> handler { return reporter; }
constexpr auto set_handler(handler h);
constexpr auto get_handler() const -> handler { return reporter; }
constexpr auto expects (bool b, CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT)
-> void { if (!b) reporter(msg CPP2_SOURCE_LOCATION_ARG); }
private:
Expand Down Expand Up @@ -373,11 +375,9 @@ auto inline Testing = contract_group(
}
);

constexpr auto contract_group::set_handler(handler h) -> handler {
constexpr auto contract_group::set_handler(handler h) {
Default.expects(h);
auto old = reporter;
reporter = h;
return old;
}


Expand Down Expand Up @@ -681,19 +681,37 @@ class out {
//
//-----------------------------------------------------------------------
//
#ifdef _MSC_VER
#if defined(_MSC_VER) && !defined(__clang_major__)
#define CPP2_FORCE_INLINE __forceinline
#define CPP2_FORCE_INLINE_LAMBDA [[msvc::forceinline]]
#define CPP2_LAMBDA_NO_DISCARD
#else
#define CPP2_FORCE_INLINE __attribute__((always_inline))
#define CPP2_FORCE_INLINE_LAMBDA __attribute__((always_inline))

#if defined(__clang_major__)
// Also check __cplusplus, only to satisfy Clang -pedantic-errors
#if __cplusplus >= 202302L && (__clang_major__ > 13 || (__clang_major__ == 13 && __clang_minor__ >= 2))
#define CPP2_LAMBDA_NO_DISCARD [[nodiscard]]
#else
#define CPP2_LAMBDA_NO_DISCARD
#endif
#elif defined(__GNUC__)
#if __GNUC__ >= 9
#define CPP2_LAMBDA_NO_DISCARD [[nodiscard]]
#else
#define CPP2_LAMBDA_NO_DISCARD
#endif
#else
#define CPP2_LAMBDA_NO_DISCARD
#endif
#endif


// Note: [&] is because a nested UFCS might be viewed as trying to capture 'this'

#define CPP2_UFCS(FUNCNAME,PARAM1,...) \
[&](auto&& obj, auto&& ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
[&] CPP2_LAMBDA_NO_DISCARD (auto&& obj, auto&& ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
if constexpr (requires{ CPP2_FORWARD(obj).FUNCNAME(CPP2_FORWARD(params)...); }) { \
return CPP2_FORWARD(obj).FUNCNAME(CPP2_FORWARD(params)...); \
} else { \
Expand All @@ -702,7 +720,7 @@ class out {
}(PARAM1, __VA_ARGS__)

#define CPP2_UFCS_0(FUNCNAME,PARAM1) \
[&](auto&& obj) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
[&] CPP2_LAMBDA_NO_DISCARD (auto&& obj) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
if constexpr (requires{ CPP2_FORWARD(obj).FUNCNAME(); }) { \
return CPP2_FORWARD(obj).FUNCNAME(); \
} else { \
Expand All @@ -713,7 +731,7 @@ class out {
#define CPP2_UFCS_REMPARENS(...) __VA_ARGS__

#define CPP2_UFCS_TEMPLATE(FUNCNAME,TEMPARGS,PARAM1,...) \
[&](auto&& obj, auto&& ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
[&] CPP2_LAMBDA_NO_DISCARD (auto&& obj, auto&& ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
if constexpr (requires{ CPP2_FORWARD(obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (CPP2_FORWARD(params)...); }) { \
return CPP2_FORWARD(obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (CPP2_FORWARD(params)...); \
} else { \
Expand All @@ -722,7 +740,7 @@ class out {
}(PARAM1, __VA_ARGS__)

#define CPP2_UFCS_TEMPLATE_0(FUNCNAME,TEMPARGS,PARAM1) \
[&](auto&& obj) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
[&] CPP2_LAMBDA_NO_DISCARD (auto&& obj) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
if constexpr (requires{ CPP2_FORWARD(obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (); }) { \
return CPP2_FORWARD(obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (); \
} else { \
Expand All @@ -734,7 +752,7 @@ class out {
// But for non-local lambdas [&] is not allowed

#define CPP2_UFCS_NONLOCAL(FUNCNAME,PARAM1,...) \
[](auto&& obj, auto&& ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
[] CPP2_LAMBDA_NO_DISCARD (auto&& obj, auto&& ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
if constexpr (requires{ CPP2_FORWARD(obj).FUNCNAME(CPP2_FORWARD(params)...); }) { \
return CPP2_FORWARD(obj).FUNCNAME(CPP2_FORWARD(params)...); \
} else { \
Expand All @@ -743,7 +761,7 @@ class out {
}(PARAM1, __VA_ARGS__)

#define CPP2_UFCS_0_NONLOCAL(FUNCNAME,PARAM1) \
[](auto&& obj) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
[] CPP2_LAMBDA_NO_DISCARD (auto&& obj) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
if constexpr (requires{ CPP2_FORWARD(obj).FUNCNAME(); }) { \
return CPP2_FORWARD(obj).FUNCNAME(); \
} else { \
Expand All @@ -752,7 +770,7 @@ class out {
}(PARAM1)

#define CPP2_UFCS_TEMPLATE_NONLOCAL(FUNCNAME,TEMPARGS,PARAM1,...) \
[](auto&& obj, auto&& ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
[] CPP2_LAMBDA_NO_DISCARD (auto&& obj, auto&& ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
if constexpr (requires{ CPP2_FORWARD(obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (CPP2_FORWARD(params)...); }) { \
return CPP2_FORWARD(obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (CPP2_FORWARD(params)...); \
} else { \
Expand All @@ -761,7 +779,7 @@ class out {
}(PARAM1, __VA_ARGS__)

#define CPP2_UFCS_TEMPLATE_0_NONLOCAL(FUNCNAME,TEMPARGS,PARAM1) \
[](auto&& obj) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
[] CPP2_LAMBDA_NO_DISCARD (auto&& obj) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
if constexpr (requires{ CPP2_FORWARD(obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (); }) { \
return CPP2_FORWARD(obj).template FUNCNAME CPP2_UFCS_REMPARENS TEMPARGS (); \
} else { \
Expand Down Expand Up @@ -1334,82 +1352,67 @@ constexpr auto as( X const& x ) -> decltype(auto)

//-----------------------------------------------------------------------
//
// A variation of GSL's final_action_success and finally to run only on success
// (based on a PR I contributed to Microsoft GSL)
// A variation of GSL's final_action_success / finally
//
// final_action_success ensures something is run at the end of a scope
// if no exception is thrown
// finally ensures something is run at the end of a scope always
//
// finally_success is a convenience function to make a final_action_success_success
// finally_success ensures something is run at the end of a scope
// if no exception is thrown
//
//-----------------------------------------------------------------------
//

template <class F>
class final_action_success
class finally_success
{
public:
explicit final_action_success(const F& ff) noexcept : f{ff} { }
explicit final_action_success(F&& ff) noexcept : f{std::move(ff)} { }
explicit finally_success(const F& ff) noexcept : f{ff} { }
explicit finally_success(F&& ff) noexcept : f{std::move(ff)} { }

~final_action_success() noexcept
~finally_success() noexcept
{
if (invoke && ecount == std::uncaught_exceptions()) {
f();
}
}

final_action_success(final_action_success&& that) noexcept
finally_success(finally_success&& that) noexcept
: f(std::move(that.f)), invoke(std::exchange(that.invoke, false))
{ }

final_action_success(final_action_success const&) = delete;
void operator= (final_action_success const&) = delete;
void operator= (final_action_success&&) = delete;
finally_success(finally_success const&) = delete;
void operator= (finally_success const&) = delete;
void operator= (finally_success&&) = delete;

private:
F f;
int ecount = std::uncaught_exceptions();
bool invoke = true;
};

[[nodiscard]] auto finally_success(auto&& f) noexcept
{
return final_action_success<CPP2_TYPEOF(f)>{CPP2_FORWARD(f)};
}


//
// Same, but clean up also on exceptional paths
//

template <class F>
class final_action
class finally
{
public:
explicit final_action(const F& ff) noexcept : f{ff} { }
explicit final_action(F&& ff) noexcept : f{std::move(ff)} { }
explicit finally(const F& ff) noexcept : f{ff} { }
explicit finally(F&& ff) noexcept : f{std::move(ff)} { }

~final_action() noexcept { f(); }
~finally() noexcept { f(); }

final_action(final_action&& that) noexcept
finally(finally&& that) noexcept
: f(std::move(that.f)), invoke(std::exchange(that.invoke, false))
{ }

final_action (final_action const&) = delete;
void operator=(final_action const&) = delete;
void operator=(final_action&&) = delete;
finally (finally const&) = delete;
void operator=(finally const&) = delete;
void operator=(finally&&) = delete;

private:
F f;
bool invoke = true;
};

[[nodiscard]] auto finally(auto&& f) noexcept
{
return final_action<CPP2_TYPEOF(f)>{CPP2_FORWARD(f)};
}


//-----------------------------------------------------------------------
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ insert_at: (where: int, val: int)
[[pre: 0 <= where && where <= vec.ssize()]]
[[post: vec.ssize() == vec.ssize()$ + 1]]
= {
vec.insert( vec.begin()+where, val );
_ = vec.insert( vec.begin()+where, val );
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
plus: const std::plus<> = ();
main: () -> int = std::plus<>()(0, 0);
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
f: <T> () requires std::regular<T> = g(T());
main: () = { }
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ main: () -> int = {
test_generic(a, "any");
test_generic(o, "optional<int>");

v.emplace<0>(1);
_ = v.emplace<0>(1);
a = 2;
o = 3;
test_generic(42, "int");
Expand Down
2 changes: 1 addition & 1 deletion regression-tests/pure2-stdio-with-raii.cpp2
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
main: () -> int = {
s: std::string = "Freddy";
myfile := cpp2::fopen("xyzzy", "w");
myfile.fprintf( "Hello %s with UFCS!", s.c_str() );
_ = myfile.fprintf( "Hello %s with UFCS!", s.c_str() );
}
4 changes: 2 additions & 2 deletions regression-tests/pure2-stdio.cpp2
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
main: () -> int = {
s: std::string = "Fred";
myfile := fopen("xyzzy", "w");
myfile.fprintf( "Hello %s with UFCS!", s.c_str() );
myfile.fclose();
_ = myfile.fprintf( "Hello %s with UFCS!", s.c_str() );
_ = myfile.fclose();
}

2 changes: 1 addition & 1 deletion regression-tests/pure2-type-safety-1.cpp2
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ main: () -> int =

std::cout << "\n";

v.emplace<1>(1);
_ = v.emplace<1>(1);
a = 2;
o = 3;
test_generic(42, "int");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ main: () -> int = {
test_generic(a, "any");
test_generic(o, "optional<int>");

v.emplace<2>(1);
_ = v.emplace<2>(1);
a = 2;
o = 3;
test_generic(42, "int");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ X: type = {
// X::exx member function description here
exx: (this, count: int) = {
// Exercise '_' anonymous objects too while we're at it
_ := finally( :()= std::cout << "leaving call to 'why((count)$)'\n"; );
_: finally = :()= std::cout << "leaving call to 'why((count)$)'\n";
if count < 5 {
py*.why( count+1 ); // use Y object from X
}
Expand Down
18 changes: 11 additions & 7 deletions regression-tests/pure2-ufcs-member-access-and-chaining.cpp2
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
main: () -> int = {
i := 42;
i.ufcs();
_ = i.ufcs();

j := fun();
j.i.ufcs();
_ = j.i.ufcs();

fun().i.ufcs();
_ = fun().i.ufcs();

k := fun().i;
k.ufcs();
_ = k.ufcs();

get_i(j).ufcs();
_ = get_i(j).ufcs();

get_i(fun()).ufcs();
_ = get_i(fun()).ufcs();

res := (42).ufcs();

(j.i).ufcs();
_ = (j.i).ufcs();

42.no_return();
}

no_return: (x: int) = { }

ufcs: (i:int) -> int = {
return i+2;
}
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

5 changes: 0 additions & 5 deletions regression-tests/test-results/gcc-10/gcc-version.output

This file was deleted.

This file was deleted.

Loading

0 comments on commit cf6cb03

Please sign in to comment.