Skip to content

Commit 1ae7c49

Browse files
committed
Auto merge of #145475 - jhpratt:rollup-jr0wado, r=jhpratt
Rollup of 11 pull requests Successful merges: - #143717 (Add `Default` impls for `Pin`ned `Box`, `Rc`, `Arc`) - #144054 (Stabilize as_array_of_cells) - #144907 (fix: Reject async assoc fns of const traits/impls in ast_passes) - #144922 (Implement `#[derive(From)]`) - #144963 (Stabilize `core::iter::chain`) - #145436 (fix(tests/rmake/wasm-unexpected-features): change features from `WASM1` to `MVP`) - #145453 (Remove duplicated tracing span in bootstrap) - #145454 (Fix tracing debug representation of steps without arguments in bootstrap) - #145455 (Do not copy files in `copy_src_dirs` in dry run) - #145462 (Stabilize `const_exposed_provenance` feature) - #145466 (Enable new `[range-diff]` feature in triagebot) r? `@ghost` `@rustbot` modify labels: rollup
2 parents cd7cbe8 + cf28e2b commit 1ae7c49

File tree

38 files changed

+722
-36
lines changed

38 files changed

+722
-36
lines changed

compiler/rustc_ast_passes/messages.ftl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ ast_passes_assoc_type_without_body =
3232
associated type in `impl` without body
3333
.suggestion = provide a definition for the type
3434
35+
ast_passes_async_fn_in_const_trait_or_trait_impl =
36+
async functions are not allowed in `const` {$in_impl ->
37+
[true] trait impls
38+
*[false] traits
39+
}
40+
.label = associated functions of `const` cannot be declared `async`
41+
3542
ast_passes_at_least_one_trait = at least one trait must be specified
3643
3744
ast_passes_auto_generic = auto traits cannot have generic parameters

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,21 @@ impl<'a> AstValidator<'a> {
293293
});
294294
}
295295

296+
fn check_async_fn_in_const_trait_or_impl(&self, sig: &FnSig, parent: &TraitOrTraitImpl) {
297+
let Some(const_keyword) = parent.constness() else { return };
298+
299+
let Some(CoroutineKind::Async { span: async_keyword, .. }) = sig.header.coroutine_kind
300+
else {
301+
return;
302+
};
303+
304+
self.dcx().emit_err(errors::AsyncFnInConstTraitOrTraitImpl {
305+
async_keyword,
306+
in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
307+
const_keyword,
308+
});
309+
}
310+
296311
fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
297312
self.check_decl_num_args(fn_decl);
298313
self.check_decl_cvariadic_pos(fn_decl);
@@ -1578,6 +1593,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
15781593
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
15791594
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
15801595
self.check_trait_fn_not_const(sig.header.constness, parent);
1596+
self.check_async_fn_in_const_trait_or_impl(sig, parent);
15811597
}
15821598
}
15831599

compiler/rustc_ast_passes/src/errors.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ pub(crate) struct TraitFnConst {
6262
pub make_trait_const_sugg: Option<Span>,
6363
}
6464

