Skip to content

fix(cpp1): contract check invalid alternative #491

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

Closed
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
f: (x) = {
[[assert: inspect x -> i32 {
is 1 = :() -> bool = 2;("");
is _ = 1;
} == 1]]
}
main: () = f(1);
5 changes: 5 additions & 0 deletions regression-tests/test-results/gcc-13/gcc-version.output
Original file line number Diff line number Diff line change
@@ -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.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Type safety violation: Statement of chosen alternative is invalid.
terminate called without an active exception
10 changes: 5 additions & 5 deletions regression-tests/test-results/mixed-inspect-templates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::vector>(__expr)) { if constexpr( requires{"std::vector";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("std::vector")),std::string> ) return "std::vector"; else return std::string{}; else return std::string{}; }
else if (cpp2::is<std::array>(__expr)) { if constexpr( requires{"std::array";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("std::array")),std::string> ) return "std::array"; else return std::string{}; else return std::string{}; }
else if (cpp2::is<std::variant>(__expr)) { if constexpr( requires{"std::variant";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("std::variant")),std::string> ) return "std::variant"; else return std::string{}; else return std::string{}; }
else if (cpp2::is<my_type>(__expr)) { if constexpr( requires{"my_type";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("my_type")),std::string> ) return "my_type"; else return std::string{}; else return std::string{}; }
else return "unknown"; }
if (cpp2::is<std::vector>(__expr)) { if constexpr( requires{"std::vector";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("std::vector")),std::string> ) return "std::vector"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
else if (cpp2::is<std::array>(__expr)) { if constexpr( requires{"std::array";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("std::array")),std::string> ) return "std::array"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
else if (cpp2::is<std::variant>(__expr)) { if constexpr( requires{"std::variant";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("std::variant")),std::string> ) return "std::variant"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
else if (cpp2::is<my_type>(__expr)) { if constexpr( requires{"my_type";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("my_type")),std::string> ) return "my_type"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
return "unknown"; }
();
}

Expand Down
6 changes: 3 additions & 3 deletions regression-tests/test-results/mixed-inspect-values-2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CPP2_TYPEOF(("i less than 10")),std::string> ) 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<CPP2_TYPEOF(("i is between 11 and 20")),std::string> ) 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<CPP2_TYPEOF(("i less than 10")),std::string> ) 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<CPP2_TYPEOF(("i is between 11 and 20")),std::string> ) 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)))) {
Expand Down
14 changes: 7 additions & 7 deletions regression-tests/test-results/mixed-inspect-values.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CPP2_TYPEOF(("zero")),std::string> ) 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<CPP2_TYPEOF(("1 or 2")),std::string> ) 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<CPP2_TYPEOF(("3")),std::string> ) 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<CPP2_TYPEOF(("the answer")),std::string> ) return "the answer"; else return std::string{}; else return std::string{}; }
else if (cpp2::is<int>(__expr)) { if constexpr( requires{"integer " + cpp2::to_string(x);} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("integer " + cpp2::to_string(x))),std::string> ) return "integer " + cpp2::to_string(x); else return std::string{}; else return std::string{}; }
else if (cpp2::is<std::string>(__expr)) { if constexpr( requires{cpp2::as<std::string>(x);} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((cpp2::as<std::string>(x))),std::string> ) return cpp2::as<std::string>(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<CPP2_TYPEOF(("zero")),std::string> ) 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<CPP2_TYPEOF(("1 or 2")),std::string> ) 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<CPP2_TYPEOF(("3")),std::string> ) 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<CPP2_TYPEOF(("the answer")),std::string> ) return "the answer"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
else if (cpp2::is<int>(__expr)) { if constexpr( requires{"integer " + cpp2::to_string(x);} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("integer " + cpp2::to_string(x))),std::string> ) return "integer " + cpp2::to_string(x); cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
else if (cpp2::is<std::string>(__expr)) { if constexpr( requires{cpp2::as<std::string>(x);} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((cpp2::as<std::string>(x))),std::string> ) return cpp2::as<std::string>(x); cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
return "(no match)"; }
() << "\n";
}

Original file line number Diff line number Diff line change
Expand Up @@ -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<int>(__expr)) { if constexpr( requires{calc<1,2>();} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((calc<1,2>())),int> ) return calc<1,2>(); else return int{}; else return int{}; }
else return 0; }
if (cpp2::is<int>(__expr)) { if constexpr( requires{calc<1,2>();} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((calc<1,2>())),int> ) return calc<1,2>(); cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
return 0; }
();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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<CPP2_TYPEOF(([]() -> 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); }

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pure2-bugfix-for-runtime-invalid-alternative.cpp2... ok (all Cpp2, passes safety checks)

