rust/rust-macro-expand.o \
rust/rust-cfg-strip.o \
rust/rust-expand-visitor.o \
+ rust/rust-ast-builder.o \
+ rust/rust-derive.o \
+ rust/rust-derive-clone.o \
rust/rust-macro-invoc-lexer.o \
rust/rust-macro-substitute-ctx.o \
rust/rust-macro-builtins.o \
--- /dev/null
+// Copyright (C) 2020-2023 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-clone.h"
+
+namespace Rust {
+namespace AST {
+
+std::unique_ptr<Expr>
+DeriveClone::clone_call (std::unique_ptr<Expr> &&to_clone)
+{
+ // $crate::core::clone::Clone::clone for the fully qualified path - we don't
+ // link with `core` yet so that might be an issue. Use `Clone::clone` for now?
+ // TODO: Factor this function inside the DeriveAccumulator
+ auto path = std::unique_ptr<Expr> (
+ new PathInExpression (builder.path_in_expression ({"Clone", "clone"})));
+
+ auto args = std::vector<std::unique_ptr<Expr>> ();
+ args.emplace_back (std::move (to_clone));
+
+ return builder.call (std::move (path), std::move (args));
+}
+
+/**
+ * Create the actual "clone" function of the implementation, so
+ *
+ * fn clone(&self) -> Self { <clone_expr> }
+ *
+ */
+std::unique_ptr<TraitImplItem>
+DeriveClone::clone_fn (std::unique_ptr<Expr> &&clone_expr)
+{
+ auto block = std::unique_ptr<BlockExpr> (
+ new BlockExpr ({}, std::move (clone_expr), {}, {}, loc, loc));
+ auto big_self_type = builder.single_type_path ("Self");
+
+ return std::unique_ptr<TraitImplItem> (
+ new Method ("clone", builder.fn_qualifiers (), /* generics */ {},
+ SelfParam (Lifetime::error (), /* is_mut */ false, loc),
+ /* function params */ {}, std::move (big_self_type),
+ WhereClause::create_empty (), std::move (block),
+ Visibility::create_private (), {}, loc));
+}
+
+/**
+ * Create the Clone trait implementation for a type
+ *
+ * impl Clone for <type> {
+ * <clone_fn>
+ * }
+ *
+ */
+std::unique_ptr<Item>
+DeriveClone::clone_impl (std::unique_ptr<TraitImplItem> &&clone_fn,
+ std::string name)
+{
+ // should that be `$crate::core::clone::Clone` instead?
+ auto segments = std::vector<std::unique_ptr<TypePathSegment>> ();
+ segments.emplace_back (builder.type_path_segment ("Clone"));
+ auto clone = TypePath (std::move (segments), loc);
+
+ auto trait_items = std::vector<std::unique_ptr<TraitImplItem>> ();
+ trait_items.emplace_back (std::move (clone_fn));
+
+ return std::unique_ptr<Item> (
+ new TraitImpl (clone, /* unsafe */ false,
+ /* exclam */ false, std::move (trait_items),
+ /* generics */ {}, builder.single_type_path (name),
+ WhereClause::create_empty (), Visibility::create_private (),
+ {}, {}, loc));
+}
+
+// TODO: Create new `make_qualified_call` helper function
+
+DeriveClone::DeriveClone (Location loc)
+ : loc (loc), expanded (nullptr), builder (AstBuilder (loc))
+{}
+
+std::unique_ptr<AST::Item>
+DeriveClone::go (Item &item)
+{
+ item.accept_vis (*this);
+
+ rust_assert (expanded);
+
+ return std::move (expanded);
+}
+
+void
+DeriveClone::visit_tuple (TupleStruct &item)
+{
+ auto cloned_fields = std::vector<std::unique_ptr<Expr>> ();
+
+ for (size_t idx = 0; idx < item.get_fields ().size (); idx++)
+ cloned_fields.emplace_back (
+ clone_call (builder.ref (builder.tuple_idx ("self", idx))));
+
+ auto path = std::unique_ptr<Expr> (new PathInExpression (
+ builder.path_in_expression ({item.get_identifier ()})));
+ auto constructor = builder.call (std::move (path), std::move (cloned_fields));
+
+ expanded
+ = clone_impl (clone_fn (std::move (constructor)), item.get_identifier ());
+}
+
+void
+DeriveClone::visit_struct (StructStruct &item)
+{
+ if (item.is_unit_struct ())
+ {
+ auto unit_ctor = builder.struct_expr_struct (item.get_struct_name ());
+ expanded = clone_impl (clone_fn (std::move (unit_ctor)),
+ item.get_struct_name ());
+ }
+ else
+ {
+ rust_sorry_at (item.get_locus (), "cannot derive %qs for these items yet",
+ "Clone");
+ }
+}
+
+void
+DeriveClone::visit_enum (Enum &item)
+{
+ rust_sorry_at (item.get_locus (), "cannot derive %qs for these items yet",
+ "Clone");
+}
+
+void
+DeriveClone::visit_union (Union &item)
+{
+ rust_sorry_at (item.get_locus (), "cannot derive %qs for these items yet",
+ "Clone");
+}
+
+} // namespace AST
+} // namespace Rust
--- /dev/null
+// Copyright (C) 2020-2023 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_CLONE_H
+#define RUST_DERIVE_CLONE_H
+
+#include "rust-derive.h"
+#include "rust-ast-builder.h"
+
+namespace Rust {
+namespace AST {
+
+class DeriveClone : DeriveVisitor
+{
+public:
+ DeriveClone (Location loc);
+
+ std::unique_ptr<AST::Item> go (Item &item);
+
+private:
+ Location loc;
+ std::unique_ptr<AST::Item> expanded;
+ AstBuilder builder;
+
+ /**
+ * Create a call to "clone". For now, this creates a call to
+ * `Clone::clone`, but should ultimately call into
+ * `::core::clone::Clone::clone`
+ *
+ * Clone::clone(<to_clone>)
+ */
+ std::unique_ptr<Expr> clone_call (std::unique_ptr<Expr> &&to_clone);
+
+ /**
+ * Create the actual "clone" function of the implementation, so
+ *
+ * fn clone(&self) -> Self { <clone_expr> }
+ *
+ */
+ std::unique_ptr<TraitImplItem> clone_fn (std::unique_ptr<Expr> &&clone_expr);
+
+ /**
+ * Create the Clone trait implementation for a type
+ *
+ * impl Clone for <type> {
+ * <clone_fn>
+ * }
+ *
+ */
+ std::unique_ptr<Item> clone_impl (std::unique_ptr<TraitImplItem> &&clone_fn,
+ std::string name);
+
+ virtual void visit_struct (StructStruct &item);
+ virtual void visit_tuple (TupleStruct &item);
+ virtual void visit_enum (Enum &item);
+ virtual void visit_union (Union &item);
+};
+
+} // namespace AST
+} // namespace Rust
+
+#endif // ! RUST_DERIVE_CLONE_H
--- /dev/null
+// Copyright (C) 2020-2023 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.h"
+#include "rust-derive-clone.h"
+
+namespace Rust {
+namespace AST {
+
+std::unique_ptr<Item>
+DeriveVisitor::derive (Item &item, const Attribute &attr,
+ BuiltinMacro to_derive)
+{
+ switch (to_derive)
+ {
+ case BuiltinMacro::Clone:
+ return DeriveClone (attr.get_locus ()).go (item);
+ case BuiltinMacro::Copy:
+ case BuiltinMacro::Debug:
+ case BuiltinMacro::Default:
+ case BuiltinMacro::Eq:
+ case BuiltinMacro::PartialEq:
+ case BuiltinMacro::Ord:
+ case BuiltinMacro::PartialOrd:
+ case BuiltinMacro::Hash:
+ default:
+ rust_sorry_at (attr.get_locus (), "uninmplemented builtin derive macro");
+ return nullptr;
+ };
+}
+
+} // namespace AST
+} // namespace Rust
--- /dev/null
+// Copyright (C) 2020-2023 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 DERIVE_VISITOR_H
+#define DERIVE_VISITOR_H
+
+#include "rust-ast-full.h"
+#include "rust-ast-visitor.h"
+#include "rust-macro-builtins.h"
+
+namespace Rust {
+namespace AST {
+
+/**
+ * The goal of this class is to accumulate and create the required items from a
+ * builtin `#[derive]` macro applied on a struct, enum or union.
+ */
+class DeriveVisitor : public AST::ASTVisitor
+{
+public:
+ static std::unique_ptr<Item> derive (Item &item, const Attribute &derive,
+ BuiltinMacro to_derive);
+
+private:
+ // the 4 "allowed" visitors, which a derive-visitor can specify and override
+ virtual void visit_struct (StructStruct &struct_item) = 0;
+ virtual void visit_tuple (TupleStruct &tuple_item) = 0;
+ virtual void visit_enum (Enum &enum_item) = 0;
+ virtual void visit_union (Union &enum_item) = 0;
+
+ // all visitors are final, so no deriving class can implement `derive` for
+ // anything other than structs, tuples, enums and unions
+
+ virtual void visit (StructStruct &struct_item) override final
+ {
+ visit_struct (struct_item);
+ }
+
+ virtual void visit (TupleStruct &tuple_struct) override final
+ {
+ visit_tuple (tuple_struct);
+ }
+
+ virtual void visit (Enum &enum_item) override final
+ {
+ visit_enum (enum_item);
+ }
+
+ virtual void visit (Union &union_item) override final
+ {
+ visit_union (union_item);
+ }
+
+ virtual void visit (Token &tok) override final{};
+ virtual void visit (DelimTokenTree &delim_tok_tree) override final{};
+ virtual void visit (AttrInputMetaItemContainer &input) override final{};
+ virtual void visit (AttrInputMacro &expr) override final{};
+ virtual void visit (IdentifierExpr &ident_expr) override final{};
+ virtual void visit (Lifetime &lifetime) override final{};
+ virtual void visit (LifetimeParam &lifetime_param) override final{};
+ virtual void visit (ConstGenericParam &const_param) override final{};
+ virtual void visit (PathInExpression &path) override final{};
+ virtual void visit (TypePathSegment &segment) override final{};
+ virtual void visit (TypePathSegmentGeneric &segment) override final{};
+ virtual void visit (TypePathSegmentFunction &segment) override final{};
+ virtual void visit (TypePath &path) override final{};
+ virtual void visit (QualifiedPathInExpression &path) override final{};
+ virtual void visit (QualifiedPathInType &path) override final{};
+ 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 (BorrowExpr &expr) override final{};
+ virtual void visit (DereferenceExpr &expr) override final{};
+ virtual void visit (ErrorPropagationExpr &expr) override final{};
+ virtual void visit (NegationExpr &expr) override final{};
+ virtual void visit (ArithmeticOrLogicalExpr &expr) override final{};
+ virtual void visit (ComparisonExpr &expr) override final{};
+ virtual void visit (LazyBooleanExpr &expr) override final{};
+ virtual void visit (TypeCastExpr &expr) override final{};
+ virtual void visit (AssignmentExpr &expr) override final{};
+ virtual void visit (CompoundAssignmentExpr &expr) override final{};
+ virtual void visit (GroupedExpr &expr) override final{};
+ virtual void visit (ArrayElemsValues &elems) override final{};
+ virtual void visit (ArrayElemsCopied &elems) override final{};
+ virtual void visit (ArrayExpr &expr) override final{};
+ virtual void visit (ArrayIndexExpr &expr) override final{};
+ virtual void visit (TupleExpr &expr) override final{};
+ virtual void visit (TupleIndexExpr &expr) override final{};
+ virtual void visit (StructExprStruct &expr) override final{};
+ virtual void visit (StructExprFieldIdentifier &field) override final{};
+ virtual void visit (StructExprFieldIdentifierValue &field) override final{};
+ virtual void visit (StructExprFieldIndexValue &field) override final{};
+ virtual void visit (StructExprStructFields &expr) override final{};
+ virtual void visit (StructExprStructBase &expr) override final{};
+ virtual void visit (CallExpr &expr) override final{};
+ virtual void visit (MethodCallExpr &expr) override final{};
+ virtual void visit (FieldAccessExpr &expr) override final{};
+ virtual void visit (ClosureExprInner &expr) override final{};
+ virtual void visit (BlockExpr &expr) override final{};
+ virtual void visit (ClosureExprInnerTyped &expr) override final{};
+ virtual void visit (ContinueExpr &expr) override final{};
+ virtual void visit (BreakExpr &expr) override final{};
+ virtual void visit (RangeFromToExpr &expr) override final{};
+ virtual void visit (RangeFromExpr &expr) override final{};
+ virtual void visit (RangeToExpr &expr) override final{};
+ virtual void visit (RangeFullExpr &expr) override final{};
+ virtual void visit (RangeFromToInclExpr &expr) override final{};
+ virtual void visit (RangeToInclExpr &expr) override final{};
+ virtual void visit (ReturnExpr &expr) override final{};
+ virtual void visit (UnsafeBlockExpr &expr) override final{};
+ virtual void visit (LoopExpr &expr) override final{};
+ virtual void visit (WhileLoopExpr &expr) override final{};
+ virtual void visit (WhileLetLoopExpr &expr) override final{};
+ virtual void visit (ForLoopExpr &expr) override final{};
+ virtual void visit (IfExpr &expr) override final{};
+ virtual void visit (IfExprConseqElse &expr) override final{};
+ virtual void visit (IfLetExpr &expr) override final{};
+ virtual void visit (IfLetExprConseqElse &expr) override final{};
+ virtual void visit (MatchExpr &expr) override final{};
+ virtual void visit (AwaitExpr &expr) override final{};
+ virtual void visit (AsyncBlockExpr &expr) override final{};
+ virtual void visit (TypeParam ¶m) override final{};
+ virtual void visit (LifetimeWhereClauseItem &item) override final{};
+ virtual void visit (TypeBoundWhereClauseItem &item) override final{};
+ virtual void visit (Method &method) override final{};
+ virtual void visit (Module &module) override final{};
+ virtual void visit (ExternCrate &crate) override final{};
+ virtual void visit (UseTreeGlob &use_tree) override final{};
+ virtual void visit (UseTreeList &use_tree) override final{};
+ virtual void visit (UseTreeRebind &use_tree) override final{};
+ virtual void visit (UseDeclaration &use_decl) override final{};
+ virtual void visit (Function &function) override final{};
+ virtual void visit (TypeAlias &type_alias) override final{};
+ virtual void visit (EnumItem &item) override final{};
+ virtual void visit (EnumItemTuple &item) override final{};
+ virtual void visit (EnumItemStruct &item) override final{};
+ virtual void visit (EnumItemDiscriminant &item) override final{};
+ virtual void visit (ConstantItem &const_item) override final{};
+ virtual void visit (StaticItem &static_item) override final{};
+ virtual void visit (TraitItemFunc &item) override final{};
+ virtual void visit (TraitItemMethod &item) override final{};
+ virtual void visit (TraitItemConst &item) override final{};
+ virtual void visit (TraitItemType &item) override final{};
+ virtual void visit (Trait &trait) override final{};
+ virtual void visit (InherentImpl &impl) override final{};
+ virtual void visit (TraitImpl &impl) override final{};
+ virtual void visit (ExternalTypeItem &type) override final{};
+ virtual void visit (ExternalStaticItem &item) override final{};
+ virtual void visit (ExternalFunctionItem &item) override final{};
+ virtual void visit (ExternBlock &block) override final{};
+ virtual void visit (MacroMatchFragment &match) override final{};
+ virtual void visit (MacroMatchRepetition &match) override final{};
+ virtual void visit (MacroMatcher &matcher) override final{};
+ virtual void visit (MacroRulesDefinition &rules_def) override final{};
+ virtual void visit (MacroInvocation ¯o_invoc) override final{};
+ virtual void visit (MetaItemPath &meta_item) override final{};
+ virtual void visit (MetaItemSeq &meta_item) override final{};
+ virtual void visit (MetaWord &meta_item) override final{};
+ virtual void visit (MetaNameValueStr &meta_item) override final{};
+ virtual void visit (MetaListPaths &meta_item) override final{};
+ virtual void visit (MetaListNameValueStr &meta_item) override final{};
+ virtual void visit (LiteralPattern &pattern) override final{};
+ virtual void visit (IdentifierPattern &pattern) override final{};
+ virtual void visit (WildcardPattern &pattern) override final{};
+ virtual void visit (RestPattern &pattern) override final{};
+ virtual void visit (RangePatternBoundLiteral &bound) override final{};
+ virtual void visit (RangePatternBoundPath &bound) override final{};
+ virtual void visit (RangePatternBoundQualPath &bound) override final{};
+ virtual void visit (RangePattern &pattern) override final{};
+ virtual void visit (ReferencePattern &pattern) override final{};
+ virtual void visit (StructPatternFieldTuplePat &field) override final{};
+ virtual void visit (StructPatternFieldIdentPat &field) override final{};
+ virtual void visit (StructPatternFieldIdent &field) override final{};
+ virtual void visit (StructPattern &pattern) override final{};
+ virtual void visit (TupleStructItemsNoRange &tuple_items) override final{};
+ virtual void visit (TupleStructItemsRange &tuple_items) override final{};
+ virtual void visit (TupleStructPattern &pattern) override final{};
+ virtual void visit (TuplePatternItemsMultiple &tuple_items) override final{};
+ 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 (SlicePattern &pattern) override final{};
+ virtual void visit (AltPattern &pattern) override final{};
+ virtual void visit (EmptyStmt &stmt) override final{};
+ virtual void visit (LetStmt &stmt) override final{};
+ virtual void visit (ExprStmt &stmt) override final{};
+ virtual void visit (TraitBound &bound) override final{};
+ virtual void visit (ImplTraitType &type) override final{};
+ virtual void visit (TraitObjectType &type) override final{};
+ virtual void visit (ParenthesisedType &type) override final{};
+ virtual void visit (ImplTraitTypeOneBound &type) override final{};
+ virtual void visit (TraitObjectTypeOneBound &type) override final{};
+ virtual void visit (TupleType &type) override final{};
+ virtual void visit (NeverType &type) override final{};
+ virtual void visit (RawPointerType &type) override final{};
+ virtual void visit (ReferenceType &type) override final{};
+ virtual void visit (ArrayType &type) override final{};
+ virtual void visit (SliceType &type) override final{};
+ virtual void visit (InferredType &type) override final{};
+ virtual void visit (BareFunctionType &type) override final{};
+};
+
+} // namespace AST
+} // namespace Rust
+
+#endif // DERIVE_VISITOR_H
#include "rust-expand-visitor.h"
#include "rust-attributes.h"
+#include "rust-ast.h"
+#include "rust-type.h"
+#include "rust-derive.h"
namespace Rust {
+bool
+is_derive (AST::Attribute &attr)
+{
+ auto path = attr.get_path ();
+ return attr.has_attr_input ()
+ && attr.get_attr_input ().get_attr_input_type ()
+ == AST::AttrInput::TOKEN_TREE
+ && path == "derive";
+}
+
+bool
+is_builtin (AST::Attribute &attr)
+{
+ auto &segments = attr.get_path ().get_segments ();
+ return !segments.empty ()
+ && !Analysis::BuiltinAttributeMappings::get ()
+ ->lookup_builtin (segments[0].get_segment_name ())
+ .is_error ();
+}
+
/* Expand all of the macro invocations currently contained in a crate */
void
ExpandVisitor::go (AST::Crate &crate)
+{
+ expand_inner_items (crate.items);
+}
+
+/**
+ * Returns a list of all the derive macros to apply, as well as the Attribute
+ * they are from.
+ *
+ * ```rust
+ * #[derive(Clone, Copy)] // attr1
+ * struct S;
+ *
+ * // returns [{Clone, &attr1}, {Copy, &attr1}]
+ *
+ * #[derive(Clone)] // attr1
+ * #[derive(Copy, PartialEq, Ord)] // attr2
+ * struct S;
+ *
+ * // returns [{Clone, &attr1}, {Copy, &attr2}, {PartialEq, &attr2}, {Ord,
+ * &attr2}]
+ * ```
+ *
+ * @param outer_attrs The list of attributes on the item to derive
+ */
+static std::vector<
+ std::pair<std::string, std::reference_wrapper<const AST::Attribute>>>
+get_traits_to_derive (std::vector<AST::Attribute> &outer_attrs)
+{
+ std::vector<
+ std::pair<std::string, std::reference_wrapper<const AST::Attribute>>>
+ to_derive;
+ for (auto it = outer_attrs.begin (); it != outer_attrs.end ();)
+ {
+ auto &attr = *it;
+
+ if (is_derive (attr))
+ {
+ auto &input = attr.get_attr_input ();
+ switch (input.get_attr_input_type ())
+ {
+ // isn't there a better way to do this?? like parse it or
+ // something idk. some function I'm not thinking of?
+ case AST::AttrInput::TOKEN_TREE: {
+ auto &tokens = static_cast<AST::DelimTokenTree &> (input)
+ .get_token_trees ();
+
+ // erase the delimiters
+ rust_assert (tokens.size () >= 3);
+ tokens.erase (tokens.begin ());
+ tokens.pop_back ();
+
+ for (auto &token : tokens)
+ {
+ // skip commas, as they are part of the token stream
+ if (token->as_string () == ",")
+ continue;
+
+ to_derive.emplace_back (token->as_string (), attr);
+ }
+ break;
+ }
+ case AST::AttrInput::LITERAL:
+ case AST::AttrInput::META_ITEM:
+ case AST::AttrInput::MACRO:
+ gcc_unreachable ();
+ break;
+ }
+
+ it = outer_attrs.erase (it);
+ }
+ else
+ {
+ it++;
+ }
+ }
+
+ return to_derive;
+}
+
+static std::unique_ptr<AST::Item>
+derive_item (std::unique_ptr<AST::Item> &item, const AST::Attribute &derive,
+ BuiltinMacro to_derive)
+{
+ return AST::DeriveVisitor::derive (*item, derive, to_derive);
+}
+
+void
+ExpandVisitor::expand_inner_items (
+ std::vector<std::unique_ptr<AST::Item>> &items)
{
expander.push_context (MacroExpander::ContextType::ITEM);
- // expand attributes recursively and strip items if required
- // AttrVisitor attr_visitor (*this);
- auto &items = crate.items;
- for (auto it = items.begin (); it != items.end ();)
+ for (auto it = items.begin (); it != items.end (); it++)
{
auto &item = *it;
- item->accept_vis (*this);
-
- auto fragment = expander.take_expanded_fragment ();
- if (fragment.should_expand ())
+ if (item->has_outer_attrs ())
{
- // Remove the current expanded invocation
- it = items.erase (it);
- for (auto &node : fragment.get_nodes ())
+ auto traits_to_derive
+ = get_traits_to_derive (item->get_outer_attrs ());
+
+ for (auto &to_derive : traits_to_derive)
{
- it = items.insert (it, node.take_item ());
- it++;
+ auto &name = to_derive.first;
+ auto &attr = to_derive.second;
+
+ auto maybe_builtin = MacroBuiltin::builtins.lookup (name);
+ if (MacroBuiltin::builtins.is_iter_ok (maybe_builtin))
+ {
+ auto new_item
+ = derive_item (item, attr, maybe_builtin->second);
+ // this inserts the derive *before* the item - is it a
+ // problem?
+ it = items.insert (it, std::move (new_item));
+ }
}
}
- else
- it++;
}
+ std::function<std::unique_ptr<AST::Item> (AST::SingleASTNode)> extractor
+ = [] (AST::SingleASTNode node) { return node.take_item (); };
+
+ expand_macro_children (items, extractor);
+
+ expander.pop_context ();
+}
+
+void
+ExpandVisitor::expand_inner_stmts (
+ std::vector<std::unique_ptr<AST::Stmt>> &stmts)
+{
+ expander.push_context (MacroExpander::ContextType::BLOCK);
+
+ for (auto it = stmts.begin (); it != stmts.end (); it++)
+ {
+ // TODO: Eventually we need to derive here as well
+
+ // auto &stmt = *it;
+
+ // if (stmt->has_outer_attrs ())
+ // {
+ // auto traits_to_derive
+ // = get_traits_to_derive (stmt->get_outer_attrs ());
+
+ // // FIXME: This needs to be reworked absolutely
+ // static const std::set<std::string> builtin_derives
+ // = {"Clone", "Copy", "Eq", "PartialEq", "Ord", "PartialOrd"};
+
+ // for (auto &to_derive : traits_to_derive)
+ // if (builtin_derives.find (to_derive) != builtin_derives.end ())
+ // {
+ // auto new_item = derive_item (
+ // item, item->get_outer_attrs ()[0] /* FIXME: This is wrong */,
+ // to_derive);
+ // // this inserts the derive *before* the item - is it a problem?
+ // it = items.insert (it, std::move (new_item));
+ // }
+ // }
+ }
+
+ std::function<std::unique_ptr<AST::Stmt> (AST::SingleASTNode)> extractor
+ = [] (AST::SingleASTNode node) { return node.take_stmt (); };
+
+ expand_macro_children (stmts, extractor);
+
expander.pop_context ();
}
void
ExpandVisitor::visit (AST::BlockExpr &expr)
{
- visit_outer_attrs (expr);
- std::function<std::unique_ptr<AST::Stmt> (AST::SingleASTNode)> extractor
- = [] (AST::SingleASTNode node) { return node.take_stmt (); };
-
- expand_macro_children (MacroExpander::ContextType::BLOCK,
- expr.get_statements (), extractor);
+ expand_inner_stmts (expr.get_statements ());
expander.push_context (MacroExpander::ContextType::BLOCK);
{
for (auto it = attrs.begin (); it != attrs.end (); /* erase => No increment*/)
{
- auto current = *it;
+ auto ¤t = *it;
if (!is_builtin (current) && !is_derive (current))
{
}
}
}
-
-bool
-ExpandVisitor::is_derive (AST::Attribute &attr)
-{
- auto &segments = attr.get_path ().get_segments ();
- return attr.has_attr_input ()
- && attr.get_attr_input ().get_attr_input_type ()
- == AST::AttrInput::TOKEN_TREE
- && !segments.empty () && "derive" == segments[0].get_segment_name ();
-}
-
-bool
-ExpandVisitor::is_builtin (AST::Attribute &attr)
-{
- auto &segments = attr.get_path ().get_segments ();
- return !segments.empty ()
- && !Analysis::BuiltinAttributeMappings::get ()
- ->lookup_builtin (segments[0].get_segment_name ())
- .is_error ();
-}
-
} // namespace Rust
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+#ifndef RUST_EXPAND_VISITOR_H
+#define RUST_EXPAND_VISITOR_H
+
#include "rust-ast-visitor.h"
#include "rust-macro-expand.h"
namespace Rust {
+/**
+ * Whether or not an attribute is a derive attribute
+ */
+bool
+is_derive (AST::Attribute &attr);
+
+/**
+ * Whether or not an attribute is builtin
+ */
+bool
+is_builtin (AST::Attribute &attr);
+
class ExpandVisitor : public AST::ASTVisitor
{
public:
*/
void expand_qualified_path_type (AST::QualifiedPathType &path_type);
+ // FIXME: Add documentation
void expand_closure_params (std::vector<AST::ClosureParam> ¶ms);
void expand_self_param (AST::SelfParam &self_param);
void expand_where_clause (AST::WhereClause &where_clause);
{
expander.push_context (ctx);
+ expand_macro_children (values, extractor);
+
+ expander.pop_context ();
+ }
+
+ /**
+ * Same as `expand_macro_children`, but does not push a context. This is
+ * useful if you're already pushing the context manually anyway for proc macro
+ * expansion, like in `expand_inner_{items, stmts}`
+ */
+ template <typename T, typename U>
+ void expand_macro_children (T &values,
+ std::function<U (AST::SingleASTNode)> extractor)
+ {
for (auto it = values.begin (); it != values.end ();)
{
auto &value = *it;
++it;
}
}
-
- expander.pop_context ();
}
+ /**
+ * Perform in-place expansion of procedural macros and macro invocations for
+ * an item container or statement container, such as `AST::Crate`,
+ * `AST::Module` or `AST::BlockExpr`. This function will insert the expanded
+ * nodes in place, and replace macro invocations with their expanded nodes.
+ *
+ * @param values Vector of values to mutate in-place and append into
+ */
+ void expand_inner_items (std::vector<std::unique_ptr<AST::Item>> &values);
+ void expand_inner_stmts (std::vector<std::unique_ptr<AST::Stmt>> &values);
+
// TODO: See if possible to make more specialization for Impl items, Block
// stmts etc? This could allow us to remove expand_macro_children or at least
// its extractor parameter
template <typename T> void visit_inner_attrs (T &item);
- bool is_derive (AST::Attribute &attr);
-
template <typename T>
void expand_derive (const T &item, std::unique_ptr<AST::TokenTree> &trait);
template <typename T> void visit_attrs_with_derive (T &item);
- bool is_builtin (AST::Attribute &attr);
-
private:
MacroExpander &expander;
};
} // namespace Rust
+
+#endif // RUST_EXPAND_VISITOR_H
#include "rust-macro.h"
#include "rust-parse.h"
#include "rust-session-manager.h"
-#include "bi-map.h"
namespace Rust {
-static const BiMap<std::string, BuiltinMacro> builtins = {{
+
+const BiMap<std::string, BuiltinMacro> MacroBuiltin::builtins = {{
{"assert", BuiltinMacro::Assert},
{"file", BuiltinMacro::File},
{"line", BuiltinMacro::Line},
{"cfg_accessible", BuiltinMacro::CfgAccessible},
{"RustcEncodable", BuiltinMacro::RustcDecodable},
{"RustcDecodable", BuiltinMacro::RustcEncodable},
+ {"Clone", BuiltinMacro::Clone},
+ {"Copy", BuiltinMacro::Copy},
+ {"Debug", BuiltinMacro::Debug},
+ {"Default", BuiltinMacro::Default},
+ {"Eq", BuiltinMacro::Eq},
+ {"PartialEq", BuiltinMacro::PartialEq},
+ {"Ord", BuiltinMacro::Ord},
+ {"PartialOrd", BuiltinMacro::PartialOrd},
+ {"Hash", BuiltinMacro::Hash},
+
}};
std::unordered_map<
{"test_case", MacroBuiltin::sorry},
{"global_allocator", MacroBuiltin::sorry},
{"cfg_accessible", MacroBuiltin::sorry},
- {"RustcEncodable", MacroBuiltin::sorry},
- {"RustcDecodable", MacroBuiltin::sorry},
};
// FIXME: This should return an Optional
BuiltinMacro
builtin_macro_from_string (const std::string &identifier)
{
- auto macro = builtins.lookup (identifier);
- rust_assert (builtins.is_iter_ok (macro));
+ auto macro = MacroBuiltin::builtins.lookup (identifier);
+ rust_assert (MacroBuiltin::builtins.is_iter_ok (macro));
return macro->second;
}
std::string
make_macro_path_str (BuiltinMacro kind)
{
- auto str = builtins.lookup (kind);
- rust_assert (builtins.is_iter_ok (str));
+ auto str = MacroBuiltin::builtins.lookup (kind);
+ rust_assert (MacroBuiltin::builtins.is_iter_ok (str));
return str->second;
}
#include "rust-ast.h"
#include "rust-ast-fragment.h"
#include "rust-location.h"
+#include "bi-map.h"
namespace Rust {
CfgAccessible,
RustcDecodable,
RustcEncodable,
+ Clone,
+ Copy,
+ Debug,
+ Default,
+ Eq,
+ PartialEq,
+ Ord,
+ PartialOrd,
+ Hash,
};
BuiltinMacro
class MacroBuiltin
{
public:
+ static const BiMap<std::string, BuiltinMacro> builtins;
static std::unordered_map<
std::string, std::function<AST::Fragment (Location, AST::MacroInvocData &)>>
builtin_transcribers;
});
if (should_be_builtin)
{
- auto builtin
+ auto builtin = MacroBuiltin::builtins.lookup (macro->get_rule_name ());
+ if (!MacroBuiltin::builtins.is_iter_ok (builtin))
+ {
+ rust_error_at (macro->get_locus (),
+ "cannot find a built-in macro with name %qs",
+ macro->get_rule_name ().c_str ());
+ return;
+ }
+
+ auto transcriber
= MacroBuiltin::builtin_transcribers.find (macro->get_rule_name ());
- if (builtin != MacroBuiltin::builtin_transcribers.end ())
- macro->set_builtin_transcriber (builtin->second);
- else
- rust_error_at (macro->get_locus (),
- "cannot find a built-in macro with name %qs",
- macro->get_rule_name ().c_str ());
+ macro->set_builtin_transcriber (transcriber->second);
}
auto it = macroMappings.find (macro->get_node_id ());
--- /dev/null
+pub trait Clone {
+ fn clone(&self) -> Self;
+}
+
+// This warning can be removed once we properly handle implems with #[automatically_derived]
+#[derive(Clone)] // { dg-warning "unused name .self." }
+pub struct S;
+
+fn main() {
+ let s = S;
+ let _s_clone = s.clone();
+}
--- /dev/null
+pub trait Clone {
+ fn clone(&self) -> Self;
+}
+
+pub trait Copy {}
+
+impl Copy for i32 {}
+
+impl<T> Clone for T
+where
+ T: Copy,
+{
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+fn main() {
+ let a = 15i32;
+ let _ = a.clone();
+}
/// assert_eq!(size_of::<Option<std::num::NonZeroU32>>(), size_of::<u32>());
/// ```
#[stable(feature = "nonzero", since = "1.28.0")]
- #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+ // not all derive macros are implemented yet, and this test does not test these anyways
+ // #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct $Ty(NonZero<$Int>);
--- /dev/null
+pub trait Clone {
+ fn clone(&self) -> Self;
+}
+
+pub trait Copy {}
+
+impl Copy for i32 {}
+
+impl<T> Clone for T
+where
+ T: Copy,
+{
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+fn main() -> i32 {
+ let a = 15i32;
+ let b = a.clone();
+
+ a - b
+}
--- /dev/null
+pub trait Clone {
+ fn clone(&self) -> Self;
+}
+
+impl Clone for i32 {
+ fn clone(&self) -> i32 {
+ *self
+ }
+}
+
+#[derive(Clone)]
+struct S(i32, i32);
+
+fn main() -> i32 {
+ let a = S(15, 15);
+ let b = a.clone();
+
+ b.0 - b.1
+}