65+
#[derive(Diagnostic)]
66+
#[diag(ast_passes_async_fn_in_const_trait_or_trait_impl)]
67+
pub(crate) struct AsyncFnInConstTraitOrTraitImpl {
68+
#[primary_span]
69+
pub async_keyword: Span,
70+
pub in_impl: bool,
71+
#[label]
72+
pub const_keyword: Span,
73+
}
74+
6575
#[derive(Diagnostic)]
6676
#[diag(ast_passes_forbidden_bound)]
6777
pub(crate) struct ForbiddenBound {

compiler/rustc_builtin_macros/messages.ftl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,15 @@ builtin_macros_format_unused_args = multiple unused formatting arguments
222222
223223
builtin_macros_format_use_positional = consider using a positional formatting argument instead
224224
225+
builtin_macros_derive_from_wrong_target = `#[derive(From)]` used on {$kind}
226+
227+
builtin_macros_derive_from_wrong_field_count = `#[derive(From)]` used on a struct with {$multiple_fields ->
228+
[true] multiple fields
229+
*[false] no fields
230+
}
231+
232+
builtin_macros_derive_from_usage_note = `#[derive(From)]` can only be used on structs with exactly one field
233+
225234
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
226235
.note = only one `#[default]` attribute is needed
227236
.label = `#[default]` used here
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
use rustc_ast as ast;
2+
use rustc_ast::{ItemKind, VariantData};
3+
use rustc_errors::MultiSpan;
4+
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
5+
use rustc_span::{Ident, Span, kw, sym};
6+
use thin_vec::thin_vec;
7+
8+
use crate::deriving::generic::ty::{Bounds, Path, PathKind, Ty};
9+
use crate::deriving::generic::{
10+
BlockOrExpr, FieldlessVariantsStrategy, MethodDef, SubstructureFields, TraitDef,
11+
combine_substructure,
12+
};
13+
use crate::deriving::pathvec_std;
14+
use crate::errors;
15+
16+
/// Generate an implementation of the `From` trait, provided that `item`
17+
/// is a struct or a tuple struct with exactly one field.
18+
pub(crate) fn expand_deriving_from(
19+
cx: &ExtCtxt<'_>,
20+
span: Span,
21+
mitem: &ast::MetaItem,
22+
annotatable: &Annotatable,
23+
push: &mut dyn FnMut(Annotatable),
24+
is_const: bool,
25+
) {
26+
let Annotatable::Item(item) = &annotatable else {
27+
cx.dcx().bug("derive(From) used on something else than an item");
28+
};
29+
30+
// #[derive(From)] is currently usable only on structs with exactly one field.
31+
let field = if let ItemKind::Struct(_, _, data) = &item.kind
32+
&& let [field] = data.fields()
33+
{
34+
Some(field.clone())
35+
} else {
36+
None
37+
};
38+
39+
let from_type = match &field {
40+
Some(field) => Ty::AstTy(field.ty.clone()),
41+
// We don't have a type to put into From<...> if we don't have a single field, so just put
42+
// unit there.
43+
None => Ty::Unit,
44+
};
45+
let path =
46+
Path::new_(pathvec_std!(convert::From), vec![Box::new(from_type.clone())], PathKind::Std);
47+
48+
// Generate code like this:
49+
//
50+
// struct S(u32);
51+
// #[automatically_derived]
52+
// impl ::core::convert::From<u32> for S {
53+
// #[inline]
54+
// fn from(value: u32) -> S {
55+
// Self(value)
56+
// }
57+
// }
58+
let from_trait_def = TraitDef {
59+
span,
60+
path,
61+
skip_path_as_bound: true,
62+
needs_copy_as_bound_if_packed: false,
63+
additional_bounds: Vec::new(),
64+
supports_unions: false,
65+
methods: vec![MethodDef {
66+
name: sym::from,
67+
generics: Bounds { bounds: vec![] },
68+
explicit_self: false,
69+
nonself_args: vec![(from_type, sym::value)],
70+
ret_ty: Ty::Self_,
71+
attributes: thin_vec![cx.attr_word(sym::inline, span)],
72+
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
73+
combine_substructure: combine_substructure(Box::new(|cx, span, substructure| {
74+
let Some(field) = &field else {
75+
let item_span = item.kind.ident().map(|ident| ident.span).unwrap_or(item.span);
76+
let err_span = MultiSpan::from_spans(vec![span, item_span]);
77+
let error = match &item.kind {
78+
ItemKind::Struct(_, _, data) => {
79+
cx.dcx().emit_err(errors::DeriveFromWrongFieldCount {
80+
span: err_span,
81+
multiple_fields: data.fields().len() > 1,
82+
})
83+
}
84+
ItemKind::Enum(_, _, _) | ItemKind::Union(_, _, _) => {
85+
cx.dcx().emit_err(errors::DeriveFromWrongTarget {
86+
span: err_span,
87+
kind: &format!("{} {}", item.kind.article(), item.kind.descr()),
88+
})
89+
}
90+
_ => cx.dcx().bug("Invalid derive(From) ADT input"),
91+
};
92+
93+
return BlockOrExpr::new_expr(DummyResult::raw_expr(span, Some(error)));
94+
};
95+
96+
let self_kw = Ident::new(kw::SelfUpper, span);
97+
let expr: Box<ast::Expr> = match substructure.fields {
98+
SubstructureFields::StaticStruct(variant, _) => match variant {
99+
// Self {
100+
// field: value
101+
// }
102+
VariantData::Struct { .. } => cx.expr_struct_ident(
103+
span,
104+
self_kw,
105+
thin_vec![cx.field_imm(
106+
span,
107+
field.ident.unwrap(),
108+
cx.expr_ident(span, Ident::new(sym::value, span))
109+
)],
110+
),
111+
// Self(value)
112+
VariantData::Tuple(_, _) => cx.expr_call_ident(
113+
span,
114+
self_kw,
115+
thin_vec![cx.expr_ident(span, Ident::new(sym::value, span))],
116+
),
117+
variant => {
118+
cx.dcx().bug(format!("Invalid derive(From) ADT variant: {variant:?}"));
119+
}
120+
},
121+
_ => cx.dcx().bug("Invalid derive(From) ADT input"),
122+
};
123+
BlockOrExpr::new_expr(expr)
124+
})),
125+
}],
126+
associated_types: Vec::new(),
127+
is_const,
128+
is_staged_api_crate: cx.ecfg.features.staged_api(),
129+
};
130+
131+
from_trait_def.expand(cx, mitem, annotatable, push);
132+
}

compiler/rustc_builtin_macros/src/deriving/generic/ty.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! when specifying impls to be derived.
33
44
pub(crate) use Ty::*;
5-
use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind};
5+
use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind, TyKind};
66
use rustc_expand::base::ExtCtxt;
77
use rustc_span::source_map::respan;
88
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw};
@@ -65,7 +65,7 @@ impl Path {
6565
}
6666
}
6767

