diff --git a/regression-tests/pure2-bugfix-for-ufcs-name-lookup.cpp2 b/regression-tests/pure2-bugfix-for-ufcs-name-lookup.cpp2 index e82c5d06b..6446c2458 100644 --- a/regression-tests/pure2-bugfix-for-ufcs-name-lookup.cpp2 +++ b/regression-tests/pure2-bugfix-for-ufcs-name-lookup.cpp2 @@ -12,10 +12,10 @@ ns: namespace = { f: (_) -> int == 1; } // namespace ns -// v: @struct type = { -// f :== :(_) 0; // Pending on #706. -// g: (i) i.f(); -// } +v: @struct type = { + f :== :(_) = 0; + g: (i) = _ = i.f(); +} main: () = { { diff --git a/regression-tests/pure2-type-and-namespace-aliases.cpp2 b/regression-tests/pure2-type-and-namespace-aliases.cpp2 index b739ccd6b..ae2cfcd81 100644 --- a/regression-tests/pure2-type-and-namespace-aliases.cpp2 +++ b/regression-tests/pure2-type-and-namespace-aliases.cpp2 @@ -33,3 +33,25 @@ main: () = { myfunc2 :== myfunc; myfunc2(); } + +myclass5: type == myclass4; + +myclass3: @struct type = { + // Defined inline. + i0 :== :std::array = (0); + i1 :== i0; + i3: _ == i0; + i7 :== :() = 0; + + // Defined out of line. + o2: myclass3 == myclass3(); + o4: myclass3 == o2; + o5: myclass4 == myclass4(); + o6: myclass5 == myclass5(); +} + +myclass4: @struct type = { } + +myclass6: @struct type = { + v: _ requires true == 0; +} diff --git a/regression-tests/test-results/pure2-bugfix-for-ufcs-name-lookup.cpp b/regression-tests/test-results/pure2-bugfix-for-ufcs-name-lookup.cpp index ae5a4442e..619c27914 100644 --- a/regression-tests/test-results/pure2-bugfix-for-ufcs-name-lookup.cpp +++ b/regression-tests/test-results/pure2-bugfix-for-ufcs-name-lookup.cpp @@ -22,6 +22,8 @@ namespace ns { } +class v; + //=== Cpp2 type definitions and function declarations =========================== @@ -41,10 +43,10 @@ namespace ns { [[nodiscard]] constexpr auto f([[maybe_unused]] auto const& unnamed_param_1) -> int; } // namespace ns -// v: @struct type = { -// f :== :(_) 0; // Pending on #706. -// g: (i) i.f(); -// } +class v { + public: static constexpr auto f = []([[maybe_unused]] auto const& unnamed_param_1) -> decltype(auto) { return 0; }; + public: [[nodiscard]] static auto g(auto const& i) -> decltype(auto); +}; auto main() -> int; @@ -64,6 +66,9 @@ namespace ns { [[nodiscard]] constexpr auto f([[maybe_unused]] auto const& unnamed_param_1) -> int { return 1; } } +#line 17 "pure2-bugfix-for-ufcs-name-lookup.cpp2" + [[nodiscard]] auto v::g(auto const& i) -> decltype(auto) { return static_cast(CPP2_UFCS(f)(i)); } + #line 20 "pure2-bugfix-for-ufcs-name-lookup.cpp2" auto main() -> int{ { diff --git a/regression-tests/test-results/pure2-type-and-namespace-aliases.cpp b/regression-tests/test-results/pure2-type-and-namespace-aliases.cpp index 0e7860066..7caa154c1 100644 --- a/regression-tests/test-results/pure2-type-and-namespace-aliases.cpp +++ b/regression-tests/test-results/pure2-type-and-namespace-aliases.cpp @@ -21,6 +21,16 @@ class myclass; template class myclass2; +#line 39 "pure2-type-and-namespace-aliases.cpp2" +class myclass3; + + +#line 53 "pure2-type-and-namespace-aliases.cpp2" +class myclass4; + +template class myclass6; + + //=== Cpp2 type definitions and function declarations =========================== #line 1 "pure2-type-and-namespace-aliases.cpp2" @@ -60,6 +70,31 @@ template class myclass2 { auto main() -> int; +#line 37 "pure2-type-and-namespace-aliases.cpp2" +using myclass5 = myclass4; + +class myclass3 { + // Defined inline. + public: static constexpr auto i0 = std::array{0}; + public: static constexpr auto i1 = i0; + public: static constexpr auto i3 = i0; + public: static constexpr auto i7 = []() -> decltype(auto) { return 0; }; + + // Defined out of line. + public: static const myclass3 o2; + public: static const myclass3 o4; + public: static const myclass4 o5; + public: static const myclass5 o6; +}; + +class myclass4 {}; + +template class myclass6 { +#line 56 "pure2-type-and-namespace-aliases.cpp2" + public: template +CPP2_REQUIRES_ (true) static constexpr auto v = 0; +}; + //=== Cpp2 function definitions ================================================= #line 1 "pure2-type-and-namespace-aliases.cpp2" @@ -94,3 +129,9 @@ auto main() -> int{ myfunc2(); } +#line 47 "pure2-type-and-namespace-aliases.cpp2" + inline CPP2_CONSTEXPR myclass3 myclass3::o2{ myclass3() }; + inline CPP2_CONSTEXPR myclass3 myclass3::o4{ o2 }; + inline CPP2_CONSTEXPR myclass4 myclass3::o5{ myclass4() }; + inline CPP2_CONSTEXPR myclass5 myclass3::o6{ myclass5() }; + diff --git a/source/to_cpp1.h b/source/to_cpp1.h index 4a891ad1d..93c790510 100644 --- a/source/to_cpp1.h +++ b/source/to_cpp1.h @@ -1255,7 +1255,7 @@ class cppfront // Now we'll open the Cpp1 file auto cpp1_filename = sourcefile.substr(0, std::ssize(sourcefile) - 1); - + // Use explicit filename override if present, // otherwise strip leading path if (!flag_cpp1_filename.empty()) { @@ -3458,12 +3458,12 @@ class cppfront last_was_prefixed = true; } - // Handle the other Cpp2 postfix operators that stay postfix in Cpp1 + // Handle the other Cpp2 postfix operators that stay postfix in Cpp1 // (currently '...' for expansion, not when used as a range operator) else if ( is_postfix_operator(i->op->type()) && !i->last_expr // not being used as a range operator - ) + ) { flush_args(); suffix.emplace_back( i->op->to_string(), i->op->position()); @@ -3504,7 +3504,7 @@ class cppfront } auto print = print_to_string( - *i->id_expr, + *i->id_expr, false, // not a local name i->op->type() == lexeme::Dot || i->op->type() == lexeme::DotDot // member access ); @@ -4453,8 +4453,8 @@ class cppfront { assert(n.declaration); auto is_param_to_namespace_scope_type = - n.declaration->parent_is_type() - && n.declaration->parent_declaration->parent_is_namespace() + n.declaration->parent_is_type() + && n.declaration->parent_declaration->parent_is_namespace() ; auto emit_in_phase_0 = @@ -5091,7 +5091,7 @@ class cppfront || n.is_swap() || n.is_destructor() || ( - n.my_decl + n.my_decl && generating_move_from == n.my_decl ) ) @@ -5105,7 +5105,7 @@ class cppfront if ( n.is_assignment() || ( - n.my_decl + n.my_decl && generating_assignment_from == n.my_decl ) ) @@ -5776,8 +5776,18 @@ class cppfront auto& a = std::get(n.type); assert(a); + // Helper for aliases that emit as a defining declaration. + auto const type_scope_object_alias_emits_in_phase_1_only = [&]() { + assert( + n.parent_is_type() + && n.is_object_alias() + ); + return !a->type_id + || a->type_id->is_wildcard(); + }; + // Namespace-scope aliases are emitted in phase 1, - // type-scope object aliases in both phases 1 and 2, and + // type-scope object aliases is emitted in phase 1 and maybe 2, and // function-scope aliases in phase 2 if ( ( @@ -5789,6 +5799,7 @@ class cppfront n.parent_is_type() && n.is_object_alias() && printer.get_phase() == printer.phase2_func_defs + && !type_scope_object_alias_emits_in_phase_1_only() ) || ( @@ -5863,7 +5874,7 @@ class cppfront // Handle object aliases: // - at function scope, it's const& // - at namespace scope, it's inline constexpr - // - at type scope, it's also inline constexpr but see note (*) below + // - at type scope, it's also static constexpr but see note (*) below else if (a->is_object_alias()) { auto type = std::string{"auto"}; @@ -5888,13 +5899,26 @@ class cppfront } }; - // (*) If this is at type scope, Cpp1 requires an out-of-line declaration dance - // for some cases to work - see https://stackoverflow.com/questions/11928089/ if (n.parent_is_type()) { assert (n.parent_declaration->name()); - if (printer.get_phase() == printer.phase1_type_defs_func_decls) { + if (type_scope_object_alias_emits_in_phase_1_only()) { + if (printer.get_phase() == printer.phase1_type_defs_func_decls) { + printer.print_cpp2( + "static constexpr " + + type + " " + + print_to_string(*n.identifier) + + " = " + + print_to_string( *std::get(a->initializer) ) + + ";\n", + n.position() + ); + } + } + // At type scope, Cpp1 requires an out-of-line declaration dance + // for some cases to work - see https://stackoverflow.com/questions/11928089/ + else if (printer.get_phase() == printer.phase1_type_defs_func_decls) { printer.print_cpp2( "static const " + type + " " @@ -6072,7 +6096,10 @@ class cppfront // In class definitions, emit the explicit access specifier if there // is one, or default to private for data and public for functions - if (printer.get_phase() == printer.phase1_type_defs_func_decls) + if ( + printer.get_phase() == printer.phase1_type_defs_func_decls + && n.identifier + ) { if (!n.is_default_access()) { assert (is_in_type); @@ -6995,8 +7022,8 @@ class cppfront return; } } - printer.preempt_position_push(n.position()); - emit( *type, {}, print_to_string(*n.identifier) ); + printer.preempt_position_push(n.position()); + emit( *type, {}, print_to_string(*n.identifier) ); printer.preempt_position_pop(); if (