aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/expand
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/expand')
-rw-r--r--gcc/rust/expand/rust-cfg-strip.cc67
-rw-r--r--gcc/rust/expand/rust-cfg-strip.h2
-rw-r--r--gcc/rust/expand/rust-derive-clone.h10
-rw-r--r--gcc/rust/expand/rust-derive-cmp-common.cc191
-rw-r--r--gcc/rust/expand/rust-derive-cmp-common.h99
-rw-r--r--gcc/rust/expand/rust-derive-copy.h8
-rw-r--r--gcc/rust/expand/rust-derive-default.cc5
-rw-r--r--gcc/rust/expand/rust-derive-eq.cc17
-rw-r--r--gcc/rust/expand/rust-derive-eq.h10
-rw-r--r--gcc/rust/expand/rust-derive-hash.cc9
-rw-r--r--gcc/rust/expand/rust-derive-hash.h10
-rw-r--r--gcc/rust/expand/rust-derive-ord.cc323
-rw-r--r--gcc/rust/expand/rust-derive-ord.h122
-rw-r--r--gcc/rust/expand/rust-derive-partial-eq.cc147
-rw-r--r--gcc/rust/expand/rust-derive-partial-eq.h29
-rw-r--r--gcc/rust/expand/rust-derive.cc36
-rw-r--r--gcc/rust/expand/rust-derive.h8
-rw-r--r--gcc/rust/expand/rust-expand-format-args.cc6
-rw-r--r--gcc/rust/expand/rust-expand-visitor.cc41
-rw-r--r--gcc/rust/expand/rust-expand-visitor.h14
-rw-r--r--gcc/rust/expand/rust-macro-builtins-asm.cc70
-rw-r--r--gcc/rust/expand/rust-macro-builtins-asm.h32
-rw-r--r--gcc/rust/expand/rust-macro-builtins-format-args.cc11
-rw-r--r--gcc/rust/expand/rust-macro-builtins-helpers.cc7
-rw-r--r--gcc/rust/expand/rust-macro-builtins-helpers.h35
-rw-r--r--gcc/rust/expand/rust-macro-builtins-offset-of.cc78
-rw-r--r--gcc/rust/expand/rust-macro-builtins.cc3
-rw-r--r--gcc/rust/expand/rust-macro-builtins.h4
-rw-r--r--gcc/rust/expand/rust-macro-expand.cc66
-rw-r--r--gcc/rust/expand/rust-macro-substitute-ctx.cc3
-rw-r--r--gcc/rust/expand/rust-proc-macro.h6
-rw-r--r--gcc/rust/expand/rust-token-tree-desugar.cc4
-rw-r--r--gcc/rust/expand/rust-token-tree-desugar.h4
33 files changed, 1184 insertions, 293 deletions
diff --git a/gcc/rust/expand/rust-cfg-strip.cc b/gcc/rust/expand/rust-cfg-strip.cc
index a8c3ca5..58d8071 100644
--- a/gcc/rust/expand/rust-cfg-strip.cc
+++ b/gcc/rust/expand/rust-cfg-strip.cc
@@ -289,7 +289,8 @@ CfgStrip::maybe_strip_generic_args (AST::GenericArgs &args)
{
switch (arg.get_kind ())
{
- case AST::GenericArg::Kind::Type: {
+ case AST::GenericArg::Kind::Type:
+ {
auto &type = arg.get_type ();
type.accept_vis (*this);
@@ -298,7 +299,8 @@ CfgStrip::maybe_strip_generic_args (AST::GenericArgs &args)
"cannot strip type in this position");
break;
}
- case AST::GenericArg::Kind::Const: {
+ case AST::GenericArg::Kind::Const:
+ {
auto &expr = arg.get_expression ();
expr.accept_vis (*this);
@@ -1190,7 +1192,7 @@ CfgStrip::visit (AST::ClosureExprInnerTyped &expr)
rust_error_at (type.get_locus (), "cannot strip type in this position");
// can't strip expression itself, but can strip sub-expressions
- auto &definition_block = expr.get_definition_block ();
+ auto &definition_block = expr.get_definition_expr ();
definition_block.accept_vis (*this);
if (definition_block.is_marked_for_strip ())
rust_error_at (definition_block.get_locus (),
@@ -1763,16 +1765,17 @@ CfgStrip::visit (AST::Module &module)
return;
}
- // A loaded module might have inner attributes
- if (module.get_kind () == AST::Module::ModuleKind::LOADED)
+ if (module.get_kind () == AST::Module::UNLOADED)
{
- // strip test based on inner attrs
- expand_cfg_attrs (module.get_inner_attrs ());
- if (fails_cfg_with_expand (module.get_inner_attrs ()))
- {
- module.mark_for_strip ();
- return;
- }
+ module.load_items ();
+ }
+
+ // strip test based on inner attrs
+ expand_cfg_attrs (module.get_inner_attrs ());
+ if (fails_cfg_with_expand (module.get_inner_attrs ()))
+ {
+ module.mark_for_strip ();
+ return;
}
// strip items if required
@@ -2260,12 +2263,12 @@ void
CfgStrip::visit (AST::IdentifierPattern &pattern)
{
// can only strip sub-patterns of the inner pattern to bind
- if (!pattern.has_pattern_to_bind ())
+ if (!pattern.has_subpattern ())
return;
AST::DefaultASTVisitor::visit (pattern);
- auto &sub_pattern = pattern.get_pattern_to_bind ();
+ auto &sub_pattern = pattern.get_subpattern ();
if (sub_pattern.is_marked_for_strip ())
rust_error_at (sub_pattern.get_locus (),
"cannot strip pattern in this position");
@@ -2475,20 +2478,44 @@ CfgStrip::visit (AST::GroupedPattern &pattern)
}
void
-CfgStrip::visit (AST::SlicePattern &pattern)
+CfgStrip::visit (AST::SlicePatternItemsNoRest &items)
{
- AST::DefaultASTVisitor::visit (pattern);
+ AST::DefaultASTVisitor::visit (items);
// can't strip individual patterns, only sub-patterns
- for (auto &item : pattern.get_items ())
+ for (auto &pattern : items.get_patterns ())
{
- if (item->is_marked_for_strip ())
- rust_error_at (item->get_locus (),
+ if (pattern->is_marked_for_strip ())
+ rust_error_at (pattern->get_locus (),
"cannot strip pattern in this position");
- // TODO: quit stripping now? or keep going?
}
}
void
+CfgStrip::visit (AST::SlicePatternItemsHasRest &items)
+{
+ AST::DefaultASTVisitor::visit (items);
+ // can't strip individual patterns, only sub-patterns
+ for (auto &pattern : items.get_lower_patterns ())
+ {
+ if (pattern->is_marked_for_strip ())
+ rust_error_at (pattern->get_locus (),
+ "cannot strip pattern in this position");
+ }
+ for (auto &pattern : items.get_upper_patterns ())
+ {
+ if (pattern->is_marked_for_strip ())
+ rust_error_at (pattern->get_locus (),
+ "cannot strip pattern in this position");
+ }
+}
+
+void
+CfgStrip::visit (AST::SlicePattern &pattern)
+{
+ AST::DefaultASTVisitor::visit (pattern);
+}
+
+void
CfgStrip::visit (AST::AltPattern &pattern)
{
AST::DefaultASTVisitor::visit (pattern);
diff --git a/gcc/rust/expand/rust-cfg-strip.h b/gcc/rust/expand/rust-cfg-strip.h
index 4900ae8..767cf28 100644
--- a/gcc/rust/expand/rust-cfg-strip.h
+++ b/gcc/rust/expand/rust-cfg-strip.h
@@ -172,6 +172,8 @@ public:
void visit (AST::TuplePatternItemsMultiple &tuple_items) override;
void visit (AST::TuplePatternItemsRanged &tuple_items) override;
void visit (AST::GroupedPattern &pattern) override;
+ void visit (AST::SlicePatternItemsNoRest &items) override;
+ void visit (AST::SlicePatternItemsHasRest &items) override;
void visit (AST::SlicePattern &pattern) override;
void visit (AST::AltPattern &pattern) override;
diff --git a/gcc/rust/expand/rust-derive-clone.h b/gcc/rust/expand/rust-derive-clone.h
index 61224ba..a3320c7 100644
--- a/gcc/rust/expand/rust-derive-clone.h
+++ b/gcc/rust/expand/rust-derive-clone.h
@@ -29,7 +29,7 @@ class DeriveClone : DeriveVisitor
public:
DeriveClone (location_t loc);
- std::unique_ptr<AST::Item> go (Item &item);
+ std::unique_ptr<Item> go (Item &item);
private:
std::unique_ptr<Item> expanded;
@@ -80,10 +80,10 @@ private:
MatchCase clone_enum_struct (PathInExpression variant_path,
const EnumItemStruct &variant);
- virtual void visit_struct (StructStruct &item);
- virtual void visit_tuple (TupleStruct &item);
- virtual void visit_enum (Enum &item);
- virtual void visit_union (Union &item);
+ virtual void visit_struct (StructStruct &item) override;
+ virtual void visit_tuple (TupleStruct &item) override;
+ virtual void visit_enum (Enum &item) override;
+ virtual void visit_union (Union &item) override;
};
} // namespace AST
diff --git a/gcc/rust/expand/rust-derive-cmp-common.cc b/gcc/rust/expand/rust-derive-cmp-common.cc
new file mode 100644
index 0000000..22ca16f
--- /dev/null
+++ b/gcc/rust/expand/rust-derive-cmp-common.cc
@@ -0,0 +1,191 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-derive-cmp-common.h"
+#include "rust-ast-builder.h"
+#include "rust-item.h"
+
+namespace Rust {
+namespace AST {
+
+SelfOther
+SelfOther::index (Builder builder, int idx)
+{
+ return SelfOther{
+ builder.tuple_idx ("self", idx),
+ builder.tuple_idx ("other", idx),
+ };
+}
+
+std::vector<SelfOther>
+SelfOther::indexes (Builder builder, const std::vector<TupleField> &fields)
+{
+ std::vector<SelfOther> vec;
+
+ for (size_t i = 0; i < fields.size (); i++)
+ vec.emplace_back (SelfOther::index (builder, i));
+
+ return vec;
+}
+
+SelfOther
+SelfOther::field (Builder builder, const std::string &field_name)
+{
+ return SelfOther{
+ builder.field_access (builder.identifier ("self"), field_name),
+ builder.field_access (builder.identifier ("other"), field_name),
+ };
+}
+
+std::vector<SelfOther>
+SelfOther::fields (Builder builder, const std::vector<StructField> &fields)
+{
+ std::vector<SelfOther> vec;
+
+ for (const auto &field : fields)
+ vec.emplace_back (
+ SelfOther::field (builder, field.get_field_name ().as_string ()));
+
+ return vec;
+}
+
+MatchCase
+EnumMatchBuilder::tuple (EnumItem &variant_raw)
+{
+ auto &variant = static_cast<EnumItemTuple &> (variant_raw);
+
+ auto self_patterns = std::vector<std::unique_ptr<Pattern>> ();
+ auto other_patterns = std::vector<std::unique_ptr<Pattern>> ();
+
+ auto self_other_exprs = std::vector<SelfOther> ();
+
+ for (size_t i = 0; i < variant.get_tuple_fields ().size (); i++)
+ {
+ // The patterns we're creating for each field are `self_<i>` and
+ // `other_<i>` where `i` is the index of the field. It doesn't actually
+ // matter what we use, as long as it's ordered, unique, and that we can
+ // reuse it in the match case's return expression to check that they are
+ // equal.
+
+ auto self_pattern_str = "__self_" + std::to_string (i);
+ auto other_pattern_str = "__other_" + std::to_string (i);
+
+ self_patterns.emplace_back (
+ builder.identifier_pattern (self_pattern_str));
+ other_patterns.emplace_back (
+ builder.identifier_pattern (other_pattern_str));
+
+ self_other_exprs.emplace_back (SelfOther{
+ builder.identifier (self_pattern_str),
+ builder.identifier (other_pattern_str),
+ });
+ }
+
+ // TODO: Replace with `reconstruct()` instead of building these twice
+ auto self_variant_path = builder.variant_path (enum_path, variant_path);
+ auto other_variant_path = builder.variant_path (enum_path, variant_path);
+
+ auto self_pattern_items = std::unique_ptr<TupleStructItems> (
+ new TupleStructItemsNoRange (std::move (self_patterns)));
+ auto other_pattern_items = std::unique_ptr<TupleStructItems> (
+ new TupleStructItemsNoRange (std::move (other_patterns)));
+
+ auto self_pattern = std::unique_ptr<Pattern> (
+ new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern (
+ self_variant_path, std::move (self_pattern_items))),
+ false, false, builder.loc));
+ auto other_pattern = std::unique_ptr<Pattern> (new ReferencePattern (
+ std::unique_ptr<Pattern> (new TupleStructPattern (
+ other_variant_path, std::move (other_pattern_items))),
+ false, false, builder.loc));
+
+ auto tuple_items = std::make_unique<TuplePatternItemsMultiple> (
+ vec (std::move (self_pattern), std::move (other_pattern)));
+
+ auto pattern
+ = std::make_unique<TuplePattern> (std::move (tuple_items), builder.loc);
+
+ auto expr = fn (std::move (self_other_exprs));
+
+ return builder.match_case (std::move (pattern), std::move (expr));
+}
+
+MatchCase
+EnumMatchBuilder::strukt (EnumItem &variant_raw)
+{
+ auto &variant = static_cast<EnumItemStruct &> (variant_raw);
+
+ auto self_fields = std::vector<std::unique_ptr<StructPatternField>> ();
+ auto other_fields = std::vector<std::unique_ptr<StructPatternField>> ();
+
+ auto self_other_exprs = std::vector<SelfOther> ();
+
+ for (auto &field : variant.get_struct_fields ())
+ {
+ // The patterns we're creating for each field are `self_<field>` and
+ // `other_<field>` where `field` is the name of the field. It doesn't
+ // actually matter what we use, as long as it's ordered, unique, and that
+ // we can reuse it in the match case's return expression to check that
+ // they are equal.
+
+ auto field_name = field.get_field_name ().as_string ();
+
+ auto self_pattern_str = "__self_" + field_name;
+ auto other_pattern_str = "__other_" + field_name;
+
+ self_fields.emplace_back (builder.struct_pattern_ident_pattern (
+ field_name, builder.identifier_pattern (self_pattern_str)));
+ other_fields.emplace_back (builder.struct_pattern_ident_pattern (
+ field_name, builder.identifier_pattern (other_pattern_str)));
+
+ self_other_exprs.emplace_back (SelfOther{
+ builder.identifier (self_pattern_str),
+ builder.identifier (other_pattern_str),
+ });
+ }
+
+ // TODO: Replace with `reconstruct()` instead of building these twice
+ auto self_variant_path = builder.variant_path (enum_path, variant_path);
+ auto other_variant_path = builder.variant_path (enum_path, variant_path);
+
+ auto self_elts = StructPatternElements (std::move (self_fields));
+ auto other_elts = StructPatternElements (std::move (other_fields));
+
+ auto self_pattern = std::unique_ptr<Pattern> (new ReferencePattern (
+ std::unique_ptr<Pattern> (new StructPattern (self_variant_path, builder.loc,
+ std::move (self_elts))),
+ false, false, builder.loc));
+ auto other_pattern = std::unique_ptr<Pattern> (
+ new ReferencePattern (std::unique_ptr<Pattern> (
+ new StructPattern (other_variant_path, builder.loc,
+ std::move (other_elts))),
+ false, false, builder.loc));
+
+ auto tuple_items = std::make_unique<TuplePatternItemsMultiple> (
+ vec (std::move (self_pattern), std::move (other_pattern)));
+
+ auto pattern
+ = std::make_unique<TuplePattern> (std::move (tuple_items), builder.loc);
+
+ auto expr = fn (std::move (self_other_exprs));
+
+ return builder.match_case (std::move (pattern), std::move (expr));
+}
+
+} // namespace AST
+} // namespace Rust
diff --git a/gcc/rust/expand/rust-derive-cmp-common.h b/gcc/rust/expand/rust-derive-cmp-common.h
new file mode 100644
index 0000000..4efbed8
--- /dev/null
+++ b/gcc/rust/expand/rust-derive-cmp-common.h
@@ -0,0 +1,99 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_DERIVE_CMP_COMMON_H
+#define RUST_DERIVE_CMP_COMMON_H
+
+#include "rust-ast.h"
+#include "rust-ast-builder.h"
+#include "rust-item.h"
+#include "rust-path.h"
+
+namespace Rust {
+namespace AST {
+
+/**
+ * A pair of two expressions from each instance being compared. E.g. this
+ * could be `self.0` and `other.0`, or `self.field` and `other.field`
+ */
+struct SelfOther
+{
+ std::unique_ptr<Expr> self_expr;
+ std::unique_ptr<Expr> other_expr;
+
+ /* Create a <self.i> and an <other.i> expression */
+ static SelfOther index (Builder builder, int idx);
+ static std::vector<SelfOther> indexes (Builder builder,
+ const std::vector<TupleField> &fields);
+
+ /* Create a <self.field> and an <other.field> expression */
+ static SelfOther field (Builder builder, const std::string &field_name);
+ static std::vector<SelfOther> fields (Builder builder,
+ const std::vector<StructField> &fields);
+};
+
+/**
+ * Builder for common match cases used when comparing two enum instances. This
+ * builder takes care of creating the unique patterns for the `self` instance
+ * and `other` instance, as well as the entire `MatchCase` required for building
+ * a proper comparision expression for an implementation of a comparision trait
+ * for an enum type. The functions take a lambda to use when creating the
+ * expression of the generated `MatchCase`.
+ */
+class EnumMatchBuilder
+{
+public:
+ /**
+ * The type of functions to call when creating the resulting expression in the
+ * generated `MatchCase`
+ */
+ using ExprFn
+ = std::function<std::unique_ptr<Expr> (std::vector<SelfOther> &&)>;
+
+ EnumMatchBuilder (const std::string &enum_path,
+ const std::string &variant_path, ExprFn fn,
+ Builder &builder)
+ : enum_path (enum_path), variant_path (variant_path), fn (fn),
+ builder (builder)
+ {}
+
+ /**
+ * Generate a `MatchCase` for an enum tuple variant
+ *
+ * (&Enum::Tuple(self0, self1), &Enum::Tuple(other0, other1)) => <fn>
+ */
+ MatchCase tuple (EnumItem &variant);
+
+ /**
+ * Generate a `MatchCase` for an enum struct variant
+ *
+ * (&Enum::Struct { a: self_a }, &Enum::Struct { a: other_a }) => <fn>
+ */
+ MatchCase strukt (EnumItem &variant);
+
+private:
+ const std::string &enum_path;
+ const std::string &variant_path;
+ ExprFn fn;
+ Builder &builder;
+};
+
+} // namespace AST
+} // namespace Rust
+
+#endif // ! RUST_DERIVE_CMP_COMMON_H
diff --git a/gcc/rust/expand/rust-derive-copy.h b/gcc/rust/expand/rust-derive-copy.h
index 71972eb..664a8e0 100644
--- a/gcc/rust/expand/rust-derive-copy.h
+++ b/gcc/rust/expand/rust-derive-copy.h
@@ -44,10 +44,10 @@ private:
copy_impl (std::string name,
const std::vector<std::unique_ptr<GenericParam>> &type_generics);
- virtual void visit_struct (StructStruct &item);
- virtual void visit_tuple (TupleStruct &item);
- virtual void visit_enum (Enum &item);
- virtual void visit_union (Union &item);
+ virtual void visit_struct (StructStruct &item) override;
+ virtual void visit_tuple (TupleStruct &item) override;
+ virtual void visit_enum (Enum &item) override;
+ virtual void visit_union (Union &item) override;
};
} // namespace AST
diff --git a/gcc/rust/expand/rust-derive-default.cc b/gcc/rust/expand/rust-derive-default.cc
index 2e8b456..26ee546 100644
--- a/gcc/rust/expand/rust-derive-default.cc
+++ b/gcc/rust/expand/rust-derive-default.cc
@@ -98,7 +98,8 @@ DeriveDefault::visit_struct (StructStruct &item)
for (auto &field : item.get_fields ())
{
auto name = field.get_field_name ().as_string ();
- auto expr = default_call (field.get_field_type ().clone_type ());
+ auto type = field.get_field_type ().reconstruct ();
+ auto expr = default_call (std::move (type));
cloned_fields.emplace_back (
builder.struct_expr_field (std::move (name), std::move (expr)));
@@ -119,7 +120,7 @@ DeriveDefault::visit_tuple (TupleStruct &tuple_item)
for (auto &field : tuple_item.get_fields ())
{
- auto type = field.get_field_type ().clone_type ();
+ auto type = field.get_field_type ().reconstruct ();
defaulted_fields.emplace_back (default_call (std::move (type)));
}
diff --git a/gcc/rust/expand/rust-derive-eq.cc b/gcc/rust/expand/rust-derive-eq.cc
index 5e7a894..7da137f 100644
--- a/gcc/rust/expand/rust-derive-eq.cc
+++ b/gcc/rust/expand/rust-derive-eq.cc
@@ -142,7 +142,7 @@ DeriveEq::visit_tuple (TupleStruct &item)
auto types = std::vector<std::unique_ptr<Type>> ();
for (auto &field : item.get_fields ())
- types.emplace_back (field.get_field_type ().clone_type ());
+ types.emplace_back (field.get_field_type ().reconstruct ());
expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)),
item.get_identifier ().as_string (),
@@ -155,7 +155,7 @@ DeriveEq::visit_struct (StructStruct &item)
auto types = std::vector<std::unique_ptr<Type>> ();
for (auto &field : item.get_fields ())
- types.emplace_back (field.get_field_type ().clone_type ());
+ types.emplace_back (field.get_field_type ().reconstruct ());
expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)),
item.get_identifier ().as_string (),
@@ -175,19 +175,20 @@ DeriveEq::visit_enum (Enum &item)
case EnumItem::Kind::Discriminant:
// nothing to do as they contain no inner types
continue;
- case EnumItem::Kind::Tuple: {
+ case EnumItem::Kind::Tuple:
+ {
auto &tuple = static_cast<EnumItemTuple &> (*variant);
for (auto &field : tuple.get_tuple_fields ())
- types.emplace_back (field.get_field_type ().clone_type ());
-
+ types.emplace_back (field.get_field_type ().reconstruct ());
break;
}
- case EnumItem::Kind::Struct: {
+ case EnumItem::Kind::Struct:
+ {
auto &tuple = static_cast<EnumItemStruct &> (*variant);
for (auto &field : tuple.get_struct_fields ())
- types.emplace_back (field.get_field_type ().clone_type ());
+ types.emplace_back (field.get_field_type ().reconstruct ());
break;
}
@@ -205,7 +206,7 @@ DeriveEq::visit_union (Union &item)
auto types = std::vector<std::unique_ptr<Type>> ();
for (auto &field : item.get_variants ())
- types.emplace_back (field.get_field_type ().clone_type ());
+ types.emplace_back (field.get_field_type ().reconstruct ());
expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)),
item.get_identifier ().as_string (),
diff --git a/gcc/rust/expand/rust-derive-eq.h b/gcc/rust/expand/rust-derive-eq.h
index 17af526..fb187cc 100644
--- a/gcc/rust/expand/rust-derive-eq.h
+++ b/gcc/rust/expand/rust-derive-eq.h
@@ -31,7 +31,7 @@ class DeriveEq : DeriveVisitor
public:
DeriveEq (location_t loc);
- std::vector<std::unique_ptr<AST::Item>> go (Item &item);
+ std::vector<std::unique_ptr<Item>> go (Item &item);
private:
std::vector<std::unique_ptr<Item>> expanded;
@@ -70,10 +70,10 @@ private:
*/
std::unique_ptr<Stmt> assert_type_is_eq (std::unique_ptr<Type> &&type);
- virtual void visit_struct (StructStruct &item);
- virtual void visit_tuple (TupleStruct &item);
- virtual void visit_enum (Enum &item);
- virtual void visit_union (Union &item);
+ virtual void visit_struct (StructStruct &item) override;
+ virtual void visit_tuple (TupleStruct &item) override;
+ virtual void visit_enum (Enum &item) override;
+ virtual void visit_union (Union &item) override;
};
} // namespace AST
diff --git a/gcc/rust/expand/rust-derive-hash.cc b/gcc/rust/expand/rust-derive-hash.cc
index 0c9b0f7..94aede2 100644
--- a/gcc/rust/expand/rust-derive-hash.cc
+++ b/gcc/rust/expand/rust-derive-hash.cc
@@ -231,14 +231,7 @@ DeriveHash::visit_enum (Enum &item)
auto cases = std::vector<MatchCase> ();
auto type_name = item.get_identifier ().as_string ();
- auto intrinsic = ptrify (
- builder.path_in_expression ({"core", "intrinsics", "discriminant_value"},
- true));
-
- auto let_discr
- = builder.let (builder.identifier_pattern (DeriveHash::discr), nullptr,
- builder.call (std::move (intrinsic),
- builder.identifier ("self")));
+ auto let_discr = builder.discriminant_value (DeriveHash::discr);
auto discr_hash = builder.statementify (
hash_call (builder.ref (builder.identifier (DeriveHash::discr))));
diff --git a/gcc/rust/expand/rust-derive-hash.h b/gcc/rust/expand/rust-derive-hash.h
index 02b0bee..67170d0 100644
--- a/gcc/rust/expand/rust-derive-hash.h
+++ b/gcc/rust/expand/rust-derive-hash.h
@@ -29,7 +29,7 @@ class DeriveHash : DeriveVisitor
public:
DeriveHash (location_t loc);
- std::unique_ptr<AST::Item> go (Item &item);
+ std::unique_ptr<Item> go (Item &item);
private:
std::unique_ptr<Item> expanded;
@@ -49,10 +49,10 @@ private:
MatchCase match_enum_struct (PathInExpression variant_path,
const EnumItemStruct &variant);
- virtual void visit_struct (StructStruct &item);
- virtual void visit_tuple (TupleStruct &item);
- virtual void visit_enum (Enum &item);
- virtual void visit_union (Union &item);
+ virtual void visit_struct (StructStruct &item) override;
+ virtual void visit_tuple (TupleStruct &item) override;
+ virtual void visit_enum (Enum &item) override;
+ virtual void visit_union (Union &item) override;
};
} // namespace AST
diff --git a/gcc/rust/expand/rust-derive-ord.cc b/gcc/rust/expand/rust-derive-ord.cc
new file mode 100644
index 0000000..afc4b71
--- /dev/null
+++ b/gcc/rust/expand/rust-derive-ord.cc
@@ -0,0 +1,323 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-derive-ord.h"
+#include "rust-ast.h"
+#include "rust-derive-cmp-common.h"
+#include "rust-derive.h"
+#include "rust-item.h"
+#include "rust-system.h"
+
+namespace Rust {
+namespace AST {
+
+DeriveOrd::DeriveOrd (Ordering ordering, location_t loc)
+ : DeriveVisitor (loc), ordering (ordering)
+{}
+
+std::unique_ptr<Item>
+DeriveOrd::go (Item &item)
+{
+ item.accept_vis (*this);
+
+ return std::move (expanded);
+}
+
+std::unique_ptr<Expr>
+DeriveOrd::cmp_call (std::unique_ptr<Expr> &&self_expr,
+ std::unique_ptr<Expr> &&other_expr)
+{
+ auto cmp_fn_path = builder.path_in_expression (
+ {"core", "cmp", trait (ordering), fn (ordering)}, true);
+
+ return builder.call (ptrify (cmp_fn_path),
+ vec (builder.ref (std::move (self_expr)),
+ builder.ref (std::move (other_expr))));
+}
+
+std::unique_ptr<Item>
+DeriveOrd::cmp_impl (
+ std::unique_ptr<BlockExpr> &&fn_block, Identifier type_name,
+ const std::vector<std::unique_ptr<GenericParam>> &type_generics)
+{
+ auto fn = cmp_fn (std::move (fn_block), type_name);
+
+ auto trait = ordering == Ordering::Partial ? "PartialOrd" : "Ord";
+ auto trait_path = builder.type_path ({"core", "cmp", trait}, true);
+
+ auto trait_bound
+ = builder.trait_bound (builder.type_path ({"core", "cmp", trait}, true));
+
+ auto trait_items = vec (std::move (fn));
+
+ auto cmp_generics
+ = setup_impl_generics (type_name.as_string (), type_generics,
+ std::move (trait_bound));
+
+ return builder.trait_impl (trait_path, std::move (cmp_generics.self_type),
+ std::move (trait_items),
+ std::move (cmp_generics.impl));
+}
+
+std::unique_ptr<AssociatedItem>
+DeriveOrd::cmp_fn (std::unique_ptr<BlockExpr> &&block, Identifier type_name)
+{
+ // Ordering
+ auto return_type = builder.type_path ({"core", "cmp", "Ordering"}, true);
+
+ // In the case of PartialOrd, we return an Option<Ordering>
+ if (ordering == Ordering::Partial)
+ {
+ auto generic = GenericArg::create_type (ptrify (return_type));
+
+ auto generic_seg = builder.type_path_segment_generic (
+ "Option", GenericArgs ({}, {generic}, {}, loc));
+ auto core = builder.type_path_segment ("core");
+ auto option = builder.type_path_segment ("option");
+
+ return_type
+ = builder.type_path (vec (std::move (core), std::move (option),
+ std::move (generic_seg)),
+ true);
+ }
+
+ // &self, other: &Self
+ auto params = vec (
+ builder.self_ref_param (),
+ builder.function_param (builder.identifier_pattern ("other"),
+ builder.reference_type (ptrify (
+ builder.type_path (type_name.as_string ())))));
+
+ auto function_name = fn (ordering);
+
+ return builder.function (function_name, std::move (params),
+ ptrify (return_type), std::move (block));
+}
+
+std::unique_ptr<Pattern>
+DeriveOrd::make_equal ()
+{
+ std::unique_ptr<Pattern> equal = ptrify (
+ builder.path_in_expression ({"core", "cmp", "Ordering", "Equal"}, true));
+
+ // We need to wrap the pattern in Option::Some if we are doing partial
+ // ordering
+ if (ordering == Ordering::Partial)
+ {
+ auto pattern_items = std::unique_ptr<TupleStructItems> (
+ new TupleStructItemsNoRange (vec (std::move (equal))));
+
+ equal
+ = std::make_unique<TupleStructPattern> (builder.path_in_expression (
+ LangItem::Kind::OPTION_SOME),
+ std::move (pattern_items));
+ }
+
+ return equal;
+}
+
+std::pair<MatchArm, MatchArm>
+DeriveOrd::make_cmp_arms ()
+{
+ // All comparison results other than Ordering::Equal
+ auto non_equal = builder.identifier_pattern (DeriveOrd::not_equal);
+ auto equal = make_equal ();
+
+ return {builder.match_arm (std::move (equal)),
+ builder.match_arm (std::move (non_equal))};
+}
+
+std::unique_ptr<Expr>
+DeriveOrd::recursive_match (std::vector<SelfOther> &&members)
+{
+ if (members.empty ())
+ {
+ std::unique_ptr<Expr> value = ptrify (
+ builder.path_in_expression ({"core", "cmp", "Ordering", "Equal"},
+ true));
+
+ if (ordering == Ordering::Partial)
+ value = builder.call (ptrify (builder.path_in_expression (
+ LangItem::Kind::OPTION_SOME)),
+ std::move (value));
+
+ return value;
+ }
+
+ std::unique_ptr<Expr> final_expr = nullptr;
+
+ for (auto it = members.rbegin (); it != members.rend (); it++)
+ {
+ auto &member = *it;
+
+ auto call = cmp_call (std::move (member.self_expr),
+ std::move (member.other_expr));
+
+ // For the last member (so the first iterator), we just create a call
+ // expression
+ if (it == members.rbegin ())
+ {
+ final_expr = std::move (call);
+ continue;
+ }
+
+ // If we aren't dealing with the last member, then we need to wrap all of
+ // that in a big match expression and keep going
+ auto match_arms = make_cmp_arms ();
+
+ auto match_cases
+ = {builder.match_case (std::move (match_arms.first),
+ std::move (final_expr)),
+ builder.match_case (std::move (match_arms.second),
+ builder.identifier (DeriveOrd::not_equal))};
+
+ final_expr = builder.match (std::move (call), std::move (match_cases));
+ }
+
+ return final_expr;
+}
+
+// we need to do a recursive match expression for all of the fields used in a
+// struct so for something like struct Foo { a: i32, b: i32, c: i32 } we must
+// first compare each `a` field, then `b`, then `c`, like this:
+//
+// match cmp_fn(self.<field>, other.<field>) {
+// Ordering::Equal => <recurse>,
+// cmp => cmp,
+// }
+//
+// and the recurse will be the exact same expression, on the next field. so that
+// our result looks like this:
+//
+// match cmp_fn(self.a, other.a) {
+// Ordering::Equal => match cmp_fn(self.b, other.b) {
+// Ordering::Equal =>cmp_fn(self.c, other.c),
+// cmp => cmp,
+// }
+// cmp => cmp,
+// }
+//
+// the last field comparison needs not to be a match but just the function call.
+// this is going to be annoying lol
+void
+DeriveOrd::visit_struct (StructStruct &item)
+{
+ auto fields = SelfOther::fields (builder, item.get_fields ());
+
+ auto match_expr = recursive_match (std::move (fields));
+
+ expanded = cmp_impl (builder.block (std::move (match_expr)),
+ item.get_identifier (), item.get_generic_params ());
+}
+
+// same as structs, but for each field index instead of each field name -
+// straightforward once we have `visit_struct` working
+void
+DeriveOrd::visit_tuple (TupleStruct &item)
+{
+ auto fields = SelfOther::indexes (builder, item.get_fields ());
+
+ auto match_expr = recursive_match (std::move (fields));
+
+ expanded = cmp_impl (builder.block (std::move (match_expr)),
+ item.get_identifier (), item.get_generic_params ());
+}
+
+// for enums, we need to generate a match for each of the enum's variant that
+// contains data and then do the same thing as visit_struct or visit_enum. if
+// the two aren't the same variant, then compare the two discriminant values for
+// all the dataless enum variants and in the general case.
+//
+// so for enum Foo { A(i32, i32), B, C } we need to do the following
+//
+// match (self, other) {
+// (A(self_0, self_1), A(other_0, other_1)) => {
+// match cmp_fn(self_0, other_0) {
+// Ordering::Equal => cmp_fn(self_1, other_1),
+// cmp => cmp,
+// },
+// _ => cmp_fn(discr_value(self), discr_value(other))
+// }
+void
+DeriveOrd::visit_enum (Enum &item)
+{
+ // NOTE: We can factor this even further with DerivePartialEq, but this is
+ // getting out of scope for this PR surely
+
+ auto cases = std::vector<MatchCase> ();
+ auto type_name = item.get_identifier ().as_string ();
+
+ auto let_sd = builder.discriminant_value (DeriveOrd::self_discr, "self");
+ auto let_od = builder.discriminant_value (DeriveOrd::other_discr, "other");
+
+ auto discr_cmp = cmp_call (builder.identifier (DeriveOrd::self_discr),
+ builder.identifier (DeriveOrd::other_discr));
+
+ auto recursive_match_fn = [this] (std::vector<SelfOther> &&fields) {
+ return recursive_match (std::move (fields));
+ };
+
+ for (auto &variant : item.get_variants ())
+ {
+ auto enum_builder
+ = EnumMatchBuilder (type_name, variant->get_identifier ().as_string (),
+ recursive_match_fn, builder);
+
+ switch (variant->get_enum_item_kind ())
+ {
+ case EnumItem::Kind::Struct:
+ cases.emplace_back (enum_builder.strukt (*variant));
+ break;
+ case EnumItem::Kind::Tuple:
+ cases.emplace_back (enum_builder.tuple (*variant));
+ break;
+ case EnumItem::Kind::Identifier:
+ case EnumItem::Kind::Discriminant:
+ // We don't need to do anything for these, as they are handled by the
+ // discriminant value comparison
+ break;
+ }
+ }
+
+ // Add the last case which compares the discriminant values in case `self` and
+ // `other` are actually different variants of the enum
+ cases.emplace_back (
+ builder.match_case (builder.wildcard (), std::move (discr_cmp)));
+
+ auto match
+ = builder.match (builder.tuple (vec (builder.identifier ("self"),
+ builder.identifier ("other"))),
+ std::move (cases));
+
+ expanded
+ = cmp_impl (builder.block (vec (std::move (let_sd), std::move (let_od)),
+ std::move (match)),
+ type_name, item.get_generic_params ());
+}
+
+void
+DeriveOrd::visit_union (Union &item)
+{
+ auto trait_name = trait (ordering);
+
+ rust_error_at (item.get_locus (), "derive(%s) cannot be used on unions",
+ trait_name.c_str ());
+}
+
+} // namespace AST
+} // namespace Rust
diff --git a/gcc/rust/expand/rust-derive-ord.h b/gcc/rust/expand/rust-derive-ord.h
new file mode 100644
index 0000000..90ce9c8
--- /dev/null
+++ b/gcc/rust/expand/rust-derive-ord.h
@@ -0,0 +1,122 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_DERIVE_ORD_H
+#define RUST_DERIVE_ORD_H
+
+#include "rust-ast.h"
+#include "rust-derive-cmp-common.h"
+#include "rust-derive.h"
+
+namespace Rust {
+namespace AST {
+
+/**
+ * DeriveOrd is a bit special as the expansion of both `PartialOrd` and `Ord`
+ * is extremely similar. The only difference is that `PartialOrd` concerns
+ * partial-ordering, and thus its main method returns an `Option<Ordering>`,
+ * while `Ord` concerns total-ordering, and its main method returns an
+ * `Ordering`. Otherwise, the expansion logic is the same, so we factor both
+ * derives into one.
+ */
+class DeriveOrd : public DeriveVisitor
+{
+public:
+ enum class Ordering
+ {
+ Total,
+ Partial
+ };
+
+ std::string fn (Ordering ordering)
+ {
+ if (ordering == Ordering::Total)
+ return "cmp";
+ else
+ return "partial_cmp";
+ }
+
+ std::string trait (Ordering ordering)
+ {
+ if (ordering == Ordering::Total)
+ return "Ord";
+ else
+ return "PartialOrd";
+ }
+
+ DeriveOrd (Ordering ordering, location_t loc);
+
+ std::unique_ptr<Item> go (Item &item);
+
+private:
+ std::unique_ptr<Item> expanded;
+
+ Ordering ordering;
+
+ /* Identifier patterns for the non-equal match arms */
+ constexpr static const char *not_equal = "#non_eq";
+ constexpr static const char *self_discr = "#self_discr";
+ constexpr static const char *other_discr = "#other_discr";
+
+ /**
+ * Create the recursive matching structure used when implementing the
+ * comparison function on multiple sub items (fields, tuple indexes...)
+ */
+ std::unique_ptr<Expr> recursive_match (std::vector<SelfOther> &&members);
+
+ /**
+ * Create a pattern for the `Ordering::Equal` case. In the case of partial
+ * ordering, `Option::Some(Ordering::Equal)`.
+ */
+ std::unique_ptr<Pattern> make_equal ();
+
+ /**
+ * Make the match arms for one inner match in a comparison function block.
+ * This returns the "equal" match arm and the "rest" match arm, so something
+ * like `Ordering::Equal` and `non_eq` in the following match expression:
+ *
+ * match cmp(...) {
+ * Ordering::Equal => match cmp(...) { ... }
+ * non_eq => non_eq,
+ * }
+ */
+ std::pair<MatchArm, MatchArm> make_cmp_arms ();
+
+ /**
+ * Generate a call to the proper trait function, based on the ordering, in
+ * order to compare two given expressions
+ */
+ std::unique_ptr<Expr> cmp_call (std::unique_ptr<Expr> &&self_expr,
+ std::unique_ptr<Expr> &&other_expr);
+
+ std::unique_ptr<Item>
+ cmp_impl (std::unique_ptr<BlockExpr> &&fn_block, Identifier type_name,
+ const std::vector<std::unique_ptr<GenericParam>> &type_generics);
+ std::unique_ptr<AssociatedItem> cmp_fn (std::unique_ptr<BlockExpr> &&block,
+ Identifier type_name);
+
+ virtual void visit_struct (StructStruct &item) override;
+ virtual void visit_tuple (TupleStruct &item) override;
+ virtual void visit_enum (Enum &item) override;
+ virtual void visit_union (Union &item) override;
+};
+
+} // namespace AST
+} // namespace Rust
+
+#endif // ! RUST_DERIVE_ORD_H
diff --git a/gcc/rust/expand/rust-derive-partial-eq.cc b/gcc/rust/expand/rust-derive-partial-eq.cc
index ff66faa..a0bf87a 100644
--- a/gcc/rust/expand/rust-derive-partial-eq.cc
+++ b/gcc/rust/expand/rust-derive-partial-eq.cc
@@ -64,11 +64,9 @@ DerivePartialEq::partialeq_impls (
}
std::unique_ptr<AssociatedItem>
-DerivePartialEq::eq_fn (std::unique_ptr<Expr> &&cmp_expression,
+DerivePartialEq::eq_fn (std::unique_ptr<BlockExpr> &&block,
std::string type_name)
{
- auto block = builder.block (tl::nullopt, std::move (cmp_expression));
-
auto self_type
= std::unique_ptr<TypeNoBounds> (new TypePath (builder.type_path ("Self")));
@@ -83,24 +81,6 @@ DerivePartialEq::eq_fn (std::unique_ptr<Expr> &&cmp_expression,
std::move (block));
}
-DerivePartialEq::SelfOther
-DerivePartialEq::tuple_indexes (int idx)
-{
- return SelfOther{
- builder.tuple_idx ("self", idx),
- builder.tuple_idx ("other", idx),
- };
-}
-
-DerivePartialEq::SelfOther
-DerivePartialEq::field_acccesses (const std::string &field_name)
-{
- return SelfOther{
- builder.field_access (builder.identifier ("self"), field_name),
- builder.field_access (builder.identifier ("other"), field_name),
- };
-}
-
std::unique_ptr<Expr>
DerivePartialEq::build_eq_expression (
std::vector<SelfOther> &&field_expressions)
@@ -134,12 +114,10 @@ void
DerivePartialEq::visit_tuple (TupleStruct &item)
{
auto type_name = item.get_struct_name ().as_string ();
- auto fields = std::vector<SelfOther> ();
-
- for (size_t idx = 0; idx < item.get_fields ().size (); idx++)
- fields.emplace_back (tuple_indexes (idx));
+ auto fields = SelfOther::indexes (builder, item.get_fields ());
- auto fn = eq_fn (build_eq_expression (std::move (fields)), type_name);
+ auto fn = eq_fn (builder.block (build_eq_expression (std::move (fields))),
+ type_name);
expanded
= partialeq_impls (std::move (fn), type_name, item.get_generic_params ());
@@ -149,13 +127,10 @@ void
DerivePartialEq::visit_struct (StructStruct &item)
{
auto type_name = item.get_struct_name ().as_string ();
- auto fields = std::vector<SelfOther> ();
+ auto fields = SelfOther::fields (builder, item.get_fields ());
- for (auto &field : item.get_fields ())
- fields.emplace_back (
- field_acccesses (field.get_field_name ().as_string ()));
-
- auto fn = eq_fn (build_eq_expression (std::move (fields)), type_name);
+ auto fn = eq_fn (builder.block (build_eq_expression (std::move (fields))),
+ type_name);
expanded
= partialeq_impls (std::move (fn), type_name, item.get_generic_params ());
@@ -199,8 +174,6 @@ DerivePartialEq::match_enum_tuple (PathInExpression variant_path,
auto self_pattern_str = "__self_" + std::to_string (i);
auto other_pattern_str = "__other_" + std::to_string (i);
- rust_debug ("]ARTHUR[ %s", self_pattern_str.c_str ());
-
self_patterns.emplace_back (
builder.identifier_pattern (self_pattern_str));
other_patterns.emplace_back (
@@ -240,15 +213,55 @@ MatchCase
DerivePartialEq::match_enum_struct (PathInExpression variant_path,
const EnumItemStruct &variant)
{
- // NOTE: We currently do not support compiling struct patterns where an
- // identifier is assigned a new pattern, e.g. Bloop { f0: x }
- // This is what we should be using to compile PartialEq for enum struct
- // variants, as we need to be comparing the field of each instance meaning we
- // need to give two different names to two different instances of the same
- // field. We cannot just use the field's name like we do when deriving
- // `Clone`.
-
- rust_unreachable ();
+ auto self_fields = std::vector<std::unique_ptr<StructPatternField>> ();
+ auto other_fields = std::vector<std::unique_ptr<StructPatternField>> ();
+
+ auto self_other_exprs = std::vector<SelfOther> ();
+
+ for (auto &field : variant.get_struct_fields ())
+ {
+ // The patterns we're creating for each field are `self_<field>` and
+ // `other_<field>` where `field` is the name of the field. It doesn't
+ // actually matter what we use, as long as it's ordered, unique, and that
+ // we can reuse it in the match case's return expression to check that
+ // they are equal.
+
+ auto field_name = field.get_field_name ().as_string ();
+
+ auto self_pattern_str = "__self_" + field_name;
+ auto other_pattern_str = "__other_" + field_name;
+
+ self_fields.emplace_back (builder.struct_pattern_ident_pattern (
+ field_name, builder.identifier_pattern (self_pattern_str)));
+ other_fields.emplace_back (builder.struct_pattern_ident_pattern (
+ field_name, builder.identifier_pattern (other_pattern_str)));
+
+ self_other_exprs.emplace_back (SelfOther{
+ builder.identifier (self_pattern_str),
+ builder.identifier (other_pattern_str),
+ });
+ }
+
+ auto self_elts = StructPatternElements (std::move (self_fields));
+ auto other_elts = StructPatternElements (std::move (other_fields));
+
+ auto self_pattern = std::unique_ptr<Pattern> (
+ new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
+ variant_path, loc, std::move (self_elts))),
+ false, false, loc));
+ auto other_pattern = std::unique_ptr<Pattern> (
+ new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
+ variant_path, loc, std::move (other_elts))),
+ false, false, loc));
+
+ auto tuple_items = std::make_unique<TuplePatternItemsMultiple> (
+ vec (std::move (self_pattern), std::move (other_pattern)));
+
+ auto pattern = std::make_unique<TuplePattern> (std::move (tuple_items), loc);
+
+ auto expr = build_eq_expression (std::move (self_other_exprs));
+
+ return builder.match_case (std::move (pattern), std::move (expr));
}
void
@@ -257,46 +270,56 @@ DerivePartialEq::visit_enum (Enum &item)
auto cases = std::vector<MatchCase> ();
auto type_name = item.get_identifier ().as_string ();
+ auto eq_expr_fn = [this] (std::vector<SelfOther> &&fields) {
+ return build_eq_expression (std::move (fields));
+ };
+
+ auto let_sd
+ = builder.discriminant_value (DerivePartialEq::self_discr, "self");
+ auto let_od
+ = builder.discriminant_value (DerivePartialEq::other_discr, "other");
+
+ auto discr_cmp
+ = builder.comparison_expr (builder.identifier (DerivePartialEq::self_discr),
+ builder.identifier (
+ DerivePartialEq::other_discr),
+ ComparisonOperator::EQUAL);
+
for (auto &variant : item.get_variants ())
{
- auto variant_path
- = builder.variant_path (type_name,
- variant->get_identifier ().as_string ());
+ auto enum_builder
+ = EnumMatchBuilder (type_name, variant->get_identifier ().as_string (),
+ eq_expr_fn, builder);
switch (variant->get_enum_item_kind ())
{
- case EnumItem::Kind::Identifier:
- case EnumItem::Kind::Discriminant:
- cases.emplace_back (match_enum_identifier (variant_path, variant));
- break;
case EnumItem::Kind::Tuple:
- cases.emplace_back (
- match_enum_tuple (variant_path,
- static_cast<EnumItemTuple &> (*variant)));
+ cases.emplace_back (enum_builder.tuple (*variant));
break;
case EnumItem::Kind::Struct:
- rust_sorry_at (
- item.get_locus (),
- "cannot derive(PartialEq) for enum struct variants yet");
+ cases.emplace_back (enum_builder.strukt (*variant));
+ break;
+ case EnumItem::Kind::Identifier:
+ case EnumItem::Kind::Discriminant:
+ // We don't need to do anything for these, as they are handled by the
+ // discriminant value comparison
break;
}
}
- // NOTE: Mention using discriminant_value and skipping that last case, and
- // instead skipping all identifiers/discriminant enum items and returning
- // `true` in the wildcard case
-
// In case the two instances of `Self` don't have the same discriminant,
// automatically return false.
cases.emplace_back (
- builder.match_case (builder.wildcard (), builder.literal_bool (false)));
+ builder.match_case (builder.wildcard (), std::move (discr_cmp)));
auto match
= builder.match (builder.tuple (vec (builder.identifier ("self"),
builder.identifier ("other"))),
std::move (cases));
- auto fn = eq_fn (std::move (match), type_name);
+ auto fn = eq_fn (builder.block (vec (std::move (let_sd), std::move (let_od)),
+ std::move (match)),
+ type_name);
expanded
= partialeq_impls (std::move (fn), type_name, item.get_generic_params ());
diff --git a/gcc/rust/expand/rust-derive-partial-eq.h b/gcc/rust/expand/rust-derive-partial-eq.h
index ac963a6..7985414 100644
--- a/gcc/rust/expand/rust-derive-partial-eq.h
+++ b/gcc/rust/expand/rust-derive-partial-eq.h
@@ -21,6 +21,7 @@
#include "rust-derive.h"
#include "rust-path.h"
+#include "rust-derive-cmp-common.h"
namespace Rust {
namespace AST {
@@ -30,7 +31,7 @@ class DerivePartialEq : DeriveVisitor
public:
DerivePartialEq (location_t loc);
- std::vector<std::unique_ptr<AST::Item>> go (Item &item);
+ std::vector<std::unique_ptr<Item>> go (Item &item);
private:
std::vector<std::unique_ptr<Item>> expanded;
@@ -43,23 +44,10 @@ private:
std::unique_ptr<AssociatedItem> &&eq_fn, std::string name,
const std::vector<std::unique_ptr<GenericParam>> &type_generics);
- std::unique_ptr<AssociatedItem> eq_fn (std::unique_ptr<Expr> &&cmp_expression,
+ std::unique_ptr<AssociatedItem> eq_fn (std::unique_ptr<BlockExpr> &&block,
std::string type_name);
/**
- * A pair of two expressions from each instance being compared. E.g. this
- * could be `self.0` and `other.0`, or `self.field` and `other.field`
- */
- struct SelfOther
- {
- std::unique_ptr<Expr> self_expr;
- std::unique_ptr<Expr> other_expr;
- };
-
- SelfOther tuple_indexes (int idx);
- SelfOther field_acccesses (const std::string &field_name);
-
- /**
* Build a suite of equality arithmetic expressions chained together by a
* boolean AND operator
*/
@@ -73,10 +61,13 @@ private:
MatchCase match_enum_struct (PathInExpression variant_path,
const EnumItemStruct &variant);
- virtual void visit_struct (StructStruct &item);
- virtual void visit_tuple (TupleStruct &item);
- virtual void visit_enum (Enum &item);
- virtual void visit_union (Union &item);
+ constexpr static const char *self_discr = "#self_discr";
+ constexpr static const char *other_discr = "#other_discr";
+
+ virtual void visit_struct (StructStruct &item) override;
+ virtual void visit_tuple (TupleStruct &item) override;
+ virtual void visit_enum (Enum &item) override;
+ virtual void visit_union (Union &item) override;
};
} // namespace AST
diff --git a/gcc/rust/expand/rust-derive.cc b/gcc/rust/expand/rust-derive.cc
index 015b81e..55147df 100644
--- a/gcc/rust/expand/rust-derive.cc
+++ b/gcc/rust/expand/rust-derive.cc
@@ -22,6 +22,7 @@
#include "rust-derive-debug.h"
#include "rust-derive-default.h"
#include "rust-derive-eq.h"
+#include "rust-derive-ord.h"
#include "rust-derive-partial-eq.h"
#include "rust-derive-hash.h"
@@ -59,10 +60,11 @@ DeriveVisitor::derive (Item &item, const Attribute &attr,
case BuiltinMacro::Hash:
return vec (DeriveHash (loc).go (item));
case BuiltinMacro::Ord:
+ return vec (DeriveOrd (DeriveOrd::Ordering::Total, loc).go (item));
case BuiltinMacro::PartialOrd:
+ return vec (DeriveOrd (DeriveOrd::Ordering::Partial, loc).go (item));
default:
- rust_sorry_at (loc, "unimplemented builtin derive macro");
- return {};
+ rust_unreachable ();
};
}
@@ -79,7 +81,8 @@ DeriveVisitor::setup_impl_generics (
{
switch (generic->get_kind ())
{
- case GenericParam::Kind::Lifetime: {
+ case GenericParam::Kind::Lifetime:
+ {
LifetimeParam &lifetime_param = (LifetimeParam &) *generic.get ();
Lifetime l = builder.new_lifetime (lifetime_param.get_lifetime ());
@@ -91,7 +94,8 @@ DeriveVisitor::setup_impl_generics (
}
break;
- case GenericParam::Kind::Type: {
+ case GenericParam::Kind::Type:
+ {
TypeParam &type_param = (TypeParam &) *generic.get ();
std::unique_ptr<Type> associated_type = builder.single_type_path (
@@ -104,7 +108,8 @@ DeriveVisitor::setup_impl_generics (
std::vector<std::unique_ptr<TypeParamBound>> extra_bounds;
if (extra_bound)
- extra_bounds.emplace_back (std::move (*extra_bound));
+ extra_bounds.emplace_back (
+ extra_bound.value ()->clone_type_param_bound ());
auto impl_type_param
= builder.new_type_param (type_param, std::move (extra_bounds));
@@ -113,17 +118,20 @@ DeriveVisitor::setup_impl_generics (
}
break;
- case GenericParam::Kind::Const: {
- rust_unreachable ();
+ case GenericParam::Kind::Const:
+ {
+ ConstGenericParam &const_param
+ = (ConstGenericParam &) *generic.get ();
- // TODO
- // const ConstGenericParam *const_param
- // = (const ConstGenericParam *) generic.get ();
- // std::unique_ptr<Expr> const_expr = nullptr;
+ std::unique_ptr<Type> associated_type
+ = builder.single_type_path (const_param.get_name ().as_string ());
- // GenericArg type_arg
- // = GenericArg::create_const (std::move (const_expr));
- // generic_args.push_back (std::move (type_arg));
+ GenericArg type_arg
+ = GenericArg::create_type (std::move (associated_type));
+ generic_args.push_back (std::move (type_arg));
+
+ auto impl_const_param = builder.new_const_param (const_param);
+ impl_generics.push_back (std::move (impl_const_param));
}
break;
}
diff --git a/gcc/rust/expand/rust-derive.h b/gcc/rust/expand/rust-derive.h
index 5fca49c..10c146c 100644
--- a/gcc/rust/expand/rust-derive.h
+++ b/gcc/rust/expand/rust-derive.h
@@ -118,7 +118,7 @@ private:
virtual void visit (LiteralExpr &expr) override final{};
virtual void visit (AttrInputLiteral &attr_input) override final{};
virtual void visit (MetaItemLitExpr &meta_item) override final{};
- virtual void visit (MetaItemPathLit &meta_item) override final{};
+ virtual void visit (MetaItemPathExpr &meta_item) override final{};
virtual void visit (BorrowExpr &expr) override final{};
virtual void visit (DereferenceExpr &expr) override final{};
virtual void visit (ErrorPropagationExpr &expr) override final{};
@@ -147,6 +147,8 @@ private:
virtual void visit (FieldAccessExpr &expr) override final{};
virtual void visit (ClosureExprInner &expr) override final{};
virtual void visit (BlockExpr &expr) override final{};
+ virtual void visit (AnonConst &expr) override final{};
+ virtual void visit (ConstBlock &expr) override final{};
virtual void visit (ClosureExprInnerTyped &expr) override final{};
virtual void visit (ContinueExpr &expr) override final{};
virtual void visit (BreakExpr &expr) override final{};
@@ -157,6 +159,7 @@ private:
virtual void visit (RangeFromToInclExpr &expr) override final{};
virtual void visit (RangeToInclExpr &expr) override final{};
virtual void visit (ReturnExpr &expr) override final{};
+ virtual void visit (TryExpr &expr) override final{};
virtual void visit (BoxExpr &expr) override final{};
virtual void visit (UnsafeBlockExpr &expr) override final{};
virtual void visit (LoopExpr &expr) override final{};
@@ -228,6 +231,8 @@ private:
virtual void visit (TuplePatternItemsRanged &tuple_items) override final{};
virtual void visit (TuplePattern &pattern) override final{};
virtual void visit (GroupedPattern &pattern) override final{};
+ virtual void visit (SlicePatternItemsNoRest &items) override final{};
+ virtual void visit (SlicePatternItemsHasRest &items) override final{};
virtual void visit (SlicePattern &pattern) override final{};
virtual void visit (AltPattern &pattern) override final{};
virtual void visit (EmptyStmt &stmt) override final{};
@@ -251,6 +256,7 @@ private:
virtual void visit (FunctionParam &param) override final{};
virtual void visit (VariadicParam &param) override final{};
virtual void visit (FormatArgs &param) override final{};
+ virtual void visit (OffsetOf &param) override final{};
};
} // namespace AST
diff --git a/gcc/rust/expand/rust-expand-format-args.cc b/gcc/rust/expand/rust-expand-format-args.cc
index af6182f..bda28dd 100644
--- a/gcc/rust/expand/rust-expand-format-args.cc
+++ b/gcc/rust/expand/rust-expand-format-args.cc
@@ -85,11 +85,13 @@ expand_format_args (AST::FormatArgs &fmt,
static_pieces.emplace_back (
builder.literal_string (node.string._0.to_string ()));
break;
- case ffi::Piece::Tag::NextArgument: {
+ case ffi::Piece::Tag::NextArgument:
+ {
auto next_argument = node.next_argument._0;
switch (node.next_argument._0.position.tag)
{
- case ffi::Position::Tag::ArgumentImplicitlyIs: {
+ case ffi::Position::Tag::ArgumentImplicitlyIs:
+ {
auto idx = next_argument.position.argument_implicitly_is._0;
auto trait = next_argument.format;
auto arg = arguments.at (idx);
diff --git a/gcc/rust/expand/rust-expand-visitor.cc b/gcc/rust/expand/rust-expand-visitor.cc
index 42df5e1..8f6e7fa 100644
--- a/gcc/rust/expand/rust-expand-visitor.cc
+++ b/gcc/rust/expand/rust-expand-visitor.cc
@@ -233,10 +233,7 @@ ExpandVisitor::expand_inner_items (
}
}
- std::function<std::unique_ptr<AST::Item> (AST::SingleASTNode)> extractor
- = [] (AST::SingleASTNode node) { return node.take_item (); };
-
- expand_macro_children (items, extractor);
+ expand_macro_children (items, &AST::SingleASTNode::take_item);
expander.pop_context ();
}
@@ -324,10 +321,7 @@ ExpandVisitor::expand_inner_stmts (AST::BlockExpr &expr)
if (!expr.has_tail_expr ())
expr.normalize_tail_expr ();
- std::function<std::unique_ptr<AST::Stmt> (AST::SingleASTNode)> extractor
- = [] (AST::SingleASTNode node) { return node.take_stmt (); };
-
- expand_macro_children (stmts, extractor);
+ expand_macro_children (stmts, &AST::SingleASTNode::take_stmt);
expander.pop_context ();
}
@@ -544,7 +538,7 @@ ExpandVisitor::visit (AST::MetaItemLitExpr &)
{}
void
-ExpandVisitor::visit (AST::MetaItemPathLit &)
+ExpandVisitor::visit (AST::MetaItemPathExpr &)
{}
void
@@ -641,7 +635,7 @@ ExpandVisitor::visit (AST::ClosureExprInnerTyped &expr)
maybe_expand_type (expr.get_return_type_ptr ());
- visit (expr.get_definition_block ());
+ visit (expr.get_definition_expr ());
}
void
@@ -866,12 +860,9 @@ ExpandVisitor::visit (AST::Trait &trait)
expander.push_context (MacroExpander::ContextType::TRAIT);
- std::function<std::unique_ptr<AST::AssociatedItem> (AST::SingleASTNode)>
- extractor
- = [] (AST::SingleASTNode node) { return node.take_assoc_item (); };
-
expand_macro_children (MacroExpander::ContextType::TRAIT,
- trait.get_trait_items (), extractor);
+ trait.get_trait_items (),
+ &AST::SingleASTNode::take_assoc_item);
expander.pop_context ();
}
@@ -894,12 +885,9 @@ ExpandVisitor::visit (AST::InherentImpl &impl)
if (impl.has_where_clause ())
expand_where_clause (impl.get_where_clause ());
- std::function<std::unique_ptr<AST::AssociatedItem> (AST::SingleASTNode)>
- extractor
- = [] (AST::SingleASTNode node) { return node.take_assoc_item (); };
-
expand_macro_children (MacroExpander::ContextType::IMPL,
- impl.get_impl_items (), extractor);
+ impl.get_impl_items (),
+ &AST::SingleASTNode::take_assoc_item);
}
void
@@ -922,12 +910,9 @@ ExpandVisitor::visit (AST::TraitImpl &impl)
if (impl.has_where_clause ())
expand_where_clause (impl.get_where_clause ());
- std::function<std::unique_ptr<AST::AssociatedItem> (AST::SingleASTNode)>
- extractor
- = [] (AST::SingleASTNode node) { return node.take_assoc_item (); };
-
expand_macro_children (MacroExpander::ContextType::TRAIT_IMPL,
- impl.get_impl_items (), extractor);
+ impl.get_impl_items (),
+ &AST::SingleASTNode::take_assoc_item);
}
void
@@ -944,12 +929,10 @@ void
ExpandVisitor::visit (AST::ExternBlock &block)
{
visit_inner_attrs (block);
- std::function<std::unique_ptr<AST::ExternalItem> (AST::SingleASTNode)>
- extractor
- = [] (AST::SingleASTNode node) { return node.take_external_item (); };
expand_macro_children (MacroExpander::ContextType::EXTERN,
- block.get_extern_items (), extractor);
+ block.get_extern_items (),
+ &AST::SingleASTNode::take_external_item);
}
void
diff --git a/gcc/rust/expand/rust-expand-visitor.h b/gcc/rust/expand/rust-expand-visitor.h
index ad237c0..845e10c 100644
--- a/gcc/rust/expand/rust-expand-visitor.h
+++ b/gcc/rust/expand/rust-expand-visitor.h
@@ -28,14 +28,12 @@ namespace Rust {
/**
* Whether or not an attribute is a derive attribute
*/
-bool
-is_derive (AST::Attribute &attr);
+bool is_derive (AST::Attribute &attr);
/**
* Whether or not an attribute is builtin
*/
-bool
-is_builtin (AST::Attribute &attr);
+bool is_builtin (AST::Attribute &attr);
class ExpandVisitor : public AST::DefaultASTVisitor
{
@@ -107,7 +105,7 @@ public:
*/
template <typename T, typename U>
void expand_macro_children (MacroExpander::ContextType ctx, T &values,
- std::function<U (AST::SingleASTNode)> extractor)
+ U (AST::SingleASTNode::*extractor) (void))
{
expander.push_context (ctx);
@@ -123,7 +121,7 @@ public:
*/
template <typename T, typename U>
void expand_macro_children (T &values,
- std::function<U (AST::SingleASTNode)> extractor)
+ U (AST::SingleASTNode::*extractor) (void))
{
for (auto it = values.begin (); it != values.end ();)
{
@@ -140,7 +138,7 @@ public:
it = values.erase (it);
for (auto &node : final_fragment.get_nodes ())
{
- U new_node = extractor (node);
+ U new_node = (node.*extractor) ();
if (new_node != nullptr)
{
it = values.insert (it, std::move (new_node));
@@ -211,7 +209,7 @@ public:
void visit (AST::AttrInputLiteral &) override;
void visit (AST::AttrInputMacro &) override;
void visit (AST::MetaItemLitExpr &) override;
- void visit (AST::MetaItemPathLit &) override;
+ void visit (AST::MetaItemPathExpr &) override;
void visit (AST::ErrorPropagationExpr &expr) override;
void visit (AST::ArithmeticOrLogicalExpr &expr) override;
void visit (AST::ComparisonExpr &expr) override;
diff --git a/gcc/rust/expand/rust-macro-builtins-asm.cc b/gcc/rust/expand/rust-macro-builtins-asm.cc
index e255729..61222db 100644
--- a/gcc/rust/expand/rust-macro-builtins-asm.cc
+++ b/gcc/rust/expand/rust-macro-builtins-asm.cc
@@ -25,18 +25,6 @@
#include "rust-parse.h"
namespace Rust {
-std::map<AST::InlineAsmOption, std::string> InlineAsmOptionMap{
- {AST::InlineAsmOption::PURE, "pure"},
- {AST::InlineAsmOption::NOMEM, "nomem"},
- {AST::InlineAsmOption::READONLY, "readonly"},
- {AST::InlineAsmOption::PRESERVES_FLAGS, "preserves_flags"},
- {AST::InlineAsmOption::NORETURN, "noreturn"},
- {AST::InlineAsmOption::NOSTACK, "nostack"},
- {AST::InlineAsmOption::MAY_UNWIND, "may_unwind"},
- {AST::InlineAsmOption::ATT_SYNTAX, "att_syntax"},
- {AST::InlineAsmOption::RAW, "raw"},
-};
-
std::set<std::string> potentially_nonpromoted_keywords
= {"in", "out", "lateout", "inout", "inlateout", "const", "sym", "label"};
@@ -396,6 +384,7 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx)
{
auto &parser = inline_asm_ctx.parser;
auto token = parser.peek_current_token ();
+ location_t locus = token->get_locus ();
if (!inline_asm_ctx.is_global_asm () && check_identifier (parser, "inout"))
{
@@ -413,10 +402,8 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx)
// TODO: Is error propogation our top priority, the ? in rust's asm.rs is
// doing a lot of work.
- // TODO: Not sure how to use parse_expr
- if (!check_identifier (parser, ""))
- rust_unreachable ();
- // auto expr = parse_format_string (inline_asm_ctx);
+ std::unique_ptr<AST::Expr> in_expr = parser.parse_expr ();
+ rust_assert (in_expr != nullptr);
std::unique_ptr<AST::Expr> out_expr;
@@ -426,11 +413,19 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx)
{
// auto result = parse_format_string (inline_asm_ctx);
- if (!check_identifier (parser, ""))
- rust_unreachable ();
- // out_expr = parser.parse_expr();
+ out_expr = parser.parse_expr ();
+
+ AST::InlineAsmOperand::SplitInOut splitinout (
+ reg, false, std::move (in_expr), std::move (out_expr));
+
+ inline_asm_ctx.inline_asm.operands.emplace_back (splitinout,
+ locus);
+
+ return inline_asm_ctx;
}
+ rust_unreachable ();
+
// TODO: Rembmer to pass in clone_expr() instead of nullptr
// https://github.com/rust-lang/rust/blob/a3167859f2fd8ff2241295469876a2b687280bdc/compiler/rustc_builtin_macros/src/asm.rs#L135
// RUST VERSION: ast::InlineAsmOperand::SplitInOut { reg, in_expr:
@@ -444,6 +439,8 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx)
}
else
{
+ AST::InlineAsmOperand::InOut inout (reg, false, std::move (in_expr));
+ inline_asm_ctx.inline_asm.operands.emplace_back (inout, locus);
// https://github.com/rust-lang/rust/blob/a3167859f2fd8ff2241295469876a2b687280bdc/compiler/rustc_builtin_macros/src/asm.rs#L137
// RUST VERSION: ast::InlineAsmOperand::InOut { reg, expr, late: false
// }
@@ -500,7 +497,7 @@ parse_reg_operand_unexpected (InlineAsmContext inline_asm_ctx)
}
void
-check_and_set (InlineAsmContext &inline_asm_ctx, AST::InlineAsmOption option)
+check_and_set (InlineAsmContext &inline_asm_ctx, AST::InlineAsm::Option option)
{
auto &parser = inline_asm_ctx.parser;
auto &inline_asm = inline_asm_ctx.inline_asm;
@@ -509,7 +506,7 @@ check_and_set (InlineAsmContext &inline_asm_ctx, AST::InlineAsmOption option)
// TODO: report an error of duplication
rust_error_at (parser.peek_current_token ()->get_locus (),
"the %qs option was already provided",
- InlineAsmOptionMap[option].c_str ());
+ AST::InlineAsm::option_to_string (option).c_str ());
return;
}
else
@@ -536,39 +533,40 @@ parse_options (InlineAsmContext &inline_asm_ctx)
{
if (!is_global_asm && check_identifier (parser, "pure"))
{
- check_and_set (inline_asm_ctx, AST::InlineAsmOption::PURE);
+ check_and_set (inline_asm_ctx, AST::InlineAsm::Option::PURE);
}
else if (!is_global_asm && check_identifier (parser, "nomem"))
{
- check_and_set (inline_asm_ctx, AST::InlineAsmOption::NOMEM);
+ check_and_set (inline_asm_ctx, AST::InlineAsm::Option::NOMEM);
}
else if (!is_global_asm && check_identifier (parser, "readonly"))
{
- check_and_set (inline_asm_ctx, AST::InlineAsmOption::READONLY);
+ check_and_set (inline_asm_ctx, AST::InlineAsm::Option::READONLY);
}
else if (!is_global_asm && check_identifier (parser, "preserves_flags"))
{
- check_and_set (inline_asm_ctx, AST::InlineAsmOption::PRESERVES_FLAGS);
+ check_and_set (inline_asm_ctx,
+ AST::InlineAsm::Option::PRESERVES_FLAGS);
}
else if (!is_global_asm && check_identifier (parser, "noreturn"))
{
- check_and_set (inline_asm_ctx, AST::InlineAsmOption::NORETURN);
+ check_and_set (inline_asm_ctx, AST::InlineAsm::Option::NORETURN);
}
else if (!is_global_asm && check_identifier (parser, "nostack"))
{
- check_and_set (inline_asm_ctx, AST::InlineAsmOption::NOSTACK);
+ check_and_set (inline_asm_ctx, AST::InlineAsm::Option::NOSTACK);
}
else if (!is_global_asm && check_identifier (parser, "may_unwind"))
{
- check_and_set (inline_asm_ctx, AST::InlineAsmOption::MAY_UNWIND);
+ check_and_set (inline_asm_ctx, AST::InlineAsm::Option::MAY_UNWIND);
}
else if (check_identifier (parser, "att_syntax"))
{
- check_and_set (inline_asm_ctx, AST::InlineAsmOption::ATT_SYNTAX);
+ check_and_set (inline_asm_ctx, AST::InlineAsm::Option::ATT_SYNTAX);
}
else if (check_identifier (parser, "raw"))
{
- check_and_set (inline_asm_ctx, AST::InlineAsmOption::RAW);
+ check_and_set (inline_asm_ctx, AST::InlineAsm::Option::RAW);
}
else
{
@@ -807,7 +805,8 @@ expand_inline_asm_strings (InlineAsmContext inline_asm_ctx)
auto next_argument = piece.next_argument._0;
switch (piece.next_argument._0.position.tag)
{
- case Fmt::ffi::Position::Tag::ArgumentImplicitlyIs: {
+ case Fmt::ffi::Position::Tag::ArgumentImplicitlyIs:
+ {
auto idx = next_argument.position.argument_implicitly_is._0;
/*auto trait = next_argument.format;*/
/*auto arg = arguments.at (idx);*/
@@ -829,6 +828,11 @@ expand_inline_asm_strings (InlineAsmContext inline_asm_ctx)
}
break;
case Fmt::ffi::Position::Tag::ArgumentIs:
+ {
+ auto idx = next_argument.position.argument_is._0;
+ transformed_template_str += "%" + std::to_string (idx);
+ break;
+ }
case Fmt::ffi::Position::Tag::ArgumentNamed:
rust_sorry_at (inline_asm.get_locus (),
"unhandled argument position specifier");
@@ -933,7 +937,9 @@ parse_format_strings (InlineAsmContext inline_asm_ctx)
{
if (!parser.skip_token (COMMA))
{
- break;
+ rust_error_at (parser.peek_current_token ()->get_locus (),
+ "expected token %qs", ";");
+ return tl::unexpected<InlineAsmParseError> (COMMITTED);
}
// Ok after the comma is good, we better be parsing correctly
// everything in here, which is formatted string in ABNF
diff --git a/gcc/rust/expand/rust-macro-builtins-asm.h b/gcc/rust/expand/rust-macro-builtins-asm.h
index bd64a7f..3196a5a 100644
--- a/gcc/rust/expand/rust-macro-builtins-asm.h
+++ b/gcc/rust/expand/rust-macro-builtins-asm.h
@@ -142,16 +142,16 @@ tl::expected<InlineAsmContext, InlineAsmParseError>
parse_reg_operand_unexpected (InlineAsmContext inline_asm_ctx);
WARN_UNUSED_RESULT
-tl::optional<AST::Fragment>
-parse_asm (location_t invoc_locus, AST::MacroInvocData &invoc,
- AST::InvocKind semicolon, AST::AsmKind is_global_asm);
+tl::optional<AST::Fragment> parse_asm (location_t invoc_locus,
+ AST::MacroInvocData &invoc,
+ AST::InvocKind semicolon,
+ AST::AsmKind is_global_asm);
WARN_UNUSED_RESULT
-bool
-check_identifier (Parser<MacroInvocLexer> &parser, std::string ident);
+bool check_identifier (Parser<MacroInvocLexer> &parser, std::string ident);
-void
-check_and_set (InlineAsmContext &inline_asm_ctx, AST::InlineAsmOption option);
+void check_and_set (InlineAsmContext &inline_asm_ctx,
+ AST::InlineAsm::Option option);
// From rustc
WARN_UNUSED_RESULT
@@ -168,9 +168,9 @@ tl::optional<std::string>
parse_format_string (InlineAsmContext &inline_asm_ctx);
WARN_UNUSED_RESULT
-tl::optional<std::string>
-parse_label (Parser<MacroInvocLexer> &parser, TokenId last_token_id,
- InlineAsmContext &inline_asm_ctx);
+tl::optional<std::string> parse_label (Parser<MacroInvocLexer> &parser,
+ TokenId last_token_id,
+ InlineAsmContext &inline_asm_ctx);
// LLVM ASM bits
@@ -188,17 +188,13 @@ public:
{}
};
-void
-parse_llvm_outputs (LlvmAsmContext &ctx);
+void parse_llvm_outputs (LlvmAsmContext &ctx);
-void
-parse_llvm_inputs (LlvmAsmContext &ctx);
+void parse_llvm_inputs (LlvmAsmContext &ctx);
-void
-parse_llvm_clobbers (LlvmAsmContext &ctx);
+void parse_llvm_clobbers (LlvmAsmContext &ctx);
-void
-parse_llvm_options (LlvmAsmContext &ctx);
+void parse_llvm_options (LlvmAsmContext &ctx);
WARN_UNUSED_RESULT tl::optional<AST::Fragment>
parse_llvm_asm (location_t invoc_locus, AST::MacroInvocData &invoc,
diff --git a/gcc/rust/expand/rust-macro-builtins-format-args.cc b/gcc/rust/expand/rust-macro-builtins-format-args.cc
index 3e1249d..b20c849 100644
--- a/gcc/rust/expand/rust-macro-builtins-format-args.cc
+++ b/gcc/rust/expand/rust-macro-builtins-format-args.cc
@@ -52,8 +52,15 @@ format_args_parse_arguments (AST::MacroInvocData &invoc)
// TODO: Handle the case where we're not parsing a string literal (macro
// invocation for e.g.)
- if (parser.peek_current_token ()->get_id () == STRING_LITERAL)
- format_expr = parser.parse_literal_expr ();
+ switch (parser.peek_current_token ()->get_id ())
+ {
+ case STRING_LITERAL:
+ case RAW_STRING_LITERAL:
+ format_expr = parser.parse_literal_expr ();
+ default:
+ // do nothing
+ ;
+ }
rust_assert (format_expr);
diff --git a/gcc/rust/expand/rust-macro-builtins-helpers.cc b/gcc/rust/expand/rust-macro-builtins-helpers.cc
index 864379a..ee01f65 100644
--- a/gcc/rust/expand/rust-macro-builtins-helpers.cc
+++ b/gcc/rust/expand/rust-macro-builtins-helpers.cc
@@ -68,6 +68,7 @@ make_eager_builtin_invocation (
{
auto path_str = make_macro_path_str (kind);
+ auto token_stream = arguments.to_token_stream ();
std::unique_ptr<AST::Expr> node = AST::MacroInvocation::Builtin (
kind,
AST::MacroInvocData (AST::SimplePath (
@@ -76,7 +77,7 @@ make_eager_builtin_invocation (
{}, locus, std::move (pending_invocations));
return AST::Fragment ({AST::SingleASTNode (std::move (node))},
- arguments.to_token_stream ());
+ std::move (token_stream));
}
/* Match the end token of a macro given the start delimiter of the macro */
@@ -110,9 +111,9 @@ std::unique_ptr<AST::LiteralExpr>
try_extract_string_literal_from_fragment (const location_t &parent_locus,
std::unique_ptr<AST::Expr> &node)
{
- auto maybe_lit = static_cast<AST::LiteralExpr *> (node.get ());
if (!node || !node->is_literal ()
- || maybe_lit->get_lit_type () != AST::Literal::STRING)
+ || static_cast<AST::LiteralExpr &> (*node).get_lit_type ()
+ != AST::Literal::STRING)
{
rust_error_at (parent_locus, "argument must be a string literal");
if (node)
diff --git a/gcc/rust/expand/rust-macro-builtins-helpers.h b/gcc/rust/expand/rust-macro-builtins-helpers.h
index 429537e..32cf58f 100644
--- a/gcc/rust/expand/rust-macro-builtins-helpers.h
+++ b/gcc/rust/expand/rust-macro-builtins-helpers.h
@@ -33,29 +33,23 @@
#include "rust-token.h"
namespace Rust {
-std::string
-make_macro_path_str (BuiltinMacro kind);
+std::string make_macro_path_str (BuiltinMacro kind);
-std::vector<std::unique_ptr<AST::MacroInvocation>>
-check_for_eager_invocations (
+std::vector<std::unique_ptr<AST::MacroInvocation>> check_for_eager_invocations (
std::vector<std::unique_ptr<AST::Expr>> &expressions);
// Shorthand function for creating unique_ptr tokens
-std::unique_ptr<AST::Token>
-make_token (const TokenPtr tok);
+std::unique_ptr<AST::Token> make_token (const TokenPtr tok);
-std::unique_ptr<AST::Expr>
-make_string (location_t locus, std::string value);
+std::unique_ptr<AST::Expr> make_string (location_t locus, std::string value);
// TODO: Is this correct?
-AST::Fragment
-make_eager_builtin_invocation (
+AST::Fragment make_eager_builtin_invocation (
BuiltinMacro kind, location_t locus, AST::DelimTokenTree arguments,
std::vector<std::unique_ptr<AST::MacroInvocation>> &&pending_invocations);
// Match the end token of a macro given the start delimiter of the macro
-TokenId
-macro_end_token (AST::DelimTokenTree &invoc_token_tree,
- Parser<MacroInvocLexer> &parser);
+TokenId macro_end_token (AST::DelimTokenTree &invoc_token_tree,
+ Parser<MacroInvocLexer> &parser);
// Expand and then extract a string literal from the macro
std::unique_ptr<AST::LiteralExpr>
try_extract_string_literal_from_fragment (const location_t &parent_locus,
@@ -70,21 +64,18 @@ try_expand_many_expr (Parser<MacroInvocLexer> &parser,
// and return the LiteralExpr for it. Allow for an optional trailing comma,
// but otherwise enforce that these are the only tokens.
-std::unique_ptr<AST::Expr>
-parse_single_string_literal (BuiltinMacro kind,
- AST::DelimTokenTree &invoc_token_tree,
- location_t invoc_locus, MacroExpander *expander,
- bool is_semicoloned = false);
+std::unique_ptr<AST::Expr> parse_single_string_literal (
+ BuiltinMacro kind, AST::DelimTokenTree &invoc_token_tree,
+ location_t invoc_locus, MacroExpander *expander, bool is_semicoloned = false);
// Treat PATH as a path relative to the source file currently being
// compiled, and return the absolute path for it.
-std::string
-source_relative_path (std::string path, location_t locus);
+std::string source_relative_path (std::string path, location_t locus);
// Read the full contents of the file FILENAME and return them in a vector.
// FIXME: platform specific.
-tl::optional<std::vector<uint8_t>>
-load_file_bytes (location_t invoc_locus, const char *filename);
+tl::optional<std::vector<uint8_t>> load_file_bytes (location_t invoc_locus,
+ const char *filename);
} // namespace Rust
#endif // GCCRS_RUST_MACRO_BUILTINS_HELPERS_H
diff --git a/gcc/rust/expand/rust-macro-builtins-offset-of.cc b/gcc/rust/expand/rust-macro-builtins-offset-of.cc
new file mode 100644
index 0000000..53efe74
--- /dev/null
+++ b/gcc/rust/expand/rust-macro-builtins-offset-of.cc
@@ -0,0 +1,78 @@
+// Copyright (C) 2020-2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "optional.h"
+#include "rust-ast-fragment.h"
+#include "rust-ast.h"
+#include "rust-builtin-ast-nodes.h"
+#include "rust-diagnostics.h"
+#include "rust-macro-builtins-helpers.h"
+#include "rust-macro-builtins.h"
+#include "rust-macro-invoc-lexer.h"
+#include "rust-parse.h"
+
+namespace Rust {
+
+tl::optional<AST::Fragment>
+MacroBuiltin::offset_of_handler (location_t invoc_locus,
+ AST::MacroInvocData &invoc,
+ AST::InvocKind semicolon)
+{
+ MacroInvocLexer lex (invoc.get_delim_tok_tree ().to_token_stream ());
+ Parser<MacroInvocLexer> parser (lex);
+
+ auto last_token = macro_end_token (invoc.get_delim_tok_tree (), parser);
+
+ auto type = parser.parse_type ();
+
+ // if we don't see a type, there might be an eager macro expansion missing
+ // FIXME: handle that
+ if (!type)
+ {
+ rust_error_at (invoc_locus, "could not parse type argument for %qs",
+ "offset_of");
+
+ // we skip so we can still parse the field arg and check if it is correct
+ while (parser.peek_current_token ()->get_id () != COMMA
+ && parser.peek_current_token ()->get_id () != last_token)
+ parser.skip_token ();
+ }
+
+ parser.skip_token (COMMA);
+
+ auto field_tok = parser.parse_identifier_or_keyword_token ();
+ auto invalid_field = !field_tok || !field_tok->has_str ();
+
+ if (invalid_field)
+ rust_error_at (invoc_locus, "could not parse field argument for %qs",
+ "offset_of");
+
+ if (!type || invalid_field)
+ return tl::nullopt;
+
+ auto field = Identifier (field_tok->get_str ());
+
+ // FIXME: Do we need to do anything to handle the optional comma at the end?
+ parser.maybe_skip_token (COMMA);
+
+ return AST::Fragment ({AST::SingleASTNode (std::make_unique<AST::OffsetOf> (
+ std::move (type), field, invoc_locus))},
+ invoc.get_delim_tok_tree ().to_token_stream ());
+}
+
+} // namespace Rust
diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc
index b58ed71..a7ae220 100644
--- a/gcc/rust/expand/rust-macro-builtins.cc
+++ b/gcc/rust/expand/rust-macro-builtins.cc
@@ -162,6 +162,9 @@ std::unordered_map<std::string, AST::MacroTranscriberFunc>
{"Ord", MacroBuiltin::proc_macro_builtin},
{"PartialOrd", MacroBuiltin::proc_macro_builtin},
{"Hash", MacroBuiltin::proc_macro_builtin},
+ /* offset_of is not declared in Rust 1.49 but still needed for
+ Rust-for-Linux, so we still create a transcriber and warn the user */
+ {"offset_of", MacroBuiltin::offset_of_handler},
};
tl::optional<BuiltinMacro>
diff --git a/gcc/rust/expand/rust-macro-builtins.h b/gcc/rust/expand/rust-macro-builtins.h
index 541e956..b6c2907 100644
--- a/gcc/rust/expand/rust-macro-builtins.h
+++ b/gcc/rust/expand/rust-macro-builtins.h
@@ -19,6 +19,7 @@
#ifndef RUST_MACRO_BUILTINS_H
#define RUST_MACRO_BUILTINS_H
+#include "optional.h"
#include "rust-ast.h"
#include "rust-builtin-ast-nodes.h"
#include "rust-ast-fragment.h"
@@ -188,6 +189,9 @@ public:
format_args_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
AST::InvocKind semicolon, AST::FormatArgs::Newline nl);
+ static tl::optional<AST::Fragment>
+ offset_of_handler (location_t, AST::MacroInvocData &, AST::InvocKind);
+
static tl::optional<AST::Fragment> sorry (location_t invoc_locus,
AST::MacroInvocData &invoc,
AST::InvocKind semicolon);
diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc
index 673b8fb..4c54cef 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -19,6 +19,7 @@
#include "rust-macro-expand.h"
#include "optional.h"
#include "rust-ast-fragment.h"
+#include "rust-macro-builtins.h"
#include "rust-macro-substitute-ctx.h"
#include "rust-ast-full.h"
#include "rust-ast-visitor.h"
@@ -287,6 +288,26 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc,
// lookup the rules
auto rules_def = mappings.lookup_macro_invocation (invoc);
+ // We special case the `offset_of!()` macro if the flag is here and manually
+ // resolve to the builtin transcriber we have specified
+ auto assume_builtin_offset_of
+ = flag_assume_builtin_offset_of
+ && (invoc.get_invoc_data ().get_path ().as_string () == "offset_of")
+ && !rules_def;
+
+ // TODO: This is *massive hack* which should be removed as we progress to
+ // Rust 1.71 when offset_of gets added to core
+ if (assume_builtin_offset_of)
+ {
+ fragment = MacroBuiltin::offset_of_handler (invoc.get_locus (),
+ invoc_data, semicolon)
+ .value_or (AST::Fragment::create_empty ());
+
+ set_expanded_fragment (std::move (fragment));
+
+ return;
+ }
+
// If there's no rule associated with the invocation, we can simply return
// early. The early name resolver will have already emitted an error.
if (!rules_def)
@@ -430,7 +451,8 @@ MacroExpander::match_fragment (Parser<MacroInvocLexer> &parser,
parser.parse_visibility ();
break;
- case AST::MacroFragSpec::STMT: {
+ case AST::MacroFragSpec::STMT:
+ {
auto restrictions = ParseRestrictions ();
restrictions.consume_semi = false;
parser.parse_stmt (restrictions);
@@ -480,19 +502,22 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
// this is used so we can check that we delimit the stream correctly.
switch (delimiter->get_id ())
{
- case LEFT_PAREN: {
+ case LEFT_PAREN:
+ {
if (!check_delim (AST::DelimType::PARENS))
return false;
}
break;
- case LEFT_SQUARE: {
+ case LEFT_SQUARE:
+ {
if (!check_delim (AST::DelimType::SQUARE))
return false;
}
break;
- case LEFT_CURLY: {
+ case LEFT_CURLY:
+ {
if (!check_delim (AST::DelimType::CURLY))
return false;
}
@@ -510,7 +535,8 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
switch (match->get_macro_match_type ())
{
- case AST::MacroMatch::MacroMatchType::Fragment: {
+ case AST::MacroMatch::MacroMatchType::Fragment:
+ {
AST::MacroMatchFragment *fragment
= static_cast<AST::MacroMatchFragment *> (match.get ());
if (!match_fragment (parser, *fragment))
@@ -524,14 +550,16 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
}
break;
- case AST::MacroMatch::MacroMatchType::Tok: {
+ case AST::MacroMatch::MacroMatchType::Tok:
+ {
AST::Token *tok = static_cast<AST::Token *> (match.get ());
if (!match_token (parser, *tok))
return false;
}
break;
- case AST::MacroMatch::MacroMatchType::Repetition: {
+ case AST::MacroMatch::MacroMatchType::Repetition:
+ {
AST::MacroMatchRepetition *rep
= static_cast<AST::MacroMatchRepetition *> (match.get ());
if (!match_repetition (parser, *rep))
@@ -539,7 +567,8 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
}
break;
- case AST::MacroMatch::MacroMatchType::Matcher: {
+ case AST::MacroMatch::MacroMatchType::Matcher:
+ {
AST::MacroMatcher *m
= static_cast<AST::MacroMatcher *> (match.get ());
expansion_depth++;
@@ -556,19 +585,22 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
switch (delimiter->get_id ())
{
- case LEFT_PAREN: {
+ case LEFT_PAREN:
+ {
if (!parser.skip_token (RIGHT_PAREN))
return false;
}
break;
- case LEFT_SQUARE: {
+ case LEFT_SQUARE:
+ {
if (!parser.skip_token (RIGHT_SQUARE))
return false;
}
break;
- case LEFT_CURLY: {
+ case LEFT_CURLY:
+ {
if (!parser.skip_token (RIGHT_CURLY))
return false;
}
@@ -617,7 +649,8 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser,
size_t offs_begin = source.get_offs ();
switch (match->get_macro_match_type ())
{
- case AST::MacroMatch::MacroMatchType::Fragment: {
+ case AST::MacroMatch::MacroMatchType::Fragment:
+ {
AST::MacroMatchFragment *fragment
= static_cast<AST::MacroMatchFragment *> (match.get ());
valid_current_match = match_fragment (parser, *fragment);
@@ -632,20 +665,23 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser,
}
break;
- case AST::MacroMatch::MacroMatchType::Tok: {
+ case AST::MacroMatch::MacroMatchType::Tok:
+ {
AST::Token *tok = static_cast<AST::Token *> (match.get ());
valid_current_match = match_token (parser, *tok);
}
break;
- case AST::MacroMatch::MacroMatchType::Repetition: {
+ case AST::MacroMatch::MacroMatchType::Repetition:
+ {
AST::MacroMatchRepetition *rep
= static_cast<AST::MacroMatchRepetition *> (match.get ());
valid_current_match = match_repetition (parser, *rep);
}
break;
- case AST::MacroMatch::MacroMatchType::Matcher: {
+ case AST::MacroMatch::MacroMatchType::Matcher:
+ {
AST::MacroMatcher *m
= static_cast<AST::MacroMatcher *> (match.get ());
valid_current_match = match_matcher (parser, *m, true);
diff --git a/gcc/rust/expand/rust-macro-substitute-ctx.cc b/gcc/rust/expand/rust-macro-substitute-ctx.cc
index 02e4e3b..ac36ed8 100644
--- a/gcc/rust/expand/rust-macro-substitute-ctx.cc
+++ b/gcc/rust/expand/rust-macro-substitute-ctx.cc
@@ -273,7 +273,8 @@ SubstituteCtx::substitute_token (size_t token_idx)
// don't substitute, dollar sign is alone/metavar is unknown
return {std::vector<std::unique_ptr<AST::Token>> (), 0};
- case LEFT_PAREN: {
+ case LEFT_PAREN:
+ {
// We need to parse up until the closing delimiter and expand this
// fragment->n times.
rust_debug ("expanding repetition");
diff --git a/gcc/rust/expand/rust-proc-macro.h b/gcc/rust/expand/rust-proc-macro.h
index 6ffaaf6..058c93a 100644
--- a/gcc/rust/expand/rust-proc-macro.h
+++ b/gcc/rust/expand/rust-proc-macro.h
@@ -82,11 +82,9 @@ public:
*
* @param The path to the shared object file to load.
*/
-const std::vector<ProcMacro::Procmacro>
-load_macros (std::string path);
+const std::vector<ProcMacro::Procmacro> load_macros (std::string path);
-std::string
-generate_proc_macro_decls_symbol (std::uint32_t stable_crate_id);
+std::string generate_proc_macro_decls_symbol (std::uint32_t stable_crate_id);
} // namespace Rust
diff --git a/gcc/rust/expand/rust-token-tree-desugar.cc b/gcc/rust/expand/rust-token-tree-desugar.cc
index 3b47180..aa20d50 100644
--- a/gcc/rust/expand/rust-token-tree-desugar.cc
+++ b/gcc/rust/expand/rust-token-tree-desugar.cc
@@ -68,5 +68,5 @@ TokenTreeDesugar::visit (Token &tts)
}
}
-}; // namespace AST
-}; // namespace Rust
+} // namespace AST
+} // namespace Rust
diff --git a/gcc/rust/expand/rust-token-tree-desugar.h b/gcc/rust/expand/rust-token-tree-desugar.h
index ccba53b..da9d732 100644
--- a/gcc/rust/expand/rust-token-tree-desugar.h
+++ b/gcc/rust/expand/rust-token-tree-desugar.h
@@ -49,7 +49,7 @@ private:
virtual void visit (Token &tts) override;
};
-}; // namespace AST
-}; // namespace Rust
+} // namespace AST
+} // namespace Rust
#endif //! RUST_TOKEN_TREE_DESUGAR_H