68-
/// A type. Supports pointers, Self, and literals.
68+
/// A type. Supports pointers, Self, literals, unit or an arbitrary AST path.
6969
#[derive(Clone)]
7070
pub(crate) enum Ty {
7171
Self_,
@@ -76,6 +76,8 @@ pub(crate) enum Ty {
7676
Path(Path),
7777
/// For () return types.
7878
Unit,
79+
/// An arbitrary type.
80+
AstTy(Box<ast::Ty>),
7981
}
8082

8183
pub(crate) fn self_ref() -> Ty {
@@ -101,6 +103,7 @@ impl Ty {
101103
let ty = ast::TyKind::Tup(ThinVec::new());
102104
cx.ty(span, ty)
103105
}
106+
AstTy(ty) => ty.clone(),
104107
}
105108
}
106109

@@ -132,6 +135,10 @@ impl Ty {
132135
cx.path_all(span, false, vec![self_ty], params)
133136
}
134137
Path(p) => p.to_path(cx, span, self_ty, generics),
138+
AstTy(ty) => match &ty.kind {
139+
TyKind::Path(_, path) => path.clone(),
140+
_ => cx.dcx().span_bug(span, "non-path in a path in generic `derive`"),
141+
},
135142
Ref(..) => cx.dcx().span_bug(span, "ref in a path in generic `derive`"),
136143
Unit => cx.dcx().span_bug(span, "unit in a path in generic `derive`"),
137144
}

compiler/rustc_builtin_macros/src/deriving/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub(crate) mod clone;
2323
pub(crate) mod coerce_pointee;
2424
pub(crate) mod debug;
2525
pub(crate) mod default;
26+
pub(crate) mod from;
2627
pub(crate) mod hash;
2728

2829
#[path = "cmp/eq.rs"]

compiler/rustc_builtin_macros/src/errors.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,24 @@ pub(crate) struct DefaultHasArg {
446446
pub(crate) span: Span,
447447
}
448448

449+
#[derive(Diagnostic)]
450+
#[diag(builtin_macros_derive_from_wrong_target)]
451+
#[note(builtin_macros_derive_from_usage_note)]
452+
pub(crate) struct DeriveFromWrongTarget<'a> {
453+
#[primary_span]
454+
pub(crate) span: MultiSpan,
455+
pub(crate) kind: &'a str,
456+
}
457+
458+
#[derive(Diagnostic)]
459+
#[diag(builtin_macros_derive_from_wrong_field_count)]
460+
#[note(builtin_macros_derive_from_usage_note)]
461+
pub(crate) struct DeriveFromWrongFieldCount {
462+
#[primary_span]
463+
pub(crate) span: MultiSpan,
464+
pub(crate) multiple_fields: bool,
465+
}
466+
449467
#[derive(Diagnostic)]
450468
#[diag(builtin_macros_derive_macro_call)]
451469
pub(crate) struct DeriveMacroCall {

compiler/rustc_builtin_macros/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
139139
PartialEq: partial_eq::expand_deriving_partial_eq,
140140
PartialOrd: partial_ord::expand_deriving_partial_ord,
141141
CoercePointee: coerce_pointee::expand_deriving_coerce_pointee,
142+
From: from::expand_deriving_from,
142143
}
143144

144145
let client = rustc_proc_macro::bridge::client::Client::expand1(rustc_proc_macro::quote);

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,8 @@ declare_features! (
470470
(unstable, deprecated_suggestion, "1.61.0", Some(94785)),
471471
/// Allows deref patterns.
472472
(incomplete, deref_patterns, "1.79.0", Some(87121)),
473+
/// Allows deriving the From trait on single-field structs.
474+
(unstable, derive_from, "CURRENT_RUSTC_VERSION", Some(144889)),
473475
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
474476
(unstable, doc_auto_cfg, "1.58.0", Some(43781)),
475477
/// Allows `#[doc(cfg(...))]`.

0 commit comments

Comments
 (0)