diff --git a/regression-tests/pure2-bugfix-for-runtime-invalid-alternative.cpp2 b/regression-tests/pure2-bugfix-for-runtime-invalid-alternative.cpp2 new file mode 100644 index 0000000000..6c57e7723f --- /dev/null +++ b/regression-tests/pure2-bugfix-for-runtime-invalid-alternative.cpp2 @@ -0,0 +1,7 @@ +f: (x) = { + [[assert: inspect x -> i32 { + is 1 = :() -> bool = 2;(""); + is _ = 1; + } == 1]] +} +main: () = f(1); diff --git a/regression-tests/test-results/gcc-13/gcc-version.output b/regression-tests/test-results/gcc-13/gcc-version.output new file mode 100644 index 0000000000..7bbac4c854 --- /dev/null +++ b/regression-tests/test-results/gcc-13/gcc-version.output @@ -0,0 +1,5 @@ +c++ (GCC) 13.1.1 20230429 +Copyright (C) 2023 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + diff --git a/regression-tests/test-results/gcc-13/pure2-bugfix-for-runtime-invalid-alternative.cpp.execution b/regression-tests/test-results/gcc-13/pure2-bugfix-for-runtime-invalid-alternative.cpp.execution new file mode 100644 index 0000000000..e121c2cc81 --- /dev/null +++ b/regression-tests/test-results/gcc-13/pure2-bugfix-for-runtime-invalid-alternative.cpp.execution @@ -0,0 +1,2 @@ +Type safety violation: Statement of chosen alternative is invalid. +terminate called without an active exception diff --git a/regression-tests/test-results/gcc-13/pure2-bugfix-for-runtime-invalid-alternative.cpp.output b/regression-tests/test-results/gcc-13/pure2-bugfix-for-runtime-invalid-alternative.cpp.output new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/mixed-inspect-templates.cpp b/regression-tests/test-results/mixed-inspect-templates.cpp index 9d0b42766a..9e3f481934 100644 --- a/regression-tests/test-results/mixed-inspect-templates.cpp +++ b/regression-tests/test-results/mixed-inspect-templates.cpp @@ -33,11 +33,11 @@ struct my_type {}; #line 8 "mixed-inspect-templates.cpp2" [[nodiscard]] auto fun(auto const& v) -> std::string{ return [&] () -> std::string { auto&& __expr = v; - if (cpp2::is(__expr)) { if constexpr( requires{"std::vector";} ) if constexpr( std::is_convertible_v ) return "std::vector"; else return std::string{}; else return std::string{}; } - else if (cpp2::is(__expr)) { if constexpr( requires{"std::array";} ) if constexpr( std::is_convertible_v ) return "std::array"; else return std::string{}; else return std::string{}; } - else if (cpp2::is(__expr)) { if constexpr( requires{"std::variant";} ) if constexpr( std::is_convertible_v ) return "std::variant"; else return std::string{}; else return std::string{}; } - else if (cpp2::is(__expr)) { if constexpr( requires{"my_type";} ) if constexpr( std::is_convertible_v ) return "my_type"; else return std::string{}; else return std::string{}; } - else return "unknown"; } + if (cpp2::is(__expr)) { if constexpr( requires{"std::vector";} ) if constexpr( std::is_convertible_v ) return "std::vector"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + else if (cpp2::is(__expr)) { if constexpr( requires{"std::array";} ) if constexpr( std::is_convertible_v ) return "std::array"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + else if (cpp2::is(__expr)) { if constexpr( requires{"std::variant";} ) if constexpr( std::is_convertible_v ) return "std::variant"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + else if (cpp2::is(__expr)) { if constexpr( requires{"my_type";} ) if constexpr( std::is_convertible_v ) return "my_type"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + return "unknown"; } (); } diff --git a/regression-tests/test-results/mixed-inspect-values-2.cpp b/regression-tests/test-results/mixed-inspect-values-2.cpp index 4b2cde6324..80ea46435a 100644 --- a/regression-tests/test-results/mixed-inspect-values-2.cpp +++ b/regression-tests/test-results/mixed-inspect-values-2.cpp @@ -39,9 +39,9 @@ constexpr auto empty = [](auto&& x){ auto i {15}; std::cout << [&] () -> std::string { auto&& __expr = i; - if (cpp2::is(__expr, (less_than(10)))) { if constexpr( requires{"i less than 10";} ) if constexpr( std::is_convertible_v ) return "i less than 10"; else return std::string{}; else return std::string{}; } - else if (cpp2::is(__expr, in(11, 20))) { if constexpr( requires{"i is between 11 and 20";} ) if constexpr( std::is_convertible_v ) return "i is between 11 and 20"; else return std::string{}; else return std::string{}; } - else return "i is out of our interest"; } + if (cpp2::is(__expr, (less_than(10)))) { if constexpr( requires{"i less than 10";} ) if constexpr( std::is_convertible_v ) return "i less than 10"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + else if (cpp2::is(__expr, in(11, 20))) { if constexpr( requires{"i is between 11 and 20";} ) if constexpr( std::is_convertible_v ) return "i is between 11 and 20"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + return "i is out of our interest"; } () << std::endl; if (cpp2::is(i, (less_than(20)))) { diff --git a/regression-tests/test-results/mixed-inspect-values.cpp b/regression-tests/test-results/mixed-inspect-values.cpp index d4e0430e76..587780e865 100644 --- a/regression-tests/test-results/mixed-inspect-values.cpp +++ b/regression-tests/test-results/mixed-inspect-values.cpp @@ -56,13 +56,13 @@ auto test(auto const& x) -> void; auto test(auto const& x) -> void{ auto forty_two {42}; std::cout << [&] () -> std::string { auto&& __expr = x; - if (cpp2::is(__expr, 0)) { if constexpr( requires{"zero";} ) if constexpr( std::is_convertible_v ) return "zero"; else return std::string{}; else return std::string{}; } - else if (cpp2::is(__expr, (in(1, 2)))) { if constexpr( requires{"1 or 2";} ) if constexpr( std::is_convertible_v ) return "1 or 2"; else return std::string{}; else return std::string{}; } - else if (cpp2::is(__expr, in_2_3)) { if constexpr( requires{"3";} ) if constexpr( std::is_convertible_v ) return "3"; else return std::string{}; else return std::string{}; } - else if (cpp2::is(__expr, std::move(forty_two))) { if constexpr( requires{"the answer";} ) if constexpr( std::is_convertible_v ) return "the answer"; else return std::string{}; else return std::string{}; } - else if (cpp2::is(__expr)) { if constexpr( requires{"integer " + cpp2::to_string(x);} ) if constexpr( std::is_convertible_v ) return "integer " + cpp2::to_string(x); else return std::string{}; else return std::string{}; } - else if (cpp2::is(__expr)) { if constexpr( requires{cpp2::as(x);} ) if constexpr( std::is_convertible_v(x))),std::string> ) return cpp2::as(x); else return std::string{}; else return std::string{}; } - else return "(no match)"; } + if (cpp2::is(__expr, 0)) { if constexpr( requires{"zero";} ) if constexpr( std::is_convertible_v ) return "zero"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + else if (cpp2::is(__expr, (in(1, 2)))) { if constexpr( requires{"1 or 2";} ) if constexpr( std::is_convertible_v ) return "1 or 2"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + else if (cpp2::is(__expr, in_2_3)) { if constexpr( requires{"3";} ) if constexpr( std::is_convertible_v ) return "3"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + else if (cpp2::is(__expr, std::move(forty_two))) { if constexpr( requires{"the answer";} ) if constexpr( std::is_convertible_v ) return "the answer"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + else if (cpp2::is(__expr)) { if constexpr( requires{"integer " + cpp2::to_string(x);} ) if constexpr( std::is_convertible_v ) return "integer " + cpp2::to_string(x); cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + else if (cpp2::is(__expr)) { if constexpr( requires{cpp2::as(x);} ) if constexpr( std::is_convertible_v(x))),std::string> ) return cpp2::as(x); cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + return "(no match)"; } () << "\n"; } diff --git a/regression-tests/test-results/mixed-inspect-with-typeof-of-template-arg-list.cpp b/regression-tests/test-results/mixed-inspect-with-typeof-of-template-arg-list.cpp index 9698ad3b5c..29fbb27a93 100644 --- a/regression-tests/test-results/mixed-inspect-with-typeof-of-template-arg-list.cpp +++ b/regression-tests/test-results/mixed-inspect-with-typeof-of-template-arg-list.cpp @@ -29,8 +29,8 @@ auto calc() { #line 7 "mixed-inspect-with-typeof-of-template-arg-list.cpp2" [[nodiscard]] auto fun(auto const& v) -> int{ return [&] () -> int { auto&& __expr = v; - if (cpp2::is(__expr)) { if constexpr( requires{calc<1,2>();} ) if constexpr( std::is_convertible_v())),int> ) return calc<1,2>(); else return int{}; else return int{}; } - else return 0; } + if (cpp2::is(__expr)) { if constexpr( requires{calc<1,2>();} ) if constexpr( std::is_convertible_v())),int> ) return calc<1,2>(); cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + return 0; } (); } diff --git a/regression-tests/test-results/pure2-bugfix-for-runtime-invalid-alternative.cpp b/regression-tests/test-results/pure2-bugfix-for-runtime-invalid-alternative.cpp new file mode 100644 index 0000000000..0ae68b9e62 --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-runtime-invalid-alternative.cpp @@ -0,0 +1,31 @@ + +#define CPP2_USE_MODULES Yes + +//=== Cpp2 type declarations ==================================================== + + +#include "cpp2util.h" + + + +//=== Cpp2 type definitions and function declarations =========================== + +#line 1 "pure2-bugfix-for-runtime-invalid-alternative.cpp2" +auto f(auto const& x) -> void; + + +#line 7 "pure2-bugfix-for-runtime-invalid-alternative.cpp2" +auto main() -> int; + + +//=== Cpp2 function definitions ================================================= + +#line 1 "pure2-bugfix-for-runtime-invalid-alternative.cpp2" +auto f(auto const& x) -> void{ + cpp2::Default.expects([&] () -> cpp2::i32 { auto&& __expr = x; + if (cpp2::is(__expr, 1)) { if constexpr( requires{[]() -> bool { return 2; }("");} ) if constexpr( std::is_convertible_v bool { return 2; }(""))),cpp2::i32> ) return []() -> bool { return 2; }(""); cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + return 1; } + ()==1, ""); +} +auto main() -> int { f(1); } + diff --git a/regression-tests/test-results/pure2-bugfix-for-runtime-invalid-alternative.cpp2.output b/regression-tests/test-results/pure2-bugfix-for-runtime-invalid-alternative.cpp2.output new file mode 100644 index 0000000000..fef18713a7 --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-runtime-invalid-alternative.cpp2.output @@ -0,0 +1,2 @@ +pure2-bugfix-for-runtime-invalid-alternative.cpp2... ok (all Cpp2, passes safety checks) + diff --git a/regression-tests/test-results/pure2-inspect-expression-in-generic-function-multiple-types.cpp b/regression-tests/test-results/pure2-inspect-expression-in-generic-function-multiple-types.cpp index 9fe635a1a6..a07c4c0a24 100644 --- a/regression-tests/test-results/pure2-inspect-expression-in-generic-function-multiple-types.cpp +++ b/regression-tests/test-results/pure2-inspect-expression-in-generic-function-multiple-types.cpp @@ -45,9 +45,9 @@ auto test_generic(auto const& x, auto const& msg) -> void{ << std::setw(30) << msg << " value is " << [&] () -> std::string { auto&& __expr = x; - if (cpp2::is(__expr)) { if constexpr( requires{"integer " + std::to_string(cpp2::as(x));} ) if constexpr( std::is_convertible_v(x)))),std::string> ) return "integer " + std::to_string(cpp2::as(x)); else return std::string{}; else return std::string{}; } - else if (cpp2::is(__expr)) { if constexpr( requires{'"' + cpp2::as(x) + '"';} ) if constexpr( std::is_convertible_v(x) + '"')),std::string> ) return '"' + cpp2::as(x) + '"'; else return std::string{}; else return std::string{}; } - else return "not an int or string"; } + if (cpp2::is(__expr)) { if constexpr( requires{"integer " + std::to_string(cpp2::as(x));} ) if constexpr( std::is_convertible_v(x)))),std::string> ) return "integer " + std::to_string(cpp2::as(x)); cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + else if (cpp2::is(__expr)) { if constexpr( requires{'"' + cpp2::as(x) + '"';} ) if constexpr( std::is_convertible_v(x) + '"')),std::string> ) return '"' + cpp2::as(x) + '"'; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + return "not an int or string"; } () << "\n"; } diff --git a/regression-tests/test-results/pure2-inspect-expression-with-as-in-generic-function.cpp b/regression-tests/test-results/pure2-inspect-expression-with-as-in-generic-function.cpp index 422360f099..56d7931f11 100644 --- a/regression-tests/test-results/pure2-inspect-expression-with-as-in-generic-function.cpp +++ b/regression-tests/test-results/pure2-inspect-expression-with-as-in-generic-function.cpp @@ -32,8 +32,8 @@ auto print_an_int(auto const& x) -> void{ << std::setw(30) << cpp2::to_string(x) << " value is " << [&] () -> std::string { auto&& __expr = x; - if (cpp2::is(__expr)) { if constexpr( requires{std::to_string(cpp2::as(x));} ) if constexpr( std::is_convertible_v(x)))),std::string> ) return std::to_string(cpp2::as(x)); else return std::string{}; else return std::string{}; } - else return "not an int"; } + if (cpp2::is(__expr)) { if constexpr( requires{std::to_string(cpp2::as(x));} ) if constexpr( std::is_convertible_v(x)))),std::string> ) return std::to_string(cpp2::as(x)); cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + return "not an int"; } () << "\n"; } diff --git a/regression-tests/test-results/pure2-inspect-fallback-with-variant-any-optional.cpp b/regression-tests/test-results/pure2-inspect-fallback-with-variant-any-optional.cpp index 7d7662bdcd..697af7f875 100644 --- a/regression-tests/test-results/pure2-inspect-fallback-with-variant-any-optional.cpp +++ b/regression-tests/test-results/pure2-inspect-fallback-with-variant-any-optional.cpp @@ -39,11 +39,11 @@ auto test_generic(auto const& x, auto const& msg) -> void{ std::cout << "\n" << msg << "\n ..." << [&] () -> std::string { auto&& __expr = x; - if (cpp2::is(__expr)) { if constexpr( requires{" matches std::string";} ) if constexpr( std::is_convertible_v ) return " matches std::string"; else return std::string{}; else return std::string{}; } - else if (cpp2::is>(__expr)) { if constexpr( requires{" matches std::variant";} ) if constexpr( std::is_convertible_v")),std::string> ) return " matches std::variant"; else return std::string{}; else return std::string{}; } - else if (cpp2::is(__expr)) { if constexpr( requires{" matches std::any";} ) if constexpr( std::is_convertible_v ) return " matches std::any"; else return std::string{}; else return std::string{}; } - else if (cpp2::is>(__expr)) { if constexpr( requires{" matches std::optional";} ) if constexpr( std::is_convertible_v")),std::string> ) return " matches std::optional"; else return std::string{}; else return std::string{}; } - else return " no match"; } + if (cpp2::is(__expr)) { if constexpr( requires{" matches std::string";} ) if constexpr( std::is_convertible_v ) return " matches std::string"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + else if (cpp2::is>(__expr)) { if constexpr( requires{" matches std::variant";} ) if constexpr( std::is_convertible_v")),std::string> ) return " matches std::variant"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + else if (cpp2::is(__expr)) { if constexpr( requires{" matches std::any";} ) if constexpr( std::is_convertible_v ) return " matches std::any"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + else if (cpp2::is>(__expr)) { if constexpr( requires{" matches std::optional";} ) if constexpr( std::is_convertible_v")),std::string> ) return " matches std::optional"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + return " no match"; } () << "\n"; } diff --git a/regression-tests/test-results/pure2-inspect-generic-void-empty-with-variant-any-optional.cpp b/regression-tests/test-results/pure2-inspect-generic-void-empty-with-variant-any-optional.cpp index 24cb1df600..b16391bd60 100644 --- a/regression-tests/test-results/pure2-inspect-generic-void-empty-with-variant-any-optional.cpp +++ b/regression-tests/test-results/pure2-inspect-generic-void-empty-with-variant-any-optional.cpp @@ -43,8 +43,8 @@ auto test_generic(auto const& x, auto const& msg) -> void{ std::cout << "\n" << msg << "\n ..." << [&] () -> std::string { auto&& __expr = x; - if (cpp2::is(__expr)) { if constexpr( requires{" VOYDE AND EMPTIE";} ) if constexpr( std::is_convertible_v ) return " VOYDE AND EMPTIE"; else return std::string{}; else return std::string{}; } - else return " no match"; } + if (cpp2::is(__expr)) { if constexpr( requires{" VOYDE AND EMPTIE";} ) if constexpr( std::is_convertible_v ) return " VOYDE AND EMPTIE"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + return " no match"; } () << "\n"; } diff --git a/regression-tests/test-results/pure2-type-safety-2-with-inspect-expression.cpp b/regression-tests/test-results/pure2-type-safety-2-with-inspect-expression.cpp index 4f4c83f3e8..c6557feed9 100644 --- a/regression-tests/test-results/pure2-type-safety-2-with-inspect-expression.cpp +++ b/regression-tests/test-results/pure2-type-safety-2-with-inspect-expression.cpp @@ -45,8 +45,8 @@ auto test_generic(auto const& x, auto const& msg) -> void{ << std::setw(30) << msg << " value is " << [&] () -> std::string { auto&& __expr = x; - if (cpp2::is(__expr)) { if constexpr( requires{std::to_string(cpp2::as(x));} ) if constexpr( std::is_convertible_v(x)))),std::string> ) return std::to_string(cpp2::as(x)); else return std::string{}; else return std::string{}; } - else return "not an int"; } + if (cpp2::is(__expr)) { if constexpr( requires{std::to_string(cpp2::as(x));} ) if constexpr( std::is_convertible_v(x)))),std::string> ) return std::to_string(cpp2::as(x)); cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); } + return "not an int"; } () << "\n"; } diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 382dfe122d..d3a228c122 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -1911,10 +1911,6 @@ class cppfront for (auto first = true; auto&& alt : n.alternatives) { assert(alt && alt->is_as_keyword); - if (!first) { - printer.print_cpp2("else ", alt->position()); - } - first = false; auto id = std::string{}; printer.emit_to_string(&id); @@ -1972,6 +1968,10 @@ class cppfront } } else { + if (!first) { + printer.print_cpp2("else ", alt->position()); + } + first = false; printer.print_cpp2("if " + constexpr_qualifier, alt->position()); if (alt->type_id) { printer.print_cpp2("(cpp2::is<" + id + ">(__expr)) ", alt->position()); @@ -1991,8 +1991,10 @@ class cppfront ) { assert(alt->statement->is_expression()); - printer.print_cpp2("; else return " + result_type + "{}", alt->position()); - printer.print_cpp2("; else return " + result_type + "{}", alt->position()); + printer.print_cpp2( + "; cpp2::Type.expects(false, \"Statement of chosen alternative is invalid.\")", + alt->position() + ); } printer.print_cpp2(return_suffix, alt->position());