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(cpp1): account for initializers of members lowered as bases #478

Closed
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
base: type = {
public x: i32 = -1;
operator=: (out this) = { }
operator=: (out this, y: i32) = x = y;
}
derived: @ struct type = {
y: i32;
this: base = 42;
}
main: () = { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
base: type = {
public x: i32 = -1;
operator=: (out this) = { }
operator=: (out this, y: i32) = x = y;
}
derived: @ struct type = {
y: i32 = 2;
this: base;
}
main: () = { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
base: type = {
public x: i32 = -1;
operator=: (out this) = { }
operator=: (implicit out this, y: i32) = x = y;
}
derived: type = {
y: i32 = 2;
this: base = 42;
}
derived2: @ struct type = {
y: i32;
this: base;
z: i32 = 3;
}
main: () = {
[[assert: derived().y == 2]]
[[assert: derived().x == 42]]
_ = :derived2 = (1, 2, 3);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pure2-bugfix-for-default-constructor-this-initializer-1-error.cpp2...
pure2-bugfix-for-default-constructor-this-initializer-1-error.cpp2(8,3): error: '@struct' scope object can have an initializer if it is ordered after all 'this' objects only

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pure2-bugfix-for-default-constructor-this-initializer-2-error.cpp2...
pure2-bugfix-for-default-constructor-this-initializer-2-error.cpp2(7,3): error: '@struct' scope object can have an initializer if it is ordered after all 'this' objects only

Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@

#define CPP2_USE_MODULES Yes

//=== Cpp2 type declarations ====================================================


#include "cpp2util.h"

#line 1 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
class base;

#line 6 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
class derived;

#line 10 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
class derived2;


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

#line 1 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
class base {
public: cpp2::i32 x {-1};
public: explicit base();
public: base(cpp2::in<cpp2::i32> y);
#line 4 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
public: auto operator=(cpp2::in<cpp2::i32> y) -> base& ;

public: base(base const&) = delete; /* No 'that' constructor, suppress copy */
public: auto operator=(base const&) -> void = delete;
#line 5 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
};

struct derived_y_as_base { cpp2::i32 y; };
#line 6 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
class derived: public derived_y_as_base, public base {
public: explicit derived();

public: derived(derived const&) = delete; /* No 'that' constructor, suppress copy */
public: auto operator=(derived const&) -> void = delete;


#line 9 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
};

struct derived2_y_as_base { cpp2::i32 y; };
#line 10 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
class derived2: public derived2_y_as_base, public base {

#line 13 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
public: cpp2::i32 z {3};
};
auto main() -> int;


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


#line 3 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
base::base(){}
base::base(cpp2::in<cpp2::i32> y)
: x{ y }
#line 4 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
{ }
#line 4 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
auto base::operator=(cpp2::in<cpp2::i32> y) -> base& {
x = y;
return *this;
#line 4 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
}

derived::derived()
: derived_y_as_base{ 2 }
, base{ 42 }{}

#line 15 "pure2-bugfix-for-default-constructor-this-initializer.cpp2"
auto main() -> int{
cpp2::Default.expects(derived().y==2, "");
cpp2::Default.expects(derived().x==42, "");
(void) derived2{1, 2, 3};
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pure2-bugfix-for-default-constructor-this-initializer.cpp2... ok (all Cpp2, passes safety checks)

92 changes: 73 additions & 19 deletions source/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,7 @@ struct postfix_expression_node
if (ops.empty()) {
return false;
} else {
return (ops.front().op->type() == lexeme::Ampersand
return (ops.front().op->type() == lexeme::Ampersand
|| ops.front().op->type() == lexeme::Tilde);
}
}
Expand Down Expand Up @@ -2625,6 +2625,51 @@ struct declaration_node
}


struct should_add_default_constructor_res{
bool value;
source_position pos_of_emitted_base_with_initializer;
};
auto should_add_default_constructor() const
-> should_add_default_constructor_res
{
if (
!is_type()
|| !initializer
|| !initializer->is_compound()
)
{
return {false, {}};
}

source_position pos = {};
bool found_initializer = false;
bool found_initializer_in_base = false;
for (auto& stmt: std::get<statement_node::compound>(initializer->statement)->statements)
{
auto& decl = std::get<statement_node::declaration>(stmt->statement);
assert(decl);
if (decl->is_constructor()) {
return {false, {}};
}
if (!decl->is_object()) {
continue;
}
if (decl->has_initializer()) {
found_initializer = true;
if (!found_initializer_in_base) {
pos = decl->position();
}
}
assert(decl->name());
if (decl->has_name("this") && found_initializer) {
found_initializer_in_base = true;
}
}

return {found_initializer_in_base, pos};
}


auto get_decl_if_type_scope_object_name_before_a_base_type( std::string_view s ) const
-> declaration_node const*
{
Expand Down Expand Up @@ -3993,7 +4038,7 @@ class parser
// || curr().type() == lexeme::LeftBrace
)
{
bool inside_initializer = (
bool inside_initializer = (
peek(-1) && peek(-1)->type() == lexeme::Assignment
);
auto open_paren = &curr();
Expand All @@ -4015,12 +4060,12 @@ class parser
next();
if (
curr().type() != lexeme::Semicolon
&& curr().type() != lexeme::RightParen
&& curr().type() != lexeme::RightBracket
&& curr().type() != lexeme::RightParen
&& curr().type() != lexeme::RightBracket
&& curr().type() != lexeme::Comma
) {
expr_list->inside_initializer = false;
}
}
n->expr = std::move(expr_list);
return n;
}
Expand Down Expand Up @@ -4374,7 +4419,7 @@ class parser
//G shift-expression '<<' additive-expression
//G shift-expression '>>' additive-expression
//G
auto shift_expression(bool allow_angle_operators = true)
auto shift_expression(bool allow_angle_operators = true)
-> auto
{
if (allow_angle_operators) {
Expand Down Expand Up @@ -4409,7 +4454,7 @@ class parser
//G shift-expression
//G compare-expression '<=>' shift-expression
//G
auto compare_expression(bool allow_angle_operators = true)
auto compare_expression(bool allow_angle_operators = true)
-> auto
{
return binary_expression<compare_expression_node> (
Expand All @@ -4425,7 +4470,7 @@ class parser
//G relational-expression '<=' compare-expression
//G relational-expression '>=' compare-expression
//G
auto relational_expression(bool allow_angle_operators = true)
auto relational_expression(bool allow_angle_operators = true)
-> auto
{
if (allow_angle_operators) {
Expand Down Expand Up @@ -4457,7 +4502,7 @@ class parser
//G equality-expression '==' relational-expression
//G equality-expression '!=' relational-expression
//G
auto equality_expression(bool allow_angle_operators = true)
auto equality_expression(bool allow_angle_operators = true)
-> auto
{
return binary_expression<equality_expression_node> (
Expand All @@ -4470,7 +4515,7 @@ class parser
//G equality-expression
//G bit-and-expression '&' equality-expression
//G
auto bit_and_expression(bool allow_angle_operators = true)
auto bit_and_expression(bool allow_angle_operators = true)
-> auto
{
return binary_expression<bit_and_expression_node> (
Expand All @@ -4483,7 +4528,7 @@ class parser
//G bit-and-expression
//G bit-xor-expression '^' bit-and-expression
//G
auto bit_xor_expression(bool allow_angle_operators = true)
auto bit_xor_expression(bool allow_angle_operators = true)
-> auto
{
return binary_expression<bit_xor_expression_node> (
Expand All @@ -4496,7 +4541,7 @@ class parser
//G bit-xor-expression
//G bit-or-expression '|' bit-xor-expression
//G
auto bit_or_expression(bool allow_angle_operators = true)
auto bit_or_expression(bool allow_angle_operators = true)
-> auto
{
return binary_expression<bit_or_expression_node> (
Expand All @@ -4509,7 +4554,7 @@ class parser
//G bit-or-expression
//G logical-and-expression '&&' bit-or-expression
//G
auto logical_and_expression(bool allow_angle_operators = true)
auto logical_and_expression(bool allow_angle_operators = true)
-> auto
{
return binary_expression<logical_and_expression_node> (
Expand All @@ -4524,7 +4569,7 @@ class parser
//G logical-and-expression
//G logical-or-expression '||' logical-and-expression
//G
auto logical_or_expression(bool allow_angle_operators = true)
auto logical_or_expression(bool allow_angle_operators = true)
-> auto
{
return binary_expression<logical_or_expression_node> (
Expand Down Expand Up @@ -4842,7 +4887,7 @@ class parser

n->open_angle = curr().position();
next();

auto term = unqualified_id_node::term{};

do {
Expand Down Expand Up @@ -6221,6 +6266,8 @@ class parser

auto apply_type_meta_functions( declaration_node& decl )
-> bool;
auto apply_internal_type_metafunctions( declaration_node& decl )
-> bool;


//G unnamed-declaration:
Expand Down Expand Up @@ -6413,7 +6460,7 @@ class parser
}
assert (n->is_type());
}

// Or a function type, declaring a function - and tell the function whether it's in a user-defined type
else if (auto t = function_type(n.get(), named))
{
Expand Down Expand Up @@ -6561,11 +6608,11 @@ class parser
)
{
auto& type = std::get<declaration_node::an_object>(n->type);
// object initialized by the address of the curr() object
// object initialized by the address of the curr() object
if (peek(1)->type() == lexeme::Ampersand) {
type->address_of = &curr();
}
// object initialized by (potentially multiple) dereference of the curr() object
// object initialized by (potentially multiple) dereference of the curr() object
else if (peek(1)->type() == lexeme::Multiply) {
type->dereference_of = &curr();
for (int i = 1; peek(i)->type() == lexeme::Multiply; ++i)
Expand Down Expand Up @@ -6599,6 +6646,13 @@ class parser
);
return {};
}
if (!apply_internal_type_metafunctions(*n)) {
error(
"error encountered while applying internal type metafunctions",
false, {}, true
);
return {};
}
}

if (
Expand Down Expand Up @@ -6770,7 +6824,7 @@ class parser
return {};
}
if (
t->is_wildcard()
t->is_wildcard()
|| ( t->get_token() && t->get_token()->to_string(true) == "auto" )
) {
errors.emplace_back(
Expand Down
Loading