From 6982babbf680dfb9a8de5c114076fd5336e2a905 Mon Sep 17 00:00:00 2001 From: Jo Bates Date: Sat, 17 Jun 2023 20:53:48 -0700 Subject: [PATCH 01/12] Statements before and between member initializers in special member functions --- source/cppfront.cpp | 245 +++++++++++++++++++++++++++----------------- source/reflect.h | 2 +- source/reflect.h2 | 2 +- 3 files changed, 153 insertions(+), 96 deletions(-) diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 38d88cc7f..6637fae0f 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -4492,15 +4492,21 @@ class cppfront // If this constructor's type has data members, handle their initialization // - objects is the list of this type's declarations - // - statements is the list of this constructor's statements - auto objects = n.parent_declaration->get_type_scope_declarations(n.objects); - auto statements = n.get_initializer_statements(); - auto out_inits = std::vector{}; + // - body_statements is the list of statements in this constructor's body + // - pending_statements is the list of statements to insert before the next (possibly implicit) member initializer + // - deferred_statements is the list of statements to insert before the next explicit member initializer + auto objects = n.parent_declaration->get_type_scope_declarations(n.objects); + auto body_statements = n.get_initializer_statements(); + auto pending_statements = std::vector{}; + auto deferred_statements = std::vector{}; auto object = objects.begin(); - auto statement = statements.begin(); + auto statement = body_statements.begin(); auto separator = std::string{": "}; + auto found_that_init = false; + auto default_until_object = objects.end(); // objects.end() means we're not yet skipping to anything + while (object != objects.end()) { auto object_name = canonize_object_name(*object); @@ -4514,12 +4520,17 @@ class cppfront auto initializer = std::string{}; - // If we're at an assignment statement, get the lhs and rhs - if (statement != statements.end()) + if (default_until_object == object) + { + default_until_object = objects.end(); // objects.end() means we're no longer skipping to anything + } + + if (default_until_object == objects.end() && statement != body_statements.end()) { assert (*statement); stmt_pos = (*statement)->position(); + // If we're at an assignment statement, get the lhs and rhs auto lhs = std::string{}; auto rhs = std::string{}; { @@ -4537,36 +4548,60 @@ class cppfront } } - // If this is an initialization of an 'out' parameter, stash it - if (n.has_out_parameter_named(lhs)){ - out_inits.push_back( print_to_string(**statement, false) ); - (*statement)->emitted = true; - ++statement; - continue; - } - - // Now we're ready to check whether this is an assignment to *object - + // Now we're ready to check whether this is a member assignment if (!lhs.empty()) { - // First, see if it's an assignment 'name = something' - found_explicit_init = object_name == lhs; - - // Otherwise, see if it's 'this.name = something' - if (!found_explicit_init) + // First, check if it's 'this = that' + if (lhs == "this" && rhs == (emitting_move_that_function ? "std::move(that)" : "that")) { - // If it's of the form 'this.name', check 'name' - if ( - starts_with( lhs, "(*this).") - && object_name == lhs.substr(8) - ) + if (!emitting_that_function) { - found_explicit_init = true; + errors.emplace_back( + stmt_pos, + "'this = that' can only be used in functions where 'that' is a parameter" + ); + return; + } + else if (object != objects.begin()) + { + errors.emplace_back( + stmt_pos, + "'this = that' must appear before all other member initializers" + ); + return; + } + else if (found_that_init) + { + errors.emplace_back( + stmt_pos, + "'this = that' may only appear once" + ); + return; + } + else + { + // All the statements before 'this = that' need to be inserted + // before the first member initializer whether or not it's explicit + pending_statements = std::move(deferred_statements); + + found_that_init = true; + (*statement)->emitted = true; + ++statement; + continue; } } - if (found_explicit_init) + // Second, check if it's an assignment 'member = something' or 'this.member = something' + auto lhs_name = lhs.substr(starts_with(lhs, "(*this).") ? 8 : 0); + auto lhs_object = std::find_if( + objects.begin(), objects.end(), + [&](auto o) { return canonize_object_name(o) == lhs_name; } + ); + + // Is it the current member? + if (lhs_object == object) { + found_explicit_init = true; initializer = rhs; // We've used this statement, so note it @@ -4574,30 +4609,49 @@ class cppfront (*statement)->emitted = true; ++statement; } + // Is it a future member? + else if (lhs_object != objects.end() && lhs_object > object) + { + // Default-initialize all the members before it + default_until_object = lhs_object; + continue; + } + } + + // Not an explicit init for the current member? + if (!found_explicit_init) + { + // Queue it up to insert before the next explicit initializer + deferred_statements.push_back( print_to_string(**statement, false) ); + (*statement)->emitted = true; + ++statement; + continue; } } + // If explicit, upgrade deferred statements to pending + if (found_explicit_init) + { + pending_statements.insert( + pending_statements.end(), + deferred_statements.begin(), + deferred_statements.end() + ); + deferred_statements.clear(); + } + // 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") + // and for a copy/move function with 'this = that' we default to "= that.same_member" + // (or, if this is a base type, just "= that") if (!found_explicit_init) { - if (emitting_move_that_function) + if (found_that_init) { - initializer = "std::move(that)"; + initializer = emitting_move_that_function ? "std::move(that)" : "that"; if (!(*object)->has_name("this")) { initializer += "." + object_name; } - found_default_init = true; - } - else if (emitting_that_function) - { - initializer = "that"; - if (!(*object)->has_name("this")) { - initializer += "." + object_name; - } - found_default_init = true; } else if ((*object)->initializer) { @@ -4607,9 +4661,10 @@ class cppfront } // If this is not an assignment to *object, - // and there was no member initializer, complain + // and there was no 'this = that' or member initializer, complain if ( !found_explicit_init + && !found_that_init && !found_default_init ) { @@ -4622,6 +4677,7 @@ class cppfront assert( found_explicit_init + || found_that_init || found_default_init ); @@ -4631,48 +4687,55 @@ class cppfront initializer = "{}"; } - // (a) ... if this is assignment, emit it in all cases + // (a) ... if this is assignment, emit if explicit or 'this = that' + // or we're generating from a constructor definition if (is_assignment) { - assert ((*object)->name()); + if ( + found_explicit_init + || found_that_init + || n.is_constructor()) + { + assert ((*object)->name()); - // Flush any 'out' parameter initializations - for (auto& init : out_inits) { - current_functions.back().prolog.statements.push_back(init + ";"); - } - out_inits = {}; + // Flush any pending statements + for (auto& stmt : pending_statements) { + current_functions.back().prolog.statements.push_back(stmt + ";"); + } + pending_statements.clear(); - // Then add this statement + // Then add this statement - // Use ::operator= for base classes - if ((*object)->has_name("this")) { - current_functions.back().prolog.statements.push_back( - print_to_string( *(*object)->get_object_type() ) + - "::operator= ( " + - initializer + - " );" - ); - } - // Else just use infix assignment - else { - current_functions.back().prolog.statements.push_back( - object_name + - " = " + - initializer + - ";" - ); + // Use ::operator= for base classes + if ((*object)->has_name("this")) { + current_functions.back().prolog.statements.push_back( + print_to_string( *(*object)->get_object_type() ) + + "::operator= ( " + + initializer + + " );" + ); + } + // Else just use infix assignment + else { + current_functions.back().prolog.statements.push_back( + object_name + + " = " + + initializer + + ";" + ); + } } } // (b) ... if this isn't assignment, only need to emit it if it was - // explicit, or is a base type or 'that' initializer + // explicit or 'this = that' or is a base type else if ( found_explicit_init + || found_that_init || is_object_before_base || ( (*object)->has_name("this") && !initializer.empty() ) - || emitting_that_function ) { if (is_object_before_base) { @@ -4684,28 +4747,17 @@ class cppfront + "_as_base"; } - // Flush any 'out' parameter initializations - auto out_inits_with_commas = [&]() -> std::string { - auto ret = std::string{}; - for (auto& init : out_inits) { - ret += init + ", "; + // If there are any pending statements, wedge them into this initializer + // using (holds nose) an immediately invoked lambda and the comma operator + if (!pending_statements.empty()) + { + auto mem_init = separator + object_name + "{([&]{"; + for (auto& stmt : pending_statements) { + mem_init += stmt + ";"; } - out_inits = {}; - return ret; - }(); - - // If there were any, wedge them into this initializer - // using (holds nose) the comma operator and extra parens - // as we add this statement - if (!out_inits_with_commas.empty()) { - current_functions.back().prolog.mem_inits.push_back( - separator + - object_name + - "{(" + - out_inits_with_commas + - initializer + - " )}" - ); + pending_statements.clear(); + mem_init += "}(), " + initializer + ")}"; + current_functions.back().prolog.mem_inits.push_back(std::move(mem_init)); } else { if (initializer == "{}") { @@ -4736,9 +4788,14 @@ class cppfront return; } - // Flush any possible remaining 'out' parameters - for (auto& init : out_inits) { - current_functions.back().prolog.statements.push_back(init + ";"); + // Flush any pending statements + for (auto& stmt : pending_statements) { + current_functions.back().prolog.statements.push_back(stmt + ";"); + } + + // Flush any deferred statements + for (auto& stmt : deferred_statements) { + current_functions.back().prolog.statements.push_back(stmt + ";"); } } diff --git a/source/reflect.h b/source/reflect.h index 1d8dfdef6..c558e4758 100644 --- a/source/reflect.h +++ b/source/reflect.h @@ -1063,7 +1063,7 @@ auto copyable(meta::type_declaration& t) -> void CPP2_UFCS(error, t, "this type is partially copyable/movable - when you provide any of the more-specific operator= signatures, you must also provide the one with the general signature (out this, that); alternatively, consider removing all the operator= functions and let them all be generated for you with default memberwise semantics"); } else {if (!(std::move(smfs).out_this_in_that)) { - CPP2_UFCS(require, t, CPP2_UFCS(add_member, t, "operator=: (out this, that) = { }"), + CPP2_UFCS(require, t, CPP2_UFCS(add_member, t, "operator=: (out this, that) = { this = that; }"), "could not add general operator=:(out this, that)"); }} } diff --git a/source/reflect.h2 b/source/reflect.h2 index 85aa6cc2c..d0f001263 100644 --- a/source/reflect.h2 +++ b/source/reflect.h2 @@ -597,7 +597,7 @@ copyable: (inout t: meta::type_declaration) = t.error( "this type is partially copyable/movable - when you provide any of the more-specific operator= signatures, you must also provide the one with the general signature (out this, that); alternatively, consider removing all the operator= functions and let them all be generated for you with default memberwise semantics" ); } else if !smfs.out_this_in_that { - t.require( t.add_member( "operator=: (out this, that) = { }"), + t.require( t.add_member( "operator=: (out this, that) = { this = that; }"), "could not add general operator=:(out this, that)"); } } From 455705b3570b4a67d13da40530491697a8de64fa Mon Sep 17 00:00:00 2001 From: Jo Bates Date: Sun, 18 Jun 2023 07:38:01 -0700 Subject: [PATCH 02/12] When generating a lambda to insert statements before a member initializer in a constructor, return the initializer from the lambda instead of using the comma operator --- source/cppfront.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 6637fae0f..21bcde853 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -4700,7 +4700,7 @@ class cppfront // Flush any pending statements for (auto& stmt : pending_statements) { - current_functions.back().prolog.statements.push_back(stmt + ";"); + current_functions.back().prolog.statements.push_back(stmt); } pending_statements.clear(); @@ -4747,16 +4747,17 @@ class cppfront + "_as_base"; } - // If there are any pending statements, wedge them into this initializer - // using (holds nose) an immediately invoked lambda and the comma operator + // If there are any pending statements, wedge them into + // this initializer using an immediately invoked lambda if (!pending_statements.empty()) { - auto mem_init = separator + object_name + "{([&]{"; + auto object_type = print_to_string( *(*object)->get_object_type() ); + auto mem_init = separator + object_name + "{ [&]() -> " + object_type + " { "; for (auto& stmt : pending_statements) { - mem_init += stmt + ";"; + mem_init += stmt; } pending_statements.clear(); - mem_init += "}(), " + initializer + ")}"; + mem_init += "return " + initializer + "; }() }"; current_functions.back().prolog.mem_inits.push_back(std::move(mem_init)); } else { From 015441ba41215a70563167961e1575d4871a9ec3 Mon Sep 17 00:00:00 2001 From: Jo Bates Date: Sun, 18 Jun 2023 08:03:00 -0700 Subject: [PATCH 03/12] Add missing semicolons --- source/cppfront.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 21bcde853..1ff10982a 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -4700,7 +4700,7 @@ class cppfront // Flush any pending statements for (auto& stmt : pending_statements) { - current_functions.back().prolog.statements.push_back(stmt); + current_functions.back().prolog.statements.push_back(stmt + ";"); } pending_statements.clear(); @@ -4754,7 +4754,7 @@ class cppfront auto object_type = print_to_string( *(*object)->get_object_type() ); auto mem_init = separator + object_name + "{ [&]() -> " + object_type + " { "; for (auto& stmt : pending_statements) { - mem_init += stmt; + mem_init += stmt + "; "; } pending_statements.clear(); mem_init += "return " + initializer + "; }() }"; From d4b61fe0796cfbbb703344829e7ff1765eaae9bf Mon Sep 17 00:00:00 2001 From: Jo Bates Date: Sun, 18 Jun 2023 08:46:38 -0700 Subject: [PATCH 04/12] Split constructor member init IIFE's across multiple lines --- source/cppfront.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 1ff10982a..96fb09906 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -4749,28 +4749,23 @@ class cppfront // If there are any pending statements, wedge them into // this initializer using an immediately invoked lambda + auto& mem_inits = current_functions.back().prolog.mem_inits; if (!pending_statements.empty()) { auto object_type = print_to_string( *(*object)->get_object_type() ); - auto mem_init = separator + object_name + "{ [&]() -> " + object_type + " { "; + mem_inits.push_back(separator + object_name + "{ [&]() -> " + object_type + " {"); for (auto& stmt : pending_statements) { - mem_init += stmt + "; "; + mem_inits.push_back(" " + stmt + ";"); } pending_statements.clear(); - mem_init += "return " + initializer + "; }() }"; - current_functions.back().prolog.mem_inits.push_back(std::move(mem_init)); + mem_inits.push_back(" return " + initializer + ";"); + mem_inits.push_back(" }() }"); } else { if (initializer == "{}") { initializer = ""; } - current_functions.back().prolog.mem_inits.push_back( - separator + - object_name + - "{ " + - initializer + - " }" - ); + mem_inits.push_back(separator + object_name + "{ " + initializer + " }"); } separator = ", "; } From 168be27a75957b1a1200e31c973dc2d0a3066913 Mon Sep 17 00:00:00 2001 From: Jo Bates Date: Sun, 18 Jun 2023 09:38:35 -0700 Subject: [PATCH 05/12] Stop relying on unspecified state of a moved std::vector --- source/cppfront.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 96fb09906..d126bfb43 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -4582,7 +4582,8 @@ class cppfront { // All the statements before 'this = that' need to be inserted // before the first member initializer whether or not it's explicit - pending_statements = std::move(deferred_statements); + pending_statements = deferred_statements; + deferred_statements.clear(); found_that_init = true; (*statement)->emitted = true; From 4e5c06734102422a9c900c8a6da1493d156c96ee Mon Sep 17 00:00:00 2001 From: Jo Bates Date: Thu, 22 Jun 2023 07:49:27 -0700 Subject: [PATCH 06/12] Eliminate some unnecessary copies --- source/cppfront.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/source/cppfront.cpp b/source/cppfront.cpp index d126bfb43..dbf0cf9c3 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -4582,8 +4582,8 @@ class cppfront { // All the statements before 'this = that' need to be inserted // before the first member initializer whether or not it's explicit - pending_statements = deferred_statements; - deferred_statements.clear(); + assert(pending_statements.empty()); + pending_statements.swap(deferred_statements); found_that_init = true; (*statement)->emitted = true; @@ -4633,11 +4633,9 @@ class cppfront // If explicit, upgrade deferred statements to pending if (found_explicit_init) { - pending_statements.insert( - pending_statements.end(), - deferred_statements.begin(), - deferred_statements.end() - ); + for (auto& stmt : deferred_statements) { + pending_statements.push_back(std::move(stmt)); + } deferred_statements.clear(); } From aeff9030061839cae29ef447a4422ea000234222 Mon Sep 17 00:00:00 2001 From: Jo Bates Date: Sat, 24 Jun 2023 06:53:13 -0700 Subject: [PATCH 07/12] Use std::make_move_iterator as @gregmarr suggested --- source/cppfront.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/cppfront.cpp b/source/cppfront.cpp index dbf0cf9c3..499b8fe45 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -4633,9 +4633,11 @@ class cppfront // If explicit, upgrade deferred statements to pending if (found_explicit_init) { - for (auto& stmt : deferred_statements) { - pending_statements.push_back(std::move(stmt)); - } + pending_statements.insert( + pending_statements.end(), + std::make_move_iterator(deferred_statements.begin()), + std::make_move_iterator(deferred_statements.end()) + ); deferred_statements.clear(); } From 90a0a0b64eed4b3ec7a3630d22206e7f71e90cfc Mon Sep 17 00:00:00 2001 From: Jo Bates Date: Sat, 24 Jun 2023 07:12:33 -0700 Subject: [PATCH 08/12] Don't include statements in prolog unless they're being inserted before a member initializer --- source/cppfront.cpp | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 499b8fe45..e6f576705 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -4497,8 +4497,8 @@ class cppfront // - deferred_statements is the list of statements to insert before the next explicit member initializer auto objects = n.parent_declaration->get_type_scope_declarations(n.objects); auto body_statements = n.get_initializer_statements(); - auto pending_statements = std::vector{}; - auto deferred_statements = std::vector{}; + auto pending_statements = std::vector{}; + auto deferred_statements = std::vector{}; auto object = objects.begin(); auto statement = body_statements.begin(); @@ -4623,8 +4623,7 @@ class cppfront if (!found_explicit_init) { // Queue it up to insert before the next explicit initializer - deferred_statements.push_back( print_to_string(**statement, false) ); - (*statement)->emitted = true; + deferred_statements.push_back( *statement ); ++statement; continue; } @@ -4700,8 +4699,11 @@ class cppfront assert ((*object)->name()); // Flush any pending statements - for (auto& stmt : pending_statements) { - current_functions.back().prolog.statements.push_back(stmt + ";"); + for (auto statement : pending_statements) { + current_functions.back().prolog.statements.push_back( + print_to_string(*statement, false) + ";" + ); + statement->emitted = true; } pending_statements.clear(); @@ -4755,8 +4757,11 @@ class cppfront { auto object_type = print_to_string( *(*object)->get_object_type() ); mem_inits.push_back(separator + object_name + "{ [&]() -> " + object_type + " {"); - for (auto& stmt : pending_statements) { - mem_inits.push_back(" " + stmt + ";"); + for (auto statement : pending_statements) { + mem_inits.push_back( + " " + print_to_string(*statement, false) + ";" + ); + statement->emitted = true; } pending_statements.clear(); mem_inits.push_back(" return " + initializer + ";"); @@ -4784,16 +4789,6 @@ class cppfront ); return; } - - // Flush any pending statements - for (auto& stmt : pending_statements) { - current_functions.back().prolog.statements.push_back(stmt + ";"); - } - - // Flush any deferred statements - for (auto& stmt : deferred_statements) { - current_functions.back().prolog.statements.push_back(stmt + ";"); - } } // For a constructor, print the type name instead of the operator= function name From c4647968f40c99b5e50f5411a425af1587d3d66e Mon Sep 17 00:00:00 2001 From: Jo Bates Date: Sat, 24 Jun 2023 07:14:22 -0700 Subject: [PATCH 09/12] Update regression tests --- ...pes-smf-and-that-1-provide-everything.cpp2 | 4 ++ ...at-2-provide-mvconstruct-and-cpassign.cpp2 | 4 ++ ...at-3-provide-mvconstruct-and-mvassign.cpp2 | 4 ++ ...-that-4-provide-cpassign-and-mvassign.cpp2 | 4 ++ ...at-5-provide-nothing-but-general-case.cpp2 | 4 ++ ...2-types-order-independence-and-nesting.cpp | 5 ++- ...ypes-smf-and-that-1-provide-everything.cpp | 39 +++++++++-------- ...hat-2-provide-mvconstruct-and-cpassign.cpp | 43 ++++++++++--------- ...hat-3-provide-mvconstruct-and-mvassign.cpp | 41 ++++++++++-------- ...d-that-4-provide-cpassign-and-mvassign.cpp | 38 ++++++++-------- ...hat-5-provide-nothing-but-general-case.cpp | 37 +++++++++------- 11 files changed, 134 insertions(+), 89 deletions(-) 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 7972b1fe3..537cae2a4 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 @@ -2,20 +2,24 @@ myclass : type = { operator=: (out this, that) = { + this = that; std::cout << "ctor - copy (GENERAL)"; } operator=: (out this, move that) = { + this = that; name = that.name + "(CM)"; std::cout << "ctor - move "; } operator=: (inout this, that) = { + this = that; addr = that.addr + "(AC)"; std::cout << "assign - copy "; } operator=: (inout this, move that) = { + this = that; std::cout << "assign - move "; } 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 8432d7560..cbb70fc70 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 @@ -2,20 +2,24 @@ myclass : type = { operator=: (out this, that) = { + this = that; std::cout << "ctor - copy (GENERAL)"; } operator=: (out this, move that) = { + this = that; name = that.name + "(CM)"; std::cout << "ctor - move "; } operator=: (inout this, that) = { + this = that; addr = that.addr + "(AC)"; std::cout << "assign - copy "; } // operator=: (inout this, move that) = { + // this = that; // std::cout << "assign - move "; // } 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 192f92185..817c05c32 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 @@ -2,20 +2,24 @@ myclass : type = { operator=: (out this, that) = { + this = that; std::cout << "ctor - copy (GENERAL)"; } operator=: (out this, move that) = { + this = that; name = that.name + "(CM)"; std::cout << "ctor - move "; } // operator=: (inout this, that) = { + // this = that; // addr = that.addr + "(AC)"; // std::cout << "assign - copy "; // } operator=: (inout this, move that) = { + this = that; std::cout << "assign - move "; } 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 87d2c048b..6572963a6 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 @@ -2,20 +2,24 @@ myclass : type = { operator=: (out this, that) = { + this = that; std::cout << "ctor - copy (GENERAL)"; } // operator=: (out this, move that) = { + // this = that; // name = that.name + "(CM)"; // std::cout << "ctor - move "; // } operator=: (inout this, that) = { + this = that; addr = that.addr + "(AC)"; std::cout << "assign - copy "; } operator=: (inout this, move that) = { + this = that; std::cout << "assign - move "; } 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 4d4bd6585..2033af113 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 @@ -2,20 +2,24 @@ myclass : type = { operator=: (out this, that) = { + this = that; std::cout << "ctor - copy (GENERAL)"; } // operator=: (out this, move that) = { + // this = that; // name = that.name + "(CM)"; // std::cout << "ctor - move "; // } // operator=: (inout this, that) = { + // this = that; // addr = that.addr + "(AC)"; // std::cout << "assign - copy "; // } // operator=: (inout this, move that) = { + // this = that; // std::cout << "assign - move "; // } 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 2020cd3b2..e4d50f1e8 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 @@ -114,7 +114,10 @@ namespace N { #line 10 "pure2-types-order-independence-and-nesting.cpp2" X::X(cpp2::out y) - : py{(y.construct(&(*this)), &y.value() )} + : py{ [&]() -> Y* { + y.construct(&(*this)); + return &y.value(); + }() } #line 10 "pure2-types-order-independence-and-nesting.cpp2" { // === The following comments will stay close to, but not exactly at, 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 5e659de8e..2e4f48fb6 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 @@ -20,26 +20,26 @@ class myclass { public: myclass(myclass const& that); -#line 8 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 9 "pure2-types-smf-and-that-1-provide-everything.cpp2" public: myclass(myclass&& that) noexcept; -#line 13 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 15 "pure2-types-smf-and-that-1-provide-everything.cpp2" public: auto operator=(myclass const& that) -> myclass& ; -#line 18 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 21 "pure2-types-smf-and-that-1-provide-everything.cpp2" public: auto operator=(myclass&& that) noexcept -> myclass& ; -#line 22 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 26 "pure2-types-smf-and-that-1-provide-everything.cpp2" public: explicit myclass(cpp2::in x); -#line 22 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 26 "pure2-types-smf-and-that-1-provide-everything.cpp2" public: auto operator=(cpp2::in x) -> myclass& ; -#line 27 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 31 "pure2-types-smf-and-that-1-provide-everything.cpp2" private: std::string name {"Henry"}; private: std::string addr {"123 Ford Dr."}; @@ -49,7 +49,7 @@ class myclass { cpp2::in suffix ) const -> void; -#line 37 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 41 "pure2-types-smf-and-that-1-provide-everything.cpp2" }; auto main() -> int; @@ -64,15 +64,17 @@ auto main() -> int; , addr{ that.addr } #line 4 "pure2-types-smf-and-that-1-provide-everything.cpp2" { + std::cout << "ctor - copy (GENERAL)"; } myclass::myclass(myclass&& that) noexcept : name{ std::move(that).name + "(CM)" } , addr{ std::move(that).addr } -#line 8 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 9 "pure2-types-smf-and-that-1-provide-everything.cpp2" { +#line 12 "pure2-types-smf-and-that-1-provide-everything.cpp2" std::cout << "ctor - move "; } @@ -80,40 +82,41 @@ auto main() -> int; name = that.name; addr = that.addr + "(AC)"; -#line 15 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 18 "pure2-types-smf-and-that-1-provide-everything.cpp2" std::cout << "assign - copy "; return *this; -#line 16 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 19 "pure2-types-smf-and-that-1-provide-everything.cpp2" } auto myclass::operator=(myclass&& that) noexcept -> myclass& { name = std::move(that).name; addr = std::move(that).addr; -#line 19 "pure2-types-smf-and-that-1-provide-everything.cpp2" + +#line 23 "pure2-types-smf-and-that-1-provide-everything.cpp2" std::cout << "assign - move "; return *this; -#line 20 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 24 "pure2-types-smf-and-that-1-provide-everything.cpp2" } myclass::myclass(cpp2::in x) : name{ x } -#line 22 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 26 "pure2-types-smf-and-that-1-provide-everything.cpp2" { std::cout << "ctor - from string "; } -#line 22 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 26 "pure2-types-smf-and-that-1-provide-everything.cpp2" auto myclass::operator=(cpp2::in x) -> myclass& { name = x; addr = "123 Ford Dr."; -#line 24 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 28 "pure2-types-smf-and-that-1-provide-everything.cpp2" std::cout << "ctor - from string "; return *this; -#line 25 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 29 "pure2-types-smf-and-that-1-provide-everything.cpp2" } -#line 30 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 34 "pure2-types-smf-and-that-1-provide-everything.cpp2" auto myclass::print( cpp2::in prefix, @@ -121,7 +124,7 @@ auto main() -> int; ) const -> void { std::cout << prefix << "[ " + cpp2::to_string(name) + " | " + cpp2::to_string(addr) + " ]" << suffix; } -#line 39 "pure2-types-smf-and-that-1-provide-everything.cpp2" +#line 43 "pure2-types-smf-and-that-1-provide-everything.cpp2" auto main() -> int{ std::cout << "Function invoked Call syntax Results\n"; std::cout << "---------------------- ------------ ------------------------------------------------------\n"; 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 a6c54323c..aab75e87a 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 @@ -20,29 +20,30 @@ class myclass { public: myclass(myclass const& that); -#line 8 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 9 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" public: myclass(myclass&& that) noexcept; -#line 13 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 15 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" public: auto operator=(myclass const& that) -> myclass& ; -#line 13 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 15 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" public: auto operator=(myclass&& that) noexcept -> myclass& ; -#line 18 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 21 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" // operator=: (inout this, move that) = { + // this = that; // std::cout << "assign - move "; // } public: explicit myclass(cpp2::in x); -#line 22 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 26 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" public: auto operator=(cpp2::in x) -> myclass& ; -#line 27 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 31 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" private: std::string name {"Henry"}; private: std::string addr {"123 Ford Dr."}; @@ -52,7 +53,7 @@ class myclass { cpp2::in suffix ) const -> void; -#line 37 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 41 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" }; auto main() -> int; @@ -67,15 +68,17 @@ auto main() -> int; , addr{ that.addr } #line 4 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" { + std::cout << "ctor - copy (GENERAL)"; } myclass::myclass(myclass&& that) noexcept : name{ std::move(that).name + "(CM)" } , addr{ std::move(that).addr } -#line 8 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 9 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" { +#line 12 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" std::cout << "ctor - move "; } @@ -83,42 +86,42 @@ auto main() -> int; name = that.name; addr = that.addr + "(AC)"; -#line 15 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 18 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" std::cout << "assign - copy "; return *this; -#line 16 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 19 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" } -#line 13 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 15 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" auto myclass::operator=(myclass&& that) noexcept -> myclass& { name = std::move(that).name; addr = std::move(that).addr + "(AC)"; -#line 15 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 18 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" std::cout << "assign - copy "; return *this; -#line 16 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 19 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" } -#line 22 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 26 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" myclass::myclass(cpp2::in x) : name{ x } -#line 22 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 26 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" { std::cout << "ctor - from string "; } -#line 22 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 26 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" auto myclass::operator=(cpp2::in x) -> myclass& { name = x; addr = "123 Ford Dr."; -#line 24 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 28 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" std::cout << "ctor - from string "; return *this; -#line 25 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 29 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" } -#line 30 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 34 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" auto myclass::print( cpp2::in prefix, @@ -126,7 +129,7 @@ auto main() -> int; ) const -> void { std::cout << prefix << "[ " + cpp2::to_string(name) + " | " + cpp2::to_string(addr) + " ]" << suffix; } -#line 39 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" +#line 43 "pure2-types-smf-and-that-2-provide-mvconstruct-and-cpassign.cpp2" auto main() -> int{ std::cout << "Function invoked Call syntax Results\n"; std::cout << "---------------------- ------------ ------------------------------------------------------\n"; 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 e17b83c9c..9a6f8c894 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 @@ -23,12 +23,13 @@ class myclass { public: auto operator=(myclass const& that) -> myclass& ; -#line 8 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 9 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" public: myclass(myclass&& that) noexcept; -#line 13 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 15 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" // operator=: (inout this, that) = { + // this = that; // addr = that.addr + "(AC)"; // std::cout << "assign - copy "; // } @@ -36,14 +37,14 @@ class myclass { public: auto operator=(myclass&& that) noexcept -> myclass& ; -#line 22 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 26 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" public: explicit myclass(cpp2::in x); -#line 22 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 26 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" public: auto operator=(cpp2::in x) -> myclass& ; -#line 27 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 31 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" private: std::string name {"Henry"}; private: std::string addr {"123 Ford Dr."}; @@ -53,7 +54,7 @@ class myclass { cpp2::in suffix ) const -> void; -#line 37 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 41 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" }; auto main() -> int; @@ -68,56 +69,60 @@ auto main() -> int; , addr{ that.addr } #line 4 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" { + std::cout << "ctor - copy (GENERAL)"; } #line 4 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" auto myclass::operator=(myclass const& that) -> myclass& { name = that.name; addr = that.addr; -#line 5 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" + +#line 6 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" std::cout << "ctor - copy (GENERAL)"; return *this; -#line 6 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 7 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" } myclass::myclass(myclass&& that) noexcept : name{ std::move(that).name + "(CM)" } , addr{ std::move(that).addr } -#line 8 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 9 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" { +#line 12 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" std::cout << "ctor - move "; } -#line 18 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 21 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" auto myclass::operator=(myclass&& that) noexcept -> myclass& { name = std::move(that).name; addr = std::move(that).addr; -#line 19 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" + +#line 23 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" std::cout << "assign - move "; return *this; -#line 20 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 24 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" } myclass::myclass(cpp2::in x) : name{ x } -#line 22 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 26 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" { std::cout << "ctor - from string "; } -#line 22 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 26 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" auto myclass::operator=(cpp2::in x) -> myclass& { name = x; addr = "123 Ford Dr."; -#line 24 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 28 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" std::cout << "ctor - from string "; return *this; -#line 25 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 29 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" } -#line 30 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 34 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" auto myclass::print( cpp2::in prefix, @@ -125,7 +130,7 @@ auto main() -> int; ) const -> void { std::cout << prefix << "[ " + cpp2::to_string(name) + " | " + cpp2::to_string(addr) + " ]" << suffix; } -#line 39 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" +#line 43 "pure2-types-smf-and-that-3-provide-mvconstruct-and-mvassign.cpp2" auto main() -> int{ std::cout << "Function invoked Call syntax Results\n"; std::cout << "---------------------- ------------ ------------------------------------------------------\n"; 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 80ea3cf34..2cdd2f83b 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 @@ -23,8 +23,9 @@ class myclass { public: myclass(myclass&& that) noexcept; -#line 8 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 9 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" // operator=: (out this, move that) = { + // this = that; // name = that.name + "(CM)"; // std::cout << "ctor - move "; // } @@ -32,18 +33,18 @@ class myclass { public: auto operator=(myclass const& that) -> myclass& ; -#line 18 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 21 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" public: auto operator=(myclass&& that) noexcept -> myclass& ; -#line 22 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 26 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" public: explicit myclass(cpp2::in x); -#line 22 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 26 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" public: auto operator=(cpp2::in x) -> myclass& ; -#line 27 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 31 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" private: std::string name {"Henry"}; private: std::string addr {"123 Ford Dr."}; @@ -53,7 +54,7 @@ class myclass { cpp2::in suffix ) const -> void; -#line 37 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 41 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" }; auto main() -> int; @@ -68,6 +69,7 @@ auto main() -> int; , addr{ that.addr } #line 4 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" { + std::cout << "ctor - copy (GENERAL)"; } #line 4 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" @@ -76,48 +78,50 @@ auto main() -> int; , addr{ std::move(that).addr } #line 4 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" { + std::cout << "ctor - copy (GENERAL)"; } -#line 13 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 15 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" auto myclass::operator=(myclass const& that) -> myclass& { name = that.name; addr = that.addr + "(AC)"; -#line 15 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 18 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" std::cout << "assign - copy "; return *this; -#line 16 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 19 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" } auto myclass::operator=(myclass&& that) noexcept -> myclass& { name = std::move(that).name; addr = std::move(that).addr; -#line 19 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" + +#line 23 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" std::cout << "assign - move "; return *this; -#line 20 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 24 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" } myclass::myclass(cpp2::in x) : name{ x } -#line 22 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 26 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" { std::cout << "ctor - from string "; } -#line 22 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 26 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" auto myclass::operator=(cpp2::in x) -> myclass& { name = x; addr = "123 Ford Dr."; -#line 24 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 28 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" std::cout << "ctor - from string "; return *this; -#line 25 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 29 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" } -#line 30 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 34 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" auto myclass::print( cpp2::in prefix, @@ -125,7 +129,7 @@ auto main() -> int; ) const -> void { std::cout << prefix << "[ " + cpp2::to_string(name) + " | " + cpp2::to_string(addr) + " ]" << suffix; } -#line 39 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" +#line 43 "pure2-types-smf-and-that-4-provide-cpassign-and-mvassign.cpp2" auto main() -> int{ std::cout << "Function invoked Call syntax Results\n"; std::cout << "---------------------- ------------ ------------------------------------------------------\n"; 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 aae06789d..61e88b165 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 @@ -29,28 +29,31 @@ class myclass { public: auto operator=(myclass&& that) noexcept -> myclass& ; -#line 8 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" +#line 9 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" // operator=: (out this, move that) = { + // this = that; // name = that.name + "(CM)"; // std::cout << "ctor - move "; // } // operator=: (inout this, that) = { + // this = that; // addr = that.addr + "(AC)"; // std::cout << "assign - copy "; // } // operator=: (inout this, move that) = { + // this = that; // std::cout << "assign - move "; // } public: explicit myclass(cpp2::in x); -#line 22 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" +#line 26 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" public: auto operator=(cpp2::in x) -> myclass& ; -#line 27 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" +#line 31 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" private: std::string name {"Henry"}; private: std::string addr {"123 Ford Dr."}; @@ -60,7 +63,7 @@ class myclass { cpp2::in suffix ) const -> void; -#line 37 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" +#line 41 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" }; auto main() -> int; @@ -75,16 +78,18 @@ auto main() -> int; , addr{ that.addr } #line 4 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" { + std::cout << "ctor - copy (GENERAL)"; } #line 4 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" auto myclass::operator=(myclass const& that) -> myclass& { name = that.name; addr = that.addr; -#line 5 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" + +#line 6 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" std::cout << "ctor - copy (GENERAL)"; return *this; -#line 6 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" +#line 7 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" } #line 4 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" myclass::myclass(myclass&& that) noexcept @@ -92,38 +97,40 @@ auto main() -> int; , addr{ std::move(that).addr } #line 4 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" { + std::cout << "ctor - copy (GENERAL)"; } #line 4 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" auto myclass::operator=(myclass&& that) noexcept -> myclass& { name = std::move(that).name; addr = std::move(that).addr; -#line 5 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" + +#line 6 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" std::cout << "ctor - copy (GENERAL)"; return *this; -#line 6 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" +#line 7 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" } -#line 22 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" +#line 26 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" myclass::myclass(cpp2::in x) : name{ x } -#line 22 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" +#line 26 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" { std::cout << "ctor - from string "; } -#line 22 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" +#line 26 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" auto myclass::operator=(cpp2::in x) -> myclass& { name = x; addr = "123 Ford Dr."; -#line 24 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" +#line 28 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" std::cout << "ctor - from string "; return *this; -#line 25 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" +#line 29 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" } -#line 30 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" +#line 34 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" auto myclass::print( cpp2::in prefix, @@ -131,7 +138,7 @@ auto main() -> int; ) const -> void { std::cout << prefix << "[ " + cpp2::to_string(name) + " | " + cpp2::to_string(addr) + " ]" << suffix; } -#line 39 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" +#line 43 "pure2-types-smf-and-that-5-provide-nothing-but-general-case.cpp2" auto main() -> int{ std::cout << "Function invoked Call syntax Results\n"; std::cout << "---------------------- ------------ ------------------------------------------------------\n"; From 161569ea6e328e36315815ab038f310111a6262f Mon Sep 17 00:00:00 2001 From: Jo Bates Date: Sat, 24 Jun 2023 07:41:13 -0700 Subject: [PATCH 10/12] Let assignment operators not contain any member assignments --- source/cppfront.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/cppfront.cpp b/source/cppfront.cpp index e6f576705..f8a38eb45 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -4666,6 +4666,7 @@ class cppfront !found_explicit_init && !found_that_init && !found_default_init + && !n.is_assignment() ) { errors.emplace_back( @@ -4679,6 +4680,7 @@ class cppfront found_explicit_init || found_that_init || found_default_init + || n.is_assignment() ); // Emit the initializer... From 03590eb7111a60341b6c561567231061d2b197e4 Mon Sep 17 00:00:00 2001 From: Jo Bates Date: Sat, 24 Jun 2023 08:01:02 -0700 Subject: [PATCH 11/12] New regression tests for statements between member initializers --- ...s-smf-statements-between-member-inits.cpp2 | 158 ++++ ...es-smf-statements-between-member-inits.cpp | 789 ++++++++++++++++++ ...tatements-between-member-inits.cpp2.output | 2 + 3 files changed, 949 insertions(+) create mode 100644 regression-tests/pure2-types-smf-statements-between-member-inits.cpp2 create mode 100644 regression-tests/test-results/pure2-types-smf-statements-between-member-inits.cpp create mode 100644 regression-tests/test-results/pure2-types-smf-statements-between-member-inits.cpp2.output diff --git a/regression-tests/pure2-types-smf-statements-between-member-inits.cpp2 b/regression-tests/pure2-types-smf-statements-between-member-inits.cpp2 new file mode 100644 index 000000000..cd0f4d379 --- /dev/null +++ b/regression-tests/pure2-types-smf-statements-between-member-inits.cpp2 @@ -0,0 +1,158 @@ +f: (a1: i32) = { + _ = a1; +} + +t1: type = { + m1: i32 = 123; + m2: i32 = 456; + + operator=: (out this, that) = { + // m1 = 123 implied + // m2 = 456 implied + f(1); + f(2); + } +} + +t2: type = { + m1: i32 = 123; + m2: i32 = 456; + + operator=: (out this, that) = { + f(1); + f(2); + m1 = 3; + // m2 = 456 implied + f(4); + f(5); + } +} + +t3: type = { + m1: i32 = 123; + m2: i32 = 456; + + operator=: (out this, that) = { + // m1 = 123 implied + f(1); + f(2); + m2 = 3; + f(4); + f(5); + } +} + +t4: type = { + m1: i32 = 123; + m2: i32 = 456; + + operator=: (out this, that) = { + f(1); + f(2); + m1 = 3; + f(4); + f(5); + m2 = 6; + f(7); + f(8); + } +} + +t5: type = { + m1: i32 = 123; + m2: i32 = 456; + + operator=: (out this, that) = { + f(1); + f(2); + this = that; + // m1 = that.m1 implied + // m2 = that.m2 implied + // This comment should show up before f(3) + f(3); + f(4); + } +} + +t6: type = { + m1: i32 = 123; + m2: i32 = 456; + + operator=: (out this, that) = { + f(1); + f(2); + this = that; + f(3); + f(4); + m1 = 5; + // m2 = that.m2 implied + // This comment should show up before f(6) + f(6); + f(7); + } +} + +t7: type = { + m1: i32 = 123; + m2: i32 = 456; + + operator=: (out this, that) = { + f(1); + f(2); + this = that; + // m1 = that.m1 implied + f(3); + f(4); + m2 = 5; + // This comment should show up before f(6) + f(6); + f(7); + } +} + +t8: type = { + m1: i32 = 123; + m2: i32 = 456; + + operator=: (out this, that) = { + f(1); + f(2); + this = that; + f(3); + f(4); + m1 = 5; + f(6); + f(7); + m2 = 8; + // This comment should show up before f(9) + f(9); + f(10); + } +} + +t9: type = { + m1: i32 = 123; + m2: i32 = 456; + + operator=: (implicit out this, a1: i32) = { + _ = a1; + f(1); + f(2); + m1 = 3; + f(4); + f(5); + m2 = 6; + // This comment should show up before f(7) + f(7); + f(8); + } + + operator=: (inout this, that) = { + // This function shouldn't contain any member assignments. + // While it's a special member function that uses 'that', + // it's explicitly an assignment operator because of 'inout this', + // so we let the programmer avoid member assignment if they choose. + f(1); + f(2); + } +} diff --git a/regression-tests/test-results/pure2-types-smf-statements-between-member-inits.cpp b/regression-tests/test-results/pure2-types-smf-statements-between-member-inits.cpp new file mode 100644 index 000000000..59ef35a9d --- /dev/null +++ b/regression-tests/test-results/pure2-types-smf-statements-between-member-inits.cpp @@ -0,0 +1,789 @@ + +#define CPP2_USE_MODULES Yes + +//=== Cpp2 type declarations ==================================================== + + +#include "cpp2util.h" + + +#line 5 "pure2-types-smf-statements-between-member-inits.cpp2" +class t1; + + +#line 17 "pure2-types-smf-statements-between-member-inits.cpp2" +class t2; + + +#line 31 "pure2-types-smf-statements-between-member-inits.cpp2" +class t3; + + +#line 45 "pure2-types-smf-statements-between-member-inits.cpp2" +class t4; + + +#line 61 "pure2-types-smf-statements-between-member-inits.cpp2" +class t5; + + +#line 77 "pure2-types-smf-statements-between-member-inits.cpp2" +class t6; + + +#line 95 "pure2-types-smf-statements-between-member-inits.cpp2" +class t7; + + +#line 113 "pure2-types-smf-statements-between-member-inits.cpp2" +class t8; + + +#line 133 "pure2-types-smf-statements-between-member-inits.cpp2" +class t9; + + +//=== Cpp2 type definitions and function declarations =========================== + +#line 1 "pure2-types-smf-statements-between-member-inits.cpp2" +auto f(cpp2::in a1) -> void; + + +#line 5 "pure2-types-smf-statements-between-member-inits.cpp2" +class t1 { + private: cpp2::i32 m1 {123}; + private: cpp2::i32 m2 {456}; + + public: t1(t1 const& that); + +#line 9 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t1 const& that) -> t1& ; + +#line 9 "pure2-types-smf-statements-between-member-inits.cpp2" + public: t1(t1&& that) noexcept; + +#line 9 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t1&& that) noexcept -> t1& ; + + +#line 15 "pure2-types-smf-statements-between-member-inits.cpp2" +}; + +class t2 { + private: cpp2::i32 m1 {123}; + private: cpp2::i32 m2 {456}; + + public: t2(t2 const& that); + +#line 21 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t2 const& that) -> t2& ; + +#line 21 "pure2-types-smf-statements-between-member-inits.cpp2" + public: t2(t2&& that) noexcept; + +#line 21 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t2&& that) noexcept -> t2& ; + + +#line 29 "pure2-types-smf-statements-between-member-inits.cpp2" +}; + +class t3 { + private: cpp2::i32 m1 {123}; + private: cpp2::i32 m2 {456}; + + public: t3(t3 const& that); + +#line 35 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t3 const& that) -> t3& ; + +#line 35 "pure2-types-smf-statements-between-member-inits.cpp2" + public: t3(t3&& that) noexcept; + +#line 35 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t3&& that) noexcept -> t3& ; + + +#line 43 "pure2-types-smf-statements-between-member-inits.cpp2" +}; + +class t4 { + private: cpp2::i32 m1 {123}; + private: cpp2::i32 m2 {456}; + + public: t4(t4 const& that); + +#line 49 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t4 const& that) -> t4& ; + +#line 49 "pure2-types-smf-statements-between-member-inits.cpp2" + public: t4(t4&& that) noexcept; + +#line 49 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t4&& that) noexcept -> t4& ; + + +#line 59 "pure2-types-smf-statements-between-member-inits.cpp2" +}; + +class t5 { + private: cpp2::i32 m1 {123}; + private: cpp2::i32 m2 {456}; + + public: t5(t5 const& that); + +#line 65 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t5 const& that) -> t5& ; + +#line 65 "pure2-types-smf-statements-between-member-inits.cpp2" + public: t5(t5&& that) noexcept; + +#line 65 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t5&& that) noexcept -> t5& ; + + +#line 75 "pure2-types-smf-statements-between-member-inits.cpp2" +}; + +class t6 { + private: cpp2::i32 m1 {123}; + private: cpp2::i32 m2 {456}; + + public: t6(t6 const& that); + +#line 81 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t6 const& that) -> t6& ; + +#line 81 "pure2-types-smf-statements-between-member-inits.cpp2" + public: t6(t6&& that) noexcept; + +#line 81 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t6&& that) noexcept -> t6& ; + + +#line 93 "pure2-types-smf-statements-between-member-inits.cpp2" +}; + +class t7 { + private: cpp2::i32 m1 {123}; + private: cpp2::i32 m2 {456}; + + public: t7(t7 const& that); + +#line 99 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t7 const& that) -> t7& ; + +#line 99 "pure2-types-smf-statements-between-member-inits.cpp2" + public: t7(t7&& that) noexcept; + +#line 99 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t7&& that) noexcept -> t7& ; + + +#line 111 "pure2-types-smf-statements-between-member-inits.cpp2" +}; + +class t8 { + private: cpp2::i32 m1 {123}; + private: cpp2::i32 m2 {456}; + + public: t8(t8 const& that); + +#line 117 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t8 const& that) -> t8& ; + +#line 117 "pure2-types-smf-statements-between-member-inits.cpp2" + public: t8(t8&& that) noexcept; + +#line 117 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t8&& that) noexcept -> t8& ; + + +#line 131 "pure2-types-smf-statements-between-member-inits.cpp2" +}; + +class t9 { + private: cpp2::i32 m1 {123}; + private: cpp2::i32 m2 {456}; + + public: t9(cpp2::in a1); + +#line 137 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(cpp2::in a1) -> t9& ; + + +#line 150 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t9 const& that) -> t9& ; + +#line 150 "pure2-types-smf-statements-between-member-inits.cpp2" + public: auto operator=(t9&& that) noexcept -> t9& ; + + public: t9(t9 const&) = delete; /* No 'that' constructor, suppress copy */ + public: auto operator=(t9 const&) -> void = delete; + + +#line 158 "pure2-types-smf-statements-between-member-inits.cpp2" +}; + + +//=== Cpp2 function definitions ================================================= + +#line 1 "pure2-types-smf-statements-between-member-inits.cpp2" +auto f(cpp2::in a1) -> void{ + (void) a1; +} + +#line 9 "pure2-types-smf-statements-between-member-inits.cpp2" + t1::t1(t1 const& that){ + // m1 = 123 implied + // m2 = 456 implied + f(1); + f(2); + } +#line 9 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t1::operator=(t1 const& that) -> t1& { + m1 = 123; + m2 = 456; + +#line 12 "pure2-types-smf-statements-between-member-inits.cpp2" + f(1); + f(2); + return *this; +#line 14 "pure2-types-smf-statements-between-member-inits.cpp2" + } +#line 9 "pure2-types-smf-statements-between-member-inits.cpp2" + t1::t1(t1&& that) noexcept{ + +#line 12 "pure2-types-smf-statements-between-member-inits.cpp2" + f(1); + f(2); + } +#line 9 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t1::operator=(t1&& that) noexcept -> t1& { + m1 = 123; + m2 = 456; + +#line 12 "pure2-types-smf-statements-between-member-inits.cpp2" + f(1); + f(2); + return *this; +#line 14 "pure2-types-smf-statements-between-member-inits.cpp2" + } + +#line 21 "pure2-types-smf-statements-between-member-inits.cpp2" + t2::t2(t2 const& that) + : m1{ [&]() -> cpp2::i32 { + f(1); + f(2); + return 3; + }() } +#line 21 "pure2-types-smf-statements-between-member-inits.cpp2" + { + +#line 25 "pure2-types-smf-statements-between-member-inits.cpp2" + // m2 = 456 implied + f(4); + f(5); + } +#line 21 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t2::operator=(t2 const& that) -> t2& { + f(1); + f(2); + m1 = 3; + m2 = 456; + +#line 26 "pure2-types-smf-statements-between-member-inits.cpp2" + f(4); + f(5); + return *this; +#line 28 "pure2-types-smf-statements-between-member-inits.cpp2" + } +#line 21 "pure2-types-smf-statements-between-member-inits.cpp2" + t2::t2(t2&& that) noexcept + : m1{ [&]() -> cpp2::i32 { + f(1); + f(2); + return 3; + }() } +#line 21 "pure2-types-smf-statements-between-member-inits.cpp2" + { + +#line 26 "pure2-types-smf-statements-between-member-inits.cpp2" + f(4); + f(5); + } +#line 21 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t2::operator=(t2&& that) noexcept -> t2& { + f(1); + f(2); + m1 = 3; + m2 = 456; + +#line 26 "pure2-types-smf-statements-between-member-inits.cpp2" + f(4); + f(5); + return *this; +#line 28 "pure2-types-smf-statements-between-member-inits.cpp2" + } + +#line 35 "pure2-types-smf-statements-between-member-inits.cpp2" + t3::t3(t3 const& that) + : m2{ [&]() -> cpp2::i32 { + f(1); + f(2); + return 3; + }() } +#line 35 "pure2-types-smf-statements-between-member-inits.cpp2" + { + // m1 = 123 implied + +#line 40 "pure2-types-smf-statements-between-member-inits.cpp2" + f(4); + f(5); + } +#line 35 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t3::operator=(t3 const& that) -> t3& { + m1 = 123; + f(1); + f(2); + m2 = 3; + +#line 40 "pure2-types-smf-statements-between-member-inits.cpp2" + f(4); + f(5); + return *this; +#line 42 "pure2-types-smf-statements-between-member-inits.cpp2" + } +#line 35 "pure2-types-smf-statements-between-member-inits.cpp2" + t3::t3(t3&& that) noexcept + : m2{ [&]() -> cpp2::i32 { + f(1); + f(2); + return 3; + }() } +#line 35 "pure2-types-smf-statements-between-member-inits.cpp2" + { + +#line 40 "pure2-types-smf-statements-between-member-inits.cpp2" + f(4); + f(5); + } +#line 35 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t3::operator=(t3&& that) noexcept -> t3& { + m1 = 123; + f(1); + f(2); + m2 = 3; + +#line 40 "pure2-types-smf-statements-between-member-inits.cpp2" + f(4); + f(5); + return *this; +#line 42 "pure2-types-smf-statements-between-member-inits.cpp2" + } + +#line 49 "pure2-types-smf-statements-between-member-inits.cpp2" + t4::t4(t4 const& that) + : m1{ [&]() -> cpp2::i32 { + f(1); + f(2); + return 3; + }() } + , m2{ [&]() -> cpp2::i32 { + f(4); + f(5); + return 6; + }() } +#line 49 "pure2-types-smf-statements-between-member-inits.cpp2" + { + +#line 56 "pure2-types-smf-statements-between-member-inits.cpp2" + f(7); + f(8); + } +#line 49 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t4::operator=(t4 const& that) -> t4& { + f(1); + f(2); + m1 = 3; + f(4); + f(5); + m2 = 6; + +#line 56 "pure2-types-smf-statements-between-member-inits.cpp2" + f(7); + f(8); + return *this; +#line 58 "pure2-types-smf-statements-between-member-inits.cpp2" + } +#line 49 "pure2-types-smf-statements-between-member-inits.cpp2" + t4::t4(t4&& that) noexcept + : m1{ [&]() -> cpp2::i32 { + f(1); + f(2); + return 3; + }() } + , m2{ [&]() -> cpp2::i32 { + f(4); + f(5); + return 6; + }() } +#line 49 "pure2-types-smf-statements-between-member-inits.cpp2" + { + +#line 56 "pure2-types-smf-statements-between-member-inits.cpp2" + f(7); + f(8); + } +#line 49 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t4::operator=(t4&& that) noexcept -> t4& { + f(1); + f(2); + m1 = 3; + f(4); + f(5); + m2 = 6; + +#line 56 "pure2-types-smf-statements-between-member-inits.cpp2" + f(7); + f(8); + return *this; +#line 58 "pure2-types-smf-statements-between-member-inits.cpp2" + } + +#line 65 "pure2-types-smf-statements-between-member-inits.cpp2" + t5::t5(t5 const& that) + : m1{ [&]() -> cpp2::i32 { + f(1); + f(2); + return that.m1; + }() } + , m2{ that.m2 } +#line 65 "pure2-types-smf-statements-between-member-inits.cpp2" + { + +#line 69 "pure2-types-smf-statements-between-member-inits.cpp2" + // m1 = that.m1 implied + // m2 = that.m2 implied + // This comment should show up before f(3) + f(3); + f(4); + } +#line 65 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t5::operator=(t5 const& that) -> t5& { + f(1); + f(2); + m1 = that.m1; + m2 = that.m2; + +#line 72 "pure2-types-smf-statements-between-member-inits.cpp2" + f(3); + f(4); + return *this; +#line 74 "pure2-types-smf-statements-between-member-inits.cpp2" + } +#line 65 "pure2-types-smf-statements-between-member-inits.cpp2" + t5::t5(t5&& that) noexcept + : m1{ [&]() -> cpp2::i32 { + f(1); + f(2); + return std::move(that).m1; + }() } + , m2{ std::move(that).m2 } +#line 65 "pure2-types-smf-statements-between-member-inits.cpp2" + { + +#line 72 "pure2-types-smf-statements-between-member-inits.cpp2" + f(3); + f(4); + } +#line 65 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t5::operator=(t5&& that) noexcept -> t5& { + f(1); + f(2); + m1 = std::move(that).m1; + m2 = std::move(that).m2; + +#line 72 "pure2-types-smf-statements-between-member-inits.cpp2" + f(3); + f(4); + return *this; +#line 74 "pure2-types-smf-statements-between-member-inits.cpp2" + } + +#line 81 "pure2-types-smf-statements-between-member-inits.cpp2" + t6::t6(t6 const& that) + : m1{ [&]() -> cpp2::i32 { + f(1); + f(2); + f(3); + f(4); + return 5; + }() } + , m2{ that.m2 } +#line 81 "pure2-types-smf-statements-between-member-inits.cpp2" + { + +#line 88 "pure2-types-smf-statements-between-member-inits.cpp2" + // m2 = that.m2 implied + // This comment should show up before f(6) + f(6); + f(7); + } +#line 81 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t6::operator=(t6 const& that) -> t6& { + f(1); + f(2); + f(3); + f(4); + m1 = 5; + m2 = that.m2; + +#line 90 "pure2-types-smf-statements-between-member-inits.cpp2" + f(6); + f(7); + return *this; +#line 92 "pure2-types-smf-statements-between-member-inits.cpp2" + } +#line 81 "pure2-types-smf-statements-between-member-inits.cpp2" + t6::t6(t6&& that) noexcept + : m1{ [&]() -> cpp2::i32 { + f(1); + f(2); + f(3); + f(4); + return 5; + }() } + , m2{ std::move(that).m2 } +#line 81 "pure2-types-smf-statements-between-member-inits.cpp2" + { + +#line 90 "pure2-types-smf-statements-between-member-inits.cpp2" + f(6); + f(7); + } +#line 81 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t6::operator=(t6&& that) noexcept -> t6& { + f(1); + f(2); + f(3); + f(4); + m1 = 5; + m2 = std::move(that).m2; + +#line 90 "pure2-types-smf-statements-between-member-inits.cpp2" + f(6); + f(7); + return *this; +#line 92 "pure2-types-smf-statements-between-member-inits.cpp2" + } + +#line 99 "pure2-types-smf-statements-between-member-inits.cpp2" + t7::t7(t7 const& that) + : m1{ [&]() -> cpp2::i32 { + f(1); + f(2); + return that.m1; + }() } + , m2{ [&]() -> cpp2::i32 { + f(3); + f(4); + return 5; + }() } +#line 99 "pure2-types-smf-statements-between-member-inits.cpp2" + { + +#line 103 "pure2-types-smf-statements-between-member-inits.cpp2" + // m1 = that.m1 implied + +#line 107 "pure2-types-smf-statements-between-member-inits.cpp2" + // This comment should show up before f(6) + f(6); + f(7); + } +#line 99 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t7::operator=(t7 const& that) -> t7& { + f(1); + f(2); + m1 = that.m1; + f(3); + f(4); + m2 = 5; + +#line 108 "pure2-types-smf-statements-between-member-inits.cpp2" + f(6); + f(7); + return *this; +#line 110 "pure2-types-smf-statements-between-member-inits.cpp2" + } +#line 99 "pure2-types-smf-statements-between-member-inits.cpp2" + t7::t7(t7&& that) noexcept + : m1{ [&]() -> cpp2::i32 { + f(1); + f(2); + return std::move(that).m1; + }() } + , m2{ [&]() -> cpp2::i32 { + f(3); + f(4); + return 5; + }() } +#line 99 "pure2-types-smf-statements-between-member-inits.cpp2" + { + +#line 108 "pure2-types-smf-statements-between-member-inits.cpp2" + f(6); + f(7); + } +#line 99 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t7::operator=(t7&& that) noexcept -> t7& { + f(1); + f(2); + m1 = std::move(that).m1; + f(3); + f(4); + m2 = 5; + +#line 108 "pure2-types-smf-statements-between-member-inits.cpp2" + f(6); + f(7); + return *this; +#line 110 "pure2-types-smf-statements-between-member-inits.cpp2" + } + +#line 117 "pure2-types-smf-statements-between-member-inits.cpp2" + t8::t8(t8 const& that) + : m1{ [&]() -> cpp2::i32 { + f(1); + f(2); + f(3); + f(4); + return 5; + }() } + , m2{ [&]() -> cpp2::i32 { + f(6); + f(7); + return 8; + }() } +#line 117 "pure2-types-smf-statements-between-member-inits.cpp2" + { + +#line 127 "pure2-types-smf-statements-between-member-inits.cpp2" + // This comment should show up before f(9) + f(9); + f(10); + } +#line 117 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t8::operator=(t8 const& that) -> t8& { + f(1); + f(2); + f(3); + f(4); + m1 = 5; + f(6); + f(7); + m2 = 8; + +#line 128 "pure2-types-smf-statements-between-member-inits.cpp2" + f(9); + f(10); + return *this; +#line 130 "pure2-types-smf-statements-between-member-inits.cpp2" + } +#line 117 "pure2-types-smf-statements-between-member-inits.cpp2" + t8::t8(t8&& that) noexcept + : m1{ [&]() -> cpp2::i32 { + f(1); + f(2); + f(3); + f(4); + return 5; + }() } + , m2{ [&]() -> cpp2::i32 { + f(6); + f(7); + return 8; + }() } +#line 117 "pure2-types-smf-statements-between-member-inits.cpp2" + { + +#line 128 "pure2-types-smf-statements-between-member-inits.cpp2" + f(9); + f(10); + } +#line 117 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t8::operator=(t8&& that) noexcept -> t8& { + f(1); + f(2); + f(3); + f(4); + m1 = 5; + f(6); + f(7); + m2 = 8; + +#line 128 "pure2-types-smf-statements-between-member-inits.cpp2" + f(9); + f(10); + return *this; +#line 130 "pure2-types-smf-statements-between-member-inits.cpp2" + } + +#line 137 "pure2-types-smf-statements-between-member-inits.cpp2" + t9::t9(cpp2::in a1) + : m1{ [&]() -> cpp2::i32 { + (void) a1; + f(1); + f(2); + return 3; + }() } + , m2{ [&]() -> cpp2::i32 { + f(4); + f(5); + return 6; + }() } +#line 137 "pure2-types-smf-statements-between-member-inits.cpp2" + { + +#line 145 "pure2-types-smf-statements-between-member-inits.cpp2" + // This comment should show up before f(7) + f(7); + f(8); + } +#line 137 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t9::operator=(cpp2::in a1) -> t9& { + (void) a1; + f(1); + f(2); + m1 = 3; + f(4); + f(5); + m2 = 6; + +#line 146 "pure2-types-smf-statements-between-member-inits.cpp2" + f(7); + f(8); + return *this; +#line 148 "pure2-types-smf-statements-between-member-inits.cpp2" + } + + auto t9::operator=(t9 const& that) -> t9& { + // This function shouldn't contain any member assignments. + // While it's a special member function that uses 'that', + // it's explicitly an assignment operator because of 'inout this', + // so we let the programmer avoid member assignment if they choose. + f(1); + f(2); + return *this; +#line 157 "pure2-types-smf-statements-between-member-inits.cpp2" + } +#line 150 "pure2-types-smf-statements-between-member-inits.cpp2" + auto t9::operator=(t9&& that) noexcept -> t9& { + +#line 155 "pure2-types-smf-statements-between-member-inits.cpp2" + f(1); + f(2); + return *this; +#line 157 "pure2-types-smf-statements-between-member-inits.cpp2" + } + diff --git a/regression-tests/test-results/pure2-types-smf-statements-between-member-inits.cpp2.output b/regression-tests/test-results/pure2-types-smf-statements-between-member-inits.cpp2.output new file mode 100644 index 000000000..4981c8c5e --- /dev/null +++ b/regression-tests/test-results/pure2-types-smf-statements-between-member-inits.cpp2.output @@ -0,0 +1,2 @@ +pure2-types-smf-statements-between-member-inits.cpp2... ok (all Cpp2, passes safety checks) + From fcaec79d55c5b97f94b693451adabba022cd23df Mon Sep 17 00:00:00 2001 From: Jo Bates Date: Sat, 24 Jun 2023 14:59:18 -0700 Subject: [PATCH 12/12] Use decltype(auto) as the return type of member initializer IIFEs --- ...2-types-order-independence-and-nesting.cpp | 2 +- ...es-smf-statements-between-member-inits.cpp | 44 +++++++++---------- source/cppfront.cpp | 3 +- 3 files changed, 24 insertions(+), 25 deletions(-) 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 e4d50f1e8..919820ea1 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 @@ -114,7 +114,7 @@ namespace N { #line 10 "pure2-types-order-independence-and-nesting.cpp2" X::X(cpp2::out y) - : py{ [&]() -> Y* { + : py{ [&]() -> decltype(auto) { y.construct(&(*this)); return &y.value(); }() } diff --git a/regression-tests/test-results/pure2-types-smf-statements-between-member-inits.cpp b/regression-tests/test-results/pure2-types-smf-statements-between-member-inits.cpp index 59ef35a9d..30dbaaa49 100644 --- a/regression-tests/test-results/pure2-types-smf-statements-between-member-inits.cpp +++ b/regression-tests/test-results/pure2-types-smf-statements-between-member-inits.cpp @@ -272,7 +272,7 @@ auto f(cpp2::in a1) -> void{ #line 21 "pure2-types-smf-statements-between-member-inits.cpp2" t2::t2(t2 const& that) - : m1{ [&]() -> cpp2::i32 { + : m1{ [&]() -> decltype(auto) { f(1); f(2); return 3; @@ -300,7 +300,7 @@ auto f(cpp2::in a1) -> void{ } #line 21 "pure2-types-smf-statements-between-member-inits.cpp2" t2::t2(t2&& that) noexcept - : m1{ [&]() -> cpp2::i32 { + : m1{ [&]() -> decltype(auto) { f(1); f(2); return 3; @@ -328,7 +328,7 @@ auto f(cpp2::in a1) -> void{ #line 35 "pure2-types-smf-statements-between-member-inits.cpp2" t3::t3(t3 const& that) - : m2{ [&]() -> cpp2::i32 { + : m2{ [&]() -> decltype(auto) { f(1); f(2); return 3; @@ -356,7 +356,7 @@ auto f(cpp2::in a1) -> void{ } #line 35 "pure2-types-smf-statements-between-member-inits.cpp2" t3::t3(t3&& that) noexcept - : m2{ [&]() -> cpp2::i32 { + : m2{ [&]() -> decltype(auto) { f(1); f(2); return 3; @@ -384,12 +384,12 @@ auto f(cpp2::in a1) -> void{ #line 49 "pure2-types-smf-statements-between-member-inits.cpp2" t4::t4(t4 const& that) - : m1{ [&]() -> cpp2::i32 { + : m1{ [&]() -> decltype(auto) { f(1); f(2); return 3; }() } - , m2{ [&]() -> cpp2::i32 { + , m2{ [&]() -> decltype(auto) { f(4); f(5); return 6; @@ -418,12 +418,12 @@ auto f(cpp2::in a1) -> void{ } #line 49 "pure2-types-smf-statements-between-member-inits.cpp2" t4::t4(t4&& that) noexcept - : m1{ [&]() -> cpp2::i32 { + : m1{ [&]() -> decltype(auto) { f(1); f(2); return 3; }() } - , m2{ [&]() -> cpp2::i32 { + , m2{ [&]() -> decltype(auto) { f(4); f(5); return 6; @@ -453,7 +453,7 @@ auto f(cpp2::in a1) -> void{ #line 65 "pure2-types-smf-statements-between-member-inits.cpp2" t5::t5(t5 const& that) - : m1{ [&]() -> cpp2::i32 { + : m1{ [&]() -> decltype(auto) { f(1); f(2); return that.m1; @@ -484,7 +484,7 @@ auto f(cpp2::in a1) -> void{ } #line 65 "pure2-types-smf-statements-between-member-inits.cpp2" t5::t5(t5&& that) noexcept - : m1{ [&]() -> cpp2::i32 { + : m1{ [&]() -> decltype(auto) { f(1); f(2); return std::move(that).m1; @@ -513,7 +513,7 @@ auto f(cpp2::in a1) -> void{ #line 81 "pure2-types-smf-statements-between-member-inits.cpp2" t6::t6(t6 const& that) - : m1{ [&]() -> cpp2::i32 { + : m1{ [&]() -> decltype(auto) { f(1); f(2); f(3); @@ -547,7 +547,7 @@ auto f(cpp2::in a1) -> void{ } #line 81 "pure2-types-smf-statements-between-member-inits.cpp2" t6::t6(t6&& that) noexcept - : m1{ [&]() -> cpp2::i32 { + : m1{ [&]() -> decltype(auto) { f(1); f(2); f(3); @@ -580,12 +580,12 @@ auto f(cpp2::in a1) -> void{ #line 99 "pure2-types-smf-statements-between-member-inits.cpp2" t7::t7(t7 const& that) - : m1{ [&]() -> cpp2::i32 { + : m1{ [&]() -> decltype(auto) { f(1); f(2); return that.m1; }() } - , m2{ [&]() -> cpp2::i32 { + , m2{ [&]() -> decltype(auto) { f(3); f(4); return 5; @@ -618,12 +618,12 @@ auto f(cpp2::in a1) -> void{ } #line 99 "pure2-types-smf-statements-between-member-inits.cpp2" t7::t7(t7&& that) noexcept - : m1{ [&]() -> cpp2::i32 { + : m1{ [&]() -> decltype(auto) { f(1); f(2); return std::move(that).m1; }() } - , m2{ [&]() -> cpp2::i32 { + , m2{ [&]() -> decltype(auto) { f(3); f(4); return 5; @@ -653,14 +653,14 @@ auto f(cpp2::in a1) -> void{ #line 117 "pure2-types-smf-statements-between-member-inits.cpp2" t8::t8(t8 const& that) - : m1{ [&]() -> cpp2::i32 { + : m1{ [&]() -> decltype(auto) { f(1); f(2); f(3); f(4); return 5; }() } - , m2{ [&]() -> cpp2::i32 { + , m2{ [&]() -> decltype(auto) { f(6); f(7); return 8; @@ -692,14 +692,14 @@ auto f(cpp2::in a1) -> void{ } #line 117 "pure2-types-smf-statements-between-member-inits.cpp2" t8::t8(t8&& that) noexcept - : m1{ [&]() -> cpp2::i32 { + : m1{ [&]() -> decltype(auto) { f(1); f(2); f(3); f(4); return 5; }() } - , m2{ [&]() -> cpp2::i32 { + , m2{ [&]() -> decltype(auto) { f(6); f(7); return 8; @@ -731,13 +731,13 @@ auto f(cpp2::in a1) -> void{ #line 137 "pure2-types-smf-statements-between-member-inits.cpp2" t9::t9(cpp2::in a1) - : m1{ [&]() -> cpp2::i32 { + : m1{ [&]() -> decltype(auto) { (void) a1; f(1); f(2); return 3; }() } - , m2{ [&]() -> cpp2::i32 { + , m2{ [&]() -> decltype(auto) { f(4); f(5); return 6; diff --git a/source/cppfront.cpp b/source/cppfront.cpp index f8a38eb45..038070cfd 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -4757,8 +4757,7 @@ class cppfront auto& mem_inits = current_functions.back().prolog.mem_inits; if (!pending_statements.empty()) { - auto object_type = print_to_string( *(*object)->get_object_type() ); - mem_inits.push_back(separator + object_name + "{ [&]() -> " + object_type + " {"); + mem_inits.push_back(separator + object_name + "{ [&]() -> decltype(auto) {"); for (auto statement : pending_statements) { mem_inits.push_back( " " + print_to_string(*statement, false) + ";"