-
Notifications
You must be signed in to change notification settings - Fork 169
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
gcc/rust/ChangeLog: * expand/rust-derive.cc (DeriveVisitor::derive): Call DeriveDefault. * expand/rust-derive-default.cc: New file. * expand/rust-derive-default.h: New file. * Make-lang.in: Compile them. gcc/testsuite/ChangeLog: * rust/compile/derive-default1.rs: New test. * rust/execute/torture/derive-default1.rs: New test. * rust/compile/nr2/exclude: Exclude them.
- Loading branch information
1 parent
32efb51
commit 0394968
Showing
7 changed files
with
290 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
// 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), {}, {}, | ||
AST::LoopLabel::error (), 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// 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_DEFAULT_H | ||
#define RUST_DERIVE_DEFAULT_H | ||
|
||
#include "rust-derive.h" | ||
#include "rust-ast.h" | ||
|
||
namespace Rust { | ||
namespace AST { | ||
|
||
// This derive is currently incomplete and only generate a stub implementation | ||
// which does not do any debug formatting | ||
class DeriveDefault : DeriveVisitor | ||
{ | ||
public: | ||
DeriveDefault (location_t loc); | ||
|
||
std::unique_ptr<Item> go (Item &); | ||
|
||
private: | ||
std::unique_ptr<Item> expanded; | ||
|
||
std::unique_ptr<Expr> default_call (std::unique_ptr<Type> &&type); | ||
|
||
std::unique_ptr<AssociatedItem> | ||
default_fn (std::unique_ptr<Expr> &&return_expr); | ||
|
||
std::unique_ptr<Item> default_impl ( | ||
std::unique_ptr<AssociatedItem> &&default_fn, std::string name, | ||
const std::vector<std::unique_ptr<GenericParam>> &type_generics); | ||
|
||
virtual void visit_struct (StructStruct &struct_item) override; | ||
virtual void visit_tuple (TupleStruct &tuple_item) override; | ||
virtual void visit_enum (Enum &enum_item) override; | ||
virtual void visit_union (Union &enum_item) override; | ||
}; | ||
|
||
} // namespace AST | ||
} // namespace Rust | ||
|
||
#endif // ! RUST_DERIVE_DEFAULT_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#[derive(Default)] | ||
struct Foo { _a: i32, _b: i64, _c: u8 } | ||
|
||
#[lang = "sized"] | ||
trait Sized {} | ||
|
||
mod core { | ||
mod default { | ||
trait Default: Sized { | ||
fn default() -> Self; | ||
} | ||
|
||
impl Default for i32 { | ||
fn default() -> Self { 0 } | ||
} | ||
|
||
impl Default for i64 { | ||
fn default() -> Self { 27 } | ||
} | ||
|
||
impl Default for u8 { | ||
fn default() -> Self { 18 } | ||
} | ||
} | ||
} | ||
|
||
fn main() { | ||
let _ = Foo::default(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#[derive(Default)] | ||
struct Foo { a: i32 } | ||
#[derive(Default)] | ||
struct Bar(i32); | ||
|
||
#[lang = "sized"] | ||
trait Sized {} | ||
|
||
mod core { | ||
mod default { | ||
trait Default: Sized { | ||
fn default() -> Self; | ||
} | ||
|
||
impl Default for i32 { | ||
fn default() -> Self { 1 } | ||
} | ||
} | ||
} | ||
|
||
fn main() -> i32 { | ||
let foo = Foo::default(); | ||
let bar = Bar::default(); | ||
|
||
foo.a + bar.0 - 2 | ||
} |