Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(to_cpp1): define type-scope object alias with wildcard type inline #706

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions regression-tests/pure2-bugfix-for-ufcs-name-lookup.cpp2
Original file line number Diff line number Diff line change
Expand Up @@ -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: () = {
{
Expand Down
22 changes: 22 additions & 0 deletions regression-tests/pure2-type-and-namespace-aliases.cpp2
Original file line number Diff line number Diff line change
Expand Up @@ -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 <T: type> type = {
v: <U> _ requires true == 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ namespace ns {

}

class v;


//=== Cpp2 type definitions and function declarations ===========================

Expand All @@ -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;

Expand All @@ -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<void>(CPP2_UFCS(f)(i)); }

#line 20 "pure2-bugfix-for-ufcs-name-lookup.cpp2"
auto main() -> int{
{
Expand Down
41 changes: 41 additions & 0 deletions regression-tests/test-results/pure2-type-and-namespace-aliases.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ class myclass;
template<typename T> class myclass2;


#line 39 "pure2-type-and-namespace-aliases.cpp2"
class myclass3;


#line 53 "pure2-type-and-namespace-aliases.cpp2"
class myclass4;

template<typename T> class myclass6;


//=== Cpp2 type definitions and function declarations ===========================

#line 1 "pure2-type-and-namespace-aliases.cpp2"
Expand Down Expand Up @@ -60,6 +70,31 @@ template<typename T> 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<typename T> class myclass6 {
#line 56 "pure2-type-and-namespace-aliases.cpp2"
public: template<typename U>
CPP2_REQUIRES_ (true) static constexpr auto v = 0;
};

//=== Cpp2 function definitions =================================================

#line 1 "pure2-type-and-namespace-aliases.cpp2"
Expand Down Expand Up @@ -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() };

59 changes: 43 additions & 16 deletions source/to_cpp1.h
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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
);
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -5091,7 +5091,7 @@ class cppfront
|| n.is_swap()
|| n.is_destructor()
|| (
n.my_decl
n.my_decl
&& generating_move_from == n.my_decl
)
)
Expand All @@ -5105,7 +5105,7 @@ class cppfront
if (
n.is_assignment()
|| (
n.my_decl
n.my_decl
&& generating_assignment_from == n.my_decl
)
)
Expand Down Expand Up @@ -5776,8 +5776,18 @@ class cppfront
auto& a = std::get<declaration_node::an_alias>(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 (
(
Expand All @@ -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()
)
||
(
Expand Down Expand Up @@ -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"};
Expand All @@ -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<alias_node::an_object>(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 + " "
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 (
Expand Down
Loading