diff --git a/regression-tests/pure2-bugfix-for-memberwise-base-assignment.cpp2 b/regression-tests/pure2-bugfix-for-memberwise-base-assignment.cpp2 new file mode 100644 index 000000000..c27d68b51 --- /dev/null +++ b/regression-tests/pure2-bugfix-for-memberwise-base-assignment.cpp2 @@ -0,0 +1,18 @@ +Base: type = { + operator=: (out this) = { } + operator=: (out this, that) = std::cout << "(out this, that)\n"; + operator=: (implicit out this, x) = std::cout << "(implicit out this, x)\n"; +} + +Derived: type = { + this: Base = (); + operator=: (out this) = { } + operator=: (out this, that) = { } + operator=: (inout this, move that) = { } +} + +main: () = { + d := Derived(); + d2 := d; + d2 = d; +} diff --git a/regression-tests/test-results/gcc-13/pure2-bugfix-for-memberwise-base-assignment.cpp.execution b/regression-tests/test-results/gcc-13/pure2-bugfix-for-memberwise-base-assignment.cpp.execution new file mode 100644 index 000000000..566837e51 --- /dev/null +++ b/regression-tests/test-results/gcc-13/pure2-bugfix-for-memberwise-base-assignment.cpp.execution @@ -0,0 +1,2 @@ +(out this, that) +(out this, that) diff --git a/regression-tests/test-results/gcc-13/pure2-bugfix-for-memberwise-base-assignment.cpp.output b/regression-tests/test-results/gcc-13/pure2-bugfix-for-memberwise-base-assignment.cpp.output new file mode 100644 index 000000000..e69de29bb diff --git a/regression-tests/test-results/pure2-bugfix-for-memberwise-base-assignment.cpp b/regression-tests/test-results/pure2-bugfix-for-memberwise-base-assignment.cpp new file mode 100644 index 000000000..187cfa4a0 --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-memberwise-base-assignment.cpp @@ -0,0 +1,93 @@ + +#define CPP2_USE_MODULES Yes + +//=== Cpp2 type declarations ==================================================== + + +#include "cpp2util.h" + +#line 1 "pure2-bugfix-for-memberwise-base-assignment.cpp2" +class Base; + + +#line 7 "pure2-bugfix-for-memberwise-base-assignment.cpp2" +class Derived; + + +//=== Cpp2 type definitions and function declarations =========================== + +#line 1 "pure2-bugfix-for-memberwise-base-assignment.cpp2" +class Base { + public: explicit Base(); + public: Base(Base const& that); + +#line 3 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + public: auto operator=(Base const& that) -> Base& ; + +#line 3 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + public: Base(Base&& that) noexcept; + +#line 3 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + public: auto operator=(Base&& that) noexcept -> Base& ; + public: Base(auto const& x); +#line 4 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + public: auto operator=(auto const& x) -> Base& ; +}; + +class Derived: public Base { + + public: explicit Derived(); + public: Derived(Derived const& that); + public: auto operator=(Derived&& that) noexcept -> Derived& ; +}; + +auto main() -> int; + + +//=== Cpp2 function definitions ================================================= + + +#line 2 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + Base::Base(){} + Base::Base (Base const& that) { std::cout << "(out this, that)\n"; } +#line 3 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + auto Base::operator=(Base const& that) -> Base& { std::cout << "(out this, that)\n"; + return *this; +#line 3 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + } +#line 3 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + Base::Base (Base&& that) noexcept { std::cout << "(out this, that)\n"; } +#line 3 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + auto Base::operator=(Base&& that) noexcept -> Base& { std::cout << "(out this, that)\n"; + return *this; +#line 3 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + } + Base::Base(auto const& x) { std::cout << "(implicit out this, x)\n"; } +#line 4 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + auto Base::operator=(auto const& x) -> Base& { std::cout << "(implicit out this, x)\n"; + return *this; +#line 4 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + } + +#line 9 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + Derived::Derived() + : Base{ } +#line 9 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + {} + Derived::Derived(Derived const& that) + : Base{ static_cast(that) } +#line 10 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + {} + auto Derived::operator=(Derived&& that) noexcept -> Derived& { + Base::operator= ( static_cast(that) ); + return *this; +#line 11 "pure2-bugfix-for-memberwise-base-assignment.cpp2" + } + +#line 14 "pure2-bugfix-for-memberwise-base-assignment.cpp2" +auto main() -> int{ + auto d {Derived()}; + auto d2 {d}; + d2 = std::move(d); +} + diff --git a/regression-tests/test-results/pure2-bugfix-for-memberwise-base-assignment.cpp2.output b/regression-tests/test-results/pure2-bugfix-for-memberwise-base-assignment.cpp2.output new file mode 100644 index 000000000..551cca17f --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-memberwise-base-assignment.cpp2.output @@ -0,0 +1,2 @@ +pure2-bugfix-for-memberwise-base-assignment.cpp2... ok (all Cpp2, passes safety checks) + diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 1bad85a53..b9e754671 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -4584,23 +4584,34 @@ class cppfront // Otherwise, use a default... for a non-copy/move that's the member initializer // (for which we don't need to emit anything special because it will get used), // and for a copy/move function we default to "= that.same_member" (or, if this - // is a base type, just "= that") + // is a base type, to assigning from the lowered base subobject) if (!found_explicit_init) { - if (emitting_move_that_function) + if (emitting_that_function && (*object)->has_name("this")) { - initializer = "std::move(that)"; - if (!(*object)->has_name("this")) { - initializer += "." + object_name; + auto pass = std::string{" const&"}; + if (emitting_move_that_function) { + pass = "&&"; } + initializer = + "static_cast<" + + object_name + + pass + + ">(that)"; + found_default_init = true; + } + else if (emitting_move_that_function) + { + initializer = + "std::move(that)." + + object_name; found_default_init = true; } else if (emitting_that_function) { - initializer = "that"; - if (!(*object)->has_name("this")) { - initializer += "." + object_name; - } + initializer = + "that." + + object_name; found_default_init = true; } else if ((*object)->initializer)