// 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-default.h" #include "rust-ast.h" #include "rust-diagnostics.h" #include "rust-path.h" #include "rust-system.h" namespace Rust { namespace AST { DeriveDefault::DeriveDefault (location_t loc) : DeriveVisitor (loc), expanded (nullptr) {} std::unique_ptr<Item> DeriveDefault::go (Item &item) { item.accept_vis (*this); rust_assert (expanded); return std::move (expanded); } std::unique_ptr<Expr> DeriveDefault::default_call (std::unique_ptr<Type> &&type) { auto default_trait = builder.type_path ({"core", "default", "Default"}, true); auto default_fn = builder.qualified_path_in_expression (std::move (type), default_trait, builder.path_segment ("default")); return builder.call (std::move (default_fn)); } std::unique_ptr<AssociatedItem> DeriveDefault::default_fn (std::unique_ptr<Expr> &&return_expr) { auto self_ty = std::unique_ptr<Type> (new TypePath (builder.type_path ("Self"))); auto block = std::unique_ptr<BlockExpr> ( new BlockExpr ({}, std::move (return_expr), {}, {}, tl::nullopt, loc, loc)); return builder.function ("default", {}, std::move (self_ty), std::move (block)); } std::unique_ptr<Item> DeriveDefault::default_impl ( std::unique_ptr<AssociatedItem> &&default_fn, std::string name, const std::vector<std::unique_ptr<GenericParam>> &type_generics) { auto default_path = builder.type_path ({"core", "default", "Default"}, true); auto trait_items = vec (std::move (default_fn)); auto generics = setup_impl_generics (name, type_generics, builder.trait_bound (default_path)); return builder.trait_impl (default_path, std::move (generics.self_type), std::move (trait_items), std::move (generics.impl)); } void DeriveDefault::visit_struct (StructStruct &item) { if (item.is_unit_struct ()) { auto unit_ctor = builder.struct_expr_struct (item.get_struct_name ().as_string ()); expanded = default_impl (default_fn (std::move (unit_ctor)), item.get_struct_name ().as_string (), item.get_generic_params ()); return; } auto cloned_fields = std::vector<std::unique_ptr<StructExprField>> (); for (auto &field : item.get_fields ()) { auto name = field.get_field_name ().as_string (); auto expr = default_call (field.get_field_type ().clone_type ()); cloned_fields.emplace_back ( builder.struct_expr_field (std::move (name), std::move (expr))); } auto ctor = builder.struct_expr (item.get_struct_name ().as_string (), std::move (cloned_fields)); expanded = default_impl (default_fn (std::move (ctor)), item.get_struct_name ().as_string (), item.get_generic_params ()); } void DeriveDefault::visit_tuple (TupleStruct &tuple_item) { auto defaulted_fields = std::vector<std::unique_ptr<Expr>> (); for (auto &field : tuple_item.get_fields ()) { auto type = field.get_field_type ().clone_type (); defaulted_fields.emplace_back (default_call (std::move (type))); } auto return_expr = builder.call (builder.identifier ( tuple_item.get_struct_name ().as_string ()), std::move (defaulted_fields)); expanded = default_impl (default_fn (std::move (return_expr)), tuple_item.get_struct_name ().as_string (), tuple_item.get_generic_params ()); } void DeriveDefault::visit_enum (Enum &enum_item) { // This is no longer the case in later Rust versions where you can choose a // default variant to emit using the `#[default]` attribute: // // ```rust // #[derive(Default)] // enum Baz { // #[default] // A, // B(i32), // C { a: i32 } // } // ``` // // will emit the following impl // // ```rust // impl ::core::default::Default for Baz { // #[inline] // fn default() -> Baz { Self::A } // } // ``` rust_error_at (loc, ErrorCode::E0665, "%<Default%> cannot be derived for enums, only structs"); } void DeriveDefault::visit_union (Union &enum_item) { rust_error_at (loc, "derive(Default) cannot be used on unions"); } } // namespace AST } // namespace Rust