From d048b633dd02014f8bff1b512ce4d5ae2b8b7903 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Fri, 25 Sep 2026 10:59:05 +0200 Subject: Fix move related memory leaks in AST helpers --- boot/ast.cc | 105 ++++++++++++++++++++++++----------- boot/name_analysis.cc | 12 ++-- boot/parser.yy | 143 +++++++++++++++++++++++------------------------- boot/type_check.cc | 12 ++-- boot/validation.cc | 8 +-- gcc/gcc/elna-generic.cc | 8 +-- include/elna/boot/ast.h | 43 +++++++++++---- 7 files changed, 191 insertions(+), 140 deletions(-) diff --git a/boot/ast.cc b/boot/ast.cc index 2d8e90d..cd2ac55 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -270,10 +270,10 @@ namespace elna::boot statement->branch().prerequisite().accept(this); traverse_block(statement->branch().body); - for (conditional_statements *branch : statement->branches) + for (conditional_statements& branch : statement->branches) { - branch->prerequisite().accept(this); - traverse_block(branch->body); + branch.prerequisite().accept(this); + traverse_block(branch.body); } if (statement->alternative != nullptr) { @@ -286,10 +286,10 @@ namespace elna::boot statement->branch().prerequisite().accept(this); traverse_block(statement->branch().body); - for (conditional_statements *branch : statement->branches) + for (conditional_statements& branch : statement->branches) { - branch->prerequisite().accept(this); - traverse_block(branch->body); + branch.prerequisite().accept(this); + traverse_block(branch.body); } } @@ -590,11 +590,6 @@ namespace elna::boot { } - attribute::attribute(attribute&& that) noexcept - : m_name(std::move(that.m_name)), m_arguments(std::move(that.m_arguments)) - { - } - attribute::~attribute() { for (const expression *argument : this->arguments()) @@ -863,17 +858,14 @@ namespace elna::boot } field_initializer::field_initializer(field_initializer&& other) noexcept - : m_name(std::move(other.m_name)), m_value(other.m_value) + : m_name(std::move(other.m_name)), m_value(std::exchange(other.m_value, nullptr)) { - other.m_value = nullptr; } field_initializer& field_initializer::operator=(field_initializer&& other) noexcept { - delete this->m_value; + std::swap(this->m_value, other.m_value); this->m_name = std::move(other.m_name); - this->m_value = other.m_value; - other.m_value = nullptr; return *this; } @@ -1078,6 +1070,15 @@ namespace elna::boot { } + block& block::operator=(block&& that) noexcept + { + std::swap(this->variables, that.variables); + std::swap(this->statements, that.statements); + std::swap(this->symbols, that.symbols); + + return *this; + } + block::~block() { for (const statement *body_statement : this->statements) @@ -1095,6 +1096,25 @@ namespace elna::boot { } + procedure_body::procedure_body(procedure_body&& that) noexcept + : block(std::move(that)), + return_expression(std::exchange(that.return_expression, nullptr)) + { + } + + procedure_body& procedure_body::operator=(procedure_body&& that) noexcept + { + block::operator=(std::move(that)); + std::swap(return_expression, that.return_expression); + + return *this; + } + + procedure_body::~procedure_body() + { + delete this->return_expression; + } + void traverse_body(parser_visitor *visitor, const procedure_body& body) { for (variable_declaration *variable : body.variables) @@ -1583,6 +1603,19 @@ namespace elna::boot { } + conditional_statements::conditional_statements(conditional_statements&& that) noexcept + : m_prerequisite(std::exchange(that.m_prerequisite, nullptr)), + body(std::move(that.body)) + { + } + + conditional_statements& conditional_statements::operator=(conditional_statements&& that) noexcept + { + std::swap(this->m_prerequisite, that.m_prerequisite); + body = std::move(that.body); + return *this; + } + expression& conditional_statements::prerequisite() { return *m_prerequisite; @@ -1593,6 +1626,27 @@ namespace elna::boot delete m_prerequisite; } + switch_case::switch_case(std::vector&& labels, block&& body) + : labels(std::move(labels)), body(std::move(body)) + { + } + + switch_case& switch_case::operator=(switch_case&& that) noexcept + { + std::swap(this->labels, that.labels); + std::swap(this->body, that.body); + + return *this; + } + + switch_case::~switch_case() + { + for (const expression *label : labels) + { + delete label; + } + } + case_statement::case_statement(const source_position position, expression *condition, std::vector&& cases, block *alternative) : node(position), m_condition(condition), cases(std::move(cases)), alternative(alternative) @@ -1612,13 +1666,6 @@ namespace elna::boot case_statement::~case_statement() { delete m_condition; - for (const switch_case& case_block : this->cases) - { - for (const expression *case_label : case_block.labels) - { - delete case_label; - } - } delete this->alternative; } @@ -1674,7 +1721,7 @@ namespace elna::boot } if_statement::if_statement(const source_position position, conditional_statements *branch, - std::vector&& branches, block *alternative) + std::vector&& branches, block *alternative) : node(position), m_branch(branch), branches(std::move(branches)), alternative(alternative) { } @@ -1692,10 +1739,6 @@ namespace elna::boot if_statement::~if_statement() { delete m_branch; - for (const conditional_statements *branch : branches) - { - delete branch; - } delete this->alternative; } @@ -1710,7 +1753,7 @@ namespace elna::boot } while_statement::while_statement(const source_position position, conditional_statements *branch, - std::vector&& branches) + std::vector&& branches) : node(position), m_branch(branch), branches(std::move(branches)) { } @@ -1728,10 +1771,6 @@ namespace elna::boot while_statement::~while_statement() { delete m_branch; - for (const conditional_statements *branch : branches) - { - delete branch; - } } repeat_statement::repeat_statement(const source_position position, block&& body, diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index 5d5bd34..2ee3da1 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -757,10 +757,10 @@ namespace elna::boot statement->branch().prerequisite().accept(this); visit_block(statement->branch().body); - for (conditional_statements *branch : statement->branches) + for (conditional_statements& branch : statement->branches) { - branch->prerequisite().accept(this); - visit_block(branch->body); + branch.prerequisite().accept(this); + visit_block(branch.body); } if (statement->alternative != nullptr) { @@ -773,10 +773,10 @@ namespace elna::boot statement->branch().prerequisite().accept(this); visit_block(statement->branch().body); - for (conditional_statements *branch : statement->branches) + for (conditional_statements& branch : statement->branches) { - branch->prerequisite().accept(this); - visit_block(branch->body); + branch.prerequisite().accept(this); + visit_block(branch.body); } } diff --git a/boot/parser.yy b/boot/parser.yy index 1e732c6..cc73aef 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -129,9 +129,9 @@ along with GCC; see the file COPYING3. If not see %left "+" "-" %left "*" "/" "%" -%type > literal; +%type literal; %type > case_labels; -%type switch_case; +%type > switch_case; %type > switch_cases; %type variable_declaration; %type > variable_declarations; @@ -141,14 +141,13 @@ along with GCC; see the file COPYING3. If not see %type binary_expression; %type > optional_expressions required_expressions actual_parameter_list; %type designator_expression; -%type > call_expression; +%type call_expression; %type statement; %type > statements statement_part optional_begin_statements; -%type block; %type procedure_declaration; -%type > procedure_heading; +%type procedure_heading; %type return_declaration; -%type > type_declaration; +%type type_declaration; %type > type_declarations sections section; %type , std::vector>> required_declarations optional_declarations; @@ -157,8 +156,8 @@ along with GCC; see the file COPYING3. If not see %type > field_declarations; %type > field_initializer; %type > field_initializers; -%type > elsif_then_statements elsif_do_statements; -%type else_statements; +%type > elsif_then_statements elsif_do_statements;; +%type > else_statements block; %type > identifier with_counter; %type > identifier_definition attributed_identifier; %type > identifier_definitions; @@ -168,7 +167,7 @@ along with GCC; see the file COPYING3. If not see %type > required_identifiers optional_identifiers generic_parameters; %type name_reference; %type > import_declarations; -%type > array_type_expression; +%type array_type_expression; %type > unit; %% program: unit @@ -231,12 +230,12 @@ sections: | section { $$ = $1; } procedure_body: block procedure_return - { $$ = std::make_unique(std::move($1), $2); } + { $$ = std::make_unique(std::move(*$1), $2); } block: "var" variable_declarations statement_part - { $$ = boot::block(std::move($2), std::move($3)); } + { $$ = std::make_unique($2, $3); } | optional_begin_statements - { $$ = boot::block(std::vector(), std::move($1)); } + { $$ = std::make_unique(std::vector(), $1); } statement_part: %empty {} | "begin" statements { $$ = $2; } @@ -277,26 +276,28 @@ return_declaration: %empty {} | "->" "!" { $$ = boot::procedure_type_expression::return_t(std::monostate{}); } | "->" type_expression { $$ = boot::procedure_type_expression::return_t($2); } -procedure_heading: "(" field_declarations ")" attributes return_declaration +procedure_heading: + "(" field_declarations ")" attributes return_declaration { - $$ = std::make_unique(boot::make_position(@$), $2, $5); + $$ = new boot::procedure_type_expression(boot::make_position(@$), $2, $5); $$->attributes = $4; } procedure_declaration: "proc" identifier_definition generic_parameters procedure_heading procedure_body { $$ = new boot::procedure_declaration(boot::make_position(@$), - std::move(*$2), $4.release(), std::move(*$5)); + std::move(*$2), $4, std::move(*$5)); $$->parameters = $3; } | "proc" identifier_definition generic_parameters procedure_heading "extern" { - $$ = new boot::procedure_declaration(boot::make_position(@$), std::move(*$2), $4.release()); + $$ = new boot::procedure_declaration(boot::make_position(@$), std::move(*$2), $4); $$->parameters = $3; } -call_expression: designator_expression actual_parameter_list +call_expression: + designator_expression actual_parameter_list { - $$ = std::make_unique(boot::make_position(@$), $1, $2); + $$ = new boot::procedure_call(boot::make_position(@$), $1, $2); } with_counter: "with" identifier { $$ = $2; } @@ -304,20 +305,18 @@ with_counter: elsif_do_statements: "elsif" expression "do" block elsif_do_statements { - boot::conditional_statements *branch = new boot::conditional_statements($2, std::move($4)); $$ = $5; - $$.emplace($$.begin(), branch); + $$.emplace($$.begin(), $2, std::move(*$4)); } | %empty {} else_statements: - "else" block { $$ = new boot::block(std::move($2)); } + "else" block { $$ = $2; } | %empty { $$ = nullptr; } elsif_then_statements: "elsif" expression "then" block elsif_then_statements { - boot::conditional_statements *branch = new boot::conditional_statements($2, std::move($4)); $$ = $5; - $$.emplace($$.begin(), branch); + $$.emplace($$.begin(), $2, std::move(*$4)); } | %empty {} procedure_return: @@ -327,94 +326,94 @@ literal: INTEGER { auto [magnitude, wants_signed] = $1; - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed, false); } | INTEGER8 { auto [magnitude, wants_signed] = $1; - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | INTEGER16 { auto [magnitude, wants_signed] = $1; - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | INTEGER32 { auto [magnitude, wants_signed] = $1; - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | INTEGER64 { auto [magnitude, wants_signed] = $1; - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | WORD { auto [magnitude, wants_signed] = $1; - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed, false); } | WORD8 { auto [magnitude, wants_signed] = $1; - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | WORD16 { auto [magnitude, wants_signed] = $1; - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | WORD32 { auto [magnitude, wants_signed] = $1; - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | WORD64 { auto [magnitude, wants_signed] = $1; - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | SINGLE { - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), boot::float_literal::from($1), boot::integer_sign::unmarked); } | DOUBLE { - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), boot::float_literal::from($1), boot::integer_sign::unmarked); } | BOOLEAN { - $$ = std::make_unique>(boot::make_position(@$), $1, boot::integer_sign::_unsigned); + $$ = new boot::literal(boot::make_position(@$), $1, boot::integer_sign::_unsigned); } | CHARACTER { - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), $1, boot::integer_sign::_unsigned); } | "nil" { - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), nullptr, boot::integer_sign::_unsigned); } | STRING { - $$ = std::make_unique>(boot::make_position(@$), + $$ = new boot::literal(boot::make_position(@$), $1, boot::integer_sign::_unsigned); } simple_expression: - literal { $$ = $1.release(); } + literal { $$ = $1; } | designator_expression { $$ = $1; } | TRAIT "(" type_expressions ")" { @@ -425,7 +424,7 @@ simple_expression: { $$ = new boot::cast_expression(boot::make_position(@$), $5, $3); } - | call_expression { $$ = $1.release(); } + | call_expression { $$ = $1; } | "(" expression ")" { $$ = $2; } | name_reference "{" field_initializers "}" { @@ -583,42 +582,42 @@ statement: { $$ = new boot::assign_statement(boot::make_position(@$), $1, $3); } | "while" expression "do" block elsif_do_statements "end" { - boot::conditional_statements *body = new boot::conditional_statements($2, std::move($4)); + boot::conditional_statements *body = new boot::conditional_statements($2, std::move(*$4)); $$ = new boot::while_statement(boot::make_position(@$), body, $5); } | "repeat" block "until" expression { - $$ = new boot::repeat_statement(boot::make_position(@$), std::move($2), $4); + $$ = new boot::repeat_statement(boot::make_position(@$), std::move(*$2), $4); } | "for" identifier "of" expression with_counter "do" block "end" { $$ = new boot::for_statement(boot::make_position(@$), std::move(*$2), $4, - std::move($7), $5.release()); + std::move(*$7), $5.release()); } | "if" expression "then" block elsif_then_statements else_statements "end" { - boot::conditional_statements *then = new boot::conditional_statements($2, std::move($4)); - $$ = new boot::if_statement(boot::make_position(@$), then, $5, $6); + boot::conditional_statements *then = new boot::conditional_statements($2, std::move(*$4)); + $$ = new boot::if_statement(boot::make_position(@$), then, $5, $6.release()); } - | call_expression { $$ = $1.release(); } + | call_expression { $$ = $1; } | "defer" block "end" - { $$ = new boot::defer_statement(boot::make_position(@$), std::move($2)); } + { $$ = new boot::defer_statement(boot::make_position(@$), std::move(*$2)); } | "block" identifier block "end" - { $$ = new boot::block_statement(boot::make_position(@$), std::move(*$2), std::move($3)); } + { $$ = new boot::block_statement(boot::make_position(@$), std::move(*$2), std::move(*$3)); } | "break" identifier { $$ = new boot::break_statement(boot::make_position(@$), std::move(*$2)); } | "case" expression "of" switch_cases else_statements "end" - { $$ = new boot::case_statement(boot::make_position(@$), $2, $4, $5); } + { $$ = new boot::case_statement(boot::make_position(@$), $2, $4, $5.release()); } | %empty { $$ = new boot::empty_statement(boot::make_position(@$)); } -switch_case: case_labels ":" block - { $$ = { .labels = $1, .body = std::move($3) }; } +switch_case: + case_labels ":" block { $$ = std::make_unique($1, std::move(*$3)); } switch_cases: switch_case "|" switch_cases { $$ = $3; - $$.emplace($$.cbegin(), $1); + $$.insert($$.cbegin(), std::move(*$1)); } - | switch_case { $$.push_back($1); } + | switch_case { $$.push_back(std::move(*$1)); } case_labels: expression "," case_labels { @@ -653,22 +652,17 @@ field_initializers: $$.emplace($$.cbegin(), std::move(*$1)); } | field_initializer { $$.push_back(std::move(*$1)); } -array_type_expression: "[" expression "]" type_expression - { $$ = std::make_unique(boot::make_position(@$), $4, $2); } +array_type_expression: + "[" expression "]" type_expression + { $$ = new boot::array_type_expression(boot::make_position(@$), $4, $2); } type_expression: - array_type_expression { $$ = $1.release(); } + array_type_expression { $$ = $1; } | "[" "]" type_expression - { - $$ = new boot::slice_type_expression(boot::make_position(@$), $3); - } + { $$ = new boot::slice_type_expression(boot::make_position(@$), $3); } | "const" type_expression - { - $$ = new boot::constant_type_expression(boot::make_position(@$), $2); - } + { $$ = new boot::constant_type_expression(boot::make_position(@$), $2); } | "^" type_expression - { - $$ = new boot::pointer_type_expression(boot::make_position(@$), $2); - } + { $$ = new boot::pointer_type_expression(boot::make_position(@$), $2); } | "record" attributes field_declarations "end" { auto *record = new boot::record_type_expression(boot::make_position(@$), $3); @@ -688,13 +682,9 @@ type_expression: $$ = record; } | "proc" procedure_heading - { - $$ = $2.release(); - } + { $$ = $2; } | "(" required_identifiers ")" - { - $$ = new boot::enumeration_type_expression(boot::make_position(@$), $2); - } + { $$ = new boot::enumeration_type_expression(boot::make_position(@$), $2); } | name_reference { $$ = $1; } generic_parameters: %empty {} @@ -749,14 +739,15 @@ import_declarations: { $$.emplace_back(new boot::import_declaration(boot::make_position(@$), $1)); } -type_declaration: identifier_definition generic_parameters "=" type_expression +type_declaration: + identifier_definition generic_parameters "=" type_expression { - $$ = std::make_unique(boot::make_position(@$), std::move(*$1), $4); + $$ = new boot::type_declaration(boot::make_position(@$), std::move(*$1), $4); $$->parameters = $2; } | identifier_definition generic_parameters "=" "extern" { - $$ = std::make_unique(boot::make_position(@$), std::move(*$1), + $$ = new boot::type_declaration(boot::make_position(@$), std::move(*$1), new boot::extern_type_expression(boot::make_position(@$))); $$->parameters = $2; } @@ -764,7 +755,7 @@ type_declarations: type_declaration type_declarations { $$ = $2; - $$.insert($$.cbegin(), $1.release()); + $$.insert($$.cbegin(), $1); } | %empty {} actual_parameter_list: diff --git a/boot/type_check.cc b/boot/type_check.cc index 7be236d..71fd8ab 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -900,10 +900,10 @@ namespace elna::boot visit_and_validate_condition(statement->branch().prerequisite()); traverse_block(statement->branch().body); - for (conditional_statements *branch : statement->branches) + for (conditional_statements& branch : statement->branches) { - visit_and_validate_condition(branch->prerequisite()); - traverse_block(branch->body); + visit_and_validate_condition(branch.prerequisite()); + traverse_block(branch.body); } } @@ -912,10 +912,10 @@ namespace elna::boot visit_and_validate_condition(statement->branch().prerequisite()); traverse_block(statement->branch().body); - for (conditional_statements *branch : statement->branches) + for (conditional_statements& branch : statement->branches) { - visit_and_validate_condition(branch->prerequisite()); - traverse_block(branch->body); + visit_and_validate_condition(branch.prerequisite()); + traverse_block(branch.body); } if (statement->alternative != nullptr) { diff --git a/boot/validation.cc b/boot/validation.cc index dda3af7..0c9259e 100644 --- a/boot/validation.cc +++ b/boot/validation.cc @@ -132,9 +132,9 @@ namespace elna::boot void validation_visitor::visit(if_statement *statement) { visit_block(statement->branch().body); - for (const conditional_statements *branch : statement->branches) + for (const conditional_statements& branch : statement->branches) { - visit_block(branch->body); + visit_block(branch.body); } if (statement->alternative != nullptr) { @@ -145,9 +145,9 @@ namespace elna::boot void validation_visitor::visit(while_statement *statement) { visit_block(statement->branch().body); - for (const conditional_statements *branch : statement->branches) + for (const conditional_statements& branch : statement->branches) { - visit_block(branch->body); + visit_block(branch.body); } } diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc index 034e4ae..464124a 100644 --- a/gcc/gcc/elna-generic.cc +++ b/gcc/gcc/elna-generic.cc @@ -985,9 +985,9 @@ namespace elna::gcc result = leave_scope(); } - for (const auto& branch : statement->branches | std::views::reverse) + for (boot::conditional_statements& branch : statement->branches | std::views::reverse) { - result = make_if_branch(*branch, result); + result = make_if_branch(branch, result); } result = make_if_branch(statement->branch(), result); @@ -1132,9 +1132,9 @@ namespace elna::gcc tree result = NULL_TREE; - for (boot::conditional_statements *branch : statement->branches | std::views::reverse) + for (boot::conditional_statements& branch : statement->branches | std::views::reverse) { - result = make_if_branch(*branch, result, goto_check); + result = make_if_branch(branch, result, goto_check); } result = make_if_branch(statement->branch(), result, goto_check); diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 4a0cdb0..6a3b9c9 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -163,15 +163,14 @@ namespace elna::boot /// Scope containing the variables, entered by the name analysis. std::shared_ptr symbols; - block() = default; block(std::vector&& variables, std::vector&& statements); block(const block&) = delete; block(block&& that) noexcept = default; block& operator=(const block&) = delete; - block& operator=(block&& that) noexcept = default; + block& operator=(block&& that) noexcept; - ~block(); + virtual ~block(); }; /** @@ -380,7 +379,7 @@ namespace elna::boot { attribute(identifier&& name, std::vector arguments); attribute(const attribute&) = delete; - attribute(attribute&& that) noexcept; + attribute(attribute&& that) noexcept = default; ~attribute(); attribute& operator=(const attribute& that) = delete; @@ -401,6 +400,11 @@ namespace elna::boot { identifier_definition(const std::string& name, const source_position& position, const bool exported, std::vector&& attributes = std::vector{}); + identifier_definition(const identifier_definition&) = delete; + identifier_definition(identifier_definition&&) noexcept = default; + + identifier_definition& operator=(const identifier_definition&) = delete; + identifier_definition& operator=(identifier_definition&&) noexcept = default; const std::string& name() const; const identifier& id() const; @@ -688,9 +692,12 @@ namespace elna::boot expression *return_expression{ nullptr }; explicit procedure_body(block&& body, expression *return_expression = nullptr); - procedure_body(procedure_body&& that) noexcept = default; + procedure_body(const procedure_body&) = delete; + procedure_body(procedure_body&& that) noexcept; + ~procedure_body() override; - virtual ~procedure_body() = default; + procedure_body& operator=(const procedure_body&) = delete; + procedure_body& operator=(procedure_body&& that) noexcept; }; void traverse_body(parser_visitor *visitor, const procedure_body& body); @@ -791,16 +798,30 @@ namespace elna::boot block body; conditional_statements(expression *prerequisite, block&& body); + conditional_statements(const conditional_statements&) = delete; + conditional_statements(conditional_statements&& that) noexcept; + + conditional_statements& operator=(const conditional_statements&) = delete; + conditional_statements& operator=(conditional_statements&& that) noexcept; expression& prerequisite(); - virtual ~conditional_statements(); + ~conditional_statements(); }; struct switch_case { std::vector labels; block body; + + switch_case(std::vector&& labels, block&& body); + switch_case(const switch_case&) = delete; + switch_case(switch_case&& that) noexcept = default; + + switch_case& operator=(const switch_case&) = delete; + switch_case& operator=(switch_case&& that) noexcept; + + ~switch_case(); }; class case_statement : public statement @@ -983,11 +1004,11 @@ namespace elna::boot conditional_statements *m_branch; public: - const std::vector branches; + std::vector branches; block *alternative; if_statement(const source_position position, conditional_statements *branch, - std::vector&& branches, + std::vector&& branches, block *alternative = nullptr); void accept(parser_visitor *visitor) override; @@ -1016,10 +1037,10 @@ namespace elna::boot conditional_statements *m_branch; public: - const std::vector branches; + std::vector branches; while_statement(const source_position position, conditional_statements *branch, - std::vector&& branches); + std::vector&& branches); void accept(parser_visitor *visitor) override; conditional_statements& branch(); -- cgit v1.2.3