Original file line number Diff line number Diff line change
Expand Up @@ -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<int>(__expr)) { if constexpr( requires{"integer " + std::to_string(cpp2::as<int>(x));} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("integer " + std::to_string(cpp2::as<int>(x)))),std::string> ) return "integer " + std::to_string(cpp2::as<int>(x)); else return std::string{}; else return std::string{}; }
else if (cpp2::is<std::string>(__expr)) { if constexpr( requires{'"' + cpp2::as<std::string>(x) + '"';} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(('"' + cpp2::as<std::string>(x) + '"')),std::string> ) return '"' + cpp2::as<std::string>(x) + '"'; else return std::string{}; else return std::string{}; }
else return "not an int or string"; }
if (cpp2::is<int>(__expr)) { if constexpr( requires{"integer " + std::to_string(cpp2::as<int>(x));} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(("integer " + std::to_string(cpp2::as<int>(x)))),std::string> ) return "integer " + std::to_string(cpp2::as<int>(x)); cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
else if (cpp2::is<std::string>(__expr)) { if constexpr( requires{'"' + cpp2::as<std::string>(x) + '"';} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(('"' + cpp2::as<std::string>(x) + '"')),std::string> ) return '"' + cpp2::as<std::string>(x) + '"'; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
return "not an int or string"; }
()
<< "\n";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>(__expr)) { if constexpr( requires{std::to_string(cpp2::as<int>(x));} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((std::to_string(cpp2::as<int>(x)))),std::string> ) return std::to_string(cpp2::as<int>(x)); else return std::string{}; else return std::string{}; }
else return "not an int"; }
if (cpp2::is<int>(__expr)) { if constexpr( requires{std::to_string(cpp2::as<int>(x));} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((std::to_string(cpp2::as<int>(x)))),std::string> ) return std::to_string(cpp2::as<int>(x)); cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
return "not an int"; }
()
<< "\n";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string>(__expr)) { if constexpr( requires{" matches std::string";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((" matches std::string")),std::string> ) return " matches std::string"; else return std::string{}; else return std::string{}; }
else if (cpp2::is<std::variant<int,std::string>>(__expr)) { if constexpr( requires{" matches std::variant<int, std::string>";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((" matches std::variant<int, std::string>")),std::string> ) return " matches std::variant<int, std::string>"; else return std::string{}; else return std::string{}; }
else if (cpp2::is<std::any>(__expr)) { if constexpr( requires{" matches std::any";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((" matches std::any")),std::string> ) return " matches std::any"; else return std::string{}; else return std::string{}; }
else if (cpp2::is<std::optional<std::string>>(__expr)) { if constexpr( requires{" matches std::optional<std::string>";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((" matches std::optional<std::string>")),std::string> ) return " matches std::optional<std::string>"; else return std::string{}; else return std::string{}; }
else return " no match"; }
if (cpp2::is<std::string>(__expr)) { if constexpr( requires{" matches std::string";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((" matches std::string")),std::string> ) return " matches std::string"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
else if (cpp2::is<std::variant<int,std::string>>(__expr)) { if constexpr( requires{" matches std::variant<int, std::string>";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((" matches std::variant<int, std::string>")),std::string> ) return " matches std::variant<int, std::string>"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
else if (cpp2::is<std::any>(__expr)) { if constexpr( requires{" matches std::any";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((" matches std::any")),std::string> ) return " matches std::any"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
else if (cpp2::is<std::optional<std::string>>(__expr)) { if constexpr( requires{" matches std::optional<std::string>";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((" matches std::optional<std::string>")),std::string> ) return " matches std::optional<std::string>"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
return " no match"; }
()
<< "\n";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>(__expr)) { if constexpr( requires{" VOYDE AND EMPTIE";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((" VOYDE AND EMPTIE")),std::string> ) return " VOYDE AND EMPTIE"; else return std::string{}; else return std::string{}; }
else return " no match"; }
if (cpp2::is<void>(__expr)) { if constexpr( requires{" VOYDE AND EMPTIE";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((" VOYDE AND EMPTIE")),std::string> ) return " VOYDE AND EMPTIE"; cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
return " no match"; }
()
<< "\n";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>(__expr)) { if constexpr( requires{std::to_string(cpp2::as<int>(x));} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((std::to_string(cpp2::as<int>(x)))),std::string> ) return std::to_string(cpp2::as<int>(x)); else return std::string{}; else return std::string{}; }
else return "not an int"; }
if (cpp2::is<int>(__expr)) { if constexpr( requires{std::to_string(cpp2::as<int>(x));} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((std::to_string(cpp2::as<int>(x)))),std::string> ) return std::to_string(cpp2::as<int>(x)); cpp2::Type.expects(false, "Statement of chosen alternative is invalid."); }
return "not an int"; }
()
<< "\n";
}
Expand Down
14 changes: 8 additions & 6 deletions source/cppfront.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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());
Expand All @@ -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());
Expand Down