diff --git a/regression-tests/pure2-bugfix-for-explicit-converting-assignment.cpp2 b/regression-tests/pure2-bugfix-for-explicit-converting-assignment.cpp2 new file mode 100644 index 0000000000..6952372011 --- /dev/null +++ b/regression-tests/pure2-bugfix-for-explicit-converting-assignment.cpp2 @@ -0,0 +1,10 @@ +quantity: type = { + value: int = (); + operator=: (out this, val: int) = { value = val; } +} + +main: () = { + x := quantity(0); + static_assert(!std::is_assignable_v); + _ = x; +} diff --git a/regression-tests/pure2-defaulted-comparisons-and-final-types.cpp2 b/regression-tests/pure2-defaulted-comparisons-and-final-types.cpp2 index 9ca90c7588..0cfc08bd54 100644 --- a/regression-tests/pure2-defaulted-comparisons-and-final-types.cpp2 +++ b/regression-tests/pure2-defaulted-comparisons-and-final-types.cpp2 @@ -3,7 +3,7 @@ widget: final type = { v: int; - operator=: (out this, value: int) = { v = value; } + operator=: (implicit out this, value: int) = { v = value; } operator==: (this, that) -> bool; diff --git a/regression-tests/pure2-types-basics.cpp2 b/regression-tests/pure2-types-basics.cpp2 index b9416943d8..2c9cabbfbc 100644 --- a/regression-tests/pure2-types-basics.cpp2 +++ b/regression-tests/pure2-types-basics.cpp2 @@ -10,7 +10,7 @@ myclass : type = { print(); } - operator=: (out this, s: std::string) = { + operator=: (implicit out this, s: std::string) = { this.data = 99; this.more = s; std::cout << "myclass: explicit from string\n"; diff --git a/regression-tests/pure2-types-smf-and-that-1-provide-everything.cpp2 b/regression-tests/pure2-types-smf-and-that-1-provide-everything.cpp2 index 7972b1fe3f..5623ea3f36 100644 --- a/regression-tests/pure2-types-smf-and-that-1-provide-everything.cpp2 +++ b/regression-tests/pure2-types-smf-and-that-1-provide-everything.cpp2 @@ -19,7 +19,7 @@ myclass : type = { std::cout << "assign - move "; } - operator=: (out this, x: std::string) = { + operator=: (implicit out this, x: std::string) = { name = x; std::cout << "ctor - from string "; } diff --git a/regression-tests/pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2 b/regression-tests/pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2 index 8432d75601..e803ca32c7 100644 --- a/regression-tests/pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2 +++ b/regression-tests/pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2 @@ -19,7 +19,7 @@ myclass : type = { // std::cout << "assign - move "; // } - operator=: (out this, x: std::string) = { + operator=: (implicit out this, x: std::string) = { name = x; std::cout << "ctor - from string "; } diff --git a/regression-tests/pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2 b/regression-tests/pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2 index 192f92185a..358be54761 100644 --- a/regression-tests/pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2 +++ b/regression-tests/pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2 @@ -19,7 +19,7 @@ myclass : type = { std::cout << "assign - move "; } - operator=: (out this, x: std::string) = { + operator=: (implicit out this, x: std::string) = { name = x; std::cout << "ctor - from string "; } diff --git a/regression-tests/pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2 b/regression-tests/pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2 index 87d2c048b9..688c6fe48b 100644 --- a/regression-tests/pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2 +++ b/regression-tests/pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2 @@ -19,7 +19,7 @@ myclass : type = { std::cout << "assign - move "; } - operator=: (out this, x: std::string) = { + operator=: (implicit out this, x: std::string) = { name = x; std::cout << "ctor - from string "; } diff --git a/regression-tests/pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2 b/regression-tests/pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2 index 4d4bd6585f..9eaf844e3d 100644 --- a/regression-tests/pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2 +++ b/regression-tests/pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2 @@ -19,7 +19,7 @@ myclass : type = { // std::cout << "assign - move "; // } - operator=: (out this, x: std::string) = { + operator=: (implicit out this, x: std::string) = { name = x; std::cout << "ctor - from string "; } diff --git a/regression-tests/test-results/gcc-13/pure2-bugfix-for-explicit-converting-assignment.cpp.execution b/regression-tests/test-results/gcc-13/pure2-bugfix-for-explicit-converting-assignment.cpp.execution new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/gcc-13/pure2-bugfix-for-explicit-converting-assignment.cpp.output b/regression-tests/test-results/gcc-13/pure2-bugfix-for-explicit-converting-assignment.cpp.output new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/pure2-bugfix-for-explicit-converting-assignment.cpp b/regression-tests/test-results/pure2-bugfix-for-explicit-converting-assignment.cpp new file mode 100644 index 0000000000..e596ce95d4 --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-explicit-converting-assignment.cpp @@ -0,0 +1,43 @@ + +#define CPP2_USE_MODULES Yes + +//=== Cpp2 type declarations ==================================================== + + +#include "cpp2util.h" + +#line 1 "pure2-bugfix-for-explicit-converting-assignment.cpp2" +class quantity; + + +//=== Cpp2 type definitions and function declarations =========================== + +#line 1 "pure2-bugfix-for-explicit-converting-assignment.cpp2" +class quantity { + private: int value {}; + public: explicit quantity(cpp2::in val); + + public: quantity(quantity const&) = delete; /* No 'that' constructor, suppress copy */ + public: auto operator=(quantity const&) -> void = delete; +#line 4 "pure2-bugfix-for-explicit-converting-assignment.cpp2" +}; + +auto main() -> int; + + +//=== Cpp2 function definitions ================================================= + + +#line 3 "pure2-bugfix-for-explicit-converting-assignment.cpp2" + quantity::quantity(cpp2::in val) + : value{ val } +#line 3 "pure2-bugfix-for-explicit-converting-assignment.cpp2" + {} + +#line 6 "pure2-bugfix-for-explicit-converting-assignment.cpp2" +auto main() -> int{ + auto x {quantity(0)}; + static_assert(!(std::is_assignable_v)); + (void) std::move(x); +} + diff --git a/regression-tests/test-results/pure2-bugfix-for-explicit-converting-assignment.cpp2.output b/regression-tests/test-results/pure2-bugfix-for-explicit-converting-assignment.cpp2.output new file mode 100644 index 0000000000..3b7fb023cb --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-explicit-converting-assignment.cpp2.output @@ -0,0 +1,2 @@ +pure2-bugfix-for-explicit-converting-assignment.cpp2... ok (all Cpp2, passes safety checks) + diff --git a/regression-tests/test-results/pure2-defaulted-comparisons-and-final-types.cpp b/regression-tests/test-results/pure2-defaulted-comparisons-and-final-types.cpp index 2a922effac..a424ea2039 100644 --- a/regression-tests/test-results/pure2-defaulted-comparisons-and-final-types.cpp +++ b/regression-tests/test-results/pure2-defaulted-comparisons-and-final-types.cpp @@ -19,7 +19,7 @@ class widget final { private: int v; - public: explicit widget(cpp2::in value); + public: widget(cpp2::in value); #line 6 "pure2-defaulted-comparisons-and-final-types.cpp2" public: auto operator=(cpp2::in value) -> widget& ; @@ -40,13 +40,13 @@ auto main() -> int; #line 6 "pure2-defaulted-comparisons-and-final-types.cpp2" widget::widget(cpp2::in value) - : v{ value } + : v{ value } #line 6 "pure2-defaulted-comparisons-and-final-types.cpp2" {} #line 6 "pure2-defaulted-comparisons-and-final-types.cpp2" auto widget::operator=(cpp2::in value) -> widget& { - v = value; - return *this; + v = value; + return *this; #line 6 "pure2-defaulted-comparisons-and-final-types.cpp2" } diff --git a/regression-tests/test-results/pure2-types-basics.cpp b/regression-tests/test-results/pure2-types-basics.cpp index 3429feb0f9..52a52c217f 100644 --- a/regression-tests/test-results/pure2-types-basics.cpp +++ b/regression-tests/test-results/pure2-types-basics.cpp @@ -31,7 +31,7 @@ class myclass { #line 13 "pure2-types-basics.cpp2" - public: explicit myclass(cpp2::in s); + public: myclass(cpp2::in s); #line 13 "pure2-types-basics.cpp2" public: auto operator=(cpp2::in s) -> myclass& ; diff --git a/regression-tests/test-results/pure2-types-order-independence-and-nesting.cpp b/regression-tests/test-results/pure2-types-order-independence-and-nesting.cpp index 2020cd3b22..0edd7eb4f7 100644 --- a/regression-tests/test-results/pure2-types-order-independence-and-nesting.cpp +++ b/regression-tests/test-results/pure2-types-order-independence-and-nesting.cpp @@ -45,9 +45,6 @@ class X { // Note: A constructor with an 'out' parameter public: explicit X(cpp2::out y); -#line 10 "pure2-types-order-independence-and-nesting.cpp2" - public: auto operator=(cpp2::out y) -> X& ; - #line 34 "pure2-types-order-independence-and-nesting.cpp2" // X::exx member function description here @@ -66,8 +63,6 @@ class Y { private: X* px; public: explicit Y(X* x); -#line 49 "pure2-types-order-independence-and-nesting.cpp2" - public: auto operator=(X* x) -> Y& ; public: auto why(cpp2::in count) const -> void; @@ -139,16 +134,6 @@ namespace N { // then do anything else the constructor wants to do std::cout << "made a safely initialized cycle\n"; } -#line 10 "pure2-types-order-independence-and-nesting.cpp2" - auto X::operator=(cpp2::out y) -> X& { - y.construct(&(*this)); - py = &y.value(); - -#line 31 "pure2-types-order-independence-and-nesting.cpp2" - std::cout << "made a safely initialized cycle\n"; - return *this; -#line 32 "pure2-types-order-independence-and-nesting.cpp2" - } #line 35 "pure2-types-order-independence-and-nesting.cpp2" auto X::exx(cpp2::in count) const -> void{ @@ -164,12 +149,6 @@ namespace N { : px{ x } #line 49 "pure2-types-order-independence-and-nesting.cpp2" { } -#line 49 "pure2-types-order-independence-and-nesting.cpp2" - auto Y::operator=(X* x) -> Y& { - px = x; - return *this; -#line 49 "pure2-types-order-independence-and-nesting.cpp2" - } auto Y::why(cpp2::in count) const -> void { CPP2_UFCS(exx, (*cpp2::assert_not_null(px)), count + 1); }// use X object from Y diff --git a/regression-tests/test-results/pure2-types-ordering-via-meta-functions.cpp b/regression-tests/test-results/pure2-types-ordering-via-meta-functions.cpp index 9f035f55b2..55242c16c1 100644 --- a/regression-tests/test-results/pure2-types-ordering-via-meta-functions.cpp +++ b/regression-tests/test-results/pure2-types-ordering-via-meta-functions.cpp @@ -30,8 +30,6 @@ class mystruct; class my_integer { private: int v; public: explicit my_integer(cpp2::in val); -#line 4 "pure2-types-ordering-via-meta-functions.cpp2" - public: auto operator=(cpp2::in val) -> my_integer& ; public: [[nodiscard]] auto operator<=>(my_integer const& that) const -> std::strong_ordering = default; @@ -43,8 +41,6 @@ public: [[nodiscard]] auto operator<=>(my_integer const& that) const -> std::str class case_insensitive_string { private: std::string v; // case insensitive public: explicit case_insensitive_string(cpp2::in val); -#line 9 "pure2-types-ordering-via-meta-functions.cpp2" - public: auto operator=(cpp2::in val) -> case_insensitive_string& ; public: [[nodiscard]] auto operator<=>(case_insensitive_string const& that) const -> std::weak_ordering = default; @@ -56,8 +52,6 @@ public: [[nodiscard]] auto operator<=>(case_insensitive_string const& that) cons class person_in_family_tree { private: int dummy_data; public: explicit person_in_family_tree(cpp2::in parents); -#line 14 "pure2-types-ordering-via-meta-functions.cpp2" - public: auto operator=(cpp2::in parents) -> person_in_family_tree& ; public: [[nodiscard]] auto operator<=>(person_in_family_tree const& that) const -> std::partial_ordering = default; @@ -81,12 +75,6 @@ auto main() -> int; : v{ val } #line 4 "pure2-types-ordering-via-meta-functions.cpp2" {} -#line 4 "pure2-types-ordering-via-meta-functions.cpp2" - auto my_integer::operator=(cpp2::in val) -> my_integer& { - v = val; - return *this; -#line 4 "pure2-types-ordering-via-meta-functions.cpp2" - } #line 9 "pure2-types-ordering-via-meta-functions.cpp2" @@ -94,12 +82,6 @@ auto main() -> int; : v{ val } #line 9 "pure2-types-ordering-via-meta-functions.cpp2" {} -#line 9 "pure2-types-ordering-via-meta-functions.cpp2" - auto case_insensitive_string::operator=(cpp2::in val) -> case_insensitive_string& { - v = val; - return *this; -#line 9 "pure2-types-ordering-via-meta-functions.cpp2" - } #line 14 "pure2-types-ordering-via-meta-functions.cpp2" @@ -107,12 +89,6 @@ auto main() -> int; : dummy_data{ parents } #line 14 "pure2-types-ordering-via-meta-functions.cpp2" {} -#line 14 "pure2-types-ordering-via-meta-functions.cpp2" - auto person_in_family_tree::operator=(cpp2::in parents) -> person_in_family_tree& { - dummy_data = parents; - return *this; -#line 14 "pure2-types-ordering-via-meta-functions.cpp2" - } #line 21 "pure2-types-ordering-via-meta-functions.cpp2" diff --git a/regression-tests/test-results/pure2-types-smf-and-that-1-provide-everything.cpp b/regression-tests/test-results/pure2-types-smf-and-that-1-provide-everything.cpp index 5e659de8e5..f22a70ccc8 100644 --- a/regression-tests/test-results/pure2-types-smf-and-that-1-provide-everything.cpp +++ b/regression-tests/test-results/pure2-types-smf-and-that-1-provide-everything.cpp @@ -33,7 +33,7 @@ class myclass { #line 22 "pure2-types-smf-and-that-1-provide-everything.cpp2" - public: explicit myclass(cpp2::in x); + public: myclass(cpp2::in x); #line 22 "pure2-types-smf-and-that-1-provide-everything.cpp2" public: auto operator=(cpp2::in x) -> myclass& ; diff --git a/regression-tests/test-results/pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp b/regression-tests/test-results/pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp index a6c54323ce..15732c2910 100644 --- a/regression-tests/test-results/pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp +++ b/regression-tests/test-results/pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp @@ -36,7 +36,7 @@ class myclass { // std::cout << "assign - move "; // } - public: explicit myclass(cpp2::in x); + public: myclass(cpp2::in x); #line 22 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" public: auto operator=(cpp2::in x) -> myclass& ; diff --git a/regression-tests/test-results/pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp b/regression-tests/test-results/pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp index e17b83c9c3..f5c0cb1d37 100644 --- a/regression-tests/test-results/pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp +++ b/regression-tests/test-results/pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp @@ -37,7 +37,7 @@ class myclass { #line 22 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" - public: explicit myclass(cpp2::in x); + public: myclass(cpp2::in x); #line 22 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" public: auto operator=(cpp2::in x) -> myclass& ; diff --git a/regression-tests/test-results/pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp b/regression-tests/test-results/pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp index 80ea3cf341..8a2e52f9ce 100644 --- a/regression-tests/test-results/pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp +++ b/regression-tests/test-results/pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp @@ -37,7 +37,7 @@ class myclass { #line 22 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" - public: explicit myclass(cpp2::in x); + public: myclass(cpp2::in x); #line 22 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" public: auto operator=(cpp2::in x) -> myclass& ; diff --git a/regression-tests/test-results/pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp b/regression-tests/test-results/pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp index aae06789df..e00f2908a5 100644 --- a/regression-tests/test-results/pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp +++ b/regression-tests/test-results/pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp @@ -44,7 +44,7 @@ class myclass { // std::cout << "assign - move "; // } - public: explicit myclass(cpp2::in x); + public: myclass(cpp2::in x); #line 22 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" public: auto operator=(cpp2::in x) -> myclass& ; diff --git a/regression-tests/test-results/pure2-types-value-types-via-meta-functions.cpp b/regression-tests/test-results/pure2-types-value-types-via-meta-functions.cpp index d032459a6f..8f0443897d 100644 --- a/regression-tests/test-results/pure2-types-value-types-via-meta-functions.cpp +++ b/regression-tests/test-results/pure2-types-value-types-via-meta-functions.cpp @@ -26,8 +26,6 @@ class p_widget; class widget { private: int val {0}; public: explicit widget(cpp2::in i); -#line 4 "pure2-types-value-types-via-meta-functions.cpp2" - public: auto operator=(cpp2::in i) -> widget& ; public: [[nodiscard]] auto operator<=>(widget const& that) const -> std::strong_ordering = default; public: widget(widget const& that); @@ -42,8 +40,6 @@ public: explicit widget(); class w_widget { private: int val {0}; public: explicit w_widget(cpp2::in i); -#line 9 "pure2-types-value-types-via-meta-functions.cpp2" - public: auto operator=(cpp2::in i) -> w_widget& ; public: [[nodiscard]] auto operator<=>(w_widget const& that) const -> std::weak_ordering = default; public: w_widget(w_widget const& that); @@ -58,8 +54,6 @@ public: explicit w_widget(); class p_widget { private: int val {0}; public: explicit p_widget(cpp2::in i); -#line 14 "pure2-types-value-types-via-meta-functions.cpp2" - public: auto operator=(cpp2::in i) -> p_widget& ; public: [[nodiscard]] auto operator<=>(p_widget const& that) const -> std::partial_ordering = default; public: p_widget(p_widget const& that); @@ -86,12 +80,6 @@ template auto test() -> void; : val{ i } #line 4 "pure2-types-value-types-via-meta-functions.cpp2" {} -#line 4 "pure2-types-value-types-via-meta-functions.cpp2" - auto widget::operator=(cpp2::in i) -> widget& { - val = i; - return *this; -#line 4 "pure2-types-value-types-via-meta-functions.cpp2" - } widget::widget(widget const& that) @@ -111,12 +99,6 @@ widget::widget(){} : val{ i } #line 9 "pure2-types-value-types-via-meta-functions.cpp2" {} -#line 9 "pure2-types-value-types-via-meta-functions.cpp2" - auto w_widget::operator=(cpp2::in i) -> w_widget& { - val = i; - return *this; -#line 9 "pure2-types-value-types-via-meta-functions.cpp2" - } w_widget::w_widget(w_widget const& that) @@ -136,12 +118,6 @@ w_widget::w_widget(){} : val{ i } #line 14 "pure2-types-value-types-via-meta-functions.cpp2" {} -#line 14 "pure2-types-value-types-via-meta-functions.cpp2" - auto p_widget::operator=(cpp2::in i) -> p_widget& { - val = i; - return *this; -#line 14 "pure2-types-value-types-via-meta-functions.cpp2" - } p_widget::p_widget(p_widget const& that) diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 5b89964d3a..a509d0de5d 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -5464,9 +5464,10 @@ class cppfront && !current_functions.back().declared_that_functions.inout_this_in_that ) || - // A3) This is '(out this, something-other-than-that)' + // A3) This is '(implicit out this, something-other-than-that)' ( n.is_constructor() + && n.is_function_with_implicit_this() && !n.is_constructor_with_that() ) ) diff --git a/source/parse.h b/source/parse.h index 2fbf60396a..6b49de04d3 100644 --- a/source/parse.h +++ b/source/parse.h @@ -1933,6 +1933,9 @@ struct function_type_node // auto is_function_with_this() const -> bool; + + auto is_function_with_implicit_this() const + -> bool; auto is_virtual_function() const -> bool; @@ -2701,6 +2704,16 @@ struct declaration_node // else return false; } + + auto is_function_with_implicit_this() const + -> bool + { + if (auto func = std::get_if(&type)) { + return (*func)->is_function_with_implicit_this(); + } + // else + return false; + } auto is_virtual_function() const -> bool @@ -3097,6 +3110,20 @@ auto function_type_node::is_function_with_this() const } +auto function_type_node::is_function_with_implicit_this() const + -> bool +{ + if ( + is_function_with_this() + && (*parameters)[0]->is_implicit() + ) + { + return true; + } + return false; +} + + auto function_type_node::is_virtual_function() const -> bool {