Auto merge of #98767 - Dylan-DPC:rollup-j1gq5sr, r=Dylan-DPC

Rollup of 6 pull requests

Successful merges:

 - #97488 (Suggest blanket impl to the local traits)
 - #98585 (Make `ThinBox<T>` covariant in `T`)
 - #98644 (fix ICE with -Wrust-2021-incompatible-closure-captures)
 - #98739 (fix grammar in useless doc comment lint)
 - #98741 (Many small deriving cleanups)
 - #98756 (Use const instead of function and make it private)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-07-01 17:33:42 +00:00
commit 5018181c79
27 changed files with 545 additions and 331 deletions

View File

@ -19,7 +19,6 @@ pub fn expand_deriving_copy(
path: path_std!(marker::Copy),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: true,
methods: Vec::new(),
associated_types: Vec::new(),

View File

@ -15,23 +15,22 @@ pub fn expand_deriving_clone(
item: &Annotatable,
push: &mut dyn FnMut(Annotatable),
) {
// check if we can use a short form
// The simple form is `fn clone(&self) -> Self { *self }`, possibly with
// some additional `AssertParamIsClone` assertions.
//
// the short form is `fn clone(&self) -> Self { *self }`
//
// we can use the short form if:
// - the item is Copy (unfortunately, all we can check is whether it's also deriving Copy)
// - there are no generic parameters (after specialization this limitation can be removed)
// if we used the short form with generics, we'd have to bound the generics with
// Clone + Copy, and then there'd be no Clone impl at all if the user fills in something
// that is Clone but not Copy. and until specialization we can't write both impls.
// - the item is a union with Copy fields
// Unions with generic parameters still can derive Clone because they require Copy
// for deriving, Clone alone is not enough.
// Wherever Clone is implemented for fields is irrelevant so we don't assert it.
// We can use the simple form if either of the following are true.
// - The type derives Copy and there are no generic parameters. (If we
// used the simple form with generics, we'd have to bound the generics
// with Clone + Copy, and then there'd be no Clone impl at all if the
// user fills in something that is Clone but not Copy. After
// specialization we can remove this no-generics limitation.)
// - The item is a union. (Unions with generic parameters still can derive
// Clone because they require Copy for deriving, Clone alone is not
// enough. Whether Clone is implemented for fields is irrelevant so we
// don't assert it.)
let bounds;
let substructure;
let is_shallow;
let is_simple;
match *item {
Annotatable::Item(ref annitem) => match annitem.kind {
ItemKind::Struct(_, Generics { ref params, .. })
@ -44,30 +43,25 @@ pub fn expand_deriving_clone(
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
{
bounds = vec![];
is_shallow = true;
is_simple = true;
substructure = combine_substructure(Box::new(|c, s, sub| {
cs_clone_shallow("Clone", c, s, sub, false)
cs_clone_simple("Clone", c, s, sub, false)
}));
} else {
bounds = vec![];
is_shallow = false;
is_simple = false;
substructure =
combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub)));
}
}
ItemKind::Union(..) => {
bounds = vec![Literal(path_std!(marker::Copy))];
is_shallow = true;
bounds = vec![Path(path_std!(marker::Copy))];
is_simple = true;
substructure = combine_substructure(Box::new(|c, s, sub| {
cs_clone_shallow("Clone", c, s, sub, true)
cs_clone_simple("Clone", c, s, sub, true)
}));
}
_ => {
bounds = vec![];
is_shallow = false;
substructure =
combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub)));
}
_ => cx.span_bug(span, "`#[derive(Clone)]` on wrong item kind"),
},
_ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
@ -81,26 +75,24 @@ pub fn expand_deriving_clone(
path: path_std!(clone::Clone),
additional_bounds: bounds,
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: true,
methods: vec![MethodDef {
name: sym::clone,
generics: Bounds::empty(),
explicit_self: borrowed_explicit_self(),
explicit_self: true,
args: Vec::new(),
ret_ty: Self_,
attributes: attrs,
is_unsafe: false,
unify_fieldless_variants: false,
combine_substructure: substructure,
}],
associated_types: Vec::new(),
};
trait_def.expand_ext(cx, mitem, item, push, is_shallow)
trait_def.expand_ext(cx, mitem, item, push, is_simple)
}
fn cs_clone_shallow(
fn cs_clone_simple(
name: &str,
cx: &mut ExtCtxt<'_>,
trait_span: Span,
@ -143,7 +135,7 @@ fn cs_clone_shallow(
}
_ => cx.span_bug(
trait_span,
&format!("unexpected substructure in shallow `derive({})`", name),
&format!("unexpected substructure in simple `derive({})`", name),
),
}
}

View File

