diff options
Diffstat (limited to 'gcc/rust/ast/rust-item.h')
-rw-r--r-- | gcc/rust/ast/rust-item.h | 1532 |
1 files changed, 1244 insertions, 288 deletions
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" |