aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/ast/rust-path.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/ast/rust-path.h')
-rw-r--r--gcc/rust/ast/rust-path.h219
1 files changed, 173 insertions, 46 deletions
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