@ -27,16 +27,14 @@ pub fn expand_deriving_eq(
path: path_std!(cmp::Eq),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: true,
methods: vec![MethodDef {
name: sym::assert_receiver_is_total_eq,
generics: Bounds::empty(),
explicit_self: borrowed_explicit_self(),
explicit_self: true,
args: vec![],
ret_ty: nil_ty(),
ret_ty: Unit,
attributes: attrs,
is_unsafe: false,
unify_fieldless_variants: true,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
cs_total_eq_assert(a, b, c)

View File

@ -23,16 +23,14 @@ pub fn expand_deriving_ord(
path: path_std!(cmp::Ord),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::cmp,
generics: Bounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec![(borrowed_self(), sym::other)],
ret_ty: Literal(path_std!(cmp::Ordering)),
explicit_self: true,
args: vec![(self_ref(), sym::other)],
ret_ty: Path(path_std!(cmp::Ordering)),
attributes: attrs,
is_unsafe: false,
unify_fieldless_variants: true,
combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))),
}],
@ -99,8 +97,8 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<
cx.expr_match(span, new, vec![eq_arm, neq_arm])
},
cx.expr_path(equals_path.clone()),
Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 {
Box::new(|cx, span, tag_tuple| {
if tag_tuple.len() != 2 {
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`")
} else {
ordering_collapsed(cx, span, tag_tuple)

View File

@ -48,7 +48,7 @@ pub fn expand_deriving_partial_eq(
None => cx.expr_bool(span, base),
}
},
Box::new(|cx, span, _, _| cx.expr_bool(span, !base)),
Box::new(|cx, span, _| cx.expr_bool(span, !base)),
cx,
span,
substr,
@ -69,11 +69,10 @@ pub fn expand_deriving_partial_eq(
MethodDef {
name: $name,
generics: Bounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec![(borrowed_self(), sym::other)],
ret_ty: Literal(path_local!(bool)),
explicit_self: true,
args: vec![(self_ref(), sym::other)],
ret_ty: Path(path_local!(bool)),
attributes: attrs,
is_unsafe: false,
unify_fieldless_variants: true,
combine_substructure: combine_substructure(Box::new(|a, b, c| $f(a, b, c))),
}
@ -102,7 +101,6 @@ pub fn expand_deriving_partial_eq(
path: path_std!(cmp::PartialEq),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods,
associated_types: Vec::new(),

View File

@ -15,13 +15,9 @@ pub fn expand_deriving_partial_ord(
item: &Annotatable,
push: &mut dyn FnMut(Annotatable),
) {
let ordering_ty = Literal(path_std!(cmp::Ordering));
let ret_ty = Literal(Path::new_(
pathvec_std!(option::Option),
None,
vec![Box::new(ordering_ty)],
PathKind::Std,
));
let ordering_ty = Path(path_std!(cmp::Ordering));
let ret_ty =
Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std));
let inline = cx.meta_word(span, sym::inline);
let attrs = vec![cx.attribute(inline)];
@ -29,11 +25,10 @@ pub fn expand_deriving_partial_ord(
let partial_cmp_def = MethodDef {
name: sym::partial_cmp,
generics: Bounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec![(borrowed_self(), sym::other)],
explicit_self: true,
args: vec![(self_ref(), sym::other)],
ret_ty,
attributes: attrs,
is_unsafe: false,
unify_fieldless_variants: true,
combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
cs_partial_cmp(cx, span, substr)
@ -46,7 +41,6 @@ pub fn expand_deriving_partial_ord(
path: path_std!(cmp::PartialOrd),
additional_bounds: vec![],
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: vec![partial_cmp_def],
associated_types: Vec::new(),
@ -102,8 +96,8 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
cx.expr_match(span, new, vec![eq_arm, neq_arm])
},
equals_expr,
Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 {
Box::new(|cx, span, tag_tuple| {
if tag_tuple.len() != 2 {
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
} else {
let lft = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[0]));

View File

@ -16,8 +16,7 @@ pub fn expand_deriving_debug(
push: &mut dyn FnMut(Annotatable),
) {
// &mut ::std::fmt::Formatter
let fmtr =
Ptr(Box::new(Literal(path_std!(fmt::Formatter))), Borrowed(None, ast::Mutability::Mut));
let fmtr = Ref(Box::new(Path(path_std!(fmt::Formatter))), ast::Mutability::Mut);
let trait_def = TraitDef {
span,
@ -25,16 +24,14 @@ pub fn expand_deriving_debug(
path: path_std!(fmt::Debug),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::fmt,
generics: Bounds::empty(),
explicit_self: borrowed_explicit_self(),
explicit_self: true,
args: vec![(fmtr, sym::f)],
ret_ty: Literal(path_std!(fmt::Result)),
ret_ty: Path(path_std!(fmt::Result)),
attributes: Vec::new(),
is_unsafe: false,
unify_fieldless_variants: false,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
show_substructure(a, b, c)
@ -64,8 +61,6 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
let (is_struct, args_per_field) = match vdata {
ast::VariantData::Unit(..) => {
// Special fast path for unit variants.
//let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
//return cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]);
assert!(fields.is_empty());
(false, 0)
}

View File

@ -23,40 +23,29 @@ pub fn expand_deriving_rustc_decodable(
let trait_def = TraitDef {
span,
attributes: Vec::new(),
path: Path::new_(vec![krate, sym::Decodable], None, vec![], PathKind::Global),
path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::decode,
generics: Bounds {
bounds: vec![(
typaram,
vec![Path::new_(vec![krate, sym::Decoder], None, vec![], PathKind::Global)],
vec![Path::new_(vec![krate, sym::Decoder], vec![], PathKind::Global)],
)],
},
explicit_self: None,
args: vec![(
Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
sym::d,
)],
ret_ty: Literal(Path::new_(
explicit_self: false,
args: vec![(Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), sym::d)],
ret_ty: Path(Path::new_(
pathvec_std!(result::Result),
None,
vec![
Box::new(Self_),
Box::new(Literal(Path::new_(
vec![typaram, sym::Error],
None,
vec![],
PathKind::Local,
))),
Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))),
],
PathKind::Std,
)),
attributes: Vec::new(),
is_unsafe: false,
unify_fieldless_variants: false,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
decodable_substructure(a, b, c, krate)

View File

@ -30,16 +30,14 @@ pub fn expand_deriving_default(
path: Path::new(vec![kw::Default, sym::Default]),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: vec![MethodDef {
name: kw::Default,
generics: Bounds::empty(),
explicit_self: None,
explicit_self: false,
args: Vec::new(),
ret_ty: Self_,
attributes: attrs,
is_unsafe: false,
unify_fieldless_variants: false,
combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| {
match substr.fields {

View File

@ -108,40 +108,29 @@ pub fn expand_deriving_rustc_encodable(
let trait_def = TraitDef {
span,
attributes: Vec::new(),
path: Path::new_(vec![krate, sym::Encodable], None, vec![], PathKind::Global),
path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::encode,
generics: Bounds {
bounds: vec![(
typaram,
vec![Path::new_(vec![krate, sym::Encoder], None, vec![], PathKind::Global)],
vec![Path::new_(vec![krate, sym::Encoder], vec![], PathKind::Global)],
)],
},
explicit_self: borrowed_explicit_self(),
args: vec![(
Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
sym::s,
)],
ret_ty: Literal(Path::new_(
explicit_self: true,
args: vec![(Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), sym::s)],
ret_ty: Path(Path::new_(
pathvec_std!(result::Result),
None,
vec![
Box::new(Tuple(Vec::new())),
Box::new(Literal(Path::new_(
vec![typaram, sym::Error],
None,
vec![],
PathKind::Local,
))),
Box::new(Unit),
Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))),
],
PathKind::Std,
)),
attributes: Vec::new(),
is_unsafe: false,
unify_fieldless_variants: false,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
encodable_substructure(a, b, c, krate)

View File

@ -146,8 +146,6 @@
//!
//! ```{.text}
//! EnumNonMatchingCollapsed(
//! vec![<ident of self>, <ident of __arg_1>],
//! &[<ast::Variant for C0>, <ast::Variant for C1>],
//! &[<ident for self index value>, <ident of __arg_1 index value>])
//! ```
//!
@ -190,7 +188,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use ty::{Bounds, Path, Ptr, PtrTy, Self_, Ty};
use ty::{Bounds, Path, Ref, Self_, Ty};
use crate::deriving;
@ -212,9 +210,6 @@ pub struct TraitDef<'a> {
/// Any extra lifetimes and/or bounds, e.g., `D: serialize::Decoder`
pub generics: Bounds,
/// Is it an `unsafe` trait?
pub is_unsafe: bool,
/// Can this trait be derived for unions?
pub supports_unions: bool,
@ -229,10 +224,8 @@ pub struct MethodDef<'a> {
/// List of generics, e.g., `R: rand::Rng`
pub generics: Bounds,
/// Whether there is a self argument (outer Option) i.e., whether
/// this is a static function, and whether it is a pointer (inner
/// Option)
pub explicit_self: Option<Option<PtrTy>>,
/// Is there is a `&self` argument? If not, it is a static function.
pub explicit_self: bool,
/// Arguments other than the self argument
pub args: Vec<(Ty, Symbol)>,
@ -242,9 +235,6 @@ pub struct MethodDef<'a> {
pub attributes: Vec<ast::Attribute>,
// Is it an `unsafe fn`?
pub is_unsafe: bool,
/// Can we combine fieldless variants for enums into a single match arm?
pub unify_fieldless_variants: bool,
@ -255,14 +245,7 @@ pub struct MethodDef<'a> {
pub struct Substructure<'a> {
/// ident of self
pub type_ident: Ident,
/// ident of the method
pub method_ident: Ident,
/// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)`][ptr] arguments
///
/// [`Self_`]: ty::Ty::Self_
/// [ptr]: ty::Ty::Ptr
pub self_args: &'a [P<Expr>],
/// verbatim access to any other arguments
/// verbatim access to any non-self arguments
pub nonself_args: &'a [P<Expr>],
pub fields: &'a SubstructureFields<'a>,
}
@ -299,13 +282,10 @@ pub enum SubstructureFields<'a> {
/// variant.
EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo<'a>>),
/// Non-matching variants of the enum, but with all state hidden from
/// the consequent code. The first component holds `Ident`s for all of
/// the `Self` arguments; the second component is a slice of all of the
/// variants for the enum itself, and the third component is a list of
/// `Ident`s bound to the variant index values for each of the actual
/// input `Self` arguments.
EnumNonMatchingCollapsed(Vec<Ident>, &'a [ast::Variant], &'a [Ident]),
/// Non-matching variants of the enum, but with all state hidden from the
/// consequent code. The field is a list of `Ident`s bound to the variant
/// index values for each of the actual input `Self` arguments.
EnumNonMatchingCollapsed(&'a [Ident]),
/// A static method where `Self` is a struct.
StaticStruct(&'a ast::VariantData, StaticFields),
@ -318,13 +298,10 @@ pub enum SubstructureFields<'a> {
pub type CombineSubstructureFunc<'a> =
Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> P<Expr> + 'a>;
/// Deal with non-matching enum variants. The tuple is a list of
/// identifiers (one for each `Self` argument, which could be any of the
/// variants since they have been collapsed together) and the identifiers
/// holding the variant index value for each of the `Self` arguments. The
/// last argument is all the non-`Self` args of the method being derived.
/// Deal with non-matching enum variants. The slice is the identifiers holding
/// the variant index value for each of the `Self` arguments.
pub type EnumNonMatchCollapsedFunc<'a> =
Box<dyn FnMut(&mut ExtCtxt<'_>, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>;
Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &[Ident]) -> P<Expr> + 'a>;
pub fn combine_substructure(
f: CombineSubstructureFunc<'_>,
@ -727,14 +704,12 @@ impl<'a> TraitDef<'a> {
let mut a = vec![attr, unused_qual];
a.extend(self.attributes.iter().cloned());
let unsafety = if self.is_unsafe { ast::Unsafe::Yes(self.span) } else { ast::Unsafe::No };
cx.item(
self.span,
Ident::empty(),
a,
ast::ItemKind::Impl(Box::new(ast::Impl {
unsafety,
unsafety: ast::Unsafe::No,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
constness: ast::Const::No,
@ -771,7 +746,6 @@ impl<'a> TraitDef<'a> {
self,
struct_def,
type_ident,
&self_args,
&nonself_args,
)
} else {
@ -820,7 +794,6 @@ impl<'a> TraitDef<'a> {
self,
enum_def,
type_ident,
&self_args,
&nonself_args,
)
} else {
@ -848,18 +821,11 @@ impl<'a> MethodDef<'a> {
cx: &mut ExtCtxt<'_>,
trait_: &TraitDef<'_>,
type_ident: Ident,
self_args: &[P<Expr>],
nonself_args: &[P<Expr>],
fields: &SubstructureFields<'_>,
) -> P<Expr> {
let span = trait_.span;
let substructure = Substructure {
type_ident,
method_ident: Ident::new(self.name, span),
self_args,
nonself_args,
fields,
};
let substructure = Substructure { type_ident, nonself_args, fields };
let mut f = self.combine_substructure.borrow_mut();
let f: &mut CombineSubstructureFunc<'_> = &mut *f;
f(cx, span, &substructure)
@ -876,7 +842,7 @@ impl<'a> MethodDef<'a> {
}
fn is_static(&self) -> bool {
self.explicit_self.is_none()
!self.explicit_self
}
fn split_self_nonself_args(
@ -889,17 +855,15 @@ impl<'a> MethodDef<'a> {
let mut self_args = Vec::new();
let mut nonself_args = Vec::new();
let mut arg_tys = Vec::new();
let mut nonstatic = false;
let span = trait_.span;
let ast_explicit_self = self.explicit_self.as_ref().map(|self_ptr| {
let (self_expr, explicit_self) = ty::get_explicit_self(cx, span, self_ptr);
let ast_explicit_self = if self.explicit_self {
let (self_expr, explicit_self) = ty::get_explicit_self(cx, span);
self_args.push(self_expr);
nonstatic = true;
explicit_self
});
Some(explicit_self)
} else {
None
};
for (ty, name) in self.args.iter() {
let ast_ty = ty.to_ty(cx, span, type_ident, generics);
@ -911,10 +875,10 @@ impl<'a> MethodDef<'a> {
match *ty {
// for static methods, just treat any Self
// arguments as a normal arg
Self_ if nonstatic => {
Self_ if !self.is_static() => {
self_args.push(arg_expr);
}
Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => {
Ref(ref ty, _) if matches!(**ty, Self_) && !self.is_static() => {
self_args.push(cx.expr_deref(span, arg_expr))
}
_ => {
@ -955,15 +919,9 @@ impl<'a> MethodDef<'a> {
let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
let body_block = cx.block_expr(body);
let unsafety = if self.is_unsafe { ast::Unsafe::Yes(span) } else { ast::Unsafe::No };
let trait_lo_sp = span.shrink_to_lo();
let sig = ast::FnSig {
header: ast::FnHeader { unsafety, ext: ast::Extern::None, ..ast::FnHeader::default() },
decl: fn_decl,
span,
};
let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span };
let defaultness = ast::Defaultness::Final;
// Create the method.
@ -1083,7 +1041,6 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
self_args,
nonself_args,
&Struct(struct_def, fields),
);
@ -1104,7 +1061,6 @@ impl<'a> MethodDef<'a> {
trait_: &TraitDef<'_>,
struct_def: &VariantData,
type_ident: Ident,
self_args: &[P<Expr>],
nonself_args: &[P<Expr>],
) -> P<Expr> {
let summary = trait_.summarise_struct(cx, struct_def);
@ -1113,7 +1069,6 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
self_args,
nonself_args,
&StaticStruct(struct_def, summary),
)
@ -1184,11 +1139,6 @@ impl<'a> MethodDef<'a> {
)
.collect::<Vec<String>>();
let self_arg_idents = self_arg_names
.iter()
.map(|name| Ident::from_str_and_span(name, span))
.collect::<Vec<Ident>>();
// The `vi_idents` will be bound, solely in the catch-all, to
// a series of let statements mapping each self_arg to an int
// value corresponding to its discriminant.
@ -1203,8 +1153,7 @@ impl<'a> MethodDef<'a> {
// Builds, via callback to call_substructure_method, the
// delegated expression that handles the catch-all case,
// using `__variants_tuple` to drive logic if necessary.
let catch_all_substructure =
EnumNonMatchingCollapsed(self_arg_idents, &variants, &vi_idents);
let catch_all_substructure = EnumNonMatchingCollapsed(&vi_idents);
let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
@ -1303,7 +1252,6 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
&self_args[..],
nonself_args,
&substructure,
);
@ -1322,7 +1270,6 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
&self_args[..],
nonself_args,
&substructure,
))
@ -1393,7 +1340,6 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
&self_args[..],
nonself_args,
&catch_all_substructure,
);
@ -1491,7 +1437,6 @@ impl<'a> MethodDef<'a> {
trait_: &TraitDef<'_>,
enum_def: &EnumDef,
type_ident: Ident,
self_args: &[P<Expr>],
nonself_args: &[P<Expr>],
) -> P<Expr> {
let summary = enum_def
@ -1507,7 +1452,6 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
self_args,
nonself_args,
&StaticEnum(enum_def, summary),
)
@ -1628,7 +1572,7 @@ impl<'a> TraitDef<'a> {
// helpful premade recipes
pub fn cs_fold_fields<'a, F>(
fn cs_fold_fields<'a, F>(
use_foldl: bool,
mut f: F,
base: P<Expr>,
@ -1650,21 +1594,19 @@ where
}
}
pub fn cs_fold_enumnonmatch(
fn cs_fold_enumnonmatch(
mut enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
cx: &mut ExtCtxt<'_>,
trait_span: Span,
substructure: &Substructure<'_>,
) -> P<Expr> {
match *substructure.fields {
EnumNonMatchingCollapsed(ref all_args, _, tuple) => {
enum_nonmatch_f(cx, trait_span, (&all_args[..], tuple), substructure.nonself_args)
}
EnumNonMatchingCollapsed(tuple) => enum_nonmatch_f(cx, trait_span, tuple),
_ => cx.span_bug(trait_span, "cs_fold_enumnonmatch expected an EnumNonMatchingCollapsed"),
}
}
pub fn cs_fold_static(cx: &mut ExtCtxt<'_>, trait_span: Span) -> P<Expr> {
fn cs_fold_static(cx: &mut ExtCtxt<'_>, trait_span: Span) -> P<Expr> {
cx.span_bug(trait_span, "static function in `derive`")
}
@ -1717,22 +1659,21 @@ where
{
match *substructure.fields {
EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => {
let (base, all_fields) = match (all_fields.is_empty(), use_foldl) {
let (base, rest) = match (all_fields.is_empty(), use_foldl) {
(false, true) => {
let field = &all_fields[0];
let args = (field.span, field.self_.clone(), &field.other[..]);
(b(cx, Some(args)), &all_fields[1..])
let (first, rest) = all_fields.split_first().unwrap();
let args = (first.span, first.self_.clone(), &first.other[..]);
(b(cx, Some(args)), rest)
}
(false, false) => {
let idx = all_fields.len() - 1;
let field = &all_fields[idx];
let args = (field.span, field.self_.clone(), &field.other[..]);
(b(cx, Some(args)), &all_fields[..idx])
let (last, rest) = all_fields.split_last().unwrap();
let args = (last.span, last.self_.clone(), &last.other[..]);
(b(cx, Some(args)), rest)
}
(true, _) => (b(cx, None), &all_fields[..]),
};
cs_fold_fields(use_foldl, f, base, cx, all_fields)
cs_fold_fields(use_foldl, f, base, cx, rest)
}
EnumNonMatchingCollapsed(..) => {
cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)

View File

@ -1,7 +1,6 @@
//! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use
//! when specifying impls to be derived.
pub use PtrTy::*;
pub use Ty::*;
use rustc_ast::ptr::P;
@ -11,22 +10,11 @@ use rustc_span::source_map::{respan, DUMMY_SP};
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::Span;
/// The types of pointers
#[derive(Clone)]
pub enum PtrTy {
/// &'lifetime mut
Borrowed(Option<Ident>, ast::Mutability),
/// *mut
#[allow(dead_code)]
Raw(ast::Mutability),
}
/// A path, e.g., `::std::option::Option::<i32>` (global). Has support
/// for type parameters and a lifetime.
/// for type parameters.
#[derive(Clone)]
pub struct Path {
path: Vec<Symbol>,
lifetime: Option<Ident>,
params: Vec<Box<Ty>>,
kind: PathKind,
}
@ -40,18 +28,13 @@ pub enum PathKind {
impl Path {
pub fn new(path: Vec<Symbol>) -> Path {
Path::new_(path, None, Vec::new(), PathKind::Std)
Path::new_(path, Vec::new(), PathKind::Std)
}
pub fn new_local(path: Symbol) -> Path {
Path::new_(vec![path], None, Vec::new(), PathKind::Local)
Path::new_(vec![path], Vec::new(), PathKind::Local)
}
pub fn new_(
path: Vec<Symbol>,
lifetime: Option<Ident>,
params: Vec<Box<Ty>>,
kind: PathKind,
) -> Path {
Path { path, lifetime, params, kind }
pub fn new_(path: Vec<Symbol>, params: Vec<Box<Ty>>, kind: PathKind) -> Path {
Path { path, params, kind }
}
pub fn to_ty(
@ -71,10 +54,8 @@ impl Path {
self_generics: &Generics,
) -> ast::Path {
let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect();
let lt = mk_lifetimes(cx, span, &self.lifetime);
let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics));
let params =
lt.into_iter().map(GenericArg::Lifetime).chain(tys.map(GenericArg::Type)).collect();
let params = tys.map(GenericArg::Type).collect();
match self.kind {
PathKind::Global => cx.path_all(span, true, idents, params),
@ -92,40 +73,17 @@ impl Path {
#[derive(Clone)]
pub enum Ty {
Self_,
/// &/Box/ Ty
Ptr(Box<Ty>, PtrTy),
/// A reference.
Ref(Box<Ty>, ast::Mutability),
/// `mod::mod::Type<[lifetime], [Params...]>`, including a plain type
/// parameter, and things like `i32`
Literal(Path),
/// includes unit
Tuple(Vec<Ty>),
Path(Path),
/// For () return types.
Unit,
}
pub fn borrowed_ptrty() -> PtrTy {
Borrowed(None, ast::Mutability::Not)
}
pub fn borrowed(ty: Box<Ty>) -> Ty {
Ptr(ty, borrowed_ptrty())
}
pub fn borrowed_explicit_self() -> Option<Option<PtrTy>> {
Some(Some(borrowed_ptrty()))
}
pub fn borrowed_self() -> Ty {
borrowed(Box::new(Self_))
}
pub fn nil_ty() -> Ty {
Tuple(Vec::new())
}
fn mk_lifetime(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Option<ast::Lifetime> {
lt.map(|ident| cx.lifetime(span, ident))
}
fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Vec<ast::Lifetime> {
mk_lifetime(cx, span, lt).into_iter().collect()
pub fn self_ref() -> Ty {
Ref(Box::new(Self_), ast::Mutability::Not)
}
impl Ty {
@ -136,23 +94,15 @@ impl Ty {
self_ty: Ident,
self_generics: &Generics,
) -> P<ast::Ty> {
match *self {
Ptr(ref ty, ref ptr) => {
match self {
Ref(ty, mutbl) => {
let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
match *ptr {
Borrowed(ref lt, mutbl) => {
let lt = mk_lifetime(cx, span, lt);
cx.ty_rptr(span, raw_ty, lt, mutbl)
}
Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl),
}
cx.ty_rptr(span, raw_ty, None, *mutbl)
}
Literal(ref p) => p.to_ty(cx, span, self_ty, self_generics),
Path(p) => p.to_ty(cx, span, self_ty, self_generics),
Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)),
Tuple(ref fields) => {
let ty = ast::TyKind::Tup(
fields.iter().map(|f| f.to_ty(cx, span, self_ty, self_generics)).collect(),
);
Unit => {
let ty = ast::TyKind::Tup(vec![]);
cx.ty(span, ty)
}
}
@ -185,9 +135,9 @@ impl Ty {
cx.path_all(span, false, vec![self_ty], params)
}
Literal(ref p) => p.to_path(cx, span, self_ty, generics),
Ptr(..) => cx.span_bug(span, "pointer in a path in generic `derive`"),
Tuple(..) => cx.span_bug(span, "tuple in a path in generic `derive`"),
Path(ref p) => p.to_path(cx, span, self_ty, generics),
Ref(..) => cx.span_bug(span, "ref in a path in generic `derive`"),
Unit => cx.span_bug(span, "unit in a path in generic `derive`"),
}
}
}
@ -245,28 +195,10 @@ impl Bounds {
}
}
pub fn get_explicit_self(
cx: &ExtCtxt<'_>,
span: Span,
self_ptr: &Option<PtrTy>,
) -> (P<Expr>, ast::ExplicitSelf) {
pub fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P<Expr>, ast::ExplicitSelf) {
// this constructs a fresh `self` path
let self_path = cx.expr_self(span);
match *self_ptr {
None => (self_path, respan(span, SelfKind::Value(ast::Mutability::Not))),
Some(ref ptr) => {
let self_ty = respan(
span,
match *ptr {
Borrowed(ref lt, mutbl) => {
let lt = lt.map(|s| cx.lifetime(span, s));
SelfKind::Region(lt, mutbl)
}
Raw(_) => cx.span_bug(span, "attempted to use *self in deriving definition"),
},
);
let self_expr = cx.expr_deref(span, self_path);
(self_expr, self_ty)
}
}
let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not));
let self_expr = cx.expr_deref(span, self_path);
(self_expr, self_ty)
}

View File

@ -15,7 +15,7 @@ pub fn expand_deriving_hash(
item: &Annotatable,
push: &mut dyn FnMut(Annotatable),
) {
let path = Path::new_(pathvec_std!(hash::Hash), None, vec![], PathKind::Std);
let path = Path::new_(pathvec_std!(hash::Hash), vec![], PathKind::Std);
let typaram = sym::__H;
@ -26,16 +26,14 @@ pub fn expand_deriving_hash(
path,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::hash,
generics: Bounds { bounds: vec![(typaram, vec![path_std!(hash::Hasher)])] },
explicit_self: borrowed_explicit_self(),
args: vec![(Ptr(Box::new(Literal(arg)), Borrowed(None, Mutability::Mut)), sym::state)],
ret_ty: nil_ty(),
explicit_self: true,
args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)],
ret_ty: Unit,
attributes: vec![],
is_unsafe: false,
unify_fieldless_variants: true,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
hash_substructure(a, b, c)

View File

@ -19,11 +19,9 @@ use rustc_target::abi::{self, Abi};
use std::borrow::Cow;
use std::convert::TryInto;
pub fn note_on_undefined_behavior_error() -> &'static str {
"The rules on what exactly is undefined behavior aren't clear, \
const NOTE_ON_UNDEFINED_BEHAVIOR_ERROR: &str = "The rules on what exactly is undefined behavior aren't clear, \
so this check might be overzealous. Please open an issue on the rustc \
repository if you believe it should not be considered undefined behavior."
}
repository if you believe it should not be considered undefined behavior.";
// Returns a pointer to where the result lives
fn eval_body_using_ecx<'mir, 'tcx>(
@ -375,7 +373,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
ecx.tcx,
"it is undefined behavior to use this value",
|diag| {
diag.note(note_on_undefined_behavior_error());
diag.note(NOTE_ON_UNDEFINED_BEHAVIOR_ERROR);
diag.note(&format!(
"the raw bytes of the constant ({}",
display_allocation(

View File

@ -1098,12 +1098,12 @@ impl EarlyLintPass for UnusedDocComment {
}
fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
warn_if_doc(cx, block.span, "block", &block.attrs());
warn_if_doc(cx, block.span, "blocks", &block.attrs());
}
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
if let ast::ItemKind::ForeignMod(_) = item.kind {
warn_if_doc(cx, item.span, "extern block", &item.attrs);
warn_if_doc(cx, item.span, "extern blocks", &item.attrs);
}
}
}

View File

@ -38,7 +38,9 @@ use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::astconv_object_safety_violations;
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
use rustc_trait_selection::traits::error_reporting::{
report_object_safety_error, suggestions::NextTypeParamName,
};
use rustc_trait_selection::traits::wf::object_region_bounds;
use smallvec::SmallVec;
@ -2986,6 +2988,50 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Some(r)
}
/// Make sure that we are in the condition to suggest the blanket implementation.
fn maybe_lint_blanket_trait_impl<T: rustc_errors::EmissionGuarantee>(
&self,
self_ty: &hir::Ty<'_>,
diag: &mut DiagnosticBuilder<'_, T>,
) {
let tcx = self.tcx();
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id);
if let hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Impl(hir::Impl {
self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
}),
..
}) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
{
if !of_trait_ref.trait_def_id().map_or(false, |def_id| def_id.is_local()) {
return;
}
let of_trait_span = of_trait_ref.path.span;
// make sure that we are not calling unwrap to abort during the compilation
let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
// check if the trait has generics, to make a correct suggestion
let param_name = generics.params.next_type_param_name(None);
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
(span, format!(", {}: {}", param_name, impl_trait_name))
} else {
(generics.span, format!("<{}: {}>", param_name, impl_trait_name))
};
diag.multipart_suggestion(
format!("alternatively use a blanket \
implementation to implement `{of_trait_name}` for \
all types that also implement `{impl_trait_name}`"),
vec![
(self_ty.span, param_name),
add_generic_sugg,
],
Applicability::MaybeIncorrect,
);
}
}
fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
let tcx = self.tcx();
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
@ -3021,9 +3067,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if self_ty.span.edition() >= Edition::Edition2021 {
let msg = "trait objects must include the `dyn` keyword";
let label = "add `dyn` keyword before this trait";
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg)
.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable)
.emit();
let mut diag =
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
// check if the impl trait that we are considering is a impl of a local trait
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
diag.emit();
} else {
let msg = "trait objects without an explicit `dyn` are deprecated";
tcx.struct_span_lint_hir(
@ -3031,13 +3080,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty.hir_id,
self_ty.span,
|lint| {
lint.build(msg)
.multipart_suggestion_verbose(
"use `dyn`",
sugg,
Applicability::MachineApplicable,
)
.emit();
let mut diag = lint.build(msg);
diag.multipart_suggestion_verbose(
"use `dyn`",
sugg,
Applicability::MachineApplicable,
);
self.maybe_lint_blanket_trait_impl::<()>(&self_ty, &mut diag);
diag.emit();
},
);
}

View File

@ -1707,12 +1707,14 @@ fn drop_location_span<'tcx>(tcx: TyCtxt<'tcx>, hir_id: hir::HirId) -> Span {
hir::Node::Item(item) => match item.kind {
hir::ItemKind::Fn(_, _, owner_id) => tcx.hir().span(owner_id.hir_id),
_ => {
bug!("Drop location span error: need to handle more ItemKind {:?}", item.kind);
bug!("Drop location span error: need to handle more ItemKind '{:?}'", item.kind);
}
},
hir::Node::Block(block) => tcx.hir().span(block.hir_id),
hir::Node::TraitItem(item) => tcx.hir().span(item.hir_id()),
hir::Node::ImplItem(item) => tcx.hir().span(item.hir_id()),
_ => {
bug!("Drop location span error: need to handle more Node {:?}", owner_node);
bug!("Drop location span error: need to handle more Node '{:?}'", owner_node);
}
};
tcx.sess.source_map().end_point(owner_span)

View File

@ -31,7 +31,9 @@ use core::ptr::{self, NonNull};
/// ```
#[unstable(feature = "thin_box", issue = "92791")]
pub struct ThinBox<T: ?Sized> {
ptr: WithHeader<<T as Pointee>::Metadata>,
// This is essentially `WithHeader<<T as Pointee>::Metadata>`,
// but that would be invariant in `T`, and we want covariance.
ptr: WithOpaqueHeader,
_marker: PhantomData<T>,
}
@ -59,7 +61,7 @@ impl<T> ThinBox<T> {
#[cfg(not(no_global_oom_handling))]
pub fn new(value: T) -> Self {
let meta = ptr::metadata(&value);
let ptr = WithHeader::new(meta, value);
let ptr = WithOpaqueHeader::new(meta, value);
ThinBox { ptr, _marker: PhantomData }
}
}
@ -83,7 +85,7 @@ impl<Dyn: ?Sized> ThinBox<Dyn> {
T: Unsize<Dyn>,
{
let meta = ptr::metadata(&value as &Dyn);
let ptr = WithHeader::new(meta, value);
let ptr = WithOpaqueHeader::new(meta, value);
ThinBox { ptr, _marker: PhantomData }
}
}
@ -130,7 +132,7 @@ impl<T: ?Sized> Drop for ThinBox<T> {
unsafe {
let value = self.deref_mut();
let value = value as *mut T;
self.ptr.drop::<T>(value);
self.with_header().drop::<T>(value);
}
}
}
@ -140,11 +142,16 @@ impl<T: ?Sized> ThinBox<T> {
fn meta(&self) -> <T as Pointee>::Metadata {
// Safety:
// - NonNull and valid.
unsafe { *self.ptr.header() }
unsafe { *self.with_header().header() }
}
fn data(&self) -> *mut u8 {
self.ptr.value()
self.with_header().value()
}
fn with_header(&self) -> &WithHeader<<T as Pointee>::Metadata> {
// SAFETY: both types are transparent to `NonNull<u8>`
unsafe { &*((&self.ptr) as *const WithOpaqueHeader as *const WithHeader<_>) }
}
}
@ -153,8 +160,22 @@ impl<T: ?Sized> ThinBox<T> {
/// metadata (`H`) are ZSTs.
/// 2. A pointer to a valid `T` that has a header `H` directly before the
/// pointed-to location.
#[repr(transparent)]
struct WithHeader<H>(NonNull<u8>, PhantomData<H>);
/// An opaque representation of `WithHeader<H>` to avoid the
/// projection invariance of `<T as Pointee>::Metadata`.
#[repr(transparent)]
struct WithOpaqueHeader(NonNull<u8>);
impl WithOpaqueHeader {
#[cfg(not(no_global_oom_handling))]
fn new<H, T>(header: H, value: T) -> Self {
let ptr = WithHeader::new(header, value);
Self(ptr.0)
}
}
impl<H> WithHeader<H> {
#[cfg(not(no_global_oom_handling))]
fn new<T>(header: H, value: T) -> WithHeader<H> {

View File

@ -26,6 +26,13 @@ fn want_thin() {
assert!(is_thin::<i32>());
}
#[allow(dead_code)]
fn assert_covariance() {
fn thin_box<'new>(b: ThinBox<[&'static str]>) -> ThinBox<[&'new str]> {
b
}
}
#[track_caller]
fn verify_aligned<T>(ptr: *const T) {
// Use `black_box` to attempt to obscure the fact that we're calling this

View File

@ -71,7 +71,7 @@ LL |
LL | / extern "C" {
LL | | fn foo();
LL | | }
| |_- rustdoc does not generate documentation for extern block
| |_- rustdoc does not generate documentation for extern blocks
|
= help: use `//` for a plain comment

View File

@ -0,0 +1,18 @@
// compile-flags: -Wrust-2021-incompatible-closure-captures
pub struct A {}
impl A {
async fn create(path: impl AsRef<std::path::Path>) { //~ ERROR `async fn` is not permitted in Rust 2015
//~^ WARN changes to closure capture in Rust 2021 will affect drop order [rust_2021_incompatible_closure_captures]
;
crate(move || {} ).await //~ ERROR expected function, found module `crate`
}
}
trait C{async fn new(val: T) {} //~ ERROR `async fn` is not permitted in Rust 2015
//~^ ERROR functions in traits cannot be declared `async`
//~^^ ERROR cannot find type `T` in this scope
//~^^^ WARN changes to closure capture in Rust 2021 will affect drop order [rust_2021_incompatible_closure_captures]
//~ ERROR this file contains an unclosed delimiter

View File

@ -0,0 +1,93 @@
error: this file contains an unclosed delimiter
--> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:18:53
|
LL | trait C{async fn new(val: T) {}
| - unclosed delimiter
...
LL |
| ^
error[E0670]: `async fn` is not permitted in Rust 2015
--> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:6:5
|
LL | async fn create(path: impl AsRef<std::path::Path>) {
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
= help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
--> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:9
|
LL | trait C{async fn new(val: T) {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
= help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0706]: functions in traits cannot be declared `async`
--> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:9
|
LL | trait C{async fn new(val: T) {}
| -----^^^^^^^^^^^^^^^^^^
| |
| `async` because of this
|
= note: `async` trait functions are not currently supported
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
error[E0423]: expected function, found module `crate`
--> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:9:5
|
LL | crate(move || {} ).await
| ^^^^^ not a function
error[E0412]: cannot find type `T` in this scope
--> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:27
|
LL | pub struct A {}
| ------------ similarly named struct `A` defined here
...
LL | trait C{async fn new(val: T) {}
| ^ help: a struct with a similar name exists: `A`
warning: changes to closure capture in Rust 2021 will affect drop order
--> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:6:57
|
LL | async fn create(path: impl AsRef<std::path::Path>) {
| _____________________----_____________________________-__^
| | | |
| | | in Rust 2018, `path` is dropped here along with the closure, but in Rust 2021 `path` is not part of the closure
| | in Rust 2018, this causes the closure to capture `path`, but in Rust 2021, it has no effect
LL | |
LL | | ;
LL | | crate(move || {} ).await
LL | | }
| |_____^
|
= note: requested on the command line with `-W rust-2021-incompatible-closure-captures`
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `path` to be fully captured
|
LL | async fn create(path: impl AsRef<std::path::Path>) { let _ = &path;
| ++++++++++++++
warning: changes to closure capture in Rust 2021 will affect drop order
--> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:30
|
LL | trait C{async fn new(val: T) {}
| --- - ^^
| | |
| | in Rust 2018, `val` is dropped here along with the closure, but in Rust 2021 `val` is not part of the closure
| in Rust 2018, this causes the closure to capture `val`, but in Rust 2021, it has no effect
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `val` to be fully captured
|
LL | trait C{async fn new(val: T) { let _ = &val;}
| +++++++++++++
error: aborting due to 6 previous errors; 2 warnings emitted
Some errors have detailed explanations: E0412, E0423, E0670, E0706.
For more information about an error, try `rustc --explain E0412`.

View File

@ -0,0 +1,15 @@
// compile-flags -Wrust-2021-incompatible-closure-captures
fn main() {}
pub(crate) struct Numberer {}
impl Numberer {
pub(crate) async fn new(
//~^ ERROR `async fn` is not permitted in Rust 2015
interval: Duration,
//~^ ERROR cannot find type `Duration` in this scope
) -> Numberer {
Numberer {}
}
}

View File

@ -0,0 +1,24 @@
error[E0670]: `async fn` is not permitted in Rust 2015
--> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:8:16
|
LL | pub(crate) async fn new(
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
= help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0412]: cannot find type `Duration` in this scope
--> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:10:19
|
LL | interval: Duration,
| ^^^^^^^^ not found in this scope
|
help: consider importing this struct
|
LL | use std::time::Duration;
|
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0412, E0670.
For more information about an error, try `rustc --explain E0412`.

View File

@ -0,0 +1,58 @@
// Ensure that the compiler include the blanklet implementation suggestion
// when inside a `impl` statment are used two local traits.
//
// edition:2021
use std::fmt;
trait LocalTraitOne { }
trait LocalTraitTwo { }
trait GenericTrait<T> {}
impl LocalTraitTwo for LocalTraitOne {}
//~^ ERROR trait objects must include the `dyn` keyword
//~| HELP add `dyn` keyword before this trait
//~| HELP alternatively use a blanket implementation to implement `LocalTraitTwo` for all types that also implement `LocalTraitOne`
impl fmt::Display for LocalTraitOne {
//~^ ERROR trait objects must include the `dyn` keyword
//~| HELP add `dyn` keyword before this trait
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
todo!();
}
}
impl fmt::Display for LocalTraitTwo + Send {
//~^ ERROR trait objects must include the `dyn` keyword
//~| HELP add `dyn` keyword before this trait
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
todo!();
}
}
impl LocalTraitOne for fmt::Display {}
//~^ ERROR trait objects must include the `dyn` keyword
//~| HELP add `dyn` keyword before this trait
//~| HELP alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display`
impl LocalTraitOne for fmt::Display + Send {}
//~^ ERROR trait objects must include the `dyn` keyword
//~| HELP add `dyn` keyword before this trait
//~| HELP alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display + Send`
impl<E> GenericTrait<E> for LocalTraitOne {}
//~^ ERROR trait objects must include the `dyn` keyword
//~| HELP add `dyn` keyword before this trait
//~| HELP alternatively use a blanket implementation to implement `GenericTrait<E>` for all types that also implement `LocalTraitOne`
trait GenericTraitTwo<T> {}
impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
//~^ ERROR trait objects must include the `dyn` keyword
//~| HELP add `dyn` keyword before this trait
//~| HELP alternatively use a blanket implementation to implement `GenericTraitTwo<E>` for all types that also implement `GenericTrait<T>`
fn main() {}

View File

@ -0,0 +1,107 @@
error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/suggest-blanket-impl-local-trait.rs:13:24
|
LL | impl LocalTraitTwo for LocalTraitOne {}
| ^^^^^^^^^^^^^
|
help: add `dyn` keyword before this trait
|
LL - impl LocalTraitTwo for LocalTraitOne {}
LL + impl LocalTraitTwo for dyn LocalTraitOne {}
|
help: alternatively use a blanket implementation to implement `LocalTraitTwo` for all types that also implement `LocalTraitOne`
|
LL | impl<T: LocalTraitOne> LocalTraitTwo for T {}
| ++++++++++++++++++ ~
error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/suggest-blanket-impl-local-trait.rs:18:23
|
LL | impl fmt::Display for LocalTraitOne {
| ^^^^^^^^^^^^^
|
help: add `dyn` keyword before this trait
|
LL - impl fmt::Display for LocalTraitOne {
LL + impl fmt::Display for dyn LocalTraitOne {
|
error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/suggest-blanket-impl-local-trait.rs:26:23
|
LL | impl fmt::Display for LocalTraitTwo + Send {
| ^^^^^^^^^^^^^^^^^^^^
|
help: add `dyn` keyword before this trait
|
LL - impl fmt::Display for LocalTraitTwo + Send {
LL + impl fmt::Display for dyn LocalTraitTwo + Send {
|
error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/suggest-blanket-impl-local-trait.rs:34:24
|
LL | impl LocalTraitOne for fmt::Display {}
| ^^^^^^^^^^^^
|
help: add `dyn` keyword before this trait
|
LL - impl LocalTraitOne for fmt::Display {}
LL + impl LocalTraitOne for dyn fmt::Display {}
|
help: alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display`
|
LL | impl<T: fmt::Display> LocalTraitOne for T {}
| +++++++++++++++++ ~
error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/suggest-blanket-impl-local-trait.rs:40:24
|
LL | impl LocalTraitOne for fmt::Display + Send {}
| ^^^^^^^^^^^^^^^^^^^
|
help: add `dyn` keyword before this trait
|
LL - impl LocalTraitOne for fmt::Display + Send {}
LL + impl LocalTraitOne for dyn fmt::Display + Send {}
|
help: alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display + Send`
|
LL | impl<T: fmt::Display + Send> LocalTraitOne for T {}
| ++++++++++++++++++++++++ ~
error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/suggest-blanket-impl-local-trait.rs:46:29
|
LL | impl<E> GenericTrait<E> for LocalTraitOne {}
| ^^^^^^^^^^^^^
|
help: add `dyn` keyword before this trait
|
LL - impl<E> GenericTrait<E> for LocalTraitOne {}
LL + impl<E> GenericTrait<E> for dyn LocalTraitOne {}
|
help: alternatively use a blanket implementation to implement `GenericTrait<E>` for all types that also implement `LocalTraitOne`
|
LL | impl<E, T: LocalTraitOne> GenericTrait<E> for T {}
| ++++++++++++++++++ ~
error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/suggest-blanket-impl-local-trait.rs:53:35
|
LL | impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
| ^^^^^^^^^^^^^^^
|
help: add `dyn` keyword before this trait
|
LL - impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
LL + impl<T, E> GenericTraitTwo<E> for dyn GenericTrait<T> {}
|
help: alternatively use a blanket implementation to implement `GenericTraitTwo<E>` for all types that also implement `GenericTrait<T>`
|
LL | impl<T, E, U: GenericTrait<T>> GenericTraitTwo<E> for U {}
| ++++++++++++++++++++ ~
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0782`.

BIN
suggest-blanket-impl-local-trait Executable file

Binary file not shown.