diff options
Diffstat (limited to 'gcc/rust/ast')
-rw-r--r-- | gcc/rust/ast/rust-ast-full-test.cc | 504 | ||||
-rw-r--r-- | gcc/rust/ast/rust-ast.h | 485 | ||||
-rw-r--r-- | gcc/rust/ast/rust-expr.h | 1728 | ||||
-rw-r--r-- | gcc/rust/ast/rust-item.h | 1532 | ||||
-rw-r--r-- | gcc/rust/ast/rust-macro.h | 55 | ||||
-rw-r--r-- | gcc/rust/ast/rust-path.h | 219 | ||||
-rw-r--r-- | gcc/rust/ast/rust-pattern.h | 341 | ||||
-rw-r--r-- | gcc/rust/ast/rust-stmt.h | 135 | ||||
-rw-r--r-- | gcc/rust/ast/rust-type.h | 243 |
9 files changed, 3758 insertions, 1484 deletions
diff --git a/gcc/rust/ast/rust-ast-full-test.cc b/gcc/rust/ast/rust-ast-full-test.cc index 0cdac5f..030b0b3 100644 --- a/gcc/rust/ast/rust-ast-full-test.cc +++ b/gcc/rust/ast/rust-ast-full-test.cc @@ -171,13 +171,33 @@ Attribute::as_string () const { std::string path_str = path.as_string (); if (attr_input == nullptr) - { - return path_str; - } + return path_str; else - { - return path_str + attr_input->as_string (); - } + return path_str + attr_input->as_string (); +} + +// Copy constructor must deep copy attr_input as unique pointer +Attribute::Attribute (Attribute const &other) + : path (other.path), locus (other.locus) +{ + // guard to protect from null pointer dereference + if (other.attr_input != nullptr) + attr_input = other.attr_input->clone_attr_input (); +} + +// overload assignment operator to use custom clone method +Attribute & +Attribute::operator= (Attribute const &other) +{ + path = other.path; + locus = other.locus; + // guard to protect from null pointer dereference + if (other.attr_input != nullptr) + attr_input = other.attr_input->clone_attr_input (); + else + attr_input = nullptr; + + return *this; } std::string @@ -307,7 +327,13 @@ std::string VisItem::as_string () const { // FIXME: can't do formatting on string to make identation occur. - std::string str = Item::as_string (); + std::string str; + + if (!outer_attrs.empty ()) + { + for (const auto &attr : outer_attrs) + str += attr.as_string () + "\n"; + } if (has_visibility ()) { @@ -318,7 +344,7 @@ VisItem::as_string () const } // Creates a string that reflects the outer attributes stored. -std::string +/*std::string Item::as_string () const { std::string str; @@ -332,7 +358,7 @@ Item::as_string () const } return str; -} +}*/ std::string Module::as_string () const @@ -654,33 +680,23 @@ Method::as_string () const else { for (const auto ¶m : function_params) - { - str += "\n " + param.as_string (); - } + str += "\n " + param.as_string (); } str += "\n Return type: "; if (has_return_type ()) - { - str += return_type->as_string (); - } + str += return_type->as_string (); else - { - str += "none (void)"; - } + str += "none (void)"; str += "\n Where clause: "; if (has_where_clause ()) - { - str += where_clause.as_string (); - } + str += where_clause.as_string (); else - { - str += "none"; - } + str += "none"; str += "\n Block expr (body): \n "; - str += expr->as_string (); + str += function_body->as_string (); return str; } @@ -1089,7 +1105,7 @@ Function::as_string () const if ("" != qstr) str += qstr + " "; - if (has_function_return_type ()) + if (has_return_type ()) { // DEBUG: null pointer check if (return_type == nullptr) @@ -1154,9 +1170,7 @@ Function::as_string () const } if (has_where_clause ()) - { - str += " where " + where_clause.as_string (); - } + str += " where " + where_clause.as_string (); str += "\n"; @@ -1187,9 +1201,7 @@ WhereClause::as_string () const else { for (const auto &item : where_clause_items) - { - str += "\n " + item->as_string (); - } + str += "\n " + item->as_string (); } return str; @@ -1214,9 +1226,7 @@ BlockExpr::as_string () const /* note that this does not print them with "inner attribute" syntax - * just the body */ for (const auto &attr : inner_attrs) - { - str += "\n" + indent_spaces (stay) + attr.as_string (); - } + str += "\n" + indent_spaces (stay) + attr.as_string (); } // statements @@ -1246,13 +1256,9 @@ BlockExpr::as_string () const // final expression str += "\n" + indent_spaces (stay) + "final expression: "; if (expr == nullptr) - { - str += "none"; - } + str += "none"; else - { - str += "\n" + expr->as_string (); - } + str += "\n" + expr->as_string (); str += "\n" + indent_spaces (out) + "}"; return str; @@ -1264,9 +1270,7 @@ TraitImpl::as_string () const std::string str = VisItem::as_string (); if (has_unsafe) - { - str += "unsafe "; - } + str += "unsafe "; str += "impl "; @@ -1279,20 +1283,14 @@ TraitImpl::as_string () const else { for (const auto ¶m : generic_params) - { - str += "\n " + param->as_string (); - } + str += "\n " + param->as_string (); } str += "\n Has exclam: "; if (has_exclam) - { - str += "true"; - } + str += "true"; else - { - str += "false"; - } + str += "false"; str += "\n TypePath (to trait): " + trait_path.as_string (); @@ -1300,13 +1298,9 @@ TraitImpl::as_string () const str += "\n Where clause: "; if (!has_where_clause ()) - { - str += "none"; - } + str += "none"; else - { - str += where_clause.as_string (); - } + str += where_clause.as_string (); // inner attributes str += "\n inner attributes: "; @@ -1319,9 +1313,7 @@ TraitImpl::as_string () const /* note that this does not print them with "inner attribute" syntax - * just the body */ for (const auto &attr : inner_attrs) - { - str += "\n " + attr.as_string (); - } + str += "\n " + attr.as_string (); } str += "\n trait impl items: "; @@ -1332,9 +1324,7 @@ TraitImpl::as_string () const else { for (const auto &item : impl_items) - { - str += "\n " + item->as_string (); - } + str += "\n " + item->as_string (); } return str; @@ -1384,8 +1374,14 @@ TypeAlias::as_string () const std::string MacroInvocationSemi::as_string () const { + std::string str; + // get outer attrs - std::string str = MacroItem::as_string (); + if (!outer_attrs.empty ()) + { + for (const auto &attr : outer_attrs) + str += attr.as_string () + "\n"; + } str += "\n" + path.as_string () + "!"; @@ -1444,9 +1440,7 @@ ExternBlock::as_string () const /* note that this does not print them with "inner attribute" syntax - * just the body */ for (const auto &attr : inner_attrs) - { - str += "\n " + attr.as_string (); - } + str += "\n " + attr.as_string (); } str += "\n external items: "; @@ -1457,9 +1451,7 @@ ExternBlock::as_string () const else { for (const auto &item : extern_items) - { - str += "\n " + item->as_string (); - } + str += "\n " + item->as_string (); } return str; @@ -1482,7 +1474,16 @@ MacroRule::as_string () const std::string MacroRulesDefinition::as_string () const { - std::string str ("macro_rules!"); + std::string str; + + // get outer attrs + if (!outer_attrs.empty ()) + { + for (const auto &attr : outer_attrs) + str += attr.as_string () + "\n"; + } + + str += "macro_rules!"; str += rule_name; @@ -1494,9 +1495,7 @@ MacroRulesDefinition::as_string () const else { for (const auto &rule : rules) - { - str += "\n " + rule.as_string (); - } + str += "\n " + rule.as_string (); } str += "\n Delim type: "; @@ -1531,9 +1530,7 @@ PathInExpression::as_string () const std::string str; if (has_opening_scope_resolution) - { - str = "::"; - } + str = "::"; return str + PathPattern::as_string (); } @@ -1564,9 +1561,7 @@ ClosureParam::as_string () const std::string str (pattern->as_string ()); if (has_type_given ()) - { - str += " : " + type->as_string (); - } + str += " : " + type->as_string (); return str; } @@ -1576,13 +1571,9 @@ ClosureExpr::as_string () const { std::string str ("ClosureExpr:\n Has move: "); if (has_move) - { - str += "true"; - } + str += "true"; else - { - str += "false"; - } + str += "false"; str += "\n Params: "; if (params.empty ()) @@ -1592,9 +1583,7 @@ ClosureExpr::as_string () const else { for (const auto ¶m : params) - { - str += "\n " + param.as_string (); - } + str += "\n " + param.as_string (); } return str; @@ -1618,9 +1607,7 @@ PathPattern::as_string () const std::string str; for (const auto &segment : segments) - { - str += segment.as_string () + "::"; - } + str += segment.as_string () + "::"; // basically a hack - remove last two characters of string (remove final ::) str.erase (str.length () - 2); @@ -1635,9 +1622,7 @@ QualifiedPathType::as_string () const str += type_to_invoke_on->as_string (); if (has_as_clause ()) - { - str += " as " + trait_path.as_string (); - } + str += " as " + trait_path.as_string (); return str + ">"; } @@ -1654,14 +1639,10 @@ BorrowExpr::as_string () const std::string str ("&"); if (double_borrow) - { - str += "&"; - } + str += "&"; if (is_mut) - { - str += "mut "; - } + str += "mut "; str += main_or_left_expr->as_string (); @@ -1673,10 +1654,8 @@ ReturnExpr::as_string () const { std::string str ("return "); - if (has_return_expr ()) - { - str += return_expr->as_string (); - } + if (has_returned_expr ()) + str += return_expr->as_string (); return str; } @@ -1697,9 +1676,7 @@ GroupedExpr::as_string () const /* note that this does not print them with "inner attribute" syntax - * just the body */ for (const auto &attr : inner_attrs) - { - str += "\n " + attr.as_string (); - } + str += "\n " + attr.as_string (); } str += "\n Expr in parens: " + expr_in_parens->as_string (); @@ -1719,9 +1696,7 @@ ContinueExpr::as_string () const std::string str ("continue "); if (has_label ()) - { - str += label.as_string (); - } + str += label.as_string (); return str; } @@ -1856,9 +1831,7 @@ MethodCallExpr::as_string () const for (const auto ¶m : params) { if (param == nullptr) - { - return "ERROR_MARK_STRING - method call expr param is null"; - } + return "ERROR_MARK_STRING - method call expr param is null"; str += "\n " + param->as_string (); } @@ -1997,9 +1970,7 @@ IfLetExpr::as_string () const else { for (const auto &pattern : match_arm_patterns) - { - str += "\n " + pattern->as_string (); - } + str += "\n " + pattern->as_string (); } str += "\n Scrutinee expr: " + value->as_string (); @@ -2188,9 +2159,7 @@ CallExpr::as_string () const for (const auto ¶m : params) { if (param == nullptr) - { - return "ERROR_MARK_STRING - call expr param is null"; - } + return "ERROR_MARK_STRING - call expr param is null"; str += "\n " + param->as_string (); } @@ -2206,13 +2175,9 @@ WhileLoopExpr::as_string () const str += "\n Label: "; if (!has_loop_label ()) - { - str += "none"; - } + str += "none"; else - { - str += loop_label.as_string (); - } + str += loop_label.as_string (); str += "\n Conditional expr: " + condition->as_string (); @@ -2228,13 +2193,9 @@ WhileLetLoopExpr::as_string () const str += "\n Label: "; if (!has_loop_label ()) - { - str += "none"; - } + str += "none"; else - { - str += loop_label.as_string (); - } + str += loop_label.as_string (); str += "\n Match arm patterns: "; if (match_arm_patterns.empty ()) @@ -2244,12 +2205,10 @@ WhileLetLoopExpr::as_string () const else { for (const auto &pattern : match_arm_patterns) - { - str += "\n " + pattern->as_string (); - } + str += "\n " + pattern->as_string (); } - str += "\n Scrutinee expr: " + condition->as_string (); + str += "\n Scrutinee expr: " + scrutinee->as_string (); str += "\n Loop block: " + loop_block->as_string (); @@ -2263,13 +2222,9 @@ LoopExpr::as_string () const str += "\n Label: "; if (!has_loop_label ()) - { - str += "none"; - } + str += "none"; else - { - str += loop_label.as_string (); - } + str += loop_label.as_string (); str += "\n Loop block: " + loop_block->as_string (); @@ -2292,20 +2247,14 @@ ArrayExpr::as_string () const /* note that this does not print them with "inner attribute" syntax - * just the body */ for (const auto &attr : inner_attrs) - { - str += "\n " + attr.as_string (); - } + str += "\n " + attr.as_string (); } str += "\n Array elems: "; if (!has_array_elems ()) - { - str += "none"; - } + str += "none"; else - { - str += internal_elements->as_string (); - } + str += internal_elements->as_string (); return str; } @@ -2322,14 +2271,10 @@ BreakExpr::as_string () const std::string str ("break "); if (has_label ()) - { - str += label.as_string () + " "; - } + str += label.as_string () + " "; if (has_break_expr ()) - { - str += break_expr->as_string (); - } + str += break_expr->as_string (); return str; } @@ -2354,9 +2299,7 @@ MatchArm::as_string () const /* note that this does not print them with "outer attribute" syntax - * just the body */ for (const auto &attr : outer_attrs) - { - str += "\n " + attr.as_string (); - } + str += "\n " + attr.as_string (); } str += "\nPatterns: "; @@ -2367,20 +2310,14 @@ MatchArm::as_string () const else { for (const auto &pattern : match_arm_patterns) - { - str += "\n " + pattern->as_string (); - } + str += "\n " + pattern->as_string (); } str += "\nGuard expr: "; if (!has_match_arm_guard ()) - { - str += "none"; - } + str += "none"; else - { - str += guard_expr->as_string (); - } + str += guard_expr->as_string (); return str; } @@ -3694,9 +3631,7 @@ StructExprTuple::as_string () const /* note that this does not print them with "inner attribute" syntax - * just the body */ for (const auto &attr : inner_attrs) - { - str += "\n" + indent_spaces (stay) + attr.as_string (); - } + str += "\n" + indent_spaces (stay) + attr.as_string (); } indent_spaces (out); indent_spaces (out); @@ -3722,9 +3657,7 @@ StructExprStruct::as_string () const /* note that this does not print them with "inner attribute" syntax - * just the body */ for (const auto &attr : inner_attrs) - { - str += "\n " + attr.as_string (); - } + str += "\n " + attr.as_string (); } return str; @@ -3734,13 +3667,9 @@ std::string StructBase::as_string () const { if (base_struct != nullptr) - { - return base_struct->as_string (); - } + return base_struct->as_string (); else - { - return "ERROR_MARK_STRING - invalid struct base had as string applied"; - } + return "ERROR_MARK_STRING - invalid struct base had as string applied"; } std::string @@ -3775,25 +3704,59 @@ StructExprStructFields::as_string () const else { for (const auto &field : fields) - { - str += "\n " + field->as_string (); - } + str += "\n " + field->as_string (); } str += "\n Struct base: "; if (!has_struct_base ()) + str += "none"; + else + str += struct_base.as_string (); + + return str; +} + +std::string +EnumExprStruct::as_string () const +{ + std::string str ("StructExprStruct (or subclass): "); + + str += "\n Path: " + get_enum_variant_path ().as_string (); + + str += "\n Fields: "; + if (fields.empty ()) { str += "none"; } else { - str += struct_base.as_string (); + for (const auto &field : fields) + str += "\n " + field->as_string (); } return str; } std::string +EnumExprFieldWithVal::as_string () const +{ + // used to get value string + return value->as_string (); +} + +std::string +EnumExprFieldIdentifierValue::as_string () const +{ + return field_name + " : " + EnumExprFieldWithVal::as_string (); +} + +std::string +EnumExprFieldIndexValue::as_string () const +{ + return std::to_string (index) + " : " + EnumExprFieldWithVal::as_string (); +} + +std::string EnumItem::as_string () const { // outer attributes @@ -3807,9 +3770,7 @@ EnumItem::as_string () const /* note that this does not print them with "outer attribute" syntax - * just the body */ for (const auto &attr : outer_attrs) - { - str += "\n " + attr.as_string (); - } + str += "\n " + attr.as_string (); } str += "\n" + variant_name; @@ -3942,6 +3903,7 @@ EnumItemDiscriminant::as_string () const return str; } +#if 0 std::string ExternalItem::as_string () const { @@ -3956,9 +3918,7 @@ ExternalItem::as_string () const /* note that this does not print them with "outer attribute" syntax - * just the body */ for (const auto &attr : outer_attrs) - { str += "\n " + attr.as_string (); - } } // start visibility on new line and with a space @@ -3966,21 +3926,35 @@ ExternalItem::as_string () const return str; } +#endif std::string ExternalStaticItem::as_string () const { - std::string str = ExternalItem::as_string (); + // outer attributes + std::string str = "outer attributes: "; + if (outer_attrs.empty ()) + { + str += "none"; + } + else + { + /* note that this does not print them with "outer attribute" syntax - + * just the body */ + for (const auto &attr : outer_attrs) + str += "\n " + attr.as_string (); + } + + // start visibility on new line and with a space + str += "\n" + visibility.as_string () + " "; str += "static "; if (has_mut) - { - str += "mut "; - } + str += "mut "; // add name - str += get_item_name (); + str += item_name; // add type on new line str += "\n Type: " + item_type->as_string (); @@ -3991,12 +3965,27 @@ ExternalStaticItem::as_string () const std::string ExternalFunctionItem::as_string () const { - std::string str = ExternalItem::as_string (); + // outer attributes + std::string str = "outer attributes: "; + if (outer_attrs.empty ()) + { + str += "none"; + } + else + { + /* note that this does not print them with "outer attribute" syntax - + * just the body */ + for (const auto &attr : outer_attrs) + str += "\n " + attr.as_string (); + } + + // start visibility on new line and with a space + str += "\n" + visibility.as_string () + " "; str += "fn "; // add name - str += get_item_name (); + str += item_name; // generic params str += "\n Generic params: "; @@ -4024,19 +4013,28 @@ ExternalFunctionItem::as_string () const // function params str += "\n Function params: "; - if (function_params.empty ()) + if (function_params.empty () && !has_variadics) { str += "none"; } else { for (const auto ¶m : function_params) - { - str += "\n " + param.as_string (); - } + str += "\n " + param.as_string (); + if (has_variadics) { - str += "\n .. (variadic)"; + str += "\n variadic outer attrs: "; + if (has_variadic_outer_attrs ()) + { + for (const auto &attr : variadic_outer_attrs) + str += "\n " + attr.as_string (); + } + else + { + str += "none"; + } + str += "\n ... (variadic)"; } } @@ -4046,13 +4044,9 @@ ExternalFunctionItem::as_string () const // where clause str += "\n Where clause: "; if (has_where_clause ()) - { - str += where_clause.as_string (); - } + str += where_clause.as_string (); else - { - str += "none"; - } + str += "none"; return str; } @@ -4060,7 +4054,19 @@ ExternalFunctionItem::as_string () const std::string NamedFunctionParam::as_string () const { - std::string str = name; + std::string str = "outer attributes: "; + + if (!has_outer_attrs ()) + { + str += "none"; + } + else + { + for (const auto &attr : outer_attrs) + str += "\n " + attr.as_string (); + } + + str += "\n" + name; str += "\n Type: " + param_type->as_string (); @@ -4730,7 +4736,8 @@ MacroParser::parse_meta_item_inner () std::vector<MetaNameValueStr> meta_name_value_str_items; for (const auto &item : meta_items) { - std::unique_ptr<MetaNameValueStr> converted_item = item->to_meta_name_value_str (); + std::unique_ptr<MetaNameValueStr> converted_item + = item->to_meta_name_value_str (); if (converted_item == nullptr) { meta_name_value_str_items.clear (); @@ -5048,18 +5055,21 @@ MacroParser::parse_meta_item_lit () bool AttrInputMetaItemContainer::check_cfg_predicate (const Session &session) const { - /* cfg value of container is purely based on cfg of each inner item - all - * must be true */ - for (const auto &inner_item : items) + /* NOTE: assuming that only first item must be true - cfg should only have one + * item, and cfg_attr only has first item as predicate. TODO ensure that this + * is correct. */ + if (items.empty ()) + return false; + + return items[0]->check_cfg_predicate (session); + + /*for (const auto &inner_item : items) { if (!inner_item->check_cfg_predicate (session)) return false; } - /* TODO: as far as I can tell, there should only be a single element to - * check here, so ensure there is only a single element in items too? */ - - return true; + return true;*/ } bool @@ -5346,6 +5356,62 @@ MetaItemPathLit::to_attribute () const new AttrInputLiteral (lit))); } +std::vector<Attribute> +AttrInputMetaItemContainer::separate_cfg_attrs () const +{ + rust_assert (!items.empty ()); + + if (items.size () == 1) + return {}; + + std::vector<Attribute> attrs; + attrs.reserve (items.size () - 1); + + for (auto it = items.begin () + 1; it != items.end (); ++it) + { + Attribute attr = (*it)->to_attribute (); + if (attr.is_empty ()) + { + // TODO should this be an error that causes us to chuck out + // everything? + continue; + } + attrs.push_back (std::move (attr)); + } + + attrs.shrink_to_fit (); + return attrs; +} + +bool +Attribute::check_cfg_predicate (const Session &session) +{ + /* assume that cfg predicate actually can exist, i.e. attribute has cfg or + * cfg_attr path */ + if (!has_attr_input () + || (path.as_string () != "cfg" && path.as_string () != "cfg_attr")) + return false; + + // TODO: maybe replace with storing a "has been parsed" variable? + parse_attr_to_meta_item (); + // can't be const because of this anyway + + return attr_input->check_cfg_predicate (session); +} + +std::vector<Attribute> +Attribute::separate_cfg_attrs () +{ + if (!has_attr_input () || path.as_string () != "cfg_attr") + return {}; + + // TODO: maybe replace with storing a "has been parsed" variable? + parse_attr_to_meta_item (); + // can't be const because of this anyway + + return attr_input->separate_cfg_attrs (); +} + /* Visitor implementations - these are short but inlining can't happen anyway * due to virtual functions and I didn't want to make the ast header includes * any longer than they already are. */ diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index ad3722f..bdc1f12 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -62,32 +62,6 @@ Location? };*/ // decided to not have node as a "node" would never need to be stored -// Attribute body - abstract base class -class AttrInput -{ -public: - virtual ~AttrInput () {} - - // Unique pointer custom clone function - std::unique_ptr<AttrInput> clone_attr_input () const - { - return std::unique_ptr<AttrInput> (clone_attr_input_impl ()); - } - - virtual std::string as_string () const = 0; - - virtual void accept_vis (ASTVisitor &vis) = 0; - - virtual bool check_cfg_predicate (const Session &session) const = 0; - - // Parse attribute input to meta item, if possible - virtual AttrInput *parse_to_meta_item () const { return nullptr; } - -protected: - // pure virtual clone implementation - virtual AttrInput *clone_attr_input_impl () const = 0; -}; - // forward decl for use in token tree method class Token; @@ -109,7 +83,7 @@ public: /* Converts token tree to a flat token stream. Tokens must be pointer to avoid * mutual dependency with Token. */ - virtual std::vector<std::unique_ptr<Token>> to_token_stream () const = 0; + virtual std::vector<std::unique_ptr<Token> > to_token_stream () const = 0; protected: // pure virtual clone implementation @@ -219,7 +193,7 @@ public: void accept_vis (ASTVisitor &vis) override; // Return copy of itself but in token stream form. - std::vector<std::unique_ptr<Token>> to_token_stream () const override; + std::vector<std::unique_ptr<Token> > to_token_stream () const override; TokenId get_id () const { return token_id; } @@ -279,95 +253,6 @@ public: bool is_error () const { return value_as_string == ""; } }; -// A token tree with delimiters -class DelimTokenTree : public TokenTree, public AttrInput -{ - DelimType delim_type; - std::vector<std::unique_ptr<TokenTree>> token_trees; - Location locus; - -protected: - DelimTokenTree *clone_delim_tok_tree_impl () const - { - return new DelimTokenTree (*this); - } - - /* Use covariance to implement clone function as returning a DelimTokenTree - * object */ - DelimTokenTree *clone_attr_input_impl () const override - { - return clone_delim_tok_tree_impl (); - } - - /* Use covariance to implement clone function as returning a DelimTokenTree - * object */ - DelimTokenTree *clone_token_tree_impl () const override - { - return clone_delim_tok_tree_impl (); - } - -public: - DelimTokenTree (DelimType delim_type, - std::vector<std::unique_ptr<TokenTree>> token_trees - = std::vector<std::unique_ptr<TokenTree>> (), - Location locus = Location ()) - : delim_type (delim_type), token_trees (std::move (token_trees)), - locus (locus) - {} - - // Copy constructor with vector clone - DelimTokenTree (DelimTokenTree const &other) - : delim_type (other.delim_type), locus (other.locus) - { - token_trees.reserve (other.token_trees.size ()); - for (const auto &e : other.token_trees) - token_trees.push_back (e->clone_token_tree ()); - } - - // overloaded assignment operator with vector clone - DelimTokenTree &operator= (DelimTokenTree const &other) - { - delim_type = other.delim_type; - locus = other.locus; - - token_trees.reserve (other.token_trees.size ()); - for (const auto &e : other.token_trees) - token_trees.push_back (e->clone_token_tree ()); - - return *this; - } - - // move constructors - DelimTokenTree (DelimTokenTree &&other) = default; - DelimTokenTree &operator= (DelimTokenTree &&other) = default; - - static DelimTokenTree create_empty () { return DelimTokenTree (PARENS); } - - std::string as_string () const override; - - void accept_vis (ASTVisitor &vis) override; - - bool - check_cfg_predicate (const Session &session ATTRIBUTE_UNUSED) const override - { - // this should never be called - should be converted first - return false; - } - - AttrInput *parse_to_meta_item () const override; - - std::vector<std::unique_ptr<Token>> to_token_stream () const override; - - std::unique_ptr<DelimTokenTree> clone_delim_token_tree () const - { - return std::unique_ptr<DelimTokenTree> (clone_delim_tok_tree_impl ()); - } -}; - -/* Forward decl - definition moved to rust-expr.h as it requires LiteralExpr to - * be defined */ -class AttrInputLiteral; - /* TODO: move applicable stuff into here or just don't include it because * nothing uses it A segment of a path (maybe) */ class PathSegment @@ -442,7 +327,7 @@ public: // does this need visitor if not polymorphic? probably not // path-to-string comparison operator - bool operator== (const std::string &rhs) + bool operator== (const std::string &rhs) const { return !has_opening_scope_resolution && segments.size () == 1 && segments[0].as_string () == rhs; @@ -460,6 +345,9 @@ public: } }; +// forward decl for Attribute +class AttrInput; + // aka Attr // Attribute AST representation struct Attribute @@ -488,15 +376,17 @@ public: ~Attribute () = default; // Copy constructor must deep copy attr_input as unique pointer - Attribute (Attribute const &other) : path (other.path), locus (other.locus) + /*Attribute (Attribute const &other) : path (other.path), locus (other.locus) { // guard to protect from null pointer dereference if (other.attr_input != nullptr) attr_input = other.attr_input->clone_attr_input (); - } + }*/ + // no point in being defined inline as requires virtual call anyway + Attribute (const Attribute &other); // overload assignment operator to use custom clone method - Attribute &operator= (Attribute const &other) + /*Attribute &operator= (Attribute const &other) { path = other.path; locus = other.locus; @@ -505,7 +395,9 @@ public: attr_input = other.attr_input->clone_attr_input (); return *this; - } + }*/ + // no point in being defined inline as requires virtual call anyway + Attribute &operator= (const Attribute &other); // default move semantics Attribute (Attribute &&other) = default; @@ -581,29 +473,18 @@ public: std::string as_string () const; // TODO: does this require visitor pattern as not polymorphic? - - // Maybe change to const-reference in future - SimplePath get_path () const { return path; } + + const SimplePath &get_path () const { return path; } + SimplePath &get_path () { return path; } // Call to parse attribute body to meta item syntax. void parse_attr_to_meta_item (); /* Determines whether cfg predicate is true and item with attribute should not * be stripped. */ - bool check_cfg_predicate (const Session &session) - { - /* assume that cfg predicate actually can exist, i.e. attribute has cfg or - * cfg_attr path */ - - if (!has_attr_input ()) - return false; + bool check_cfg_predicate (const Session &session); - // TODO: maybe replace with storing a "has been parsed" variable? - parse_attr_to_meta_item (); - // can't be const because of this anyway - - return attr_input->check_cfg_predicate (session); - } + std::vector<Attribute> separate_cfg_attrs (); protected: // not virtual as currently no subclasses of Attribute, but could be in future @@ -613,6 +494,122 @@ protected: } }; +// Attribute body - abstract base class +class AttrInput +{ +public: + virtual ~AttrInput () {} + + // Unique pointer custom clone function + std::unique_ptr<AttrInput> clone_attr_input () const + { + return std::unique_ptr<AttrInput> (clone_attr_input_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual bool check_cfg_predicate (const Session &session) const = 0; + + // Parse attribute input to meta item, if possible + virtual AttrInput *parse_to_meta_item () const { return nullptr; } + + virtual std::vector<Attribute> separate_cfg_attrs () const { return {}; } + +protected: + // pure virtual clone implementation + virtual AttrInput *clone_attr_input_impl () const = 0; +}; + +// A token tree with delimiters +class DelimTokenTree : public TokenTree, public AttrInput +{ + DelimType delim_type; + std::vector<std::unique_ptr<TokenTree> > token_trees; + Location locus; + +protected: + DelimTokenTree *clone_delim_tok_tree_impl () const + { + return new DelimTokenTree (*this); + } + + /* Use covariance to implement clone function as returning a DelimTokenTree + * object */ + DelimTokenTree *clone_attr_input_impl () const override + { + return clone_delim_tok_tree_impl (); + } + + /* Use covariance to implement clone function as returning a DelimTokenTree + * object */ + DelimTokenTree *clone_token_tree_impl () const override + { + return clone_delim_tok_tree_impl (); + } + +public: + DelimTokenTree (DelimType delim_type, + std::vector<std::unique_ptr<TokenTree> > token_trees + = std::vector<std::unique_ptr<TokenTree> > (), + Location locus = Location ()) + : delim_type (delim_type), token_trees (std::move (token_trees)), + locus (locus) + {} + + // Copy constructor with vector clone + DelimTokenTree (DelimTokenTree const &other) + : delim_type (other.delim_type), locus (other.locus) + { + token_trees.reserve (other.token_trees.size ()); + for (const auto &e : other.token_trees) + token_trees.push_back (e->clone_token_tree ()); + } + + // overloaded assignment operator with vector clone + DelimTokenTree &operator= (DelimTokenTree const &other) + { + delim_type = other.delim_type; + locus = other.locus; + + token_trees.reserve (other.token_trees.size ()); + for (const auto &e : other.token_trees) + token_trees.push_back (e->clone_token_tree ()); + + return *this; + } + + // move constructors + DelimTokenTree (DelimTokenTree &&other) = default; + DelimTokenTree &operator= (DelimTokenTree &&other) = default; + + static DelimTokenTree create_empty () { return DelimTokenTree (PARENS); } + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + bool check_cfg_predicate (const Session &) const override + { + // this should never be called - should be converted first + return false; + } + + AttrInput *parse_to_meta_item () const override; + + std::vector<std::unique_ptr<Token> > to_token_stream () const override; + + std::unique_ptr<DelimTokenTree> clone_delim_token_tree () const + { + return std::unique_ptr<DelimTokenTree> (clone_delim_tok_tree_impl ()); + } +}; + +/* Forward decl - definition moved to rust-expr.h as it requires LiteralExpr to + * be defined */ +class AttrInputLiteral; + // Forward decl - defined in rust-macro.h class MetaNameValueStr; @@ -638,7 +635,10 @@ public: /* HACK: used to simplify parsing - creates a copy of that type, or returns * null */ - virtual std::unique_ptr<MetaNameValueStr> to_meta_name_value_str () const { return nullptr; } + virtual std::unique_ptr<MetaNameValueStr> to_meta_name_value_str () const + { + return nullptr; + } // HACK: used to simplify parsing - same thing virtual SimplePath to_path_item () const @@ -646,7 +646,7 @@ public: return SimplePath::create_empty (); } - virtual Attribute to_attribute() const { return Attribute::create_empty (); } + virtual Attribute to_attribute () const { return Attribute::create_empty (); } virtual bool check_cfg_predicate (const Session &session) const = 0; }; @@ -654,11 +654,11 @@ public: // Container used to store MetaItems as AttrInput (bridge-ish kinda thing) class AttrInputMetaItemContainer : public AttrInput { - std::vector<std::unique_ptr<MetaItemInner>> items; + std::vector<std::unique_ptr<MetaItemInner> > items; public: AttrInputMetaItemContainer ( - std::vector<std::unique_ptr<MetaItemInner>> items) + std::vector<std::unique_ptr<MetaItemInner> > items) : items (std::move (items)) {} @@ -683,6 +683,8 @@ public: clone_attr_input_meta_item_container_impl ()); } + std::vector<Attribute> separate_cfg_attrs () const override; + protected: // Use covariance to implement clone function as returning this type AttrInputMetaItemContainer *clone_attr_input_impl () const override @@ -764,6 +766,9 @@ public: * methods. */ virtual Location get_locus_slow () const { return Location (); } + virtual void mark_for_strip () = 0; + virtual bool is_marked_for_strip () const = 0; + protected: // Clone function implementation as pure virtual method virtual Stmt *clone_stmt_impl () const = 0; @@ -772,10 +777,6 @@ protected: // Rust "item" AST node (declaration of top-level/module-level allowed stuff) class Item : public Stmt { - std::vector<Attribute> outer_attrs; - - // TODO: should outer attrs be defined here or in each derived class? - public: // Unique pointer custom clone function std::unique_ptr<Item> clone_item () const @@ -783,29 +784,22 @@ public: return std::unique_ptr<Item> (clone_item_impl ()); } - std::string as_string () const; + std::string as_string () const = 0; /* Adds crate names to the vector passed by reference, if it can - * (polymorphism). */ + * (polymorphism). TODO: remove, unused. */ virtual void add_crate_name (std::vector<std::string> &names ATTRIBUTE_UNUSED) const {} - virtual void accept_vis (ASTVisitor &vis ATTRIBUTE_UNUSED) {} - protected: - // Constructor - Item (std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) - : outer_attrs (std::move (outer_attribs)) - {} - // Clone function implementation as pure virtual method virtual Item *clone_item_impl () const = 0; /* Save having to specify two clone methods in derived classes by making * statement clone return item clone. Hopefully won't affect performance too * much. */ - Item *clone_stmt_impl () const override { return clone_item_impl (); } + Item *clone_stmt_impl () const final override { return clone_item_impl (); } }; // forward decl of ExprWithoutBlock @@ -818,7 +812,9 @@ class Expr std::vector<Attribute> outer_attrs; public: + // TODO: this mutable getter seems really dodgy. Think up better way. const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } // Unique pointer custom clone function std::unique_ptr<Expr> clone_expr () const @@ -849,6 +845,9 @@ public: virtual void accept_vis (ASTVisitor &vis) = 0; + virtual void mark_for_strip () = 0; + virtual bool is_marked_for_strip () const = 0; + protected: // Constructor Expr (std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) @@ -882,7 +881,7 @@ protected: /* Save having to specify two clone methods in derived classes by making expr * clone return exprwithoutblock clone. Hopefully won't affect performance too * much. */ - ExprWithoutBlock *clone_expr_impl () const override + ExprWithoutBlock *clone_expr_impl () const final override { return clone_expr_without_block_impl (); } @@ -910,11 +909,10 @@ public: */ class IdentifierExpr : public ExprWithoutBlock { -public: Identifier ident; - Location locus; +public: IdentifierExpr (Identifier ident, Location locus = Location (), std::vector<Attribute> outer_attrs = std::vector<Attribute> ()) @@ -927,6 +925,8 @@ public: Location get_locus () const { return locus; } Location get_locus_slow () const override { return get_locus (); } + Identifier get_ident () const { return ident; } + void accept_vis (ASTVisitor &vis) override; // Clones this object. @@ -935,6 +935,10 @@ public: return std::unique_ptr<IdentifierExpr> (clone_identifier_expr_impl ()); } + // "Error state" if ident is empty, so base stripping on this. + void mark_for_strip () override { ident = {}; } + bool is_marked_for_strip () const override { return ident.empty (); } + protected: // Clone method implementation IdentifierExpr *clone_expr_without_block_impl () const override @@ -946,9 +950,6 @@ protected: { return new IdentifierExpr (*this); } - - IdentifierExpr (IdentifierExpr const &other) = default; - IdentifierExpr &operator= (IdentifierExpr const &other) = default; }; // Pattern base AST node @@ -969,6 +970,14 @@ public: virtual void accept_vis (ASTVisitor &vis) = 0; + // as only one kind of pattern can be stripped, have default of nothing + virtual void mark_for_strip () {} + virtual bool is_marked_for_strip () const { return false; } + + /* HACK: slow way of getting location from base expression through virtual + * methods. */ + virtual Location get_locus_slow () const = 0; + protected: // Clone pattern implementation as pure virtual method virtual Pattern *clone_pattern_impl () const = 0; @@ -994,15 +1003,18 @@ public: /* HACK: convert to trait bound. Virtual method overriden by classes that * enable this. */ - virtual TraitBound *to_trait_bound (bool in_parens ATTRIBUTE_UNUSED) const - { - return nullptr; - } + virtual TraitBound *to_trait_bound (bool) const { return nullptr; } /* as pointer, shouldn't require definition beforehand, only forward * declaration. */ virtual void accept_vis (ASTVisitor &vis) = 0; + // as only two kinds of types can be stripped, have default of nothing + virtual void mark_for_strip () {} + virtual bool is_marked_for_strip () const { return false; } + + virtual Location get_locus_slow () const = 0; + protected: // Clone function implementation as pure virtual method virtual Type *clone_type_impl () const = 0; @@ -1025,7 +1037,7 @@ protected: /* Save having to specify two clone methods in derived classes by making type * clone return typenobounds clone. Hopefully won't affect performance too * much. */ - TypeNoBounds *clone_type_impl () const override + TypeNoBounds *clone_type_impl () const final override { return clone_type_no_bounds_impl (); } @@ -1082,7 +1094,7 @@ public: {} // Creates an "error" lifetime. - static Lifetime error () { return Lifetime (NAMED, std::string ("")); } + static Lifetime error () { return Lifetime (NAMED, ""); } // Returns true if the lifetime is in an error state. bool is_error () const @@ -1207,10 +1219,12 @@ class MacroItem : public Item { /*public: std::string as_string() const;*/ + // std::vector<Attribute> outer_attrs; + protected: - MacroItem (std::vector<Attribute> outer_attribs) - : Item (std::move (outer_attribs)) - {} + /*MacroItem (std::vector<Attribute> outer_attribs) + : outer_attrs (std::move (outer_attribs)) + {}*/ }; // Item used in trait declarations - abstract base class @@ -1223,21 +1237,12 @@ class TraitItem // NOTE: all children should have outer attributes protected: - // Constructor - /*TraitItem(std::vector<Attribute> outer_attrs = std::vector<Attribute>()) - : outer_attrs(std::move(outer_attrs)) {}*/ - // Clone function implementation as pure virtual method virtual TraitItem *clone_trait_item_impl () const = 0; public: virtual ~TraitItem () {} - // Returns whether TraitItem has outer attributes. - /*bool has_outer_attrs() const { - return !outer_attrs.empty(); - }*/ - // Unique pointer custom clone function std::unique_ptr<TraitItem> clone_trait_item () const { @@ -1247,6 +1252,9 @@ public: virtual std::string as_string () const = 0; virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual void mark_for_strip () = 0; + virtual bool is_marked_for_strip () const = 0; }; /* Abstract base class for items used within an inherent impl block (the impl @@ -1269,6 +1277,9 @@ public: virtual std::string as_string () const = 0; virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual void mark_for_strip () = 0; + virtual bool is_marked_for_strip () const = 0; }; // Abstract base class for items used in a trait impl @@ -1289,6 +1300,33 @@ public: virtual std::string as_string () const = 0; virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual void mark_for_strip () = 0; + virtual bool is_marked_for_strip () const = 0; +}; + +// Abstract base class for an item used inside an extern block +class ExternalItem +{ +public: + virtual ~ExternalItem () {} + + // Unique pointer custom clone function + std::unique_ptr<ExternalItem> clone_external_item () const + { + return std::unique_ptr<ExternalItem> (clone_external_item_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual void mark_for_strip () = 0; + virtual bool is_marked_for_strip () const = 0; + +protected: + // Clone function implementation as pure virtual method + virtual ExternalItem *clone_external_item_impl () const = 0; }; /* A macro invocation item (or statement) AST node (i.e. semi-coloned macro @@ -1296,51 +1334,32 @@ public: class MacroInvocationSemi : public MacroItem, public TraitItem, public InherentImplItem, - public TraitImplItem + public TraitImplItem, + public ExternalItem { + std::vector<Attribute> outer_attrs; SimplePath path; // all delim types except curly must have invocation end with a semicolon DelimType delim_type; - std::vector<std::unique_ptr<TokenTree>> token_trees; + std::vector<std::unique_ptr<TokenTree> > token_trees; Location locus; public: std::string as_string () const override; MacroInvocationSemi (SimplePath macro_path, DelimType delim_type, - std::vector<std::unique_ptr<TokenTree>> token_trees, + std::vector<std::unique_ptr<TokenTree> > token_trees, std::vector<Attribute> outer_attribs, Location locus) - : MacroItem (std::move (outer_attribs)), path (std::move (macro_path)), + : outer_attrs (std::move (outer_attribs)), path (std::move (macro_path)), delim_type (delim_type), token_trees (std::move (token_trees)), locus (locus) {} - /* TODO: possible issue with Item and TraitItem hierarchies both having outer - * attributes - * - storage inefficiency at least. - * Best current idea is to make Item preferred and have TraitItem get virtual - * functions for attributes or something. Or just redo the "composition" - * approach, but then this prevents polymorphism and would entail redoing - * quite a bit of the parser. */ - - // Move constructors - MacroInvocationSemi (MacroInvocationSemi &&other) = default; - MacroInvocationSemi &operator= (MacroInvocationSemi &&other) = default; - - void accept_vis (ASTVisitor &vis) override; - - // Clones this macro invocation semi. - std::unique_ptr<MacroInvocationSemi> clone_macro_invocation_semi () const - { - return std::unique_ptr<MacroInvocationSemi> ( - clone_macro_invocation_semi_impl ()); - } -protected: // Copy constructor with vector clone MacroInvocationSemi (MacroInvocationSemi const &other) : MacroItem (other), TraitItem (other), InherentImplItem (other), - TraitImplItem (other), path (other.path), delim_type (other.delim_type), - locus (other.locus) + TraitImplItem (other), outer_attrs (other.outer_attrs), path (other.path), + delim_type (other.delim_type), locus (other.locus) { token_trees.reserve (other.token_trees.size ()); for (const auto &e : other.token_trees) @@ -1354,6 +1373,7 @@ protected: TraitItem::operator= (other); InherentImplItem::operator= (other); TraitImplItem::operator= (other); + outer_attrs = other.outer_attrs; path = other.path; delim_type = other.delim_type; locus = other.locus; @@ -1365,6 +1385,28 @@ protected: return *this; } + // Move constructors + MacroInvocationSemi (MacroInvocationSemi &&other) = default; + MacroInvocationSemi &operator= (MacroInvocationSemi &&other) = default; + + void accept_vis (ASTVisitor &vis) override; + + // Clones this macro invocation semi. + std::unique_ptr<MacroInvocationSemi> clone_macro_invocation_semi () const + { + return std::unique_ptr<MacroInvocationSemi> ( + clone_macro_invocation_semi_impl ()); + } + + // Invalid if path is empty, so base stripping on that. + void mark_for_strip () override { path = SimplePath::create_empty (); } + bool is_marked_for_strip () const override { return path.is_empty (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + +protected: MacroInvocationSemi *clone_macro_invocation_semi_impl () const { return new MacroInvocationSemi (*this); @@ -1391,19 +1433,19 @@ protected: return clone_macro_invocation_semi_impl (); } - // FIXME: remove if item impl virtual override works properly - // Use covariance to implement clone function as returning this object rather - // than base - /*MacroInvocationSemi* clone_statement_impl() const override { - return clone_macro_invocation_semi_impl (); - }*/ - /* Use covariance to implement clone function as returning this object rather * than base */ MacroInvocationSemi *clone_trait_item_impl () const override { return clone_macro_invocation_semi_impl (); } + + /* Use covariance to implement clone function as returning this object rather + * than base */ + MacroInvocationSemi *clone_external_item_impl () const override + { + return clone_macro_invocation_semi_impl (); + } }; // A crate AST object - holds all the data for a single compilation unit @@ -1416,11 +1458,11 @@ struct Crate // dodgy spacing required here /* TODO: is it better to have a vector of items here or a module (implicit * top-level one)? */ - std::vector<std::unique_ptr<Item>> items; + std::vector<std::unique_ptr<Item> > items; public: // Constructor - Crate (std::vector<std::unique_ptr<Item>> items, + Crate (std::vector<std::unique_ptr<Item> > items, std::vector<Attribute> inner_attrs, bool has_utf8bom = false, bool has_shebang = false) : has_utf8bom (has_utf8bom), has_shebang (has_shebang), @@ -1459,6 +1501,17 @@ public: // Get crate representation as string (e.g. for debugging). std::string as_string () const; + + // Delete all crate information, e.g. if fails cfg. + void strip_crate () + { + inner_attrs.clear (); + inner_attrs.shrink_to_fit (); + + items.clear (); + items.shrink_to_fit (); + // TODO: is this the best way to do this? + } }; // Base path expression AST node - abstract diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h index f587c00..f86aa54 100644 --- a/gcc/rust/ast/rust-expr.h +++ b/gcc/rust/ast/rust-expr.h @@ -23,7 +23,7 @@ protected: virtual ExprWithBlock *clone_expr_with_block_impl () const = 0; // prevent having to define multiple clone expressions - ExprWithBlock *clone_expr_impl () const override + ExprWithBlock *clone_expr_impl () const final override { return clone_expr_with_block_impl (); } @@ -41,10 +41,10 @@ public: // Literals? Or literal base? class LiteralExpr : public ExprWithoutBlock { -public: Literal literal; Location locus; +public: std::string as_string () const override { return literal.as_string (); } Literal::LitType get_lit_type () const { return literal.get_lit_type (); } @@ -71,21 +71,20 @@ public: Location get_locus () const { return locus; } Location get_locus_slow () const override { return get_locus (); } + Literal get_literal () const { return literal; } + void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - LiteralExpr *clone_expr_impl () const override - { - return new LiteralExpr (*this); - } + // Invalid if literal is in error state, so base stripping on that. + void mark_for_strip () override { literal = Literal::create_error (); } + bool is_marked_for_strip () const override { return literal.is_error (); } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ LiteralExpr *clone_expr_without_block_impl () const override { - return new LiteralExpr (*this); + return clone_literal_expr_impl (); } /* not virtual as currently no subclasses of LiteralExpr, but could be in @@ -120,11 +119,7 @@ public: /* this can never be a cfg predicate - cfg and cfg_attr require a token-tree * cfg */ - bool - check_cfg_predicate (const Session &session ATTRIBUTE_UNUSED) const override - { - return false; - } + bool check_cfg_predicate (const Session &) const override { return false; } protected: /* Use covariance to implement clone function as returning this object rather @@ -212,18 +207,26 @@ protected: // Copy constructor (only for initialisation of expr purposes) OperatorExpr (OperatorExpr const &other) - : ExprWithoutBlock (other), locus (other.locus), - main_or_left_expr (other.main_or_left_expr->clone_expr ()) - {} + : ExprWithoutBlock (other), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.main_or_left_expr != nullptr) + main_or_left_expr = other.main_or_left_expr->clone_expr (); + } // Overload assignment operator to deep copy expr OperatorExpr &operator= (OperatorExpr const &other) { ExprWithoutBlock::operator= (other); - main_or_left_expr = other.main_or_left_expr->clone_expr (); locus = other.locus; // outer_attrs = other.outer_attrs; + // guard to prevent null dereference (only required if error state) + if (other.main_or_left_expr != nullptr) + main_or_left_expr = other.main_or_left_expr->clone_expr (); + else + main_or_left_expr = nullptr; + return *this; } @@ -234,6 +237,13 @@ protected: public: Location get_locus () const { return locus; } Location get_locus_slow () const override { return get_locus (); } + + // Invalid if expr is null, so base stripping on that. + void mark_for_strip () override { main_or_left_expr = nullptr; } + bool is_marked_for_strip () const override + { + return main_or_left_expr == nullptr; + } }; /* Unary prefix & or &mut (or && and &&mut) borrow operator. Cannot be @@ -256,14 +266,14 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - BorrowExpr *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_borrowed_expr () { - return new BorrowExpr (*this); + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ BorrowExpr *clone_expr_without_block_impl () const override @@ -286,14 +296,14 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - DereferenceExpr *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_dereferenced_expr () { - return new DereferenceExpr (*this); + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ DereferenceExpr *clone_expr_without_block_impl () const override @@ -317,14 +327,14 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - ErrorPropagationExpr *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_propagating_expr () { - return new ErrorPropagationExpr (*this); + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ ErrorPropagationExpr *clone_expr_without_block_impl () const override @@ -343,6 +353,7 @@ public: NOT }; +private: /* Note: overload negation via std::ops::Neg and not via std::ops::Not * Negation only works for signed integer and floating-point types, NOT only * works for boolean and integer types (via bitwise NOT) */ @@ -363,16 +374,14 @@ public: void accept_vis (ASTVisitor &vis) override; - Expr *get_expr () { return main_or_left_expr.get (); } - -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - NegationExpr *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_negated_expr () { - return new NegationExpr (*this); + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ NegationExpr *clone_expr_without_block_impl () const override @@ -399,6 +408,7 @@ public: RIGHT_SHIFT // std::ops::Shr }; +private: // Note: overloading trait specified in comments ExprType expr_type; @@ -442,7 +452,19 @@ public: void accept_vis (ASTVisitor &vis) override; - Expr *get_lhs () { return main_or_left_expr.get (); } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_left_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_right_expr () + { + rust_assert (right_expr != nullptr); + return right_expr; + } void visit_lhs (ASTVisitor &vis) { main_or_left_expr->accept_vis (vis); } void visit_rhs (ASTVisitor &vis) { right_expr->accept_vis (vis); } @@ -450,13 +472,6 @@ public: protected: /* Use covariance to implement clone function as returning this object rather * than base */ - ArithmeticOrLogicalExpr *clone_expr_impl () const override - { - return new ArithmeticOrLogicalExpr (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ ArithmeticOrLogicalExpr *clone_expr_without_block_impl () const override { return new ArithmeticOrLogicalExpr (*this); @@ -477,6 +492,7 @@ public: LESS_OR_EQUAL // std::cmp::PartialEq::le }; +private: // Note: overloading trait specified in comments ExprType expr_type; @@ -520,18 +536,23 @@ public: void accept_vis (ASTVisitor &vis) override; - Expr *get_lhs () { return main_or_left_expr.get (); } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_left_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } - /* TODO: implement via a function call to std::cmp::PartialEq::eq(&op1, &op2) - * maybe? */ -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - ComparisonExpr *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_right_expr () { - return new ComparisonExpr (*this); + rust_assert (right_expr != nullptr); + return right_expr; } + /* TODO: implement via a function call to std::cmp::PartialEq::eq(&op1, &op2) + * maybe? */ +protected: /* Use covariance to implement clone function as returning this object rather * than base */ ComparisonExpr *clone_expr_without_block_impl () const override @@ -550,6 +571,7 @@ public: LOGICAL_AND }; +private: ExprType expr_type; std::unique_ptr<Expr> right_expr; @@ -592,16 +614,21 @@ public: void accept_vis (ASTVisitor &vis) override; - Expr *get_lhs () { return main_or_left_expr.get (); } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_left_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - LazyBooleanExpr *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_right_expr () { - return new LazyBooleanExpr (*this); + rust_assert (right_expr != nullptr); + return right_expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ LazyBooleanExpr *clone_expr_without_block_impl () const override @@ -643,20 +670,27 @@ public: return *this; } - // move constructors as not supported in c++03 + // move constructors TypeCastExpr (TypeCastExpr &&other) = default; TypeCastExpr &operator= (TypeCastExpr &&other) = default; void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - TypeCastExpr *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_casted_expr () { - return new TypeCastExpr (*this); + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<TypeNoBounds> &get_type_to_cast_to () + { + rust_assert (type_to_convert_to != nullptr); + return type_to_convert_to; + } + +protected: /* Use covariance to implement clone function as returning this object rather * than base */ TypeCastExpr *clone_expr_without_block_impl () const override @@ -668,9 +702,9 @@ protected: // Binary assignment expression. class AssignmentExpr : public OperatorExpr { -public: std::unique_ptr<Expr> right_expr; +public: std::string as_string () const override; // Call OperatorExpr constructor to initialise left_expr @@ -707,16 +741,21 @@ public: void visit_lhs (ASTVisitor &vis) { main_or_left_expr->accept_vis (vis); } void visit_rhs (ASTVisitor &vis) { right_expr->accept_vis (vis); } - Expr *get_lhs () { return main_or_left_expr.get (); } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_left_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - AssignmentExpr *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_right_expr () { - return new AssignmentExpr (*this); + rust_assert (right_expr != nullptr); + return right_expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ AssignmentExpr *clone_expr_without_block_impl () const override @@ -788,14 +827,21 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - CompoundAssignmentExpr *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_left_expr () { - return new CompoundAssignmentExpr (*this); + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_right_expr () + { + rust_assert (right_expr != nullptr); + return right_expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ CompoundAssignmentExpr *clone_expr_without_block_impl () const override @@ -815,7 +861,8 @@ class GroupedExpr : public ExprWithoutBlock public: std::string as_string () const override; - std::vector<Attribute> get_inner_attrs () const { return inner_attrs; } + const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; } + std::vector<Attribute> &get_inner_attrs () { return inner_attrs; } GroupedExpr (std::unique_ptr<Expr> parenthesised_expr, std::vector<Attribute> inner_attribs, @@ -828,18 +875,27 @@ public: // Copy constructor includes clone for expr_in_parens GroupedExpr (GroupedExpr const &other) : ExprWithoutBlock (other), inner_attrs (other.inner_attrs), - expr_in_parens (other.expr_in_parens->clone_expr ()), locus (other.locus) - {} + locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.expr_in_parens != nullptr) + expr_in_parens = other.expr_in_parens->clone_expr (); + } // Overloaded assignment operator to clone expr_in_parens GroupedExpr &operator= (GroupedExpr const &other) { ExprWithoutBlock::operator= (other); inner_attrs = other.inner_attrs; - expr_in_parens = other.expr_in_parens->clone_expr (); locus = other.locus; // outer_attrs = other.outer_attrs; + // guard to prevent null dereference (only required if error state) + if (other.expr_in_parens != nullptr) + expr_in_parens = other.expr_in_parens->clone_expr (); + else + expr_in_parens = nullptr; + return *this; } @@ -852,14 +908,21 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - GroupedExpr *clone_expr_impl () const override + // Invalid if inner expr is null, so base stripping on that. + void mark_for_strip () override { expr_in_parens = nullptr; } + bool is_marked_for_strip () const override { - return new GroupedExpr (*this); + return expr_in_parens == nullptr; } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_expr_in_parens () + { + rust_assert (expr_in_parens != nullptr); + return expr_in_parens; + } + +protected: /* Use covariance to implement clone function as returning this object rather * than base */ GroupedExpr *clone_expr_without_block_impl () const override @@ -928,6 +991,13 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector<std::unique_ptr<Expr> > &get_values () const + { + return values; + } + std::vector<std::unique_ptr<Expr> > &get_values () { return values; } + size_t get_num_values () const { return values.size (); } void iterate (std::function<bool (Expr *)> cb) @@ -985,6 +1055,20 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_elem_to_copy () + { + rust_assert (elem_to_copy != nullptr); + return elem_to_copy; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_num_copies () + { + rust_assert (num_copies != nullptr); + return num_copies; + } + protected: ArrayElemsCopied *clone_array_elems_impl () const override { @@ -1000,6 +1084,9 @@ class ArrayExpr : public ExprWithoutBlock Location locus; + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + // this is a reference to what the inferred type is based on // this init expression Type *inferredType; @@ -1007,7 +1094,8 @@ class ArrayExpr : public ExprWithoutBlock public: std::string as_string () const override; - std::vector<Attribute> get_inner_attrs () const { return inner_attrs; } + const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; } + std::vector<Attribute> &get_inner_attrs () { return inner_attrs; } // Returns whether array expr has array elems or if it is just empty. bool has_array_elems () const { return internal_elements != nullptr; } @@ -1024,7 +1112,7 @@ public: // Copy constructor requires cloning ArrayElems for polymorphism to hold ArrayExpr (ArrayExpr const &other) : ExprWithoutBlock (other), inner_attrs (other.inner_attrs), - locus (other.locus) + locus (other.locus), marked_for_strip (other.marked_for_strip) { if (other.has_array_elems ()) internal_elements = other.internal_elements->clone_array_elems (); @@ -1035,11 +1123,15 @@ public: { ExprWithoutBlock::operator= (other); inner_attrs = other.inner_attrs; - if (other.has_array_elems ()) - internal_elements = other.internal_elements->clone_array_elems (); locus = other.locus; + marked_for_strip = other.marked_for_strip; // outer_attrs = other.outer_attrs; + if (other.has_array_elems ()) + internal_elements = other.internal_elements->clone_array_elems (); + else + internal_elements = nullptr; + return *this; } @@ -1052,7 +1144,16 @@ public: void accept_vis (ASTVisitor &vis) override; - ArrayElems *get_internal_elements () { return internal_elements.get (); }; + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<ArrayElems> &get_array_elems () + { + rust_assert (internal_elements != nullptr); + return internal_elements; + } Type *get_inferred_type () { return inferredType; } void set_inferred_type (Type *type) { inferredType = type; } @@ -1060,10 +1161,6 @@ public: protected: /* Use covariance to implement clone function as returning this object rather * than base */ - ArrayExpr *clone_expr_impl () const override { return new ArrayExpr (*this); } - - /* Use covariance to implement clone function as returning this object rather - * than base */ ArrayExpr *clone_expr_without_block_impl () const override { return new ArrayExpr (*this); @@ -1095,19 +1192,32 @@ public: // Copy constructor requires special cloning due to unique_ptr ArrayIndexExpr (ArrayIndexExpr const &other) - : ExprWithoutBlock (other), array_expr (other.array_expr->clone_expr ()), - index_expr (other.index_expr->clone_expr ()), locus (other.locus) - {} + : ExprWithoutBlock (other), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.array_expr != nullptr) + array_expr = other.array_expr->clone_expr (); + if (other.index_expr != nullptr) + index_expr = other.index_expr->clone_expr (); + } // Overload assignment operator to clone unique_ptrs ArrayIndexExpr &operator= (ArrayIndexExpr const &other) { ExprWithoutBlock::operator= (other); - array_expr = other.array_expr->clone_expr (); - index_expr = other.index_expr->clone_expr (); // outer_attrs = other.outer_attrs; locus = other.locus; + // guard to prevent null dereference (only required if error state) + if (other.array_expr != nullptr) + array_expr = other.array_expr->clone_expr (); + else + array_expr = nullptr; + if (other.index_expr != nullptr) + index_expr = other.index_expr->clone_expr (); + else + index_expr = nullptr; + return *this; } @@ -1120,17 +1230,32 @@ public: void accept_vis (ASTVisitor &vis) override; - Expr *get_array_expr () { return array_expr.get (); } - Expr *get_index_expr () { return index_expr.get (); } + // Invalid if either expr is null, so base stripping on that. + void mark_for_strip () override + { + array_expr = nullptr; + index_expr = nullptr; + } + bool is_marked_for_strip () const override + { + return array_expr == nullptr && index_expr == nullptr; + } -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - ArrayIndexExpr *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_array_expr () { - return new ArrayIndexExpr (*this); + rust_assert (array_expr != nullptr); + return array_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_index_expr () + { + rust_assert (index_expr != nullptr); + return index_expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ ArrayIndexExpr *clone_expr_without_block_impl () const override @@ -1149,10 +1274,14 @@ class TupleExpr : public ExprWithoutBlock Location locus; + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + public: std::string as_string () const override; - std::vector<Attribute> get_inner_attrs () const { return inner_attrs; } + const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; } + std::vector<Attribute> &get_inner_attrs () { return inner_attrs; } TupleExpr (std::vector<std::unique_ptr<Expr> > tuple_elements, std::vector<Attribute> inner_attribs, @@ -1165,7 +1294,7 @@ public: // copy constructor with vector clone TupleExpr (TupleExpr const &other) : ExprWithoutBlock (other), inner_attrs (other.inner_attrs), - locus (other.locus) + locus (other.locus), marked_for_strip (other.marked_for_strip) { tuple_elems.reserve (other.tuple_elems.size ()); for (const auto &e : other.tuple_elems) @@ -1178,6 +1307,7 @@ public: ExprWithoutBlock::operator= (other); inner_attrs = other.inner_attrs; locus = other.locus; + marked_for_strip = other.marked_for_strip; tuple_elems.reserve (other.tuple_elems.size ()); for (const auto &e : other.tuple_elems) @@ -1198,11 +1328,21 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - TupleExpr *clone_expr_impl () const override { return new TupleExpr (*this); } + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector<std::unique_ptr<Expr> > &get_tuple_elems () const + { + return tuple_elems; + } + std::vector<std::unique_ptr<Expr> > &get_tuple_elems () + { + return tuple_elems; + } + +protected: /* Use covariance to implement clone function as returning this object rather * than base */ TupleExpr *clone_expr_without_block_impl () const override @@ -1236,19 +1376,28 @@ public: // Copy constructor requires a clone for tuple_expr TupleIndexExpr (TupleIndexExpr const &other) - : ExprWithoutBlock (other), tuple_expr (other.tuple_expr->clone_expr ()), - tuple_index (other.tuple_index), locus (other.locus) - {} + : ExprWithoutBlock (other), tuple_index (other.tuple_index), + locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.tuple_expr != nullptr) + tuple_expr = other.tuple_expr->clone_expr (); + } // Overload assignment operator in order to clone TupleIndexExpr &operator= (TupleIndexExpr const &other) { ExprWithoutBlock::operator= (other); - tuple_expr = other.tuple_expr->clone_expr (); tuple_index = other.tuple_index; locus = other.locus; // outer_attrs = other.outer_attrs; + // guard to prevent null dereference (only required if error state) + if (other.tuple_expr != nullptr) + tuple_expr = other.tuple_expr->clone_expr (); + else + tuple_expr = nullptr; + return *this; } @@ -1261,14 +1410,18 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - TupleIndexExpr *clone_expr_impl () const override + // Invalid if tuple expr is null, so base stripping on that. + void mark_for_strip () override { tuple_expr = nullptr; } + bool is_marked_for_strip () const override { return tuple_expr == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_tuple_expr () { - return new TupleIndexExpr (*this); + rust_assert (tuple_expr != nullptr); + return tuple_expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ TupleIndexExpr *clone_expr_without_block_impl () const override @@ -1292,8 +1445,16 @@ protected: public: const PathInExpression &get_struct_name () const { return struct_name; } + PathInExpression &get_struct_name () { return struct_name; } std::string as_string () const override; + + // Invalid if path is empty, so base stripping on that. + void mark_for_strip () override + { + struct_name = PathInExpression::create_error (); + } + bool is_marked_for_strip () const override { return struct_name.is_error (); } }; // Actual AST node of the struct creator (with no fields). Not abstract! @@ -1306,7 +1467,8 @@ class StructExprStruct : public StructExpr public: std::string as_string () const override; - std::vector<Attribute> get_inner_attrs () const { return inner_attrs; } + const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; } + std::vector<Attribute> &get_inner_attrs () { return inner_attrs; } // Constructor has to call protected constructor of base class StructExprStruct (PathInExpression struct_path, @@ -1324,13 +1486,6 @@ public: protected: /* Use covariance to implement clone function as returning this object rather * than base */ - StructExprStruct *clone_expr_impl () const override - { - return new StructExprStruct (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ StructExprStruct *clone_expr_without_block_impl () const override { return new StructExprStruct (*this); @@ -1341,9 +1496,10 @@ protected: * struct */ struct StructBase { -public: +private: std::unique_ptr<Expr> base_struct; +public: // TODO: should this store location data? StructBase (std::unique_ptr<Expr> base_struct_ptr) : base_struct (std::move (base_struct_ptr)) @@ -1355,7 +1511,7 @@ public: /* HACK: gets around base_struct pointer being null (e.g. if no struct base * exists) */ if (other.base_struct != nullptr) - other.base_struct->clone_expr (); + base_struct = other.base_struct->clone_expr (); } // Destructor @@ -1364,7 +1520,11 @@ public: // Overload assignment operator to clone base_struct StructBase &operator= (StructBase const &other) { - base_struct = other.base_struct->clone_expr (); + // prevent null pointer dereference + if (other.base_struct != nullptr) + base_struct = other.base_struct->clone_expr (); + else + base_struct = nullptr; return *this; } @@ -1380,6 +1540,13 @@ public: bool is_invalid () const { return base_struct == nullptr; } std::string as_string () const; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_base_struct () + { + rust_assert (base_struct != nullptr); + return base_struct; + } }; /* Base AST node for a single struct expression field (in struct instance @@ -1399,6 +1566,8 @@ public: virtual void accept_vis (ASTVisitor &vis) = 0; + virtual Location get_locus_slow () const = 0; + protected: // pure virtual clone implementation virtual StructExprField *clone_struct_expr_field_impl () const = 0; @@ -1407,17 +1576,19 @@ protected: // Identifier-only variant of StructExprField AST node class StructExprFieldIdentifier : public StructExprField { -public: Identifier field_name; + Location locus; - // TODO: should this store location data? - - StructExprFieldIdentifier (Identifier field_identifier) - : field_name (std::move (field_identifier)) +public: + StructExprFieldIdentifier (Identifier field_identifier, Location locus) + : field_name (std::move (field_identifier)), locus (locus) {} std::string as_string () const override { return field_name; } + Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } + void accept_vis (ASTVisitor &vis) override; protected: @@ -1433,7 +1604,6 @@ protected: * abstract */ class StructExprFieldWithVal : public StructExprField { -public: std::unique_ptr<Expr> value; protected: @@ -1460,26 +1630,37 @@ protected: public: std::string as_string () const override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_value () + { + rust_assert (value != nullptr); + return value; + } }; // Identifier and value variant of StructExprField AST node class StructExprFieldIdentifierValue : public StructExprFieldWithVal { -public: Identifier field_name; + Location locus; - // TODO: should this store location data? - +public: StructExprFieldIdentifierValue (Identifier field_identifier, - std::unique_ptr<Expr> field_value) + std::unique_ptr<Expr> field_value, Location locus) : StructExprFieldWithVal (std::move (field_value)), - field_name (std::move (field_identifier)) + field_name (std::move (field_identifier)), locus (locus) {} std::string as_string () const override; void accept_vis (ASTVisitor &vis) override; + std::string get_field_name () const { return field_name; } + + Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1492,20 +1673,24 @@ protected: // Tuple index and value variant of StructExprField AST node class StructExprFieldIndexValue : public StructExprFieldWithVal { -public: TupleIndex index; + Location locus; - // TODO: should this store location data? - +public: StructExprFieldIndexValue (TupleIndex tuple_index, - std::unique_ptr<Expr> field_value) - : StructExprFieldWithVal (std::move (field_value)), index (tuple_index) + std::unique_ptr<Expr> field_value, Location locus) + : StructExprFieldWithVal (std::move (field_value)), index (tuple_index), locus (locus) {} std::string as_string () const override; void accept_vis (ASTVisitor &vis) override; + TupleIndex get_index () const { return index; } + + Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1518,25 +1703,17 @@ protected: // AST node of a struct creator with fields class StructExprStructFields : public StructExprStruct { -public: // std::vector<StructExprField> fields; std::vector<std::unique_ptr<StructExprField> > fields; // bool has_struct_base; StructBase struct_base; +public: std::string as_string () const override; bool has_struct_base () const { return !struct_base.is_invalid (); } - /*inline std::vector<std::unique_ptr<StructExprField>> get_fields() - const { return fields; - }*/ - - /*inline StructBase get_struct_base() const { - return has_struct_base ? struct_base : StructBase::error(); - }*/ - // Constructor for StructExprStructFields when no struct base is used StructExprStructFields ( PathInExpression struct_path, @@ -1577,14 +1754,20 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - StructExprStructFields *clone_expr_impl () const override + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<std::unique_ptr<StructExprField> > &get_fields () { - return new StructExprStructFields (*this); + return fields; + } + const std::vector<std::unique_ptr<StructExprField> > &get_fields () const + { + return fields; } + StructBase &get_struct_base () { return struct_base; } + const StructBase &get_struct_base () const { return struct_base; } + +protected: /* Use covariance to implement clone function as returning this object rather * than base */ StructExprStructFields *clone_expr_without_block_impl () const override @@ -1594,6 +1777,8 @@ protected: }; // AST node of the functional update struct creator +/* TODO: remove and replace with StructExprStructFields, except with empty + * vector of fields? */ class StructExprStructBase : public StructExprStruct { StructBase struct_base; @@ -1601,10 +1786,6 @@ class StructExprStructBase : public StructExprStruct public: std::string as_string () const override; - /*inline StructBase get_struct_base() const { - return struct_base; - }*/ - StructExprStructBase (PathInExpression struct_path, StructBase base_struct, std::vector<Attribute> inner_attribs, std::vector<Attribute> outer_attribs, Location locus) @@ -1615,14 +1796,10 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - StructExprStructBase *clone_expr_impl () const override - { - return new StructExprStructBase (*this); - } + StructBase &get_struct_base () { return struct_base; } + const StructBase &get_struct_base () const { return struct_base; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ StructExprStructBase *clone_expr_without_block_impl () const override @@ -1643,10 +1820,7 @@ public: std::string as_string () const override; const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; } - - /*inline std::vector<std::unique_ptr<Expr>> get_exprs() const { - return exprs; - }*/ + std::vector<Attribute> &get_inner_attrs () { return inner_attrs; } StructExprTuple (PathInExpression struct_path, std::vector<std::unique_ptr<Expr> > tuple_exprs, @@ -1689,14 +1863,13 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - StructExprTuple *clone_expr_impl () const override + const std::vector<std::unique_ptr<Expr> > &get_elems () const { - return new StructExprTuple (*this); + return exprs; } + std::vector<std::unique_ptr<Expr> > &get_elems () { return exprs; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ StructExprTuple *clone_expr_without_block_impl () const override @@ -1714,7 +1887,6 @@ public: std::string as_string () const override { return get_struct_name ().as_string (); - // return struct_name.as_string(); } StructExprUnit (PathInExpression struct_path, @@ -1731,13 +1903,6 @@ public: protected: /* Use covariance to implement clone function as returning this object rather * than base */ - StructExprUnit *clone_expr_impl () const override - { - return new StructExprUnit (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ StructExprUnit *clone_expr_without_block_impl () const override { return new StructExprUnit (*this); @@ -1759,8 +1924,21 @@ protected: {} public: - // TODO: maybe remove and have string version gotten here directly - PathInExpression get_enum_variant_path () const { return enum_variant_path; } + const PathInExpression &get_enum_variant_path () const + { + return enum_variant_path; + } + PathInExpression &get_enum_variant_path () { return enum_variant_path; } + + // Invalid if path is in error state, so base stripping on that. + void mark_for_strip () override + { + enum_variant_path = PathInExpression::create_error (); + } + bool is_marked_for_strip () const override + { + return enum_variant_path.is_error (); + } }; /* Base AST node for a single enum expression field (in enum instance creation) @@ -1776,8 +1954,12 @@ public: return std::unique_ptr<EnumExprField> (clone_enum_expr_field_impl ()); } + virtual std::string as_string () const = 0; + virtual void accept_vis (ASTVisitor &vis) = 0; + virtual Location get_locus_slow () const = 0; + protected: // Clone function implementation as pure virtual method virtual EnumExprField *clone_enum_expr_field_impl () const = 0; @@ -1787,16 +1969,20 @@ protected: class EnumExprFieldIdentifier : public EnumExprField { Identifier field_name; - - // TODO: should this store location data? + Location locus; public: - EnumExprFieldIdentifier (Identifier field_identifier) - : field_name (std::move (field_identifier)) + EnumExprFieldIdentifier (Identifier field_identifier, Location locus) + : field_name (std::move (field_identifier)), locus (locus) {} void accept_vis (ASTVisitor &vis) override; + std::string as_string () const override { return field_name; } + + Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1812,8 +1998,6 @@ class EnumExprFieldWithVal : public EnumExprField { std::unique_ptr<Expr> value; - // TODO: should this store location data? - protected: EnumExprFieldWithVal (std::unique_ptr<Expr> field_value) : value (std::move (field_value)) @@ -1835,27 +2019,38 @@ protected: // move constructors EnumExprFieldWithVal (EnumExprFieldWithVal &&other) = default; EnumExprFieldWithVal &operator= (EnumExprFieldWithVal &&other) = default; + +public: + std::string as_string () const override; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_value () + { + rust_assert (value != nullptr); + return value; + } }; // Identifier and value variant of EnumExprField AST node class EnumExprFieldIdentifierValue : public EnumExprFieldWithVal { Identifier field_name; - - // TODO: should this store location data? + Location locus; public: EnumExprFieldIdentifierValue (Identifier field_name, - std::unique_ptr<Expr> field_value) + std::unique_ptr<Expr> field_value, Location locus) : EnumExprFieldWithVal (std::move (field_value)), - field_name (std::move (field_name)) + field_name (std::move (field_name)), locus (locus) {} - // copy constructor, destructor, and assignment operator should not need - // defining + std::string as_string () const override; void accept_vis (ASTVisitor &vis) override; + Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1871,16 +2066,21 @@ class EnumExprFieldIndexValue : public EnumExprFieldWithVal TupleIndex index; // TODO: implement "with val" as a template with EnumExprField as type param? - // TODO: should this store location data? + Location locus; public: EnumExprFieldIndexValue (TupleIndex field_index, - std::unique_ptr<Expr> field_value) - : EnumExprFieldWithVal (std::move (field_value)), index (field_index) + std::unique_ptr<Expr> field_value, Location locus) + : EnumExprFieldWithVal (std::move (field_value)), index (field_index), locus (locus) {} + std::string as_string () const override; + void accept_vis (ASTVisitor &vis) override; + Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1893,18 +2093,12 @@ protected: // Struct-like syntax enum variant instance creation AST node class EnumExprStruct : public EnumVariantExpr { - // std::vector<EnumExprField> fields; std::vector<std::unique_ptr<EnumExprField> > fields; - Location locus; public: std::string as_string () const override; - /*inline std::vector<std::unique_ptr<EnumExprField>> get_fields() const - { return fields; - }*/ - EnumExprStruct (PathInExpression enum_variant_path, std::vector<std::unique_ptr<EnumExprField> > variant_fields, std::vector<Attribute> outer_attribs, Location locus) @@ -1944,14 +2138,14 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - EnumExprStruct *clone_expr_impl () const override + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<std::unique_ptr<EnumExprField> > &get_fields () { return fields; } + const std::vector<std::unique_ptr<EnumExprField> > &get_fields () const { - return new EnumExprStruct (*this); + return fields; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ EnumExprStruct *clone_expr_without_block_impl () const override @@ -1970,10 +2164,6 @@ class EnumExprTuple : public EnumVariantExpr public: std::string as_string () const override; - /*inline std::vector<std::unique_ptr<Expr>> get_values() const { - return values; - }*/ - EnumExprTuple (PathInExpression enum_variant_path, std::vector<std::unique_ptr<Expr> > variant_values, std::vector<Attribute> outer_attribs, Location locus) @@ -2013,14 +2203,13 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - EnumExprTuple *clone_expr_impl () const override + const std::vector<std::unique_ptr<Expr> > &get_elems () const { - return new EnumExprTuple (*this); + return values; } + std::vector<std::unique_ptr<Expr> > &get_elems () { return values; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ EnumExprTuple *clone_expr_without_block_impl () const override @@ -2056,13 +2245,6 @@ public: protected: /* Use covariance to implement clone function as returning this object rather * than base */ - EnumExprFieldless *clone_expr_impl () const override - { - return new EnumExprFieldless (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ EnumExprFieldless *clone_expr_without_block_impl () const override { return new EnumExprFieldless (*this); @@ -2075,21 +2257,17 @@ class Function; // Function call expression AST node class CallExpr : public ExprWithoutBlock { -public: std::unique_ptr<Expr> function; // inlined form of CallParams std::vector<std::unique_ptr<Expr> > params; Location locus; +public: Function *fndeclRef; std::string as_string () const override; - /*inline std::vector<std::unique_ptr<Expr>> get_params() const { - return params; - }*/ - CallExpr (std::unique_ptr<Expr> function_expr, std::vector<std::unique_ptr<Expr> > function_params, std::vector<Attribute> outer_attribs, Location locus) @@ -2100,9 +2278,12 @@ public: // copy constructor requires clone CallExpr (CallExpr const &other) - : ExprWithoutBlock (other), function (other.function->clone_expr ()), - locus (other.locus) - /*, params(other.params),*/ { + : ExprWithoutBlock (other), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.function != nullptr) + function = other.function->clone_expr (); + params.reserve (other.params.size ()); for (const auto &e : other.params) params.push_back (e->clone_expr ()); @@ -2112,11 +2293,15 @@ public: CallExpr &operator= (CallExpr const &other) { ExprWithoutBlock::operator= (other); - function = other.function->clone_expr (); locus = other.locus; - // params = other.params; // outer_attrs = other.outer_attrs; + // guard to prevent null dereference (only required if error state) + if (other.function != nullptr) + function = other.function->clone_expr (); + else + function = nullptr; + params.reserve (other.params.size ()); for (const auto &e : other.params) params.push_back (e->clone_expr ()); @@ -2136,11 +2321,25 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - CallExpr *clone_expr_impl () const override { return new CallExpr (*this); } + // Invalid if function expr is null, so base stripping on that. + void mark_for_strip () override { function = nullptr; } + bool is_marked_for_strip () const override { return function == nullptr; } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector<std::unique_ptr<Expr> > &get_params () const + { + return params; + } + std::vector<std::unique_ptr<Expr> > &get_params () { return params; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_function_expr () + { + rust_assert (function != nullptr); + return function; + } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ CallExpr *clone_expr_without_block_impl () const override @@ -2162,10 +2361,6 @@ class MethodCallExpr : public ExprWithoutBlock public: std::string as_string () const override; - /*inline std::vector<std::unique_ptr<Expr>> get_params() const { - return params; - }*/ - MethodCallExpr (std::unique_ptr<Expr> call_receiver, PathExprSegment method_path, std::vector<std::unique_ptr<Expr> > method_params, @@ -2178,9 +2373,13 @@ public: // copy constructor required due to cloning MethodCallExpr (MethodCallExpr const &other) - : ExprWithoutBlock (other), receiver (other.receiver->clone_expr ()), - method_name (other.method_name), locus (other.locus) - /*, params(other.params),*/ { + : ExprWithoutBlock (other), method_name (other.method_name), + locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.receiver != nullptr) + receiver = other.receiver->clone_expr (); + params.reserve (other.params.size ()); for (const auto &e : other.params) params.push_back (e->clone_expr ()); @@ -2190,12 +2389,16 @@ public: MethodCallExpr &operator= (MethodCallExpr const &other) { ExprWithoutBlock::operator= (other); - receiver = other.receiver->clone_expr (); method_name = other.method_name; locus = other.locus; - // params = other.params; // outer_attrs = other.outer_attrs; + // guard to prevent null dereference (only required if error state) + if (other.receiver != nullptr) + receiver = other.receiver->clone_expr (); + else + receiver = nullptr; + params.reserve (other.params.size ()); for (const auto &e : other.params) params.push_back (e->clone_expr ()); @@ -2212,14 +2415,28 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - MethodCallExpr *clone_expr_impl () const override + // Invalid if receiver expr is null, so base stripping on that. + void mark_for_strip () override { receiver = nullptr; } + bool is_marked_for_strip () const override { return receiver == nullptr; } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector<std::unique_ptr<Expr> > &get_params () const { - return new MethodCallExpr (*this); + return params; } + std::vector<std::unique_ptr<Expr> > &get_params () { return params; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_receiver_expr () + { + rust_assert (receiver != nullptr); + return receiver; + } + + const PathExprSegment &get_method_name () const { return method_name; } + PathExprSegment &get_method_name () { return method_name; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ MethodCallExpr *clone_expr_without_block_impl () const override @@ -2250,19 +2467,27 @@ public: // Copy constructor required due to unique_ptr cloning FieldAccessExpr (FieldAccessExpr const &other) - : ExprWithoutBlock (other), receiver (other.receiver->clone_expr ()), - field (other.field), locus (other.locus) - {} + : ExprWithoutBlock (other), field (other.field), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.receiver != nullptr) + receiver = other.receiver->clone_expr (); + } // Overload assignment operator to clone unique_ptr FieldAccessExpr &operator= (FieldAccessExpr const &other) { ExprWithoutBlock::operator= (other); - receiver = other.receiver->clone_expr (); field = other.field; locus = other.locus; // outer_attrs = other.outer_attrs; + // guard to prevent null dereference (only required if error state) + if (other.receiver != nullptr) + receiver = other.receiver->clone_expr (); + else + receiver = nullptr; + return *this; } @@ -2275,14 +2500,20 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - FieldAccessExpr *clone_expr_impl () const override + // Invalid if receiver expr is null, so base stripping on that. + void mark_for_strip () override { receiver = nullptr; } + bool is_marked_for_strip () const override { return receiver == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_receiver_expr () { - return new FieldAccessExpr (*this); + rust_assert (receiver != nullptr); + return receiver; } + Identifier get_field_name () const { return field; } + +protected: /* Use covariance to implement clone function as returning this object rather * than base */ FieldAccessExpr *clone_expr_without_block_impl () const override @@ -2295,6 +2526,7 @@ protected: struct ClosureParam { private: + std::vector<Attribute> outer_attrs; std::unique_ptr<Pattern> pattern; // bool has_type_given; @@ -2306,17 +2538,22 @@ public: // Returns whether the type of the parameter has been given. bool has_type_given () const { return type != nullptr; } + bool has_outer_attrs () const { return !outer_attrs.empty (); } + // Constructor for closure parameter ClosureParam (std::unique_ptr<Pattern> param_pattern, - std::unique_ptr<Type> param_type = nullptr) - : pattern (std::move (param_pattern)), type (std::move (param_type)) + std::unique_ptr<Type> param_type = nullptr, + std::vector<Attribute> outer_attrs = {}) + : outer_attrs (std::move (outer_attrs)), + pattern (std::move (param_pattern)), type (std::move (param_type)) {} // Copy constructor required due to cloning as a result of unique_ptrs - ClosureParam (ClosureParam const &other) - : pattern (other.pattern->clone_pattern ()) + ClosureParam (ClosureParam const &other) : outer_attrs (other.outer_attrs) { // guard to protect from null pointer dereference + if (other.pattern != nullptr) + pattern = other.pattern->clone_pattern (); if (other.type != nullptr) type = other.type->clone_type (); } @@ -2326,8 +2563,17 @@ public: // Assignment operator must be overloaded to clone as well ClosureParam &operator= (ClosureParam const &other) { - pattern = other.pattern->clone_pattern (); - type = other.type->clone_type (); + outer_attrs = other.outer_attrs; + + // guard to protect from null pointer dereference + if (other.pattern != nullptr) + pattern = other.pattern->clone_pattern (); + else + pattern = nullptr; + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; return *this; } @@ -2343,6 +2589,23 @@ public: static ClosureParam create_error () { return ClosureParam (nullptr); } std::string as_string () const; + + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Pattern> &get_pattern () + { + rust_assert (pattern != nullptr); + return pattern; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_type () + { + rust_assert (has_type_given ()); + return type; + } }; // Base closure definition expression AST node - abstract @@ -2367,6 +2630,10 @@ public: Location get_locus () const { return locus; } Location get_locus_slow () const override { return get_locus (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector<ClosureParam> &get_params () const { return params; } + std::vector<ClosureParam> &get_params () { return params; } }; // Represents a non-type-specified closure expression AST node @@ -2389,19 +2656,27 @@ public: {} // Copy constructor must be defined to allow copying via cloning of unique_ptr - ClosureExprInner (ClosureExprInner const &other) - : ClosureExpr (other), closure_inner (other.closure_inner->clone_expr ()) - {} + ClosureExprInner (ClosureExprInner const &other) : ClosureExpr (other) + { + // guard to prevent null dereference (only required if error state) + if (other.closure_inner != nullptr) + closure_inner = other.closure_inner->clone_expr (); + } // Overload assignment operator to clone closure_inner ClosureExprInner &operator= (ClosureExprInner const &other) { ClosureExpr::operator= (other); - closure_inner = other.closure_inner->clone_expr (); // params = other.params; // has_move = other.has_move; // outer_attrs = other.outer_attrs; + // guard to prevent null dereference (only required if error state) + if (other.closure_inner != nullptr) + closure_inner = other.closure_inner->clone_expr (); + else + closure_inner = nullptr; + return *this; } @@ -2411,14 +2686,21 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - ClosureExprInner *clone_expr_impl () const override + // Invalid if inner expr is null, so base stripping on that. + void mark_for_strip () override { closure_inner = nullptr; } + bool is_marked_for_strip () const override { - return new ClosureExprInner (*this); + return closure_inner == nullptr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_definition_expr () + { + rust_assert (closure_inner != nullptr); + return closure_inner; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ ClosureExprInner *clone_expr_without_block_impl () const override @@ -2430,7 +2712,6 @@ protected: // A block AST node class BlockExpr : public ExprWithBlock { -public: std::vector<Attribute> inner_attrs; // bool has_statements; @@ -2439,14 +2720,16 @@ public: std::unique_ptr<ExprWithoutBlock> expr; // inlined from Statements Location locus; + bool marked_for_strip = false; +public: std::string as_string () const override; // Returns whether the block contains statements. bool has_statements () const { return !statements.empty (); } - // Returns whether the block contains an expression - bool has_expr () const { return expr != nullptr; } + // Returns whether the block contains a final expression. + bool has_tail_expr () const { return expr != nullptr; } BlockExpr (std::vector<std::unique_ptr<Stmt> > block_statements, std::unique_ptr<ExprWithoutBlock> block_expr, @@ -2460,8 +2743,8 @@ public: // Copy constructor with clone BlockExpr (BlockExpr const &other) - : ExprWithBlock (other), /*statements(other.statements),*/ - inner_attrs (other.inner_attrs), locus (other.locus) + : ExprWithBlock (other), inner_attrs (other.inner_attrs), + locus (other.locus), marked_for_strip (other.marked_for_strip) { // guard to protect from null pointer dereference if (other.expr != nullptr) @@ -2476,12 +2759,17 @@ public: BlockExpr &operator= (BlockExpr const &other) { ExprWithBlock::operator= (other); - // statements = other.statements; - expr = other.expr->clone_expr_without_block (); inner_attrs = other.inner_attrs; locus = other.locus; + marked_for_strip = other.marked_for_strip; // outer_attrs = other.outer_attrs; + // guard to protect from null pointer dereference + if (other.expr != nullptr) + expr = other.expr->clone_expr_without_block (); + else + expr = nullptr; + statements.reserve (other.statements.size ()); for (const auto &e : other.statements) statements.push_back (e->clone_stmt ()); @@ -2500,18 +2788,41 @@ public: } Location get_locus () const { return locus; } - Location get_locus_slow () const override { return get_locus (); } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - BlockExpr *clone_expr_impl () const override + // Can be completely empty, so have to have a separate flag. + void mark_for_strip () override { - return clone_block_expr_impl (); + marked_for_strip = true; + } + bool is_marked_for_strip () const override + { + return marked_for_strip; + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; } + std::vector<Attribute> &get_inner_attrs () { return inner_attrs; } + + const std::vector<std::unique_ptr<Stmt> > &get_statements () const + { + return statements; } + std::vector<std::unique_ptr<Stmt> > &get_statements () { return statements; } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<ExprWithoutBlock> &get_tail_expr () + { + rust_assert (has_tail_expr ()); + return expr; + } + + // Removes the tail expression from the block. + void strip_tail_expr () { expr = nullptr; } + +protected: /* Use covariance to implement clone function as returning this object rather * than base */ BlockExpr *clone_expr_with_block_impl () const override @@ -2530,6 +2841,7 @@ protected: // Represents a type-specified closure expression AST node class ClosureExprInnerTyped : public ClosureExpr { + // TODO: spec says typenobounds std::unique_ptr<Type> return_type; std::unique_ptr<BlockExpr> expr; // only used because may be polymorphic in future @@ -2552,20 +2864,33 @@ public: // Copy constructor requires cloning ClosureExprInnerTyped (ClosureExprInnerTyped const &other) - : ClosureExpr (other), return_type (other.return_type->clone_type ()), - expr (other.expr->clone_block_expr ()) - {} + : ClosureExpr (other) + { + // guard to prevent null dereference (only required if error state) + if (other.expr != nullptr) + expr = other.expr->clone_block_expr (); + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + } // Overload assignment operator to clone unique_ptrs ClosureExprInnerTyped &operator= (ClosureExprInnerTyped const &other) { ClosureExpr::operator= (other); - return_type = other.return_type->clone_type (); - expr = other.expr->clone_block_expr (); // params = other.params; // has_move = other.has_move; // outer_attrs = other.outer_attrs; + // guard to prevent null dereference (only required if error state) + if (other.expr != nullptr) + expr = other.expr->clone_block_expr (); + else + expr = nullptr; + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; + return *this; } @@ -2575,14 +2900,26 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - ClosureExprInnerTyped *clone_expr_impl () const override + /* Invalid if inner expr is null, so base stripping on that. Technically, + * type should also not be null. */ + void mark_for_strip () override { expr = nullptr; } + bool is_marked_for_strip () const override { return expr == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_definition_block () { - return new ClosureExprInnerTyped (*this); + rust_assert (expr != nullptr); + return expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_return_type () + { + rust_assert (return_type != nullptr); + return return_type; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ ClosureExprInnerTyped *clone_expr_without_block_impl () const override @@ -2598,6 +2935,9 @@ class ContinueExpr : public ExprWithoutBlock Lifetime label; Location locus; + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + public: std::string as_string () const override; @@ -2617,14 +2957,11 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - ContinueExpr *clone_expr_impl () const override - { - return new ContinueExpr (*this); - } + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ ContinueExpr *clone_expr_without_block_impl () const override @@ -2645,6 +2982,9 @@ class BreakExpr : public ExprWithoutBlock Location locus; + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + public: std::string as_string () const override; @@ -2666,7 +3006,8 @@ public: // Copy constructor defined to use clone for unique pointer BreakExpr (BreakExpr const &other) - : ExprWithoutBlock (other), label (other.label), locus (other.locus) + : ExprWithoutBlock (other), label (other.label), locus (other.locus), + marked_for_strip (other.marked_for_strip) { // guard to protect from null pointer dereference if (other.break_expr != nullptr) @@ -2678,10 +3019,16 @@ public: { ExprWithoutBlock::operator= (other); label = other.label; - break_expr = other.break_expr->clone_expr (); locus = other.locus; + marked_for_strip = other.marked_for_strip; // outer_attrs = other.outer_attrs; + // guard to protect from null pointer dereference + if (other.break_expr != nullptr) + break_expr = other.break_expr->clone_expr (); + else + break_expr = nullptr; + return *this; } @@ -2694,11 +3041,18 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - BreakExpr *clone_expr_impl () const override { return new BreakExpr (*this); } + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_break_expr () + { + rust_assert (break_expr != nullptr); + return break_expr; + } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ BreakExpr *clone_expr_without_block_impl () const override @@ -2740,17 +3094,29 @@ public: {} // Copy constructor with cloning - RangeFromToExpr (RangeFromToExpr const &other) - : RangeExpr (other), from (other.from->clone_expr ()), - to (other.to->clone_expr ()) - {} + RangeFromToExpr (RangeFromToExpr const &other) : RangeExpr (other) + { + // guard to prevent null dereference (only required if error state) + if (other.from != nullptr) + from = other.from->clone_expr (); + if (other.to != nullptr) + to = other.to->clone_expr (); + } // Overload assignment operator to clone unique pointers RangeFromToExpr &operator= (RangeFromToExpr const &other) { RangeExpr::operator= (other); - from = other.from->clone_expr (); - to = other.to->clone_expr (); + + // guard to prevent null dereference (only required if error state) + if (other.from != nullptr) + from = other.from->clone_expr (); + else + from = nullptr; + if (other.to != nullptr) + to = other.to->clone_expr (); + else + to = nullptr; return *this; } @@ -2761,14 +3127,32 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - RangeFromToExpr *clone_expr_impl () const override + // Invalid if either expr is null, so base stripping on that. + void mark_for_strip () override { - return new RangeFromToExpr (*this); + from = nullptr; + to = nullptr; + } + bool is_marked_for_strip () const override + { + return from == nullptr && to == nullptr; } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_from_expr () + { + rust_assert (from != nullptr); + return from; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_to_expr () + { + rust_assert (to != nullptr); + return to; + } + +protected: /* Use covariance to implement clone function as returning this object rather * than base */ RangeFromToExpr *clone_expr_without_block_impl () const override @@ -2791,15 +3175,23 @@ public: {} // Copy constructor with clone - RangeFromExpr (RangeFromExpr const &other) - : RangeExpr (other), from (other.from->clone_expr ()) - {} + RangeFromExpr (RangeFromExpr const &other) : RangeExpr (other) + { + // guard to prevent null dereference (only required if error state) + if (other.from != nullptr) + from = other.from->clone_expr (); + } // Overload assignment operator to clone unique_ptr RangeFromExpr &operator= (RangeFromExpr const &other) { RangeExpr::operator= (other); - from = other.from->clone_expr (); + + // guard to prevent null dereference (only required if error state) + if (other.from != nullptr) + from = other.from->clone_expr (); + else + from = nullptr; return *this; } @@ -2810,14 +3202,18 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - RangeFromExpr *clone_expr_impl () const override + // Invalid if expr is null, so base stripping on that. + void mark_for_strip () override { from = nullptr; } + bool is_marked_for_strip () const override { return from == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_from_expr () { - return new RangeFromExpr (*this); + rust_assert (from != nullptr); + return from; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ RangeFromExpr *clone_expr_without_block_impl () const override @@ -2841,15 +3237,23 @@ public: {} // Copy constructor with clone - RangeToExpr (RangeToExpr const &other) - : RangeExpr (other), to (other.to->clone_expr ()) - {} + RangeToExpr (RangeToExpr const &other) : RangeExpr (other) + { + // guard to prevent null dereference (only required if error state) + if (other.to != nullptr) + to = other.to->clone_expr (); + } // Overload assignment operator to clone unique_ptr RangeToExpr &operator= (RangeToExpr const &other) { RangeExpr::operator= (other); - to = other.to->clone_expr (); + + // guard to prevent null dereference (only required if error state) + if (other.to != nullptr) + to = other.to->clone_expr (); + else + to = nullptr; return *this; } @@ -2860,14 +3264,18 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - RangeToExpr *clone_expr_impl () const override + // Invalid if expr is null, so base stripping on that. + void mark_for_strip () override { to = nullptr; } + bool is_marked_for_strip () const override { return to == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_to_expr () { - return new RangeToExpr (*this); + rust_assert (to != nullptr); + return to; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ RangeToExpr *clone_expr_without_block_impl () const override @@ -2880,6 +3288,9 @@ protected: // constructs a std::ops::RangeFull object class RangeFullExpr : public RangeExpr { + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + public: std::string as_string () const override; @@ -2888,14 +3299,11 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - RangeFullExpr *clone_expr_impl () const override - { - return new RangeFullExpr (*this); - } + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ RangeFullExpr *clone_expr_without_block_impl () const override @@ -2922,17 +3330,29 @@ public: // outer attributes not allowed // Copy constructor with clone - RangeFromToInclExpr (RangeFromToInclExpr const &other) - : RangeExpr (other), from (other.from->clone_expr ()), - to (other.to->clone_expr ()) - {} + RangeFromToInclExpr (RangeFromToInclExpr const &other) : RangeExpr (other) + { + // guard to prevent null dereference (only required if error state) + if (other.from != nullptr) + from = other.from->clone_expr (); + if (other.to != nullptr) + to = other.to->clone_expr (); + } // Overload assignment operator to use clone RangeFromToInclExpr &operator= (RangeFromToInclExpr const &other) { RangeExpr::operator= (other); - from = other.from->clone_expr (); - to = other.to->clone_expr (); + + // guard to prevent null dereference (only required if error state) + if (other.from != nullptr) + from = other.from->clone_expr (); + else + from = nullptr; + if (other.to != nullptr) + to = other.to->clone_expr (); + else + to = nullptr; return *this; } @@ -2943,14 +3363,32 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - RangeFromToInclExpr *clone_expr_impl () const override + // Invalid if either expr is null, so base stripping on that. + void mark_for_strip () override { - return new RangeFromToInclExpr (*this); + from = nullptr; + to = nullptr; + } + bool is_marked_for_strip () const override + { + return from == nullptr && to == nullptr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_from_expr () + { + rust_assert (from != nullptr); + return from; } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_to_expr () + { + rust_assert (to != nullptr); + return to; + } + +protected: /* Use covariance to implement clone function as returning this object rather * than base */ RangeFromToInclExpr *clone_expr_without_block_impl () const override @@ -2974,15 +3412,23 @@ public: // outer attributes not allowed // Copy constructor with clone - RangeToInclExpr (RangeToInclExpr const &other) - : RangeExpr (other), to (other.to->clone_expr ()) - {} + RangeToInclExpr (RangeToInclExpr const &other) : RangeExpr (other) + { + // guard to prevent null dereference (only required if error state) + if (other.to != nullptr) + to = other.to->clone_expr (); + } // Overload assignment operator to clone pointer RangeToInclExpr &operator= (RangeToInclExpr const &other) { RangeExpr::operator= (other); - to = other.to->clone_expr (); + + // guard to prevent null dereference (only required if error state) + if (other.to != nullptr) + to = other.to->clone_expr (); + else + to = nullptr; return *this; } @@ -2993,14 +3439,18 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - RangeToInclExpr *clone_expr_impl () const override + // Invalid if expr is null, so base stripping on that. + void mark_for_strip () override { to = nullptr; } + bool is_marked_for_strip () const override { return to == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_to_expr () { - return new RangeToInclExpr (*this); + rust_assert (to != nullptr); + return to; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ RangeToInclExpr *clone_expr_without_block_impl () const override @@ -3016,12 +3466,15 @@ class ReturnExpr : public ExprWithoutBlock Location locus; + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + public: std::string as_string () const override; /* Returns whether the object has an expression returned (i.e. not void return * type). */ - bool has_return_expr () const { return return_expr != nullptr; } + bool has_returned_expr () const { return return_expr != nullptr; } // Constructor for ReturnExpr. ReturnExpr (Location locus, std::unique_ptr<Expr> returned_expr = nullptr, @@ -3032,7 +3485,8 @@ public: // Copy constructor with clone ReturnExpr (ReturnExpr const &other) - : ExprWithoutBlock (other), locus (other.locus) + : ExprWithoutBlock (other), locus (other.locus), + marked_for_strip (other.marked_for_strip) { // guard to protect from null pointer dereference if (other.return_expr != nullptr) @@ -3043,10 +3497,16 @@ public: ReturnExpr &operator= (ReturnExpr const &other) { ExprWithoutBlock::operator= (other); - return_expr = other.return_expr->clone_expr (); locus = other.locus; + marked_for_strip = other.marked_for_strip; // outer_attrs = other.outer_attrs; + // guard to protect from null pointer dereference + if (other.return_expr != nullptr) + return_expr = other.return_expr->clone_expr (); + else + return_expr = nullptr; + return *this; } @@ -3059,16 +3519,18 @@ public: void accept_vis (ASTVisitor &vis) override; - Expr *get_expr () { return return_expr.get (); } + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - ReturnExpr *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_returned_expr () { - return new ReturnExpr (*this); + rust_assert (return_expr != nullptr); + return return_expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ ReturnExpr *clone_expr_without_block_impl () const override @@ -3085,7 +3547,6 @@ class UnsafeBlockExpr : public ExprWithBlock { // Or just have it extend BlockExpr std::unique_ptr<BlockExpr> expr; - Location locus; public: @@ -3099,18 +3560,26 @@ public: // Copy constructor with clone UnsafeBlockExpr (UnsafeBlockExpr const &other) - : ExprWithBlock (other), expr (other.expr->clone_block_expr ()), - locus (other.locus) - {} + : ExprWithBlock (other), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.expr != nullptr) + expr = other.expr->clone_block_expr (); + } // Overloaded assignment operator to clone UnsafeBlockExpr &operator= (UnsafeBlockExpr const &other) { ExprWithBlock::operator= (other); - expr = other.expr->clone_block_expr (); locus = other.locus; // outer_attrs = other.outer_attrs; + // guard to prevent null dereference (only required if error state) + if (other.expr != nullptr) + expr = other.expr->clone_block_expr (); + else + expr = nullptr; + return *this; } @@ -3123,14 +3592,18 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - UnsafeBlockExpr *clone_expr_impl () const override + // Invalid if block is null, so base stripping on that. + void mark_for_strip () override { expr = nullptr; } + bool is_marked_for_strip () const override { return expr == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_block_expr () { - return new UnsafeBlockExpr (*this); + rust_assert (expr != nullptr); + return expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ UnsafeBlockExpr *clone_expr_with_block_impl () const override @@ -3144,7 +3617,6 @@ protected: class LoopLabel /*: public Node*/ { Lifetime label; // or type LIFETIME_OR_LABEL - Location locus; public: @@ -3189,19 +3661,27 @@ protected: // Copy constructor for BaseLoopExpr with clone BaseLoopExpr (BaseLoopExpr const &other) - : ExprWithBlock (other), loop_label (other.loop_label), - loop_block (other.loop_block->clone_block_expr ()), locus (other.locus) - {} + : ExprWithBlock (other), loop_label (other.loop_label), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.loop_block != nullptr) + loop_block = other.loop_block->clone_block_expr (); + } // Overloaded assignment operator to clone BaseLoopExpr &operator= (BaseLoopExpr const &other) { ExprWithBlock::operator= (other); - loop_block = other.loop_block->clone_block_expr (); loop_label = other.loop_label; locus = other.locus; // outer_attrs = other.outer_attrs; + // guard to prevent null dereference (only required if error state) + if (other.loop_block != nullptr) + loop_block = other.loop_block->clone_block_expr (); + else + loop_block = nullptr; + return *this; } @@ -3214,6 +3694,17 @@ public: Location get_locus () const { return locus; } Location get_locus_slow () const override { return get_locus (); } + + // Invalid if loop block is null, so base stripping on that. + void mark_for_strip () override { loop_block = nullptr; } + bool is_marked_for_strip () const override { return loop_block == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_loop_block () + { + rust_assert (loop_block != nullptr); + return loop_block; + } }; // 'Loop' expression (i.e. the infinite loop) AST node @@ -3235,10 +3726,6 @@ public: protected: /* Use covariance to implement clone function as returning this object rather * than base */ - LoopExpr *clone_expr_impl () const override { return new LoopExpr (*this); } - - /* Use covariance to implement clone function as returning this object rather - * than base */ LoopExpr *clone_expr_with_block_impl () const override { return new LoopExpr (*this); @@ -3287,14 +3774,14 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - WhileLoopExpr *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_predicate_expr () { - return new WhileLoopExpr (*this); + rust_assert (condition != nullptr); + return condition; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ WhileLoopExpr *clone_expr_with_block_impl () const override @@ -3308,14 +3795,14 @@ class WhileLetLoopExpr : public BaseLoopExpr { // MatchArmPatterns patterns; std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined - std::unique_ptr<Expr> condition; + std::unique_ptr<Expr> scrutinee; public: std::string as_string () const override; // Constructor with a loop label WhileLetLoopExpr (std::vector<std::unique_ptr<Pattern> > match_arm_patterns, - std::unique_ptr<Expr> condition, + std::unique_ptr<Expr> scrutinee, std::unique_ptr<BlockExpr> loop_block, Location locus, LoopLabel loop_label = LoopLabel::error (), std::vector<Attribute> outer_attribs @@ -3323,14 +3810,14 @@ public: : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label), std::move (outer_attribs)), match_arm_patterns (std::move (match_arm_patterns)), - condition (std::move (condition)) + scrutinee (std::move (scrutinee)) {} // Copy constructor with clone WhileLetLoopExpr (WhileLetLoopExpr const &other) : BaseLoopExpr (other), - /*match_arm_patterns(other.match_arm_patterns),*/ condition ( - other.condition->clone_expr ()) + /*match_arm_patterns(other.match_arm_patterns),*/ scrutinee ( + other.scrutinee->clone_expr ()) { match_arm_patterns.reserve (other.match_arm_patterns.size ()); for (const auto &e : other.match_arm_patterns) @@ -3342,7 +3829,7 @@ public: { BaseLoopExpr::operator= (other); // match_arm_patterns = other.match_arm_patterns; - condition = other.condition->clone_expr (); + scrutinee = other.scrutinee->clone_expr (); // loop_block = other.loop_block->clone_block_expr(); // loop_label = other.loop_label; // outer_attrs = other.outer_attrs; @@ -3360,14 +3847,24 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - WhileLetLoopExpr *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_scrutinee_expr () { - return new WhileLetLoopExpr (*this); + rust_assert (scrutinee != nullptr); + return scrutinee; } + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector<std::unique_ptr<Pattern> > &get_patterns () const + { + return match_arm_patterns; + } + std::vector<std::unique_ptr<Pattern> > &get_patterns () + { + return match_arm_patterns; + } + +protected: /* Use covariance to implement clone function as returning this object rather * than base */ WhileLetLoopExpr *clone_expr_with_block_impl () const override @@ -3422,14 +3919,21 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - ForLoopExpr *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_iterator_expr () { - return new ForLoopExpr (*this); + rust_assert (iterator_expr != nullptr); + return iterator_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Pattern> &get_pattern () + { + rust_assert (pattern != nullptr); + return pattern; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ ForLoopExpr *clone_expr_with_block_impl () const override @@ -3461,19 +3965,31 @@ public: // outer attributes are never allowed on IfExprs // Copy constructor with clone - IfExpr (IfExpr const &other) - : ExprWithBlock (other), condition (other.condition->clone_expr ()), - if_block (other.if_block->clone_block_expr ()), locus (other.locus) - {} + IfExpr (IfExpr const &other) : ExprWithBlock (other), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.condition != nullptr) + condition = other.condition->clone_expr (); + if (other.if_block != nullptr) + if_block = other.if_block->clone_block_expr (); + } // Overloaded assignment operator to clone expressions IfExpr &operator= (IfExpr const &other) { ExprWithBlock::operator= (other); - condition = other.condition->clone_expr (); - if_block = other.if_block->clone_block_expr (); locus = other.locus; + // guard to prevent null dereference (only required if error state) + if (other.condition != nullptr) + condition = other.condition->clone_expr (); + else + condition = nullptr; + if (other.if_block != nullptr) + if_block = other.if_block->clone_block_expr (); + else + if_block = nullptr; + return *this; } @@ -3499,22 +4015,40 @@ public: void vis_if_condition (ASTVisitor &vis) { condition->accept_vis (vis); } void vis_if_block (ASTVisitor &vis) { if_block->accept_vis (vis); } - Expr *get_if_condition () { return condition.get (); } - BlockExpr *get_if_block () { return if_block.get (); } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_condition_expr () + { + rust_assert (condition != nullptr); + return condition; + } -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfExpr *clone_expr_impl () const override { return new IfExpr (*this); } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_if_block () + { + rust_assert (if_block != nullptr); + return if_block; + } + // Invalid if if block or condition is null, so base stripping on that. + void mark_for_strip () override + { + if_block = nullptr; + condition = nullptr; + } + bool is_marked_for_strip () const override + { + return if_block == nullptr && condition == nullptr; + } + +protected: // Base clone function but still concrete as concrete base class virtual IfExpr *clone_if_expr_impl () const { return new IfExpr (*this); } /* Use covariance to implement clone function as returning this object rather * than base */ - IfExpr *clone_expr_with_block_impl () const override + IfExpr *clone_expr_with_block_impl () const final override { - return new IfExpr (*this); + return clone_if_expr_impl (); } }; @@ -3558,21 +4092,14 @@ public: void vis_else_block (ASTVisitor &vis) { else_block->accept_vis (vis); } -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfExprConseqElse *clone_expr_impl () const override - { - return new IfExprConseqElse (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfExprConseqElse *clone_expr_with_block_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_else_block () { - return new IfExprConseqElse (*this); + rust_assert (else_block != nullptr); + return else_block; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ IfExprConseqElse *clone_if_expr_impl () const override @@ -3624,21 +4151,14 @@ public: conseq_if_expr->accept_vis (vis); } -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfExprConseqIf *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<IfExpr> &get_conseq_if_expr () { - return new IfExprConseqIf (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfExprConseqIf *clone_expr_with_block_impl () const override - { - return new IfExprConseqIf (*this); + rust_assert (conseq_if_expr != nullptr); + return conseq_if_expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ IfExprConseqIf *clone_if_expr_impl () const override @@ -3654,7 +4174,6 @@ class IfLetExpr : public ExprWithBlock std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined std::unique_ptr<Expr> value; std::unique_ptr<BlockExpr> if_block; - Location locus; public: @@ -3671,11 +4190,14 @@ public: // copy constructor with clone IfLetExpr (IfLetExpr const &other) - : ExprWithBlock (other), - /*match_arm_patterns(other.match_arm_patterns),*/ value ( - other.value->clone_expr ()), - if_block (other.if_block->clone_block_expr ()), locus (other.locus) + : ExprWithBlock (other), locus (other.locus) { + // guard to prevent null dereference (only required if error state) + if (other.value != nullptr) + value = other.value->clone_expr (); + if (other.if_block != nullptr) + if_block = other.if_block->clone_block_expr (); + match_arm_patterns.reserve (other.match_arm_patterns.size ()); for (const auto &e : other.match_arm_patterns) match_arm_patterns.push_back (e->clone_pattern ()); @@ -3685,11 +4207,18 @@ public: IfLetExpr &operator= (IfLetExpr const &other) { ExprWithBlock::operator= (other); - // match_arm_patterns = other.match_arm_patterns; - value = other.value->clone_expr (); - if_block = other.if_block->clone_block_expr (); locus = other.locus; + // guard to prevent null dereference (only required if error state) + if (other.value != nullptr) + value = other.value->clone_expr (); + else + value = nullptr; + if (other.if_block != nullptr) + if_block = other.if_block->clone_block_expr (); + else + if_block = nullptr; + match_arm_patterns.reserve (other.match_arm_patterns.size ()); for (const auto &e : other.match_arm_patterns) match_arm_patterns.push_back (e->clone_pattern ()); @@ -3712,16 +4241,47 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExpr *clone_expr_impl () const override { return new IfLetExpr (*this); } + // Invalid if block or value is null, so base stripping on that. + void mark_for_strip () override + { + if_block = nullptr; + value = nullptr; + } + bool is_marked_for_strip () const override + { + return if_block == nullptr && value == nullptr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_value_expr () + { + rust_assert (value != nullptr); + return value; + } + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_if_block () + { + rust_assert (if_block != nullptr); + return if_block; + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector<std::unique_ptr<Pattern> > &get_patterns () const + { + return match_arm_patterns; + } + std::vector<std::unique_ptr<Pattern> > &get_patterns () + { + return match_arm_patterns; + } + +protected: /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExpr *clone_expr_with_block_impl () const override + * than base (or rather this or any derived object) */ + IfLetExpr *clone_expr_with_block_impl () const final override { - return new IfLetExpr (*this); + return clone_if_let_expr_impl (); } // Base clone function but still concrete as concrete base class @@ -3770,21 +4330,14 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfExprConseqIfLet *clone_expr_impl () const override - { - return new IfExprConseqIfLet (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfExprConseqIfLet *clone_expr_with_block_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<IfLetExpr> &get_conseq_if_let_expr () { - return new IfExprConseqIfLet (*this); + rust_assert (if_let_expr != nullptr); + return if_let_expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ IfExprConseqIfLet *clone_if_expr_impl () const override @@ -3836,21 +4389,14 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExprConseqElse *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_else_block () { - return new IfLetExprConseqElse (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExprConseqElse *clone_expr_with_block_impl () const override - { - return new IfLetExprConseqElse (*this); + rust_assert (else_block != nullptr); + return else_block; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ IfLetExprConseqElse *clone_if_let_expr_impl () const override @@ -3901,21 +4447,14 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExprConseqIf *clone_expr_impl () const override - { - return new IfLetExprConseqIf (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExprConseqIf *clone_expr_with_block_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<IfExpr> &get_conseq_if_expr () { - return new IfLetExprConseqIf (*this); + rust_assert (if_expr != nullptr); + return if_expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ IfLetExprConseqIf *clone_if_let_expr_impl () const override @@ -3966,21 +4505,14 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExprConseqIfLet *clone_expr_impl () const override + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<IfLetExpr> &get_conseq_if_let_expr () { - return new IfLetExprConseqIfLet (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExprConseqIfLet *clone_expr_with_block_impl () const override - { - return new IfLetExprConseqIfLet (*this); + rust_assert (if_let_expr != nullptr); + return if_let_expr; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ IfLetExprConseqIfLet *clone_if_let_expr_impl () const override @@ -4037,6 +4569,8 @@ public: if (other.guard_expr != nullptr) guard_expr = other.guard_expr->clone_expr (); + else + guard_expr = nullptr; match_arm_patterns.reserve (other.match_arm_patterns.size ()); for (const auto &e : other.match_arm_patterns) @@ -4059,6 +4593,26 @@ public: } std::string as_string () const; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_guard_expr () + { + rust_assert (has_match_arm_guard ()); + return guard_expr; + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + + const std::vector<std::unique_ptr<Pattern> > &get_patterns () const + { + return match_arm_patterns; + } + std::vector<std::unique_ptr<Pattern> > &get_patterns () + { + return match_arm_patterns; + } }; /* @@ -4124,6 +4678,20 @@ public: ~MatchCase () = default; std::string as_string () const; + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_expr () + { + rust_assert (expr != nullptr); + return expr; + } + + // TODO: is this better? Or is a "vis_block" better? + MatchArm &get_arm () + { + rust_assert (!arm.is_error ()); + return arm; + } }; #if 0 @@ -4249,10 +4817,13 @@ public: // Copy constructor requires clone due to unique_ptr MatchExpr (MatchExpr const &other) - : ExprWithBlock (other), branch_value (other.branch_value->clone_expr ()), - inner_attrs (other.inner_attrs), match_arms (other.match_arms), - locus (other.locus) + : ExprWithBlock (other), inner_attrs (other.inner_attrs), + match_arms (other.match_arms), locus (other.locus) { + // guard to prevent null dereference (only required if error state) + if (other.branch_value != nullptr) + branch_value = other.branch_value->clone_expr (); + /*match_arms.reserve (other.match_arms.size ()); for (const auto &e : other.match_arms) match_arms.push_back (e->clone_match_case ());*/ @@ -4262,12 +4833,17 @@ public: MatchExpr &operator= (MatchExpr const &other) { ExprWithBlock::operator= (other); - branch_value = other.branch_value->clone_expr (); inner_attrs = other.inner_attrs; match_arms = other.match_arms; // outer_attrs = other.outer_attrs; locus = other.locus; + // guard to prevent null dereference (only required if error state) + if (other.branch_value != nullptr) + branch_value = other.branch_value->clone_expr (); + else + branch_value = nullptr; + /*match_arms.reserve (other.match_arms.size ()); for (const auto &e : other.match_arms) match_arms.push_back (e->clone_match_case ());*/ @@ -4284,11 +4860,25 @@ public: void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - MatchExpr *clone_expr_impl () const override { return new MatchExpr (*this); } + // Invalid if branch value is null, so base stripping on that. + void mark_for_strip () override { branch_value = nullptr; } + bool is_marked_for_strip () const override { return branch_value == nullptr; } + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; } + std::vector<Attribute> &get_inner_attrs () { return inner_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_scrutinee_expr () + { + rust_assert (branch_value != nullptr); + return branch_value; + } + + const std::vector<MatchCase> &get_match_cases () const { return match_arms; } + std::vector<MatchCase> &get_match_cases () { return match_arms; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ MatchExpr *clone_expr_with_block_impl () const override @@ -4301,7 +4891,6 @@ protected: class AwaitExpr : public ExprWithoutBlock { std::unique_ptr<Expr> awaited_expr; - Location locus; public: @@ -4314,17 +4903,25 @@ public: // copy constructor with clone AwaitExpr (AwaitExpr const &other) - : ExprWithoutBlock (other), - awaited_expr (other.awaited_expr->clone_expr ()), locus (other.locus) - {} + : ExprWithoutBlock (other), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.awaited_expr != nullptr) + awaited_expr = other.awaited_expr->clone_expr (); + } // overloaded assignment operator with clone AwaitExpr &operator= (AwaitExpr const &other) { ExprWithoutBlock::operator= (other); - awaited_expr = other.awaited_expr->clone_expr (); locus = other.locus; + // guard to prevent null dereference (only required if error state) + if (other.awaited_expr != nullptr) + awaited_expr = other.awaited_expr->clone_expr (); + else + awaited_expr = nullptr; + return *this; } @@ -4339,6 +4936,17 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if awaited expr is null, so base stripping on that. + void mark_for_strip () override { awaited_expr = nullptr; } + bool is_marked_for_strip () const override { return awaited_expr == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_awaited_expr () + { + rust_assert (awaited_expr != nullptr); + return awaited_expr; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -4354,7 +4962,6 @@ class AsyncBlockExpr : public ExprWithBlock // TODO: should this extend BlockExpr rather than be a composite of it? bool has_move; std::unique_ptr<BlockExpr> block_expr; - Location locus; public: @@ -4366,18 +4973,26 @@ public: // copy constructor with clone AsyncBlockExpr (AsyncBlockExpr const &other) - : ExprWithBlock (other), has_move (other.has_move), - block_expr (other.block_expr->clone_block_expr ()), locus (other.locus) - {} + : ExprWithBlock (other), has_move (other.has_move), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.block_expr != nullptr) + block_expr = other.block_expr->clone_block_expr (); + } // overloaded assignment operator to clone AsyncBlockExpr &operator= (AsyncBlockExpr const &other) { ExprWithBlock::operator= (other); has_move = other.has_move; - block_expr = other.block_expr->clone_block_expr (); locus = other.locus; + // guard to prevent null dereference (only required if error state) + if (other.block_expr != nullptr) + block_expr = other.block_expr->clone_block_expr (); + else + block_expr = nullptr; + return *this; } @@ -4392,6 +5007,17 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if block is null, so base stripping on that. + void mark_for_strip () override { block_expr = nullptr; } + bool is_marked_for_strip () const override { return block_expr == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_block_expr () + { + rust_assert (block_expr != nullptr); + return block_expr; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h index b5d9247..f18124d 100644 --- a/gcc/rust/ast/rust-item.h +++ b/gcc/rust/ast/rust-item.h @@ -57,7 +57,7 @@ class TypeParam : public GenericParam // bool has_type_param_bounds; // TypeParamBounds type_param_bounds; - std::vector<std::unique_ptr<TypeParamBound>> + std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds; // inlined form // bool has_type; @@ -76,8 +76,8 @@ public: bool has_outer_attribute () const { return !outer_attr.is_empty (); } TypeParam (Identifier type_representation, Location locus = Location (), - std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds - = std::vector<std::unique_ptr<TypeParamBound>> (), + std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds + = std::vector<std::unique_ptr<TypeParamBound> > (), std::unique_ptr<Type> type = nullptr, Attribute outer_attr = Attribute::create_empty ()) : outer_attr (std::move (outer_attr)), @@ -89,9 +89,12 @@ public: // Copy constructor uses clone TypeParam (TypeParam const &other) : outer_attr (other.outer_attr), - type_representation (other.type_representation), - type (other.type->clone_type ()), locus (other.locus) + type_representation (other.type_representation), locus (other.locus) { + // guard to prevent null pointer dereference + if (other.type != nullptr) + type = other.type->clone_type (); + type_param_bounds.reserve (other.type_param_bounds.size ()); for (const auto &e : other.type_param_bounds) type_param_bounds.push_back (e->clone_type_param_bound ()); @@ -101,11 +104,15 @@ public: TypeParam &operator= (TypeParam const &other) { type_representation = other.type_representation; - // type_param_bounds = other.type_param_bounds; - type = other.type->clone_type (); outer_attr = other.outer_attr; locus = other.locus; + // guard to prevent null pointer dereference + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + type_param_bounds.reserve (other.type_param_bounds.size ()); for (const auto &e : other.type_param_bounds) type_param_bounds.push_back (e->clone_type_param_bound ()); @@ -123,6 +130,24 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_type () + { + rust_assert (type != nullptr); + return type; + } + + // TODO: mutable getter seems kinda dodgy + std::vector<std::unique_ptr<TypeParamBound> > &get_type_param_bounds () + { + return type_param_bounds; + } + const std::vector<std::unique_ptr<TypeParamBound> > & + get_type_param_bounds () const + { + return type_param_bounds; + } + protected: // Clone function implementation as (not pure) virtual method TypeParam *clone_generic_param_impl () const override @@ -193,7 +218,7 @@ class TypeBoundWhereClauseItem : public WhereClauseItem // bool has_type_param_bounds; // TypeParamBounds type_param_bounds; - std::vector<std::unique_ptr<TypeParamBound>> + std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds; // inlined form // should this store location info? @@ -207,7 +232,7 @@ public: TypeBoundWhereClauseItem ( std::vector<LifetimeParam> for_lifetimes, std::unique_ptr<Type> bound_type, - std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds) + std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds) : for_lifetimes (std::move (for_lifetimes)), bound_type (std::move (bound_type)), type_param_bounds (std::move (type_param_bounds)) @@ -245,6 +270,24 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_type () + { + rust_assert (bound_type != nullptr); + return bound_type; + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<std::unique_ptr<TypeParamBound> > &get_type_param_bounds () + { + return type_param_bounds; + } + const std::vector<std::unique_ptr<TypeParamBound> > & + get_type_param_bounds () const + { + return type_param_bounds; + } + protected: // Clone function implementation as (not pure) virtual method TypeBoundWhereClauseItem *clone_where_clause_item_impl () const override @@ -257,13 +300,13 @@ protected: struct WhereClause { private: - std::vector<std::unique_ptr<WhereClauseItem>> where_clause_items; + std::vector<std::unique_ptr<WhereClauseItem> > where_clause_items; // should this store location info? public: WhereClause ( - std::vector<std::unique_ptr<WhereClauseItem>> where_clause_items) + std::vector<std::unique_ptr<WhereClauseItem> > where_clause_items) : where_clause_items (std::move (where_clause_items)) {} @@ -292,13 +335,23 @@ public: // Creates a WhereClause with no items. static WhereClause create_empty () { - return WhereClause (std::vector<std::unique_ptr<WhereClauseItem>> ()); + return WhereClause (std::vector<std::unique_ptr<WhereClauseItem> > ()); } // Returns whether the WhereClause has no items. bool is_empty () const { return where_clause_items.empty (); } std::string as_string () const; + + // TODO: this mutable getter seems kinda dodgy + std::vector<std::unique_ptr<WhereClauseItem> > &get_items () + { + return where_clause_items; + } + const std::vector<std::unique_ptr<WhereClauseItem> > &get_items () const + { + return where_clause_items; + } }; // A self parameter in a method @@ -322,6 +375,8 @@ private: {} // this is ok as no outside classes can ever call this + // TODO: self param can have outer attributes + public: // Returns whether the self-param has a type field. bool has_type () const { return type != nullptr; } @@ -332,21 +387,15 @@ public: // Returns whether the self-param is in an error state. bool is_error () const { - return has_type () && has_lifetime (); + return (has_type () && has_lifetime ()) || (has_lifetime () && !has_ref); // not having either is not an error } // Creates an error state self-param. static SelfParam create_error () { - /* HACK: creates a dummy type. Since it's a unique pointer, it should - * clean it up, but it still allocates memory, which is not ideal. */ - return SelfParam (Lifetime (Lifetime::STATIC), false, false, - new QualifiedPathInType ( - QualifiedPathInType::create_error ())); - /* FIXME: is there a reason why I didn't just create a null pointer? Is it - * due to error being having both a type and a lifetime? If it is, wouldn't - * something like "not has_ref and has lifetime" for error be better? */ + // cannot have no ref but have a lifetime at the same time + return SelfParam (Lifetime (Lifetime::STATIC), false, false, nullptr); } // Type-based self parameter (not ref, no lifetime) @@ -373,13 +422,16 @@ public: // Overload assignment operator to use clone SelfParam &operator= (SelfParam const &other) { - if (other.type != nullptr) - type = other.type->clone_type (); is_mut = other.is_mut; has_ref = other.has_ref; lifetime = other.lifetime; locus = other.locus; + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + return *this; } @@ -390,6 +442,13 @@ public: std::string as_string () const; Location get_locus () const { return locus; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_type () + { + rust_assert (has_type ()); + return type; + } }; // Qualifiers for function, i.e. const, unsafe, extern etc. @@ -424,7 +483,7 @@ public: if (!this->extern_abi.empty ()) { // having extern is required; not having it is an implementation error - gcc_assert (has_extern); + rust_assert (has_extern); } } @@ -434,31 +493,45 @@ public: // A function parameter struct FunctionParam { -public: +private: + std::vector<Attribute> outer_attrs; + Location locus; std::unique_ptr<Pattern> param_name; std::unique_ptr<Type> type; - Location locus; - +public: FunctionParam (std::unique_ptr<Pattern> param_name, - std::unique_ptr<Type> param_type, Location locus) - : param_name (std::move (param_name)), type (std::move (param_type)), - locus (locus) + std::unique_ptr<Type> param_type, + std::vector<Attribute> outer_attrs, Location locus) + : outer_attrs (std::move (outer_attrs)), locus (locus), + param_name (std::move (param_name)), type (std::move (param_type)) {} // Copy constructor uses clone - FunctionParam (FunctionParam const &other) - : param_name (other.param_name->clone_pattern ()), - type (other.type->clone_type ()), locus (other.locus) - {} + FunctionParam (FunctionParam const &other) : locus (other.locus) + { + // guard to prevent nullptr dereference + if (other.param_name != nullptr) + param_name = other.param_name->clone_pattern (); + if (other.type != nullptr) + type = other.type->clone_type (); + } // Overload assignment operator to use clone FunctionParam &operator= (FunctionParam const &other) { - param_name = other.param_name->clone_pattern (); - type = other.type->clone_type (); locus = other.locus; + // guard to prevent nullptr dereference + if (other.param_name != nullptr) + param_name = other.param_name->clone_pattern (); + else + param_name = nullptr; + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + return *this; } @@ -472,12 +545,30 @@ public: // Creates an error FunctionParam. static FunctionParam create_error () { - return FunctionParam (nullptr, nullptr, Location ()); + return FunctionParam (nullptr, nullptr, {}, Location ()); } std::string as_string () const; Location get_locus () const { return locus; } + + // TODO: seems kinda dodgy. Think of better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Pattern> &get_pattern () + { + rust_assert (param_name != nullptr); + return param_name; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_type () + { + rust_assert (type != nullptr); + return type; + } }; // Visibility of item - if the item has it, then it is some form of public @@ -581,7 +672,7 @@ class Method : public InherentImplItem, public TraitImplItem // bool has_generics; // Generics generic_params; - std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined + std::vector<std::unique_ptr<GenericParam> > generic_params; // inlined SelfParam self_param; @@ -596,7 +687,7 @@ class Method : public InherentImplItem, public TraitImplItem // bool has_where_clause; WhereClause where_clause; - std::unique_ptr<BlockExpr> expr; + std::unique_ptr<BlockExpr> function_body; Location locus; @@ -604,17 +695,18 @@ public: // Returns whether the method is in an error state. bool is_error () const { - return expr == nullptr || method_name.empty () || self_param.is_error (); + return function_body == nullptr || method_name.empty () + || self_param.is_error (); } // Creates an error state method. static Method create_error () { return Method ("", FunctionQualifiers (FunctionQualifiers::NONE, true), - std::vector<std::unique_ptr<GenericParam>> (), + std::vector<std::unique_ptr<GenericParam> > (), SelfParam::create_error (), std::vector<FunctionParam> (), nullptr, WhereClause::create_empty (), nullptr, - Visibility::create_error (), std::vector<Attribute> ()); + Visibility::create_error (), std::vector<Attribute> (), {}); } // Returns whether the method has generic parameters. @@ -634,11 +726,11 @@ public: // Mega-constructor with all possible fields Method (Identifier method_name, FunctionQualifiers qualifiers, - std::vector<std::unique_ptr<GenericParam>> generic_params, + std::vector<std::unique_ptr<GenericParam> > generic_params, SelfParam self_param, std::vector<FunctionParam> function_params, std::unique_ptr<Type> return_type, WhereClause where_clause, std::unique_ptr<BlockExpr> function_body, Visibility vis, - std::vector<Attribute> outer_attrs, Location locus = Location ()) + std::vector<Attribute> outer_attrs, Location locus) : outer_attrs (std::move (outer_attrs)), vis (std::move (vis)), qualifiers (std::move (qualifiers)), method_name (std::move (method_name)), @@ -646,8 +738,8 @@ public: self_param (std::move (self_param)), function_params (std::move (function_params)), return_type (std::move (return_type)), - where_clause (std::move (where_clause)), expr (std::move (function_body)), - locus (locus) + where_clause (std::move (where_clause)), + function_body (std::move (function_body)), locus (locus) {} // TODO: add constructor with less fields @@ -657,10 +749,16 @@ public: : outer_attrs (other.outer_attrs), vis (other.vis), qualifiers (other.qualifiers), method_name (other.method_name), self_param (other.self_param), function_params (other.function_params), - return_type (other.return_type->clone_type ()), - where_clause (other.where_clause), expr (other.expr->clone_block_expr ()), - locus (other.locus) + where_clause (other.where_clause), locus (other.locus) { + // guard to prevent null dereference (always required) + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + + // guard to prevent null dereference (only required if error state) + if (other.function_body != nullptr) + function_body = other.function_body->clone_block_expr (); + generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) generic_params.push_back (e->clone_generic_param ()); @@ -675,11 +773,21 @@ public: qualifiers = other.qualifiers; self_param = other.self_param; function_params = other.function_params; - return_type = other.return_type->clone_type (); where_clause = other.where_clause; - expr = other.expr->clone_block_expr (); locus = other.locus; + // guard to prevent null dereference (always required) + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; + + // guard to prevent null dereference (only required if error state) + if (other.function_body != nullptr) + function_body = other.function_body->clone_block_expr (); + else + function_body = nullptr; + generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) generic_params.push_back (e->clone_generic_param ()); @@ -695,6 +803,56 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if block is null, so base stripping on that. + void mark_for_strip () override { function_body = nullptr; } + bool is_marked_for_strip () const override + { + return function_body == nullptr; + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + + std::vector<FunctionParam> &get_function_params () { return function_params; } + const std::vector<FunctionParam> &get_function_params () const + { + return function_params; + } + + std::vector<std::unique_ptr<GenericParam> > &get_generic_params () + { + return generic_params; + } + const std::vector<std::unique_ptr<GenericParam> > &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_definition () + { + rust_assert (function_body != nullptr); + return function_body; + } + + SelfParam &get_self_param () { return self_param; } + const SelfParam &get_self_param () const { return self_param; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_return_type () + { + rust_assert (has_return_type ()); + return return_type; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () + { + rust_assert (has_where_clause ()); + return where_clause; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -715,24 +873,25 @@ protected: class VisItem : public Item { Visibility visibility; + std::vector<Attribute> outer_attrs; protected: // Visibility constructor VisItem (Visibility visibility, std::vector<Attribute> outer_attrs = std::vector<Attribute> ()) - : Item (std::move (outer_attrs)), visibility (std::move (visibility)) + : visibility (std::move (visibility)), outer_attrs (std::move (outer_attrs)) {} // Visibility copy constructor - VisItem (VisItem const &other) : Item (other), visibility (other.visibility) + VisItem (VisItem const &other) + : visibility (other.visibility), outer_attrs (other.outer_attrs) {} // Overload assignment operator to clone VisItem &operator= (VisItem const &other) { - Item::operator= (other); visibility = other.visibility; - // outer_attrs = other.outer_attrs; + outer_attrs = other.outer_attrs; return *this; } @@ -747,6 +906,13 @@ public: bool has_visibility () const { return !visibility.is_error (); } std::string as_string () const override; + + // TODO: this mutable getter seems really dodgy. Think up better way. + Visibility &get_vis () { return visibility; } + const Visibility &get_vis () const { return visibility; } + + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } }; // Rust module item - abstract base class @@ -767,6 +933,10 @@ public: std::string as_string () const override; Location get_locus () const { return locus; } + + // Invalid if name is empty, so base stripping on that. + void mark_for_strip () override { module_name = ""; } + bool is_marked_for_strip () const override { return module_name.empty (); } }; // Module with a body, defined in file @@ -775,7 +945,7 @@ class ModuleBodied : public Module // bool has_inner_attrs; std::vector<Attribute> inner_attrs; // bool has_items; - std::vector<std::unique_ptr<Item>> items; + std::vector<std::unique_ptr<Item> > items; public: std::string as_string () const override; @@ -788,8 +958,8 @@ public: // Full constructor ModuleBodied (Identifier name, Location locus, - std::vector<std::unique_ptr<Item>> items - = std::vector<std::unique_ptr<Item>> (), + std::vector<std::unique_ptr<Item> > items + = std::vector<std::unique_ptr<Item> > (), Visibility visibility = Visibility::create_error (), std::vector<Attribute> inner_attrs = std::vector<Attribute> (), std::vector<Attribute> outer_attrs = std::vector<Attribute> ()) @@ -830,6 +1000,16 @@ public: * the module. */ void add_crate_name (std::vector<std::string> &names) const override; + // TODO: think of better way to do this - mutable getter seems dodgy + const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; } + std::vector<Attribute> &get_inner_attrs () { return inner_attrs; } + + const std::vector<std::unique_ptr<Item> > &get_items () const + { + return items; + } + std::vector<std::unique_ptr<Item> > &get_items () { return items; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -837,17 +1017,16 @@ protected: { return new ModuleBodied (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual ModuleBodied* clone_statement_impl() const override { - return new ModuleBodied(*this); - }*/ }; // Module without a body, loaded from external file class ModuleNoBody : public Module { + /* TODO: are modules loaded from file unique? As in, can you load the same + * file into two different other files? Because this may make the difference + * between simply replacing this with the module + * "definition" (as loaded from another file) vs this having to "reference" a + * module with body. */ public: std::string as_string () const override; @@ -867,12 +1046,6 @@ protected: { return new ModuleNoBody (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual ModuleNoBody* clone_statement_impl() const override { - return new ModuleNoBody(*this); - }*/ }; // Rust extern crate declaration AST node @@ -920,6 +1093,13 @@ public: names.push_back (referenced_crate); } + // Invalid if crate name is empty, so base stripping on that. + void mark_for_strip () override { referenced_crate = ""; } + bool is_marked_for_strip () const override + { + return referenced_crate.empty (); + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -927,12 +1107,6 @@ protected: { return new ExternCrate (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual ExternCrate* clone_statement_impl() const override { - return new ExternCrate(*this); - }*/ }; // The path-ish thing referred to in a use declaration - abstract base class @@ -985,7 +1159,7 @@ public: { // compiler implementation error if there is a path with a // non-path-prefixed use tree glob - gcc_assert (!has_path ()); + rust_assert (!has_path ()); } // TODO: do path-prefixed paths also have to have a path? If so, have an // assert for that too. @@ -1025,11 +1199,11 @@ private: PathType path_type; SimplePath path; - std::vector<std::unique_ptr<UseTree>> trees; + std::vector<std::unique_ptr<UseTree> > trees; public: UseTreeList (PathType path_type, SimplePath path, - std::vector<std::unique_ptr<UseTree>> trees, Location locus) + std::vector<std::unique_ptr<UseTree> > trees, Location locus) : UseTree (locus), path_type (path_type), path (std::move (path)), trees (std::move (trees)) { @@ -1037,7 +1211,7 @@ public: { // compiler implementation error if there is a path with a // non-path-prefixed use tree glob - gcc_assert (!has_path ()); + rust_assert (!has_path ()); } // TODO: do path-prefixed paths also have to have a path? If so, have an // assert for that too. @@ -1153,19 +1327,27 @@ public: // Copy constructor with clone UseDeclaration (UseDeclaration const &other) - : VisItem (other), use_tree (other.use_tree->clone_use_tree ()), - locus (other.locus) - {} + : VisItem (other), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.use_tree != nullptr) + use_tree = other.use_tree->clone_use_tree (); + } // Overloaded assignment operator to clone UseDeclaration &operator= (UseDeclaration const &other) { VisItem::operator= (other); - use_tree = other.use_tree->clone_use_tree (); // visibility = other.visibility->clone_visibility(); // outer_attrs = other.outer_attrs; locus = other.locus; + // guard to prevent null dereference (only required if error state) + if (other.use_tree != nullptr) + use_tree = other.use_tree->clone_use_tree (); + else + use_tree = nullptr; + return *this; } @@ -1177,6 +1359,10 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if use tree is null, so base stripping on that. + void mark_for_strip () override { use_tree = nullptr; } + bool is_marked_for_strip () const override { return use_tree == nullptr; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -1184,12 +1370,6 @@ protected: { return new UseDeclaration (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual UseDeclaration* clone_statement_impl() const override { - return new UseDeclaration(*this); - }*/ }; // Parameters used in a function - TODO inline? @@ -1202,13 +1382,12 @@ class LetStmt; // Rust function declaration AST node class Function : public VisItem, public InherentImplItem, public TraitImplItem { -public: FunctionQualifiers qualifiers; Identifier function_name; // bool has_generics; // Generics generic_params; - std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined + std::vector<std::unique_ptr<GenericParam> > generic_params; // inlined // bool has_function_params; // FunctionParams function_params; @@ -1224,6 +1403,7 @@ public: Location locus; +public: std::vector<LetStmt *> locals; std::string as_string () const override; @@ -1235,14 +1415,14 @@ public: bool has_function_params () const { return !function_params.empty (); } // Returns whether function has return type - if not, it is void. - bool has_function_return_type () const { return return_type != nullptr; } + bool has_return_type () const { return return_type != nullptr; } // Returns whether function has a where clause. bool has_where_clause () const { return !where_clause.is_empty (); } // Mega-constructor with all possible fields Function (Identifier function_name, FunctionQualifiers qualifiers, - std::vector<std::unique_ptr<GenericParam>> generic_params, + std::vector<std::unique_ptr<GenericParam> > generic_params, std::vector<FunctionParam> function_params, std::unique_ptr<Type> return_type, WhereClause where_clause, std::unique_ptr<BlockExpr> function_body, Visibility vis, @@ -1264,11 +1444,16 @@ public: : VisItem (other), qualifiers (other.qualifiers), function_name (other.function_name), function_params (other.function_params), - return_type (other.return_type->clone_type ()), - where_clause (other.where_clause), - function_body (other.function_body->clone_block_expr ()), - locus (other.locus) + where_clause (other.where_clause), locus (other.locus) { + // guard to prevent null dereference (always required) + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + + // guard to prevent null dereference (only required if error state) + if (other.function_body != nullptr) + function_body = other.function_body->clone_block_expr (); + generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) generic_params.push_back (e->clone_generic_param ()); @@ -1280,15 +1465,24 @@ public: VisItem::operator= (other); function_name = other.function_name; qualifiers = other.qualifiers; - // generic_params = other.generic_params; function_params = other.function_params; - return_type = other.return_type->clone_type (); where_clause = other.where_clause; - function_body = other.function_body->clone_block_expr (); // visibility = other.visibility->clone_visibility(); // outer_attrs = other.outer_attrs; locus = other.locus; + // guard to prevent null dereference (always required) + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; + + // guard to prevent null dereference (only required if error state) + if (other.function_body != nullptr) + function_body = other.function_body->clone_block_expr (); + else + function_body = nullptr; + generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) generic_params.push_back (e->clone_generic_param ()); @@ -1304,6 +1498,54 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if block is null, so base stripping on that. + void mark_for_strip () override { function_body = nullptr; } + bool is_marked_for_strip () const override + { + return function_body == nullptr; + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<FunctionParam> &get_function_params () { return function_params; } + const std::vector<FunctionParam> &get_function_params () const + { + return function_params; + } + + std::vector<std::unique_ptr<GenericParam> > &get_generic_params () + { + return generic_params; + } + const std::vector<std::unique_ptr<GenericParam> > &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_definition () + { + rust_assert (function_body != nullptr); + return function_body; + } + + FunctionQualifiers get_qualifiers () const { return qualifiers; } + + Identifier get_function_name () const { return function_name; } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () + { + rust_assert (has_where_clause ()); + return where_clause; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_return_type () + { + rust_assert (has_return_type ()); + return return_type; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -1322,12 +1564,6 @@ protected: { return new Function (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual Function* clone_statement_impl() const override { - return new Function(*this); - }*/ }; // Rust type alias (i.e. typedef) AST node @@ -1337,7 +1573,7 @@ class TypeAlias : public VisItem, public TraitImplItem // bool has_generics; // Generics generic_params; - std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined + std::vector<std::unique_ptr<GenericParam> > generic_params; // inlined // bool has_where_clause; WhereClause where_clause; @@ -1357,7 +1593,7 @@ public: // Mega-constructor with all possible fields TypeAlias (Identifier new_type_name, - std::vector<std::unique_ptr<GenericParam>> generic_params, + std::vector<std::unique_ptr<GenericParam> > generic_params, WhereClause where_clause, std::unique_ptr<Type> existing_type, Visibility vis, std::vector<Attribute> outer_attrs, Location locus) : VisItem (std::move (vis), std::move (outer_attrs)), @@ -1370,9 +1606,12 @@ public: // Copy constructor TypeAlias (TypeAlias const &other) : VisItem (other), new_type_name (other.new_type_name), - where_clause (other.where_clause), - existing_type (other.existing_type->clone_type ()), locus (other.locus) + where_clause (other.where_clause), locus (other.locus) { + // guard to prevent null dereference (only required if error state) + if (other.existing_type != nullptr) + existing_type = other.existing_type->clone_type (); + generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) generic_params.push_back (e->clone_generic_param ()); @@ -1383,13 +1622,17 @@ public: { VisItem::operator= (other); new_type_name = other.new_type_name; - // generic_params = other.generic_params; where_clause = other.where_clause; - existing_type = other.existing_type->clone_type (); // visibility = other.visibility->clone_visibility(); // outer_attrs = other.outer_attrs; locus = other.locus; + // guard to prevent null dereference (only required if error state) + if (other.existing_type != nullptr) + existing_type = other.existing_type->clone_type (); + else + existing_type = nullptr; + generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) generic_params.push_back (e->clone_generic_param ()); @@ -1405,6 +1648,36 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if existing type is null, so base stripping on that. + void mark_for_strip () override { existing_type = nullptr; } + bool is_marked_for_strip () const override + { + return existing_type == nullptr; + } + + std::vector<std::unique_ptr<GenericParam> > &get_generic_params () + { + return generic_params; + } + const std::vector<std::unique_ptr<GenericParam> > &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () + { + rust_assert (has_where_clause ()); + return where_clause; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_type_aliased () + { + rust_assert (existing_type != nullptr); + return existing_type; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -1416,30 +1689,26 @@ protected: { return new TypeAlias (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual TypeAlias* clone_statement_impl() const override { - return new TypeAlias(*this); - }*/ }; // Rust base struct declaration AST node - abstract base class class Struct : public VisItem { -public: +protected: // protected to enable access by derived classes - allows better as_string Identifier struct_name; // bool has_generics; // Generics generic_params; - std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined + std::vector<std::unique_ptr<GenericParam> > generic_params; // inlined // bool has_where_clause; WhereClause where_clause; +private: Location locus; +public: // Returns whether struct has generic parameters. bool has_generics () const { return !generic_params.empty (); } @@ -1448,9 +1717,31 @@ public: Location get_locus () const { return locus; } + // Invalid if name is empty, so base stripping on that. + void mark_for_strip () override { struct_name = ""; } + bool is_marked_for_strip () const override { return struct_name.empty (); } + + Identifier get_struct_name () const { return struct_name; } + + std::vector<std::unique_ptr<GenericParam> > &get_generic_params () + { + return generic_params; + } + const std::vector<std::unique_ptr<GenericParam> > &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () + { + rust_assert (has_where_clause ()); + return where_clause; + } + protected: Struct (Identifier struct_name, - std::vector<std::unique_ptr<GenericParam>> generic_params, + std::vector<std::unique_ptr<GenericParam> > generic_params, WhereClause where_clause, Visibility vis, Location locus, std::vector<Attribute> outer_attrs = std::vector<Attribute> ()) : VisItem (std::move (vis), std::move (outer_attrs)), @@ -1492,7 +1783,7 @@ protected: // A single field in a struct struct StructField { -public: +private: // bool has_outer_attributes; std::vector<Attribute> outer_attrs; @@ -1504,6 +1795,7 @@ public: // should this store location info? +public: // Returns whether struct field has any outer attributes. bool has_outer_attributes () const { return !outer_attrs.empty (); } @@ -1520,9 +1812,12 @@ public: // Copy constructor StructField (StructField const &other) : outer_attrs (other.outer_attrs), visibility (other.visibility), - field_name (other.field_name), - field_type (other.field_type->clone_type ()) - {} + field_name (other.field_name) + { + // guard to prevent null dereference + if (other.field_type != nullptr) + field_type = other.field_type->clone_type (); + } ~StructField () = default; @@ -1530,10 +1825,15 @@ public: StructField &operator= (StructField const &other) { field_name = other.field_name; - field_type = other.field_type->clone_type (); visibility = other.visibility; outer_attrs = other.outer_attrs; + // guard to prevent null dereference + if (other.field_type != nullptr) + field_type = other.field_type->clone_type (); + else + field_type = nullptr; + return *this; } @@ -1555,20 +1855,35 @@ public: } std::string as_string () const; + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + + Identifier get_field_name () const { return field_name; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_field_type () + { + rust_assert (field_type != nullptr); + return field_type; + } + + Visibility get_visibility () const { return visibility; } }; // Rust struct declaration with true struct type AST node class StructStruct : public Struct { -public: std::vector<StructField> fields; bool is_unit; +public: std::string as_string () const override; // Mega-constructor with all possible fields StructStruct (std::vector<StructField> fields, Identifier struct_name, - std::vector<std::unique_ptr<GenericParam>> generic_params, + std::vector<std::unique_ptr<GenericParam> > generic_params, WhereClause where_clause, bool is_unit, Visibility vis, std::vector<Attribute> outer_attrs, Location locus) : Struct (std::move (struct_name), std::move (generic_params), @@ -1579,7 +1894,7 @@ public: // Unit struct constructor StructStruct (Identifier struct_name, - std::vector<std::unique_ptr<GenericParam>> generic_params, + std::vector<std::unique_ptr<GenericParam> > generic_params, WhereClause where_clause, Visibility vis, std::vector<Attribute> outer_attrs, Location locus) : Struct (std::move (struct_name), std::move (generic_params), @@ -1596,6 +1911,10 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<StructField> &get_fields () { return fields; } + const std::vector<StructField> &get_fields () const { return fields; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -1603,12 +1922,6 @@ protected: { return new StructStruct (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual StructStruct* clone_statement_impl() const override { - return new StructStruct(*this); - }*/ }; // A single field in a tuple @@ -1642,19 +1955,27 @@ public: // Copy constructor with clone TupleField (TupleField const &other) - : outer_attrs (other.outer_attrs), visibility (other.visibility), - field_type (other.field_type->clone_type ()) - {} + : outer_attrs (other.outer_attrs), visibility (other.visibility) + { + // guard to prevent null dereference (only required if error) + if (other.field_type != nullptr) + field_type = other.field_type->clone_type (); + } ~TupleField () = default; // Overloaded assignment operator to clone TupleField &operator= (TupleField const &other) { - field_type = other.field_type->clone_type (); visibility = other.visibility; outer_attrs = other.outer_attrs; + // guard to prevent null dereference (only required if error) + if (other.field_type != nullptr) + field_type = other.field_type->clone_type (); + else + field_type = nullptr; + return *this; } @@ -1672,6 +1993,17 @@ public: } std::string as_string () const; + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_field_type () + { + rust_assert (field_type != nullptr); + return field_type; + } }; // Rust tuple declared using struct keyword AST node @@ -1684,7 +2016,7 @@ public: // Mega-constructor with all possible fields TupleStruct (std::vector<TupleField> fields, Identifier struct_name, - std::vector<std::unique_ptr<GenericParam>> generic_params, + std::vector<std::unique_ptr<GenericParam> > generic_params, WhereClause where_clause, Visibility vis, std::vector<Attribute> outer_attrs, Location locus) : Struct (std::move (struct_name), std::move (generic_params), @@ -1695,6 +2027,10 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<TupleField> &get_fields () { return fields; } + const std::vector<TupleField> &get_fields () const { return fields; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -1702,12 +2038,6 @@ protected: { return new TupleStruct (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual TupleStruct* clone_statement_impl() const override { - return new TupleStruct(*this); - }*/ }; /* An item used in an "enum" tagged union - not abstract: base represents a @@ -1744,6 +2074,14 @@ public: // not pure virtual as not abstract virtual void accept_vis (ASTVisitor &vis); + // Based on idea that name is never empty. + void mark_for_strip () { variant_name = ""; } + bool is_marked_for_strip () const { return variant_name.empty (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + protected: // Clone function implementation as (not pure) virtual method virtual EnumItem *clone_enum_item_impl () const @@ -1772,6 +2110,13 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<TupleField> &get_tuple_fields () { return tuple_fields; } + const std::vector<TupleField> &get_tuple_fields () const + { + return tuple_fields; + } + protected: // Clone function implementation as (not pure) virtual method EnumItemTuple *clone_enum_item_impl () const override @@ -1801,6 +2146,13 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<StructField> &get_struct_fields () { return struct_fields; } + const std::vector<StructField> &get_struct_fields () const + { + return struct_fields; + } + protected: // Clone function implementation as (not pure) virtual method EnumItemStruct *clone_enum_item_impl () const override @@ -1845,6 +2197,13 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_expr () + { + rust_assert (expression != nullptr); + return expression; + } + protected: // Clone function implementation as (not pure) virtual method EnumItemDiscriminant *clone_enum_item_impl () const override @@ -1860,12 +2219,12 @@ class Enum : public VisItem // bool has_generics; // Generics generic_params; - std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined + std::vector<std::unique_ptr<GenericParam> > generic_params; // inlined // bool has_where_clause; WhereClause where_clause; - std::vector<std::unique_ptr<EnumItem>> items; + std::vector<std::unique_ptr<EnumItem> > items; Location locus; @@ -1884,8 +2243,8 @@ public: // Mega-constructor Enum (Identifier enum_name, Visibility vis, - std::vector<std::unique_ptr<GenericParam>> generic_params, - WhereClause where_clause, std::vector<std::unique_ptr<EnumItem>> items, + std::vector<std::unique_ptr<GenericParam> > generic_params, + WhereClause where_clause, std::vector<std::unique_ptr<EnumItem> > items, std::vector<Attribute> outer_attrs, Location locus) : VisItem (std::move (vis), std::move (outer_attrs)), enum_name (std::move (enum_name)), @@ -1937,16 +2296,37 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if name is empty, so base stripping on that. + void mark_for_strip () override { enum_name = ""; } + bool is_marked_for_strip () const override { return enum_name.empty (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<std::unique_ptr<EnumItem> > &get_variants () { return items; } + const std::vector<std::unique_ptr<EnumItem> > &get_variants () const + { + return items; + } + + std::vector<std::unique_ptr<GenericParam> > &get_generic_params () + { + return generic_params; + } + const std::vector<std::unique_ptr<GenericParam> > &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () + { + rust_assert (has_where_clause ()); + return where_clause; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ Enum *clone_item_impl () const override { return new Enum (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual Enum* clone_statement_impl() const override { - return new Enum(*this); - }*/ }; // Rust untagged union used for C compat AST node @@ -1956,7 +2336,7 @@ class Union : public VisItem // bool has_generics; // Generics generic_params; - std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined + std::vector<std::unique_ptr<GenericParam> > generic_params; // inlined // bool has_where_clause; WhereClause where_clause; @@ -1975,7 +2355,7 @@ public: bool has_where_clause () const { return !where_clause.is_empty (); } Union (Identifier union_name, Visibility vis, - std::vector<std::unique_ptr<GenericParam>> generic_params, + std::vector<std::unique_ptr<GenericParam> > generic_params, WhereClause where_clause, std::vector<StructField> variants, std::vector<Attribute> outer_attrs, Location locus) : VisItem (std::move (vis), std::move (outer_attrs)), @@ -2020,16 +2400,34 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if name is empty, so base stripping on that. + void mark_for_strip () override { union_name = ""; } + bool is_marked_for_strip () const override { return union_name.empty (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<StructField> &get_variants () { return variants; } + const std::vector<StructField> &get_variants () const { return variants; } + + std::vector<std::unique_ptr<GenericParam> > &get_generic_params () + { + return generic_params; + } + const std::vector<std::unique_ptr<GenericParam> > &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () + { + rust_assert (has_where_clause ()); + return where_clause; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ Union *clone_item_impl () const override { return new Union (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual Union* clone_statement_impl() const override { - return new Union(*this); - }*/ }; /* "Constant item" AST node - used for constant, compile-time expressions @@ -2041,7 +2439,7 @@ class ConstantItem : public VisItem, // either has an identifier or "_" - maybe handle in identifier? // bool identifier_is_underscore; // if no identifier declared, identifier will be "_" - Identifier identifier; + std::string identifier; std::unique_ptr<Type> type; std::unique_ptr<Expr> const_expr; @@ -2051,7 +2449,7 @@ class ConstantItem : public VisItem, public: std::string as_string () const override; - ConstantItem (Identifier ident, Visibility vis, std::unique_ptr<Type> type, + ConstantItem (std::string ident, Visibility vis, std::unique_ptr<Type> type, std::unique_ptr<Expr> const_expr, std::vector<Attribute> outer_attrs, Location locus) : VisItem (std::move (vis), std::move (outer_attrs)), @@ -2060,20 +2458,32 @@ public: {} ConstantItem (ConstantItem const &other) - : VisItem (other), identifier (other.identifier), - type (other.type->clone_type ()), - const_expr (other.const_expr->clone_expr ()), locus (other.locus) - {} + : VisItem (other), identifier (other.identifier), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.type != nullptr) + type = other.type->clone_type (); + if (other.const_expr != nullptr) + const_expr = other.const_expr->clone_expr (); + } // Overload assignment operator to clone ConstantItem &operator= (ConstantItem const &other) { VisItem::operator= (other); identifier = other.identifier; - type = other.type->clone_type (); - const_expr = other.const_expr->clone_expr (); locus = other.locus; + // guard to prevent null dereference (only required if error state) + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + if (other.const_expr != nullptr) + const_expr = other.const_expr->clone_expr (); + else + const_expr = nullptr; + return *this; } @@ -2083,12 +2493,37 @@ public: /* Returns whether constant item is an "unnamed" (wildcard underscore used * as identifier) constant. */ - bool is_unnamed () const { return identifier == std::string ("_"); } + bool is_unnamed () const { return identifier == "_"; } Location get_locus () const { return locus; } void accept_vis (ASTVisitor &vis) override; + // Invalid if type or expression are null, so base stripping on that. + void mark_for_strip () override + { + type = nullptr; + const_expr = nullptr; + } + bool is_marked_for_strip () const override + { + return type == nullptr && const_expr == nullptr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_expr () + { + rust_assert (const_expr != nullptr); + return const_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_type () + { + rust_assert (type != nullptr); + return type; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -2110,12 +2545,6 @@ protected: { return new ConstantItem (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual ConstantItem* clone_statement_impl() const override { - return new ConstantItem(*this); - }*/ }; /* Static item AST node - items within module scope with fixed storage @@ -2142,9 +2571,14 @@ public: // Copy constructor with clone StaticItem (StaticItem const &other) : VisItem (other), has_mut (other.has_mut), name (other.name), - type (other.type->clone_type ()), expr (other.expr->clone_expr ()), locus (other.locus) - {} + { + // guard to prevent null dereference (only required if error state) + if (other.type != nullptr) + type = other.type->clone_type (); + if (other.expr != nullptr) + expr = other.expr->clone_expr (); + } // Overloaded assignment operator to clone StaticItem &operator= (StaticItem const &other) @@ -2152,10 +2586,18 @@ public: VisItem::operator= (other); name = other.name; has_mut = other.has_mut; - type = other.type->clone_type (); - expr = other.expr->clone_expr (); locus = other.locus; + // guard to prevent null dereference (only required if error state) + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + if (other.expr != nullptr) + expr = other.expr->clone_expr (); + else + expr = nullptr; + return *this; } @@ -2167,6 +2609,31 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if type or expression are null, so base stripping on that. + void mark_for_strip () override + { + type = nullptr; + expr = nullptr; + } + bool is_marked_for_strip () const override + { + return type == nullptr && expr == nullptr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_expr () + { + rust_assert (expr != nullptr); + return expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_type () + { + rust_assert (type != nullptr); + return type; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -2174,12 +2641,6 @@ protected: { return new StaticItem (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual StaticItem* clone_statement_impl() const override { - return new StaticItem(*this); - }*/ }; // Function declaration in traits @@ -2192,7 +2653,7 @@ private: // bool has_generics; // Generics generic_params; - std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined + std::vector<std::unique_ptr<GenericParam> > generic_params; // inlined // bool has_params; // FunctionParams function_params; @@ -2221,7 +2682,7 @@ public: // Mega-constructor TraitFunctionDecl (Identifier function_name, FunctionQualifiers qualifiers, - std::vector<std::unique_ptr<GenericParam>> generic_params, + std::vector<std::unique_ptr<GenericParam> > generic_params, std::vector<FunctionParam> function_params, std::unique_ptr<Type> return_type, WhereClause where_clause) @@ -2236,10 +2697,12 @@ public: // Copy constructor with clone TraitFunctionDecl (TraitFunctionDecl const &other) : qualifiers (other.qualifiers), function_name (other.function_name), - function_params (other.function_params), - return_type (other.return_type->clone_type ()), - where_clause (other.where_clause) + function_params (other.function_params), where_clause (other.where_clause) { + // guard to prevent nullptr dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) generic_params.push_back (e->clone_generic_param ()); @@ -2253,9 +2716,14 @@ public: function_name = other.function_name; qualifiers = other.qualifiers; function_params = other.function_params; - return_type = other.return_type->clone_type (); where_clause = other.where_clause; + // guard to prevent nullptr dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; + generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) generic_params.push_back (e->clone_generic_param ()); @@ -2268,6 +2736,40 @@ public: TraitFunctionDecl &operator= (TraitFunctionDecl &&other) = default; std::string as_string () const; + + // Invalid if function name is empty, so base stripping on that. + void mark_for_strip () { function_name = ""; } + bool is_marked_for_strip () const { return function_name.empty (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<FunctionParam> &get_function_params () { return function_params; } + const std::vector<FunctionParam> &get_function_params () const + { + return function_params; + } + + std::vector<std::unique_ptr<GenericParam> > &get_generic_params () + { + return generic_params; + } + const std::vector<std::unique_ptr<GenericParam> > &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_return_type () + { + rust_assert (has_return_type ()); + return return_type; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () + { + rust_assert (has_where_clause ()); + return where_clause; + } }; // Actual trait item function declaration within traits @@ -2292,6 +2794,7 @@ public: TraitItemFunc (TraitItemFunc const &other) : outer_attrs (other.outer_attrs), decl (other.decl), locus (other.locus) { + // guard to prevent null dereference if (other.block_expr != nullptr) block_expr = other.block_expr->clone_block_expr (); } @@ -2303,8 +2806,12 @@ public: outer_attrs = other.outer_attrs; decl = other.decl; locus = other.locus; + + // guard to prevent null dereference if (other.block_expr != nullptr) block_expr = other.block_expr->clone_block_expr (); + else + block_expr = nullptr; return *this; } @@ -2319,6 +2826,31 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if trait decl is empty, so base stripping on that. + void mark_for_strip () override { decl.mark_for_strip (); } + bool is_marked_for_strip () const override + { + return decl.is_marked_for_strip (); + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_definition () + { + rust_assert (has_definition ()); + return block_expr; + } + + // TODO: is this better? Or is a "vis_block" better? + TraitFunctionDecl &get_trait_function_decl () + { + // TODO: maybe only allow access if not marked for strip? + return decl; + } + protected: // Clone function implementation as (not pure) virtual method TraitItemFunc *clone_trait_item_impl () const override @@ -2337,7 +2869,7 @@ private: // bool has_generics; // Generics generic_params; - std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined + std::vector<std::unique_ptr<GenericParam> > generic_params; // inlined SelfParam self_param; @@ -2368,7 +2900,7 @@ public: // Mega-constructor TraitMethodDecl (Identifier function_name, FunctionQualifiers qualifiers, - std::vector<std::unique_ptr<GenericParam>> generic_params, + std::vector<std::unique_ptr<GenericParam> > generic_params, SelfParam self_param, std::vector<FunctionParam> function_params, std::unique_ptr<Type> return_type, WhereClause where_clause) @@ -2385,9 +2917,12 @@ public: TraitMethodDecl (TraitMethodDecl const &other) : qualifiers (other.qualifiers), function_name (other.function_name), self_param (other.self_param), function_params (other.function_params), - return_type (other.return_type->clone_type ()), where_clause (other.where_clause) { + // guard to prevent nullptr dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) generic_params.push_back (e->clone_generic_param ()); @@ -2402,9 +2937,14 @@ public: qualifiers = other.qualifiers; self_param = other.self_param; function_params = other.function_params; - return_type = other.return_type->clone_type (); where_clause = other.where_clause; + // guard to prevent nullptr dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; + generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) generic_params.push_back (e->clone_generic_param ()); @@ -2417,6 +2957,43 @@ public: TraitMethodDecl &operator= (TraitMethodDecl &&other) = default; std::string as_string () const; + + // Invalid if method name is empty, so base stripping on that. + void mark_for_strip () { function_name = ""; } + bool is_marked_for_strip () const { return function_name.empty (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<FunctionParam> &get_function_params () { return function_params; } + const std::vector<FunctionParam> &get_function_params () const + { + return function_params; + } + + std::vector<std::unique_ptr<GenericParam> > &get_generic_params () + { + return generic_params; + } + const std::vector<std::unique_ptr<GenericParam> > &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_return_type () + { + rust_assert (has_return_type ()); + return return_type; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () + { + rust_assert (has_where_clause ()); + return where_clause; + } + + SelfParam &get_self_param () { return self_param; } + const SelfParam &get_self_param () const { return self_param; } }; // Actual trait item method declaration within traits @@ -2439,9 +3016,12 @@ public: // Copy constructor with clone TraitItemMethod (TraitItemMethod const &other) - : outer_attrs (other.outer_attrs), decl (other.decl), - block_expr (other.block_expr->clone_block_expr ()), locus (other.locus) - {} + : outer_attrs (other.outer_attrs), decl (other.decl), locus (other.locus) + { + // guard to prevent null dereference + if (other.block_expr != nullptr) + block_expr = other.block_expr->clone_block_expr (); + } // Overloaded assignment operator to clone TraitItemMethod &operator= (TraitItemMethod const &other) @@ -2449,9 +3029,14 @@ public: TraitItem::operator= (other); outer_attrs = other.outer_attrs; decl = other.decl; - block_expr = other.block_expr->clone_block_expr (); locus = other.locus; + // guard to prevent null dereference + if (other.block_expr != nullptr) + block_expr = other.block_expr->clone_block_expr (); + else + block_expr = nullptr; + return *this; } @@ -2465,6 +3050,31 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if trait decl is empty, so base stripping on that. + void mark_for_strip () override { decl.mark_for_strip (); } + bool is_marked_for_strip () const override + { + return decl.is_marked_for_strip (); + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + TraitMethodDecl &get_trait_method_decl () + { + // TODO: maybe only allow access if not marked for strip? + return decl; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<BlockExpr> &get_definition () + { + rust_assert (has_definition ()); + return block_expr; + } + protected: // Clone function implementation as (not pure) virtual method TraitItemMethod *clone_trait_item_impl () const override @@ -2498,10 +3108,16 @@ public: // Copy constructor with clones TraitItemConst (TraitItemConst const &other) - : outer_attrs (other.outer_attrs), name (other.name), - type (other.type->clone_type ()), expr (other.expr->clone_expr ()), - locus (other.locus) - {} + : outer_attrs (other.outer_attrs), name (other.name), locus (other.locus) + { + // guard to prevent null dereference + if (other.expr != nullptr) + expr = other.expr->clone_expr (); + + // guard to prevent null dereference (only for error state) + if (other.type != nullptr) + type = other.type->clone_type (); + } // Overloaded assignment operator to clone TraitItemConst &operator= (TraitItemConst const &other) @@ -2509,10 +3125,20 @@ public: TraitItem::operator= (other); outer_attrs = other.outer_attrs; name = other.name; - type = other.type->clone_type (); - expr = other.expr->clone_expr (); locus = other.locus; + // guard to prevent null dereference + if (other.expr != nullptr) + expr = other.expr->clone_expr (); + else + expr = nullptr; + + // guard to prevent null dereference (only for error state) + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + return *this; } @@ -2526,6 +3152,28 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if type is null, so base stripping on that. + void mark_for_strip () override { type = nullptr; } + bool is_marked_for_strip () const override { return type == nullptr; } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_expr () + { + rust_assert (expr != nullptr); + return expr; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_type () + { + rust_assert (type != nullptr); + return type; + } + protected: // Clone function implementation as (not pure) virtual method TraitItemConst *clone_trait_item_impl () const override @@ -2543,7 +3191,7 @@ class TraitItemType : public TraitItem // bool has_type_param_bounds; // TypeParamBounds type_param_bounds; - std::vector<std::unique_ptr<TypeParamBound>> + std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds; // inlined form Location locus; @@ -2554,7 +3202,7 @@ public: TraitItemType ( Identifier name, - std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, + std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds, std::vector<Attribute> outer_attrs, Location locus) : outer_attrs (std::move (outer_attrs)), name (std::move (name)), type_param_bounds (std::move (type_param_bounds)), locus (locus) @@ -2594,6 +3242,25 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if name is empty, so base stripping on that. + void mark_for_strip () override { name = ""; } + bool is_marked_for_strip () const override { return name.empty (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + + // TODO: mutable getter seems kinda dodgy + std::vector<std::unique_ptr<TypeParamBound> > &get_type_param_bounds () + { + return type_param_bounds; + } + const std::vector<std::unique_ptr<TypeParamBound> > & + get_type_param_bounds () const + { + return type_param_bounds; + } + protected: // Clone function implementation as (not pure) virtual method TraitItemType *clone_trait_item_impl () const override @@ -2606,23 +3273,24 @@ protected: class Trait : public VisItem { bool has_unsafe; - Identifier name; // bool has_generics; // Generics generic_params; - std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined + std::vector<std::unique_ptr<GenericParam> > generic_params; // inlined // bool has_type_param_bounds; // TypeParamBounds type_param_bounds; - std::vector<std::unique_ptr<TypeParamBound>> + std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds; // inlined form // bool has_where_clause; WhereClause where_clause; + std::vector<Attribute> inner_attrs; + // bool has_trait_items; - std::vector<std::unique_ptr<TraitItem>> trait_items; + std::vector<std::unique_ptr<TraitItem> > trait_items; Location locus; @@ -2641,25 +3309,31 @@ public: // Returns whether trait has trait items. bool has_trait_items () const { return !trait_items.empty (); } + // Returns whether trait has inner attributes. + bool has_inner_attrs () const { return !inner_attrs.empty (); } + // Mega-constructor Trait (Identifier name, bool is_unsafe, - std::vector<std::unique_ptr<GenericParam>> generic_params, - std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, + std::vector<std::unique_ptr<GenericParam> > generic_params, + std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds, WhereClause where_clause, - std::vector<std::unique_ptr<TraitItem>> trait_items, Visibility vis, - std::vector<Attribute> outer_attrs, Location locus) + std::vector<std::unique_ptr<TraitItem> > trait_items, Visibility vis, + std::vector<Attribute> outer_attrs, std::vector<Attribute> inner_attrs, + Location locus) : VisItem (std::move (vis), std::move (outer_attrs)), has_unsafe (is_unsafe), name (std::move (name)), generic_params (std::move (generic_params)), type_param_bounds (std::move (type_param_bounds)), where_clause (std::move (where_clause)), + inner_attrs (std::move (inner_attrs)), trait_items (std::move (trait_items)), locus (locus) {} // Copy constructor with vector clone Trait (Trait const &other) : VisItem (other), has_unsafe (other.has_unsafe), name (other.name), - where_clause (other.where_clause), locus (other.locus) + where_clause (other.where_clause), inner_attrs (other.inner_attrs), + locus (other.locus) { generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) @@ -2681,6 +3355,7 @@ public: name = other.name; has_unsafe = other.has_unsafe; where_clause = other.where_clause; + inner_attrs = other.inner_attrs; locus = other.locus; generic_params.reserve (other.generic_params.size ()); @@ -2706,16 +3381,53 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if trait name is empty, so base stripping on that. + void mark_for_strip () override { name = ""; } + bool is_marked_for_strip () const override { return name.empty (); } + + // TODO: think of better way to do this + const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; } + std::vector<Attribute> &get_inner_attrs () { return inner_attrs; } + + const std::vector<std::unique_ptr<TraitItem> > &get_trait_items () const + { + return trait_items; + } + std::vector<std::unique_ptr<TraitItem> > &get_trait_items () + { + return trait_items; + } + + std::vector<std::unique_ptr<GenericParam> > &get_generic_params () + { + return generic_params; + } + const std::vector<std::unique_ptr<GenericParam> > &get_generic_params () const + { + return generic_params; + } + + std::vector<std::unique_ptr<TypeParamBound> > &get_type_param_bounds () + { + return type_param_bounds; + } + const std::vector<std::unique_ptr<TypeParamBound> > & + get_type_param_bounds () const + { + return type_param_bounds; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () + { + rust_assert (has_where_clause ()); + return where_clause; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ Trait *clone_item_impl () const override { return new Trait (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual Trait* clone_statement_impl() const override { - return new Trait(*this); - }*/ }; // Implementation item declaration AST node - abstract base class @@ -2725,7 +3437,7 @@ class Impl : public VisItem protected: // bool has_generics; // Generics generic_params; - std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined + std::vector<std::unique_ptr<GenericParam> > generic_params; // inlined std::unique_ptr<Type> trait_type; @@ -2751,9 +3463,40 @@ public: Location get_locus () const { return locus; } + // Invalid if trait type is null, so base stripping on that. + void mark_for_strip () override { trait_type = nullptr; } + bool is_marked_for_strip () const override { return trait_type == nullptr; } + + // TODO: think of better way to do this + const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; } + std::vector<Attribute> &get_inner_attrs () { return inner_attrs; } + + std::vector<std::unique_ptr<GenericParam> > &get_generic_params () + { + return generic_params; + } + const std::vector<std::unique_ptr<GenericParam> > &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () + { + rust_assert (has_where_clause ()); + return where_clause; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_type () + { + rust_assert (trait_type != nullptr); + return trait_type; + } + protected: // Mega-constructor - Impl (std::vector<std::unique_ptr<GenericParam>> generic_params, + Impl (std::vector<std::unique_ptr<GenericParam> > generic_params, std::unique_ptr<Type> trait_type, WhereClause where_clause, Visibility vis, std::vector<Attribute> inner_attrs, std::vector<Attribute> outer_attrs, Location locus) @@ -2766,10 +3509,13 @@ protected: // Copy constructor Impl (Impl const &other) - : VisItem (other), trait_type (other.trait_type->clone_type ()), - where_clause (other.where_clause), inner_attrs (other.inner_attrs), - locus (other.locus) + : VisItem (other), where_clause (other.where_clause), + inner_attrs (other.inner_attrs), locus (other.locus) { + // guard to prevent null dereference (only required if error state) + if (other.trait_type != nullptr) + trait_type = other.trait_type->clone_type (); + generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) generic_params.push_back (e->clone_generic_param ()); @@ -2779,11 +3525,16 @@ protected: Impl &operator= (Impl const &other) { VisItem::operator= (other); - trait_type = other.trait_type->clone_type (); where_clause = other.where_clause; inner_attrs = other.inner_attrs; locus = other.locus; + // guard to prevent null dereference (only required if error state) + if (other.trait_type != nullptr) + trait_type = other.trait_type->clone_type (); + else + trait_type = nullptr; + generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) generic_params.push_back (e->clone_generic_param ()); @@ -2800,7 +3551,7 @@ protected: class InherentImpl : public Impl { // bool has_impl_items; - std::vector<std::unique_ptr<InherentImplItem>> impl_items; + std::vector<std::unique_ptr<InherentImplItem> > impl_items; public: std::string as_string () const override; @@ -2809,8 +3560,8 @@ public: bool has_impl_items () const { return !impl_items.empty (); } // Mega-constructor - InherentImpl (std::vector<std::unique_ptr<InherentImplItem>> impl_items, - std::vector<std::unique_ptr<GenericParam>> generic_params, + InherentImpl (std::vector<std::unique_ptr<InherentImplItem> > impl_items, + std::vector<std::unique_ptr<GenericParam> > generic_params, std::unique_ptr<Type> trait_type, WhereClause where_clause, Visibility vis, std::vector<Attribute> inner_attrs, std::vector<Attribute> outer_attrs, Location locus) @@ -2846,6 +3597,16 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: think of better way to do this + const std::vector<std::unique_ptr<InherentImplItem> > &get_impl_items () const + { + return impl_items; + } + std::vector<std::unique_ptr<InherentImplItem> > &get_impl_items () + { + return impl_items; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -2853,12 +3614,6 @@ protected: { return new InherentImpl (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual InherentImpl* clone_statement_impl() const override { - return new InherentImpl(*this); - }*/ }; // The "impl footrait for foo" impl block declaration AST node @@ -2869,7 +3624,7 @@ class TraitImpl : public Impl TypePath trait_path; // bool has_impl_items; - std::vector<std::unique_ptr<TraitImplItem>> impl_items; + std::vector<std::unique_ptr<TraitImplItem> > impl_items; public: std::string as_string () const override; @@ -2879,8 +3634,8 @@ public: // Mega-constructor TraitImpl (TypePath trait_path, bool is_unsafe, bool has_exclam, - std::vector<std::unique_ptr<TraitImplItem>> impl_items, - std::vector<std::unique_ptr<GenericParam>> generic_params, + std::vector<std::unique_ptr<TraitImplItem> > impl_items, + std::vector<std::unique_ptr<GenericParam> > generic_params, std::unique_ptr<Type> trait_type, WhereClause where_clause, Visibility vis, std::vector<Attribute> inner_attrs, std::vector<Attribute> outer_attrs, Location locus) @@ -2924,18 +3679,30 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: think of better way to do this + const std::vector<std::unique_ptr<TraitImplItem> > &get_impl_items () const + { + return impl_items; + } + std::vector<std::unique_ptr<TraitImplItem> > &get_impl_items () + { + return impl_items; + } + + // TODO: is this better? Or is a "vis_block" better? + TypePath &get_trait_path () + { + // TODO: assert that trait path is not empty? + return trait_path; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ TraitImpl *clone_item_impl () const override { return new TraitImpl (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual TraitImpl* clone_statement_impl() const override { - return new TraitImpl(*this); - }*/ }; +#if 0 // Abstract base class for an item used inside an extern block class ExternalItem { @@ -2951,6 +3718,10 @@ class ExternalItem public: virtual ~ExternalItem () {} + /* TODO: spec syntax rules state that "MacroInvocationSemi" can be used as + * ExternalItem, but text body isn't so clear. Adding MacroInvocationSemi + * support would require a lot of refactoring. */ + // Returns whether item has outer attributes. bool has_outer_attrs () const { return !outer_attrs.empty (); } @@ -2969,6 +3740,11 @@ public: virtual void accept_vis (ASTVisitor &vis) = 0; + // TODO: make virtual? Would be more flexible. + // Based on idea that name should never be empty. + void mark_for_strip () { item_name = ""; }; + bool is_marked_for_strip () const { return item_name.empty (); }; + protected: ExternalItem (Identifier item_name, Visibility vis, std::vector<Attribute> outer_attrs, Location locus) @@ -3003,10 +3779,20 @@ protected: // possibly make this public if required std::string get_item_name () const { return item_name; } }; +#endif // A static item used in an extern block class ExternalStaticItem : public ExternalItem { + // bool has_outer_attrs; + std::vector<Attribute> outer_attrs; + + // bool has_visibility; + Visibility visibility; + + Identifier item_name; + Location locus; + bool has_mut; std::unique_ptr<Type> item_type; @@ -3014,24 +3800,36 @@ public: ExternalStaticItem (Identifier item_name, std::unique_ptr<Type> item_type, bool is_mut, Visibility vis, std::vector<Attribute> outer_attrs, Location locus) - : ExternalItem (std::move (item_name), std::move (vis), - std::move (outer_attrs), locus), - has_mut (is_mut), item_type (std::move (item_type)) + : outer_attrs (std::move (outer_attrs)), visibility (std::move (vis)), + item_name (std::move (item_name)), locus (locus), has_mut (is_mut), + item_type (std::move (item_type)) {} // Copy constructor ExternalStaticItem (ExternalStaticItem const &other) - : ExternalItem (other), has_mut (other.has_mut), - item_type (other.item_type->clone_type ()) - {} + : outer_attrs (other.outer_attrs), visibility (other.visibility), + item_name (other.item_name), locus (other.locus), has_mut (other.has_mut) + { + // guard to prevent null dereference (only required if error state) + if (other.item_type != nullptr) + item_type = other.item_type->clone_type (); + } // Overloaded assignment operator to clone ExternalStaticItem &operator= (ExternalStaticItem const &other) { - ExternalItem::operator= (other); - item_type = other.item_type->clone_type (); + outer_attrs = other.outer_attrs; + visibility = other.visibility; + item_name = other.item_name; + locus = other.locus; has_mut = other.has_mut; + // guard to prevent null dereference (only required if error state) + if (other.item_type != nullptr) + item_type = other.item_type->clone_type (); + else + item_type = nullptr; + return *this; } @@ -3043,6 +3841,29 @@ public: void accept_vis (ASTVisitor &vis) override; + // Returns whether item has outer attributes. + bool has_outer_attrs () const { return !outer_attrs.empty (); } + + // Returns whether item has non-default visibility. + bool has_visibility () const { return !visibility.is_error (); } + + Location get_locus () const { return locus; } + + // Based on idea that type should never be null. + void mark_for_strip () override { item_type = nullptr; }; + bool is_marked_for_strip () const override { return item_type == nullptr; }; + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_type () + { + rust_assert (item_type != nullptr); + return item_type; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -3057,17 +3878,22 @@ struct NamedFunctionParam { private: // bool has_name; // otherwise is _ - Identifier name; // TODO: handle wildcard in identifier? + std::string name; std::unique_ptr<Type> param_type; // TODO: should this store location data? + // seemingly new since writing this node + std::vector<Attribute> outer_attrs; + public: - // Returns whether the named function parameter has a name (i.e. name is not - // '_'). + /* Returns whether the named function parameter has a name (i.e. name is not + * '_'). */ bool has_name () const { return name != "_"; } + bool has_outer_attrs () const { return !outer_attrs.empty (); } + // Returns whether the named function parameter is in an error state. bool is_error () const { @@ -3078,17 +3904,23 @@ public: // Creates an error state named function parameter. static NamedFunctionParam create_error () { - return NamedFunctionParam ("", nullptr); + return NamedFunctionParam ("", nullptr, {}); } - NamedFunctionParam (Identifier name, std::unique_ptr<Type> param_type) - : name (std::move (name)), param_type (std::move (param_type)) + NamedFunctionParam (std::string name, std::unique_ptr<Type> param_type, + std::vector<Attribute> outer_attrs) + : name (std::move (name)), param_type (std::move (param_type)), + outer_attrs (std::move (outer_attrs)) {} // Copy constructor NamedFunctionParam (NamedFunctionParam const &other) - : name (other.name), param_type (other.param_type->clone_type ()) - {} + : name (other.name), outer_attrs (other.outer_attrs) + { + // guard to prevent null dereference (only required if error state) + if (other.param_type != nullptr) + param_type = other.param_type->clone_type (); + } ~NamedFunctionParam () = default; @@ -3096,8 +3928,14 @@ public: NamedFunctionParam &operator= (NamedFunctionParam const &other) { name = other.name; - param_type = other.param_type->clone_type (); // has_name = other.has_name; + outer_attrs = other.outer_attrs; + + // guard to prevent null dereference (only required if error state) + if (other.param_type != nullptr) + param_type = other.param_type->clone_type (); + else + param_type = nullptr; return *this; } @@ -3107,14 +3945,38 @@ public: NamedFunctionParam &operator= (NamedFunctionParam &&other) = default; std::string as_string () const; + + // Based on idea that nane should never be empty. + void mark_for_strip () { param_type = nullptr; }; + bool is_marked_for_strip () const { return is_error (); }; + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_type () + { + rust_assert (param_type != nullptr); + return param_type; + } }; // A function item used in an extern block class ExternalFunctionItem : public ExternalItem { + // bool has_outer_attrs; + std::vector<Attribute> outer_attrs; + + // bool has_visibility; + Visibility visibility; + + Identifier item_name; + Location locus; + // bool has_generics; // Generics generic_params; - std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined + std::vector<std::unique_ptr<GenericParam> > generic_params; // inlined // bool has_return_type; // FunctionReturnType return_type; @@ -3125,6 +3987,7 @@ class ExternalFunctionItem : public ExternalItem std::vector<NamedFunctionParam> function_params; bool has_variadics; + std::vector<Attribute> variadic_outer_attrs; public: // Returns whether item has generic parameters. @@ -3136,28 +3999,56 @@ public: // Returns whether item has a where clause. bool has_where_clause () const { return !where_clause.is_empty (); } + // Returns whether item has outer attributes. + bool has_outer_attrs () const { return !outer_attrs.empty (); } + + // Returns whether item has non-default visibility. + bool has_visibility () const { return !visibility.is_error (); } + + // Returns whether item has variadic parameters. + bool is_variadic () const { return has_variadics; } + + // Returns whether item has outer attributes on its variadic parameters. + bool has_variadic_outer_attrs () const + { + return !variadic_outer_attrs.empty (); + } + + Location get_locus () const { return locus; } + ExternalFunctionItem ( Identifier item_name, - std::vector<std::unique_ptr<GenericParam>> generic_params, + std::vector<std::unique_ptr<GenericParam> > generic_params, std::unique_ptr<Type> return_type, WhereClause where_clause, std::vector<NamedFunctionParam> function_params, bool has_variadics, - Visibility vis, std::vector<Attribute> outer_attrs, Location locus) - : ExternalItem (std::move (item_name), std::move (vis), - std::move (outer_attrs), locus), + std::vector<Attribute> variadic_outer_attrs, Visibility vis, + std::vector<Attribute> outer_attrs, Location locus) + : outer_attrs (std::move (outer_attrs)), visibility (std::move (vis)), + item_name (std::move (item_name)), locus (locus), generic_params (std::move (generic_params)), return_type (std::move (return_type)), where_clause (std::move (where_clause)), function_params (std::move (function_params)), - has_variadics (has_variadics) - {} + has_variadics (has_variadics), + variadic_outer_attrs (std::move (variadic_outer_attrs)) + { + // TODO: assert that if has variadic outer attrs, then has_variadics is + // true? + } // Copy constructor with clone ExternalFunctionItem (ExternalFunctionItem const &other) - : ExternalItem (other), return_type (other.return_type->clone_type ()), + : outer_attrs (other.outer_attrs), visibility (other.visibility), + item_name (other.item_name), locus (other.locus), where_clause (other.where_clause), function_params (other.function_params), - has_variadics (other.has_variadics) + has_variadics (other.has_variadics), + variadic_outer_attrs (other.variadic_outer_attrs) { + // guard to prevent null pointer dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) generic_params.push_back (e->clone_generic_param ()); @@ -3166,11 +4057,20 @@ public: // Overloaded assignment operator with clone ExternalFunctionItem &operator= (ExternalFunctionItem const &other) { - ExternalItem::operator= (other); - return_type = other.return_type->clone_type (); + outer_attrs = other.outer_attrs; + visibility = other.visibility; + item_name = other.item_name; + locus = other.locus; where_clause = other.where_clause; function_params = other.function_params; has_variadics = other.has_variadics; + variadic_outer_attrs = other.variadic_outer_attrs; + + // guard to prevent null pointer dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) @@ -3187,6 +4087,46 @@ public: void accept_vis (ASTVisitor &vis) override; + // Based on idea that nane should never be empty. + void mark_for_strip () override { item_name = ""; }; + bool is_marked_for_strip () const override { return item_name.empty (); }; + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + + std::vector<NamedFunctionParam> &get_function_params () + { + return function_params; + } + const std::vector<NamedFunctionParam> &get_function_params () const + { + return function_params; + } + + std::vector<std::unique_ptr<GenericParam> > &get_generic_params () + { + return generic_params; + } + const std::vector<std::unique_ptr<GenericParam> > &get_generic_params () const + { + return generic_params; + } + + // TODO: is this better? Or is a "vis_block" better? + WhereClause &get_where_clause () + { + rust_assert (has_where_clause ()); + return where_clause; + } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Type> &get_return_type () + { + rust_assert (has_return_type ()); + return return_type; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -3206,10 +4146,13 @@ class ExternBlock : public VisItem std::vector<Attribute> inner_attrs; // bool has_extern_items; - std::vector<std::unique_ptr<ExternalItem>> extern_items; + std::vector<std::unique_ptr<ExternalItem> > extern_items; Location locus; + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + public: std::string as_string () const override; @@ -3223,7 +4166,7 @@ public: bool has_abi () const { return !abi.empty (); } ExternBlock (std::string abi, - std::vector<std::unique_ptr<ExternalItem>> extern_items, + std::vector<std::unique_ptr<ExternalItem> > extern_items, Visibility vis, std::vector<Attribute> inner_attrs, std::vector<Attribute> outer_attrs, Location locus) : VisItem (std::move (vis), std::move (outer_attrs)), abi (std::move (abi)), @@ -3234,7 +4177,7 @@ public: // Copy constructor with vector clone ExternBlock (ExternBlock const &other) : VisItem (other), abi (other.abi), inner_attrs (other.inner_attrs), - locus (other.locus) + locus (other.locus), marked_for_strip (other.marked_for_strip) { extern_items.reserve (other.extern_items.size ()); for (const auto &e : other.extern_items) @@ -3248,6 +4191,7 @@ public: abi = other.abi; inner_attrs = other.inner_attrs; locus = other.locus; + marked_for_strip = other.marked_for_strip; extern_items.reserve (other.extern_items.size ()); for (const auto &e : other.extern_items) @@ -3264,6 +4208,24 @@ public: void accept_vis (ASTVisitor &vis) override; + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + + // TODO: think of better way to do this + const std::vector<std::unique_ptr<ExternalItem> > &get_extern_items () const + { + return extern_items; + } + std::vector<std::unique_ptr<ExternalItem> > &get_extern_items () + { + return extern_items; + } + + // TODO: think of better way to do this + const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; } + std::vector<Attribute> &get_inner_attrs () { return inner_attrs; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -3271,12 +4233,6 @@ protected: { return new ExternBlock (*this); } - - /* Use covariance to implement clone function as returning this object - * rather than base */ - /*virtual ExternBlock* clone_statement_impl() const override { - return new ExternBlock(*this); - }*/ }; // Replaced with forward decls - defined in "rust-macro.h" diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h index b51b149..2cae0f9 100644 --- a/gcc/rust/ast/rust-macro.h +++ b/gcc/rust/ast/rust-macro.h @@ -124,7 +124,7 @@ private: public: // Returns whether macro match repetition has separator token. - bool has_sep () const { return sep != NULL; } + bool has_sep () const { return sep != nullptr; } MacroMatchRepetition (std::vector<std::unique_ptr<MacroMatch> > matches, MacroRepOp op, std::unique_ptr<MacroRepSep> sep) @@ -132,9 +132,12 @@ public: {} // Copy constructor with clone - MacroMatchRepetition (MacroMatchRepetition const &other) - : op (other.op), sep (other.sep->clone_token ()) + MacroMatchRepetition (MacroMatchRepetition const &other) : op (other.op) { + // guard to protect from null pointer dereference + if (other.sep != nullptr) + sep = other.sep->clone_token (); + matches.reserve (other.matches.size ()); for (const auto &e : other.matches) matches.push_back (e->clone_macro_match ()); @@ -144,7 +147,12 @@ public: MacroMatchRepetition &operator= (MacroMatchRepetition const &other) { op = other.op; - sep = other.sep->clone_token (); + + // guard to protect from null pointer dereference + if (other.sep != nullptr) + sep = other.sep->clone_token (); + else + sep = nullptr; matches.reserve (other.matches.size ()); for (const auto &e : other.matches) @@ -280,8 +288,9 @@ public: // A macro rules definition item AST node class MacroRulesDefinition : public MacroItem { + std::vector<Attribute> outer_attrs; Identifier rule_name; - // MacroRulesDef rules_def; // TODO: inline + // MacroRulesDef rules_def; // only curly without required semicolon at end DelimType delim_type; // MacroRules rules; @@ -295,12 +304,23 @@ public: MacroRulesDefinition (Identifier rule_name, DelimType delim_type, std::vector<MacroRule> rules, std::vector<Attribute> outer_attrs, Location locus) - : MacroItem (std::move (outer_attrs)), rule_name (std::move (rule_name)), + : outer_attrs (std::move (outer_attrs)), rule_name (std::move (rule_name)), delim_type (delim_type), rules (std::move (rules)), locus (locus) {} void accept_vis (ASTVisitor &vis) override; + // Invalid if rule name is empty, so base stripping on that. + void mark_for_strip () override { rule_name = ""; } + bool is_marked_for_strip () const override { return rule_name.empty (); } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + + std::vector<MacroRule> &get_macro_rules () { return rules; } + const std::vector<MacroRule> &get_macro_rules () const { return rules; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -334,6 +354,13 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if path is empty, so base stripping on that. + void mark_for_strip () override { path = SimplePath::create_empty (); } + bool is_marked_for_strip () const override { return path.is_empty (); } + + const SimplePath &get_path () const { return path; } + SimplePath &get_path () { return path; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -344,13 +371,6 @@ protected: /* Use covariance to implement clone function as returning this object rather * than base */ - MacroInvocation *clone_expr_impl () const override - { - return new MacroInvocation (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ MacroInvocation *clone_expr_without_block_impl () const override { return new MacroInvocation (*this); @@ -358,13 +378,6 @@ protected: /* Use covariance to implement clone function as returning this object rather * than base */ - MacroInvocation *clone_type_impl () const override - { - return new MacroInvocation (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ MacroInvocation *clone_type_no_bounds_impl () const override { return new MacroInvocation (*this); @@ -572,6 +585,8 @@ protected: }; // Object that parses macros from a token stream. +/* TODO: would "AttributeParser" be a better name? MetaItems are only for + * attributes, I believe */ struct MacroParser { private: diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h index 3006780..392fc18 100644 --- a/gcc/rust/ast/rust-path.h +++ b/gcc/rust/ast/rust-path.h @@ -45,7 +45,6 @@ struct GenericArgsBinding private: Identifier identifier; std::unique_ptr<Type> type; - Location locus; public: @@ -70,9 +69,12 @@ public: // Copy constructor has to deep copy the type as it is a unique pointer GenericArgsBinding (GenericArgsBinding const &other) - : identifier (other.identifier), type (other.type->clone_type ()), - locus (other.locus) - {} + : identifier (other.identifier), locus (other.locus) + { + // guard to protect from null pointer dereference + if (other.type != nullptr) + type = other.type->clone_type (); + } // default destructor ~GenericArgsBinding () = default; @@ -81,8 +83,14 @@ public: GenericArgsBinding &operator= (GenericArgsBinding const &other) { identifier = other.identifier; - type = other.type->clone_type (); locus = other.locus; + + // guard to protect from null pointer dereference + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + return *this; } @@ -91,13 +99,20 @@ public: GenericArgsBinding &operator= (GenericArgsBinding &&other) = default; std::string as_string () const; + + // TODO: is this better? Or is a "vis_pattern" better? + std::unique_ptr<Type> &get_type () + { + rust_assert (type != nullptr); + return type; + } }; // Generic arguments allowed in each path expression segment - inline? struct GenericArgs { std::vector<Lifetime> lifetime_args; - std::vector<std::unique_ptr<Type>> type_args; + std::vector<std::unique_ptr<Type> > type_args; std::vector<GenericArgsBinding> binding_args; Location locus; @@ -110,7 +125,7 @@ public: } GenericArgs (std::vector<Lifetime> lifetime_args, - std::vector<std::unique_ptr<Type>> type_args, + std::vector<std::unique_ptr<Type> > type_args, std::vector<GenericArgsBinding> binding_args, Location locus = Location ()) : lifetime_args (std::move (lifetime_args)), @@ -152,11 +167,17 @@ public: static GenericArgs create_empty () { return GenericArgs (std::vector<Lifetime> (), - std::vector<std::unique_ptr<Type>> (), + std::vector<std::unique_ptr<Type> > (), std::vector<GenericArgsBinding> ()); } std::string as_string () const; + + // TODO: is this better? Or is a "vis_pattern" better? + std::vector<std::unique_ptr<Type> > &get_type_args () { return type_args; } + + // TODO: is this better? Or is a "vis_pattern" better? + std::vector<GenericArgsBinding> &get_binding_args () { return binding_args; } }; /* A segment of a path in expression, including an identifier aspect and maybe @@ -189,8 +210,8 @@ public: PathExprSegment (std::string segment_name, Location locus, std::vector<Lifetime> lifetime_args = std::vector<Lifetime> (), - std::vector<std::unique_ptr<Type>> type_args - = std::vector<std::unique_ptr<Type>> (), + std::vector<std::unique_ptr<Type> > type_args + = std::vector<std::unique_ptr<Type> > (), std::vector<GenericArgsBinding> binding_args = std::vector<GenericArgsBinding> ()) : segment_name (PathIdentSegment (std::move (segment_name))), @@ -212,6 +233,13 @@ public: std::string as_string () const; Location get_locus () const { return locus; } + + // TODO: is this better? Or is a "vis_pattern" better? + GenericArgs &get_generic_args () + { + rust_assert (has_generic_args ()); + return generic_args; + } }; // AST node representing a pattern that involves a "path" - abstract base class @@ -231,12 +259,23 @@ protected: * and creates a SimplePath from them. */ SimplePath convert_to_simple_path (bool with_opening_scope_resolution) const; + // Removes all segments of the path. + void remove_all_segments () + { + segments.clear (); + segments.shrink_to_fit (); + } + public: /* Returns whether the path is a single segment (excluding qualified path * initial as segment). */ bool is_single_segment () const { return segments.size () == 1; } std::string as_string () const override; + + // TODO: this seems kinda dodgy + std::vector<PathExprSegment> &get_segments () { return segments; } + const std::vector<PathExprSegment> &get_segments () const { return segments; } }; /* AST node representing a path-in-expression pattern (path that allows generic @@ -286,6 +325,10 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if path is empty (error state), so base stripping on that. + void mark_for_strip () override { remove_all_segments (); } + bool is_marked_for_strip () const override { return is_error (); } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -312,7 +355,6 @@ class TypePathSegment * GenericArgs are, so could disallow that in constructor, which won't give * that much size overhead. */ PathIdentSegment ident_segment; - Location locus; protected: @@ -387,7 +429,7 @@ public: TypePathSegmentGeneric (std::string segment_name, bool has_separating_scope_resolution, std::vector<Lifetime> lifetime_args, - std::vector<std::unique_ptr<Type>> type_args, + std::vector<std::unique_ptr<Type> > type_args, std::vector<GenericArgsBinding> binding_args, Location locus) : TypePathSegment (std::move (segment_name), @@ -401,6 +443,13 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_pattern" better? + GenericArgs &get_generic_args () + { + rust_assert (has_generic_args ()); + return generic_args; + } + protected: // Use covariance to override base class method TypePathSegmentGeneric *clone_type_path_segment_impl () const override @@ -417,7 +466,7 @@ private: /*bool has_inputs; TypePathFnInputs inputs;*/ // inlined from TypePathFnInputs - std::vector<std::unique_ptr<Type>> inputs; + std::vector<std::unique_ptr<Type> > inputs; // bool has_type; std::unique_ptr<Type> return_type; @@ -445,14 +494,7 @@ public: static TypePathFunction create_error () { return TypePathFunction (true); } // Constructor - TypePathFunction (std::vector<std::unique_ptr<Type>> inputs, - Type *type = nullptr) - : inputs (std::move (inputs)), return_type (type), is_invalid (false) - {} - // FIXME: deprecated - - // Constructor - TypePathFunction (std::vector<std::unique_ptr<Type>> inputs, + TypePathFunction (std::vector<std::unique_ptr<Type> > inputs, std::unique_ptr<Type> type = nullptr) : inputs (std::move (inputs)), return_type (std::move (type)), is_invalid (false) @@ -460,9 +502,12 @@ public: // Copy constructor with clone TypePathFunction (TypePathFunction const &other) - : return_type (other.return_type->clone_type ()), - is_invalid (other.is_invalid) + : is_invalid (other.is_invalid) { + // guard to protect from null pointer dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + inputs.reserve (other.inputs.size ()); for (const auto &e : other.inputs) inputs.push_back (e->clone_type ()); @@ -473,9 +518,14 @@ public: // Overloaded assignment operator to clone type TypePathFunction &operator= (TypePathFunction const &other) { - return_type = other.return_type->clone_type (); is_invalid = other.is_invalid; + // guard to protect from null pointer dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; + inputs.reserve (other.inputs.size ()); for (const auto &e : other.inputs) inputs.push_back (e->clone_type ()); @@ -488,6 +538,20 @@ public: TypePathFunction &operator= (TypePathFunction &&other) = default; std::string as_string () const; + + // TODO: this mutable getter seems really dodgy. Think up better way. + const std::vector<std::unique_ptr<Type> > &get_params () const + { + return inputs; + } + std::vector<std::unique_ptr<Type> > &get_params () { return inputs; } + + // TODO: is this better? Or is a "vis_pattern" better? + std::unique_ptr<Type> &get_return_type () + { + rust_assert (has_return_type ()); + return return_type; + } }; // Segment used in type path with a function argument @@ -520,6 +584,13 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_pattern" better? + TypePathFunction &get_type_path_function () + { + rust_assert (!function_path.is_error ()); + return function_path; + } + protected: // Use covariance to override base class method TypePathSegmentFunction *clone_type_path_segment_impl () const override @@ -531,18 +602,13 @@ protected: // Path used inside types class TypePath : public TypeNoBounds { -public: bool has_opening_scope_resolution; - std::vector<std::unique_ptr<TypePathSegment>> segments; + std::vector<std::unique_ptr<TypePathSegment> > segments; Location locus; protected: /* Use covariance to implement clone function as returning this object rather * than base */ - TypePath *clone_type_impl () const override { return new TypePath (*this); } - - /* Use covariance to implement clone function as returning this object rather - * than base */ TypePath *clone_type_no_bounds_impl () const override { return new TypePath (*this); @@ -562,12 +628,12 @@ public: // Creates an error state TypePath. static TypePath create_error () { - return TypePath (std::vector<std::unique_ptr<TypePathSegment>> (), + return TypePath (std::vector<std::unique_ptr<TypePathSegment> > (), Location ()); } // Constructor - TypePath (std::vector<std::unique_ptr<TypePathSegment>> segments, + TypePath (std::vector<std::unique_ptr<TypePathSegment> > segments, Location locus, bool has_opening_scope_resolution = false) : has_opening_scope_resolution (has_opening_scope_resolution), segments (std::move (segments)), locus (locus) @@ -610,8 +676,19 @@ public: TraitBound *to_trait_bound (bool in_parens) const override; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; + + // TODO: this seems kinda dodgy + std::vector<std::unique_ptr<TypePathSegment> > &get_segments () + { + return segments; + } + const std::vector<std::unique_ptr<TypePathSegment> > &get_segments () const + { + return segments; + } }; struct QualifiedPathType @@ -635,9 +712,12 @@ public: // Copy constructor uses custom deep copy for Type to preserve polymorphism QualifiedPathType (QualifiedPathType const &other) - : type_to_invoke_on (other.type_to_invoke_on->clone_type ()), - trait_path (other.trait_path), locus (other.locus) - {} + : trait_path (other.trait_path), locus (other.locus) + { + // guard to prevent null dereference + if (other.type_to_invoke_on != nullptr) + type_to_invoke_on = other.type_to_invoke_on->clone_type (); + } // default destructor ~QualifiedPathType () = default; @@ -645,9 +725,15 @@ public: // overload assignment operator to use custom clone method QualifiedPathType &operator= (QualifiedPathType const &other) { - type_to_invoke_on = other.type_to_invoke_on->clone_type (); trait_path = other.trait_path; locus = other.locus; + + // guard to prevent null dereference + if (other.type_to_invoke_on != nullptr) + type_to_invoke_on = other.type_to_invoke_on->clone_type (); + else + type_to_invoke_on = nullptr; + return *this; } @@ -670,6 +756,20 @@ public: std::string as_string () const; Location get_locus () const { return locus; } + + // TODO: is this better? Or is a "vis_pattern" better? + std::unique_ptr<Type> &get_type () + { + rust_assert (type_to_invoke_on != nullptr); + return type_to_invoke_on; + } + + // TODO: is this better? Or is a "vis_pattern" better? + TypePath &get_as_type_path () + { + rust_assert (has_as_clause ()); + return trait_path; + } }; /* AST node representing a qualified path-in-expression pattern (path that @@ -710,6 +810,20 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if path_type is error, so base stripping on that. + void mark_for_strip () override + { + path_type = QualifiedPathType::create_error (); + } + bool is_marked_for_strip () const override { return is_error (); } + + // TODO: is this better? Or is a "vis_pattern" better? + QualifiedPathType &get_qualified_path_type () + { + rust_assert (!path_type.is_error ()); + return path_type; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -731,19 +845,12 @@ protected: class QualifiedPathInType : public TypeNoBounds { QualifiedPathType path_type; - std::vector<std::unique_ptr<TypePathSegment>> segments; + std::vector<std::unique_ptr<TypePathSegment> > segments; Location locus; protected: /* Use covariance to implement clone function as returning this object rather * than base */ - QualifiedPathInType *clone_type_impl () const override - { - return new QualifiedPathInType (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ QualifiedPathInType *clone_type_no_bounds_impl () const override { return new QualifiedPathInType (*this); @@ -752,7 +859,7 @@ protected: public: QualifiedPathInType ( QualifiedPathType qual_path_type, - std::vector<std::unique_ptr<TypePathSegment>> path_segments, + std::vector<std::unique_ptr<TypePathSegment> > path_segments, Location locus = Location ()) : path_type (std::move (qual_path_type)), segments (std::move (path_segments)), locus (locus) @@ -795,12 +902,32 @@ public: { return QualifiedPathInType ( QualifiedPathType::create_error (), - std::vector<std::unique_ptr<TypePathSegment>> ()); + std::vector<std::unique_ptr<TypePathSegment> > ()); } std::string as_string () const override; void accept_vis (ASTVisitor &vis) override; + + // TODO: is this better? Or is a "vis_pattern" better? + QualifiedPathType &get_qualified_path_type () + { + rust_assert (!path_type.is_error ()); + return path_type; + } + + // TODO: this seems kinda dodgy + std::vector<std::unique_ptr<TypePathSegment> > &get_segments () + { + return segments; + } + const std::vector<std::unique_ptr<TypePathSegment> > &get_segments () const + { + return segments; + } + + Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } }; } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-pattern.h b/gcc/rust/ast/rust-pattern.h index 4e639a5..3a87a83 100644 --- a/gcc/rust/ast/rust-pattern.h +++ b/gcc/rust/ast/rust-pattern.h @@ -34,6 +34,7 @@ public: {} Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; @@ -49,7 +50,6 @@ protected: // Identifier pattern AST node (bind value matched to a variable) class IdentifierPattern : public Pattern { -public: Identifier variable_ident; bool is_ref; bool is_mut; @@ -59,6 +59,7 @@ public: Location locus; +public: std::string as_string () const; // Returns whether the IdentifierPattern has a pattern to bind. @@ -77,7 +78,7 @@ public: : variable_ident (other.variable_ident), is_ref (other.is_ref), is_mut (other.is_mut), locus (other.locus) { - // fix to get prevent null pointer dereference + // fix to prevent null pointer dereference if (other.to_bind != nullptr) to_bind = other.to_bind->clone_pattern (); } @@ -90,9 +91,11 @@ public: is_mut = other.is_mut; locus = other.locus; - // fix to get prevent null pointer dereference + // fix to prevent null pointer dereference if (other.to_bind != nullptr) to_bind = other.to_bind->clone_pattern (); + else + to_bind = nullptr; return *this; } @@ -102,9 +105,19 @@ public: IdentifierPattern &operator= (IdentifierPattern &&other) = default; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_pattern" better? + std::unique_ptr<Pattern> &get_pattern_to_bind () + { + rust_assert (has_pattern_to_bind ()); + return to_bind; + } + + Identifier get_ident () const { return variable_ident; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -125,6 +138,7 @@ public: WildcardPattern (Location locus) : locus (locus) {} Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; @@ -210,6 +224,10 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: this mutable getter seems kinda dodgy + PathInExpression &get_path () { return path; } + const PathInExpression &get_path () const { return path; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -238,6 +256,10 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: this mutable getter seems kinda dodgy + QualifiedPathInExpression &get_qualified_path () { return path; } + const QualifiedPathInExpression &get_qualified_path () const { return path; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -293,9 +315,23 @@ public: RangePattern &operator= (RangePattern &&other) = default; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? or is a "vis_bound" better? + std::unique_ptr<RangePatternBound> &get_lower_bound () + { + rust_assert (lower != nullptr); + return lower; + } + + std::unique_ptr<RangePatternBound> &get_upper_bound () + { + rust_assert (upper != nullptr); + return upper; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -343,8 +379,18 @@ public: ReferencePattern (ReferencePattern &&other) = default; ReferencePattern &operator= (ReferencePattern &&other) = default; + Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } + void accept_vis (ASTVisitor &vis) override; + // TODO: is this better? Or is a "vis_pattern" better? + std::unique_ptr<Pattern> &get_referenced_pattern () + { + rust_assert (pattern != nullptr); + return pattern; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -354,6 +400,7 @@ protected: } }; +#if 0 // aka StructPatternEtCetera; potential element in struct pattern struct StructPatternEtc { @@ -373,6 +420,7 @@ public: return StructPatternEtc (std::vector<Attribute> ()); } }; +#endif // Base class for a single field in a struct pattern - abstract class StructPatternField @@ -396,6 +444,13 @@ public: virtual void accept_vis (ASTVisitor &vis) = 0; + virtual void mark_for_strip () = 0; + virtual bool is_marked_for_strip () const = 0; + + // TODO: seems kinda dodgy. Think of better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + protected: StructPatternField (std::vector<Attribute> outer_attribs, Location locus) : outer_attrs (std::move (outer_attribs)), locus (locus) @@ -422,19 +477,27 @@ public: // Copy constructor requires clone StructPatternFieldTuplePat (StructPatternFieldTuplePat const &other) - : StructPatternField (other), index (other.index), - tuple_pattern (other.tuple_pattern->clone_pattern ()) - {} + : StructPatternField (other), index (other.index) + { + // guard to prevent null dereference (only required if error state) + if (other.tuple_pattern != nullptr) + tuple_pattern = other.tuple_pattern->clone_pattern (); + } // Overload assignment operator to perform clone StructPatternFieldTuplePat & operator= (StructPatternFieldTuplePat const &other) { StructPatternField::operator= (other); - tuple_pattern = other.tuple_pattern->clone_pattern (); index = other.index; // outer_attrs = other.outer_attrs; + // guard to prevent null dereference (only required if error state) + if (other.tuple_pattern != nullptr) + tuple_pattern = other.tuple_pattern->clone_pattern (); + else + tuple_pattern = nullptr; + return *this; } @@ -447,6 +510,20 @@ public: void accept_vis (ASTVisitor &vis) override; + // based on idea of tuple pattern no longer existing + void mark_for_strip () override { tuple_pattern = nullptr; } + bool is_marked_for_strip () const override + { + return tuple_pattern == nullptr; + } + + // TODO: is this better? Or is a "vis_pattern" better? + std::unique_ptr<Pattern> &get_index_pattern () + { + rust_assert (tuple_pattern != nullptr); + return tuple_pattern; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -473,9 +550,12 @@ public: // Copy constructor requires clone StructPatternFieldIdentPat (StructPatternFieldIdentPat const &other) - : StructPatternField (other), ident (other.ident), - ident_pattern (other.ident_pattern->clone_pattern ()) - {} + : StructPatternField (other), ident (other.ident) + { + // guard to prevent null dereference (only required if error state) + if (other.ident_pattern != nullptr) + ident_pattern = other.ident_pattern->clone_pattern (); + } // Overload assignment operator to clone StructPatternFieldIdentPat & @@ -483,9 +563,14 @@ public: { StructPatternField::operator= (other); ident = other.ident; - ident_pattern = other.ident_pattern->clone_pattern (); // outer_attrs = other.outer_attrs; + // guard to prevent null dereference (only required if error state) + if (other.ident_pattern != nullptr) + ident_pattern = other.ident_pattern->clone_pattern (); + else + ident_pattern = nullptr; + return *this; } @@ -498,6 +583,20 @@ public: void accept_vis (ASTVisitor &vis) override; + // based on idea of identifier pattern no longer existing + void mark_for_strip () override { ident_pattern = nullptr; } + bool is_marked_for_strip () const override + { + return ident_pattern == nullptr; + } + + // TODO: is this better? Or is a "vis_pattern" better? + std::unique_ptr<Pattern> &get_ident_pattern () + { + rust_assert (ident_pattern != nullptr); + return ident_pattern; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -525,6 +624,10 @@ public: void accept_vis (ASTVisitor &vis) override; + // based on idea of identifier no longer existing + void mark_for_strip () override { ident = {}; } + bool is_marked_for_strip () const override { return ident.empty (); } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -539,10 +642,11 @@ struct StructPatternElements { private: // bool has_struct_pattern_fields; - std::vector<std::unique_ptr<StructPatternField>> fields; + std::vector<std::unique_ptr<StructPatternField> > fields; bool has_struct_pattern_etc; - StructPatternEtc etc; + std::vector<Attribute> struct_pattern_etc_attrs; + // StructPatternEtc etc; // must have at least one of the two and maybe both @@ -559,24 +663,27 @@ public: return !has_struct_pattern_fields () && !has_struct_pattern_etc; } + bool has_etc () const { return has_struct_pattern_etc; } + // Constructor for StructPatternElements with both (potentially) StructPatternElements ( - std::vector<std::unique_ptr<StructPatternField>> fields, - StructPatternEtc etc) + std::vector<std::unique_ptr<StructPatternField> > fields, + std::vector<Attribute> etc_attrs) : fields (std::move (fields)), has_struct_pattern_etc (true), - etc (std::move (etc)) + struct_pattern_etc_attrs (std::move (etc_attrs)) {} // Constructor for StructPatternElements with no StructPatternEtc StructPatternElements ( - std::vector<std::unique_ptr<StructPatternField>> fields) + std::vector<std::unique_ptr<StructPatternField> > fields) : fields (std::move (fields)), has_struct_pattern_etc (false), - etc (StructPatternEtc::create_empty ()) + struct_pattern_etc_attrs () {} // Copy constructor with vector clone StructPatternElements (StructPatternElements const &other) - : has_struct_pattern_etc (other.has_struct_pattern_etc), etc (other.etc) + : has_struct_pattern_etc (other.has_struct_pattern_etc), + struct_pattern_etc_attrs (other.struct_pattern_etc_attrs) { fields.reserve (other.fields.size ()); for (const auto &e : other.fields) @@ -586,7 +693,7 @@ public: // Overloaded assignment operator with vector clone StructPatternElements &operator= (StructPatternElements const &other) { - etc = other.etc; + struct_pattern_etc_attrs = other.struct_pattern_etc_attrs; has_struct_pattern_etc = other.has_struct_pattern_etc; fields.reserve (other.fields.size ()); @@ -604,10 +711,38 @@ public: static StructPatternElements create_empty () { return StructPatternElements ( - std::vector<std::unique_ptr<StructPatternField>> ()); + std::vector<std::unique_ptr<StructPatternField> > ()); } std::string as_string () const; + + // TODO: seems kinda dodgy. Think of better way. + std::vector<std::unique_ptr<StructPatternField> > & + get_struct_pattern_fields () + { + return fields; + } + const std::vector<std::unique_ptr<StructPatternField> > & + get_struct_pattern_fields () const + { + return fields; + } + + std::vector<Attribute> &get_etc_outer_attrs () + { + return struct_pattern_etc_attrs; + } + const std::vector<Attribute> &get_etc_outer_attrs () const + { + return struct_pattern_etc_attrs; + } + + void strip_etc () + { + has_struct_pattern_etc = false; + struct_pattern_etc_attrs.clear (); + struct_pattern_etc_attrs.shrink_to_fit (); + } }; // Struct pattern AST node representation @@ -638,9 +773,20 @@ public: bool has_struct_pattern_elems () const { return !elems.is_empty (); } Location get_locus () const { return path.get_locus (); } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; + // TODO: seems kinda dodgy. Think of better way. + StructPatternElements &get_struct_pattern_elems () { return elems; } + const StructPatternElements &get_struct_pattern_elems () const + { + return elems; + } + + PathInExpression &get_path () { return path; } + const PathInExpression &get_path () const { return path; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -676,10 +822,10 @@ protected: // Class for non-ranged tuple struct pattern patterns class TupleStructItemsNoRange : public TupleStructItems { - std::vector<std::unique_ptr<Pattern>> patterns; + std::vector<std::unique_ptr<Pattern> > patterns; public: - TupleStructItemsNoRange (std::vector<std::unique_ptr<Pattern>> patterns) + TupleStructItemsNoRange (std::vector<std::unique_ptr<Pattern> > patterns) : patterns (std::move (patterns)) {} @@ -710,6 +856,13 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: seems kinda dodgy. Think of better way. + std::vector<std::unique_ptr<Pattern> > &get_patterns () { return patterns; } + const std::vector<std::unique_ptr<Pattern> > &get_patterns () const + { + return patterns; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -722,12 +875,12 @@ protected: // Class for ranged tuple struct pattern patterns class TupleStructItemsRange : public TupleStructItems { - std::vector<std::unique_ptr<Pattern>> lower_patterns; - std::vector<std::unique_ptr<Pattern>> upper_patterns; + std::vector<std::unique_ptr<Pattern> > lower_patterns; + std::vector<std::unique_ptr<Pattern> > upper_patterns; public: - TupleStructItemsRange (std::vector<std::unique_ptr<Pattern>> lower_patterns, - std::vector<std::unique_ptr<Pattern>> upper_patterns) + TupleStructItemsRange (std::vector<std::unique_ptr<Pattern> > lower_patterns, + std::vector<std::unique_ptr<Pattern> > upper_patterns) : lower_patterns (std::move (lower_patterns)), upper_patterns (std::move (upper_patterns)) {} @@ -766,6 +919,26 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: seems kinda dodgy. Think of better way. + std::vector<std::unique_ptr<Pattern> > &get_lower_patterns () + { + return lower_patterns; + } + const std::vector<std::unique_ptr<Pattern> > &get_lower_patterns () const + { + return lower_patterns; + } + + // TODO: seems kinda dodgy. Think of better way. + std::vector<std::unique_ptr<Pattern> > &get_upper_patterns () + { + return upper_patterns; + } + const std::vector<std::unique_ptr<Pattern> > &get_upper_patterns () const + { + return upper_patterns; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -787,21 +960,32 @@ class TupleStructPattern : public Pattern public: std::string as_string () const override; + // Returns whether the pattern has tuple struct items. + bool has_items () const { return items != nullptr; } + TupleStructPattern (PathInExpression tuple_struct_path, std::unique_ptr<TupleStructItems> items) : path (std::move (tuple_struct_path)), items (std::move (items)) {} // Copy constructor required to clone - TupleStructPattern (TupleStructPattern const &other) - : path (other.path), items (other.items->clone_tuple_struct_items ()) - {} + TupleStructPattern (TupleStructPattern const &other) : path (other.path) + { + // guard to protect from null dereference + if (other.items != nullptr) + items = other.items->clone_tuple_struct_items (); + } // Operator overload assignment operator to clone TupleStructPattern &operator= (TupleStructPattern const &other) { path = other.path; - items = other.items->clone_tuple_struct_items (); + + // guard to protect from null dereference + if (other.items != nullptr) + items = other.items->clone_tuple_struct_items (); + else + items = nullptr; return *this; } @@ -811,9 +995,20 @@ public: TupleStructPattern &operator= (TupleStructPattern &&other) = default; Location get_locus () const { return path.get_locus (); } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; + // TODO: seems kinda dodgy. Think of better way. + std::unique_ptr<TupleStructItems> &get_items () + { + rust_assert (has_items ()); + return items; + } + + PathInExpression &get_path () { return path; } + const PathInExpression &get_path () const { return path; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -885,10 +1080,10 @@ TuplePatternItemsSingle(*this); // Class representing TuplePattern patterns where there are multiple patterns class TuplePatternItemsMultiple : public TuplePatternItems { - std::vector<std::unique_ptr<Pattern>> patterns; + std::vector<std::unique_ptr<Pattern> > patterns; public: - TuplePatternItemsMultiple (std::vector<std::unique_ptr<Pattern>> patterns) + TuplePatternItemsMultiple (std::vector<std::unique_ptr<Pattern> > patterns) : patterns (std::move (patterns)) {} @@ -919,6 +1114,13 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: seems kinda dodgy. Think of better way. + std::vector<std::unique_ptr<Pattern> > &get_patterns () { return patterns; } + const std::vector<std::unique_ptr<Pattern> > &get_patterns () const + { + return patterns; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -931,13 +1133,13 @@ protected: // Class representing TuplePattern patterns where there are a range of patterns class TuplePatternItemsRanged : public TuplePatternItems { - std::vector<std::unique_ptr<Pattern>> lower_patterns; - std::vector<std::unique_ptr<Pattern>> upper_patterns; + std::vector<std::unique_ptr<Pattern> > lower_patterns; + std::vector<std::unique_ptr<Pattern> > upper_patterns; public: TuplePatternItemsRanged ( - std::vector<std::unique_ptr<Pattern>> lower_patterns, - std::vector<std::unique_ptr<Pattern>> upper_patterns) + std::vector<std::unique_ptr<Pattern> > lower_patterns, + std::vector<std::unique_ptr<Pattern> > upper_patterns) : lower_patterns (std::move (lower_patterns)), upper_patterns (std::move (upper_patterns)) {} @@ -977,6 +1179,26 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: seems kinda dodgy. Think of better way. + std::vector<std::unique_ptr<Pattern> > &get_lower_patterns () + { + return lower_patterns; + } + const std::vector<std::unique_ptr<Pattern> > &get_lower_patterns () const + { + return lower_patterns; + } + + // TODO: seems kinda dodgy. Think of better way. + std::vector<std::unique_ptr<Pattern> > &get_upper_patterns () + { + return upper_patterns; + } + const std::vector<std::unique_ptr<Pattern> > &get_upper_patterns () const + { + return upper_patterns; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -991,7 +1213,6 @@ class TuplePattern : public Pattern { // bool has_tuple_pattern_items; std::unique_ptr<TuplePatternItems> items; - Location locus; public: @@ -1005,23 +1226,39 @@ public: {} // Copy constructor requires clone - TuplePattern (TuplePattern const &other) - : items (other.items->clone_tuple_pattern_items ()), locus (other.locus) - {} + TuplePattern (TuplePattern const &other) : locus (other.locus) + { + // guard to prevent null dereference + if (other.items != nullptr) + items = other.items->clone_tuple_pattern_items (); + } // Overload assignment operator to clone TuplePattern &operator= (TuplePattern const &other) { - items = other.items->clone_tuple_pattern_items (); locus = other.locus; + // guard to prevent null dereference + if (other.items != nullptr) + items = other.items->clone_tuple_pattern_items (); + else + items = nullptr; + return *this; } Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; + // TODO: seems kinda dodgy. Think of better way. + std::unique_ptr<TuplePatternItems> &get_items () + { + rust_assert (has_tuple_pattern_items ()); + return items; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1067,9 +1304,17 @@ public: GroupedPattern &operator= (GroupedPattern &&other) = default; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; + // TODO: seems kinda dodgy. Think of better way. + std::unique_ptr<Pattern> &get_pattern_in_parens () + { + rust_assert (pattern_in_parens != nullptr); + return pattern_in_parens; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1082,13 +1327,13 @@ protected: // AST node representing patterns that can match slices and arrays class SlicePattern : public Pattern { - std::vector<std::unique_ptr<Pattern>> items; + std::vector<std::unique_ptr<Pattern> > items; Location locus; public: std::string as_string () const override; - SlicePattern (std::vector<std::unique_ptr<Pattern>> items, Location locus) + SlicePattern (std::vector<std::unique_ptr<Pattern> > items, Location locus) : items (std::move (items)), locus (locus) {} @@ -1117,9 +1362,17 @@ public: SlicePattern &operator= (SlicePattern &&other) = default; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; + // TODO: seems kinda dodgy. Think of better way. + std::vector<std::unique_ptr<Pattern> > &get_items () { return items; } + const std::vector<std::unique_ptr<Pattern> > &get_items () const + { + return items; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/ast/rust-stmt.h b/gcc/rust/ast/rust-stmt.h index ce7a37a..faea905 100644 --- a/gcc/rust/ast/rust-stmt.h +++ b/gcc/rust/ast/rust-stmt.h @@ -12,6 +12,9 @@ class EmptyStmt : public Stmt { Location locus; + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + public: std::string as_string () const override { return std::string (1, ';'); } @@ -21,6 +24,10 @@ public: void accept_vis (ASTVisitor &vis) override; + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -31,7 +38,6 @@ protected: * introduces new name into scope */ class LetStmt : public Stmt { -public: // bool has_outer_attrs; std::vector<Attribute> outer_attrs; @@ -45,6 +51,7 @@ public: Location locus; +public: Type *inferedType; // Returns whether let statement has outer attributes. @@ -68,21 +75,41 @@ public: // Copy constructor with clone LetStmt (LetStmt const &other) - : outer_attrs (other.outer_attrs), - variables_pattern (other.variables_pattern->clone_pattern ()), - type (other.type->clone_type ()), - init_expr (other.init_expr->clone_expr ()), locus (other.locus) - {} + : outer_attrs (other.outer_attrs), locus (other.locus) + { + // guard to prevent null dereference (only required if error state) + if (other.variables_pattern != nullptr) + variables_pattern = other.variables_pattern->clone_pattern (); + + // guard to prevent null dereference (always required) + if (other.init_expr != nullptr) + init_expr = other.init_expr->clone_expr (); + if (other.type != nullptr) + type = other.type->clone_type (); + } // Overloaded assignment operator to clone LetStmt &operator= (LetStmt const &other) { - variables_pattern = other.variables_pattern->clone_pattern (); - init_expr = other.init_expr->clone_expr (); - type = other.type->clone_type (); outer_attrs = other.outer_attrs; locus = other.locus; + // guard to prevent null dereference (only required if error state) + if (other.variables_pattern != nullptr) + variables_pattern = other.variables_pattern->clone_pattern (); + else + variables_pattern = nullptr; + + // guard to prevent null dereference (always required) + if (other.init_expr != nullptr) + init_expr = other.init_expr->clone_expr (); + else + init_expr = nullptr; + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + return *this; } @@ -94,6 +121,36 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if pattern is null, so base stripping on that. + void mark_for_strip () override { variables_pattern = nullptr; } + bool is_marked_for_strip () const override + { + return variables_pattern == nullptr; + } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<Expr> &get_init_expr () + { + rust_assert (has_init_expr ()); + return init_expr; + } + + std::unique_ptr<Pattern> &get_pattern () + { + rust_assert (variables_pattern != nullptr); + return variables_pattern; + } + + std::unique_ptr<Type> &get_type () + { + rust_assert (has_type ()); + return type; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -119,7 +176,6 @@ protected: * difficulties, can only be guaranteed to hold an expression). */ class ExprStmtWithoutBlock : public ExprStmt { -public: // TODO: ensure that this works std::unique_ptr<ExprWithoutBlock> expr; /* HACK: cannot ensure type safety of ExprWithoutBlock due to Pratt parsing, @@ -127,6 +183,7 @@ public: * or redesign AST. */ // std::unique_ptr<Expr> expr; +public: std::string as_string () const override; ExprStmtWithoutBlock (std::unique_ptr<ExprWithoutBlock> expr, Location locus) @@ -137,9 +194,12 @@ public: {}*/ // Copy constructor with clone - ExprStmtWithoutBlock (ExprStmtWithoutBlock const &other) - : ExprStmt (other), expr (other.expr->clone_expr_without_block ()) - {} + ExprStmtWithoutBlock (ExprStmtWithoutBlock const &other) : ExprStmt (other) + { + // guard to prevent null dereference (only required if error state) + if (other.expr != nullptr) + expr = other.expr->clone_expr_without_block (); + } /*ExprStmtWithoutBlock (ExprStmtWithoutBlock const &other) : ExprStmt (other), expr (other.expr->clone_expr ()) {}*/ @@ -148,8 +208,13 @@ public: ExprStmtWithoutBlock &operator= (ExprStmtWithoutBlock const &other) { ExprStmt::operator= (other); - expr = other.expr->clone_expr_without_block (); - //expr = other.expr->clone_expr (); + // expr = other.expr->clone_expr (); + + // guard to prevent null dereference (only required if error state) + if (other.expr != nullptr) + expr = other.expr->clone_expr_without_block (); + else + expr = nullptr; return *this; } @@ -160,6 +225,17 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if expr is null, so base stripping on that. + void mark_for_strip () override { expr = nullptr; } + bool is_marked_for_strip () const override { return expr == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<ExprWithoutBlock> &get_expr () + { + rust_assert (expr != nullptr); + return expr; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -172,9 +248,9 @@ protected: // Statement containing an expression with a block class ExprStmtWithBlock : public ExprStmt { -public: std::unique_ptr<ExprWithBlock> expr; +public: std::string as_string () const override; std::vector<LetStmt *> locals; @@ -184,15 +260,23 @@ public: {} // Copy constructor with clone - ExprStmtWithBlock (ExprStmtWithBlock const &other) - : ExprStmt (other), expr (other.expr->clone_expr_with_block ()) - {} + ExprStmtWithBlock (ExprStmtWithBlock const &other) : ExprStmt (other) + { + // guard to prevent null dereference (only required if error state) + if (other.expr != nullptr) + expr = other.expr->clone_expr_with_block (); + } // Overloaded assignment operator to clone ExprStmtWithBlock &operator= (ExprStmtWithBlock const &other) { ExprStmt::operator= (other); - expr = other.expr->clone_expr_with_block (); + + // guard to prevent null dereference (only required if error state) + if (other.expr != nullptr) + expr = other.expr->clone_expr_with_block (); + else + expr = nullptr; return *this; } @@ -203,6 +287,17 @@ public: void accept_vis (ASTVisitor &vis) override; + // Invalid if expr is null, so base stripping on that. + void mark_for_strip () override { expr = nullptr; } + bool is_marked_for_strip () const override { return expr == nullptr; } + + // TODO: is this better? Or is a "vis_block" better? + std::unique_ptr<ExprWithBlock> &get_expr () + { + rust_assert (expr != nullptr); + return expr; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/ast/rust-type.h b/gcc/rust/ast/rust-type.h index 089aaeb..8c175d3 100644 --- a/gcc/rust/ast/rust-type.h +++ b/gcc/rust/ast/rust-type.h @@ -43,6 +43,10 @@ public: void accept_vis (ASTVisitor &vis) override; + // TODO: this mutable getter seems kinda dodgy + TypePath &get_type_path () { return type_path; } + const TypePath &get_type_path () const { return type_path; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -106,8 +110,20 @@ public: std::string as_string () const override; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; + + // TODO: mutable getter seems kinda dodgy + std::vector<std::unique_ptr<TypeParamBound> > &get_type_param_bounds () + { + return type_param_bounds; + } + const std::vector<std::unique_ptr<TypeParamBound> > & + get_type_param_bounds () const + { + return type_param_bounds; + } }; // An opaque value of another type that implements a set of traits @@ -164,8 +180,20 @@ public: std::string as_string () const override; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; + + // TODO: mutable getter seems kinda dodgy + std::vector<std::unique_ptr<TypeParamBound> > &get_type_param_bounds () + { + return type_param_bounds; + } + const std::vector<std::unique_ptr<TypeParamBound> > & + get_type_param_bounds () const + { + return type_param_bounds; + } }; // A type with parentheses around it, used to avoid ambiguity. @@ -177,13 +205,6 @@ class ParenthesisedType : public TypeNoBounds protected: /* Use covariance to implement clone function as returning this object rather * than base */ - ParenthesisedType *clone_type_impl () const override - { - return new ParenthesisedType (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ ParenthesisedType *clone_type_no_bounds_impl () const override { return new ParenthesisedType (*this); @@ -219,7 +240,7 @@ public: } // Creates a trait bound (clone of this one's trait bound) - HACK - TraitBound *to_trait_bound (bool in_parens ATTRIBUTE_UNUSED) const override + TraitBound *to_trait_bound (bool) const override { /* NOTE: obviously it is unknown whether the internal type is a trait bound * due to polymorphism, so just let the internal type handle it. As @@ -228,27 +249,27 @@ public: } Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; + + // TODO: would a "vis_type" be better? + std::unique_ptr<Type> &get_type_in_parens () + { + rust_assert (type_in_parens != nullptr); + return type_in_parens; + } }; // Impl trait with a single bound? Poor reference material here. class ImplTraitTypeOneBound : public TypeNoBounds { TraitBound trait_bound; - Location locus; protected: /* Use covariance to implement clone function as returning this object rather * than base */ - ImplTraitTypeOneBound *clone_type_impl () const override - { - return new ImplTraitTypeOneBound (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ ImplTraitTypeOneBound *clone_type_no_bounds_impl () const override { return new ImplTraitTypeOneBound (*this); @@ -262,8 +283,16 @@ public: std::string as_string () const override; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; + + // TODO: would a "vis_type" be better? + TraitBound &get_trait_bound () + { + // TODO: check to ensure invariants are met? + return trait_bound; + } }; /* A trait object with a single trait bound. The "trait bound" is really just @@ -272,19 +301,11 @@ class TraitObjectTypeOneBound : public TypeNoBounds { bool has_dyn; TraitBound trait_bound; - Location locus; protected: /* Use covariance to implement clone function as returning this object rather * than base */ - TraitObjectTypeOneBound *clone_type_impl () const override - { - return new TraitObjectTypeOneBound (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ TraitObjectTypeOneBound *clone_type_no_bounds_impl () const override { return new TraitObjectTypeOneBound (*this); @@ -300,16 +321,24 @@ public: std::string as_string () const override; // Creates a trait bound (clone of this one's trait bound) - HACK - TraitBound *to_trait_bound (bool in_parens ATTRIBUTE_UNUSED) const override + TraitBound *to_trait_bound (bool) const override { /* NOTE: this assumes there is no dynamic dispatch specified- if there was, * this cloning would not be required as parsing is unambiguous. */ - return new AST::TraitBound (trait_bound); + return new TraitBound (trait_bound); } Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; + + // TODO: would a "vis_type" be better? + TraitBound &get_trait_bound () + { + // TODO: check to ensure invariants are met? + return trait_bound; + } }; class TypePath; // definition moved to "rust-path.h" @@ -356,14 +385,18 @@ public: std::string as_string () const override; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - TupleType *clone_type_impl () const override { return new TupleType (*this); } + // TODO: mutable getter seems kinda dodgy + std::vector<std::unique_ptr<Type> > &get_elems () { return elems; } + const std::vector<std::unique_ptr<Type> > &get_elems () const + { + return elems; + } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ TupleType *clone_type_no_bounds_impl () const override @@ -382,10 +415,6 @@ class NeverType : public TypeNoBounds protected: /* Use covariance to implement clone function as returning this object rather * than base */ - NeverType *clone_type_impl () const override { return new NeverType (*this); } - - /* Use covariance to implement clone function as returning this object rather - * than base */ NeverType *clone_type_no_bounds_impl () const override { return new NeverType (*this); @@ -397,6 +426,7 @@ public: std::string as_string () const override { return "! (never type)"; } Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; }; @@ -449,17 +479,18 @@ public: std::string as_string () const override; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - RawPointerType *clone_type_impl () const override + // TODO: would a "vis_type" be better? + std::unique_ptr<TypeNoBounds> &get_type_pointed_to () { - return new RawPointerType (*this); + rust_assert (type != nullptr); + return type; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ RawPointerType *clone_type_no_bounds_impl () const override @@ -516,17 +547,18 @@ public: std::string as_string () const override; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - ReferenceType *clone_type_impl () const override + // TODO: would a "vis_type" be better? + std::unique_ptr<TypeNoBounds> &get_type_referenced () { - return new ReferenceType (*this); + rust_assert (type != nullptr); + return type; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ ReferenceType *clone_type_no_bounds_impl () const override @@ -571,22 +603,27 @@ public: std::string as_string () const override; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; - Type *get_element_type () { return elem_type.get (); } - - Expr *get_size_expr () { return size.get (); } + // TODO: would a "vis_type" be better? + std::unique_ptr<Type> &get_elem_type () + { + rust_assert (elem_type != nullptr); + return elem_type; + } - Location &get_locus () { return locus; } + // TODO: would a "vis_expr" be better? + std::unique_ptr<Expr> &get_size_expr () + { + rust_assert (size != nullptr); + return size; + } protected: /* Use covariance to implement clone function as returning this object rather * than base */ - ArrayType *clone_type_impl () const override { return new ArrayType (*this); } - - /* Use covariance to implement clone function as returning this object rather - * than base */ ArrayType *clone_type_no_bounds_impl () const override { return new ArrayType (*this); @@ -627,14 +664,18 @@ public: std::string as_string () const override; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - SliceType *clone_type_impl () const override { return new SliceType (*this); } + // TODO: would a "vis_type" be better? + std::unique_ptr<Type> &get_elem_type () + { + rust_assert (elem_type != nullptr); + return elem_type; + } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ SliceType *clone_type_no_bounds_impl () const override @@ -653,13 +694,6 @@ class InferredType : public TypeNoBounds protected: /* Use covariance to implement clone function as returning this object rather * than base */ - InferredType *clone_type_impl () const override - { - return new InferredType (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ InferredType *clone_type_no_bounds_impl () const override { return new InferredType (*this); @@ -671,6 +705,7 @@ public: std::string as_string () const override; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; }; @@ -689,6 +724,8 @@ public: }; private: + std::vector<Attribute> outer_attrs; + std::unique_ptr<Type> param_type; ParamKind param_kind; @@ -698,27 +735,39 @@ private: public: MaybeNamedParam (Identifier name, ParamKind param_kind, - std::unique_ptr<Type> param_type, Location locus) - : param_type (std::move (param_type)), param_kind (param_kind), + std::unique_ptr<Type> param_type, + std::vector<Attribute> outer_attrs, Location locus) + : outer_attrs (std::move (outer_attrs)), + param_type (std::move (param_type)), param_kind (param_kind), name (std::move (name)), locus (locus) {} // Copy constructor with clone MaybeNamedParam (MaybeNamedParam const &other) - : param_type (other.param_type->clone_type ()), - param_kind (other.param_kind), name (other.name), locus (other.locus) - {} + : outer_attrs (other.outer_attrs), param_kind (other.param_kind), + name (other.name), locus (other.locus) + { + // guard to prevent null dereference + if (other.param_type != nullptr) + param_type = other.param_type->clone_type (); + } ~MaybeNamedParam () = default; // Overloaded assignment operator with clone MaybeNamedParam &operator= (MaybeNamedParam const &other) { + outer_attrs = other.outer_attrs; name = other.name; param_kind = other.param_kind; - param_type = other.param_type->clone_type (); locus = other.locus; + // guard to prevent null dereference + if (other.param_type != nullptr) + param_type = other.param_type->clone_type (); + else + param_type = nullptr; + return *this; } @@ -734,10 +783,21 @@ public: // Creates an error state param. static MaybeNamedParam create_error () { - return MaybeNamedParam ("", UNNAMED, nullptr, Location ()); + return MaybeNamedParam ("", UNNAMED, nullptr, {}, Location ()); } Location get_locus () const { return locus; } + + // TODO: this mutable getter seems really dodgy. Think up better way. + std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + + // TODO: would a "vis_type" be better? + std::unique_ptr<Type> &get_type () + { + rust_assert (param_type != nullptr); + return param_type; + } }; /* A function pointer type - can be created via coercion from function items and @@ -751,6 +811,7 @@ class BareFunctionType : public TypeNoBounds FunctionQualifiers function_qualifiers; std::vector<MaybeNamedParam> params; bool is_variadic; + std::vector<Attribute> variadic_attrs; // bool has_return_type; // BareFunctionReturnType return_type; @@ -768,21 +829,29 @@ public: BareFunctionType (std::vector<LifetimeParam> lifetime_params, FunctionQualifiers qualifiers, std::vector<MaybeNamedParam> named_params, bool is_variadic, + std::vector<Attribute> variadic_attrs, std::unique_ptr<TypeNoBounds> type, Location locus) : for_lifetimes (std::move (lifetime_params)), function_qualifiers (std::move (qualifiers)), params (std::move (named_params)), is_variadic (is_variadic), + variadic_attrs (std::move (variadic_attrs)), return_type (std::move (type)), locus (locus) - {} + { + if (!variadic_attrs.empty ()) + is_variadic = true; + } // Copy constructor with clone BareFunctionType (BareFunctionType const &other) : for_lifetimes (other.for_lifetimes), function_qualifiers (other.function_qualifiers), params (other.params), - is_variadic (other.is_variadic), - return_type (other.return_type->clone_type_no_bounds ()), + is_variadic (other.is_variadic), variadic_attrs (other.variadic_attrs), locus (other.locus) - {} + { + // guard to prevent null dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type_no_bounds (); + } // Overload assignment operator to deep copy BareFunctionType &operator= (BareFunctionType const &other) @@ -791,9 +860,15 @@ public: function_qualifiers = other.function_qualifiers; params = other.params; is_variadic = other.is_variadic; - return_type = other.return_type->clone_type_no_bounds (); + variadic_attrs = other.variadic_attrs; locus = other.locus; + // guard to prevent null dereference + if (other.return_type != nullptr) + return_type = other.return_type->clone_type_no_bounds (); + else + return_type = nullptr; + return *this; } @@ -804,17 +879,25 @@ public: std::string as_string () const override; Location get_locus () const { return locus; } + Location get_locus_slow () const final override { return get_locus (); } void accept_vis (ASTVisitor &vis) override; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - BareFunctionType *clone_type_impl () const override + // TODO: this mutable getter seems kinda dodgy + std::vector<MaybeNamedParam> &get_function_params () { return params; } + const std::vector<MaybeNamedParam> &get_function_params () const { - return new BareFunctionType (*this); + return params; + } + + // TODO: would a "vis_type" be better? + std::unique_ptr<TypeNoBounds> &get_return_type () + { + rust_assert (has_return_type ()); + return return_type; } +protected: /* Use covariance to implement clone function as returning this object rather * than base */ BareFunctionType *clone_type_no_bounds_impl () const override |