diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 39d0f2c7305f..8387e4499ae3 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -11,6 +11,7 @@ use crate::ast::*; use crate::ptr::P; use crate::token::{self, Token}; use crate::tokenstream::*; +use crate::visit::{AssocCtxt, BoundKind}; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -34,8 +35,8 @@ impl ExpectOne for SmallVec { } } -pub trait NoopVisitItemKind { - fn noop_visit(&mut self, visitor: &mut impl MutVisitor); +pub trait WalkItemKind { + fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor); } pub trait MutVisitor: Sized { @@ -78,79 +79,84 @@ pub trait MutVisitor: Sized { // forget to add handling for it. fn visit_crate(&mut self, c: &mut Crate) { - noop_visit_crate(c, self) + walk_crate(self, c) } fn visit_meta_list_item(&mut self, list_item: &mut NestedMetaItem) { - noop_visit_meta_list_item(list_item, self); + walk_meta_list_item(self, list_item); } fn visit_meta_item(&mut self, meta_item: &mut MetaItem) { - noop_visit_meta_item(meta_item, self); + walk_meta_item(self, meta_item); } fn visit_use_tree(&mut self, use_tree: &mut UseTree) { - noop_visit_use_tree(use_tree, self); + walk_use_tree(self, use_tree); } fn flat_map_foreign_item(&mut self, ni: P) -> SmallVec<[P; 1]> { - noop_flat_map_item(ni, self) + walk_flat_map_item(self, ni) } fn flat_map_item(&mut self, i: P) -> SmallVec<[P; 1]> { - noop_flat_map_item(i, self) + walk_flat_map_item(self, i) } fn visit_fn_header(&mut self, header: &mut FnHeader) { - noop_visit_fn_header(header, self); + walk_fn_header(self, header); } fn flat_map_field_def(&mut self, fd: FieldDef) -> SmallVec<[FieldDef; 1]> { - noop_flat_map_field_def(fd, self) + walk_flat_map_field_def(self, fd) } - fn flat_map_trait_item(&mut self, i: P) -> SmallVec<[P; 1]> { - noop_flat_map_item(i, self) - } - - fn flat_map_impl_item(&mut self, i: P) -> SmallVec<[P; 1]> { - noop_flat_map_item(i, self) + fn flat_map_assoc_item( + &mut self, + i: P, + _ctxt: AssocCtxt, + ) -> SmallVec<[P; 1]> { + walk_flat_map_item(self, i) } fn visit_fn_decl(&mut self, d: &mut P) { - noop_visit_fn_decl(d, self); + walk_fn_decl(self, d); + } + + /// `Span` and `NodeId` are mutated at the caller site. + fn visit_fn(&mut self, fk: FnKind<'_>, _: Span, _: NodeId) { + walk_fn(self, fk) } fn visit_coroutine_kind(&mut self, a: &mut CoroutineKind) { - noop_visit_coroutine_kind(a, self); + walk_coroutine_kind(self, a); } fn visit_closure_binder(&mut self, b: &mut ClosureBinder) { - noop_visit_closure_binder(b, self); + walk_closure_binder(self, b); } fn visit_block(&mut self, b: &mut P) { - noop_visit_block(b, self); + walk_block(self, b); } fn flat_map_stmt(&mut self, s: Stmt) -> SmallVec<[Stmt; 1]> { - noop_flat_map_stmt(s, self) + walk_flat_map_stmt(self, s) } fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> { - noop_flat_map_arm(arm, self) + walk_flat_map_arm(self, arm) } fn visit_pat(&mut self, p: &mut P) { - noop_visit_pat(p, self); + walk_pat(self, p); } fn visit_anon_const(&mut self, c: &mut AnonConst) { - noop_visit_anon_const(c, self); + walk_anon_const(self, c); } fn visit_expr(&mut self, e: &mut P) { - noop_visit_expr(e, self); + walk_expr(self, e); } /// This method is a hack to workaround unstable of `stmt_expr_attributes`. @@ -160,127 +166,131 @@ pub trait MutVisitor: Sized { } fn filter_map_expr(&mut self, e: P) -> Option> { - noop_filter_map_expr(e, self) + noop_filter_map_expr(self, e) } fn visit_generic_arg(&mut self, arg: &mut GenericArg) { - noop_visit_generic_arg(arg, self); + walk_generic_arg(self, arg); } fn visit_ty(&mut self, t: &mut P) { - noop_visit_ty(t, self); + walk_ty(self, t); } fn visit_lifetime(&mut self, l: &mut Lifetime) { - noop_visit_lifetime(l, self); + walk_lifetime(self, l); } fn visit_assoc_item_constraint(&mut self, c: &mut AssocItemConstraint) { - noop_visit_assoc_item_constraint(c, self); + walk_assoc_item_constraint(self, c); } fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) { - noop_visit_foreign_mod(nm, self); + walk_foreign_mod(self, nm); } fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> { - noop_flat_map_variant(v, self) + walk_flat_map_variant(self, v) } fn visit_ident(&mut self, i: &mut Ident) { - noop_visit_ident(i, self); + walk_ident(self, i); } fn visit_path(&mut self, p: &mut Path) { - noop_visit_path(p, self); + walk_path(self, p); + } + + fn visit_path_segment(&mut self, p: &mut PathSegment) { + walk_path_segment(self, p) } fn visit_qself(&mut self, qs: &mut Option>) { - noop_visit_qself(qs, self); + walk_qself(self, qs); } fn visit_generic_args(&mut self, p: &mut GenericArgs) { - noop_visit_generic_args(p, self); + walk_generic_args(self, p); } fn visit_angle_bracketed_parameter_data(&mut self, p: &mut AngleBracketedArgs) { - noop_visit_angle_bracketed_parameter_data(p, self); + walk_angle_bracketed_parameter_data(self, p); } fn visit_parenthesized_parameter_data(&mut self, p: &mut ParenthesizedArgs) { - noop_visit_parenthesized_parameter_data(p, self); + walk_parenthesized_parameter_data(self, p); } fn visit_local(&mut self, l: &mut P) { - noop_visit_local(l, self); + walk_local(self, l); } fn visit_mac_call(&mut self, mac: &mut MacCall) { - noop_visit_mac(mac, self); + walk_mac(self, mac); } fn visit_macro_def(&mut self, def: &mut MacroDef) { - noop_visit_macro_def(def, self); + walk_macro_def(self, def); } fn visit_label(&mut self, label: &mut Label) { - noop_visit_label(label, self); + walk_label(self, label); } fn visit_attribute(&mut self, at: &mut Attribute) { - noop_visit_attribute(at, self); + walk_attribute(self, at); } fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> { - noop_flat_map_param(param, self) + walk_flat_map_param(self, param) } fn visit_generics(&mut self, generics: &mut Generics) { - noop_visit_generics(generics, self); + walk_generics(self, generics); } fn visit_trait_ref(&mut self, tr: &mut TraitRef) { - noop_visit_trait_ref(tr, self); + walk_trait_ref(self, tr); } fn visit_poly_trait_ref(&mut self, p: &mut PolyTraitRef) { - noop_visit_poly_trait_ref(p, self); + walk_poly_trait_ref(self, p); } fn visit_variant_data(&mut self, vdata: &mut VariantData) { - noop_visit_variant_data(vdata, self); + walk_variant_data(self, vdata); } fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> { - noop_flat_map_generic_param(param, self) + walk_flat_map_generic_param(self, param) } - fn visit_param_bound(&mut self, tpb: &mut GenericBound) { - noop_visit_param_bound(tpb, self); + fn visit_param_bound(&mut self, tpb: &mut GenericBound, _ctxt: BoundKind) { + walk_param_bound(self, tpb); } fn visit_precise_capturing_arg(&mut self, arg: &mut PreciseCapturingArg) { - noop_visit_precise_capturing_arg(arg, self); + walk_precise_capturing_arg(self, arg); } fn visit_mt(&mut self, mt: &mut MutTy) { - noop_visit_mt(mt, self); + walk_mt(self, mt); } fn flat_map_expr_field(&mut self, f: ExprField) -> SmallVec<[ExprField; 1]> { - noop_flat_map_expr_field(f, self) + walk_flat_map_expr_field(self, f) } fn visit_where_clause(&mut self, where_clause: &mut WhereClause) { - noop_visit_where_clause(where_clause, self); + walk_where_clause(self, where_clause); } fn visit_where_predicate(&mut self, where_predicate: &mut WherePredicate) { - noop_visit_where_predicate(where_predicate, self); + walk_where_predicate(self, where_predicate); } fn visit_vis(&mut self, vis: &mut Visibility) { - noop_visit_vis(vis, self); + walk_vis(self, vis); } fn visit_id(&mut self, _id: &mut NodeId) { @@ -292,23 +302,23 @@ pub trait MutVisitor: Sized { } fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> { - noop_flat_map_pat_field(fp, self) + walk_flat_map_pat_field(self, fp) } fn visit_inline_asm(&mut self, asm: &mut InlineAsm) { - noop_visit_inline_asm(asm, self) + walk_inline_asm(self, asm) } fn visit_inline_asm_sym(&mut self, sym: &mut InlineAsmSym) { - noop_visit_inline_asm_sym(sym, self) + walk_inline_asm_sym(self, sym) } fn visit_format_args(&mut self, fmt: &mut FormatArgs) { - noop_visit_format_args(fmt, self) + walk_format_args(self, fmt) } fn visit_capture_by(&mut self, capture_by: &mut CaptureBy) { - noop_visit_capture_by(capture_by, self) + walk_capture_by(self, capture_by) } } @@ -356,7 +366,7 @@ where } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_attrs(attrs: &mut AttrVec, vis: &mut T) { +fn visit_attrs(vis: &mut T, attrs: &mut AttrVec) { for attr in attrs.iter_mut() { vis.visit_attribute(attr); } @@ -364,32 +374,25 @@ fn visit_attrs(attrs: &mut AttrVec, vis: &mut T) { // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. #[allow(unused)] -fn visit_exprs(exprs: &mut Vec>, vis: &mut T) { +fn visit_exprs(vis: &mut T, exprs: &mut Vec>) { exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr)) } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_thin_exprs(exprs: &mut ThinVec>, vis: &mut T) { +fn visit_thin_exprs(vis: &mut T, exprs: &mut ThinVec>) { exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr)) } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_bounds(bounds: &mut GenericBounds, vis: &mut T) { - visit_vec(bounds, |bound| vis.visit_param_bound(bound)); +fn visit_bounds(vis: &mut T, bounds: &mut GenericBounds, ctxt: BoundKind) { + visit_vec(bounds, |bound| vis.visit_param_bound(bound, ctxt)); } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_fn_sig(FnSig { header, decl, span }: &mut FnSig, vis: &mut T) { - vis.visit_fn_header(header); - vis.visit_fn_decl(decl); - vis.visit_span(span); -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_attr_args(args: &mut AttrArgs, vis: &mut T) { +fn visit_attr_args(vis: &mut T, args: &mut AttrArgs) { match args { AttrArgs::Empty => {} - AttrArgs::Delimited(args) => visit_delim_args(args, vis), + AttrArgs::Delimited(args) => visit_delim_args(vis, args), AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => { vis.visit_expr(expr); vis.visit_span(eq_span); @@ -401,31 +404,31 @@ fn visit_attr_args(args: &mut AttrArgs, vis: &mut T) { } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_delim_args(args: &mut DelimArgs, vis: &mut T) { +fn visit_delim_args(vis: &mut T, args: &mut DelimArgs) { let DelimArgs { dspan, delim: _, tokens } = args; - visit_tts(tokens, vis); - visit_delim_span(dspan, vis); + visit_tts(vis, tokens); + visit_delim_span(vis, dspan); } -pub fn visit_delim_span(DelimSpan { open, close }: &mut DelimSpan, vis: &mut T) { +pub fn visit_delim_span(vis: &mut T, DelimSpan { open, close }: &mut DelimSpan) { vis.visit_span(open); vis.visit_span(close); } -pub fn noop_flat_map_pat_field( - mut fp: PatField, +pub fn walk_flat_map_pat_field( vis: &mut T, + mut fp: PatField, ) -> SmallVec<[PatField; 1]> { let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = &mut fp; vis.visit_id(id); - visit_attrs(attrs, vis); + visit_attrs(vis, attrs); vis.visit_ident(ident); vis.visit_pat(pat); vis.visit_span(span); smallvec![fp] } -fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { +fn walk_use_tree(vis: &mut T, use_tree: &mut UseTree) { let UseTree { prefix, kind, span } = use_tree; vis.visit_path(prefix); match kind { @@ -442,10 +445,10 @@ fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { vis.visit_span(span); } -pub fn noop_flat_map_arm(mut arm: Arm, vis: &mut T) -> SmallVec<[Arm; 1]> { +pub fn walk_flat_map_arm(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> { let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm; vis.visit_id(id); - visit_attrs(attrs, vis); + visit_attrs(vis, attrs); vis.visit_pat(pat); visit_opt(guard, |guard| vis.visit_expr(guard)); visit_opt(body, |body| vis.visit_expr(body)); @@ -453,9 +456,9 @@ pub fn noop_flat_map_arm(mut arm: Arm, vis: &mut T) -> SmallVec<[ smallvec![arm] } -fn noop_visit_assoc_item_constraint( - AssocItemConstraint { id, ident, gen_args, kind, span }: &mut AssocItemConstraint, +fn walk_assoc_item_constraint( vis: &mut T, + AssocItemConstraint { id, ident, gen_args, kind, span }: &mut AssocItemConstraint, ) { vis.visit_id(id); vis.visit_ident(ident); @@ -467,12 +470,12 @@ fn noop_visit_assoc_item_constraint( Term::Ty(ty) => vis.visit_ty(ty), Term::Const(c) => vis.visit_anon_const(c), }, - AssocItemConstraintKind::Bound { bounds } => visit_bounds(bounds, vis), + AssocItemConstraintKind::Bound { bounds } => visit_bounds(vis, bounds, BoundKind::Bound), } vis.visit_span(span); } -pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { +pub fn walk_ty(vis: &mut T, ty: &mut P) { let Ty { id, kind, span, tokens } = ty.deref_mut(); vis.visit_id(id); match kind { @@ -487,7 +490,7 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { } TyKind::BareFn(bft) => { let BareFnTy { safety, ext: _, generic_params, decl, decl_span } = bft.deref_mut(); - visit_safety(safety, vis); + visit_safety(vis, safety); generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_fn_decl(decl); vis.visit_span(decl_span); @@ -508,11 +511,11 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { } TyKind::Typeof(expr) => vis.visit_anon_const(expr), TyKind::TraitObject(bounds, _syntax) => { - visit_vec(bounds, |bound| vis.visit_param_bound(bound)) + visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::TraitObject)) } TyKind::ImplTrait(id, bounds) => { vis.visit_id(id); - visit_vec(bounds, |bound| vis.visit_param_bound(bound)); + visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Impl)); } TyKind::MacCall(mac) => vis.visit_mac_call(mac), TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => { @@ -520,23 +523,23 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); } } - visit_lazy_tts(tokens, vis); + visit_lazy_tts(vis, tokens); vis.visit_span(span); } -fn noop_visit_foreign_mod(foreign_mod: &mut ForeignMod, vis: &mut T) { +fn walk_foreign_mod(vis: &mut T, foreign_mod: &mut ForeignMod) { let ForeignMod { safety, abi: _, items } = foreign_mod; - visit_safety(safety, vis); + visit_safety(vis, safety); items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); } -pub fn noop_flat_map_variant( - mut variant: Variant, +pub fn walk_flat_map_variant( visitor: &mut T, + mut variant: Variant, ) -> SmallVec<[Variant; 1]> { let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant; visitor.visit_id(id); - visit_attrs(attrs, visitor); + visit_attrs(visitor, attrs); visitor.visit_vis(vis); visitor.visit_ident(ident); visitor.visit_variant_data(data); @@ -545,21 +548,26 @@ pub fn noop_flat_map_variant( smallvec![variant] } -fn noop_visit_ident(Ident { name: _, span }: &mut Ident, vis: &mut T) { +fn walk_ident(vis: &mut T, Ident { name: _, span }: &mut Ident) { vis.visit_span(span); } -fn noop_visit_path(Path { segments, span, tokens }: &mut Path, vis: &mut T) { - for PathSegment { ident, id, args } in segments { - vis.visit_id(id); - vis.visit_ident(ident); - visit_opt(args, |args| vis.visit_generic_args(args)); +fn walk_path_segment(vis: &mut T, segment: &mut PathSegment) { + let PathSegment { ident, id, args } = segment; + vis.visit_id(id); + vis.visit_ident(ident); + visit_opt(args, |args| vis.visit_generic_args(args)); +} + +fn walk_path(vis: &mut T, Path { segments, span, tokens }: &mut Path) { + for segment in segments { + vis.visit_path_segment(segment); } - visit_lazy_tts(tokens, vis); + visit_lazy_tts(vis, tokens); vis.visit_span(span); } -fn noop_visit_qself(qself: &mut Option>, vis: &mut T) { +fn walk_qself(vis: &mut T, qself: &mut Option>) { visit_opt(qself, |qself| { let QSelf { ty, path_span, position: _ } = &mut **qself; vis.visit_ty(ty); @@ -567,7 +575,7 @@ fn noop_visit_qself(qself: &mut Option>, vis: &mut T) { }) } -fn noop_visit_generic_args(generic_args: &mut GenericArgs, vis: &mut T) { +fn walk_generic_args(vis: &mut T, generic_args: &mut GenericArgs) { match generic_args { GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data), GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data), @@ -575,7 +583,7 @@ fn noop_visit_generic_args(generic_args: &mut GenericArgs, vis: & } } -fn noop_visit_generic_arg(arg: &mut GenericArg, vis: &mut T) { +fn walk_generic_arg(vis: &mut T, arg: &mut GenericArg) { match arg { GenericArg::Lifetime(lt) => vis.visit_lifetime(lt), GenericArg::Type(ty) => vis.visit_ty(ty), @@ -583,10 +591,7 @@ fn noop_visit_generic_arg(arg: &mut GenericArg, vis: &mut T) { } } -fn noop_visit_angle_bracketed_parameter_data( - data: &mut AngleBracketedArgs, - vis: &mut T, -) { +fn walk_angle_bracketed_parameter_data(vis: &mut T, data: &mut AngleBracketedArgs) { let AngleBracketedArgs { args, span } = data; visit_thin_vec(args, |arg| match arg { AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg), @@ -595,21 +600,18 @@ fn noop_visit_angle_bracketed_parameter_data( vis.visit_span(span); } -fn noop_visit_parenthesized_parameter_data( - args: &mut ParenthesizedArgs, - vis: &mut T, -) { +fn walk_parenthesized_parameter_data(vis: &mut T, args: &mut ParenthesizedArgs) { let ParenthesizedArgs { inputs, output, span, inputs_span } = args; visit_thin_vec(inputs, |input| vis.visit_ty(input)); - noop_visit_fn_ret_ty(output, vis); + walk_fn_ret_ty(vis, output); vis.visit_span(span); vis.visit_span(inputs_span); } -fn noop_visit_local(local: &mut P, vis: &mut T) { +fn walk_local(vis: &mut T, local: &mut P) { let Local { id, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut(); vis.visit_id(id); - visit_attrs(attrs, vis); + visit_attrs(vis, attrs); vis.visit_pat(pat); visit_opt(ty, |ty| vis.visit_ty(ty)); match kind { @@ -622,12 +624,12 @@ fn noop_visit_local(local: &mut P, vis: &mut T) { vis.visit_block(els); } } - visit_lazy_tts(tokens, vis); + visit_lazy_tts(vis, tokens); visit_opt(colon_sp, |sp| vis.visit_span(sp)); vis.visit_span(span); } -fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { +fn walk_attribute(vis: &mut T, attr: &mut Attribute) { let Attribute { kind, id: _, style: _, span } = attr; match kind { AttrKind::Normal(normal) => { @@ -636,34 +638,34 @@ fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { tokens: attr_tokens, } = &mut **normal; vis.visit_path(path); - visit_attr_args(args, vis); - visit_lazy_tts(tokens, vis); - visit_lazy_tts(attr_tokens, vis); + visit_attr_args(vis, args); + visit_lazy_tts(vis, tokens); + visit_lazy_tts(vis, attr_tokens); } AttrKind::DocComment(_kind, _sym) => {} } vis.visit_span(span); } -fn noop_visit_mac(mac: &mut MacCall, vis: &mut T) { +fn walk_mac(vis: &mut T, mac: &mut MacCall) { let MacCall { path, args } = mac; vis.visit_path(path); - visit_delim_args(args, vis); + visit_delim_args(vis, args); } -fn noop_visit_macro_def(macro_def: &mut MacroDef, vis: &mut T) { +fn walk_macro_def(vis: &mut T, macro_def: &mut MacroDef) { let MacroDef { body, macro_rules: _ } = macro_def; - visit_delim_args(body, vis); + visit_delim_args(vis, body); } -fn noop_visit_meta_list_item(li: &mut NestedMetaItem, vis: &mut T) { +fn walk_meta_list_item(vis: &mut T, li: &mut NestedMetaItem) { match li { NestedMetaItem::MetaItem(mi) => vis.visit_meta_item(mi), NestedMetaItem::Lit(_lit) => {} } } -fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { +fn walk_meta_item(vis: &mut T, mi: &mut MetaItem) { let MetaItem { unsafety: _, path: _, kind, span } = mi; match kind { MetaItemKind::Word => {} @@ -673,10 +675,10 @@ fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { vis.visit_span(span); } -pub fn noop_flat_map_param(mut param: Param, vis: &mut T) -> SmallVec<[Param; 1]> { +pub fn walk_flat_map_param(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> { let Param { attrs, id, pat, span, ty, is_placeholder: _ } = &mut param; vis.visit_id(id); - visit_attrs(attrs, vis); + visit_attrs(vis, attrs); vis.visit_pat(pat); vis.visit_ty(ty); vis.visit_span(span); @@ -684,69 +686,69 @@ pub fn noop_flat_map_param(mut param: Param, vis: &mut T) -> Smal } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_attr_tt(tt: &mut AttrTokenTree, vis: &mut T) { +fn visit_attr_tt(vis: &mut T, tt: &mut AttrTokenTree) { match tt { AttrTokenTree::Token(token, _spacing) => { - visit_token(token, vis); + visit_token(vis, token); } AttrTokenTree::Delimited(dspan, _spacing, _delim, tts) => { - visit_attr_tts(tts, vis); - visit_delim_span(dspan, vis); + visit_attr_tts(vis, tts); + visit_delim_span(vis, dspan); } AttrTokenTree::AttrsTarget(AttrsTarget { attrs, tokens }) => { - visit_attrs(attrs, vis); - visit_lazy_tts_opt_mut(Some(tokens), vis); + visit_attrs(vis, attrs); + visit_lazy_tts_opt_mut(vis, Some(tokens)); } } } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_tt(tt: &mut TokenTree, vis: &mut T) { +fn visit_tt(vis: &mut T, tt: &mut TokenTree) { match tt { TokenTree::Token(token, _spacing) => { - visit_token(token, vis); + visit_token(vis, token); } TokenTree::Delimited(dspan, _spacing, _delim, tts) => { - visit_tts(tts, vis); - visit_delim_span(dspan, vis); + visit_tts(vis, tts); + visit_delim_span(vis, dspan); } } } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_tts(TokenStream(tts): &mut TokenStream, vis: &mut T) { +fn visit_tts(vis: &mut T, TokenStream(tts): &mut TokenStream) { if T::VISIT_TOKENS && !tts.is_empty() { let tts = Lrc::make_mut(tts); - visit_vec(tts, |tree| visit_tt(tree, vis)); + visit_vec(tts, |tree| visit_tt(vis, tree)); } } -fn visit_attr_tts(AttrTokenStream(tts): &mut AttrTokenStream, vis: &mut T) { +fn visit_attr_tts(vis: &mut T, AttrTokenStream(tts): &mut AttrTokenStream) { if T::VISIT_TOKENS && !tts.is_empty() { let tts = Lrc::make_mut(tts); - visit_vec(tts, |tree| visit_attr_tt(tree, vis)); + visit_vec(tts, |tree| visit_attr_tt(vis, tree)); } } -fn visit_lazy_tts_opt_mut(lazy_tts: Option<&mut LazyAttrTokenStream>, vis: &mut T) { +fn visit_lazy_tts_opt_mut(vis: &mut T, lazy_tts: Option<&mut LazyAttrTokenStream>) { if T::VISIT_TOKENS { if let Some(lazy_tts) = lazy_tts { let mut tts = lazy_tts.to_attr_token_stream(); - visit_attr_tts(&mut tts, vis); + visit_attr_tts(vis, &mut tts); *lazy_tts = LazyAttrTokenStream::new(tts); } } } -fn visit_lazy_tts(lazy_tts: &mut Option, vis: &mut T) { - visit_lazy_tts_opt_mut(lazy_tts.as_mut(), vis); +fn visit_lazy_tts(vis: &mut T, lazy_tts: &mut Option) { + visit_lazy_tts_opt_mut(vis, lazy_tts.as_mut()); } /// Applies ident visitor if it's an ident; applies other visits to interpolated nodes. /// In practice the ident part is not actually used by specific visitors right now, /// but there's a test below checking that it works. // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_token(t: &mut Token, vis: &mut T) { +pub fn visit_token(vis: &mut T, t: &mut Token) { let Token { kind, span } = t; match kind { token::Ident(name, _ /*raw*/) | token::Lifetime(name) => { @@ -764,7 +766,7 @@ pub fn visit_token(t: &mut Token, vis: &mut T) { } token::Interpolated(nt) => { let nt = Lrc::make_mut(nt); - visit_nonterminal(nt, vis); + visit_nonterminal(vis, nt); } _ => {} } @@ -795,7 +797,7 @@ pub fn visit_token(t: &mut Token, vis: &mut T) { // contain multiple items, but decided against it when I looked at // `parse_item_or_view_item` and tried to figure out what I would do with // multiple items there.... -fn visit_nonterminal(nt: &mut token::Nonterminal, vis: &mut T) { +fn visit_nonterminal(vis: &mut T, nt: &mut token::Nonterminal) { match nt { token::NtItem(item) => visit_clobber(item, |item| { // This is probably okay, because the only visitors likely to @@ -817,8 +819,8 @@ fn visit_nonterminal(nt: &mut token::Nonterminal, vis: &mut T) { token::NtMeta(item) => { let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut(); vis.visit_path(path); - visit_attr_args(args, vis); - visit_lazy_tts(tokens, vis); + visit_attr_args(vis, args); + visit_lazy_tts(vis, tokens); } token::NtPath(path) => vis.visit_path(path), token::NtVis(visib) => vis.visit_vis(visib), @@ -826,7 +828,7 @@ fn visit_nonterminal(nt: &mut token::Nonterminal, vis: &mut T) { } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_defaultness(defaultness: &mut Defaultness, vis: &mut T) { +fn visit_defaultness(vis: &mut T, defaultness: &mut Defaultness) { match defaultness { Defaultness::Default(span) => vis.visit_span(span), Defaultness::Final => {} @@ -834,7 +836,7 @@ fn visit_defaultness(defaultness: &mut Defaultness, vis: &mut T) } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_safety(safety: &mut Safety, vis: &mut T) { +fn visit_safety(vis: &mut T, safety: &mut Safety) { match safety { Safety::Unsafe(span) => vis.visit_span(span), Safety::Safe(span) => vis.visit_span(span), @@ -843,7 +845,7 @@ fn visit_safety(safety: &mut Safety, vis: &mut T) { } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_polarity(polarity: &mut ImplPolarity, vis: &mut T) { +fn visit_polarity(vis: &mut T, polarity: &mut ImplPolarity) { match polarity { ImplPolarity::Positive => {} ImplPolarity::Negative(span) => vis.visit_span(span), @@ -851,14 +853,14 @@ fn visit_polarity(polarity: &mut ImplPolarity, vis: &mut T) { } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_constness(constness: &mut Const, vis: &mut T) { +fn visit_constness(vis: &mut T, constness: &mut Const) { match constness { Const::Yes(span) => vis.visit_span(span), Const::No => {} } } -fn noop_visit_closure_binder(binder: &mut ClosureBinder, vis: &mut T) { +fn walk_closure_binder(vis: &mut T, binder: &mut ClosureBinder) { match binder { ClosureBinder::NotPresent => {} ClosureBinder::For { span: _, generic_params } => { @@ -867,7 +869,7 @@ fn noop_visit_closure_binder(binder: &mut ClosureBinder, vis: &mu } } -fn noop_visit_coroutine_kind(coroutine_kind: &mut CoroutineKind, vis: &mut T) { +fn walk_coroutine_kind(vis: &mut T, coroutine_kind: &mut CoroutineKind) { match coroutine_kind { CoroutineKind::Async { span, closure_id, return_impl_trait_id } | CoroutineKind::Gen { span, closure_id, return_impl_trait_id } @@ -879,23 +881,43 @@ fn noop_visit_coroutine_kind(coroutine_kind: &mut CoroutineKind, } } -fn noop_visit_fn_decl(decl: &mut P, vis: &mut T) { - let FnDecl { inputs, output } = decl.deref_mut(); - inputs.flat_map_in_place(|param| vis.flat_map_param(param)); - noop_visit_fn_ret_ty(output, vis); +fn walk_fn(vis: &mut T, kind: FnKind<'_>) { + match kind { + FnKind::Fn(FnSig { header, decl, span }, generics, body) => { + // Identifier and visibility are visited as a part of the item. + vis.visit_fn_header(header); + vis.visit_generics(generics); + vis.visit_fn_decl(decl); + if let Some(body) = body { + vis.visit_block(body); + } + vis.visit_span(span); + } + FnKind::Closure(binder, decl, body) => { + vis.visit_closure_binder(binder); + vis.visit_fn_decl(decl); + vis.visit_expr(body); + } + } } -fn noop_visit_fn_ret_ty(fn_ret_ty: &mut FnRetTy, vis: &mut T) { +fn walk_fn_decl(vis: &mut T, decl: &mut P) { + let FnDecl { inputs, output } = decl.deref_mut(); + inputs.flat_map_in_place(|param| vis.flat_map_param(param)); + walk_fn_ret_ty(vis, output); +} + +fn walk_fn_ret_ty(vis: &mut T, fn_ret_ty: &mut FnRetTy) { match fn_ret_ty { FnRetTy::Default(span) => vis.visit_span(span), FnRetTy::Ty(ty) => vis.visit_ty(ty), } } -fn noop_visit_param_bound(pb: &mut GenericBound, vis: &mut T) { +fn walk_param_bound(vis: &mut T, pb: &mut GenericBound) { match pb { GenericBound::Trait(ty, _modifier) => vis.visit_poly_trait_ref(ty), - GenericBound::Outlives(lifetime) => noop_visit_lifetime(lifetime, vis), + GenericBound::Outlives(lifetime) => walk_lifetime(vis, lifetime), GenericBound::Use(args, span) => { for arg in args { vis.visit_precise_capturing_arg(arg); @@ -905,7 +927,7 @@ fn noop_visit_param_bound(pb: &mut GenericBound, vis: &mut T) { } } -fn noop_visit_precise_capturing_arg(arg: &mut PreciseCapturingArg, vis: &mut T) { +fn walk_precise_capturing_arg(vis: &mut T, arg: &mut PreciseCapturingArg) { match arg { PreciseCapturingArg::Lifetime(lt) => { vis.visit_lifetime(lt); @@ -917,15 +939,15 @@ fn noop_visit_precise_capturing_arg(arg: &mut PreciseCapturingArg } } -pub fn noop_flat_map_generic_param( - mut param: GenericParam, +pub fn walk_flat_map_generic_param( vis: &mut T, + mut param: GenericParam, ) -> SmallVec<[GenericParam; 1]> { let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = &mut param; vis.visit_id(id); - visit_attrs(attrs, vis); + visit_attrs(vis, attrs); vis.visit_ident(ident); - visit_vec(bounds, |bound| vis.visit_param_bound(bound)); + visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound)); match kind { GenericParamKind::Lifetime => {} GenericParamKind::Type { default } => { @@ -942,23 +964,23 @@ pub fn noop_flat_map_generic_param( smallvec![param] } -fn noop_visit_label(Label { ident }: &mut Label, vis: &mut T) { +fn walk_label(vis: &mut T, Label { ident }: &mut Label) { vis.visit_ident(ident); } -fn noop_visit_lifetime(Lifetime { id, ident }: &mut Lifetime, vis: &mut T) { +fn walk_lifetime(vis: &mut T, Lifetime { id, ident }: &mut Lifetime) { vis.visit_id(id); vis.visit_ident(ident); } -fn noop_visit_generics(generics: &mut Generics, vis: &mut T) { +fn walk_generics(vis: &mut T, generics: &mut Generics) { let Generics { params, where_clause, span } = generics; params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_where_clause(where_clause); vis.visit_span(span); } -fn noop_visit_ty_alias_where_clauses(tawcs: &mut TyAliasWhereClauses, vis: &mut T) { +fn walk_ty_alias_where_clauses(vis: &mut T, tawcs: &mut TyAliasWhereClauses) { let TyAliasWhereClauses { before, after, split: _ } = tawcs; let TyAliasWhereClause { has_where_token: _, span: span_before } = before; let TyAliasWhereClause { has_where_token: _, span: span_after } = after; @@ -966,25 +988,25 @@ fn noop_visit_ty_alias_where_clauses(tawcs: &mut TyAliasWhereClau vis.visit_span(span_after); } -fn noop_visit_where_clause(wc: &mut WhereClause, vis: &mut T) { +fn walk_where_clause(vis: &mut T, wc: &mut WhereClause) { let WhereClause { has_where_token: _, predicates, span } = wc; visit_thin_vec(predicates, |predicate| vis.visit_where_predicate(predicate)); vis.visit_span(span); } -fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: &mut T) { +fn walk_where_predicate(vis: &mut T, pred: &mut WherePredicate) { match pred { WherePredicate::BoundPredicate(bp) => { let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp; bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_ty(bounded_ty); - visit_vec(bounds, |bound| vis.visit_param_bound(bound)); + visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound)); vis.visit_span(span); } WherePredicate::RegionPredicate(rp) => { let WhereRegionPredicate { span, lifetime, bounds } = rp; vis.visit_lifetime(lifetime); - visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis)); + visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound)); vis.visit_span(span); } WherePredicate::EqPredicate(ep) => { @@ -996,7 +1018,7 @@ fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: &mu } } -fn noop_visit_variant_data(vdata: &mut VariantData, vis: &mut T) { +fn walk_variant_data(vis: &mut T, vdata: &mut VariantData) { match vdata { VariantData::Struct { fields, recovered: _ } => { fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); @@ -1009,25 +1031,25 @@ fn noop_visit_variant_data(vdata: &mut VariantData, vis: &mut T) } } -fn noop_visit_trait_ref(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) { +fn walk_trait_ref(vis: &mut T, TraitRef { path, ref_id }: &mut TraitRef) { vis.visit_id(ref_id); vis.visit_path(path); } -fn noop_visit_poly_trait_ref(p: &mut PolyTraitRef, vis: &mut T) { +fn walk_poly_trait_ref(vis: &mut T, p: &mut PolyTraitRef) { let PolyTraitRef { bound_generic_params, trait_ref, span } = p; bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_trait_ref(trait_ref); vis.visit_span(span); } -pub fn noop_flat_map_field_def( - mut fd: FieldDef, +pub fn walk_flat_map_field_def( visitor: &mut T, + mut fd: FieldDef, ) -> SmallVec<[FieldDef; 1]> { let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut fd; visitor.visit_id(id); - visit_attrs(attrs, visitor); + visit_attrs(visitor, attrs); visitor.visit_vis(vis); visit_opt(ident, |ident| visitor.visit_ident(ident)); visitor.visit_ty(ty); @@ -1035,37 +1057,42 @@ pub fn noop_flat_map_field_def( smallvec![fd] } -pub fn noop_flat_map_expr_field( - mut f: ExprField, +pub fn walk_flat_map_expr_field( vis: &mut T, + mut f: ExprField, ) -> SmallVec<[ExprField; 1]> { let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = &mut f; vis.visit_id(id); - visit_attrs(attrs, vis); + visit_attrs(vis, attrs); vis.visit_ident(ident); vis.visit_expr(expr); vis.visit_span(span); smallvec![f] } -fn noop_visit_mt(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mut T) { +fn walk_mt(vis: &mut T, MutTy { ty, mutbl: _ }: &mut MutTy) { vis.visit_ty(ty); } -pub fn noop_visit_block(block: &mut P, vis: &mut T) { +pub fn walk_block(vis: &mut T, block: &mut P) { let Block { id, stmts, rules: _, span, tokens, could_be_bare_literal: _ } = block.deref_mut(); vis.visit_id(id); stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); - visit_lazy_tts(tokens, vis); + visit_lazy_tts(vis, tokens); vis.visit_span(span); } -pub fn noop_visit_item_kind(kind: &mut impl NoopVisitItemKind, vis: &mut impl MutVisitor) { - kind.noop_visit(vis) +pub fn walk_item_kind( + kind: &mut impl WalkItemKind, + span: Span, + id: NodeId, + vis: &mut impl MutVisitor, +) { + kind.walk(span, id, vis) } -impl NoopVisitItemKind for ItemKind { - fn noop_visit(&mut self, vis: &mut impl MutVisitor) { +impl WalkItemKind for ItemKind { + fn walk(&mut self, span: Span, id: NodeId, vis: &mut impl MutVisitor) { match self { ItemKind::ExternCrate(_orig_name) => {} ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), @@ -1077,13 +1104,11 @@ impl NoopVisitItemKind for ItemKind { visit_const_item(item, vis); } ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { - visit_defaultness(defaultness, vis); - vis.visit_generics(generics); - visit_fn_sig(sig, vis); - visit_opt(body, |body| vis.visit_block(body)); + visit_defaultness(vis, defaultness); + vis.visit_fn(FnKind::Fn(sig, generics, body), span, id); } ItemKind::Mod(safety, mod_kind) => { - visit_safety(safety, vis); + visit_safety(vis, safety); match mod_kind { ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => { items.flat_map_in_place(|item| vis.flat_map_item(item)); @@ -1096,11 +1121,11 @@ impl NoopVisitItemKind for ItemKind { ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), ItemKind::GlobalAsm(asm) => vis.visit_inline_asm(asm), ItemKind::TyAlias(box TyAlias { defaultness, generics, where_clauses, bounds, ty }) => { - visit_defaultness(defaultness, vis); + visit_defaultness(vis, defaultness); vis.visit_generics(generics); - visit_bounds(bounds, vis); + visit_bounds(vis, bounds, BoundKind::Bound); visit_opt(ty, |ty| vis.visit_ty(ty)); - noop_visit_ty_alias_where_clauses(where_clauses, vis); + walk_ty_alias_where_clauses(vis, where_clauses); } ItemKind::Enum(EnumDef { variants }, generics) => { vis.visit_generics(generics); @@ -1120,24 +1145,24 @@ impl NoopVisitItemKind for ItemKind { self_ty, items, }) => { - visit_defaultness(defaultness, vis); - visit_safety(safety, vis); + visit_defaultness(vis, defaultness); + visit_safety(vis, safety); vis.visit_generics(generics); - visit_constness(constness, vis); - visit_polarity(polarity, vis); + visit_constness(vis, constness); + visit_polarity(vis, polarity); visit_opt(of_trait, |trait_ref| vis.visit_trait_ref(trait_ref)); vis.visit_ty(self_ty); - items.flat_map_in_place(|item| vis.flat_map_impl_item(item)); + items.flat_map_in_place(|item| vis.flat_map_assoc_item(item, AssocCtxt::Impl)); } ItemKind::Trait(box Trait { safety, is_auto: _, generics, bounds, items }) => { - visit_safety(safety, vis); + visit_safety(vis, safety); vis.visit_generics(generics); - visit_bounds(bounds, vis); - items.flat_map_in_place(|item| vis.flat_map_trait_item(item)); + visit_bounds(vis, bounds, BoundKind::Bound); + items.flat_map_in_place(|item| vis.flat_map_assoc_item(item, AssocCtxt::Trait)); } ItemKind::TraitAlias(generics, bounds) => { vis.visit_generics(generics); - visit_bounds(bounds, vis); + visit_bounds(vis, bounds, BoundKind::Bound); } ItemKind::MacCall(m) => vis.visit_mac_call(m), ItemKind::MacroDef(def) => vis.visit_macro_def(def), @@ -1178,17 +1203,15 @@ impl NoopVisitItemKind for ItemKind { } } -impl NoopVisitItemKind for AssocItemKind { - fn noop_visit(&mut self, visitor: &mut impl MutVisitor) { +impl WalkItemKind for AssocItemKind { + fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) { match self { AssocItemKind::Const(item) => { visit_const_item(item, visitor); } AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { - visit_defaultness(defaultness, visitor); - visitor.visit_generics(generics); - visit_fn_sig(sig, visitor); - visit_opt(body, |body| visitor.visit_block(body)); + visit_defaultness(visitor, defaultness); + visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id); } AssocItemKind::Type(box TyAlias { defaultness, @@ -1197,11 +1220,11 @@ impl NoopVisitItemKind for AssocItemKind { bounds, ty, }) => { - visit_defaultness(defaultness, visitor); + visit_defaultness(visitor, defaultness); visitor.visit_generics(generics); - visit_bounds(bounds, visitor); + visit_bounds(visitor, bounds, BoundKind::Bound); visit_opt(ty, |ty| visitor.visit_ty(ty)); - noop_visit_ty_alias_where_clauses(where_clauses, visitor); + walk_ty_alias_where_clauses(visitor, where_clauses); } AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac), AssocItemKind::Delegation(box Delegation { @@ -1245,57 +1268,55 @@ fn visit_const_item( ConstItem { defaultness, generics, ty, expr }: &mut ConstItem, visitor: &mut T, ) { - visit_defaultness(defaultness, visitor); + visit_defaultness(visitor, defaultness); visitor.visit_generics(generics); visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); } -fn noop_visit_fn_header(header: &mut FnHeader, vis: &mut T) { +fn walk_fn_header(vis: &mut T, header: &mut FnHeader) { let FnHeader { safety, coroutine_kind, constness, ext: _ } = header; - visit_constness(constness, vis); + visit_constness(vis, constness); coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind)); - visit_safety(safety, vis); + visit_safety(vis, safety); } -pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { +pub fn walk_crate(vis: &mut T, krate: &mut Crate) { let Crate { attrs, items, spans, id, is_placeholder: _ } = krate; vis.visit_id(id); - visit_attrs(attrs, vis); + visit_attrs(vis, attrs); items.flat_map_in_place(|item| vis.flat_map_item(item)); let ModSpans { inner_span, inject_use_span } = spans; vis.visit_span(inner_span); vis.visit_span(inject_use_span); } -// Mutates one item into possibly many items. -pub fn noop_flat_map_item( - mut item: P>, +/// Mutates one item, returning the item again. +pub fn walk_flat_map_item( visitor: &mut impl MutVisitor, + mut item: P>, ) -> SmallVec<[P>; 1]> { let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut(); visitor.visit_id(id); - visit_attrs(attrs, visitor); + visit_attrs(visitor, attrs); visitor.visit_vis(vis); visitor.visit_ident(ident); - kind.noop_visit(visitor); - visit_lazy_tts(tokens, visitor); + kind.walk(*span, *id, visitor); + visit_lazy_tts(visitor, tokens); visitor.visit_span(span); smallvec![item] } -impl NoopVisitItemKind for ForeignItemKind { - fn noop_visit(&mut self, visitor: &mut impl MutVisitor) { +impl WalkItemKind for ForeignItemKind { + fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) { match self { ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => { visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); } ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { - visit_defaultness(defaultness, visitor); - visitor.visit_generics(generics); - visit_fn_sig(sig, visitor); - visit_opt(body, |body| visitor.visit_block(body)); + visit_defaultness(visitor, defaultness); + visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id); } ForeignItemKind::TyAlias(box TyAlias { defaultness, @@ -1304,18 +1325,18 @@ impl NoopVisitItemKind for ForeignItemKind { bounds, ty, }) => { - visit_defaultness(defaultness, visitor); + visit_defaultness(visitor, defaultness); visitor.visit_generics(generics); - visit_bounds(bounds, visitor); + visit_bounds(visitor, bounds, BoundKind::Bound); visit_opt(ty, |ty| visitor.visit_ty(ty)); - noop_visit_ty_alias_where_clauses(where_clauses, visitor); + walk_ty_alias_where_clauses(visitor, where_clauses); } ForeignItemKind::MacCall(mac) => visitor.visit_mac_call(mac), } } } -pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { +pub fn walk_pat(vis: &mut T, pat: &mut P) { let Pat { id, kind, span, tokens } = pat.deref_mut(); vis.visit_id(id); match kind { @@ -1354,16 +1375,16 @@ pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { PatKind::Paren(inner) => vis.visit_pat(inner), PatKind::MacCall(mac) => vis.visit_mac_call(mac), } - visit_lazy_tts(tokens, vis); + visit_lazy_tts(vis, tokens); vis.visit_span(span); } -fn noop_visit_anon_const(AnonConst { id, value }: &mut AnonConst, vis: &mut T) { +fn walk_anon_const(vis: &mut T, AnonConst { id, value }: &mut AnonConst) { vis.visit_id(id); vis.visit_expr(value); } -fn noop_visit_inline_asm(asm: &mut InlineAsm, vis: &mut T) { +fn walk_inline_asm(vis: &mut T, asm: &mut InlineAsm) { // FIXME: Visit spans inside all this currently ignored stuff. let InlineAsm { template: _, @@ -1393,16 +1414,16 @@ fn noop_visit_inline_asm(asm: &mut InlineAsm, vis: &mut T) { } } -fn noop_visit_inline_asm_sym( - InlineAsmSym { id, qself, path }: &mut InlineAsmSym, +fn walk_inline_asm_sym( vis: &mut T, + InlineAsmSym { id, qself, path }: &mut InlineAsmSym, ) { vis.visit_id(id); vis.visit_qself(qself); vis.visit_path(path); } -fn noop_visit_format_args(fmt: &mut FormatArgs, vis: &mut T) { +fn walk_format_args(vis: &mut T, fmt: &mut FormatArgs) { // FIXME: visit the template exhaustively. let FormatArgs { span, template: _, arguments } = fmt; for FormatArgument { kind, expr } in arguments.all_args_mut() { @@ -1417,14 +1438,11 @@ fn noop_visit_format_args(fmt: &mut FormatArgs, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_expr( - Expr { kind, id, span, attrs, tokens }: &mut Expr, - vis: &mut T, -) { +pub fn walk_expr(vis: &mut T, Expr { kind, id, span, attrs, tokens }: &mut Expr) { vis.visit_id(id); - visit_attrs(attrs, vis); + visit_attrs(vis, attrs); match kind { - ExprKind::Array(exprs) => visit_thin_exprs(exprs, vis), + ExprKind::Array(exprs) => visit_thin_exprs(vis, exprs), ExprKind::ConstBlock(anon_const) => { vis.visit_anon_const(anon_const); } @@ -1432,10 +1450,10 @@ pub fn noop_visit_expr( vis.visit_expr(expr); vis.visit_anon_const(count); } - ExprKind::Tup(exprs) => visit_thin_exprs(exprs, vis), + ExprKind::Tup(exprs) => visit_thin_exprs(vis, exprs), ExprKind::Call(f, args) => { vis.visit_expr(f); - visit_thin_exprs(args, vis); + visit_thin_exprs(vis, args); } ExprKind::MethodCall(box MethodCall { seg: PathSegment { ident, id, args: seg_args }, @@ -1447,7 +1465,7 @@ pub fn noop_visit_expr( vis.visit_id(id); vis.visit_ident(ident); visit_opt(seg_args, |args| vis.visit_generic_args(args)); - visit_thin_exprs(call_args, vis); + visit_thin_exprs(vis, call_args); vis.visit_span(span); } ExprKind::Binary(_binop, lhs, rhs) => { @@ -1505,12 +1523,10 @@ pub fn noop_visit_expr( fn_decl_span, fn_arg_span, }) => { - vis.visit_closure_binder(binder); - visit_constness(constness, vis); + visit_constness(vis, constness); coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind)); vis.visit_capture_by(capture_clause); - vis.visit_fn_decl(fn_decl); - vis.visit_expr(body); + vis.visit_fn(FnKind::Closure(binder, fn_decl, body), *span, *id); vis.visit_span(fn_decl_span); vis.visit_span(fn_arg_span); } @@ -1600,23 +1616,23 @@ pub fn noop_visit_expr( ExprKind::Err(_guar) => {} ExprKind::Dummy => {} } - visit_lazy_tts(tokens, vis); + visit_lazy_tts(vis, tokens); vis.visit_span(span); } -pub fn noop_filter_map_expr(mut e: P, vis: &mut T) -> Option> { +pub fn noop_filter_map_expr(vis: &mut T, mut e: P) -> Option> { Some({ vis.visit_expr(&mut e); e }) } -pub fn noop_flat_map_stmt( - Stmt { kind, mut span, mut id }: Stmt, +pub fn walk_flat_map_stmt( vis: &mut T, + Stmt { kind, mut span, mut id }: Stmt, ) -> SmallVec<[Stmt; 1]> { vis.visit_id(&mut id); - let stmts: SmallVec<_> = noop_flat_map_stmt_kind(kind, vis) + let stmts: SmallVec<_> = walk_flat_map_stmt_kind(vis, kind) .into_iter() .map(|kind| Stmt { id, kind, span }) .collect(); @@ -1630,7 +1646,7 @@ pub fn noop_flat_map_stmt( stmts } -fn noop_flat_map_stmt_kind(kind: StmtKind, vis: &mut T) -> SmallVec<[StmtKind; 1]> { +fn walk_flat_map_stmt_kind(vis: &mut T, kind: StmtKind) -> SmallVec<[StmtKind; 1]> { match kind { StmtKind::Let(mut local) => smallvec![StmtKind::Let({ vis.visit_local(&mut local); @@ -1642,15 +1658,15 @@ fn noop_flat_map_stmt_kind(kind: StmtKind, vis: &mut T) -> SmallV StmtKind::Empty => smallvec![StmtKind::Empty], StmtKind::MacCall(mut mac) => { let MacCallStmt { mac: mac_, style: _, attrs, tokens } = mac.deref_mut(); - visit_attrs(attrs, vis); + visit_attrs(vis, attrs); vis.visit_mac_call(mac_); - visit_lazy_tts(tokens, vis); + visit_lazy_tts(vis, tokens); smallvec![StmtKind::MacCall(mac)] } } } -fn noop_visit_vis(visibility: &mut Visibility, vis: &mut T) { +fn walk_vis(vis: &mut T, visibility: &mut Visibility) { let Visibility { kind, span, tokens } = visibility; match kind { VisibilityKind::Public | VisibilityKind::Inherited => {} @@ -1659,11 +1675,11 @@ fn noop_visit_vis(visibility: &mut Visibility, vis: &mut T) { vis.visit_path(path); } } - visit_lazy_tts(tokens, vis); + visit_lazy_tts(vis, tokens); vis.visit_span(span); } -fn noop_visit_capture_by(capture_by: &mut CaptureBy, vis: &mut T) { +fn walk_capture_by(vis: &mut T, capture_by: &mut CaptureBy) { match capture_by { CaptureBy::Ref => {} CaptureBy::Value { move_kw } => { @@ -1767,3 +1783,12 @@ impl DummyAstNode for crate::ast_traits::AstNo crate::ast_traits::AstNodeWrapper::new(N::dummy(), T::dummy()) } } + +#[derive(Debug)] +pub enum FnKind<'a> { + /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. + Fn(&'a mut FnSig, &'a mut Generics, &'a mut Option>), + + /// E.g., `|x, y| body`. + Closure(&'a mut ClosureBinder, &'a mut P, &'a mut P), +} diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 6303584bb784..ac36b0746096 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -44,13 +44,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let mut res = self.lower_res(base_res); // When we have an `async` kw on a bound, map the trait it resolves to. - let mut bound_modifier_allowed_features = None; if let Some(TraitBoundModifiers { asyncness: BoundAsyncness::Async(_), .. }) = modifiers { match res { Res::Def(DefKind::Trait, def_id) => { - if let Some((async_def_id, features)) = self.map_trait_to_async_trait(def_id) { + if let Some(async_def_id) = self.map_trait_to_async_trait(def_id) { res = Res::Def(DefKind::Trait, async_def_id); - bound_modifier_allowed_features = Some(features); } else { self.dcx().emit_err(AsyncBoundOnlyForFnTraits { span: p.span }); } @@ -67,6 +65,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } + // Ungate the `async_fn_traits` feature in the path if the trait is + // named via either `async Fn*()` or `AsyncFn*()`. + let bound_modifier_allowed_features = if let Res::Def(DefKind::Trait, async_def_id) = res + && self.tcx.async_fn_trait_kind_from_def_id(async_def_id).is_some() + { + Some(self.allow_async_fn_traits.clone()) + } else { + None + }; + let path_span_lo = p.span.shrink_to_lo(); let proj_start = p.segments.len() - unresolved_segments; let path = self.arena.alloc(hir::Path { @@ -506,14 +514,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// This only needs to be done until we unify `AsyncFn` and `Fn` traits into one /// that is generic over `async`ness, if that's ever possible, or modify the /// lowering of `async Fn()` bounds to desugar to another trait like `LendingFn`. - fn map_trait_to_async_trait(&self, def_id: DefId) -> Option<(DefId, Lrc<[Symbol]>)> { + fn map_trait_to_async_trait(&self, def_id: DefId) -> Option { let lang_items = self.tcx.lang_items(); if Some(def_id) == lang_items.fn_trait() { - Some((lang_items.async_fn_trait()?, self.allow_async_fn_traits.clone())) + lang_items.async_fn_trait() } else if Some(def_id) == lang_items.fn_mut_trait() { - Some((lang_items.async_fn_mut_trait()?, self.allow_async_fn_traits.clone())) + lang_items.async_fn_mut_trait() } else if Some(def_id) == lang_items.fn_once_trait() { - Some((lang_items.async_fn_once_trait()?, self.allow_async_fn_traits.clone())) + lang_items.async_fn_once_trait() } else { None } diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index b09975c0ba79..b3d252e06a58 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -4,7 +4,7 @@ use core::ops::ControlFlow; use rustc_ast as ast; use rustc_ast::mut_visit::MutVisitor; use rustc_ast::ptr::P; -use rustc_ast::visit::Visitor; +use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::NodeId; use rustc_ast::{mut_visit, visit}; use rustc_ast::{Attribute, HasAttrs, HasTokens}; @@ -53,11 +53,8 @@ fn flat_map_annotatable( ) -> Option { match annotatable { Annotatable::Item(item) => vis.flat_map_item(item).pop().map(Annotatable::Item), - Annotatable::TraitItem(item) => { - vis.flat_map_trait_item(item).pop().map(Annotatable::TraitItem) - } - Annotatable::ImplItem(item) => { - vis.flat_map_impl_item(item).pop().map(Annotatable::ImplItem) + Annotatable::AssocItem(item, ctxt) => { + Some(Annotatable::AssocItem(vis.flat_map_assoc_item(item, ctxt).pop()?, ctxt)) } Annotatable::ForeignItem(item) => { vis.flat_map_foreign_item(item).pop().map(Annotatable::ForeignItem) @@ -106,8 +103,7 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool { let res = match annotatable { Annotatable::Item(item) => CfgFinder.visit_item(item), - Annotatable::TraitItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Trait), - Annotatable::ImplItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Impl), + Annotatable::AssocItem(item, ctxt) => CfgFinder.visit_assoc_item(item, *ctxt), Annotatable::ForeignItem(item) => CfgFinder.visit_foreign_item(item), Annotatable::Stmt(stmt) => CfgFinder.visit_stmt(stmt), Annotatable::Expr(expr) => CfgFinder.visit_expr(expr), @@ -150,14 +146,16 @@ impl CfgEval<'_> { Annotatable::Item(_) => { |parser| Ok(Annotatable::Item(parser.parse_item(ForceCollect::Yes)?.unwrap())) } - Annotatable::TraitItem(_) => |parser| { - Ok(Annotatable::TraitItem( + Annotatable::AssocItem(_, AssocCtxt::Trait) => |parser| { + Ok(Annotatable::AssocItem( parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap(), + AssocCtxt::Trait, )) }, - Annotatable::ImplItem(_) => |parser| { - Ok(Annotatable::ImplItem( + Annotatable::AssocItem(_, AssocCtxt::Impl) => |parser| { + Ok(Annotatable::AssocItem( parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap(), + AssocCtxt::Impl, )) }, Annotatable::ForeignItem(_) => |parser| { @@ -214,18 +212,18 @@ impl MutVisitor for CfgEval<'_> { #[instrument(level = "trace", skip(self))] fn visit_expr(&mut self, expr: &mut P) { self.0.configure_expr(expr, false); - mut_visit::noop_visit_expr(expr, self); + mut_visit::walk_expr(self, expr); } #[instrument(level = "trace", skip(self))] fn visit_method_receiver_expr(&mut self, expr: &mut P) { self.0.configure_expr(expr, true); - mut_visit::noop_visit_expr(expr, self); + mut_visit::walk_expr(self, expr); } fn filter_map_expr(&mut self, expr: P) -> Option> { let mut expr = configure!(self, expr); - mut_visit::noop_visit_expr(&mut expr, self); + mut_visit::walk_expr(self, &mut expr); Some(expr) } @@ -233,53 +231,64 @@ impl MutVisitor for CfgEval<'_> { &mut self, param: ast::GenericParam, ) -> SmallVec<[ast::GenericParam; 1]> { - mut_visit::noop_flat_map_generic_param(configure!(self, param), self) + let param = configure!(self, param); + mut_visit::walk_flat_map_generic_param(self, param) } fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { - mut_visit::noop_flat_map_stmt(configure!(self, stmt), self) + let stmt = configure!(self, stmt); + mut_visit::walk_flat_map_stmt(self, stmt) } fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { - mut_visit::noop_flat_map_item(configure!(self, item), self) + let item = configure!(self, item); + mut_visit::walk_flat_map_item(self, item) } - fn flat_map_impl_item(&mut self, item: P) -> SmallVec<[P; 1]> { - mut_visit::noop_flat_map_item(configure!(self, item), self) - } - - fn flat_map_trait_item(&mut self, item: P) -> SmallVec<[P; 1]> { - mut_visit::noop_flat_map_item(configure!(self, item), self) + fn flat_map_assoc_item( + &mut self, + item: P, + _ctxt: AssocCtxt, + ) -> SmallVec<[P; 1]> { + let item = configure!(self, item); + mut_visit::walk_flat_map_item(self, item) } fn flat_map_foreign_item( &mut self, foreign_item: P, ) -> SmallVec<[P; 1]> { - mut_visit::noop_flat_map_item(configure!(self, foreign_item), self) + let foreign_item = configure!(self, foreign_item); + mut_visit::walk_flat_map_item(self, foreign_item) } fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { - mut_visit::noop_flat_map_arm(configure!(self, arm), self) + let arm = configure!(self, arm); + mut_visit::walk_flat_map_arm(self, arm) } fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> { - mut_visit::noop_flat_map_expr_field(configure!(self, field), self) + let field = configure!(self, field); + mut_visit::walk_flat_map_expr_field(self, field) } fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> { - mut_visit::noop_flat_map_pat_field(configure!(self, fp), self) + let fp = configure!(self, fp); + mut_visit::walk_flat_map_pat_field(self, fp) } fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> { - mut_visit::noop_flat_map_param(configure!(self, p), self) + let p = configure!(self, p); + mut_visit::walk_flat_map_param(self, p) } fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> { - mut_visit::noop_flat_map_field_def(configure!(self, sf), self) + let sf = configure!(self, sf); + mut_visit::walk_flat_map_field_def(self, sf) } fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> { - mut_visit::noop_flat_map_variant(configure!(self, variant), self) + let variant = configure!(self, variant); + mut_visit::walk_flat_map_variant(self, variant) } } diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 9d032eb190a0..bbafb0ac299c 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -122,15 +122,15 @@ impl TestHarnessGenerator<'_> { impl<'a> MutVisitor for TestHarnessGenerator<'a> { fn visit_crate(&mut self, c: &mut ast::Crate) { let prev_tests = mem::take(&mut self.tests); - noop_visit_crate(c, self); + walk_crate(self, c); self.add_test_cases(ast::CRATE_NODE_ID, c.spans.inner_span, prev_tests); // Create a main function to run our tests c.items.push(mk_main(&mut self.cx)); } - fn flat_map_item(&mut self, i: P) -> SmallVec<[P; 1]> { - let mut item = i.into_inner(); + fn flat_map_item(&mut self, mut i: P) -> SmallVec<[P; 1]> { + let item = &mut *i; if let Some(name) = get_test_name(&item) { debug!("this is a test item"); @@ -144,13 +144,13 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { item.kind { let prev_tests = mem::take(&mut self.tests); - noop_visit_item_kind(&mut item.kind, self); + walk_item_kind(&mut item.kind, item.span, item.id, self); self.add_test_cases(item.id, span, prev_tests); } else { // But in those cases, we emit a lint to warn the user of these missing tests. walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item); } - smallvec![P(item)] + smallvec![i] } } @@ -192,7 +192,7 @@ struct EntryPointCleaner<'a> { impl<'a> MutVisitor for EntryPointCleaner<'a> { fn flat_map_item(&mut self, i: P) -> SmallVec<[P; 1]> { self.depth += 1; - let item = noop_flat_map_item(i, self).expect_one("noop did something"); + let item = walk_flat_map_item(self, i).expect_one("noop did something"); self.depth -= 1; // Remove any #[rustc_main] or #[start] from the AST so it doesn't diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index 652e34268ea9..fabcb6a4b706 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -27,8 +27,7 @@ pub(crate) fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaI pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: Symbol) { let attrs: Option<&[Attribute]> = match item { Annotatable::Item(item) => Some(&item.attrs), - Annotatable::TraitItem(item) => Some(&item.attrs), - Annotatable::ImplItem(item) => Some(&item.attrs), + Annotatable::AssocItem(item, _) => Some(&item.attrs), Annotatable::ForeignItem(item) => Some(&item.attrs), Annotatable::Expr(expr) => Some(&expr.attrs), Annotatable::Arm(arm) => Some(&arm.attrs), diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 9fd7219499b2..d5d3f7767b13 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -100,7 +100,33 @@ impl Qualif for HasMutInterior { } fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - !ty.is_freeze(cx.tcx, cx.param_env) + // Avoid selecting for simple cases, such as builtin types. + if ty.is_trivially_freeze() { + return false; + } + + // We do not use `ty.is_freeze` here, because that requires revealing opaque types, which + // requires borrowck, which in turn will invoke mir_const_qualifs again, causing a cycle error. + // Instead we invoke an obligation context manually, and provide the opaque type inference settings + // that allow the trait solver to just error out instead of cycling. + let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, Some(cx.body.span)); + + let obligation = Obligation::new( + cx.tcx, + ObligationCause::dummy_with_span(cx.body.span), + cx.param_env, + ty::TraitRef::new(cx.tcx, freeze_def_id, [ty::GenericArg::from(ty)]), + ); + + let infcx = cx + .tcx + .infer_ctxt() + .with_opaque_type_inference(cx.body.source.def_id().expect_local()) + .build(); + let ocx = ObligationCtxt::new(&infcx); + ocx.register_obligation(obligation); + let errors = ocx.select_all_or_error(); + !errors.is_empty() } fn in_adt_inherently<'tcx>( diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index d8e6d3525da8..b439ec74ffae 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -37,8 +37,7 @@ use thin_vec::ThinVec; #[derive(Debug, Clone)] pub enum Annotatable { Item(P), - TraitItem(P), - ImplItem(P), + AssocItem(P, AssocCtxt), ForeignItem(P), Stmt(P), Expr(P), @@ -56,8 +55,7 @@ impl Annotatable { pub fn span(&self) -> Span { match self { Annotatable::Item(item) => item.span, - Annotatable::TraitItem(trait_item) => trait_item.span, - Annotatable::ImplItem(impl_item) => impl_item.span, + Annotatable::AssocItem(assoc_item, _) => assoc_item.span, Annotatable::ForeignItem(foreign_item) => foreign_item.span, Annotatable::Stmt(stmt) => stmt.span, Annotatable::Expr(expr) => expr.span, @@ -75,8 +73,7 @@ impl Annotatable { pub fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { match self { Annotatable::Item(item) => item.visit_attrs(f), - Annotatable::TraitItem(trait_item) => trait_item.visit_attrs(f), - Annotatable::ImplItem(impl_item) => impl_item.visit_attrs(f), + Annotatable::AssocItem(assoc_item, _) => assoc_item.visit_attrs(f), Annotatable::ForeignItem(foreign_item) => foreign_item.visit_attrs(f), Annotatable::Stmt(stmt) => stmt.visit_attrs(f), Annotatable::Expr(expr) => expr.visit_attrs(f), @@ -94,8 +91,7 @@ impl Annotatable { pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) -> V::Result { match self { Annotatable::Item(item) => visitor.visit_item(item), - Annotatable::TraitItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Trait), - Annotatable::ImplItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Impl), + Annotatable::AssocItem(item, ctxt) => visitor.visit_assoc_item(item, *ctxt), Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item), Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt), Annotatable::Expr(expr) => visitor.visit_expr(expr), @@ -113,9 +109,7 @@ impl Annotatable { pub fn to_tokens(&self) -> TokenStream { match self { Annotatable::Item(node) => TokenStream::from_ast(node), - Annotatable::TraitItem(node) | Annotatable::ImplItem(node) => { - TokenStream::from_ast(node) - } + Annotatable::AssocItem(node, _) => TokenStream::from_ast(node), Annotatable::ForeignItem(node) => TokenStream::from_ast(node), Annotatable::Stmt(node) => { assert!(!matches!(node.kind, ast::StmtKind::Empty)); @@ -142,14 +136,14 @@ impl Annotatable { pub fn expect_trait_item(self) -> P { match self { - Annotatable::TraitItem(i) => i, + Annotatable::AssocItem(i, AssocCtxt::Trait) => i, _ => panic!("expected Item"), } } pub fn expect_impl_item(self) -> P { match self { - Annotatable::ImplItem(i) => i, + Annotatable::AssocItem(i, AssocCtxt::Impl) => i, _ => panic!("expected Item"), } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 9da4aa84db52..6c02c237115c 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -6,7 +6,7 @@ use crate::errors::{ }; use rustc_ast::ptr::P; use rustc_ast::token::{Delimiter, Token, TokenKind}; -use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, DelimSpacing, DelimSpan, Spacing}; +use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, Spacing}; use rustc_ast::tokenstream::{LazyAttrTokenStream, TokenTree}; use rustc_ast::NodeId; use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem}; @@ -298,47 +298,47 @@ impl<'a> StripUnconfigured<'a> { cfg_attr: &Attribute, (item, item_span): (ast::AttrItem, Span), ) -> Attribute { - // We are taking an attribute of the form `#[cfg_attr(pred, attr)]` - // and producing an attribute of the form `#[attr]`. We - // have captured tokens for `attr` itself, but we need to - // synthesize tokens for the wrapper `#` and `[]`, which - // we do below. + // Convert `#[cfg_attr(pred, attr)]` to `#[attr]`. - // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token - // for `attr` when we expand it to `#[attr]` + // Use the `#` from `#[cfg_attr(pred, attr)]` in the result `#[attr]`. let mut orig_trees = cfg_attr.token_trees().into_iter(); - let TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _) = - orig_trees.next().unwrap().clone() + let Some(TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _)) = + orig_trees.next() else { panic!("Bad tokens for attribute {cfg_attr:?}"); }; - // We don't really have a good span to use for the synthesized `[]` - // in `#[attr]`, so just use the span of the `#` token. - let bracket_group = AttrTokenTree::Delimited( - DelimSpan::from_single(pound_token.span), - DelimSpacing::new(Spacing::JointHidden, Spacing::Alone), - Delimiter::Bracket, - item.tokens - .as_ref() - .unwrap_or_else(|| panic!("Missing tokens for {item:?}")) - .to_attr_token_stream(), - ); - let trees = if cfg_attr.style == AttrStyle::Inner { - // For inner attributes, we do the same thing for the `!` in `#![some_attr]` - let TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _) = - orig_trees.next().unwrap().clone() + // For inner attributes, we do the same thing for the `!` in `#![attr]`. + let mut trees = if cfg_attr.style == AttrStyle::Inner { + let Some(TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _)) = + orig_trees.next() else { panic!("Bad tokens for attribute {cfg_attr:?}"); }; vec![ AttrTokenTree::Token(pound_token, Spacing::Joint), AttrTokenTree::Token(bang_token, Spacing::JointHidden), - bracket_group, ] } else { - vec![AttrTokenTree::Token(pound_token, Spacing::JointHidden), bracket_group] + vec![AttrTokenTree::Token(pound_token, Spacing::JointHidden)] }; + + // And the same thing for the `[`/`]` delimiters in `#[attr]`. + let Some(TokenTree::Delimited(delim_span, delim_spacing, Delimiter::Bracket, _)) = + orig_trees.next() + else { + panic!("Bad tokens for attribute {cfg_attr:?}"); + }; + trees.push(AttrTokenTree::Delimited( + delim_span, + delim_spacing, + Delimiter::Bracket, + item.tokens + .as_ref() + .unwrap_or_else(|| panic!("Missing tokens for {item:?}")) + .to_attr_token_stream(), + )); + let tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::new(trees))); let attr = attr::mk_attr_from_item( &self.sess.psess.attr_id_generator, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 26fc77c7f33d..3c43d47292fb 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -140,7 +140,7 @@ macro_rules! ast_fragments { AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr), $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)* $($(AstFragment::$Kind(ast) => - ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)* + ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast, $($args)*)),)?)* } } @@ -177,13 +177,13 @@ ast_fragments! { } TraitItems(SmallVec<[P; 1]>) { "trait item"; - many fn flat_map_trait_item; + many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Trait); fn make_trait_items; } ImplItems(SmallVec<[P; 1]>) { "impl item"; - many fn flat_map_impl_item; + many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl); fn make_impl_items; } @@ -833,7 +833,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx, deleg, &item, &suffixes, item.span, true, ); fragment_kind.expect_from_annotatables( - single_delegations.map(|item| Annotatable::ImplItem(P(item))), + single_delegations.map(|item| Annotatable::AssocItem(P(item), AssocCtxt::Impl)), ) } }) @@ -843,8 +843,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) { let kind = match item { Annotatable::Item(_) - | Annotatable::TraitItem(_) - | Annotatable::ImplItem(_) + | Annotatable::AssocItem(..) | Annotatable::ForeignItem(_) | Annotatable::Crate(..) => return, Annotatable::Stmt(stmt) => { @@ -1037,7 +1036,7 @@ pub(crate) fn ensure_complete_parse<'a>( } } -/// Wraps a call to `noop_visit_*` / `noop_flat_map_*` +/// Wraps a call to `walk_*` / `walk_flat_map_*` /// for an AST node that supports attributes /// (see the `Annotatable` enum) /// This method assigns a `NodeId`, and sets that `NodeId` @@ -1057,7 +1056,7 @@ pub(crate) fn ensure_complete_parse<'a>( /// * `id` is a mutable reference to the `NodeId` field /// of the current AST node. /// * `closure` is a closure that executes the -/// `noop_visit_*` / `noop_flat_map_*` method +/// `walk_*` / `walk_flat_map_*` method /// for the current AST node. macro_rules! assign_id { ($self:ident, $id:expr, $closure:expr) => {{ @@ -1091,10 +1090,10 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { fn descr() -> &'static str { unreachable!() } - fn noop_flat_map(self, _visitor: &mut V) -> Self::OutputTy { + fn walk_flat_map(self, _visitor: &mut V) -> Self::OutputTy { unreachable!() } - fn noop_visit(&mut self, _visitor: &mut V) { + fn walk(&mut self, _visitor: &mut V) { unreachable!() } fn is_mac_call(&self) -> bool { @@ -1118,12 +1117,12 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {} fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) { } - fn wrap_flat_map_node_noop_flat_map( + fn wrap_flat_map_node_walk_flat_map( node: Self, collector: &mut InvocationCollector<'_, '_>, - noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy, + walk_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy, ) -> Result { - Ok(noop_flat_map(node, collector)) + Ok(walk_flat_map(node, collector)) } fn expand_cfg_false( &mut self, @@ -1149,8 +1148,8 @@ impl InvocationCollectorNode for P { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_items() } - fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_item(self, visitor) + fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { + walk_flat_map_item(visitor, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, ItemKind::MacCall(..)) @@ -1177,13 +1176,13 @@ impl InvocationCollectorNode for P { fn flatten_outputs(items: impl Iterator) -> Self::OutputTy { items.flatten().collect() } - fn wrap_flat_map_node_noop_flat_map( + fn wrap_flat_map_node_walk_flat_map( mut node: Self, collector: &mut InvocationCollector<'_, '_>, - noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy, + walk_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy, ) -> Result { if !matches!(node.kind, ItemKind::Mod(..)) { - return Ok(noop_flat_map(node, collector)); + return Ok(walk_flat_map(node, collector)); } // Work around borrow checker not seeing through `P`'s deref. @@ -1253,7 +1252,7 @@ impl InvocationCollectorNode for P { let orig_dir_ownership = mem::replace(&mut ecx.current_expansion.dir_ownership, dir_ownership); - let res = Ok(noop_flat_map(node, collector)); + let res = Ok(walk_flat_map(node, collector)); collector.cx.current_expansion.dir_ownership = orig_dir_ownership; collector.cx.current_expansion.module = orig_module; @@ -1288,13 +1287,13 @@ impl InvocationCollectorNode for AstNodeWrapper, TraitItemTag> type ItemKind = AssocItemKind; const KIND: AstFragmentKind = AstFragmentKind::TraitItems; fn to_annotatable(self) -> Annotatable { - Annotatable::TraitItem(self.wrapped) + Annotatable::AssocItem(self.wrapped, AssocCtxt::Trait) } fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_trait_items() } - fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_item(self.wrapped, visitor) + fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { + walk_flat_map_item(visitor, self.wrapped) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) @@ -1329,13 +1328,13 @@ impl InvocationCollectorNode for AstNodeWrapper, ImplItemTag> type ItemKind = AssocItemKind; const KIND: AstFragmentKind = AstFragmentKind::ImplItems; fn to_annotatable(self) -> Annotatable { - Annotatable::ImplItem(self.wrapped) + Annotatable::AssocItem(self.wrapped, AssocCtxt::Impl) } fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_impl_items() } - fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_item(self.wrapped, visitor) + fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { + walk_flat_map_item(visitor, self.wrapped) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) @@ -1372,8 +1371,8 @@ impl InvocationCollectorNode for P { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_foreign_items() } - fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_item(self, visitor) + fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { + walk_flat_map_item(visitor, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, ForeignItemKind::MacCall(..)) @@ -1395,8 +1394,8 @@ impl InvocationCollectorNode for ast::Variant { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_variants() } - fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_variant(self, visitor) + fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { + walk_flat_map_variant(visitor, self) } } @@ -1408,8 +1407,8 @@ impl InvocationCollectorNode for ast::FieldDef { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_field_defs() } - fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_field_def(self, visitor) + fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { + walk_flat_map_field_def(visitor, self) } } @@ -1421,8 +1420,8 @@ impl InvocationCollectorNode for ast::PatField { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_pat_fields() } - fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_pat_field(self, visitor) + fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { + walk_flat_map_pat_field(visitor, self) } } @@ -1434,8 +1433,8 @@ impl InvocationCollectorNode for ast::ExprField { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_expr_fields() } - fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_expr_field(self, visitor) + fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { + walk_flat_map_expr_field(visitor, self) } } @@ -1447,8 +1446,8 @@ impl InvocationCollectorNode for ast::Param { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_params() } - fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_param(self, visitor) + fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { + walk_flat_map_param(visitor, self) } } @@ -1460,8 +1459,8 @@ impl InvocationCollectorNode for ast::GenericParam { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_generic_params() } - fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_generic_param(self, visitor) + fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { + walk_flat_map_generic_param(visitor, self) } } @@ -1473,8 +1472,8 @@ impl InvocationCollectorNode for ast::Arm { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_arms() } - fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_arm(self, visitor) + fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { + walk_flat_map_arm(visitor, self) } } @@ -1487,8 +1486,8 @@ impl InvocationCollectorNode for ast::Stmt { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_stmts() } - fn noop_flat_map(self, visitor: &mut V) -> Self::OutputTy { - noop_flat_map_stmt(self, visitor) + fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { + walk_flat_map_stmt(visitor, self) } fn is_mac_call(&self) -> bool { match &self.kind { @@ -1561,8 +1560,8 @@ impl InvocationCollectorNode for ast::Crate { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_crate() } - fn noop_visit(&mut self, visitor: &mut V) { - noop_visit_crate(self, visitor) + fn walk(&mut self, visitor: &mut V) { + walk_crate(visitor, self) } fn expand_cfg_false( &mut self, @@ -1587,8 +1586,8 @@ impl InvocationCollectorNode for P { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_ty() } - fn noop_visit(&mut self, visitor: &mut V) { - noop_visit_ty(self, visitor) + fn walk(&mut self, visitor: &mut V) { + walk_ty(visitor, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, ast::TyKind::MacCall(..)) @@ -1611,8 +1610,8 @@ impl InvocationCollectorNode for P { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_pat() } - fn noop_visit(&mut self, visitor: &mut V) { - noop_visit_pat(self, visitor) + fn walk(&mut self, visitor: &mut V) { + walk_pat(visitor, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, PatKind::MacCall(..)) @@ -1639,8 +1638,8 @@ impl InvocationCollectorNode for P { fn descr() -> &'static str { "an expression" } - fn noop_visit(&mut self, visitor: &mut V) { - noop_visit_expr(self, visitor) + fn walk(&mut self, visitor: &mut V) { + walk_expr(visitor, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, ExprKind::MacCall(..)) @@ -1665,8 +1664,8 @@ impl InvocationCollectorNode for AstNodeWrapper, OptExprTag> { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_opt_expr() } - fn noop_flat_map(mut self, visitor: &mut V) -> Self::OutputTy { - noop_visit_expr(&mut self.wrapped, visitor); + fn walk_flat_map(mut self, visitor: &mut V) -> Self::OutputTy { + walk_expr(visitor, &mut self.wrapped); Some(self.wrapped) } fn is_mac_call(&self) -> bool { @@ -1705,8 +1704,8 @@ impl InvocationCollectorNode for AstNodeWrapper, MethodReceiverTag> fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { AstNodeWrapper::new(fragment.make_method_receiver_expr(), MethodReceiverTag) } - fn noop_visit(&mut self, visitor: &mut V) { - noop_visit_expr(&mut self.wrapped, visitor) + fn walk(&mut self, visitor: &mut V) { + walk_expr(visitor, &mut self.wrapped) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) @@ -1993,9 +1992,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let traitless_qself = matches!(&deleg.qself, Some(qself) if qself.position == 0); let item = match node.to_annotatable() { - Annotatable::ImplItem(item) => item, + Annotatable::AssocItem(item, AssocCtxt::Impl) => item, ann @ (Annotatable::Item(_) - | Annotatable::TraitItem(_) + | Annotatable::AssocItem(..) | Annotatable::Stmt(_)) => { let span = ann.span(); self.cx.dcx().emit_err(GlobDelegationOutsideImpls { span }); @@ -2016,12 +2015,12 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { ); Node::flatten_outputs(single_delegations.map(|item| { let mut item = Node::from_item(item); - assign_id!(self, item.node_id_mut(), || item.noop_flat_map(self)) + assign_id!(self, item.node_id_mut(), || item.walk_flat_map(self)) })) } None => { - match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| { - assign_id!(this, node.node_id_mut(), || node.noop_flat_map(this)) + match Node::wrap_flat_map_node_walk_flat_map(node, self, |mut node, this| { + assign_id!(this, node.node_id_mut(), || node.walk_flat_map(this)) }) { Ok(output) => output, Err(returned_node) => { @@ -2069,7 +2068,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } None if node.delegation().is_some() => unreachable!(), None => { - assign_id!(self, node.node_id_mut(), || node.noop_visit(self)) + assign_id!(self, node.node_id_mut(), || node.walk(self)) } }; } @@ -2081,12 +2080,15 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.flat_map_node(node) } - fn flat_map_trait_item(&mut self, node: P) -> SmallVec<[P; 1]> { - self.flat_map_node(AstNodeWrapper::new(node, TraitItemTag)) - } - - fn flat_map_impl_item(&mut self, node: P) -> SmallVec<[P; 1]> { - self.flat_map_node(AstNodeWrapper::new(node, ImplItemTag)) + fn flat_map_assoc_item( + &mut self, + node: P, + ctxt: AssocCtxt, + ) -> SmallVec<[P; 1]> { + match ctxt { + AssocCtxt::Trait => self.flat_map_node(AstNodeWrapper::new(node, TraitItemTag)), + AssocCtxt::Impl => self.flat_map_node(AstNodeWrapper::new(node, ImplItemTag)), + } } fn flat_map_foreign_item( @@ -2145,11 +2147,11 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.cx.current_expansion.is_trailing_mac = true; // Don't use `assign_id` for this statement - it may get removed // entirely due to a `#[cfg]` on the contained expression - let res = noop_flat_map_stmt(node, self); + let res = walk_flat_map_stmt(self, node); self.cx.current_expansion.is_trailing_mac = false; res } - _ => noop_flat_map_stmt(node, self), + _ => walk_flat_map_stmt(self, node), }; } @@ -2193,7 +2195,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { &mut self.cx.current_expansion.dir_ownership, DirOwnership::UnownedViaBlock, ); - noop_visit_block(node, self); + walk_block(self, node); self.cx.current_expansion.dir_ownership = orig_dir_ownership; } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 62337756cd88..0da542d379d2 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -333,7 +333,7 @@ pub(super) fn transcribe<'a>( // jump back out of the Delimited, pop the result_stack and add the new results back to // the previous results (from outside the Delimited). mbe::TokenTree::Delimited(mut span, spacing, delimited) => { - mut_visit::visit_delim_span(&mut span, &mut marker); + mut_visit::visit_delim_span(&mut marker, &mut span); stack.push(Frame::new_delimited(delimited, span, *spacing)); result_stack.push(mem::take(&mut result)); } @@ -342,7 +342,7 @@ pub(super) fn transcribe<'a>( // preserve syntax context. mbe::TokenTree::Token(token) => { let mut token = token.clone(); - mut_visit::visit_token(&mut token, &mut marker); + mut_visit::visit_token(&mut marker, &mut token); let tt = TokenTree::Token(token, Spacing::Alone); result.push(tt); } diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index e21f041d69af..3fa909877cc7 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -1,8 +1,8 @@ use crate::expand::{AstFragment, AstFragmentKind}; -use rustc_ast as ast; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::token::Delimiter; +use rustc_ast::{self as ast, visit::AssocCtxt}; use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::Ident; use rustc_span::DUMMY_SP; @@ -209,7 +209,7 @@ impl MutVisitor for PlaceholderExpander { if arm.is_placeholder { self.remove(arm.id).make_arms() } else { - noop_flat_map_arm(arm, self) + walk_flat_map_arm(self, arm) } } @@ -217,7 +217,7 @@ impl MutVisitor for PlaceholderExpander { if field.is_placeholder { self.remove(field.id).make_expr_fields() } else { - noop_flat_map_expr_field(field, self) + walk_flat_map_expr_field(self, field) } } @@ -225,7 +225,7 @@ impl MutVisitor for PlaceholderExpander { if fp.is_placeholder { self.remove(fp.id).make_pat_fields() } else { - noop_flat_map_pat_field(fp, self) + walk_flat_map_pat_field(self, fp) } } @@ -236,7 +236,7 @@ impl MutVisitor for PlaceholderExpander { if param.is_placeholder { self.remove(param.id).make_generic_params() } else { - noop_flat_map_generic_param(param, self) + walk_flat_map_generic_param(self, param) } } @@ -244,7 +244,7 @@ impl MutVisitor for PlaceholderExpander { if p.is_placeholder { self.remove(p.id).make_params() } else { - noop_flat_map_param(p, self) + walk_flat_map_param(self, p) } } @@ -252,7 +252,7 @@ impl MutVisitor for PlaceholderExpander { if sf.is_placeholder { self.remove(sf.id).make_field_defs() } else { - noop_flat_map_field_def(sf, self) + walk_flat_map_field_def(self, sf) } } @@ -260,28 +260,31 @@ impl MutVisitor for PlaceholderExpander { if variant.is_placeholder { self.remove(variant.id).make_variants() } else { - noop_flat_map_variant(variant, self) + walk_flat_map_variant(self, variant) } } fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { match item.kind { ast::ItemKind::MacCall(_) => self.remove(item.id).make_items(), - _ => noop_flat_map_item(item, self), + _ => walk_flat_map_item(self, item), } } - fn flat_map_trait_item(&mut self, item: P) -> SmallVec<[P; 1]> { + fn flat_map_assoc_item( + &mut self, + item: P, + ctxt: AssocCtxt, + ) -> SmallVec<[P; 1]> { match item.kind { - ast::AssocItemKind::MacCall(_) => self.remove(item.id).make_trait_items(), - _ => noop_flat_map_item(item, self), - } - } - - fn flat_map_impl_item(&mut self, item: P) -> SmallVec<[P; 1]> { - match item.kind { - ast::AssocItemKind::MacCall(_) => self.remove(item.id).make_impl_items(), - _ => noop_flat_map_item(item, self), + ast::AssocItemKind::MacCall(_) => { + let it = self.remove(item.id); + match ctxt { + AssocCtxt::Trait => it.make_trait_items(), + AssocCtxt::Impl => it.make_impl_items(), + } + } + _ => walk_flat_map_item(self, item), } } @@ -291,35 +294,35 @@ impl MutVisitor for PlaceholderExpander { ) -> SmallVec<[P; 1]> { match item.kind { ast::ForeignItemKind::MacCall(_) => self.remove(item.id).make_foreign_items(), - _ => noop_flat_map_item(item, self), + _ => walk_flat_map_item(self, item), } } fn visit_expr(&mut self, expr: &mut P) { match expr.kind { ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_expr(), - _ => noop_visit_expr(expr, self), + _ => walk_expr(self, expr), } } fn visit_method_receiver_expr(&mut self, expr: &mut P) { match expr.kind { ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_method_receiver_expr(), - _ => noop_visit_expr(expr, self), + _ => walk_expr(self, expr), } } fn filter_map_expr(&mut self, expr: P) -> Option> { match expr.kind { ast::ExprKind::MacCall(_) => self.remove(expr.id).make_opt_expr(), - _ => noop_filter_map_expr(expr, self), + _ => noop_filter_map_expr(self, expr), } } fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { let (style, mut stmts) = match stmt.kind { ast::StmtKind::MacCall(mac) => (mac.style, self.remove(stmt.id).make_stmts()), - _ => return noop_flat_map_stmt(stmt, self), + _ => return walk_flat_map_stmt(self, stmt), }; if style == ast::MacStmtStyle::Semicolon { @@ -365,14 +368,14 @@ impl MutVisitor for PlaceholderExpander { fn visit_pat(&mut self, pat: &mut P) { match pat.kind { ast::PatKind::MacCall(_) => *pat = self.remove(pat.id).make_pat(), - _ => noop_visit_pat(pat, self), + _ => walk_pat(self, pat), } } fn visit_ty(&mut self, ty: &mut P) { match ty.kind { ast::TyKind::MacCall(_) => *ty = self.remove(ty.id).make_ty(), - _ => noop_visit_ty(ty, self), + _ => walk_ty(self, ty), } } @@ -380,7 +383,7 @@ impl MutVisitor for PlaceholderExpander { if krate.is_placeholder { *krate = self.remove(krate.id).make_crate(); } else { - noop_visit_crate(krate, self) + walk_crate(self, krate) } } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index bf773f2d4879..20b15499234e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -763,7 +763,7 @@ impl<'hir> Generics<'hir> { ) } - fn span_for_predicate_removal(&self, pos: usize) -> Span { + pub fn span_for_predicate_removal(&self, pos: usize) -> Span { let predicate = &self.predicates[pos]; let span = predicate.span(); @@ -806,15 +806,21 @@ impl<'hir> Generics<'hir> { return self.span_for_predicate_removal(predicate_pos); } - let span = bounds[bound_pos].span(); - if bound_pos == 0 { - // where T: ?Sized + Bar, Foo: Bar, - // ^^^^^^^^^ - span.to(bounds[1].span().shrink_to_lo()) + let bound_span = bounds[bound_pos].span(); + if bound_pos < bounds.len() - 1 { + // If there's another bound after the current bound + // include the following '+' e.g.: + // + // `T: Foo + CurrentBound + Bar` + // ^^^^^^^^^^^^^^^ + bound_span.to(bounds[bound_pos + 1].span().shrink_to_lo()) } else { - // where T: Bar + ?Sized, Foo: Bar, - // ^^^^^^^^^ - bounds[bound_pos - 1].span().shrink_to_hi().to(span) + // If the current bound is the last bound + // include the preceding '+' E.g.: + // + // `T: Foo + Bar + CurrentBound` + // ^^^^^^^^^^^^^^^ + bound_span.with_lo(bounds[bound_pos - 1].span().hi()) } } } diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index 10be69a9fbb8..db91a6ab2f49 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -888,7 +888,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let comma = if args.len() > 0 { ", " } else { "" }; let trait_path = self.tcx.def_path_str(trait_def_id); let method_name = self.tcx.item_name(self.def_id); - err.span_suggestion( + err.span_suggestion_verbose( expr.span, msg, format!("{trait_path}::{generics}::{method_name}({rcvr}{comma}{rest})"), @@ -939,18 +939,20 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - let span_lo_redundant_lt_args = lt_arg_spans[self.num_expected_lifetime_args()]; + let span_lo_redundant_lt_args = if self.num_expected_lifetime_args() == 0 { + lt_arg_spans[0] + } else { + lt_arg_spans[self.num_expected_lifetime_args() - 1] + }; let span_hi_redundant_lt_args = lt_arg_spans[lt_arg_spans.len() - 1]; - let span_redundant_lt_args = span_lo_redundant_lt_args.to(span_hi_redundant_lt_args); + let span_redundant_lt_args = + span_lo_redundant_lt_args.shrink_to_hi().to(span_hi_redundant_lt_args); debug!("span_redundant_lt_args: {:?}", span_redundant_lt_args); let num_redundant_lt_args = lt_arg_spans.len() - self.num_expected_lifetime_args(); - let msg_lifetimes = format!( - "remove {these} lifetime argument{s}", - these = pluralize!("this", num_redundant_lt_args), - s = pluralize!(num_redundant_lt_args), - ); + let msg_lifetimes = + format!("remove the lifetime argument{s}", s = pluralize!(num_redundant_lt_args)); err.span_suggestion( span_redundant_lt_args, @@ -979,18 +981,22 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } let span_lo_redundant_type_or_const_args = - gen_arg_spans[self.num_expected_type_or_const_args()]; + if self.num_expected_type_or_const_args() == 0 { + gen_arg_spans[0] + } else { + gen_arg_spans[self.num_expected_type_or_const_args() - 1] + }; let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1]; + let span_redundant_type_or_const_args = span_lo_redundant_type_or_const_args + .shrink_to_hi() + .to(span_hi_redundant_type_or_const_args); - let span_redundant_type_or_const_args = - span_lo_redundant_type_or_const_args.to(span_hi_redundant_type_or_const_args); debug!("span_redundant_type_or_const_args: {:?}", span_redundant_type_or_const_args); let num_redundant_gen_args = gen_arg_spans.len() - self.num_expected_type_or_const_args(); let msg_types_or_consts = format!( - "remove {these} generic argument{s}", - these = pluralize!("this", num_redundant_gen_args), + "remove the unnecessary generic argument{s}", s = pluralize!(num_redundant_gen_args), ); @@ -1036,7 +1042,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { .with_lo(self.path_segment.ident.span.hi()); let msg = format!( - "remove these {}generics", + "remove the unnecessary {}generics", if self.gen_args.parenthesized == hir::GenericArgsParentheses::ParenSugar { "parenthetical " } else { diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 9cb6124ab217..ae34ddeaa87d 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1846,7 +1846,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /// Determine if the associated item with the given DefId matches /// the desired name via a doc alias. fn matches_by_doc_alias(&self, def_id: DefId) -> bool { - let Some(name) = self.method_name else { + let Some(method) = self.method_name else { return false; }; let Some(local_def_id) = def_id.as_local() else { @@ -1863,7 +1863,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // #[rustc_confusables("foo", "bar"))] for n in confusables { if let Some(lit) = n.lit() - && name.as_str() == lit.symbol.as_str() + && method.name == lit.symbol { return true; } @@ -1883,14 +1883,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // #[doc(alias("foo", "bar"))] for n in nested { if let Some(lit) = n.lit() - && name.as_str() == lit.symbol.as_str() + && method.name == lit.symbol { return true; } } } else if let Some(meta) = v.meta_item() && let Some(lit) = meta.name_value_literal() - && name.as_str() == lit.symbol.as_str() + && method.name == lit.symbol { // #[doc(alias = "foo")] return true; diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 2f4e6a323083..5d4cc7561a63 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1424,7 +1424,7 @@ declare_lint! { Deny, "detects missing fragment specifiers in unused `macro_rules!` patterns", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #40107 ", }; } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index f479b18c7c43..f2261f4a43b8 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -188,31 +188,60 @@ fn suggest_changing_unsized_bound( continue; }; - for (pos, bound) in predicate.bounds.iter().enumerate() { - let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound else { - continue; - }; - if poly.trait_ref.trait_def_id() != def_id { - continue; - } - if predicate.origin == PredicateOrigin::ImplTrait && predicate.bounds.len() == 1 { - // For `impl ?Sized` with no other bounds, suggest `impl Sized` instead. - let bound_span = bound.span(); - if bound_span.can_be_used_for_suggestions() { - let question_span = bound_span.with_hi(bound_span.lo() + BytePos(1)); - suggestions.push(( + let unsized_bounds = predicate + .bounds + .iter() + .enumerate() + .filter(|(_, bound)| { + if let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound + && poly.trait_ref.trait_def_id() == def_id + { + true + } else { + false + } + }) + .collect::>(); + + if unsized_bounds.is_empty() { + continue; + } + + let mut push_suggestion = |sp, msg| suggestions.push((sp, String::new(), msg)); + + if predicate.bounds.len() == unsized_bounds.len() { + // All the bounds are unsized bounds, e.g. + // `T: ?Sized + ?Sized` or `_: impl ?Sized + ?Sized`, + // so in this case: + // - if it's an impl trait predicate suggest changing the + // the first bound to sized and removing the rest + // - Otherwise simply suggest removing the entire predicate + if predicate.origin == PredicateOrigin::ImplTrait { + let first_bound = unsized_bounds[0].1; + let first_bound_span = first_bound.span(); + if first_bound_span.can_be_used_for_suggestions() { + let question_span = + first_bound_span.with_hi(first_bound_span.lo() + BytePos(1)); + push_suggestion( question_span, - String::new(), SuggestChangingConstraintsMessage::ReplaceMaybeUnsizedWithSized, - )); + ); + + for (pos, _) in unsized_bounds.iter().skip(1) { + let sp = generics.span_for_bound_removal(where_pos, *pos); + push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized); + } } } else { + let sp = generics.span_for_predicate_removal(where_pos); + push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized); + } + } else { + // Some of the bounds are other than unsized. + // So push separate removal suggestion for each unsized bound + for (pos, _) in unsized_bounds { let sp = generics.span_for_bound_removal(where_pos, pos); - suggestions.push(( - sp, - String::new(), - SuggestChangingConstraintsMessage::RemoveMaybeUnsized, - )); + push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized); } } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 9307e3806812..4335d96737aa 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1268,7 +1268,7 @@ impl<'tcx> Ty<'tcx> { /// /// Returning true means the type is known to be `Freeze`. Returning /// `false` means nothing -- could be `Freeze`, might not be. - fn is_trivially_freeze(self) -> bool { + pub fn is_trivially_freeze(self) -> bool { match self.kind() { ty::Int(_) | ty::Uint(_) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 95bc8b3d0cbc..6ac8f0d00234 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -528,12 +528,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { end_block.unit() } - /// Binds the variables and ascribes types for a given `match` arm or - /// `let` binding. + /// For a top-level `match` arm or a `let` binding, binds the variables and + /// ascribes types, and also checks the match arm guard (if present). /// - /// Also check if the guard matches, if it's provided. /// `arm_scope` should be `Some` if and only if this is called for a /// `match` arm. + /// + /// In the presence of or-patterns, a match arm might have multiple + /// sub-branches representing different ways to match, with each sub-branch + /// requiring its own bindings and its own copy of the guard. This method + /// handles those sub-branches individually, and then has them jump together + /// to a common block. + /// + /// Returns a single block that the match arm can be lowered into. + /// (For `let` bindings, this is the code that can use the bindings.) fn bind_pattern( &mut self, outer_source_info: SourceInfo, @@ -638,12 +646,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Optimize the case of `let x: T = ...` to write directly // into `x` and then require that `T == typeof(x)`. - // - // Weirdly, this is needed to prevent the - // `intrinsic-move-val.rs` test case from crashing. That - // test works with uninitialized values in a rather - // dubious way, so it may be that the test is kind of - // broken. PatKind::AscribeUserType { subpattern: box Pat { @@ -1022,7 +1024,8 @@ impl<'tcx> PatternExtraData<'tcx> { } } -/// A pattern in a form suitable for generating code. +/// A pattern in a form suitable for lowering the match tree, with all irrefutable +/// patterns simplified away, and or-patterns sorted to the end. /// /// Here, "flat" indicates that the pattern's match pairs have been recursively /// simplified by [`Builder::simplify_match_pairs`]. They are not necessarily @@ -1055,36 +1058,89 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { ascriptions: Vec::new(), is_never: pattern.is_never_pattern(), }; - // Partly-flatten and sort the match pairs, while recording extra data. + // Recursively remove irrefutable match pairs, while recording their + // bindings/ascriptions, and sort or-patterns after other match pairs. cx.simplify_match_pairs(&mut match_pairs, &mut extra_data); Self { match_pairs, extra_data } } } +/// Candidates are a generalization of (a) top-level match arms, and +/// (b) sub-branches of or-patterns, allowing the match-lowering process to handle +/// them both in a mostly-uniform way. For example, the list of candidates passed +/// to [`Builder::match_candidates`] will often contain a mixture of top-level +/// candidates and or-pattern subcandidates. +/// +/// At the start of match lowering, there is one candidate for each match arm. +/// During match lowering, arms with or-patterns will be expanded into a tree +/// of candidates, where each "leaf" candidate represents one of the ways for +/// the arm pattern to successfully match. #[derive(Debug)] struct Candidate<'pat, 'tcx> { /// For the candidate to match, all of these must be satisfied... - // Invariant: all the match pairs are recursively simplified. - // Invariant: or-patterns must be sorted at the end. + /// + /// --- + /// Initially contains a list of match pairs created by [`FlatPat`], but is + /// subsequently mutated (in a queue-like way) while lowering the match tree. + /// When this list becomes empty, the candidate is fully matched and becomes + /// a leaf (see [`Builder::select_matched_candidate`]). + /// + /// Key mutations include: + /// + /// - When a match pair is fully satisfied by a test, it is removed from the + /// list, and its subpairs are added instead (see [`Builder::sort_candidate`]). + /// - During or-pattern expansion, any leading or-pattern is removed, and is + /// converted into subcandidates (see [`Builder::expand_and_match_or_candidates`]). + /// - After a candidate's subcandidates have been lowered, a copy of any remaining + /// or-patterns is added to each leaf subcandidate + /// (see [`Builder::test_remaining_match_pairs_after_or`]). + /// + /// Invariants: + /// - All [`TestCase::Irrefutable`] patterns have been removed by simplification. + /// - All or-patterns ([`TestCase::Or`]) have been sorted to the end. match_pairs: Vec>, /// ...and if this is non-empty, one of these subcandidates also has to match... - // Invariant: at the end of the algorithm, this must never contain a `is_never` candidate - // because that would break binding consistency. + /// + /// --- + /// Initially a candidate has no subcandidates; they are added (and then immediately + /// lowered) during or-pattern expansion. Their main function is to serve as _output_ + /// of match tree lowering, allowing later steps to see the leaf candidates that + /// represent a match of the entire match arm. + /// + /// A candidate no subcandidates is either incomplete (if it has match pairs left), + /// or is a leaf in the match tree. A candidate with one or more subcandidates is + /// an internal node in the match tree. + /// + /// Invariant: at the end of match tree lowering, this must not contain an + /// `is_never` candidate, because that would break binding consistency. + /// - See [`Builder::remove_never_subcandidates`]. subcandidates: Vec>, /// ...and if there is a guard it must be evaluated; if it's `false` then branch to `otherwise_block`. + /// + /// --- + /// For subcandidates, this is copied from the parent candidate, so it indicates + /// whether the enclosing match arm has a guard. has_guard: bool, - /// If the candidate matches, bindings and ascriptions must be established. + /// Holds extra pattern data that was prepared by [`FlatPat`], including bindings and + /// ascriptions that must be established if this candidate succeeds. extra_data: PatternExtraData<'tcx>, - /// If we filled `self.subcandidate`, we store here the span of the or-pattern they came from. - // Invariant: it is `None` iff `subcandidates.is_empty()`. + /// When setting `self.subcandidates`, we store here the span of the or-pattern they came from. + /// + /// --- + /// Invariant: it is `None` iff `subcandidates.is_empty()`. + /// - FIXME: We sometimes don't unset this when clearing `subcandidates`. or_span: Option, /// The block before the `bindings` have been established. + /// + /// After the match tree has been lowered, [`Builder::lower_match_arms`] + /// will use this as the start point for lowering bindings and guards, and + /// then jump to a shared block containing the arm body. pre_binding_block: Option, /// The block to branch to if the guard or a nested candidate fails to match. @@ -1144,14 +1200,24 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { /// A depth-first traversal of the `Candidate` and all of its recursive /// subcandidates. +/// +/// This signature is very generic, to support traversing candidate trees by +/// reference or by value, and to allow a mutable "context" to be shared by the +/// traversal callbacks. Most traversals can use the simpler +/// [`Candidate::visit_leaves`] wrapper instead. fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>( candidate: C, context: &mut T, + // Called when visiting a "leaf" candidate (with no subcandidates). visit_leaf: &mut impl FnMut(C, &mut T), + // Called when visiting a "node" candidate (with one or more subcandidates). + // Returns an iterator over the candidate's children (by value or reference). + // Can perform setup before visiting the node's children. get_children: impl Copy + Fn(C, &mut T) -> I, + // Called after visiting a "node" candidate's children. complete_children: impl Copy + Fn(&mut T), ) where - C: Borrow>, + C: Borrow>, // Typically `Candidate` or `&mut Candidate` I: Iterator, { if candidate.borrow().subcandidates.is_empty() { @@ -1182,6 +1248,24 @@ struct Ascription<'tcx> { variance: ty::Variance, } +/// Partial summary of a [`thir::Pat`], indicating what sort of test should be +/// performed to match/reject the pattern, and what the desired test outcome is. +/// This avoids having to perform a full match on [`thir::PatKind`] in some places, +/// and helps [`TestKind::Switch`] and [`TestKind::SwitchInt`] know what target +/// values to use. +/// +/// Created by [`MatchPairTree::for_pattern`], and then inspected primarily by: +/// - [`Builder::pick_test_for_match_pair`] (to choose a test) +/// - [`Builder::sort_candidate`] (to see how the test interacts with a match pair) +/// +/// Two variants are unlike the others and deserve special mention: +/// +/// - [`Self::Irrefutable`] is only used temporarily when building a [`MatchPairTree`]. +/// They are then flattened away by [`Builder::simplify_match_pairs`], with any +/// bindings/ascriptions incorporated into the enclosing [`FlatPat`]. +/// - [`Self::Or`] are not tested directly like the other variants. Instead they +/// participate in or-pattern expansion, where they are transformed into subcandidates. +/// - See [`Builder::expand_and_match_or_candidates`]. #[derive(Debug, Clone)] enum TestCase<'pat, 'tcx> { Irrefutable { binding: Option>, ascription: Option> }, @@ -1224,6 +1308,12 @@ pub(crate) struct MatchPairTree<'pat, 'tcx> { test_case: TestCase<'pat, 'tcx>, /// ... and these subpairs must match. + /// + /// --- + /// Subpairs typically represent tests that can only be performed after their + /// parent has succeeded. For example, the pattern `Some(3)` might have an + /// outer match pair that tests for the variant `Some`, and then a subpair + /// that tests its field for the value `3`. subpairs: Vec, /// The pattern this was created from. @@ -1234,15 +1324,22 @@ pub(crate) struct MatchPairTree<'pat, 'tcx> { #[derive(Clone, Debug, PartialEq)] enum TestKind<'tcx> { /// Test what enum variant a value is. + /// + /// The subset of expected variants is not stored here; instead they are + /// extracted from the [`TestCase`]s of the candidates participating in the + /// test. Switch { /// The enum type being tested. adt_def: ty::AdtDef<'tcx>, }, /// Test what value an integer or `char` has. + /// + /// The test's target values are not stored here; instead they are extracted + /// from the [`TestCase`]s of the candidates participating in the test. SwitchInt, - /// Test what value a `bool` has. + /// Test whether a `bool` is `true` or `false`. If, /// Test for equality with value, possibly after an unsizing coercion to @@ -1258,7 +1355,7 @@ enum TestKind<'tcx> { /// Test whether the value falls within an inclusive or exclusive range. Range(Box>), - /// Test that the length of the slice is equal to `len`. + /// Test that the length of the slice is `== len` or `>= len`. Len { len: u64, op: BinOp }, /// Call `Deref::deref[_mut]` on the value. @@ -1385,20 +1482,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// The main match algorithm. It begins with a set of candidates `candidates` and has the job of /// generating code that branches to an appropriate block if the scrutinee matches one of these /// candidates. The - /// candidates are sorted such that the first item in the list + /// candidates are ordered such that the first item in the list /// has the highest priority. When a candidate is found to match /// the value, we will set and generate a branch to the appropriate /// pre-binding block. /// /// If none of the candidates apply, we continue to the returned `otherwise_block`. /// - /// It might be surprising that the input can be non-exhaustive. - /// Indeed, for matches, initially, it is not, because all matches are - /// exhaustive in Rust. But during processing we sometimes divide - /// up the list of candidates and recurse with a non-exhaustive - /// list. This is how our lowering approach (called "backtracking - /// automaton" in the literature) works. - /// See [`Builder::test_candidates`] for more details. + /// Note that while `match` expressions in the Rust language are exhaustive, + /// candidate lists passed to this method are often _non-exhaustive_. + /// For example, the match lowering process will frequently divide up the + /// list of candidates, and recursively call this method with a non-exhaustive + /// subset of candidates. + /// See [`Builder::test_candidates`] for more details on this + /// "backtracking automata" approach. /// /// For an example of how we use `otherwise_block`, consider: /// ``` @@ -1478,14 +1575,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return start_block; } [first, remaining @ ..] if first.match_pairs.is_empty() => { - // The first candidate has satisfied all its match pairs; we link it up and continue - // with the remaining candidates. + // The first candidate has satisfied all its match pairs. + // We record the blocks that will be needed by match arm lowering, + // and then continue with the remaining candidates. let remainder_start = self.select_matched_candidate(first, start_block); remainder_start.and(remaining) } candidates if candidates.iter().any(|candidate| candidate.starts_with_or_pattern()) => { - // If any candidate starts with an or-pattern, we have to expand the or-pattern before we - // can proceed further. + // If any candidate starts with an or-pattern, we want to expand or-patterns + // before we do any more tests. + // + // The only candidate we strictly _need_ to expand here is the first one. + // But by expanding other candidates as early as possible, we unlock more + // opportunities to include them in test outcomes, making the match tree + // smaller and simpler. self.expand_and_match_or_candidates(span, scrutinee_span, start_block, candidates) } candidates => { @@ -1588,6 +1691,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until); // Expand one level of or-patterns for each candidate in `candidates_to_expand`. + // We take care to preserve the relative ordering of candidates, so that + // or-patterns are expanded in their parent's relative position. let mut expanded_candidates = Vec::new(); for candidate in candidates_to_expand.iter_mut() { if candidate.starts_with_or_pattern() { @@ -1608,7 +1713,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - // Process the expanded candidates. + // Recursively lower the part of the match tree represented by the + // expanded candidates. This is where subcandidates actually get lowered! let remainder_start = self.match_candidates( span, scrutinee_span, @@ -1628,6 +1734,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.remove_never_subcandidates(candidate); } } + // It's important to perform the above simplifications _before_ dealing + // with remaining match pairs, to avoid exponential blowup if possible + // (for trivial or-patterns), and avoid useless work (for never patterns). if let Some(last_candidate) = candidates_to_expand.last_mut() { self.test_remaining_match_pairs_after_or(span, scrutinee_span, last_candidate); } @@ -1808,6 +1917,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .all(|match_pair| matches!(match_pair.test_case, TestCase::Or { .. })) ); + // Visit each leaf candidate within this subtree, add a copy of the remaining + // match pairs to it, and then recursively lower the rest of the match tree + // from that point. candidate.visit_leaves(|leaf_candidate| { // At this point the leaf's own match pairs have all been lowered // and removed, so `extend` and assignment are equivalent, @@ -1860,17 +1972,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (match_place, test) } - /// Given a test, we sort the input candidates into several buckets. If a candidate only matches - /// in one of the branches of `test`, we move it there. If it could match in more than one of - /// the branches of `test`, we stop sorting candidates. + /// Given a test, we partition the input candidates into several buckets. + /// If a candidate matches in exactly one of the branches of `test` + /// (and no other branches), we put it into the corresponding bucket. + /// If it could match in more than one of the branches of `test`, the test + /// doesn't usefully apply to it, and we stop partitioning candidates. + /// + /// Importantly, we also **mutate** the branched candidates to remove match pairs + /// that are entailed by the outcome of the test, and add any sub-pairs of the + /// removed pairs. /// /// This returns a pair of /// - the candidates that weren't sorted; /// - for each possible outcome of the test, the candidates that match in that outcome. /// - /// Moreover, we transform the branched candidates to reflect the fact that we know which - /// outcome of `test` occurred. - /// /// For example: /// ``` /// # let (x, y, z) = (true, true, true); @@ -1883,14 +1998,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// # ; /// ``` /// - /// Assume we are testing on `x`. There are 2 overlapping candidate sets: - /// - If the outcome is that `x` is true, candidates 0, 2, and 3 - /// - If the outcome is that `x` is false, candidates 1 and 2 + /// Assume we are testing on `x`. Conceptually, there are 2 overlapping candidate sets: + /// - If the outcome is that `x` is true, candidates {0, 2, 3} are possible + /// - If the outcome is that `x` is false, candidates {1, 2} are possible /// - /// Following our algorithm, candidate 0 is sorted into outcome `x == true`, candidate 1 goes - /// into outcome `x == false`, and candidate 2 and 3 remain unsorted. + /// Following our algorithm: + /// - Candidate 0 is sorted into outcome `x == true` + /// - Candidate 1 is sorted into outcome `x == false` + /// - Candidate 2 remains unsorted, because testing `x` has no effect on it + /// - Candidate 3 remains unsorted, because a previous candidate (2) was unsorted + /// - This helps preserve the illusion that candidates are tested "in order" /// - /// The sorted candidates are transformed: + /// The sorted candidates are mutated to remove entailed match pairs: /// - candidate 0 becomes `[z @ true]` since we know that `x` was `true`; /// - candidate 1 becomes `[y @ false]` since we know that `x` was `false`. fn sort_candidates<'b, 'c, 'pat>( @@ -1933,15 +2052,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (candidates, target_candidates) } - /// This is the most subtle part of the match lowering algorithm. At this point, the input - /// candidates have been fully simplified, so all remaining match-pairs require some sort of - /// test. + /// This is the most subtle part of the match lowering algorithm. At this point, there are + /// no fully-satisfied candidates, and no or-patterns to expand, so we actually need to + /// perform some sort of test to make progress. /// /// Once we pick what sort of test we are going to perform, this test will help us winnow down /// our candidates. So we walk over the candidates (from high to low priority) and check. We - /// compute, for each outcome of the test, a transformed list of candidates. If a candidate - /// matches in a single branch of our test, we add it to the corresponding outcome. We also - /// transform it to record the fact that we know which outcome occurred. + /// compute, for each outcome of the test, a list of (modified) candidates. If a candidate + /// matches in exactly one branch of our test, we add it to the corresponding outcome. We also + /// **mutate its list of match pairs** if appropriate, to reflect the fact that we know which + /// outcome occurred. /// /// For example, if we are testing `x.0`'s variant, and we have a candidate `(x.0 @ Some(v), x.1 /// @ 22)`, then we would have a resulting candidate of `((x.0 as Some).0 @ v, x.1 @ 22)` in the @@ -2036,32 +2156,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], start_block: BasicBlock, ) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> { - // Extract the match-pair from the highest priority candidate and build a test from it. + // Choose a match pair from the first candidate, and use it to determine a + // test to perform that will confirm or refute that match pair. let (match_place, test) = self.pick_test(candidates); // For each of the N possible test outcomes, build the vector of candidates that applies if - // the test has that particular outcome. + // the test has that particular outcome. This also mutates the candidates to remove match + // pairs that are fully satisfied by the relevant outcome. let (remaining_candidates, target_candidates) = self.sort_candidates(match_place, &test, candidates); - // The block that we should branch to if none of the - // `target_candidates` match. + // The block that we should branch to if none of the `target_candidates` match. let remainder_start = self.cfg.start_new_block(); - // For each outcome of test, process the candidates that still apply. + // For each outcome of the test, recursively lower the rest of the match tree + // from that point. (Note that we haven't lowered the actual test yet!) let target_blocks: FxIndexMap<_, _> = target_candidates .into_iter() .map(|(branch, mut candidates)| { let branch_start = self.cfg.start_new_block(); + // Recursively lower the rest of the match tree after the relevant outcome. let branch_otherwise = self.match_candidates(span, scrutinee_span, branch_start, &mut *candidates); + + // Link up the `otherwise` block of the subtree to `remainder_start`. let source_info = self.source_info(span); self.cfg.goto(branch_otherwise, source_info, remainder_start); (branch, branch_start) }) .collect(); - // Perform the test, branching to one of N blocks. + // Perform the chosen test, branching to one of the N subtrees prepared above + // (or to `remainder_start` if no outcome was satisfied). self.perform_test( span, scrutinee_span, diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 8a02ea1a06de..802193b8ddfd 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -51,6 +51,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestCase::Never => TestKind::Never, + // Or-patterns are not tested directly; instead they are expanded into subcandidates, + // which are then distinguished by testing whatever non-or patterns they contain. TestCase::Or { .. } => bug!("or-patterns should have already been handled"), TestCase::Irrefutable { .. } => span_bug!( @@ -544,6 +546,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .enumerate() .find(|&(_, mp)| mp.place == Some(test_place))?; + // If true, the match pair is completely entailed by its corresponding test + // branch, so it can be removed. If false, the match pair is _compatible_ + // with its test branch, but still needs a more specific test. let fully_matched; let ret = match (&test.kind, &match_pair.test_case) { // If we are performing a variant switch, then this @@ -565,8 +570,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (TestKind::SwitchInt, &TestCase::Constant { value }) if is_switch_ty(match_pair.pattern.ty) => { - // Beware: there might be some ranges sorted into the failure case; we must not add - // a success case that could be matched by one of these ranges. + // An important invariant of candidate sorting is that a candidate + // must not match in multiple branches. For `SwitchInt` tests, adding + // a new value might invalidate that property for range patterns that + // have already been sorted into the failure arm, so we must take care + // not to add such values here. let is_covering_range = |test_case: &TestCase<'_, 'tcx>| { test_case.as_range().is_some_and(|range| { matches!(range.contains(value, self.tcx, self.param_env), None | Some(true)) @@ -591,6 +599,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } (TestKind::SwitchInt, TestCase::Range(range)) => { + // When performing a `SwitchInt` test, a range pattern can be + // sorted into the failure arm if it doesn't contain _any_ of + // the values being tested. (This restricts what values can be + // added to the test by subsequent candidates.) fully_matched = false; let not_contained = sorted_candidates.keys().filter_map(|br| br.as_constant()).copied().all( diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 2542108728f7..389a6d11e19e 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -10,7 +10,7 @@ use super::{ use crate::errors; use crate::maybe_recover_from_interpolated_ty_qpath; -use ast::mut_visit::{noop_visit_expr, MutVisitor}; +use ast::mut_visit::{self, MutVisitor}; use ast::token::IdentIsRaw; use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered}; use core::mem; @@ -3939,14 +3939,14 @@ impl MutVisitor for CondChecker<'_> { } } ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => { - noop_visit_expr(e, self); + mut_visit::walk_expr(self, e); } ExprKind::Binary(Spanned { node: BinOpKind::Or, span: or_span }, _, _) if let None | Some(NotSupportedOr(_)) = self.forbid_let_reason => { let forbid_let_reason = self.forbid_let_reason; self.forbid_let_reason = Some(NotSupportedOr(or_span)); - noop_visit_expr(e, self); + mut_visit::walk_expr(self, e); self.forbid_let_reason = forbid_let_reason; } ExprKind::Paren(ref inner) @@ -3954,7 +3954,7 @@ impl MutVisitor for CondChecker<'_> { { let forbid_let_reason = self.forbid_let_reason; self.forbid_let_reason = Some(NotSupportedParentheses(inner.span)); - noop_visit_expr(e, self); + mut_visit::walk_expr(self, e); self.forbid_let_reason = forbid_let_reason; } ExprKind::Assign(ref lhs, _, span) => { @@ -3972,7 +3972,7 @@ impl MutVisitor for CondChecker<'_> { } let comparison = self.comparison; self.comparison = Some(errors::MaybeComparison { span: span.shrink_to_hi() }); - noop_visit_expr(e, self); + mut_visit::walk_expr(self, e); self.forbid_let_reason = forbid_let_reason; self.missing_let = missing_let; self.comparison = comparison; @@ -3992,7 +3992,7 @@ impl MutVisitor for CondChecker<'_> { | ExprKind::Paren(_) => { let forbid_let_reason = self.forbid_let_reason; self.forbid_let_reason = Some(OtherForbidden); - noop_visit_expr(e, self); + mut_visit::walk_expr(self, e); self.forbid_let_reason = forbid_let_reason; } ExprKind::Cast(ref mut op, _) | ExprKind::Type(ref mut op, _) => { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 18d531faeaa1..aa818878cd81 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -12,7 +12,7 @@ use crate::errors::{ }; use crate::parser::expr::{could_be_unclosed_char_literal, LhsExpr}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; -use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; +use rustc_ast::mut_visit::{walk_pat, MutVisitor}; use rustc_ast::ptr::P; use rustc_ast::token::{self, BinOpToken, Delimiter, Token}; use rustc_ast::{ @@ -810,7 +810,7 @@ impl<'a> Parser<'a> { self.0 = true; *m = Mutability::Mut; } - noop_visit_pat(pat, self); + walk_pat(self, pat); } } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 4c3d833b0f90..06b79ea63ca4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -772,7 +772,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } - ty::Alias(ty::Opaque, _) => { + ty::Alias(ty::Opaque, alias) => { if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(_))) { // We do not generate an auto impl candidate for `impl Trait`s which already // reference our auto trait. @@ -787,6 +787,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We do not emit auto trait candidates for opaque types in coherence. // Doing so can result in weird dependency cycles. candidates.ambiguous = true; + } else if self.infcx.can_define_opaque_ty(alias.def_id) { + // We do not emit auto trait candidates for opaque types in their defining scope, as + // we need to know the hidden type first, which we can't reliably know within the defining + // scope. + candidates.ambiguous = true; } else { candidates.vec.push(AutoImplCandidate) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index d6590322caab..c007cd5314a8 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1498,7 +1498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return false; } - // Avoid using the master cache during coherence and just rely + // Avoid using the global cache during coherence and just rely // on the local cache. This effectively disables caching // during coherence. It is really just a simplification to // avoid us having to fear that coherence results "pollute" @@ -1509,6 +1509,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return false; } + // Avoid using the global cache when we're defining opaque types + // as their hidden type may impact the result of candidate selection. + if !self.infcx.defining_opaque_types().is_empty() { + return false; + } + // Otherwise, we can use the global cache. true } @@ -2380,13 +2386,17 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { - // We can resolve the `impl Trait` to its concrete type, - // which enforces a DAG between the functions requiring - // the auto trait bounds in question. - match self.tcx().type_of_opaque(def_id) { - Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]), - Err(_) => { - return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); + if self.infcx.can_define_opaque_ty(def_id) { + unreachable!() + } else { + // We can resolve the `impl Trait` to its concrete type, + // which enforces a DAG between the functions requiring + // the auto trait bounds in question. + match self.tcx().type_of_opaque(def_id) { + Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]), + Err(_) => { + return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); + } } } } diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index af01db19139e..fe1ff2413955 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -484,7 +484,7 @@ impl BinaryHeap { /// heap.push(4); /// ``` #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_binary_heap_new_in", issue = "112353")] + #[rustc_const_unstable(feature = "const_binary_heap_new_in", issue = "125961")] #[must_use] pub const fn new_in(alloc: A) -> BinaryHeap { BinaryHeap { data: Vec::new_in(alloc) } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index a7715740cbd8..4491a717dc2e 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -101,6 +101,7 @@ #![feature(array_windows)] #![feature(ascii_char)] #![feature(assert_matches)] +#![feature(async_closure)] #![feature(async_fn_traits)] #![feature(async_iterator)] #![feature(clone_to_uninit)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 9982c8ea6dcb..bfe3ea208001 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -259,7 +259,7 @@ use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -use core::mem::{self, align_of_val_raw, forget, ManuallyDrop}; +use core::mem::{self, align_of_val_raw, ManuallyDrop}; use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; #[cfg(not(no_global_oom_handling))] @@ -908,19 +908,18 @@ impl Rc { #[stable(feature = "rc_unique", since = "1.4.0")] pub fn try_unwrap(this: Self) -> Result { if Rc::strong_count(&this) == 1 { - unsafe { - let val = ptr::read(&*this); // copy the contained object - let alloc = ptr::read(&this.alloc); // copy the allocator + let this = ManuallyDrop::new(this); - // Indicate to Weaks that they can't be promoted by decrementing - // the strong count, and then remove the implicit "strong weak" - // pointer while also handling drop logic by just crafting a - // fake Weak. - this.inner().dec_strong(); - let _weak = Weak { ptr: this.ptr, alloc }; - forget(this); - Ok(val) - } + let val: T = unsafe { ptr::read(&**this) }; // copy the contained object + let alloc: A = unsafe { ptr::read(&this.alloc) }; // copy the allocator + + // Indicate to Weaks that they can't be promoted by decrementing + // the strong count, and then remove the implicit "strong weak" + // pointer while also handling drop logic by just crafting a + // fake Weak. + this.inner().dec_strong(); + let _weak = Weak { ptr: this.ptr, alloc }; + Ok(val) } else { Err(this) } @@ -1354,9 +1353,8 @@ impl Rc { #[stable(feature = "rc_raw", since = "1.17.0")] #[rustc_never_returns_null_ptr] pub fn into_raw(this: Self) -> *const T { - let ptr = Self::as_ptr(&this); - mem::forget(this); - ptr + let this = ManuallyDrop::new(this); + Self::as_ptr(&*this) } /// Consumes the `Rc`, returning the wrapped pointer and allocator. @@ -2127,7 +2125,7 @@ impl Rc<[T]> { } // All clear. Forget the guard so it doesn't free the new RcBox. - forget(guard); + mem::forget(guard); Self::from_ptr(ptr) } @@ -3080,9 +3078,7 @@ impl Weak { #[must_use = "losing the pointer will leak memory"] #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn into_raw(self) -> *const T { - let result = self.as_ptr(); - mem::forget(self); - result + mem::ManuallyDrop::new(self).as_ptr() } /// Consumes the `Weak`, returning the wrapped pointer and allocator. @@ -3762,10 +3758,11 @@ impl UniqueRcUninit { /// # Safety /// /// The data must have been initialized (by writing to [`Self::data_ptr()`]). - unsafe fn into_rc(mut self) -> Rc { - let ptr = self.ptr; - let alloc = self.alloc.take().unwrap(); - mem::forget(self); + unsafe fn into_rc(self) -> Rc { + let mut this = ManuallyDrop::new(self); + let ptr = this.ptr; + let alloc = this.alloc.take().unwrap(); + // SAFETY: The pointer is valid as per `UniqueRcUninit::new`, and the caller is responsible // for having initialized the data. unsafe { Rc::from_ptr_in(ptr.as_ptr(), alloc) } diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 3bb808a6c73a..94053ef83a0e 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -269,7 +269,7 @@ impl str { without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String { + pub fn replace(&self, from: P, to: &str) -> String { let mut result = String::new(); let mut last_end = 0; for (start, part) in self.match_indices(from) { @@ -309,7 +309,7 @@ impl str { #[must_use = "this returns the replaced string as a new allocation, \ without modifying the original"] #[stable(feature = "str_replacen", since = "1.16.0")] - pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String { + pub fn replacen(&self, pat: P, to: &str, count: usize) -> String { // Hope to reduce the times of re-allocation let mut result = String::with_capacity(32); let mut last_end = 0; diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 07ffd3e15191..0ff66167a46a 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1497,10 +1497,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "string_remove_matches", reason = "new API", issue = "72826")] - pub fn remove_matches<'a, P>(&'a mut self, pat: P) - where - P: for<'x> Pattern<'x>, - { + pub fn remove_matches(&mut self, pat: P) { use core::str::pattern::Searcher; let rejections = { @@ -2288,35 +2285,41 @@ impl<'a> Extend> for String { reason = "API not fully fleshed out and ready to be stabilized", issue = "27721" )] -impl<'a, 'b> Pattern<'a> for &'b String { - type Searcher = <&'b str as Pattern<'a>>::Searcher; +impl<'b> Pattern for &'b String { + type Searcher<'a> = <&'b str as Pattern>::Searcher<'a>; - fn into_searcher(self, haystack: &'a str) -> <&'b str as Pattern<'a>>::Searcher { + fn into_searcher(self, haystack: &str) -> <&'b str as Pattern>::Searcher<'_> { self[..].into_searcher(haystack) } #[inline] - fn is_contained_in(self, haystack: &'a str) -> bool { + fn is_contained_in(self, haystack: &str) -> bool { self[..].is_contained_in(haystack) } #[inline] - fn is_prefix_of(self, haystack: &'a str) -> bool { + fn is_prefix_of(self, haystack: &str) -> bool { self[..].is_prefix_of(haystack) } #[inline] - fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> { + fn strip_prefix_of(self, haystack: &str) -> Option<&str> { self[..].strip_prefix_of(haystack) } #[inline] - fn is_suffix_of(self, haystack: &'a str) -> bool { + fn is_suffix_of<'a>(self, haystack: &'a str) -> bool + where + Self::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>, + { self[..].is_suffix_of(haystack) } #[inline] - fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> { + fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&str> + where + Self::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>, + { self[..].strip_suffix_of(haystack) } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index a905a1e6b7e6..c36b8f6a1ac8 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -20,7 +20,7 @@ use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -use core::mem::{self, align_of_val_raw}; +use core::mem::{self, align_of_val_raw, ManuallyDrop}; use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; use core::pin::Pin; @@ -960,16 +960,14 @@ impl Arc { acquire!(this.inner().strong); - unsafe { - let elem = ptr::read(&this.ptr.as_ref().data); - let alloc = ptr::read(&this.alloc); // copy the allocator + let this = ManuallyDrop::new(this); + let elem: T = unsafe { ptr::read(&this.ptr.as_ref().data) }; + let alloc: A = unsafe { ptr::read(&this.alloc) }; // copy the allocator - // Make a weak pointer to clean up the implicit strong-weak reference - let _weak = Weak { ptr: this.ptr, alloc }; - mem::forget(this); + // Make a weak pointer to clean up the implicit strong-weak reference + let _weak = Weak { ptr: this.ptr, alloc }; - Ok(elem) - } + Ok(elem) } /// Returns the inner value, if the `Arc` has exactly one strong reference. @@ -1493,9 +1491,8 @@ impl Arc { #[stable(feature = "rc_raw", since = "1.17.0")] #[rustc_never_returns_null_ptr] pub fn into_raw(this: Self) -> *const T { - let ptr = Self::as_ptr(&this); - mem::forget(this); - ptr + let this = ManuallyDrop::new(this); + Self::as_ptr(&*this) } /// Consumes the `Arc`, returning the wrapped pointer and allocator. @@ -2801,9 +2798,7 @@ impl Weak { #[must_use = "losing the pointer will leak memory"] #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn into_raw(self) -> *const T { - let result = self.as_ptr(); - mem::forget(self); - result + ManuallyDrop::new(self).as_ptr() } /// Consumes the `Weak`, returning the wrapped pointer and allocator. @@ -3875,13 +3870,14 @@ impl UniqueArcUninit { /// # Safety /// /// The data must have been initialized (by writing to [`Self::data_ptr()`]). - unsafe fn into_arc(mut self) -> Arc { - let ptr = self.ptr; - let alloc = self.alloc.take().unwrap(); - mem::forget(self); + unsafe fn into_arc(self) -> Arc { + let mut this = ManuallyDrop::new(self); + let ptr = this.ptr.as_ptr(); + let alloc = this.alloc.take().unwrap(); + // SAFETY: The pointer is valid as per `UniqueArcUninit::new`, and the caller is responsible // for having initialized the data. - unsafe { Arc::from_ptr_in(ptr.as_ptr(), alloc) } + unsafe { Arc::from_ptr_in(ptr, alloc) } } } diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 0078f5eaa3d2..de5d3991c914 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1927,12 +1927,10 @@ mod pattern { } } - fn cmp_search_to_vec<'a>( - rev: bool, - pat: impl Pattern<'a, Searcher: ReverseSearcher<'a>>, - haystack: &'a str, - right: Vec, - ) { + fn cmp_search_to_vec

(rev: bool, pat: P, haystack: &str, right: Vec) + where + P: for<'a> Pattern: ReverseSearcher<'a>>, + { let mut searcher = pat.into_searcher(haystack); let mut v = vec![]; loop { @@ -2191,9 +2189,9 @@ generate_iterator_test! { fn different_str_pattern_forwarding_lifetimes() { use std::str::pattern::Pattern; - fn foo<'a, P>(p: P) + fn foo

(p: P) where - for<'b> &'b P: Pattern<'a>, + for<'b> &'b P: Pattern, { for _ in 0..3 { "asdf".find(&p); diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 0b92767c9320..e96a41422a2a 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -183,6 +183,8 @@ impl Layout { /// - a [slice], then the length of the slice tail must be an initialized /// integer, and the size of the *entire value* /// (dynamic tail length + statically sized prefix) must fit in `isize`. + /// For the special case where the dynamic tail length is 0, this function + /// is safe to call. /// - a [trait object], then the vtable part of the pointer must point /// to a valid vtable for the type `T` acquired by an unsizing coercion, /// and the size of the *entire value* diff --git a/library/core/src/error.rs b/library/core/src/error.rs index ca8983d4cbcf..19b7bb44f855 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -506,7 +506,7 @@ where /// ``` /// #[unstable(feature = "error_generic_member_access", issue = "99301")] -#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435 +#[repr(transparent)] pub struct Request<'a>(Tagged + 'a>); impl<'a> Request<'a> { diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 563f0a324e3f..c9111254082d 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -103,7 +103,7 @@ use crate::str; // However, `CStr` layout is considered an implementation detail and must not be relied upon. We // want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under // `cfg(doc)`. This is an ad-hoc implementation of attribute privacy. -#[cfg_attr(not(doc), repr(transparent))] +#[repr(transparent)] #[allow(clippy::derived_hash_with_manual_eq)] pub struct CStr { // FIXME: this should not be represented with a DST slice but rather with diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 88adc378477f..93426b90c706 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -191,7 +191,7 @@ mod c_long_definition { // be UB. #[doc = include_str!("c_void.md")] #[lang = "c_void"] -#[cfg_attr(not(doc), repr(u8))] // work around https://github.com/rust-lang/rust/issues/90435 +#[cfg_attr(not(doc), repr(u8))] // An implementation detail we don't want to show up in rustdoc #[stable(feature = "core_c_void", since = "1.30.0")] pub enum c_void { #[unstable( diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 6a2e8b67d0c2..f4c746225dc0 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -23,7 +23,7 @@ use crate::ops::{Deref, DerefMut}; target_os = "uefi", windows, ))] -#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435 +#[repr(transparent)] #[lang = "va_list"] pub struct VaListImpl<'f> { ptr: *mut c_void, @@ -115,7 +115,7 @@ pub struct VaListImpl<'f> { } /// A wrapper for a `va_list` -#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435 +#[repr(transparent)] #[derive(Debug)] pub struct VaList<'a, 'f: 'a> { #[cfg(any( diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index dd4b6e823434..9bb4ba922cd4 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -359,6 +359,12 @@ pub const fn size_of_val(val: &T) -> usize { /// - a [slice], then the length of the slice tail must be an initialized /// integer, and the size of the *entire value* /// (dynamic tail length + statically sized prefix) must fit in `isize`. +/// For the special case where the dynamic tail length is 0, this function +/// is safe to call. +// NOTE: the reason this is safe is that if an overflow were to occur already with size 0, +// then we would stop compilation as even the "statically known" part of the type would +// already be too big (or the call may be in dead code and optimized away, but then it +// doesn't matter). /// - a [trait object], then the vtable part of the pointer must point /// to a valid vtable acquired by an unsizing coercion, and the size /// of the *entire value* (dynamic tail length + statically sized prefix) @@ -506,6 +512,8 @@ pub const fn align_of_val(val: &T) -> usize { /// - a [slice], then the length of the slice tail must be an initialized /// integer, and the size of the *entire value* /// (dynamic tail length + statically sized prefix) must fit in `isize`. +/// For the special case where the dynamic tail length is 0, this function +/// is safe to call. /// - a [trait object], then the vtable part of the pointer must point /// to a valid vtable acquired by an unsizing coercion, and the size /// of the *entire value* (dynamic tail length + statically sized prefix) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index d50bcde01571..e6bdc4d450d4 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -65,8 +65,13 @@ macro_rules! uint_impl { /// /// ``` #[doc = concat!("let n = 0b01001100", stringify!($SelfT), ";")] - /// /// assert_eq!(n.count_ones(), 3); + /// + #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")] + #[doc = concat!("assert_eq!(max.count_ones(), ", stringify!($BITS), ");")] + /// + #[doc = concat!("let zero = 0", stringify!($SelfT), ";")] + /// assert_eq!(zero.count_ones(), 0); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] @@ -86,7 +91,11 @@ macro_rules! uint_impl { /// Basic usage: /// /// ``` - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);")] + #[doc = concat!("let zero = 0", stringify!($SelfT), ";")] + #[doc = concat!("assert_eq!(zero.count_zeros(), ", stringify!($BITS), ");")] + /// + #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")] + /// assert_eq!(max.count_zeros(), 0); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] @@ -108,8 +117,13 @@ macro_rules! uint_impl { /// /// ``` #[doc = concat!("let n = ", stringify!($SelfT), "::MAX >> 2;")] - /// /// assert_eq!(n.leading_zeros(), 2); + /// + #[doc = concat!("let zero = 0", stringify!($SelfT), ";")] + #[doc = concat!("assert_eq!(zero.leading_zeros(), ", stringify!($BITS), ");")] + /// + #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")] + /// assert_eq!(max.leading_zeros(), 0); /// ``` #[doc = concat!("[`ilog2`]: ", stringify!($SelfT), "::ilog2")] #[stable(feature = "rust1", since = "1.0.0")] @@ -130,8 +144,13 @@ macro_rules! uint_impl { /// /// ``` #[doc = concat!("let n = 0b0101000", stringify!($SelfT), ";")] - /// /// assert_eq!(n.trailing_zeros(), 3); + /// + #[doc = concat!("let zero = 0", stringify!($SelfT), ";")] + #[doc = concat!("assert_eq!(zero.trailing_zeros(), ", stringify!($BITS), ");")] + /// + #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")] + #[doc = concat!("assert_eq!(max.trailing_zeros(), 0);")] /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] @@ -150,8 +169,13 @@ macro_rules! uint_impl { /// /// ``` #[doc = concat!("let n = !(", stringify!($SelfT), "::MAX >> 2);")] - /// /// assert_eq!(n.leading_ones(), 2); + /// + #[doc = concat!("let zero = 0", stringify!($SelfT), ";")] + /// assert_eq!(zero.leading_ones(), 0); + /// + #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")] + #[doc = concat!("assert_eq!(max.leading_ones(), ", stringify!($BITS), ");")] /// ``` #[stable(feature = "leading_trailing_ones", since = "1.46.0")] #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] @@ -171,8 +195,13 @@ macro_rules! uint_impl { /// /// ``` #[doc = concat!("let n = 0b1010111", stringify!($SelfT), ";")] - /// /// assert_eq!(n.trailing_ones(), 3); + /// + #[doc = concat!("let zero = 0", stringify!($SelfT), ";")] + /// assert_eq!(zero.trailing_ones(), 0); + /// + #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")] + #[doc = concat!("assert_eq!(max.trailing_ones(), ", stringify!($BITS), ");")] /// ``` #[stable(feature = "leading_trailing_ones", since = "1.46.0")] #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] @@ -736,6 +765,67 @@ macro_rules! uint_impl { } } + #[doc = concat!( + "Checked integer subtraction. Computes `self - rhs` and checks if the result fits into an [`", + stringify!($SignedT), "`], returning `None` if overflow occurred." + )] + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(unsigned_signed_diff)] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_signed_diff(2), Some(8));")] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_signed_diff(10), Some(-8));")] + #[doc = concat!( + "assert_eq!(", + stringify!($SelfT), + "::MAX.checked_signed_diff(", + stringify!($SignedT), + "::MAX as ", + stringify!($SelfT), + "), None);" + )] + #[doc = concat!( + "assert_eq!((", + stringify!($SignedT), + "::MAX as ", + stringify!($SelfT), + ").checked_signed_diff(", + stringify!($SelfT), + "::MAX), Some(", + stringify!($SignedT), + "::MIN));" + )] + #[doc = concat!( + "assert_eq!((", + stringify!($SignedT), + "::MAX as ", + stringify!($SelfT), + " + 1).checked_signed_diff(0), None);" + )] + #[doc = concat!( + "assert_eq!(", + stringify!($SelfT), + "::MAX.checked_signed_diff(", + stringify!($SelfT), + "::MAX), Some(0));" + )] + /// ``` + #[unstable(feature = "unsigned_signed_diff", issue = "126041")] + #[inline] + pub const fn checked_signed_diff(self, rhs: Self) -> Option<$SignedT> { + let res = self.wrapping_sub(rhs) as $SignedT; + let overflow = (self >= rhs) == (res < 0); + + if !overflow { + Some(res) + } else { + None + } + } + /// Checked integer multiplication. Computes `self * rhs`, returning /// `None` if overflow occurred. /// diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs index 48d1042d9df4..37fac2b126fa 100644 --- a/library/core/src/ops/async_function.rs +++ b/library/core/src/ops/async_function.rs @@ -4,7 +4,7 @@ use crate::marker::Tuple; /// An async-aware version of the [`Fn`](crate::ops::Fn) trait. /// /// All `async fn` and functions returning futures implement this trait. -#[unstable(feature = "async_fn_traits", issue = "none")] +#[unstable(feature = "async_closure", issue = "62290")] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -18,7 +18,7 @@ pub trait AsyncFn: AsyncFnMut { /// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait. /// /// All `async fn` and functions returning futures implement this trait. -#[unstable(feature = "async_fn_traits", issue = "none")] +#[unstable(feature = "async_closure", issue = "62290")] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] @@ -39,7 +39,7 @@ pub trait AsyncFnMut: AsyncFnOnce { /// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait. /// /// All `async fn` and functions returning futures implement this trait. -#[unstable(feature = "async_fn_traits", issue = "none")] +#[unstable(feature = "async_closure", issue = "62290")] #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] diff --git a/library/core/src/primitive.rs b/library/core/src/primitive.rs index e20b2c5c9382..81a72118614d 100644 --- a/library/core/src/primitive.rs +++ b/library/core/src/primitive.rs @@ -12,7 +12,7 @@ //! const SOME_PROPERTY: bool = true; //! } //! -//! # trait QueryId { const SOME_PROPERTY: core::primitive::bool; } +//! # trait QueryId { const SOME_PROPERTY: ::core::primitive::bool; } //! ``` //! //! Note that the `SOME_PROPERTY` associated constant would not compile, as its @@ -25,11 +25,17 @@ //! pub struct bool; //! //! impl QueryId for bool { -//! const SOME_PROPERTY: core::primitive::bool = true; +//! const SOME_PROPERTY: ::core::primitive::bool = true; //! } //! -//! # trait QueryId { const SOME_PROPERTY: core::primitive::bool; } +//! # trait QueryId { const SOME_PROPERTY: ::core::primitive::bool; } //! ``` +//! +//! We also used `::core` instead of `core`, because `core` can be +//! shadowed, too. Paths, starting with `::`, are searched in +//! the [extern prelude] since Edition 2018. +//! +//! [extern prelude]: https://doc.rust-lang.org/nightly/reference/names/preludes.html#extern-prelude #[stable(feature = "core_primitive", since = "1.43.0")] pub use bool; diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 68508e85f8e1..6d3e625bef42 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -4522,6 +4522,121 @@ impl [T] { // are disjunct and in bounds. unsafe { Ok(self.get_many_unchecked_mut(indices)) } } + + /// Returns the index that an element reference points to. + /// + /// Returns `None` if `element` does not point within the slice or if it points between elements. + /// + /// This method is useful for extending slice iterators like [`slice::split`]. + /// + /// Note that this uses pointer arithmetic and **does not compare elements**. + /// To find the index of an element via comparison, use + /// [`.iter().position()`](crate::iter::Iterator::position) instead. + /// + /// # Panics + /// Panics if `T` is zero-sized. + /// + /// # Examples + /// Basic usage: + /// ``` + /// #![feature(substr_range)] + /// + /// let nums: &[u32] = &[1, 7, 1, 1]; + /// let num = &nums[2]; + /// + /// assert_eq!(num, &1); + /// assert_eq!(nums.elem_offset(num), Some(2)); + /// ``` + /// Returning `None` with an in-between element: + /// ``` + /// #![feature(substr_range)] + /// + /// let arr: &[[u32; 2]] = &[[0, 1], [2, 3]]; + /// let flat_arr: &[u32] = arr.as_flattened(); + /// + /// let ok_elm: &[u32; 2] = flat_arr[0..2].try_into().unwrap(); + /// let weird_elm: &[u32; 2] = flat_arr[1..3].try_into().unwrap(); + /// + /// assert_eq!(ok_elm, &[0, 1]); + /// assert_eq!(weird_elm, &[1, 2]); + /// + /// assert_eq!(arr.elem_offset(ok_elm), Some(0)); // Points to element 0 + /// assert_eq!(arr.elem_offset(weird_elm), None); // Points between element 0 and 1 + /// ``` + #[must_use] + #[unstable(feature = "substr_range", issue = "126769")] + pub fn elem_offset(&self, element: &T) -> Option { + if T::IS_ZST { + panic!("elements are zero-sized"); + } + + let self_start = self.as_ptr() as usize; + let elem_start = element as *const T as usize; + + let byte_offset = elem_start.wrapping_sub(self_start); + + if byte_offset % mem::size_of::() != 0 { + return None; + } + + let offset = byte_offset / mem::size_of::(); + + if offset < self.len() { Some(offset) } else { None } + } + + /// Returns the range of indices that a subslice points to. + /// + /// Returns `None` if `subslice` does not point within the slice or if it points between elements. + /// + /// This method **does not compare elements**. Instead, this method finds the location in the slice that + /// `subslice` was obtained from. To find the index of a subslice via comparison, instead use + /// [`.windows()`](slice::windows)[`.position()`](crate::iter::Iterator::position). + /// + /// This method is useful for extending slice iterators like [`slice::split`]. + /// + /// Note that this may return a false positive (either `Some(0..0)` or `Some(self.len()..self.len())`) + /// if `subslice` has a length of zero and points to the beginning or end of another, separate, slice. + /// + /// # Panics + /// Panics if `T` is zero-sized. + /// + /// # Examples + /// Basic usage: + /// ``` + /// #![feature(substr_range)] + /// + /// let nums = &[0, 5, 10, 0, 0, 5]; + /// + /// let mut iter = nums + /// .split(|t| *t == 0) + /// .map(|n| nums.subslice_range(n).unwrap()); + /// + /// assert_eq!(iter.next(), Some(0..0)); + /// assert_eq!(iter.next(), Some(1..3)); + /// assert_eq!(iter.next(), Some(4..4)); + /// assert_eq!(iter.next(), Some(5..6)); + /// ``` + #[must_use] + #[unstable(feature = "substr_range", issue = "126769")] + pub fn subslice_range(&self, subslice: &[T]) -> Option> { + if T::IS_ZST { + panic!("elements are zero-sized"); + } + + let self_start = self.as_ptr() as usize; + let subslice_start = subslice.as_ptr() as usize; + + let byte_start = subslice_start.wrapping_sub(self_start); + + if byte_start % core::mem::size_of::() != 0 { + return None; + } + + let start = byte_start / core::mem::size_of::(); + let end = start.wrapping_add(subslice.len()); + + if start <= self.len() && end <= self.len() { Some(start..end) } else { None } + } } impl [[T; N]] { diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 19627f28e64f..5845e3b5481a 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -411,7 +411,7 @@ macro_rules! derive_pattern_clone { (clone $t:ident with |$s:ident| $e:expr) => { impl<'a, P> Clone for $t<'a, P> where - P: Pattern<'a, Searcher: Clone>, + P: Pattern: Clone>, { fn clone(&self) -> Self { let $s = self; @@ -424,7 +424,7 @@ macro_rules! derive_pattern_clone { /// This macro generates two public iterator structs /// wrapping a private internal one that makes use of the `Pattern` API. /// -/// For all patterns `P: Pattern<'a>` the following items will be +/// For all patterns `P: Pattern` the following items will be /// generated (generics omitted): /// /// struct $forward_iterator($internal_iterator); @@ -484,12 +484,12 @@ macro_rules! generate_pattern_iterators { } => { $(#[$forward_iterator_attribute])* $(#[$common_stability_attribute])* - pub struct $forward_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>); + pub struct $forward_iterator<'a, P: Pattern>(pub(super) $internal_iterator<'a, P>); $(#[$common_stability_attribute])* impl<'a, P> fmt::Debug for $forward_iterator<'a, P> where - P: Pattern<'a, Searcher: fmt::Debug>, + P: Pattern: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple(stringify!($forward_iterator)) @@ -499,7 +499,7 @@ macro_rules! generate_pattern_iterators { } $(#[$common_stability_attribute])* - impl<'a, P: Pattern<'a>> Iterator for $forward_iterator<'a, P> { + impl<'a, P: Pattern> Iterator for $forward_iterator<'a, P> { type Item = $iterty; #[inline] @@ -511,7 +511,7 @@ macro_rules! generate_pattern_iterators { $(#[$common_stability_attribute])* impl<'a, P> Clone for $forward_iterator<'a, P> where - P: Pattern<'a, Searcher: Clone>, + P: Pattern: Clone>, { fn clone(&self) -> Self { $forward_iterator(self.0.clone()) @@ -520,12 +520,12 @@ macro_rules! generate_pattern_iterators { $(#[$reverse_iterator_attribute])* $(#[$common_stability_attribute])* - pub struct $reverse_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>); + pub struct $reverse_iterator<'a, P: Pattern>(pub(super) $internal_iterator<'a, P>); $(#[$common_stability_attribute])* impl<'a, P> fmt::Debug for $reverse_iterator<'a, P> where - P: Pattern<'a, Searcher: fmt::Debug>, + P: Pattern: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple(stringify!($reverse_iterator)) @@ -537,7 +537,7 @@ macro_rules! generate_pattern_iterators { $(#[$common_stability_attribute])* impl<'a, P> Iterator for $reverse_iterator<'a, P> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + P: Pattern: ReverseSearcher<'a>>, { type Item = $iterty; @@ -550,7 +550,7 @@ macro_rules! generate_pattern_iterators { $(#[$common_stability_attribute])* impl<'a, P> Clone for $reverse_iterator<'a, P> where - P: Pattern<'a, Searcher: Clone>, + P: Pattern: Clone>, { fn clone(&self) -> Self { $reverse_iterator(self.0.clone()) @@ -558,12 +558,12 @@ macro_rules! generate_pattern_iterators { } #[stable(feature = "fused", since = "1.26.0")] - impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} + impl<'a, P: Pattern> FusedIterator for $forward_iterator<'a, P> {} #[stable(feature = "fused", since = "1.26.0")] impl<'a, P> FusedIterator for $reverse_iterator<'a, P> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + P: Pattern: ReverseSearcher<'a>>, {} generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*, @@ -578,7 +578,7 @@ macro_rules! generate_pattern_iterators { $(#[$common_stability_attribute])* impl<'a, P> DoubleEndedIterator for $forward_iterator<'a, P> where - P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, + P: Pattern: DoubleEndedSearcher<'a>>, { #[inline] fn next_back(&mut self) -> Option<$iterty> { @@ -589,7 +589,7 @@ macro_rules! generate_pattern_iterators { $(#[$common_stability_attribute])* impl<'a, P> DoubleEndedIterator for $reverse_iterator<'a, P> where - P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, + P: Pattern: DoubleEndedSearcher<'a>>, { #[inline] fn next_back(&mut self) -> Option<$iterty> { @@ -609,17 +609,17 @@ derive_pattern_clone! { with |s| SplitInternal { matcher: s.matcher.clone(), ..*s } } -pub(super) struct SplitInternal<'a, P: Pattern<'a>> { +pub(super) struct SplitInternal<'a, P: Pattern> { pub(super) start: usize, pub(super) end: usize, - pub(super) matcher: P::Searcher, + pub(super) matcher: P::Searcher<'a>, pub(super) allow_trailing_empty: bool, pub(super) finished: bool, } impl<'a, P> fmt::Debug for SplitInternal<'a, P> where - P: Pattern<'a, Searcher: fmt::Debug>, + P: Pattern: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitInternal") @@ -632,7 +632,7 @@ where } } -impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { +impl<'a, P: Pattern> SplitInternal<'a, P> { #[inline] fn get_end(&mut self) -> Option<&'a str> { if !self.finished { @@ -689,7 +689,7 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { #[inline] fn next_back(&mut self) -> Option<&'a str> where - P::Searcher: ReverseSearcher<'a>, + P::Searcher<'a>: ReverseSearcher<'a>, { if self.finished { return None; @@ -726,7 +726,7 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { #[inline] fn next_back_inclusive(&mut self) -> Option<&'a str> where - P::Searcher: ReverseSearcher<'a>, + P::Searcher<'a>: ReverseSearcher<'a>, { if self.finished { return None; @@ -796,7 +796,7 @@ generate_pattern_iterators! { delegate double ended; } -impl<'a, P: Pattern<'a>> Split<'a, P> { +impl<'a, P: Pattern> Split<'a, P> { /// Returns remainder of the split string. /// /// If the iterator is empty, returns `None`. @@ -819,7 +819,7 @@ impl<'a, P: Pattern<'a>> Split<'a, P> { } } -impl<'a, P: Pattern<'a>> RSplit<'a, P> { +impl<'a, P: Pattern> RSplit<'a, P> { /// Returns remainder of the split string. /// /// If the iterator is empty, returns `None`. @@ -860,7 +860,7 @@ generate_pattern_iterators! { delegate double ended; } -impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> { +impl<'a, P: Pattern> SplitTerminator<'a, P> { /// Returns remainder of the split string. /// /// If the iterator is empty, returns `None`. @@ -883,7 +883,7 @@ impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> { } } -impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> { +impl<'a, P: Pattern> RSplitTerminator<'a, P> { /// Returns remainder of the split string. /// /// If the iterator is empty, returns `None`. @@ -911,7 +911,7 @@ derive_pattern_clone! { with |s| SplitNInternal { iter: s.iter.clone(), ..*s } } -pub(super) struct SplitNInternal<'a, P: Pattern<'a>> { +pub(super) struct SplitNInternal<'a, P: Pattern> { pub(super) iter: SplitInternal<'a, P>, /// The number of splits remaining pub(super) count: usize, @@ -919,7 +919,7 @@ pub(super) struct SplitNInternal<'a, P: Pattern<'a>> { impl<'a, P> fmt::Debug for SplitNInternal<'a, P> where - P: Pattern<'a, Searcher: fmt::Debug>, + P: Pattern: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitNInternal") @@ -929,7 +929,7 @@ where } } -impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { +impl<'a, P: Pattern> SplitNInternal<'a, P> { #[inline] fn next(&mut self) -> Option<&'a str> { match self.count { @@ -948,7 +948,7 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { #[inline] fn next_back(&mut self) -> Option<&'a str> where - P::Searcher: ReverseSearcher<'a>, + P::Searcher<'a>: ReverseSearcher<'a>, { match self.count { 0 => None, @@ -987,7 +987,7 @@ generate_pattern_iterators! { delegate single ended; } -impl<'a, P: Pattern<'a>> SplitN<'a, P> { +impl<'a, P: Pattern> SplitN<'a, P> { /// Returns remainder of the split string. /// /// If the iterator is empty, returns `None`. @@ -1010,7 +1010,7 @@ impl<'a, P: Pattern<'a>> SplitN<'a, P> { } } -impl<'a, P: Pattern<'a>> RSplitN<'a, P> { +impl<'a, P: Pattern> RSplitN<'a, P> { /// Returns remainder of the split string. /// /// If the iterator is empty, returns `None`. @@ -1038,18 +1038,18 @@ derive_pattern_clone! { with |s| MatchIndicesInternal(s.0.clone()) } -pub(super) struct MatchIndicesInternal<'a, P: Pattern<'a>>(pub(super) P::Searcher); +pub(super) struct MatchIndicesInternal<'a, P: Pattern>(pub(super) P::Searcher<'a>); impl<'a, P> fmt::Debug for MatchIndicesInternal<'a, P> where - P: Pattern<'a, Searcher: fmt::Debug>, + P: Pattern: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("MatchIndicesInternal").field(&self.0).finish() } } -impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { +impl<'a, P: Pattern> MatchIndicesInternal<'a, P> { #[inline] fn next(&mut self) -> Option<(usize, &'a str)> { self.0 @@ -1061,7 +1061,7 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { #[inline] fn next_back(&mut self) -> Option<(usize, &'a str)> where - P::Searcher: ReverseSearcher<'a>, + P::Searcher<'a>: ReverseSearcher<'a>, { self.0 .next_match_back() @@ -1093,18 +1093,18 @@ derive_pattern_clone! { with |s| MatchesInternal(s.0.clone()) } -pub(super) struct MatchesInternal<'a, P: Pattern<'a>>(pub(super) P::Searcher); +pub(super) struct MatchesInternal<'a, P: Pattern>(pub(super) P::Searcher<'a>); impl<'a, P> fmt::Debug for MatchesInternal<'a, P> where - P: Pattern<'a, Searcher: fmt::Debug>, + P: Pattern: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("MatchesInternal").field(&self.0).finish() } } -impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { +impl<'a, P: Pattern> MatchesInternal<'a, P> { #[inline] fn next(&mut self) -> Option<&'a str> { // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. @@ -1117,7 +1117,7 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { #[inline] fn next_back(&mut self) -> Option<&'a str> where - P::Searcher: ReverseSearcher<'a>, + P::Searcher<'a>: ReverseSearcher<'a>, { // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. self.0.next_match_back().map(|(a, b)| unsafe { @@ -1288,7 +1288,7 @@ pub struct SplitAsciiWhitespace<'a> { /// /// [`split_inclusive`]: str::split_inclusive #[stable(feature = "split_inclusive", since = "1.51.0")] -pub struct SplitInclusive<'a, P: Pattern<'a>>(pub(super) SplitInternal<'a, P>); +pub struct SplitInclusive<'a, P: Pattern>(pub(super) SplitInternal<'a, P>); #[stable(feature = "split_whitespace", since = "1.1.0")] impl<'a> Iterator for SplitWhitespace<'a> { @@ -1410,7 +1410,7 @@ impl<'a> SplitAsciiWhitespace<'a> { } #[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> { +impl<'a, P: Pattern> Iterator for SplitInclusive<'a, P> { type Item = &'a str; #[inline] @@ -1420,7 +1420,7 @@ impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> { } #[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> { +impl<'a, P: Pattern: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitInclusive").field("0", &self.0).finish() } @@ -1428,14 +1428,14 @@ impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, // FIXME(#26925) Remove in favor of `#[derive(Clone)]` #[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> { +impl<'a, P: Pattern: Clone>> Clone for SplitInclusive<'a, P> { fn clone(&self) -> Self { SplitInclusive(self.0.clone()) } } #[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>> DoubleEndedIterator +impl<'a, P: Pattern: DoubleEndedSearcher<'a>>> DoubleEndedIterator for SplitInclusive<'a, P> { #[inline] @@ -1445,9 +1445,9 @@ impl<'a, P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>> DoubleEndedIterator } #[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {} +impl<'a, P: Pattern> FusedIterator for SplitInclusive<'a, P> {} -impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> { +impl<'a, P: Pattern> SplitInclusive<'a, P> { /// Returns remainder of the split string. /// /// If the iterator is empty, returns `None`. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 683109380439..6cd029f74363 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -19,6 +19,7 @@ use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher}; use crate::ascii; use crate::char::{self, EscapeDebugExtArgs}; use crate::mem; +use crate::ops::Range; use crate::slice::{self, SliceIndex}; pub mod pattern; @@ -1137,7 +1138,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { + pub fn contains(&self, pat: P) -> bool { pat.is_contained_in(self) } @@ -1174,7 +1175,7 @@ impl str { /// assert!(bananas.starts_with(&['a', 'b', 'c', 'd'])); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { + pub fn starts_with(&self, pat: P) -> bool { pat.is_prefix_of(self) } @@ -1198,9 +1199,9 @@ impl str { /// assert!(!bananas.ends_with("nana")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn ends_with<'a, P>(&'a self, pat: P) -> bool + pub fn ends_with(&self, pat: P) -> bool where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { pat.is_suffix_of(self) } @@ -1249,7 +1250,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { + pub fn find(&self, pat: P) -> Option { pat.into_searcher(self).next_match().map(|(i, _)| i) } @@ -1295,9 +1296,9 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn rfind<'a, P>(&'a self, pat: P) -> Option + pub fn rfind(&self, pat: P) -> Option where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { pat.into_searcher(self).next_match_back().map(|(i, _)| i) } @@ -1417,7 +1418,7 @@ impl str { /// [`split_whitespace`]: str::split_whitespace #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { + pub fn split(&self, pat: P) -> Split<'_, P> { Split(SplitInternal { start: 0, end: self.len(), @@ -1457,7 +1458,7 @@ impl str { /// ``` #[stable(feature = "split_inclusive", since = "1.51.0")] #[inline] - pub fn split_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInclusive<'a, P> { + pub fn split_inclusive(&self, pat: P) -> SplitInclusive<'_, P> { SplitInclusive(SplitInternal { start: 0, end: self.len(), @@ -1512,9 +1513,9 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn rsplit<'a, P>(&'a self, pat: P) -> RSplit<'a, P> + pub fn rsplit(&self, pat: P) -> RSplit<'_, P> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { RSplit(self.split(pat).0) } @@ -1561,7 +1562,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { + pub fn split_terminator(&self, pat: P) -> SplitTerminator<'_, P> { SplitTerminator(SplitInternal { allow_trailing_empty: false, ..self.split(pat).0 }) } @@ -1607,9 +1608,9 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn rsplit_terminator<'a, P>(&'a self, pat: P) -> RSplitTerminator<'a, P> + pub fn rsplit_terminator(&self, pat: P) -> RSplitTerminator<'_, P> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { RSplitTerminator(self.split_terminator(pat).0) } @@ -1662,7 +1663,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { + pub fn splitn(&self, n: usize, pat: P) -> SplitN<'_, P> { SplitN(SplitNInternal { iter: self.split(pat).0, count: n }) } @@ -1711,9 +1712,9 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn rsplitn<'a, P>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> + pub fn rsplitn(&self, n: usize, pat: P) -> RSplitN<'_, P> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { RSplitN(self.splitn(n, pat).0) } @@ -1731,7 +1732,7 @@ impl str { /// ``` #[stable(feature = "str_split_once", since = "1.52.0")] #[inline] - pub fn split_once<'a, P: Pattern<'a>>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> { + pub fn split_once(&self, delimiter: P) -> Option<(&'_ str, &'_ str)> { let (start, end) = delimiter.into_searcher(self).next_match()?; // SAFETY: `Searcher` is known to return valid indices. unsafe { Some((self.get_unchecked(..start), self.get_unchecked(end..))) } @@ -1749,9 +1750,9 @@ impl str { /// ``` #[stable(feature = "str_split_once", since = "1.52.0")] #[inline] - pub fn rsplit_once<'a, P>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> + pub fn rsplit_once(&self, delimiter: P) -> Option<(&'_ str, &'_ str)> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { let (start, end) = delimiter.into_searcher(self).next_match_back()?; // SAFETY: `Searcher` is known to return valid indices. @@ -1789,7 +1790,7 @@ impl str { /// ``` #[stable(feature = "str_matches", since = "1.2.0")] #[inline] - pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { + pub fn matches(&self, pat: P) -> Matches<'_, P> { Matches(MatchesInternal(pat.into_searcher(self))) } @@ -1823,9 +1824,9 @@ impl str { /// ``` #[stable(feature = "str_matches", since = "1.2.0")] #[inline] - pub fn rmatches<'a, P>(&'a self, pat: P) -> RMatches<'a, P> + pub fn rmatches(&self, pat: P) -> RMatches<'_, P> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { RMatches(self.matches(pat).0) } @@ -1867,7 +1868,7 @@ impl str { /// ``` #[stable(feature = "str_match_indices", since = "1.5.0")] #[inline] - pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { + pub fn match_indices(&self, pat: P) -> MatchIndices<'_, P> { MatchIndices(MatchIndicesInternal(pat.into_searcher(self))) } @@ -1907,9 +1908,9 @@ impl str { /// ``` #[stable(feature = "str_match_indices", since = "1.5.0")] #[inline] - pub fn rmatch_indices<'a, P>(&'a self, pat: P) -> RMatchIndices<'a, P> + pub fn rmatch_indices(&self, pat: P) -> RMatchIndices<'_, P> where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { RMatchIndices(self.match_indices(pat).0) } @@ -2122,9 +2123,9 @@ impl str { #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_matches<'a, P>(&'a self, pat: P) -> &'a str + pub fn trim_matches(&self, pat: P) -> &str where - P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, + for<'a> P::Searcher<'a>: DoubleEndedSearcher<'a>, { let mut i = 0; let mut j = 0; @@ -2169,7 +2170,7 @@ impl str { #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] #[stable(feature = "trim_direction", since = "1.30.0")] - pub fn trim_start_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { + pub fn trim_start_matches(&self, pat: P) -> &str { let mut i = self.len(); let mut matcher = pat.into_searcher(self); if let Some((a, _)) = matcher.next_reject() { @@ -2202,7 +2203,7 @@ impl str { #[must_use = "this returns the remaining substring as a new slice, \ without modifying the original"] #[stable(feature = "str_strip", since = "1.45.0")] - pub fn strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<&'a str> { + pub fn strip_prefix(&self, prefix: P) -> Option<&str> { prefix.strip_prefix_of(self) } @@ -2229,10 +2230,9 @@ impl str { #[must_use = "this returns the remaining substring as a new slice, \ without modifying the original"] #[stable(feature = "str_strip", since = "1.45.0")] - pub fn strip_suffix<'a, P>(&'a self, suffix: P) -> Option<&'a str> + pub fn strip_suffix(&self, suffix: P) -> Option<&str> where - P: Pattern<'a>, -

>::Searcher: ReverseSearcher<'a>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { suffix.strip_suffix_of(self) } @@ -2273,9 +2273,9 @@ impl str { #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] #[stable(feature = "trim_direction", since = "1.30.0")] - pub fn trim_end_matches<'a, P>(&'a self, pat: P) -> &'a str + pub fn trim_end_matches(&self, pat: P) -> &str where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { let mut j = 0; let mut matcher = pat.into_searcher(self); @@ -2317,7 +2317,7 @@ impl str { note = "superseded by `trim_start_matches`", suggestion = "trim_start_matches" )] - pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { + pub fn trim_left_matches(&self, pat: P) -> &str { self.trim_start_matches(pat) } @@ -2360,9 +2360,9 @@ impl str { note = "superseded by `trim_end_matches`", suggestion = "trim_end_matches" )] - pub fn trim_right_matches<'a, P>(&'a self, pat: P) -> &'a str + pub fn trim_right_matches(&self, pat: P) -> &str where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { self.trim_end_matches(pat) } @@ -2721,6 +2721,39 @@ impl str { pub fn escape_unicode(&self) -> EscapeUnicode<'_> { EscapeUnicode { inner: self.chars().flat_map(CharEscapeUnicode) } } + + /// Returns the range that a substring points to. + /// + /// Returns `None` if `substr` does not point within `self`. + /// + /// Unlike [`str::find`], **this does not search through the string**. + /// Instead, it uses pointer arithmetic to find where in the string + /// `substr` is derived from. + /// + /// This is useful for extending [`str::split`] and similar methods. + /// + /// Note that this method may return false positives (typically either + /// `Some(0..0)` or `Some(self.len()..self.len())`) if `substr` is a + /// zero-length `str` that points at the beginning or end of another, + /// independent, `str`. + /// + /// # Examples + /// ``` + /// #![feature(substr_range)] + /// + /// let data = "a, b, b, a"; + /// let mut iter = data.split(", ").map(|s| data.substr_range(s).unwrap()); + /// + /// assert_eq!(iter.next(), Some(0..1)); + /// assert_eq!(iter.next(), Some(3..4)); + /// assert_eq!(iter.next(), Some(6..7)); + /// assert_eq!(iter.next(), Some(9..10)); + /// ``` + #[must_use] + #[unstable(feature = "substr_range", issue = "126769")] + pub fn substr_range(&self, substr: &str) -> Option> { + self.as_bytes().subslice_range(substr.as_bytes()) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 8988229be2e5..33a5d45e445d 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -48,8 +48,8 @@ use crate::slice::memchr; /// A string pattern. /// -/// A `Pattern<'a>` expresses that the implementing type -/// can be used as a string pattern for searching in a [`&'a str`][str]. +/// A `Pattern` expresses that the implementing type +/// can be used as a string pattern for searching in a [`&str`][str]. /// /// For example, both `'a'` and `"aa"` are patterns that /// would match at index `1` in the string `"baaaab"`. @@ -97,38 +97,38 @@ use crate::slice::memchr; /// assert_eq!("abcdef_z".find(|ch| ch > 'd' && ch < 'y'), Some(4)); /// assert_eq!("abcddd_z".find(|ch| ch > 'd' && ch < 'y'), None); /// ``` -pub trait Pattern<'a>: Sized { +pub trait Pattern: Sized { /// Associated searcher for this pattern - type Searcher: Searcher<'a>; + type Searcher<'a>: Searcher<'a>; /// Constructs the associated searcher from /// `self` and the `haystack` to search in. - fn into_searcher(self, haystack: &'a str) -> Self::Searcher; + fn into_searcher(self, haystack: &str) -> Self::Searcher<'_>; /// Checks whether the pattern matches anywhere in the haystack #[inline] - fn is_contained_in(self, haystack: &'a str) -> bool { + fn is_contained_in(self, haystack: &str) -> bool { self.into_searcher(haystack).next_match().is_some() } /// Checks whether the pattern matches at the front of the haystack #[inline] - fn is_prefix_of(self, haystack: &'a str) -> bool { + fn is_prefix_of(self, haystack: &str) -> bool { matches!(self.into_searcher(haystack).next(), SearchStep::Match(0, _)) } /// Checks whether the pattern matches at the back of the haystack #[inline] - fn is_suffix_of(self, haystack: &'a str) -> bool + fn is_suffix_of<'a>(self, haystack: &'a str) -> bool where - Self::Searcher: ReverseSearcher<'a>, + Self::Searcher<'a>: ReverseSearcher<'a>, { matches!(self.into_searcher(haystack).next_back(), SearchStep::Match(_, j) if haystack.len() == j) } /// Removes the pattern from the front of haystack, if it matches. #[inline] - fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> { + fn strip_prefix_of(self, haystack: &str) -> Option<&str> { if let SearchStep::Match(start, len) = self.into_searcher(haystack).next() { debug_assert_eq!( start, 0, @@ -144,9 +144,9 @@ pub trait Pattern<'a>: Sized { /// Removes the pattern from the back of haystack, if it matches. #[inline] - fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> + fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str> where - Self::Searcher: ReverseSearcher<'a>, + Self::Searcher<'a>: ReverseSearcher<'a>, { if let SearchStep::Match(start, end) = self.into_searcher(haystack).next_back() { debug_assert_eq!( @@ -349,7 +349,7 @@ pub trait DoubleEndedSearcher<'a>: ReverseSearcher<'a> {} // Impl for char ///////////////////////////////////////////////////////////////////////////// -/// Associated type for `>::Searcher`. +/// Associated type for `::Searcher<'a>`. #[derive(Clone, Debug)] pub struct CharSearcher<'a> { haystack: &'a str, @@ -543,11 +543,11 @@ impl<'a> DoubleEndedSearcher<'a> for CharSearcher<'a> {} /// ``` /// assert_eq!("Hello world".find('o'), Some(4)); /// ``` -impl<'a> Pattern<'a> for char { - type Searcher = CharSearcher<'a>; +impl Pattern for char { + type Searcher<'a> = CharSearcher<'a>; #[inline] - fn into_searcher(self, haystack: &'a str) -> Self::Searcher { + fn into_searcher(self, haystack: &str) -> Self::Searcher<'_> { let mut utf8_encoded = [0; 4]; let utf8_size = self .encode_utf8(&mut utf8_encoded) @@ -566,7 +566,7 @@ impl<'a> Pattern<'a> for char { } #[inline] - fn is_contained_in(self, haystack: &'a str) -> bool { + fn is_contained_in(self, haystack: &str) -> bool { if (self as u32) < 128 { haystack.as_bytes().contains(&(self as u8)) } else { @@ -576,27 +576,27 @@ impl<'a> Pattern<'a> for char { } #[inline] - fn is_prefix_of(self, haystack: &'a str) -> bool { + fn is_prefix_of(self, haystack: &str) -> bool { self.encode_utf8(&mut [0u8; 4]).is_prefix_of(haystack) } #[inline] - fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> { + fn strip_prefix_of(self, haystack: &str) -> Option<&str> { self.encode_utf8(&mut [0u8; 4]).strip_prefix_of(haystack) } #[inline] - fn is_suffix_of(self, haystack: &'a str) -> bool + fn is_suffix_of<'a>(self, haystack: &'a str) -> bool where - Self::Searcher: ReverseSearcher<'a>, + Self::Searcher<'a>: ReverseSearcher<'a>, { self.encode_utf8(&mut [0u8; 4]).is_suffix_of(haystack) } #[inline] - fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> + fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str> where - Self::Searcher: ReverseSearcher<'a>, + Self::Searcher<'a>: ReverseSearcher<'a>, { self.encode_utf8(&mut [0u8; 4]).strip_suffix_of(haystack) } @@ -651,11 +651,11 @@ struct MultiCharEqSearcher<'a, C: MultiCharEq> { char_indices: super::CharIndices<'a>, } -impl<'a, C: MultiCharEq> Pattern<'a> for MultiCharEqPattern { - type Searcher = MultiCharEqSearcher<'a, C>; +impl Pattern for MultiCharEqPattern { + type Searcher<'a> = MultiCharEqSearcher<'a, C>; #[inline] - fn into_searcher(self, haystack: &'a str) -> MultiCharEqSearcher<'a, C> { + fn into_searcher(self, haystack: &str) -> MultiCharEqSearcher<'_, C> { MultiCharEqSearcher { haystack, char_eq: self.0, char_indices: haystack.char_indices() } } } @@ -710,41 +710,41 @@ impl<'a, C: MultiCharEq> DoubleEndedSearcher<'a> for MultiCharEqSearcher<'a, C> ///////////////////////////////////////////////////////////////////////////// macro_rules! pattern_methods { - ($t:ty, $pmap:expr, $smap:expr) => { - type Searcher = $t; + ($a:lifetime, $t:ty, $pmap:expr, $smap:expr) => { + type Searcher<$a> = $t; #[inline] - fn into_searcher(self, haystack: &'a str) -> $t { + fn into_searcher<$a>(self, haystack: &$a str) -> $t { ($smap)(($pmap)(self).into_searcher(haystack)) } #[inline] - fn is_contained_in(self, haystack: &'a str) -> bool { + fn is_contained_in<$a>(self, haystack: &$a str) -> bool { ($pmap)(self).is_contained_in(haystack) } #[inline] - fn is_prefix_of(self, haystack: &'a str) -> bool { + fn is_prefix_of<$a>(self, haystack: &$a str) -> bool { ($pmap)(self).is_prefix_of(haystack) } #[inline] - fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> { + fn strip_prefix_of<$a>(self, haystack: &$a str) -> Option<&$a str> { ($pmap)(self).strip_prefix_of(haystack) } #[inline] - fn is_suffix_of(self, haystack: &'a str) -> bool + fn is_suffix_of<$a>(self, haystack: &$a str) -> bool where - $t: ReverseSearcher<'a>, + $t: ReverseSearcher<$a>, { ($pmap)(self).is_suffix_of(haystack) } #[inline] - fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> + fn strip_suffix_of<$a>(self, haystack: &$a str) -> Option<&$a str> where - $t: ReverseSearcher<'a>, + $t: ReverseSearcher<$a>, { ($pmap)(self).strip_suffix_of(haystack) } @@ -786,16 +786,16 @@ macro_rules! searcher_methods { }; } -/// Associated type for `<[char; N] as Pattern<'a>>::Searcher`. +/// Associated type for `<[char; N] as Pattern>::Searcher<'a>`. #[derive(Clone, Debug)] pub struct CharArraySearcher<'a, const N: usize>( - as Pattern<'a>>::Searcher, + as Pattern>::Searcher<'a>, ); -/// Associated type for `<&[char; N] as Pattern<'a>>::Searcher`. +/// Associated type for `<&[char; N] as Pattern>::Searcher<'a>`. #[derive(Clone, Debug)] pub struct CharArrayRefSearcher<'a, 'b, const N: usize>( - as Pattern<'a>>::Searcher, + as Pattern>::Searcher<'a>, ); /// Searches for chars that are equal to any of the [`char`]s in the array. @@ -806,8 +806,8 @@ pub struct CharArrayRefSearcher<'a, 'b, const N: usize>( /// assert_eq!("Hello world".find(['o', 'l']), Some(2)); /// assert_eq!("Hello world".find(['h', 'w']), Some(6)); /// ``` -impl<'a, const N: usize> Pattern<'a> for [char; N] { - pattern_methods!(CharArraySearcher<'a, N>, MultiCharEqPattern, CharArraySearcher); +impl Pattern for [char; N] { + pattern_methods!('a, CharArraySearcher<'a, N>, MultiCharEqPattern, CharArraySearcher); } unsafe impl<'a, const N: usize> Searcher<'a> for CharArraySearcher<'a, N> { @@ -828,8 +828,8 @@ impl<'a, const N: usize> DoubleEndedSearcher<'a> for CharArraySearcher<'a, N> {} /// assert_eq!("Hello world".find(&['o', 'l']), Some(2)); /// assert_eq!("Hello world".find(&['h', 'w']), Some(6)); /// ``` -impl<'a, 'b, const N: usize> Pattern<'a> for &'b [char; N] { - pattern_methods!(CharArrayRefSearcher<'a, 'b, N>, MultiCharEqPattern, CharArrayRefSearcher); +impl<'b, const N: usize> Pattern for &'b [char; N] { + pattern_methods!('a, CharArrayRefSearcher<'a, 'b, N>, MultiCharEqPattern, CharArrayRefSearcher); } unsafe impl<'a, 'b, const N: usize> Searcher<'a> for CharArrayRefSearcher<'a, 'b, N> { @@ -848,9 +848,9 @@ impl<'a, 'b, const N: usize> DoubleEndedSearcher<'a> for CharArrayRefSearcher<'a // Todo: Change / Remove due to ambiguity in meaning. -/// Associated type for `<&[char] as Pattern<'a>>::Searcher`. +/// Associated type for `<&[char] as Pattern>::Searcher<'a>`. #[derive(Clone, Debug)] -pub struct CharSliceSearcher<'a, 'b>( as Pattern<'a>>::Searcher); +pub struct CharSliceSearcher<'a, 'b>( as Pattern>::Searcher<'a>); unsafe impl<'a, 'b> Searcher<'a> for CharSliceSearcher<'a, 'b> { searcher_methods!(forward); @@ -870,17 +870,17 @@ impl<'a, 'b> DoubleEndedSearcher<'a> for CharSliceSearcher<'a, 'b> {} /// assert_eq!("Hello world".find(&['l', 'l'] as &[_]), Some(2)); /// assert_eq!("Hello world".find(&['l', 'l'][..]), Some(2)); /// ``` -impl<'a, 'b> Pattern<'a> for &'b [char] { - pattern_methods!(CharSliceSearcher<'a, 'b>, MultiCharEqPattern, CharSliceSearcher); +impl<'b> Pattern for &'b [char] { + pattern_methods!('a, CharSliceSearcher<'a, 'b>, MultiCharEqPattern, CharSliceSearcher); } ///////////////////////////////////////////////////////////////////////////// // Impl for F: FnMut(char) -> bool ///////////////////////////////////////////////////////////////////////////// -/// Associated type for `>::Searcher`. +/// Associated type for `::Searcher<'a>`. #[derive(Clone)] -pub struct CharPredicateSearcher<'a, F>( as Pattern<'a>>::Searcher) +pub struct CharPredicateSearcher<'a, F>( as Pattern>::Searcher<'a>) where F: FnMut(char) -> bool; @@ -919,11 +919,11 @@ impl<'a, F> DoubleEndedSearcher<'a> for CharPredicateSearcher<'a, F> where F: Fn /// assert_eq!("Hello world".find(char::is_uppercase), Some(0)); /// assert_eq!("Hello world".find(|c| "aeiou".contains(c)), Some(1)); /// ``` -impl<'a, F> Pattern<'a> for F +impl Pattern for F where F: FnMut(char) -> bool, { - pattern_methods!(CharPredicateSearcher<'a, F>, MultiCharEqPattern, CharPredicateSearcher); + pattern_methods!('a, CharPredicateSearcher<'a, F>, MultiCharEqPattern, CharPredicateSearcher); } ///////////////////////////////////////////////////////////////////////////// @@ -931,8 +931,8 @@ where ///////////////////////////////////////////////////////////////////////////// /// Delegates to the `&str` impl. -impl<'a, 'b, 'c> Pattern<'a> for &'c &'b str { - pattern_methods!(StrSearcher<'a, 'b>, |&s| s, |s| s); +impl<'b, 'c> Pattern for &'c &'b str { + pattern_methods!('a, StrSearcher<'a, 'b>, |&s| s, |s| s); } ///////////////////////////////////////////////////////////////////////////// @@ -949,23 +949,23 @@ impl<'a, 'b, 'c> Pattern<'a> for &'c &'b str { /// ``` /// assert_eq!("Hello world".find("world"), Some(6)); /// ``` -impl<'a, 'b> Pattern<'a> for &'b str { - type Searcher = StrSearcher<'a, 'b>; +impl<'b> Pattern for &'b str { + type Searcher<'a> = StrSearcher<'a, 'b>; #[inline] - fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> { + fn into_searcher(self, haystack: &str) -> StrSearcher<'_, 'b> { StrSearcher::new(haystack, self) } /// Checks whether the pattern matches at the front of the haystack. #[inline] - fn is_prefix_of(self, haystack: &'a str) -> bool { + fn is_prefix_of(self, haystack: &str) -> bool { haystack.as_bytes().starts_with(self.as_bytes()) } /// Checks whether the pattern matches anywhere in the haystack #[inline] - fn is_contained_in(self, haystack: &'a str) -> bool { + fn is_contained_in(self, haystack: &str) -> bool { if self.len() == 0 { return true; } @@ -991,7 +991,7 @@ impl<'a, 'b> Pattern<'a> for &'b str { /// Removes the pattern from the front of haystack, if it matches. #[inline] - fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> { + fn strip_prefix_of(self, haystack: &str) -> Option<&str> { if self.is_prefix_of(haystack) { // SAFETY: prefix was just verified to exist. unsafe { Some(haystack.get_unchecked(self.as_bytes().len()..)) } @@ -1002,13 +1002,19 @@ impl<'a, 'b> Pattern<'a> for &'b str { /// Checks whether the pattern matches at the back of the haystack. #[inline] - fn is_suffix_of(self, haystack: &'a str) -> bool { + fn is_suffix_of<'a>(self, haystack: &'a str) -> bool + where + Self::Searcher<'a>: ReverseSearcher<'a>, + { haystack.as_bytes().ends_with(self.as_bytes()) } /// Removes the pattern from the back of haystack, if it matches. #[inline] - fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> { + fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str> + where + Self::Searcher<'a>: ReverseSearcher<'a>, + { if self.is_suffix_of(haystack) { let i = haystack.len() - self.as_bytes().len(); // SAFETY: suffix was just verified to exist. @@ -1024,7 +1030,7 @@ impl<'a, 'b> Pattern<'a> for &'b str { ///////////////////////////////////////////////////////////////////////////// #[derive(Clone, Debug)] -/// Associated type for `<&str as Pattern<'a>>::Searcher`. +/// Associated type for `<&str as Pattern>::Searcher<'a>`. pub struct StrSearcher<'a, 'b> { haystack: &'a str, needle: &'b str, diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 86a965f68e08..d2b1d74ff6a0 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -1,10 +1,9 @@ #![stable(feature = "futures_api", since = "1.36.0")] -use crate::mem::transmute; - use crate::any::Any; use crate::fmt; use crate::marker::PhantomData; +use crate::mem::{transmute, ManuallyDrop}; use crate::panic::AssertUnwindSafe; use crate::ptr; @@ -429,7 +428,7 @@ impl<'a> ContextBuilder<'a> { /// [`Future::poll()`]: core::future::Future::poll /// [`Poll::Pending`]: core::task::Poll::Pending /// [`Wake`]: ../../alloc/task/trait.Wake.html -#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/66401 +#[repr(transparent)] #[stable(feature = "futures_api", since = "1.36.0")] pub struct Waker { waker: RawWaker, @@ -465,16 +464,14 @@ impl Waker { pub fn wake(self) { // The actual wakeup call is delegated through a virtual function call // to the implementation which is defined by the executor. - let wake = self.waker.vtable.wake; - let data = self.waker.data; // Don't call `drop` -- the waker will be consumed by `wake`. - crate::mem::forget(self); + let this = ManuallyDrop::new(self); // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `wake` and `data` requiring the user to acknowledge // that the contract of `RawWaker` is upheld. - unsafe { (wake)(data) }; + unsafe { (this.waker.vtable.wake)(this.waker.data) }; } /// Wake up the task associated with this `Waker` without consuming the `Waker`. @@ -695,7 +692,7 @@ impl fmt::Debug for Waker { /// [`Poll::Pending`]: core::task::Poll::Pending /// [`local_waker`]: core::task::Context::local_waker #[unstable(feature = "local_waker", issue = "118959")] -#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/66401 +#[repr(transparent)] pub struct LocalWaker { waker: RawWaker, } @@ -726,16 +723,14 @@ impl LocalWaker { pub fn wake(self) { // The actual wakeup call is delegated through a virtual function call // to the implementation which is defined by the executor. - let wake = self.waker.vtable.wake; - let data = self.waker.data; // Don't call `drop` -- the waker will be consumed by `wake`. - crate::mem::forget(self); + let this = ManuallyDrop::new(self); // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `wake` and `data` requiring the user to acknowledge // that the contract of `RawWaker` is upheld. - unsafe { (wake)(data) }; + unsafe { (this.waker.vtable.wake)(this.waker.data) }; } /// Wake up the task associated with this `LocalWaker` without consuming the `LocalWaker`. diff --git a/library/proc_macro/src/bridge/buffer.rs b/library/proc_macro/src/bridge/buffer.rs index 149767bf7052..78fcd1999b2f 100644 --- a/library/proc_macro/src/bridge/buffer.rs +++ b/library/proc_macro/src/bridge/buffer.rs @@ -1,7 +1,7 @@ //! Buffer management for same-process client<->server communication. use std::io::{self, Write}; -use std::mem; +use std::mem::{self, ManuallyDrop}; use std::ops::{Deref, DerefMut}; use std::slice; @@ -129,17 +129,16 @@ impl Drop for Buffer { } impl From> for Buffer { - fn from(mut v: Vec) -> Self { + fn from(v: Vec) -> Self { + let mut v = ManuallyDrop::new(v); let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity()); - mem::forget(v); // This utility function is nested in here because it can *only* // be safely called on `Buffer`s created by *this* `proc_macro`. fn to_vec(b: Buffer) -> Vec { unsafe { - let Buffer { data, len, capacity, .. } = b; - mem::forget(b); - Vec::from_raw_parts(data, len, capacity) + let b = ManuallyDrop::new(b); + Vec::from_raw_parts(b.data, b.len, b.capacity) } } diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index faca745e56f7..9658fc4840f6 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -51,9 +51,7 @@ macro_rules! define_client_handles { impl Encode for $oty { fn encode(self, w: &mut Writer, s: &mut S) { - let handle = self.handle; - mem::forget(self); - handle.encode(w, s); + mem::ManuallyDrop::new(self).handle.encode(w, s); } } diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index f9dba08da4c3..0fb3964c9a9b 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -115,10 +115,8 @@ impl crate::sealed::Sealed for OsString {} #[stable(feature = "rust1", since = "1.0.0")] // `OsStr::from_inner` current implementation relies // on `OsStr` being layout-compatible with `Slice`. -// However, `OsStr` layout is considered an implementation detail and must not be relied upon. We -// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under -// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy. -#[cfg_attr(not(doc), repr(transparent))] +// However, `OsStr` layout is considered an implementation detail and must not be relied upon. +#[repr(transparent)] pub struct OsStr { inner: Slice, } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 6413b3515ece..536d0d1b356a 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2400,13 +2400,8 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// /// # Errors /// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * If any directory in the path specified by `path` -/// does not already exist and it could not be created otherwise. The specific -/// error conditions for when a directory is being created (after it is -/// determined to not exist) are outlined by [`fs::create_dir`]. +/// The function will return an error if any directory specified in path does not exist and +/// could not be created. There may be other error conditions; see [`fs::create_dir`] for specifics. /// /// Notable exception is made for situations where any of the directories /// specified in the `path` could not be created as it was being created concurrently. diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 5833c5972568..bbd5093e44c6 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -8,7 +8,7 @@ use crate::fmt; use crate::fs; use crate::io; use crate::marker::PhantomData; -use crate::mem::forget; +use crate::mem::ManuallyDrop; #[cfg(not(any(target_arch = "wasm32", target_env = "sgx", target_os = "hermit")))] use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -148,9 +148,7 @@ impl AsRawFd for OwnedFd { impl IntoRawFd for OwnedFd { #[inline] fn into_raw_fd(self) -> RawFd { - let fd = self.fd; - forget(self); - fd + ManuallyDrop::new(self).fd } } diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs index e75bcf74e5cd..bbf7e96d53d9 100644 --- a/library/std/src/os/solid/io.rs +++ b/library/std/src/os/solid/io.rs @@ -48,7 +48,7 @@ use crate::fmt; use crate::marker::PhantomData; -use crate::mem::forget; +use crate::mem::ManuallyDrop; use crate::net; use crate::sys; use crate::sys_common::{self, AsInner, FromInner, IntoInner}; @@ -148,9 +148,7 @@ impl AsRawFd for OwnedFd { impl IntoRawFd for OwnedFd { #[inline] fn into_raw_fd(self) -> RawFd { - let fd = self.fd; - forget(self); - fd + ManuallyDrop::new(self).fd } } diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 970023d8cf19..20c472040fad 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -1064,7 +1064,7 @@ pub fn lchown>(dir: P, uid: Option, gid: Option) -> io: /// } /// ``` #[stable(feature = "unix_chroot", since = "1.56.0")] -#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))] +#[cfg(not(target_os = "fuchsia"))] pub fn chroot>(dir: P) -> io::Result<()> { sys::fs::chroot(dir.as_ref()) } diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index a9d1983dce61..9865386e753d 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -7,7 +7,7 @@ use crate::fmt; use crate::fs; use crate::io; use crate::marker::PhantomData; -use crate::mem::{forget, ManuallyDrop}; +use crate::mem::ManuallyDrop; use crate::ptr; use crate::sys; use crate::sys::cvt; @@ -319,9 +319,7 @@ impl AsRawHandle for OwnedHandle { impl IntoRawHandle for OwnedHandle { #[inline] fn into_raw_handle(self) -> RawHandle { - let handle = self.handle; - forget(self); - handle + ManuallyDrop::new(self).handle } } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 4334d041439d..df5b56d30620 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -6,8 +6,7 @@ use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; use crate::fmt; use crate::io; use crate::marker::PhantomData; -use crate::mem; -use crate::mem::forget; +use crate::mem::{self, ManuallyDrop}; use crate::sys; #[cfg(not(target_vendor = "uwp"))] use crate::sys::cvt; @@ -191,9 +190,7 @@ impl AsRawSocket for OwnedSocket { impl IntoRawSocket for OwnedSocket { #[inline] fn into_raw_socket(self) -> RawSocket { - let socket = self.socket; - forget(self); - socket + ManuallyDrop::new(self).socket } } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index d5121a554bf6..0cef862549c8 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2079,10 +2079,8 @@ impl AsRef for PathBuf { #[stable(feature = "rust1", since = "1.0.0")] // `Path::new` current implementation relies // on `Path` being layout-compatible with `OsStr`. -// However, `Path` layout is considered an implementation detail and must not be relied upon. We -// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under -// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy. -#[cfg_attr(not(doc), repr(transparent))] +// However, `Path` layout is considered an implementation detail and must not be relied upon. +#[repr(transparent)] pub struct Path { inner: OsStr, } diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs index a244b953d2a4..3723f03081c1 100644 --- a/library/std/src/sys/pal/hermit/thread.rs +++ b/library/std/src/sys/pal/hermit/thread.rs @@ -3,7 +3,7 @@ use super::hermit_abi; use crate::ffi::CStr; use crate::io; -use crate::mem; +use crate::mem::ManuallyDrop; use crate::num::NonZero; use crate::ptr; use crate::time::Duration; @@ -90,9 +90,7 @@ impl Thread { #[inline] pub fn into_id(self) -> Tid { - let id = self.tid; - mem::forget(self); - id + ManuallyDrop::new(self).tid } } diff --git a/library/std/src/sys/pal/sgx/abi/tls/mod.rs b/library/std/src/sys/pal/sgx/abi/tls/mod.rs index 8a9ea4ac00df..bab59a3422d1 100644 --- a/library/std/src/sys/pal/sgx/abi/tls/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/tls/mod.rs @@ -95,8 +95,8 @@ impl Tls { #[allow(unused)] pub unsafe fn activate_persistent(self: Box) { // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition. - unsafe { set_tls_ptr(core::ptr::addr_of!(*self) as _) }; - mem::forget(self); + let ptr = Box::into_raw(self).cast_const().cast::(); + unsafe { set_tls_ptr(ptr) }; } unsafe fn current<'a>() -> &'a Tls { diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs index f99cea360f1f..b625636752cc 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs @@ -5,7 +5,7 @@ use crate::cell::UnsafeCell; use crate::cmp; use crate::convert::TryInto; use crate::intrinsics; -use crate::mem; +use crate::mem::{self, ManuallyDrop}; use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut}; use crate::ptr::{self, NonNull}; use crate::slice; @@ -176,6 +176,7 @@ unsafe impl UserSafe for [T] { /// are used solely to indicate intent: a mutable reference is for writing to /// user memory, an immutable reference for reading from user memory. #[unstable(feature = "sgx_platform", issue = "56975")] +#[repr(transparent)] pub struct UserRef(UnsafeCell); /// An owned type in userspace memory. `User` is equivalent to `Box` in /// enclave memory. Access to the memory is only allowed by copying to avoid @@ -266,9 +267,7 @@ where /// Converts this value into a raw pointer. The value will no longer be /// automatically freed. pub fn into_raw(self) -> *mut T { - let ret = self.0; - mem::forget(self); - ret.as_ptr() as _ + ManuallyDrop::new(self).0.as_ptr() as _ } } diff --git a/library/std/src/sys/pal/sgx/fd.rs b/library/std/src/sys/pal/sgx/fd.rs index b3686d0e2832..c41b527cff79 100644 --- a/library/std/src/sys/pal/sgx/fd.rs +++ b/library/std/src/sys/pal/sgx/fd.rs @@ -2,7 +2,7 @@ use fortanix_sgx_abi::Fd; use super::abi::usercalls; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::mem; +use crate::mem::ManuallyDrop; use crate::sys::{AsInner, FromInner, IntoInner}; #[derive(Debug)] @@ -21,9 +21,7 @@ impl FileDesc { /// Extracts the actual file descriptor without closing it. pub fn into_raw(self) -> Fd { - let fd = self.fd; - mem::forget(self); - fd + ManuallyDrop::new(self).fd } pub fn read(&self, buf: &mut [u8]) -> io::Result { @@ -70,9 +68,7 @@ impl AsInner for FileDesc { impl IntoInner for FileDesc { fn into_inner(self) -> Fd { - let fd = self.fd; - mem::forget(self); - fd + ManuallyDrop::new(self).fd } } diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs index 7a27d749f1c9..b821e98f9cb8 100644 --- a/library/std/src/sys/pal/teeos/thread.rs +++ b/library/std/src/sys/pal/teeos/thread.rs @@ -1,9 +1,7 @@ -use core::convert::TryInto; - use crate::cmp; use crate::ffi::CStr; use crate::io; -use crate::mem; +use crate::mem::{self, ManuallyDrop}; use crate::num::NonZero; use crate::ptr; use crate::sys::os; @@ -115,11 +113,9 @@ impl Thread { /// must join, because no pthread_detach supported pub fn join(self) { - unsafe { - let ret = libc::pthread_join(self.id, ptr::null_mut()); - mem::forget(self); - assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); - } + let id = self.into_id(); + let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; + assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); } pub fn id(&self) -> libc::pthread_t { @@ -127,9 +123,7 @@ impl Thread { } pub fn into_id(self) -> libc::pthread_t { - let id = self.id; - mem::forget(self); - id + ManuallyDrop::new(self).id } } diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index 10ae3c3ab570..f705bd614422 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -125,6 +125,7 @@ impl FileDesc { (&mut me).read_to_end(buf) } + #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))] pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { #[cfg(not(any( all(target_os = "linux", not(target_env = "musl")), @@ -318,6 +319,7 @@ impl FileDesc { cfg!(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))) } + #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))] pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { #[cfg(not(any( all(target_os = "linux", not(target_env = "musl")), diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 8308a48f16a9..c7915e26e3f0 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -463,15 +463,15 @@ impl FileAttr { #[cfg(target_os = "aix")] impl FileAttr { pub fn modified(&self) -> io::Result { - Ok(SystemTime::new(self.stat.st_mtime.tv_sec as i64, self.stat.st_mtime.tv_nsec as i64)) + SystemTime::new(self.stat.st_mtime.tv_sec as i64, self.stat.st_mtime.tv_nsec as i64) } pub fn accessed(&self) -> io::Result { - Ok(SystemTime::new(self.stat.st_atime.tv_sec as i64, self.stat.st_atime.tv_nsec as i64)) + SystemTime::new(self.stat.st_atime.tv_sec as i64, self.stat.st_atime.tv_nsec as i64) } pub fn created(&self) -> io::Result { - Ok(SystemTime::new(self.stat.st_ctime.tv_sec as i64, self.stat.st_ctime.tv_nsec as i64)) + SystemTime::new(self.stat.st_ctime.tv_sec as i64, self.stat.st_ctime.tv_nsec as i64) } } @@ -857,6 +857,7 @@ impl Drop for Dir { target_os = "espidf", target_os = "fuchsia", target_os = "horizon", + target_os = "vxworks", )))] { let fd = unsafe { libc::dirfd(self.0) }; @@ -1313,7 +1314,12 @@ impl File { } pub fn set_times(&self, times: FileTimes) -> io::Result<()> { - #[cfg(not(any(target_os = "redox", target_os = "espidf", target_os = "horizon")))] + #[cfg(not(any( + target_os = "redox", + target_os = "espidf", + target_os = "horizon", + target_os = "vxworks" + )))] let to_timespec = |time: Option| match time { Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts), Some(time) if time > crate::sys::time::UNIX_EPOCH => Err(io::const_io_error!( @@ -1327,10 +1333,11 @@ impl File { None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }), }; cfg_if::cfg_if! { - if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon"))] { + if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "vxworks"))] { // Redox doesn't appear to support `UTIME_OMIT`. // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore // the same as for Redox. + // `futimens` and `UTIME_OMIT` are a work in progress for vxworks. let _ = times; Err(io::const_io_error!( io::ErrorKind::Unsupported, @@ -1962,6 +1969,7 @@ pub fn fchown(fd: c_int, uid: u32, gid: u32) -> io::Result<()> { Ok(()) } +#[cfg(not(target_os = "vxworks"))] pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { run_path_with_cstr(path, &|path| { cvt(unsafe { libc::lchown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) }) @@ -1969,11 +1977,23 @@ pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { }) } +#[cfg(target_os = "vxworks")] +pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { + let (_, _, _) = (path, uid, gid); + Err(io::const_io_error!(io::ErrorKind::Unsupported, "lchown not supported by vxworks")) +} + #[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))] pub fn chroot(dir: &Path) -> io::Result<()> { run_path_with_cstr(dir, &|dir| cvt(unsafe { libc::chroot(dir.as_ptr()) }).map(|_| ())) } +#[cfg(target_os = "vxworks")] +pub fn chroot(dir: &Path) -> io::Result<()> { + let _ = dir; + Err(io::const_io_error!(io::ErrorKind::Unsupported, "chroot not supported by vxworks")) +} + pub use remove_dir_impl::remove_dir_all; // Fallback for REDOX, ESP-ID, Horizon, Vita, Vxworks and Miri diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 262f9c704a88..bdb995876ff2 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -164,6 +164,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_os = "emscripten", target_os = "fuchsia", target_os = "horizon", + target_os = "vxworks", // Unikraft's `signal` implementation is currently broken: // https://github.com/unikraft/lib-musl/issues/57 target_vendor = "unikraft", @@ -209,6 +210,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_os = "emscripten", target_os = "fuchsia", target_os = "horizon", + target_os = "vxworks", )))] static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::AtomicBool = crate::sync::atomic::AtomicBool::new(false); @@ -218,6 +220,7 @@ static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::AtomicBool = target_os = "emscripten", target_os = "fuchsia", target_os = "horizon", + target_os = "vxworks", )))] pub(crate) fn on_broken_pipe_flag_used() -> bool { ON_BROKEN_PIPE_FLAG_USED.load(crate::sync::atomic::Ordering::Relaxed) diff --git a/library/std/src/sys/pal/unix/process/process_vxworks.rs b/library/std/src/sys/pal/unix/process/process_vxworks.rs index 5007dbd34b4a..26b8a0a39dc4 100644 --- a/library/std/src/sys/pal/unix/process/process_vxworks.rs +++ b/library/std/src/sys/pal/unix/process/process_vxworks.rs @@ -3,8 +3,8 @@ use crate::io::{self, ErrorKind}; use crate::num::NonZero; use crate::sys; use crate::sys::cvt; +use crate::sys::pal::unix::thread; use crate::sys::process::process_common::*; -use crate::sys_common::thread; use libc::RTP_ID; use libc::{self, c_char, c_int}; @@ -68,7 +68,12 @@ impl Command { .as_ref() .map(|c| c.as_ptr()) .unwrap_or_else(|| *sys::os::environ() as *const _); - let stack_size = thread::min_stack(); + let stack_size = crate::cmp::max( + crate::env::var_os("RUST_MIN_STACK") + .and_then(|s| s.to_str().and_then(|s| s.parse().ok())) + .unwrap_or(thread::DEFAULT_MIN_STACK_SIZE), + libc::PTHREAD_STACK_MIN, + ); // ensure that access to the environment is synchronized let _lock = sys::os::env_read_lock(); diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 619f4e4121e7..483697b8597f 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -1,7 +1,7 @@ use crate::cmp; use crate::ffi::CStr; use crate::io; -use crate::mem; +use crate::mem::{self, ManuallyDrop}; use crate::num::NonZero; use crate::ptr; use crate::sys::{os, stack_overflow}; @@ -268,11 +268,9 @@ impl Thread { } pub fn join(self) { - unsafe { - let ret = libc::pthread_join(self.id, ptr::null_mut()); - mem::forget(self); - assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); - } + let id = self.into_id(); + let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; + assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); } pub fn id(&self) -> libc::pthread_t { @@ -280,9 +278,7 @@ impl Thread { } pub fn into_id(self) -> libc::pthread_t { - let id = self.id; - mem::forget(self); - id + ManuallyDrop::new(self).id } } diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs index 975eef2451f4..2a3a39aafa70 100644 --- a/library/std/src/sys/pal/wasi/thread.rs +++ b/library/std/src/sys/pal/wasi/thread.rs @@ -172,12 +172,10 @@ impl Thread { pub fn join(self) { cfg_if::cfg_if! { if #[cfg(target_feature = "atomics")] { - unsafe { - let ret = libc::pthread_join(self.id, ptr::null_mut()); - mem::forget(self); - if ret != 0 { - rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret)); - } + let id = mem::ManuallyDrop::new(self).id; + let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; + if ret != 0 { + rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret)); } } else { self.0 diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs index 987be6b69eec..020a2a4f3a28 100644 --- a/library/std/src/sys/pal/windows/alloc.rs +++ b/library/std/src/sys/pal/windows/alloc.rs @@ -37,7 +37,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> c::HANDLE) // Note that `dwBytes` is allowed to be zero, contrary to some other allocators. // // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapalloc -windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dwflags: u32, dwbytes: usize) -> *mut core::ffi::c_void); +windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dwflags: u32, dwbytes: usize) -> *mut c_void); // Reallocate a block of memory behind a given pointer `lpMem` from a given heap `hHeap`, // to a block of at least `dwBytes` bytes, either shrinking the block in place, @@ -61,9 +61,9 @@ windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dw windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc( hheap: c::HANDLE, dwflags : u32, - lpmem: *const core::ffi::c_void, + lpmem: *const c_void, dwbytes: usize -) -> *mut core::ffi::c_void); +) -> *mut c_void); // Free a block of memory behind a given pointer `lpMem` from a given heap `hHeap`. // Returns a nonzero value if the operation is successful, and zero if the operation fails. @@ -79,7 +79,7 @@ windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc( // Note that `lpMem` is allowed to be null, which will not cause the operation to fail. // // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree -windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap: c::HANDLE, dwflags: u32, lpmem: *const core::ffi::c_void) -> c::BOOL); +windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap: c::HANDLE, dwflags: u32, lpmem: *const c_void) -> c::BOOL); // Cached handle to the default heap of the current process. // Either a non-null handle returned by `GetProcessHeap`, or null when not yet initialized or `GetProcessHeap` failed. diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 488e74dc2fcb..f7ec17fde22e 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -4,13 +4,10 @@ #![cfg_attr(test, allow(dead_code))] #![unstable(issue = "none", feature = "windows_c")] #![allow(clippy::style)] -#![allow(unsafe_op_in_unsafe_fn)] -use crate::ffi::CStr; -use crate::mem; -use crate::os::raw::{c_uint, c_ulong, c_ushort, c_void}; -use crate::os::windows::io::{AsRawHandle, BorrowedHandle}; -use crate::ptr; +use core::ffi::{c_uint, c_ulong, c_ushort, c_void, CStr}; +use core::mem; +use core::ptr; pub(super) mod windows_targets; @@ -114,89 +111,6 @@ if #[cfg(not(target_vendor = "uwp"))] { } } -pub unsafe extern "system" fn WriteFileEx( - hFile: BorrowedHandle<'_>, - lpBuffer: *mut ::core::ffi::c_void, - nNumberOfBytesToWrite: u32, - lpOverlapped: *mut OVERLAPPED, - lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE, -) -> BOOL { - windows_sys::WriteFileEx( - hFile.as_raw_handle(), - lpBuffer.cast::(), - nNumberOfBytesToWrite, - lpOverlapped, - lpCompletionRoutine, - ) -} - -pub unsafe extern "system" fn ReadFileEx( - hFile: BorrowedHandle<'_>, - lpBuffer: *mut ::core::ffi::c_void, - nNumberOfBytesToRead: u32, - lpOverlapped: *mut OVERLAPPED, - lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE, -) -> BOOL { - windows_sys::ReadFileEx( - hFile.as_raw_handle(), - lpBuffer.cast::(), - nNumberOfBytesToRead, - lpOverlapped, - lpCompletionRoutine, - ) -} - -cfg_if::cfg_if! { -if #[cfg(not(target_vendor = "uwp"))] { -pub unsafe fn NtReadFile( - filehandle: BorrowedHandle<'_>, - event: HANDLE, - apcroutine: PIO_APC_ROUTINE, - apccontext: *mut c_void, - iostatusblock: &mut IO_STATUS_BLOCK, - buffer: *mut crate::mem::MaybeUninit, - length: u32, - byteoffset: Option<&i64>, - key: Option<&u32>, -) -> NTSTATUS { - windows_sys::NtReadFile( - filehandle.as_raw_handle(), - event, - apcroutine, - apccontext, - iostatusblock, - buffer.cast::(), - length, - byteoffset.map(|o| o as *const i64).unwrap_or(ptr::null()), - key.map(|k| k as *const u32).unwrap_or(ptr::null()), - ) -} -pub unsafe fn NtWriteFile( - filehandle: BorrowedHandle<'_>, - event: HANDLE, - apcroutine: PIO_APC_ROUTINE, - apccontext: *mut c_void, - iostatusblock: &mut IO_STATUS_BLOCK, - buffer: *const u8, - length: u32, - byteoffset: Option<&i64>, - key: Option<&u32>, -) -> NTSTATUS { - windows_sys::NtWriteFile( - filehandle.as_raw_handle(), - event, - apcroutine, - apccontext, - iostatusblock, - buffer.cast::(), - length, - byteoffset.map(|o| o as *const i64).unwrap_or(ptr::null()), - key.map(|k| k as *const u32).unwrap_or(ptr::null()), - ) -} -} -} - // Use raw-dylib to import ProcessPrng as we can't rely on there being an import library. cfg_if::cfg_if! { if #[cfg(not(target_vendor = "win7"))] { @@ -220,26 +134,26 @@ compat_fn_with_fallback! { // >= Win10 1607 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription pub fn SetThreadDescription(hthread: HANDLE, lpthreaddescription: PCWSTR) -> HRESULT { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL } } // >= Win10 1607 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreaddescription pub fn GetThreadDescription(hthread: HANDLE, lpthreaddescription: *mut PWSTR) -> HRESULT { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL } } // >= Win8 / Server 2012 // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime #[cfg(target_vendor = "win7")] pub fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime: *mut FILETIME) -> () { - GetSystemTimeAsFileTime(lpsystemtimeasfiletime) + unsafe { GetSystemTimeAsFileTime(lpsystemtimeasfiletime) } } // >= Win11 / Server 2022 // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a pub fn GetTempPath2W(bufferlength: u32, buffer: PWSTR) -> u32 { - GetTempPathW(bufferlength, buffer) + unsafe { GetTempPathW(bufferlength, buffer) } } } @@ -272,12 +186,12 @@ extern "system" { compat_fn_optional! { crate::sys::compat::load_synch_functions(); pub fn WaitOnAddress( - address: *const ::core::ffi::c_void, - compareaddress: *const ::core::ffi::c_void, + address: *const c_void, + compareaddress: *const c_void, addresssize: usize, dwmilliseconds: u32 ) -> BOOL; - pub fn WakeByAddressSingle(address: *const ::core::ffi::c_void); + pub fn WakeByAddressSingle(address: *const c_void); } #[cfg(any(target_vendor = "win7", target_vendor = "uwp"))] @@ -324,36 +238,36 @@ compat_fn_with_fallback! { shareaccess: FILE_SHARE_MODE, createdisposition: NTCREATEFILE_CREATE_DISPOSITION, createoptions: NTCREATEFILE_CREATE_OPTIONS, - eabuffer: *const ::core::ffi::c_void, + eabuffer: *const c_void, ealength: u32 ) -> NTSTATUS { STATUS_NOT_IMPLEMENTED } #[cfg(target_vendor = "uwp")] pub fn NtReadFile( - filehandle: BorrowedHandle<'_>, + filehandle: HANDLE, event: HANDLE, apcroutine: PIO_APC_ROUTINE, - apccontext: *mut c_void, - iostatusblock: &mut IO_STATUS_BLOCK, - buffer: *mut crate::mem::MaybeUninit, + apccontext: *const c_void, + iostatusblock: *mut IO_STATUS_BLOCK, + buffer: *mut c_void, length: u32, - byteoffset: Option<&i64>, - key: Option<&u32> + byteoffset: *const i64, + key: *const u32 ) -> NTSTATUS { STATUS_NOT_IMPLEMENTED } #[cfg(target_vendor = "uwp")] pub fn NtWriteFile( - filehandle: BorrowedHandle<'_>, + filehandle: HANDLE, event: HANDLE, apcroutine: PIO_APC_ROUTINE, - apccontext: *mut c_void, - iostatusblock: &mut IO_STATUS_BLOCK, - buffer: *const u8, + apccontext: *const c_void, + iostatusblock: *mut IO_STATUS_BLOCK, + buffer: *const c_void, length: u32, - byteoffset: Option<&i64>, - key: Option<&u32> + byteoffset: *const i64, + key: *const u32 ) -> NTSTATUS { STATUS_NOT_IMPLEMENTED } diff --git a/library/std/src/sys/pal/windows/compat.rs b/library/std/src/sys/pal/windows/compat.rs index 49fa1603f3e1..75232dfc0b0f 100644 --- a/library/std/src/sys/pal/windows/compat.rs +++ b/library/std/src/sys/pal/windows/compat.rs @@ -158,8 +158,10 @@ macro_rules! compat_fn_with_fallback { static PTR: AtomicPtr = AtomicPtr::new(load as *mut _); unsafe extern "system" fn load($($argname: $argtype),*) -> $rettype { - let func = load_from_module(Module::new($module)); - func($($argname),*) + unsafe { + let func = load_from_module(Module::new($module)); + func($($argname),*) + } } fn load_from_module(module: Option) -> F { @@ -182,8 +184,10 @@ macro_rules! compat_fn_with_fallback { #[inline(always)] pub unsafe fn call($($argname: $argtype),*) -> $rettype { - let func: F = mem::transmute(PTR.load(Ordering::Relaxed)); - func($($argname),*) + unsafe { + let func: F = mem::transmute(PTR.load(Ordering::Relaxed)); + func($($argname),*) + } } } #[allow(unused)] @@ -225,7 +229,7 @@ macro_rules! compat_fn_optional { } #[inline] pub unsafe extern "system" fn $symbol($($argname: $argtype),*) $(-> $rettype)? { - $symbol::option().unwrap()($($argname),*) + unsafe { $symbol::option().unwrap()($($argname),*) } } )+ ) diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index 706062ab984e..e5b2da697821 100644 --- a/library/std/src/sys/pal/windows/handle.rs +++ b/library/std/src/sys/pal/windows/handle.rs @@ -3,16 +3,17 @@ #[cfg(test)] mod tests; -use crate::cmp; use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, Read}; -use crate::mem; use crate::os::windows::io::{ AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, }; -use crate::ptr; use crate::sys::c; use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; +use core::cmp; +use core::ffi::c_void; +use core::mem; +use core::ptr; /// An owned container for `HANDLE` object, closing them on Drop. /// @@ -250,15 +251,15 @@ impl Handle { // the provided `len`. let status = unsafe { c::NtReadFile( - self.as_handle(), + self.as_raw_handle(), ptr::null_mut(), None, ptr::null_mut(), &mut io_status, - buf, + buf.cast::(), len, - offset.map(|n| n as _).as_ref(), - None, + offset.as_ref().map(|n| ptr::from_ref(n).cast::()).unwrap_or(ptr::null()), + ptr::null(), ) }; @@ -300,15 +301,15 @@ impl Handle { let len = cmp::min(buf.len(), u32::MAX as usize) as u32; let status = unsafe { c::NtWriteFile( - self.as_handle(), + self.as_raw_handle(), ptr::null_mut(), None, ptr::null_mut(), &mut io_status, - buf.as_ptr(), + buf.as_ptr().cast::(), len, - offset.map(|n| n as _).as_ref(), - None, + offset.as_ref().map(|n| ptr::from_ref(n).cast::()).unwrap_or(ptr::null()), + ptr::null(), ) }; let status = if status == c::STATUS_PENDING { diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index b85a8318bcbb..881ca17936d3 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -1,5 +1,5 @@ #![allow(missing_docs, nonstandard_style)] -#![deny(unsafe_op_in_unsafe_fn)] +#![forbid(unsafe_op_in_unsafe_fn)] use crate::ffi::{OsStr, OsString}; use crate::io::ErrorKind; diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index d5e2356116f2..01433d68b695 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -238,15 +238,6 @@ fn random_number() -> usize { } } -// Abstracts over `ReadFileEx` and `WriteFileEx` -type AlertableIoFn = unsafe extern "system" fn( - BorrowedHandle<'_>, - *mut core::ffi::c_void, - u32, - *mut c::OVERLAPPED, - c::LPOVERLAPPED_COMPLETION_ROUTINE, -) -> c::BOOL; - impl AnonPipe { pub fn handle(&self) -> &Handle { &self.inner @@ -262,7 +253,10 @@ impl AnonPipe { pub fn read(&self, buf: &mut [u8]) -> io::Result { let result = unsafe { let len = crate::cmp::min(buf.len(), u32::MAX as usize) as u32; - self.alertable_io_internal(c::ReadFileEx, buf.as_mut_ptr() as _, len) + let ptr = buf.as_mut_ptr(); + self.alertable_io_internal(|overlapped, callback| { + c::ReadFileEx(self.inner.as_raw_handle(), ptr, len, overlapped, callback) + }) }; match result { @@ -278,7 +272,10 @@ impl AnonPipe { pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { let result = unsafe { let len = crate::cmp::min(buf.capacity(), u32::MAX as usize) as u32; - self.alertable_io_internal(c::ReadFileEx, buf.as_mut().as_mut_ptr() as _, len) + let ptr = buf.as_mut().as_mut_ptr().cast::(); + self.alertable_io_internal(|overlapped, callback| { + c::ReadFileEx(self.inner.as_raw_handle(), ptr, len, overlapped, callback) + }) }; match result { @@ -313,7 +310,9 @@ impl AnonPipe { pub fn write(&self, buf: &[u8]) -> io::Result { unsafe { let len = crate::cmp::min(buf.len(), u32::MAX as usize) as u32; - self.alertable_io_internal(c::WriteFileEx, buf.as_ptr() as _, len) + self.alertable_io_internal(|overlapped, callback| { + c::WriteFileEx(self.inner.as_raw_handle(), buf.as_ptr(), len, overlapped, callback) + }) } } @@ -341,12 +340,9 @@ impl AnonPipe { /// [`ReadFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfileex /// [`WriteFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefileex /// [Asynchronous Procedure Call]: https://docs.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls - #[allow(unsafe_op_in_unsafe_fn)] unsafe fn alertable_io_internal( &self, - io: AlertableIoFn, - buf: *mut core::ffi::c_void, - len: u32, + io: impl FnOnce(&mut c::OVERLAPPED, c::LPOVERLAPPED_COMPLETION_ROUTINE) -> c::BOOL, ) -> io::Result { // Use "alertable I/O" to synchronize the pipe I/O. // This has four steps. @@ -384,20 +380,25 @@ impl AnonPipe { lpOverlapped: *mut c::OVERLAPPED, ) { // Set `async_result` using a pointer smuggled through `hEvent`. - let result = - AsyncResult { error: dwErrorCode, transferred: dwNumberOfBytesTransferred }; - *(*lpOverlapped).hEvent.cast::>() = Some(result); + // SAFETY: + // At this point, the OVERLAPPED struct will have been written to by the OS, + // except for our `hEvent` field which we set to a valid AsyncResult pointer (see below) + unsafe { + let result = + AsyncResult { error: dwErrorCode, transferred: dwNumberOfBytesTransferred }; + *(*lpOverlapped).hEvent.cast::>() = Some(result); + } } // STEP 1: Start the I/O operation. - let mut overlapped: c::OVERLAPPED = crate::mem::zeroed(); + let mut overlapped: c::OVERLAPPED = unsafe { crate::mem::zeroed() }; // `hEvent` is unused by `ReadFileEx` and `WriteFileEx`. // Therefore the documentation suggests using it to smuggle a pointer to the callback. overlapped.hEvent = core::ptr::addr_of_mut!(async_result) as *mut _; // Asynchronous read of the pipe. // If successful, `callback` will be called once it completes. - let result = io(self.inner.as_handle(), buf, len, &mut overlapped, Some(callback)); + let result = io(&mut overlapped, Some(callback)); if result == c::FALSE { // We can return here because the call failed. // After this we must not return until the I/O completes. @@ -408,7 +409,7 @@ impl AnonPipe { let result = loop { // STEP 2: Enter an alertable state. // The second parameter of `SleepEx` is used to make this sleep alertable. - c::SleepEx(c::INFINITE, c::TRUE); + unsafe { c::SleepEx(c::INFINITE, c::TRUE) }; if let Some(result) = async_result { break result; } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index e9731bc85d61..40c0d44df900 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -165,7 +165,7 @@ use crate::ffi::CStr; use crate::fmt; use crate::io; use crate::marker::PhantomData; -use crate::mem::{self, forget}; +use crate::mem::{self, forget, ManuallyDrop}; use crate::num::NonZero; use crate::panic; use crate::panicking; @@ -192,22 +192,14 @@ pub use scoped::{scope, Scope, ScopedJoinHandle}; #[macro_use] mod local; -cfg_if::cfg_if! { - if #[cfg(test)] { - // Avoid duplicating the global state associated with thread-locals between this crate and - // realstd. Miri relies on this. - pub use realstd::thread::{local_impl, AccessError, LocalKey}; - } else { - #[stable(feature = "rust1", since = "1.0.0")] - pub use self::local::{AccessError, LocalKey}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::local::{AccessError, LocalKey}; - // Implementation details used by the thread_local!{} macro. - #[doc(hidden)] - #[unstable(feature = "thread_local_internals", issue = "none")] - pub mod local_impl { - pub use crate::sys::thread_local::*; - } - } +// Implementation details used by the thread_local!{} macro. +#[doc(hidden)] +#[unstable(feature = "thread_local_internals", issue = "none")] +pub mod local_impl { + pub use crate::sys::thread_local::*; } //////////////////////////////////////////////////////////////////////////////// @@ -510,11 +502,10 @@ impl Builder { MaybeDangling(mem::MaybeUninit::new(x)) } fn into_inner(self) -> T { - // SAFETY: we are always initialized. - let ret = unsafe { self.0.assume_init_read() }; // Make sure we don't drop. - mem::forget(self); - ret + let this = ManuallyDrop::new(self); + // SAFETY: we are always initialized. + unsafe { this.0.assume_init_read() } } } impl Drop for MaybeDangling { diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 3e79acad1c4b..9bbebf9b8703 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1700,6 +1700,7 @@ impl Step for Assemble { // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0. if builder.download_rustc() { + builder.ensure(Std::new(target_compiler, target_compiler.host)); let sysroot = builder.ensure(Sysroot { compiler: target_compiler, force_recompile: false }); // Ensure that `libLLVM.so` ends up in the newly created target directory, diff --git a/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh b/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh index c806b886dae8..1a0b141e984b 100755 --- a/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh +++ b/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh @@ -35,7 +35,7 @@ PICK_REFS=() # commit hash of fuchsia.git and some other repos in the "monorepo" checkout, in # addition to versions of prebuilts. It should be bumped regularly by the # Fuchsia team – we aim for every 1-2 months. -INTEGRATION_SHA=d1d2f20efe46e22be179953dd6726c96eced54ab +INTEGRATION_SHA=1c5b42266fbfefb2337c6b2f0030a91bde15f9e9 checkout=fuchsia jiri=.jiri_root/bin/jiri diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index a04313b4b790..cf78a1d223c8 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -316,7 +316,8 @@ trait ItemTemplate<'a, 'cx: 'a>: rinja::Template + fmt::Display { fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: &[clean::Item]) { write!(w, "{}", document(cx, item, None, HeadingOffset::H2)); - let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::>(); + let mut not_stripped_items = + items.iter().filter(|i| !i.is_stripped()).enumerate().collect::>(); // the order of item types in the listing fn reorder(ty: ItemType) -> u8 { @@ -338,37 +339,29 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: } } - fn cmp( - i1: &clean::Item, - i2: &clean::Item, - idx1: usize, - idx2: usize, - tcx: TyCtxt<'_>, - ) -> Ordering { - let ty1 = i1.type_(); - let ty2 = i2.type_(); - if item_ty_to_section(ty1) != item_ty_to_section(ty2) - || (ty1 != ty2 && (ty1 == ItemType::ExternCrate || ty2 == ItemType::ExternCrate)) - { - return (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2)); + fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering { + let rty1 = reorder(i1.type_()); + let rty2 = reorder(i2.type_()); + if rty1 != rty2 { + return rty1.cmp(&rty2); } - let s1 = i1.stability(tcx).as_ref().map(|s| s.level); - let s2 = i2.stability(tcx).as_ref().map(|s| s.level); - if let (Some(a), Some(b)) = (s1, s2) { - match (a.is_stable(), b.is_stable()) { - (true, true) | (false, false) => {} - (false, true) => return Ordering::Greater, - (true, false) => return Ordering::Less, - } + let is_stable1 = i1.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true); + let is_stable2 = i2.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true); + if is_stable1 != is_stable2 { + // true is bigger than false in the standard bool ordering, + // but we actually want stable items to come first + return is_stable2.cmp(&is_stable1); } let lhs = i1.name.unwrap_or(kw::Empty); let rhs = i2.name.unwrap_or(kw::Empty); compare_names(lhs.as_str(), rhs.as_str()) } + let tcx = cx.tcx(); + match cx.shared.module_sorting { ModuleSorting::Alphabetical => { - indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2, cx.tcx())); + not_stripped_items.sort_by(|(_, i1), (_, i2)| cmp(i1, i2, tcx)); } ModuleSorting::DeclarationOrder => {} } @@ -391,24 +384,19 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: // can be identical even if the elements are different (mostly in imports). // So in case this is an import, we keep everything by adding a "unique id" // (which is the position in the vector). - indices.dedup_by_key(|i| { + not_stripped_items.dedup_by_key(|(idx, i)| { ( - items[*i].item_id, - if items[*i].name.is_some() { Some(full_path(cx, &items[*i])) } else { None }, - items[*i].type_(), - if items[*i].is_import() { *i } else { 0 }, + i.item_id, + if i.name.is_some() { Some(full_path(cx, i)) } else { None }, + i.type_(), + if i.is_import() { *idx } else { 0 }, ) }); - debug!("{indices:?}"); + debug!("{not_stripped_items:?}"); let mut last_section = None; - for &idx in &indices { - let myitem = &items[idx]; - if myitem.is_stripped() { - continue; - } - + for (_, myitem) in ¬_stripped_items { let my_section = item_ty_to_section(myitem.type_()); if Some(my_section) != last_section { if last_section.is_some() { @@ -424,7 +412,6 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: ); } - let tcx = cx.tcx(); match *myitem.kind { clean::ExternCrateItem { ref src } => { use crate::html::format::anchor; @@ -453,7 +440,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: let stab_tags = if let Some(import_def_id) = import.source.did { // Just need an item with the correct def_id and attrs let import_item = - clean::Item { item_id: import_def_id.into(), ..myitem.clone() }; + clean::Item { item_id: import_def_id.into(), ..(*myitem).clone() }; let stab_tags = Some(extra_info_tags(&import_item, item, tcx).to_string()); stab_tags @@ -2010,40 +1997,102 @@ fn item_keyword(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { } /// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order). -pub(crate) fn compare_names(mut lhs: &str, mut rhs: &str) -> Ordering { - /// Takes a non-numeric and a numeric part from the given &str. - fn take_parts<'a>(s: &mut &'a str) -> (&'a str, &'a str) { - let i = s.find(|c: char| c.is_ascii_digit()); - let (a, b) = s.split_at(i.unwrap_or(s.len())); - let i = b.find(|c: char| !c.is_ascii_digit()); - let (b, c) = b.split_at(i.unwrap_or(b.len())); - *s = c; - (a, b) - } +/// +/// This code is copied from [`rustfmt`], and should probably be released as a crate at some point. +/// +/// [`rustfmt`]:https://github.com/rust-lang/rustfmt/blob/rustfmt-2.0.0-rc.2/src/formatting/reorder.rs#L32 +pub(crate) fn compare_names(left: &str, right: &str) -> Ordering { + let mut left = left.chars().peekable(); + let mut right = right.chars().peekable(); - while !lhs.is_empty() || !rhs.is_empty() { - let (la, lb) = take_parts(&mut lhs); - let (ra, rb) = take_parts(&mut rhs); - // First process the non-numeric part. - match la.cmp(ra) { - Ordering::Equal => (), - x => return x, - } - // Then process the numeric part, if both sides have one (and they fit in a u64). - if let (Ok(ln), Ok(rn)) = (lb.parse::(), rb.parse::()) { - match ln.cmp(&rn) { - Ordering::Equal => (), - x => return x, + loop { + // The strings are equal so far and not inside a number in both sides + let (l, r) = match (left.next(), right.next()) { + // Is this the end of both strings? + (None, None) => return Ordering::Equal, + // If for one, the shorter one is considered smaller + (None, Some(_)) => return Ordering::Less, + (Some(_), None) => return Ordering::Greater, + (Some(l), Some(r)) => (l, r), + }; + let next_ordering = match (l.to_digit(10), r.to_digit(10)) { + // If neither is a digit, just compare them + (None, None) => Ord::cmp(&l, &r), + // The one with shorter non-digit run is smaller + // For `strverscmp` it's smaller iff next char in longer is greater than digits + (None, Some(_)) => Ordering::Greater, + (Some(_), None) => Ordering::Less, + // If both start numbers, we have to compare the numbers + (Some(l), Some(r)) => { + if l == 0 || r == 0 { + // Fraction mode: compare as if there was leading `0.` + let ordering = Ord::cmp(&l, &r); + if ordering != Ordering::Equal { + return ordering; + } + loop { + // Get next pair + let (l, r) = match (left.peek(), right.peek()) { + // Is this the end of both strings? + (None, None) => return Ordering::Equal, + // If for one, the shorter one is considered smaller + (None, Some(_)) => return Ordering::Less, + (Some(_), None) => return Ordering::Greater, + (Some(l), Some(r)) => (l, r), + }; + // Are they digits? + match (l.to_digit(10), r.to_digit(10)) { + // If out of digits, use the stored ordering due to equal length + (None, None) => break Ordering::Equal, + // If one is shorter, it's smaller + (None, Some(_)) => return Ordering::Less, + (Some(_), None) => return Ordering::Greater, + // If both are digits, consume them and take into account + (Some(l), Some(r)) => { + left.next(); + right.next(); + let ordering = Ord::cmp(&l, &r); + if ordering != Ordering::Equal { + return ordering; + } + } + } + } + } else { + // Integer mode + let mut same_length_ordering = Ord::cmp(&l, &r); + loop { + // Get next pair + let (l, r) = match (left.peek(), right.peek()) { + // Is this the end of both strings? + (None, None) => return same_length_ordering, + // If for one, the shorter one is considered smaller + (None, Some(_)) => return Ordering::Less, + (Some(_), None) => return Ordering::Greater, + (Some(l), Some(r)) => (l, r), + }; + // Are they digits? + match (l.to_digit(10), r.to_digit(10)) { + // If out of digits, use the stored ordering due to equal length + (None, None) => break same_length_ordering, + // If one is shorter, it's smaller + (None, Some(_)) => return Ordering::Less, + (Some(_), None) => return Ordering::Greater, + // If both are digits, consume them and take into account + (Some(l), Some(r)) => { + left.next(); + right.next(); + same_length_ordering = same_length_ordering.then(Ord::cmp(&l, &r)); + } + } + } + } } - } - // Then process the numeric part again, but this time as strings. - match lb.cmp(rb) { - Ordering::Equal => (), - x => return x, + }; + if next_ordering != Ordering::Equal { + return next_ordering; } } - - Ordering::Equal } pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String { diff --git a/src/librustdoc/html/render/tests.rs b/src/librustdoc/html/render/tests.rs index 3175fbe5666d..4a9724a6f840 100644 --- a/src/librustdoc/html/render/tests.rs +++ b/src/librustdoc/html/render/tests.rs @@ -34,7 +34,7 @@ fn test_compare_names() { #[test] fn test_name_sorting() { let names = [ - "Apple", "Banana", "Fruit", "Fruit0", "Fruit00", "Fruit01", "Fruit1", "Fruit02", "Fruit2", + "Apple", "Banana", "Fruit", "Fruit0", "Fruit00", "Fruit01", "Fruit02", "Fruit1", "Fruit2", "Fruit20", "Fruit30x", "Fruit100", "Pear", ]; let mut sorted = names.to_owned(); diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index fcc41b51542f..842046c941d4 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -121,7 +121,7 @@ fn remove_all_parens(pat: &mut P) { struct Visitor; impl MutVisitor for Visitor { fn visit_pat(&mut self, pat: &mut P) { - noop_visit_pat(pat, self); + walk_pat(self, pat); let inner = match &mut pat.kind { Paren(i) => mem::replace(&mut i.kind, Wild), _ => return, @@ -138,7 +138,7 @@ fn insert_necessary_parens(pat: &mut P) { impl MutVisitor for Visitor { fn visit_pat(&mut self, pat: &mut P) { use ast::BindingMode; - noop_visit_pat(pat, self); + walk_pat(self, pat); let target = match &mut pat.kind { // `i @ a | b`, `box a | b`, and `& mut? a | b`. Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p, @@ -160,7 +160,7 @@ fn unnest_or_patterns(pat: &mut P) -> bool { impl MutVisitor for Visitor { fn visit_pat(&mut self, p: &mut P) { // This is a bottom up transformation, so recurse first. - noop_visit_pat(p, self); + walk_pat(self, p); // Don't have an or-pattern? Just quit early on. let Or(alternatives) = &mut p.kind else { return }; @@ -189,7 +189,7 @@ fn unnest_or_patterns(pat: &mut P) -> bool { // Deal with `Some(Some(0)) | Some(Some(1))`. if this_level_changed { - noop_visit_pat(p, self); + walk_pat(self, p); } } } diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 0cf05b32e968..81a5acb5cf28 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -25,7 +25,7 @@ use build_helper::git::{get_git_modified_files, get_git_untracked_files}; use core::panic; use getopts::Options; use std::collections::HashSet; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::fs; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; @@ -225,6 +225,29 @@ pub fn parse_config(args: Vec) -> Config { // Avoid spawning an external command when we know tidy won't be used. false }; + let filters = if mode == Mode::RunMake { + matches + .free + .iter() + .map(|f| { + let path = Path::new(f); + let mut iter = path.iter().skip(1); + + // We skip the test folder and check if the user passed `rmake.rs` or `Makefile`. + if iter + .next() + .is_some_and(|s| s == OsStr::new("rmake.rs") || s == OsStr::new("Makefile")) + && iter.next().is_none() + { + path.parent().unwrap().to_str().unwrap().to_string() + } else { + f.to_string() + } + }) + .collect::>() + } else { + matches.free.clone() + }; Config { bless: matches.opt_present("bless"), compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), @@ -249,7 +272,7 @@ pub fn parse_config(args: Vec) -> Config { debugger: None, run_ignored, with_debug_assertions, - filters: matches.free.clone(), + filters, skip: matches.opt_strs("skip"), filter_exact: matches.opt_present("exact"), force_pass_mode: matches.opt_str("pass").map(|mode| { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr index 987d0fc4c2d0..079c1729b600 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr @@ -10,7 +10,7 @@ LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _ error: deadlock: the evaluated program deadlocked --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC | -LL | let ret = libc::pthread_join(self.id, ptr::null_mut()); +LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ the evaluated program deadlocked | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr index bc9b15f293ef..d03c6402d64f 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr @@ -10,7 +10,7 @@ LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu error: deadlock: the evaluated program deadlocked --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC | -LL | let ret = libc::pthread_join(self.id, ptr::null_mut()); +LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ the evaluated program deadlocked | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr index 66c142bbc5c8..73c5e77a1bce 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr @@ -10,7 +10,7 @@ LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu error: deadlock: the evaluated program deadlocked --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC | -LL | let ret = libc::pthread_join(self.id, ptr::null_mut()); +LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ the evaluated program deadlocked | = note: BACKTRACE: diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 8e693c35adcb..8d8cc7ad6d39 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -18,9 +18,9 @@ // ignore-tidy-dbg use crate::walk::{filter_dirs, walk}; -use regex::RegexSet; +use regex::RegexSetBuilder; use rustc_hash::FxHashMap; -use std::{ffi::OsStr, path::Path}; +use std::{ffi::OsStr, path::Path, sync::LazyLock}; #[cfg(test)] mod tests; @@ -110,16 +110,26 @@ const ROOT_PROBLEMATIC_CONSTS: &[u32] = &[ 173390526, 721077, ]; +const LETTER_DIGIT: &[(char, char)] = &[('A', '4'), ('B', '8'), ('E', '3')]; + // Returns all permutations of problematic consts, over 2000 elements. fn generate_problematic_strings( consts: &[u32], letter_digit: &FxHashMap, ) -> Vec { generate_problems(consts, letter_digit) - .flat_map(|v| vec![v.to_string(), format!("{:x}", v), format!("{:X}", v)]) + .flat_map(|v| vec![v.to_string(), format!("{:X}", v)]) .collect() } +static PROBLEMATIC_CONSTS_STRINGS: LazyLock> = LazyLock::new(|| { + generate_problematic_strings(ROOT_PROBLEMATIC_CONSTS, &LETTER_DIGIT.iter().cloned().collect()) +}); + +fn contains_problematic_const(trimmed: &str) -> bool { + PROBLEMATIC_CONSTS_STRINGS.iter().any(|s| trimmed.to_uppercase().contains(s)) +} + const INTERNAL_COMPILER_DOCS_LINE: &str = "#### This error code is internal to the compiler and will not be emitted with normal Rust code."; /// Parser states for `line_is_url`. @@ -316,14 +326,14 @@ pub fn check(path: &Path, bad: &mut bool) { // We only check CSS files in rustdoc. path.extension().map_or(false, |e| e == "css") && !is_in(path, "src", "librustdoc") } - let problematic_consts_strings = generate_problematic_strings( - ROOT_PROBLEMATIC_CONSTS, - &[('A', '4'), ('B', '8'), ('E', '3')].iter().cloned().collect(), - ); + // This creates a RegexSet as regex contains performance optimizations to be able to deal with these over // 2000 needles efficiently. This runs over the entire source code, so performance matters. - let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap(); - + let problematic_regex = RegexSetBuilder::new(PROBLEMATIC_CONSTS_STRINGS.as_slice()) + .case_insensitive(true) + .build() + .unwrap(); + let style_file = Path::new(file!()); walk(path, skip, &mut |entry, contents| { let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); @@ -389,10 +399,15 @@ pub fn check(path: &Path, bad: &mut bool) { let mut lines = 0; let mut last_safety_comment = false; let mut comment_block: Option<(usize, usize)> = None; - let is_test = file.components().any(|c| c.as_os_str() == "tests"); + let is_test = file.components().any(|c| c.as_os_str() == "tests") + || file.file_stem().unwrap() == "tests"; + let is_style = file.ends_with(style_file) || style_file.ends_with(file); + let is_style_test = + is_test && file.parent().unwrap().ends_with(style_file.with_extension("")); // scanning the whole file for multiple needles at once is more efficient than // executing lines times needles separate searches. - let any_problematic_line = problematic_regex.is_match(contents); + let any_problematic_line = + !is_style && !is_style_test && problematic_regex.is_match(contents); for (i, line) in contents.split('\n').enumerate() { if line.is_empty() { if i == 0 { @@ -451,7 +466,7 @@ pub fn check(path: &Path, bad: &mut bool) { if line.contains('\r') { suppressible_tidy_err!(err, skip_cr, "CR character"); } - if filename != "style.rs" { + if !is_style { // Allow using TODO in diagnostic suggestions by marking the // relevant line with `// ignore-tidy-todo`. if trimmed.contains("TODO") && !trimmed.contains("ignore-tidy-todo") { @@ -462,12 +477,8 @@ pub fn check(path: &Path, bad: &mut bool) { if trimmed.contains("//") && trimmed.contains(" XXX") { err("Instead of XXX use FIXME") } - if any_problematic_line { - for s in problematic_consts_strings.iter() { - if trimmed.contains(s) { - err("Don't use magic numbers that spell things (consider 0x12345678)"); - } - } + if any_problematic_line && contains_problematic_const(trimmed) { + err("Don't use magic numbers that spell things (consider 0x12345678)"); } } // for now we just check libcore diff --git a/src/tools/tidy/src/style/tests.rs b/src/tools/tidy/src/style/tests.rs index 292e23916d24..8a3586dad0e3 100644 --- a/src/tools/tidy/src/style/tests.rs +++ b/src/tools/tidy/src/style/tests.rs @@ -1,17 +1,10 @@ use super::*; #[test] -fn test_generate_problematic_strings() { - let problematic_regex = RegexSet::new( - generate_problematic_strings( - ROOT_PROBLEMATIC_CONSTS, - &[('A', '4'), ('B', '8'), ('E', '3'), ('0', 'F')].iter().cloned().collect(), // use "futile" F intentionally - ) - .as_slice(), - ) - .unwrap(); - assert!(problematic_regex.is_match("786357")); // check with no "decimal" hex digits - converted to integer - assert!(problematic_regex.is_match("589701")); // check with "decimal" replacements - converted to integer - assert!(problematic_regex.is_match("8FF85")); // check for hex display - assert!(!problematic_regex.is_match("1193046")); // check for non-matching value +fn test_contains_problematic_const() { + assert!(contains_problematic_const("721077")); // check with no "decimal" hex digits - converted to integer + assert!(contains_problematic_const("524421")); // check with "decimal" replacements - converted to integer + assert!(contains_problematic_const(&(285 * 281).to_string())); // check for hex display + assert!(contains_problematic_const(&format!("{:x}B5", 2816))); // check for case-alternating hex display + assert!(!contains_problematic_const("1193046")); // check for non-matching value } diff --git a/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr b/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr index 50d55284754e..ef551cbea3e6 100644 --- a/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr +++ b/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr @@ -18,7 +18,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w --> $DIR/invalid_const_in_lifetime_position.rs:4:26 | LL | fn f<'a>(arg : Box = &'a ()>>) {} - | ^--- help: remove these generics + | ^--- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -49,7 +49,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w --> $DIR/invalid_const_in_lifetime_position.rs:4:26 | LL | fn f<'a>(arg : Box = &'a ()>>) {} - | ^--- help: remove these generics + | ^--- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -81,7 +81,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w --> $DIR/invalid_const_in_lifetime_position.rs:4:26 | LL | fn f<'a>(arg : Box = &'a ()>>) {} - | ^--- help: remove these generics + | ^--- help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/rustdoc-ui/mismatched_arg_count.stderr b/tests/rustdoc-ui/mismatched_arg_count.stderr index 857bbda2ef47..5daeef2eb18f 100644 --- a/tests/rustdoc-ui/mismatched_arg_count.stderr +++ b/tests/rustdoc-ui/mismatched_arg_count.stderr @@ -2,7 +2,7 @@ error[E0107]: type alias takes 1 lifetime argument but 2 lifetime arguments were --> $DIR/mismatched_arg_count.rs:7:29 | LL | fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {} - | ^^^^^ -- help: remove this lifetime argument + | ^^^^^ ---- help: remove the lifetime argument | | | expected 1 lifetime argument | diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs index 762ad0b79ecc..8379ca86494c 100644 --- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs @@ -46,9 +46,11 @@ use thin_vec::{thin_vec, ThinVec}; fn parse_expr(psess: &ParseSess, src: &str) -> Option> { let src_as_string = src.to_string(); - let mut p = unwrap_or_emit_fatal( - new_parser_from_source_str(psess, FileName::Custom(src_as_string.clone()), src_as_string) - ); + let mut p = unwrap_or_emit_fatal(new_parser_from_source_str( + psess, + FileName::Custom(src_as_string.clone()), + src_as_string, + )); p.parse_expr().map_err(|e| e.cancel()).ok() } @@ -181,10 +183,9 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { 18 => { let pat = P(Pat { id: DUMMY_NODE_ID, kind: PatKind::Wild, span: DUMMY_SP, tokens: None }); - iter_exprs( - depth - 1, - &mut |e| g(ExprKind::Let(pat.clone(), e, DUMMY_SP, Recovered::No)) - ) + iter_exprs(depth - 1, &mut |e| { + g(ExprKind::Let(pat.clone(), e, DUMMY_SP, Recovered::No)) + }) } _ => panic!("bad counter value in iter_exprs"), } @@ -202,7 +203,7 @@ impl MutVisitor for RemoveParens { ExprKind::Paren(inner) => *e = inner, _ => {} }; - mut_visit::noop_visit_expr(e, self); + mut_visit::walk_expr(self, e); } } @@ -211,7 +212,7 @@ struct AddParens; impl MutVisitor for AddParens { fn visit_expr(&mut self, e: &mut P) { - mut_visit::noop_visit_expr(e, self); + mut_visit::walk_expr(self, e); visit_clobber(e, |e| { P(Expr { id: DUMMY_NODE_ID, diff --git a/tests/ui/argument-suggestions/issue-100154.stderr b/tests/ui/argument-suggestions/issue-100154.stderr index 966f56e2a156..7eaebcafb595 100644 --- a/tests/ui/argument-suggestions/issue-100154.stderr +++ b/tests/ui/argument-suggestions/issue-100154.stderr @@ -2,7 +2,7 @@ error[E0107]: function takes 0 generic arguments but 1 generic argument was supp --> $DIR/issue-100154.rs:4:5 | LL | foo::<()>(()); - | ^^^------ help: remove these generics + | ^^^------ help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/async-await/async-fn/edition-2015.rs b/tests/ui/async-await/async-fn/edition-2015.rs index 83b9d415ddab..50448313b301 100644 --- a/tests/ui/async-await/async-fn/edition-2015.rs +++ b/tests/ui/async-await/async-fn/edition-2015.rs @@ -3,5 +3,7 @@ fn foo(x: impl async Fn()) -> impl async Fn() { x } //~| ERROR `async` trait bounds are only allowed in Rust 2018 or later //~| ERROR async closures are unstable //~| ERROR async closures are unstable +//~| ERROR use of unstable library feature 'async_closure' +//~| ERROR use of unstable library feature 'async_closure' fn main() {} diff --git a/tests/ui/async-await/async-fn/edition-2015.stderr b/tests/ui/async-await/async-fn/edition-2015.stderr index 0029d53868d4..23ffee0d0a6b 100644 --- a/tests/ui/async-await/async-fn/edition-2015.stderr +++ b/tests/ui/async-await/async-fn/edition-2015.stderr @@ -38,6 +38,26 @@ LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: to use an async block, remove the `||`: `async {` -error: aborting due to 4 previous errors +error[E0658]: use of unstable library feature 'async_closure' + --> $DIR/edition-2015.rs:1:22 + | +LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } + | ^^^^ + | + = note: see issue #62290 for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'async_closure' + --> $DIR/edition-2015.rs:1:42 + | +LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } + | ^^^^ + | + = note: see issue #62290 for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/async-await/async-fn/simple.rs b/tests/ui/async-await/async-fn/simple.rs index 21972ba5aefa..3f15b08560af 100644 --- a/tests/ui/async-await/async-fn/simple.rs +++ b/tests/ui/async-await/async-fn/simple.rs @@ -2,7 +2,7 @@ //@ edition: 2021 //@ build-pass -#![feature(async_fn_traits)] +#![feature(async_closure)] extern crate block_on; diff --git a/tests/crashes/119272.rs b/tests/ui/auto-traits/opaque_type_candidate_selection.rs similarity index 91% rename from tests/crashes/119272.rs rename to tests/ui/auto-traits/opaque_type_candidate_selection.rs index 02e2cfd09e2f..d6973b76a6e1 100644 --- a/tests/crashes/119272.rs +++ b/tests/ui/auto-traits/opaque_type_candidate_selection.rs @@ -1,4 +1,7 @@ -//@ known-bug: #119272 +//! used to ICE: #119272 + +//@ check-pass + #![feature(type_alias_impl_trait)] mod defining_scope { use super::*; diff --git a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr index c0b6dcd1512f..e9efc932ea8a 100644 --- a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr +++ b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr @@ -2,7 +2,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp --> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59 | LL | async fn buy_lock(coroutine: &Mutex) -> LockedMarket<'_> { - | ^^^^^^^^^^^^---- help: remove these generics + | ^^^^^^^^^^^^---- help: remove the unnecessary generics | | | expected 0 lifetime arguments | @@ -32,7 +32,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp --> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59 | LL | async fn buy_lock(coroutine: &Mutex) -> LockedMarket<'_> { - | ^^^^^^^^^^^^---- help: remove these generics + | ^^^^^^^^^^^^---- help: remove the unnecessary generics | | | expected 0 lifetime arguments | diff --git a/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr b/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr index a8fc742e89f5..5c04c4c9d5b5 100644 --- a/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr +++ b/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr @@ -2,7 +2,7 @@ error[E0107]: trait takes at most 2 generic arguments but 3 generic arguments we --> $DIR/transmutable-ice-110969.rs:11:14 | LL | Dst: BikeshedIntrinsicFrom, - | ^^^^^^^^^^^^^^^^^^^^^ ------ help: remove this generic argument + | ^^^^^^^^^^^^^^^^^^^^^ -------- help: remove the unnecessary generic argument | | | expected at most 2 generic arguments diff --git a/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr b/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr index 6d8dd017734c..a9c57dbf26a0 100644 --- a/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr +++ b/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr @@ -23,7 +23,7 @@ error[E0107]: struct takes 2 generic arguments but 3 generic arguments were supp --> $DIR/infer-arg-test.rs:18:10 | LL | let a: All<_, _, _>; - | ^^^ - help: remove this generic argument + | ^^^ --- help: remove the unnecessary generic argument | | | expected 2 generic arguments | diff --git a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr index 0c29d94ed5b4..4d1fb02b59e9 100644 --- a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr +++ b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr @@ -2,7 +2,7 @@ error[E0107]: function takes 1 generic argument but 2 generic arguments were sup --> $DIR/issue_114151.rs:17:5 | LL | foo::<_, L>([(); L + 1 + L]); - | ^^^ - help: remove this generic argument + | ^^^ --- help: remove the unnecessary generic argument | | | expected 1 generic argument | diff --git a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr index a470c36134cf..37e09a075fe3 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr @@ -18,7 +18,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w --> $DIR/issue-102768.rs:9:30 | LL | fn f2<'a>(arg: Box = &'a ()>>) {} - | ^--- help: remove these generics + | ^--- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -49,7 +49,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w --> $DIR/issue-102768.rs:9:30 | LL | fn f2<'a>(arg: Box = &'a ()>>) {} - | ^--- help: remove these generics + | ^--- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -81,7 +81,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w --> $DIR/issue-102768.rs:9:30 | LL | fn f2<'a>(arg: Box = &'a ()>>) {} - | ^--- help: remove these generics + | ^--- help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/const-generics/incorrect-number-of-const-args.stderr b/tests/ui/const-generics/incorrect-number-of-const-args.stderr index 01ac4e69a057..09c963c350ef 100644 --- a/tests/ui/const-generics/incorrect-number-of-const-args.stderr +++ b/tests/ui/const-generics/incorrect-number-of-const-args.stderr @@ -20,7 +20,7 @@ error[E0107]: function takes 2 generic arguments but 3 generic arguments were su --> $DIR/incorrect-number-of-const-args.rs:9:5 | LL | foo::<0, 0, 0>(); - | ^^^ - help: remove this generic argument + | ^^^ --- help: remove the unnecessary generic argument | | | expected 2 generic arguments | diff --git a/tests/ui/const-generics/invalid-const-arg-for-type-param.stderr b/tests/ui/const-generics/invalid-const-arg-for-type-param.stderr index 4a649d8a7e88..4004ad190325 100644 --- a/tests/ui/const-generics/invalid-const-arg-for-type-param.stderr +++ b/tests/ui/const-generics/invalid-const-arg-for-type-param.stderr @@ -8,7 +8,7 @@ help: consider moving this generic argument to the `TryInto` trait, which takes | LL | let _: u32 = TryInto::<32>::try_into(5i32).unwrap(); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: remove these generics +help: remove the unnecessary generics | LL - let _: u32 = 5i32.try_into::<32>().unwrap(); LL + let _: u32 = 5i32.try_into().unwrap(); @@ -27,7 +27,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli --> $DIR/invalid-const-arg-for-type-param.rs:12:5 | LL | S::<0>; - | ^----- help: remove these generics + | ^----- help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/const-generics/invalid-constant-in-args.stderr b/tests/ui/const-generics/invalid-constant-in-args.stderr index 158b9722ee61..3e1263e8e8c0 100644 --- a/tests/ui/const-generics/invalid-constant-in-args.stderr +++ b/tests/ui/const-generics/invalid-constant-in-args.stderr @@ -2,7 +2,7 @@ error[E0107]: struct takes 1 generic argument but 2 generic arguments were suppl --> $DIR/invalid-constant-in-args.rs:4:12 | LL | let _: Cell<&str, "a"> = Cell::new(""); - | ^^^^ --- help: remove this generic argument + | ^^^^ ----- help: remove the unnecessary generic argument | | | expected 1 generic argument diff --git a/tests/ui/const-generics/opaque_types.stderr b/tests/ui/const-generics/opaque_types.stderr index 2c7384984c69..3947d645fcbe 100644 --- a/tests/ui/const-generics/opaque_types.stderr +++ b/tests/ui/const-generics/opaque_types.stderr @@ -122,8 +122,6 @@ note: ...which requires const checking `main::{constant#0}`... | LL | foo::<42>(); | ^^ - = note: ...which requires computing whether `Foo` is freeze... - = note: ...which requires evaluating trait selection obligation `Foo: core::marker::Freeze`... = note: ...which again requires computing type of opaque `Foo::{opaque#0}`, completing the cycle note: cycle used when computing type of `Foo::{opaque#0}` --> $DIR/opaque_types.rs:3:12 diff --git a/tests/ui/constructor-lifetime-args.stderr b/tests/ui/constructor-lifetime-args.stderr index a18123fe19cb..d3759f4b3658 100644 --- a/tests/ui/constructor-lifetime-args.stderr +++ b/tests/ui/constructor-lifetime-args.stderr @@ -20,7 +20,7 @@ error[E0107]: struct takes 2 lifetime arguments but 3 lifetime arguments were su --> $DIR/constructor-lifetime-args.rs:19:5 | LL | S::<'static, 'static, 'static>(&0, &0); - | ^ ------- help: remove this lifetime argument + | ^ --------- help: remove the lifetime argument | | | expected 2 lifetime arguments | @@ -52,7 +52,7 @@ error[E0107]: enum takes 2 lifetime arguments but 3 lifetime arguments were supp --> $DIR/constructor-lifetime-args.rs:24:8 | LL | E::V::<'static, 'static, 'static>(&0); - | ^ ------- help: remove this lifetime argument + | ^ --------- help: remove the lifetime argument | | | expected 2 lifetime arguments | diff --git a/tests/ui/consts/const-fn-cycle.rs b/tests/ui/consts/const-fn-cycle.rs index 5175296a53e5..2879e3049c0d 100644 --- a/tests/ui/consts/const-fn-cycle.rs +++ b/tests/ui/consts/const-fn-cycle.rs @@ -7,6 +7,8 @@ /// to end up revealing opaque types (the RPIT in `many`'s return type), /// which can quickly lead to cycles. +//@ check-pass + pub struct Parser(H); impl Parser @@ -18,7 +20,6 @@ where } pub const fn many<'s>(&'s self) -> Parser Fn(&'a str) -> Vec + 's> { - //~^ ERROR: cycle detected Parser::new(|_| unimplemented!()) } } diff --git a/tests/ui/consts/const-fn-cycle.stderr b/tests/ui/consts/const-fn-cycle.stderr deleted file mode 100644 index c851f7342be9..000000000000 --- a/tests/ui/consts/const-fn-cycle.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0391]: cycle detected when computing type of opaque `::many::{opaque#0}` - --> $DIR/const-fn-cycle.rs:20:47 - | -LL | pub const fn many<'s>(&'s self) -> Parser Fn(&'a str) -> Vec + 's> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires borrow-checking `::many`... - --> $DIR/const-fn-cycle.rs:20:5 - | -LL | pub const fn many<'s>(&'s self) -> Parser Fn(&'a str) -> Vec + 's> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires promoting constants in MIR for `::many`... - --> $DIR/const-fn-cycle.rs:20:5 - | -LL | pub const fn many<'s>(&'s self) -> Parser Fn(&'a str) -> Vec + 's> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const checking `::many`... - --> $DIR/const-fn-cycle.rs:20:5 - | -LL | pub const fn many<'s>(&'s self) -> Parser Fn(&'a str) -> Vec + 's> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing whether `Parser<::many::{opaque#0}>` is freeze... - = note: ...which requires evaluating trait selection obligation `Parser<::many::{opaque#0}>: core::marker::Freeze`... - = note: ...which again requires computing type of opaque `::many::{opaque#0}`, completing the cycle -note: cycle used when computing type of `::many::{opaque#0}` - --> $DIR/const-fn-cycle.rs:20:47 - | -LL | pub const fn many<'s>(&'s self) -> Parser Fn(&'a str) -> Vec + 's> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/consts/const-promoted-opaque.atomic.stderr b/tests/ui/consts/const-promoted-opaque.atomic.stderr index a0459f4040ec..1f2a7753ff54 100644 --- a/tests/ui/consts/const-promoted-opaque.atomic.stderr +++ b/tests/ui/consts/const-promoted-opaque.atomic.stderr @@ -1,5 +1,5 @@ error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability - --> $DIR/const-promoted-opaque.rs:29:25 + --> $DIR/const-promoted-opaque.rs:28:25 | LL | let _: &'static _ = &FOO; | ^^^^ @@ -9,7 +9,7 @@ LL | let _: &'static _ = &FOO; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0493]: destructor of `helper::Foo` cannot be evaluated at compile-time - --> $DIR/const-promoted-opaque.rs:29:26 + --> $DIR/const-promoted-opaque.rs:28:26 | LL | let _: &'static _ = &FOO; | ^^^ the destructor for this type cannot be evaluated in constants @@ -18,13 +18,13 @@ LL | }; | - value is dropped here error[E0492]: constants cannot refer to interior mutable data - --> $DIR/const-promoted-opaque.rs:34:19 + --> $DIR/const-promoted-opaque.rs:33:19 | LL | const BAZ: &Foo = &FOO; | ^^^^ this borrow of an interior mutable value may end up in the final value error[E0716]: temporary value dropped while borrowed - --> $DIR/const-promoted-opaque.rs:38:26 + --> $DIR/const-promoted-opaque.rs:37:26 | LL | let _: &'static _ = &FOO; | ---------- ^^^ creates a temporary value which is freed while still in use @@ -34,38 +34,7 @@ LL | LL | } | - temporary value is freed at the end of this statement -error[E0391]: cycle detected when computing type of opaque `helper::Foo::{opaque#0}` - --> $DIR/const-promoted-opaque.rs:14:20 - | -LL | pub type Foo = impl Sized; - | ^^^^^^^^^^ - | -note: ...which requires borrow-checking `helper::FOO`... - --> $DIR/const-promoted-opaque.rs:21:5 - | -LL | pub const FOO: Foo = std::sync::atomic::AtomicU8::new(42); - | ^^^^^^^^^^^^^^^^^^ -note: ...which requires promoting constants in MIR for `helper::FOO`... - --> $DIR/const-promoted-opaque.rs:21:5 - | -LL | pub const FOO: Foo = std::sync::atomic::AtomicU8::new(42); - | ^^^^^^^^^^^^^^^^^^ -note: ...which requires const checking `helper::FOO`... - --> $DIR/const-promoted-opaque.rs:21:5 - | -LL | pub const FOO: Foo = std::sync::atomic::AtomicU8::new(42); - | ^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing whether `helper::Foo` is freeze... - = note: ...which requires evaluating trait selection obligation `helper::Foo: core::marker::Freeze`... - = note: ...which again requires computing type of opaque `helper::Foo::{opaque#0}`, completing the cycle -note: cycle used when computing type of `helper::Foo::{opaque#0}` - --> $DIR/const-promoted-opaque.rs:14:20 - | -LL | pub type Foo = impl Sized; - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +error: aborting due to 4 previous errors -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0391, E0492, E0493, E0658, E0716. -For more information about an error, try `rustc --explain E0391`. +Some errors have detailed explanations: E0492, E0493, E0658, E0716. +For more information about an error, try `rustc --explain E0492`. diff --git a/tests/ui/consts/const-promoted-opaque.rs b/tests/ui/consts/const-promoted-opaque.rs index e20823527f48..303618df9df0 100644 --- a/tests/ui/consts/const-promoted-opaque.rs +++ b/tests/ui/consts/const-promoted-opaque.rs @@ -12,7 +12,6 @@ mod helper { pub type Foo = impl Sized; - //[string,atomic]~^ ERROR cycle detected #[cfg(string)] pub const FOO: Foo = String::new(); @@ -28,11 +27,11 @@ use helper::*; const BAR: () = { let _: &'static _ = &FOO; //[string,atomic]~^ ERROR: destructor of `helper::Foo` cannot be evaluated at compile-time - //[string,atomic]~| ERROR: cannot borrow here + //[atomic]~| ERROR: cannot borrow here }; const BAZ: &Foo = &FOO; -//[string,atomic]~^ ERROR: constants cannot refer to interior mutable data +//[atomic]~^ ERROR: constants cannot refer to interior mutable data fn main() { let _: &'static _ = &FOO; diff --git a/tests/ui/consts/const-promoted-opaque.string.stderr b/tests/ui/consts/const-promoted-opaque.string.stderr index a613d517e68e..fa1dbb05d175 100644 --- a/tests/ui/consts/const-promoted-opaque.string.stderr +++ b/tests/ui/consts/const-promoted-opaque.string.stderr @@ -1,15 +1,5 @@ -error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability - --> $DIR/const-promoted-opaque.rs:29:25 - | -LL | let _: &'static _ = &FOO; - | ^^^^ - | - = note: see issue #80384 for more information - = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0493]: destructor of `helper::Foo` cannot be evaluated at compile-time - --> $DIR/const-promoted-opaque.rs:29:26 + --> $DIR/const-promoted-opaque.rs:28:26 | LL | let _: &'static _ = &FOO; | ^^^ the destructor for this type cannot be evaluated in constants @@ -17,14 +7,8 @@ LL | let _: &'static _ = &FOO; LL | }; | - value is dropped here -error[E0492]: constants cannot refer to interior mutable data - --> $DIR/const-promoted-opaque.rs:34:19 - | -LL | const BAZ: &Foo = &FOO; - | ^^^^ this borrow of an interior mutable value may end up in the final value - error[E0716]: temporary value dropped while borrowed - --> $DIR/const-promoted-opaque.rs:38:26 + --> $DIR/const-promoted-opaque.rs:37:26 | LL | let _: &'static _ = &FOO; | ---------- ^^^ creates a temporary value which is freed while still in use @@ -34,38 +18,7 @@ LL | LL | } | - temporary value is freed at the end of this statement -error[E0391]: cycle detected when computing type of opaque `helper::Foo::{opaque#0}` - --> $DIR/const-promoted-opaque.rs:14:20 - | -LL | pub type Foo = impl Sized; - | ^^^^^^^^^^ - | -note: ...which requires borrow-checking `helper::FOO`... - --> $DIR/const-promoted-opaque.rs:18:5 - | -LL | pub const FOO: Foo = String::new(); - | ^^^^^^^^^^^^^^^^^^ -note: ...which requires promoting constants in MIR for `helper::FOO`... - --> $DIR/const-promoted-opaque.rs:18:5 - | -LL | pub const FOO: Foo = String::new(); - | ^^^^^^^^^^^^^^^^^^ -note: ...which requires const checking `helper::FOO`... - --> $DIR/const-promoted-opaque.rs:18:5 - | -LL | pub const FOO: Foo = String::new(); - | ^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing whether `helper::Foo` is freeze... - = note: ...which requires evaluating trait selection obligation `helper::Foo: core::marker::Freeze`... - = note: ...which again requires computing type of opaque `helper::Foo::{opaque#0}`, completing the cycle -note: cycle used when computing type of `helper::Foo::{opaque#0}` - --> $DIR/const-promoted-opaque.rs:14:20 - | -LL | pub type Foo = impl Sized; - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +error: aborting due to 2 previous errors -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0391, E0492, E0493, E0658, E0716. -For more information about an error, try `rustc --explain E0391`. +Some errors have detailed explanations: E0493, E0716. +For more information about an error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/effect_param.stderr b/tests/ui/consts/effect_param.stderr index dba5d49b7921..c63be8035f30 100644 --- a/tests/ui/consts/effect_param.stderr +++ b/tests/ui/consts/effect_param.stderr @@ -2,7 +2,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli --> $DIR/effect_param.rs:11:9 | LL | i8::checked_sub::(42, 43); - | ^^^^^^^^^^^--------- help: remove these generics + | ^^^^^^^^^^^--------- help: remove the unnecessary generics | | | expected 0 generic arguments @@ -10,7 +10,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli --> $DIR/effect_param.rs:13:9 | LL | i8::checked_sub::(42, 43); - | ^^^^^^^^^^^-------- help: remove these generics + | ^^^^^^^^^^^-------- help: remove the unnecessary generics | | | expected 0 generic arguments @@ -18,7 +18,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli --> $DIR/effect_param.rs:4:9 | LL | i8::checked_sub::(42, 43); - | ^^^^^^^^^^^-------- help: remove these generics + | ^^^^^^^^^^^-------- help: remove the unnecessary generics | | | expected 0 generic arguments @@ -26,7 +26,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli --> $DIR/effect_param.rs:6:9 | LL | i8::checked_sub::(42, 43); - | ^^^^^^^^^^^--------- help: remove these generics + | ^^^^^^^^^^^--------- help: remove the unnecessary generics | | | expected 0 generic arguments diff --git a/tests/ui/error-codes/E0107.rs b/tests/ui/error-codes/E0107.rs index fd23e7c00f2b..161360a50128 100644 --- a/tests/ui/error-codes/E0107.rs +++ b/tests/ui/error-codes/E0107.rs @@ -16,35 +16,35 @@ struct Baz<'a, 'b, 'c> { bar: Bar<'a>, //~^ ERROR enum takes 0 lifetime arguments - //~| HELP remove these generics + //~| HELP remove the unnecessary generics foo2: Foo<'a, 'b, 'c>, //~^ ERROR struct takes 1 lifetime argument - //~| HELP remove these lifetime arguments + //~| HELP remove the lifetime arguments qux1: Qux<'a, 'b, i32>, //~^ ERROR struct takes 1 lifetime argument - //~| HELP remove this lifetime argument + //~| HELP remove the lifetime argument qux2: Qux<'a, i32, 'b>, //~^ ERROR struct takes 1 lifetime argument - //~| HELP remove this lifetime argument + //~| HELP remove the lifetime argument qux3: Qux<'a, 'b, 'c, i32>, //~^ ERROR struct takes 1 lifetime argument - //~| HELP remove these lifetime arguments + //~| HELP remove the lifetime arguments qux4: Qux<'a, i32, 'b, 'c>, //~^ ERROR struct takes 1 lifetime argument - //~| HELP remove these lifetime arguments + //~| HELP remove the lifetime arguments qux5: Qux<'a, 'b, i32, 'c>, //~^ ERROR struct takes 1 lifetime argument - //~| HELP remove this lifetime argument + //~| HELP remove the lifetime argument quux: Quux<'a, i32, 'b>, //~^ ERROR struct takes 0 lifetime arguments - //~| HELP remove this lifetime argument + //~| HELP remove the lifetime argument } pub trait T { diff --git a/tests/ui/error-codes/E0107.stderr b/tests/ui/error-codes/E0107.stderr index 3f540eb08bc7..4aa83cf7f5ff 100644 --- a/tests/ui/error-codes/E0107.stderr +++ b/tests/ui/error-codes/E0107.stderr @@ -20,7 +20,7 @@ error[E0107]: enum takes 0 lifetime arguments but 1 lifetime argument was suppli --> $DIR/E0107.rs:17:10 | LL | bar: Bar<'a>, - | ^^^---- help: remove these generics + | ^^^---- help: remove the unnecessary generics | | | expected 0 lifetime arguments | @@ -34,7 +34,7 @@ error[E0107]: struct takes 1 lifetime argument but 3 lifetime arguments were sup --> $DIR/E0107.rs:21:11 | LL | foo2: Foo<'a, 'b, 'c>, - | ^^^ ------ help: remove these lifetime arguments + | ^^^ -------- help: remove the lifetime arguments | | | expected 1 lifetime argument | @@ -48,7 +48,7 @@ error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were sup --> $DIR/E0107.rs:25:11 | LL | qux1: Qux<'a, 'b, i32>, - | ^^^ -- help: remove this lifetime argument + | ^^^ ---- help: remove the lifetime argument | | | expected 1 lifetime argument | @@ -62,7 +62,7 @@ error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were sup --> $DIR/E0107.rs:29:11 | LL | qux2: Qux<'a, i32, 'b>, - | ^^^ -- help: remove this lifetime argument + | ^^^ --------- help: remove the lifetime argument | | | expected 1 lifetime argument | @@ -76,7 +76,7 @@ error[E0107]: struct takes 1 lifetime argument but 3 lifetime arguments were sup --> $DIR/E0107.rs:33:11 | LL | qux3: Qux<'a, 'b, 'c, i32>, - | ^^^ ------ help: remove these lifetime arguments + | ^^^ -------- help: remove the lifetime arguments | | | expected 1 lifetime argument | @@ -90,7 +90,7 @@ error[E0107]: struct takes 1 lifetime argument but 3 lifetime arguments were sup --> $DIR/E0107.rs:37:11 | LL | qux4: Qux<'a, i32, 'b, 'c>, - | ^^^ ------ help: remove these lifetime arguments + | ^^^ ------------- help: remove the lifetime arguments | | | expected 1 lifetime argument | @@ -104,7 +104,7 @@ error[E0107]: struct takes 1 lifetime argument but 3 lifetime arguments were sup --> $DIR/E0107.rs:41:11 | LL | qux5: Qux<'a, 'b, i32, 'c>, - | ^^^ -- help: remove this lifetime argument + | ^^^ ---- help: remove the lifetime argument | | | expected 1 lifetime argument | @@ -118,7 +118,7 @@ error[E0107]: struct takes 0 lifetime arguments but 2 lifetime arguments were su --> $DIR/E0107.rs:45:11 | LL | quux: Quux<'a, i32, 'b>, - | ^^^^ -- help: remove this lifetime argument + | ^^^^ -- help: remove the lifetime argument | | | expected 0 lifetime arguments | diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr index fcd3e7d9aace..9d8e91c02ca3 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr +++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr @@ -43,7 +43,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w --> $DIR/gat-trait-path-parenthesised-args.rs:5:27 | LL | fn foo<'a>(arg: Box>) {} - | ^---- help: remove these generics + | ^---- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -74,7 +74,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w --> $DIR/gat-trait-path-parenthesised-args.rs:5:27 | LL | fn foo<'a>(arg: Box>) {} - | ^---- help: remove these generics + | ^---- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -106,7 +106,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w --> $DIR/gat-trait-path-parenthesised-args.rs:5:27 | LL | fn foo<'a>(arg: Box>) {} - | ^---- help: remove these generics + | ^---- help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/generic-associated-types/parameter_number_and_kind.stderr b/tests/ui/generic-associated-types/parameter_number_and_kind.stderr index 4523044b5886..4a20cf55cae7 100644 --- a/tests/ui/generic-associated-types/parameter_number_and_kind.stderr +++ b/tests/ui/generic-associated-types/parameter_number_and_kind.stderr @@ -2,7 +2,7 @@ error[E0107]: associated type takes 1 lifetime argument but 2 lifetime arguments --> $DIR/parameter_number_and_kind.rs:11:24 | LL | type FErr1 = Self::E<'static, 'static>; - | ^ ------- help: remove this lifetime argument + | ^ --------- help: remove the lifetime argument | | | expected 1 lifetime argument | @@ -32,7 +32,7 @@ error[E0107]: associated type takes 1 generic argument but 2 generic arguments w --> $DIR/parameter_number_and_kind.rs:14:27 | LL | type FErr2 = Self::E<'static, T, u32>; - | ^ --- help: remove this generic argument + | ^ ----- help: remove the unnecessary generic argument | | | expected 1 generic argument | diff --git a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr index 2090f75aed32..539b6695e9e8 100644 --- a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr +++ b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr @@ -18,7 +18,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w --> $DIR/trait-path-type-error-once-implemented.rs:6:29 | LL | fn f2<'a>(arg : Box = &'a ()>>) {} - | ^--- help: remove these generics + | ^--- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -49,7 +49,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w --> $DIR/trait-path-type-error-once-implemented.rs:6:29 | LL | fn f2<'a>(arg : Box = &'a ()>>) {} - | ^--- help: remove these generics + | ^--- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -81,7 +81,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w --> $DIR/trait-path-type-error-once-implemented.rs:6:29 | LL | fn f2<'a>(arg : Box = &'a ()>>) {} - | ^--- help: remove these generics + | ^--- help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/generics/bad-mid-path-type-params.stderr b/tests/ui/generics/bad-mid-path-type-params.stderr index 71e15dd4c926..de3c0289fc6e 100644 --- a/tests/ui/generics/bad-mid-path-type-params.stderr +++ b/tests/ui/generics/bad-mid-path-type-params.stderr @@ -2,7 +2,7 @@ error[E0107]: associated function takes 1 generic argument but 2 generic argumen --> $DIR/bad-mid-path-type-params.rs:30:16 | LL | let _ = S::new::(1, 1.0); - | ^^^ --- help: remove this generic argument + | ^^^ ---- help: remove the unnecessary generic argument | | | expected 1 generic argument | @@ -16,7 +16,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp --> $DIR/bad-mid-path-type-params.rs:33:13 | LL | let _ = S::<'a,isize>::new::(1, 1.0); - | ^ -- help: remove this lifetime argument + | ^ -- help: remove the lifetime argument | | | expected 0 lifetime arguments | @@ -30,7 +30,7 @@ error[E0107]: associated function takes 1 generic argument but 2 generic argumen --> $DIR/bad-mid-path-type-params.rs:36:24 | LL | let _: S2 = Trait::new::(1, 1.0); - | ^^^ --- help: remove this generic argument + | ^^^ ---- help: remove the unnecessary generic argument | | | expected 1 generic argument | @@ -44,7 +44,7 @@ error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was suppl --> $DIR/bad-mid-path-type-params.rs:39:17 | LL | let _: S2 = Trait::<'a,isize>::new::(1, 1.0); - | ^^^^^ -- help: remove this lifetime argument + | ^^^^^ -- help: remove the lifetime argument | | | expected 0 lifetime arguments | @@ -58,7 +58,7 @@ error[E0107]: associated function takes 1 generic argument but 2 generic argumen --> $DIR/bad-mid-path-type-params.rs:39:36 | LL | let _: S2 = Trait::<'a,isize>::new::(1, 1.0); - | ^^^ --- help: remove this generic argument + | ^^^ ---- help: remove the unnecessary generic argument | | | expected 1 generic argument | diff --git a/tests/ui/generics/foreign-generic-mismatch.stderr b/tests/ui/generics/foreign-generic-mismatch.stderr index 5322b3f919d2..32beac41b21b 100644 --- a/tests/ui/generics/foreign-generic-mismatch.stderr +++ b/tests/ui/generics/foreign-generic-mismatch.stderr @@ -20,7 +20,7 @@ error[E0107]: function takes 1 lifetime argument but 2 lifetime arguments were s --> $DIR/foreign-generic-mismatch.rs:8:31 | LL | foreign_generic_mismatch::lt_arg::<'static, 'static>(); - | ^^^^^^ ------- help: remove this lifetime argument + | ^^^^^^ --------- help: remove the lifetime argument | | | expected 1 lifetime argument | diff --git a/tests/ui/generics/generic-arg-mismatch-recover.stderr b/tests/ui/generics/generic-arg-mismatch-recover.stderr index f549a7180fc6..172683a8f9b3 100644 --- a/tests/ui/generics/generic-arg-mismatch-recover.stderr +++ b/tests/ui/generics/generic-arg-mismatch-recover.stderr @@ -2,7 +2,7 @@ error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were sup --> $DIR/generic-arg-mismatch-recover.rs:6:5 | LL | Foo::<'static, 'static, ()>(&0); - | ^^^ ------- help: remove this lifetime argument + | ^^^ --------- help: remove the lifetime argument | | | expected 1 lifetime argument | @@ -16,7 +16,7 @@ error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were sup --> $DIR/generic-arg-mismatch-recover.rs:9:5 | LL | Bar::<'static, 'static, ()>(&()); - | ^^^ ------- help: remove this lifetime argument + | ^^^ --------- help: remove the lifetime argument | | | expected 1 lifetime argument | @@ -30,7 +30,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli --> $DIR/generic-arg-mismatch-recover.rs:9:5 | LL | Bar::<'static, 'static, ()>(&()); - | ^^^ -- help: remove this generic argument + | ^^^ -- help: remove the unnecessary generic argument | | | expected 0 generic arguments | diff --git a/tests/ui/generics/generic-impl-more-params-with-defaults.stderr b/tests/ui/generics/generic-impl-more-params-with-defaults.stderr index c5812abfd3df..16bdc2de2520 100644 --- a/tests/ui/generics/generic-impl-more-params-with-defaults.stderr +++ b/tests/ui/generics/generic-impl-more-params-with-defaults.stderr @@ -2,7 +2,7 @@ error[E0107]: struct takes at most 2 generic arguments but 3 generic arguments w --> $DIR/generic-impl-more-params-with-defaults.rs:13:5 | LL | Vec::::new(); - | ^^^ ---- help: remove this generic argument + | ^^^ ------ help: remove the unnecessary generic argument | | | expected at most 2 generic arguments | diff --git a/tests/ui/generics/generic-type-more-params-with-defaults.stderr b/tests/ui/generics/generic-type-more-params-with-defaults.stderr index c44f6b7ddc02..1eb76e043e04 100644 --- a/tests/ui/generics/generic-type-more-params-with-defaults.stderr +++ b/tests/ui/generics/generic-type-more-params-with-defaults.stderr @@ -2,7 +2,7 @@ error[E0107]: struct takes at most 2 generic arguments but 3 generic arguments w --> $DIR/generic-type-more-params-with-defaults.rs:9:12 | LL | let _: Vec; - | ^^^ ---- help: remove this generic argument + | ^^^ ------ help: remove the unnecessary generic argument | | | expected at most 2 generic arguments | diff --git a/tests/ui/generics/wrong-number-of-args.rs b/tests/ui/generics/wrong-number-of-args.rs index 95463d1c32c3..6524bd538b6b 100644 --- a/tests/ui/generics/wrong-number-of-args.rs +++ b/tests/ui/generics/wrong-number-of-args.rs @@ -5,19 +5,19 @@ mod no_generics { type B = Ty<'static>; //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument - //~| HELP remove these generics + //~| HELP remove the unnecessary generics type C = Ty<'static, usize>; //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument //~| ERROR struct takes 0 generic arguments but 1 generic argument - //~| HELP remove this lifetime argument - //~| HELP remove this generic argument + //~| HELP remove the lifetime argument + //~| HELP remove the unnecessary generic argument type D = Ty<'static, usize, { 0 }>; //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument //~| ERROR struct takes 0 generic arguments but 2 generic arguments - //~| HELP remove this lifetime argument - //~| HELP remove these generic arguments + //~| HELP remove the lifetime argument + //~| HELP remove the unnecessary generic arguments } mod type_and_type { @@ -35,7 +35,7 @@ mod type_and_type { type D = Ty; //~^ ERROR struct takes 2 generic arguments but 3 generic arguments - //~| HELP remove this + //~| HELP remove the type E = Ty<>; //~^ ERROR struct takes 2 generic arguments but 0 generic arguments were supplied @@ -70,8 +70,8 @@ mod lifetime_and_type { type F = Ty<'static, usize, 'static, usize>; //~^ ERROR struct takes 1 lifetime argument but 2 lifetime arguments //~| ERROR struct takes 1 generic argument but 2 generic arguments - //~| HELP remove this lifetime argument - //~| HELP remove this generic argument + //~| HELP remove the lifetime argument + //~| HELP remove the unnecessary generic argument } mod type_and_type_and_type { @@ -317,13 +317,13 @@ mod stdlib { type C = HashMap<'static>; //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument - //~| HELP remove these generics + //~| HELP remove the //~| ERROR struct takes at least 2 //~| HELP add missing type D = HashMap; //~^ ERROR struct takes at most 3 - //~| HELP remove this + //~| HELP remove the type E = HashMap<>; //~^ ERROR struct takes at least 2 generic arguments but 0 generic arguments @@ -341,7 +341,7 @@ mod stdlib { type C = Result<'static>; //~^ ERROR enum takes 0 lifetime arguments but 1 lifetime argument - //~| HELP remove these generics + //~| HELP remove the unnecessary generics //~| ERROR enum takes 2 generic arguments but 0 generic arguments //~| HELP add missing diff --git a/tests/ui/generics/wrong-number-of-args.stderr b/tests/ui/generics/wrong-number-of-args.stderr index e04408a0fdf3..bac0d26b622d 100644 --- a/tests/ui/generics/wrong-number-of-args.stderr +++ b/tests/ui/generics/wrong-number-of-args.stderr @@ -171,7 +171,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp --> $DIR/wrong-number-of-args.rs:6:14 | LL | type B = Ty<'static>; - | ^^--------- help: remove these generics + | ^^--------- help: remove the unnecessary generics | | | expected 0 lifetime arguments | @@ -185,7 +185,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp --> $DIR/wrong-number-of-args.rs:10:14 | LL | type C = Ty<'static, usize>; - | ^^ ------- help: remove this lifetime argument + | ^^ ------- help: remove the lifetime argument | | | expected 0 lifetime arguments | @@ -199,7 +199,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli --> $DIR/wrong-number-of-args.rs:10:14 | LL | type C = Ty<'static, usize>; - | ^^ ----- help: remove this generic argument + | ^^ ----- help: remove the unnecessary generic argument | | | expected 0 generic arguments | @@ -213,7 +213,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp --> $DIR/wrong-number-of-args.rs:16:14 | LL | type D = Ty<'static, usize, { 0 }>; - | ^^ ------- help: remove this lifetime argument + | ^^ ------- help: remove the lifetime argument | | | expected 0 lifetime arguments | @@ -227,7 +227,7 @@ error[E0107]: struct takes 0 generic arguments but 2 generic arguments were supp --> $DIR/wrong-number-of-args.rs:16:14 | LL | type D = Ty<'static, usize, { 0 }>; - | ^^ ------------ help: remove these generic arguments + | ^^ ------- help: remove the unnecessary generic arguments | | | expected 0 generic arguments | @@ -275,7 +275,7 @@ error[E0107]: struct takes 2 generic arguments but 3 generic arguments were supp --> $DIR/wrong-number-of-args.rs:36:14 | LL | type D = Ty; - | ^^ ---- help: remove this generic argument + | ^^ ------ help: remove the unnecessary generic argument | | | expected 2 generic arguments | @@ -353,7 +353,7 @@ error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were sup --> $DIR/wrong-number-of-args.rs:70:14 | LL | type F = Ty<'static, usize, 'static, usize>; - | ^^ ------- help: remove this lifetime argument + | ^^ ---------------- help: remove the lifetime argument | | | expected 1 lifetime argument | @@ -367,7 +367,7 @@ error[E0107]: struct takes 1 generic argument but 2 generic arguments were suppl --> $DIR/wrong-number-of-args.rs:70:14 | LL | type F = Ty<'static, usize, 'static, usize>; - | ^^ ----- help: remove this generic argument + | ^^ ---------------- help: remove the unnecessary generic argument | | | expected 1 generic argument | @@ -415,7 +415,7 @@ error[E0107]: struct takes at most 3 generic arguments but 4 generic arguments w --> $DIR/wrong-number-of-args.rs:92:14 | LL | type E = Ty; - | ^^ --- help: remove this generic argument + | ^^ ----- help: remove the unnecessary generic argument | | | expected at most 3 generic arguments | @@ -445,7 +445,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/wrong-number-of-args.rs:116:22 | LL | type A = Box>; - | ^^^^^^^^^^------- help: remove these generics + | ^^^^^^^^^^------- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -459,7 +459,7 @@ error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supp --> $DIR/wrong-number-of-args.rs:125:22 | LL | type C = Box>; - | ^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument + | ^^^^^^^^^^^^^^^ --------- help: remove the lifetime argument | | | expected 1 lifetime argument | @@ -489,7 +489,7 @@ error[E0107]: trait takes 1 generic argument but 2 generic arguments were suppli --> $DIR/wrong-number-of-args.rs:133:22 | LL | type E = Box>; - | ^^^^^^^^^^^ ----- help: remove this generic argument + | ^^^^^^^^^^^ ------- help: remove the unnecessary generic argument | | | expected 1 generic argument | @@ -519,7 +519,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/wrong-number-of-args.rs:153:26 | LL | type A = Box>; - | ^^^^^^^^^^^^------------------- help: remove these generics + | ^^^^^^^^^^^^------------------- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -533,7 +533,7 @@ error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supp --> $DIR/wrong-number-of-args.rs:168:26 | LL | type B = Box>; - | ^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument + | ^^^^^^^^^^^^^^^^^ --------- help: remove the lifetime argument | | | expected 1 lifetime argument | @@ -547,7 +547,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/wrong-number-of-args.rs:172:26 | LL | type C = Box>; - | ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument + | ^^^^^^^^^^^^^^^^^ -- help: remove the unnecessary generic argument | | | expected 0 generic arguments | @@ -577,7 +577,7 @@ error[E0107]: trait takes 1 generic argument but 2 generic arguments were suppli --> $DIR/wrong-number-of-args.rs:189:26 | LL | type B = Box>; - | ^^^^^^^^^^^^^ -- help: remove this generic argument + | ^^^^^^^^^^^^^ ---- help: remove the unnecessary generic argument | | | expected 1 generic argument | @@ -591,7 +591,7 @@ error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was suppl --> $DIR/wrong-number-of-args.rs:193:26 | LL | type C = Box>; - | ^^^^^^^^^^^^^--------------------- help: remove these generics + | ^^^^^^^^^^^^^--------------------- help: remove the unnecessary generics | | | expected 0 lifetime arguments | @@ -653,7 +653,7 @@ error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supp --> $DIR/wrong-number-of-args.rs:216:26 | LL | type C = Box>; - | ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument + | ^^^^^^^^^^^^^^^^^^^^^ --------- help: remove the lifetime argument | | | expected 1 lifetime argument | @@ -683,7 +683,7 @@ error[E0107]: trait takes 1 generic argument but 2 generic arguments were suppli --> $DIR/wrong-number-of-args.rs:227:26 | LL | type E = Box>; - | ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument + | ^^^^^^^^^^^^^^^^^^^^^ ---- help: remove the unnecessary generic argument | | | expected 1 generic argument | @@ -697,7 +697,7 @@ error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supp --> $DIR/wrong-number-of-args.rs:234:26 | LL | type F = Box>; - | ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument + | ^^^^^^^^^^^^^^^^^^^^^ --------- help: remove the lifetime argument | | | expected 1 lifetime argument | @@ -711,7 +711,7 @@ error[E0107]: trait takes 1 generic argument but 2 generic arguments were suppli --> $DIR/wrong-number-of-args.rs:238:26 | LL | type G = Box>; - | ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument + | ^^^^^^^^^^^^^^^^^^^^^ ---- help: remove the unnecessary generic argument | | | expected 1 generic argument | @@ -725,7 +725,7 @@ error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supp --> $DIR/wrong-number-of-args.rs:242:26 | LL | type H = Box>; - | ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument + | ^^^^^^^^^^^^^^^^^^^^^ --------- help: remove the lifetime argument | | | expected 1 lifetime argument | @@ -739,7 +739,7 @@ error[E0107]: trait takes 1 generic argument but 2 generic arguments were suppli --> $DIR/wrong-number-of-args.rs:242:26 | LL | type H = Box>; - | ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument + | ^^^^^^^^^^^^^^^^^^^^^ ---- help: remove the unnecessary generic argument | | | expected 1 generic argument | @@ -787,7 +787,7 @@ error[E0107]: trait takes 2 generic arguments but 3 generic arguments were suppl --> $DIR/wrong-number-of-args.rs:262:26 | LL | type C = Box>; - | ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument + | ^^^^^^^^^^^^^^^^^ ---- help: remove the unnecessary generic argument | | | expected 2 generic arguments | @@ -911,7 +911,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp --> $DIR/wrong-number-of-args.rs:318:18 | LL | type C = HashMap<'static>; - | ^^^^^^^--------- help: remove these generics + | ^^^^^^^--------- help: remove the unnecessary generics | | | expected 0 lifetime arguments @@ -930,7 +930,7 @@ error[E0107]: struct takes at most 3 generic arguments but 4 generic arguments w --> $DIR/wrong-number-of-args.rs:324:18 | LL | type D = HashMap; - | ^^^^^^^ --- help: remove this generic argument + | ^^^^^^^ ----- help: remove the unnecessary generic argument | | | expected at most 3 generic arguments @@ -973,7 +973,7 @@ error[E0107]: enum takes 0 lifetime arguments but 1 lifetime argument was suppli --> $DIR/wrong-number-of-args.rs:342:18 | LL | type C = Result<'static>; - | ^^^^^^--------- help: remove these generics + | ^^^^^^--------- help: remove the unnecessary generics | | | expected 0 lifetime arguments @@ -992,7 +992,7 @@ error[E0107]: enum takes 2 generic arguments but 3 generic arguments were suppli --> $DIR/wrong-number-of-args.rs:348:18 | LL | type D = Result; - | ^^^^^^ ---- help: remove this generic argument + | ^^^^^^ ------ help: remove the unnecessary generic argument | | | expected 2 generic arguments diff --git a/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr new file mode 100644 index 000000000000..5caf0eb2fd4e --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr @@ -0,0 +1,22 @@ +error[E0283]: type annotations needed + --> $DIR/auto-trait-selection-freeze.rs:19:16 + | +LL | if false { is_trait(foo()) } else { Default::default() } + | ^^^^^^^^ ----- type must be known at this point + | | + | cannot infer type of the type parameter `T` declared on the function `is_trait` + | + = note: cannot satisfy `_: Trait<_>` +note: required by a bound in `is_trait` + --> $DIR/auto-trait-selection-freeze.rs:11:16 + | +LL | fn is_trait, U: Default>(_: T) -> U { + | ^^^^^^^^ required by this bound in `is_trait` +help: consider specifying the generic arguments + | +LL | if false { is_trait::(foo()) } else { Default::default() } + | ++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/impl-trait/auto-trait-selection-freeze.old.stderr b/tests/ui/impl-trait/auto-trait-selection-freeze.old.stderr new file mode 100644 index 000000000000..b4d2229d408d --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-selection-freeze.old.stderr @@ -0,0 +1,26 @@ +error[E0283]: type annotations needed + --> $DIR/auto-trait-selection-freeze.rs:19:16 + | +LL | if false { is_trait(foo()) } else { Default::default() } + | ^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `is_trait` + | +note: multiple `impl`s satisfying `impl Sized: Trait<_>` found + --> $DIR/auto-trait-selection-freeze.rs:16:1 + | +LL | impl Trait for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Trait for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `is_trait` + --> $DIR/auto-trait-selection-freeze.rs:11:16 + | +LL | fn is_trait, U: Default>(_: T) -> U { + | ^^^^^^^^ required by this bound in `is_trait` +help: consider specifying the generic arguments + | +LL | if false { is_trait::<_, U>(foo()) } else { Default::default() } + | ++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/impl-trait/auto-trait-selection-freeze.rs b/tests/ui/impl-trait/auto-trait-selection-freeze.rs new file mode 100644 index 000000000000..7306a1c41f74 --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-selection-freeze.rs @@ -0,0 +1,23 @@ +//! This test shows how we fail selection in a way that can influence +//! selection in a code path that succeeds. + +//@ revisions: next old +//@[next] compile-flags: -Znext-solver + +#![feature(freeze)] + +use std::marker::Freeze; + +fn is_trait, U: Default>(_: T) -> U { + Default::default() +} + +trait Trait {} +impl Trait for T {} +impl Trait for T {} +fn foo() -> impl Sized { + if false { is_trait(foo()) } else { Default::default() } + //~^ ERROR: type annotations needed +} + +fn main() {} diff --git a/tests/ui/impl-trait/auto-trait-selection.next.stderr b/tests/ui/impl-trait/auto-trait-selection.next.stderr new file mode 100644 index 000000000000..d34fdcc44967 --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-selection.next.stderr @@ -0,0 +1,22 @@ +error[E0283]: type annotations needed + --> $DIR/auto-trait-selection.rs:15:16 + | +LL | if false { is_trait(foo()) } else { Default::default() } + | ^^^^^^^^ ----- type must be known at this point + | | + | cannot infer type of the type parameter `T` declared on the function `is_trait` + | + = note: cannot satisfy `_: Trait<_>` +note: required by a bound in `is_trait` + --> $DIR/auto-trait-selection.rs:7:16 + | +LL | fn is_trait, U: Default>(_: T) -> U { + | ^^^^^^^^ required by this bound in `is_trait` +help: consider specifying the generic arguments + | +LL | if false { is_trait::(foo()) } else { Default::default() } + | ++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/impl-trait/auto-trait-selection.old.stderr b/tests/ui/impl-trait/auto-trait-selection.old.stderr new file mode 100644 index 000000000000..1b5fd95fdf90 --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-selection.old.stderr @@ -0,0 +1,26 @@ +error[E0283]: type annotations needed + --> $DIR/auto-trait-selection.rs:15:16 + | +LL | if false { is_trait(foo()) } else { Default::default() } + | ^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `is_trait` + | +note: multiple `impl`s satisfying `impl Sized: Trait<_>` found + --> $DIR/auto-trait-selection.rs:12:1 + | +LL | impl Trait for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Trait for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `is_trait` + --> $DIR/auto-trait-selection.rs:7:16 + | +LL | fn is_trait, U: Default>(_: T) -> U { + | ^^^^^^^^ required by this bound in `is_trait` +help: consider specifying the generic arguments + | +LL | if false { is_trait::<_, U>(foo()) } else { Default::default() } + | ++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/impl-trait/auto-trait-selection.rs b/tests/ui/impl-trait/auto-trait-selection.rs new file mode 100644 index 000000000000..ee5612459c25 --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-selection.rs @@ -0,0 +1,19 @@ +//! This test shows how we fail selection in a way that can influence +//! selection in a code path that succeeds. + +//@ revisions: next old +//@[next] compile-flags: -Znext-solver + +fn is_trait, U: Default>(_: T) -> U { + Default::default() +} + +trait Trait {} +impl Trait for T {} +impl Trait for T {} +fn foo() -> impl Sized { + if false { is_trait(foo()) } else { Default::default() } + //~^ ERROR: type annotations needed +} + +fn main() {} diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr index fe6e166cb4fa..fb51bb7b4173 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `my_debug` found for opaque type `impl Debug` in the current scope - --> $DIR/call_method_on_inherent_impl_ref.rs:20:11 + --> $DIR/call_method_on_inherent_impl_ref.rs:19:11 | LL | fn my_debug(&self); | -------- the method is available for `&impl Debug` here @@ -14,27 +14,6 @@ note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it LL | trait MyDebug { | ^^^^^^^^^^^^^ -error[E0391]: cycle detected when computing type of opaque `my_foo::{opaque#0}` - --> $DIR/call_method_on_inherent_impl_ref.rs:15:16 - | -LL | fn my_foo() -> impl std::fmt::Debug { - | ^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires type-checking `my_foo`... - --> $DIR/call_method_on_inherent_impl_ref.rs:20:9 - | -LL | x.my_debug(); - | ^ - = note: ...which requires evaluating trait selection obligation `my_foo::{opaque#0}: core::marker::Unpin`... - = note: ...which again requires computing type of opaque `my_foo::{opaque#0}`, completing the cycle -note: cycle used when computing type of `my_foo::{opaque#0}` - --> $DIR/call_method_on_inherent_impl_ref.rs:15:16 - | -LL | fn my_foo() -> impl std::fmt::Debug { - | ^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +error: aborting due to 1 previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0391, E0599. -For more information about an error, try `rustc --explain E0391`. +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr index 327f6ca3450f..7202cb6f90a6 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/call_method_on_inherent_impl_ref.rs:18:13 + --> $DIR/call_method_on_inherent_impl_ref.rs:17:13 | LL | let x = my_foo(); | ^ @@ -13,7 +13,7 @@ LL | let x: /* Type */ = my_foo(); | ++++++++++++ error[E0282]: type annotations needed for `&_` - --> $DIR/call_method_on_inherent_impl_ref.rs:28:13 + --> $DIR/call_method_on_inherent_impl_ref.rs:27:13 | LL | let x = &my_bar(); | ^ diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs index 40ad21532a4e..abe60e5e45a3 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs @@ -13,7 +13,6 @@ where } fn my_foo() -> impl std::fmt::Debug { - //[current]~^ cycle if false { let x = my_foo(); //[next]~^ type annotations needed diff --git a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr index e8cd16bc3016..9b0d0c554f01 100644 --- a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr +++ b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr @@ -2,7 +2,7 @@ error[E0107]: function takes 1 generic argument but 2 generic arguments were sup --> $DIR/explicit-generic-args-for-impl.rs:4:5 | LL | foo::("".to_string()); - | ^^^ ------ help: remove this generic argument + | ^^^ -------- help: remove the unnecessary generic argument | | | expected 1 generic argument | diff --git a/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr b/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr index 1f8a0d5edd78..81570781b27d 100644 --- a/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr +++ b/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr @@ -38,7 +38,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli --> $DIR/opaque-and-lifetime-mismatch.rs:4:17 | LL | fn bar() -> Wrapper; - | ^^^^^^^ ---------- help: remove this generic argument + | ^^^^^^^ ---------- help: remove the unnecessary generic argument | | | expected 0 generic arguments | @@ -52,7 +52,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli --> $DIR/opaque-and-lifetime-mismatch.rs:18:17 | LL | fn foo() -> Wrapper; - | ^^^^^^^ ---------- help: remove this generic argument + | ^^^^^^^ ---------- help: remove the unnecessary generic argument | | | expected 0 generic arguments | @@ -93,7 +93,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli --> $DIR/opaque-and-lifetime-mismatch.rs:24:17 | LL | fn foo() -> Wrapper { - | ^^^^^^^ ---------- help: remove this generic argument + | ^^^^^^^ ---------- help: remove the unnecessary generic argument | | | expected 0 generic arguments | diff --git a/tests/ui/impl-trait/rpit/const_check_false_cycle.rs b/tests/ui/impl-trait/rpit/const_check_false_cycle.rs new file mode 100644 index 000000000000..d4ea0e3b1478 --- /dev/null +++ b/tests/ui/impl-trait/rpit/const_check_false_cycle.rs @@ -0,0 +1,14 @@ +//! This test caused a cycle error when checking whether the +//! return type is `Freeze` during const checking, even though +//! the information is readily available. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ check-pass + +const fn f() -> impl Eq { + g() +} +const fn g() {} + +fn main() {} diff --git a/tests/ui/impl-trait/unsized_coercion3.next.stderr b/tests/ui/impl-trait/unsized_coercion3.next.stderr index bab8d1cd83b3..586ae0760282 100644 --- a/tests/ui/impl-trait/unsized_coercion3.next.stderr +++ b/tests/ui/impl-trait/unsized_coercion3.next.stderr @@ -5,7 +5,7 @@ LL | let x = hello(); | ^^^^^^^ types differ error[E0308]: mismatched types - --> $DIR/unsized_coercion3.rs:19:14 + --> $DIR/unsized_coercion3.rs:18:14 | LL | fn hello() -> Box { | ------------------- the expected opaque type @@ -21,7 +21,7 @@ note: associated function defined here --> $SRC_DIR/alloc/src/boxed.rs:LL:COL error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time - --> $DIR/unsized_coercion3.rs:19:14 + --> $DIR/unsized_coercion3.rs:18:14 | LL | Box::new(1u32) | -------- ^^^^ doesn't have a size known at compile-time diff --git a/tests/ui/impl-trait/unsized_coercion3.old.stderr b/tests/ui/impl-trait/unsized_coercion3.old.stderr index 24a302d7007a..52a72b84a8dd 100644 --- a/tests/ui/impl-trait/unsized_coercion3.old.stderr +++ b/tests/ui/impl-trait/unsized_coercion3.old.stderr @@ -1,17 +1,3 @@ -error: cannot check whether the hidden type of opaque type satisfies auto traits - --> $DIR/unsized_coercion3.rs:15:32 - | -LL | let y: Box = x; - | ^ - | - = note: fetching the hidden types of an opaque inside of the defining scope is not supported. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule -note: opaque type is declared here - --> $DIR/unsized_coercion3.rs:11:19 - | -LL | fn hello() -> Box { - | ^^^^^^^^^^^^^^^^^^^ - = note: required for the cast from `Box` to `Box` - error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time --> $DIR/unsized_coercion3.rs:15:32 | @@ -21,6 +7,6 @@ LL | let y: Box = x; = help: the trait `Sized` is not implemented for `impl Trait + ?Sized` = note: required for the cast from `Box` to `Box` -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/unsized_coercion3.rs b/tests/ui/impl-trait/unsized_coercion3.rs index 85950ac583eb..7e862de2157d 100644 --- a/tests/ui/impl-trait/unsized_coercion3.rs +++ b/tests/ui/impl-trait/unsized_coercion3.rs @@ -14,7 +14,6 @@ fn hello() -> Box { //[next]~^ ERROR: type mismatch resolving `impl Trait + ?Sized <: dyn Send` let y: Box = x; //[old]~^ ERROR: the size for values of type `impl Trait + ?Sized` cannot be know - //[old]~| ERROR: cannot check whether the hidden type of opaque type satisfies auto traits } Box::new(1u32) //[next]~^ ERROR: mismatched types diff --git a/tests/ui/impl-trait/unsized_coercion5.old.stderr b/tests/ui/impl-trait/unsized_coercion5.old.stderr index b6437266f27d..06ad54b1f1d8 100644 --- a/tests/ui/impl-trait/unsized_coercion5.old.stderr +++ b/tests/ui/impl-trait/unsized_coercion5.old.stderr @@ -9,20 +9,6 @@ LL | let y: Box = x as Box; = note: expected struct `Box` found struct `Box` -error: cannot check whether the hidden type of opaque type satisfies auto traits - --> $DIR/unsized_coercion5.rs:16:32 - | -LL | let y: Box = x as Box; - | ^ - | - = note: fetching the hidden types of an opaque inside of the defining scope is not supported. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule -note: opaque type is declared here - --> $DIR/unsized_coercion5.rs:13:19 - | -LL | fn hello() -> Box { - | ^^^^^^^^^^^^^^^^^^^ - = note: required for the cast from `Box` to `Box` - error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time --> $DIR/unsized_coercion5.rs:16:32 | @@ -32,7 +18,7 @@ LL | let y: Box = x as Box; = help: the trait `Sized` is not implemented for `impl Trait + ?Sized` = note: required for the cast from `Box` to `Box` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/unsized_coercion5.rs b/tests/ui/impl-trait/unsized_coercion5.rs index b007267a0066..85d313caa135 100644 --- a/tests/ui/impl-trait/unsized_coercion5.rs +++ b/tests/ui/impl-trait/unsized_coercion5.rs @@ -15,8 +15,7 @@ fn hello() -> Box { let x = hello(); let y: Box = x as Box; //[old]~^ ERROR: the size for values of type `impl Trait + ?Sized` cannot be know - //[old]~| ERROR: cannot check whether the hidden type of opaque type satisfies auto traits - //~^^^ ERROR: mismatched types + //~^^ ERROR: mismatched types } Box::new(1u32) } diff --git a/tests/ui/issues/issue-18423.stderr b/tests/ui/issues/issue-18423.stderr index 2c6015eaa9d4..b5f19b5c9b23 100644 --- a/tests/ui/issues/issue-18423.stderr +++ b/tests/ui/issues/issue-18423.stderr @@ -2,7 +2,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp --> $DIR/issue-18423.rs:4:8 | LL | x: Box<'a, isize> - | ^^^ -- help: remove this lifetime argument + | ^^^ -- help: remove the lifetime argument | | | expected 0 lifetime arguments diff --git a/tests/ui/issues/issue-53251.stderr b/tests/ui/issues/issue-53251.stderr index 05ea63115896..981966354b97 100644 --- a/tests/ui/issues/issue-53251.stderr +++ b/tests/ui/issues/issue-53251.stderr @@ -2,7 +2,7 @@ error[E0107]: associated function takes 0 generic arguments but 1 generic argume --> $DIR/issue-53251.rs:11:20 | LL | S::f::(); - | ^------- help: remove these generics + | ^------- help: remove the unnecessary generics | | | expected 0 generic arguments ... @@ -20,7 +20,7 @@ error[E0107]: associated function takes 0 generic arguments but 1 generic argume --> $DIR/issue-53251.rs:11:20 | LL | S::f::(); - | ^------- help: remove these generics + | ^------- help: remove the unnecessary generics | | | expected 0 generic arguments ... diff --git a/tests/ui/issues/issue-60622.stderr b/tests/ui/issues/issue-60622.stderr index 43da2773940e..298ef3799f24 100644 --- a/tests/ui/issues/issue-60622.stderr +++ b/tests/ui/issues/issue-60622.stderr @@ -20,7 +20,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli --> $DIR/issue-60622.rs:10:7 | LL | b.a::<'_, T>(); - | ^ - help: remove this generic argument + | ^ - help: remove the unnecessary generic argument | | | expected 0 generic arguments | diff --git a/tests/ui/late-bound-lifetimes/mismatched_arg_count.stderr b/tests/ui/late-bound-lifetimes/mismatched_arg_count.stderr index 1b8f1c3fd6fa..1717b6aa1242 100644 --- a/tests/ui/late-bound-lifetimes/mismatched_arg_count.stderr +++ b/tests/ui/late-bound-lifetimes/mismatched_arg_count.stderr @@ -2,7 +2,7 @@ error[E0107]: type alias takes 1 lifetime argument but 2 lifetime arguments were --> $DIR/mismatched_arg_count.rs:9:29 | LL | fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {} - | ^^^^^ -- help: remove this lifetime argument + | ^^^^^ ---- help: remove the lifetime argument | | | expected 1 lifetime argument | diff --git a/tests/ui/layout/size-of-val-raw-too-big.rs b/tests/ui/layout/size-of-val-raw-too-big.rs new file mode 100644 index 000000000000..8d82c78d9539 --- /dev/null +++ b/tests/ui/layout/size-of-val-raw-too-big.rs @@ -0,0 +1,18 @@ +//@ build-fail +//@ compile-flags: --crate-type lib +//@ only-32bit Layout computation rejects this layout for different reasons on 64-bit. +//@ error-pattern: too big for the current architecture +#![feature(core_intrinsics)] +#![allow(internal_features)] + +// isize::MAX is fine, but with the padding for the unsized tail it is too big. +#[repr(C)] +pub struct Example([u8; isize::MAX as usize], [u16]); + +// We guarantee that with length 0, `size_of_val_raw` (which calls the `size_of_val` intrinsic) +// is safe to call. The compiler aborts compilation if a length of 0 would overflow. +// So let's construct a case where length 0 just barely overflows, and ensure that +// does abort compilation. +pub fn check(x: *const Example) -> usize { + unsafe { std::intrinsics::size_of_val(x) } +} diff --git a/tests/ui/layout/size-of-val-raw-too-big.stderr b/tests/ui/layout/size-of-val-raw-too-big.stderr new file mode 100644 index 000000000000..aa9abd644faa --- /dev/null +++ b/tests/ui/layout/size-of-val-raw-too-big.stderr @@ -0,0 +1,4 @@ +error: values of the type `Example` are too big for the current architecture + +error: aborting due to 1 previous error + diff --git a/tests/ui/lifetimes/noisy-follow-up-erro.stderr b/tests/ui/lifetimes/noisy-follow-up-erro.stderr index f549009a87c1..04863badbd1e 100644 --- a/tests/ui/lifetimes/noisy-follow-up-erro.stderr +++ b/tests/ui/lifetimes/noisy-follow-up-erro.stderr @@ -2,7 +2,7 @@ error[E0107]: struct takes 2 lifetime arguments but 3 lifetime arguments were su --> $DIR/noisy-follow-up-erro.rs:12:30 | LL | fn boom(&self, foo: &mut Foo<'_, '_, 'a>) -> Result<(), &'a ()> { - | ^^^ -- help: remove this lifetime argument + | ^^^ ---- help: remove the lifetime argument | | | expected 2 lifetime arguments | diff --git a/tests/ui/lint/expansion-time.stderr b/tests/ui/lint/expansion-time.stderr index 626e51dd00c2..e490ae91a488 100644 --- a/tests/ui/lint/expansion-time.stderr +++ b/tests/ui/lint/expansion-time.stderr @@ -55,6 +55,21 @@ LL | #[warn(incomplete_include)] warning: 4 warnings emitted Future incompatibility report: Future breakage diagnostic: +warning: missing fragment specifier + --> $DIR/expansion-time.rs:9:19 + | +LL | macro_rules! m { ($i) => {} } + | ^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 +note: the lint level is defined here + --> $DIR/expansion-time.rs:8:8 + | +LL | #[warn(missing_fragment_specifier)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: warning: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable --> $DIR/expansion-time.rs:14:7 | diff --git a/tests/ui/macros/issue-39404.stderr b/tests/ui/macros/issue-39404.stderr index 33cafd93a404..176c8e9f073c 100644 --- a/tests/ui/macros/issue-39404.stderr +++ b/tests/ui/macros/issue-39404.stderr @@ -10,3 +10,14 @@ LL | macro_rules! m { ($i) => {} } error: aborting due to 1 previous error +Future incompatibility report: Future breakage diagnostic: +error: missing fragment specifier + --> $DIR/issue-39404.rs:3:19 + | +LL | macro_rules! m { ($i) => {} } + | ^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 + = note: `#[deny(missing_fragment_specifier)]` on by default + diff --git a/tests/ui/macros/macro-match-nonterminal.stderr b/tests/ui/macros/macro-match-nonterminal.stderr index ef7261c02394..831579c4fefd 100644 --- a/tests/ui/macros/macro-match-nonterminal.stderr +++ b/tests/ui/macros/macro-match-nonterminal.stderr @@ -25,3 +25,25 @@ LL | ($a, $b) => { error: aborting due to 3 previous errors +Future incompatibility report: Future breakage diagnostic: +error: missing fragment specifier + --> $DIR/macro-match-nonterminal.rs:2:8 + | +LL | ($a, $b) => { + | ^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 + = note: `#[deny(missing_fragment_specifier)]` on by default + +Future breakage diagnostic: +error: missing fragment specifier + --> $DIR/macro-match-nonterminal.rs:2:10 + | +LL | ($a, $b) => { + | ^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 + = note: `#[deny(missing_fragment_specifier)]` on by default + diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.stderr b/tests/ui/macros/macro-missing-fragment-deduplication.stderr index 3b9e716e194d..c46712f70fd5 100644 --- a/tests/ui/macros/macro-missing-fragment-deduplication.stderr +++ b/tests/ui/macros/macro-missing-fragment-deduplication.stderr @@ -16,3 +16,14 @@ LL | ($name) => {} error: aborting due to 2 previous errors +Future incompatibility report: Future breakage diagnostic: +error: missing fragment specifier + --> $DIR/macro-missing-fragment-deduplication.rs:4:6 + | +LL | ($name) => {} + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 + = note: `#[deny(missing_fragment_specifier)]` on by default + diff --git a/tests/ui/macros/macro-missing-fragment.stderr b/tests/ui/macros/macro-missing-fragment.stderr index 1089f67f4336..abe4d4cd68a2 100644 --- a/tests/ui/macros/macro-missing-fragment.stderr +++ b/tests/ui/macros/macro-missing-fragment.stderr @@ -38,3 +38,48 @@ LL | ( $name ) => {}; error: aborting due to 1 previous error; 3 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: missing fragment specifier + --> $DIR/macro-missing-fragment.rs:4:20 + | +LL | ( $( any_token $field_rust_type )* ) => {}; + | ^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 +note: the lint level is defined here + --> $DIR/macro-missing-fragment.rs:1:9 + | +LL | #![warn(missing_fragment_specifier)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +warning: missing fragment specifier + --> $DIR/macro-missing-fragment.rs:12:7 + | +LL | ( $name ) => {}; + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 +note: the lint level is defined here + --> $DIR/macro-missing-fragment.rs:1:9 + | +LL | #![warn(missing_fragment_specifier)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +warning: missing fragment specifier + --> $DIR/macro-missing-fragment.rs:18:7 + | +LL | ( $name ) => {}; + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 +note: the lint level is defined here + --> $DIR/macro-missing-fragment.rs:1:9 + | +LL | #![warn(missing_fragment_specifier)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/methods/method-call-lifetime-args-fail.stderr b/tests/ui/methods/method-call-lifetime-args-fail.stderr index 645d8b8d14ad..b251dd4d342f 100644 --- a/tests/ui/methods/method-call-lifetime-args-fail.stderr +++ b/tests/ui/methods/method-call-lifetime-args-fail.stderr @@ -20,7 +20,7 @@ error[E0107]: method takes 2 lifetime arguments but 3 lifetime arguments were su --> $DIR/method-call-lifetime-args-fail.rs:18:7 | LL | S.early::<'static, 'static, 'static>(); - | ^^^^^ ------- help: remove this lifetime argument + | ^^^^^ --------- help: remove the lifetime argument | | | expected 2 lifetime arguments | @@ -220,7 +220,7 @@ error[E0107]: method takes 2 lifetime arguments but 3 lifetime arguments were su --> $DIR/method-call-lifetime-args-fail.rs:65:8 | LL | S::early::<'static, 'static, 'static>(S); - | ^^^^^ ------- help: remove this lifetime argument + | ^^^^^ --------- help: remove the lifetime argument | | | expected 2 lifetime arguments | diff --git a/tests/ui/parser/macro/issue-33569.stderr b/tests/ui/parser/macro/issue-33569.stderr index 0dca090fb87c..d1b6abfeeebf 100644 --- a/tests/ui/parser/macro/issue-33569.stderr +++ b/tests/ui/parser/macro/issue-33569.stderr @@ -28,3 +28,14 @@ LL | { $+ } => { error: aborting due to 4 previous errors +Future incompatibility report: Future breakage diagnostic: +error: missing fragment specifier + --> $DIR/issue-33569.rs:2:8 + | +LL | { $+ } => { + | ^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 + = note: `#[deny(missing_fragment_specifier)]` on by default + diff --git a/tests/ui/proc-macro/cfg-eval-inner.stdout b/tests/ui/proc-macro/cfg-eval-inner.stdout index 9fa8f437d0ef..1aac28b2ec2f 100644 --- a/tests/ui/proc-macro/cfg-eval-inner.stdout +++ b/tests/ui/proc-macro/cfg-eval-inner.stdout @@ -73,7 +73,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: $DIR/cfg-eval-inner.rs:19:40: 19:54 (#0), }, ], - span: $DIR/cfg-eval-inner.rs:19:5: 19:6 (#0), + span: $DIR/cfg-eval-inner.rs:19:7: 19:56 (#0), }, Punct { ch: '#', @@ -168,7 +168,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: $DIR/cfg-eval-inner.rs:23:48: 23:70 (#0), }, ], - span: $DIR/cfg-eval-inner.rs:23:13: 23:14 (#0), + span: $DIR/cfg-eval-inner.rs:23:15: 23:72 (#0), }, Literal { kind: Integer, @@ -233,7 +233,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: $DIR/cfg-eval-inner.rs:32:40: 32:56 (#0), }, ], - span: $DIR/cfg-eval-inner.rs:32:5: 32:6 (#0), + span: $DIR/cfg-eval-inner.rs:32:7: 32:58 (#0), }, Ident { ident: "fn", diff --git a/tests/ui/proc-macro/cfg-eval.stdout b/tests/ui/proc-macro/cfg-eval.stdout index e26e16f5a8ce..5d88297ad688 100644 --- a/tests/ui/proc-macro/cfg-eval.stdout +++ b/tests/ui/proc-macro/cfg-eval.stdout @@ -60,7 +60,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: $DIR/cfg-eval.rs:22:36: 22:38 (#0), }, ], - span: $DIR/cfg-eval.rs:22:5: 22:6 (#0), + span: $DIR/cfg-eval.rs:22:6: 22:40 (#0), }, Ident { ident: "field_true", @@ -99,7 +99,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: $DIR/cfg-eval.rs:35:62: 35:73 (#0), }, ], - span: $DIR/cfg-eval.rs:35:39: 35:40 (#0), + span: $DIR/cfg-eval.rs:35:40: 35:75 (#0), }, Group { delimiter: Parenthesis, diff --git a/tests/ui/proc-macro/expand-to-derive.stdout b/tests/ui/proc-macro/expand-to-derive.stdout index d59b7e5b88f4..81fc52ea22d7 100644 --- a/tests/ui/proc-macro/expand-to-derive.stdout +++ b/tests/ui/proc-macro/expand-to-derive.stdout @@ -57,7 +57,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ span: $DIR/expand-to-derive.rs:27:28: 27:39 (#0), }, ], - span: $DIR/expand-to-derive.rs:27:5: 27:6 (#0), + span: $DIR/expand-to-derive.rs:27:6: 27:41 (#0), }, Ident { ident: "struct", diff --git a/tests/ui/proc-macro/inner-attrs.stdout b/tests/ui/proc-macro/inner-attrs.stdout index c8d93babe3a4..ed47ee2cf5ac 100644 --- a/tests/ui/proc-macro/inner-attrs.stdout +++ b/tests/ui/proc-macro/inner-attrs.stdout @@ -674,7 +674,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ span: $DIR/inner-attrs.rs:41:52: 41:59 (#0), }, ], - span: $DIR/inner-attrs.rs:41:17: 41:18 (#0), + span: $DIR/inner-attrs.rs:41:19: 41:61 (#0), }, Ident { ident: "true", diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout index cc712abf2a57..4dcf2b717d8a 100644 --- a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout +++ b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout @@ -119,7 +119,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: $DIR/issue-75930-derive-cfg.rs:50:29: 50:40 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:50:1: 50:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:50:2: 50:42 (#0), }, Punct { ch: '#', @@ -1395,7 +1395,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ span: $DIR/issue-75930-derive-cfg.rs:50:29: 50:40 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:50:1: 50:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:50:2: 50:42 (#0), }, Punct { ch: '#', @@ -1571,7 +1571,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ span: $DIR/issue-75930-derive-cfg.rs:63:41: 63:51 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:63:13: 63:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:14: 63:53 (#0), }, Ident { ident: "false", diff --git a/tests/ui/proc-macro/macro-rules-derive-cfg.stdout b/tests/ui/proc-macro/macro-rules-derive-cfg.stdout index 257d59974b88..fadf210127e4 100644 --- a/tests/ui/proc-macro/macro-rules-derive-cfg.stdout +++ b/tests/ui/proc-macro/macro-rules-derive-cfg.stdout @@ -88,7 +88,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ span: $DIR/macro-rules-derive-cfg.rs:19:59: 19:66 (#3), }, ], - span: $DIR/macro-rules-derive-cfg.rs:19:25: 19:26 (#3), + span: $DIR/macro-rules-derive-cfg.rs:19:26: 19:68 (#3), }, Punct { ch: '#', @@ -113,7 +113,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ span: $DIR/macro-rules-derive-cfg.rs:26:47: 26:55 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:26:13: 26:14 (#0), + span: $DIR/macro-rules-derive-cfg.rs:26:14: 26:57 (#0), }, Group { delimiter: Brace, @@ -146,7 +146,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ span: $DIR/macro-rules-derive-cfg.rs:27:34: 27:42 (#0), }, ], - span: $DIR/macro-rules-derive-cfg.rs:27:5: 27:6 (#0), + span: $DIR/macro-rules-derive-cfg.rs:27:7: 27:44 (#0), }, Literal { kind: Integer, diff --git a/tests/ui/resolve/issue-3214.stderr b/tests/ui/resolve/issue-3214.stderr index 5b57c1baf90b..1c64fdc1711f 100644 --- a/tests/ui/resolve/issue-3214.stderr +++ b/tests/ui/resolve/issue-3214.stderr @@ -12,7 +12,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli --> $DIR/issue-3214.rs:6:22 | LL | impl Drop for Foo { - | ^^^--- help: remove these generics + | ^^^--- help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr index fa2e3da368bd..8c591edac540 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr @@ -2,7 +2,7 @@ error[E0107]: function takes 0 generic arguments but 1 generic argument was supp --> $DIR/no-explicit-const-params-cross-crate.rs:14:5 | LL | foo::(); - | ^^^--------- help: remove these generics + | ^^^--------- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -32,7 +32,7 @@ error[E0107]: function takes 0 generic arguments but 1 generic argument was supp --> $DIR/no-explicit-const-params-cross-crate.rs:7:5 | LL | foo::(); - | ^^^-------- help: remove these generics + | ^^^-------- help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr index fbb96dfd85e1..cc08114ddb56 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr @@ -16,7 +16,7 @@ error[E0107]: function takes 0 generic arguments but 1 generic argument was supp --> $DIR/no-explicit-const-params.rs:22:5 | LL | foo::(); - | ^^^--------- help: remove these generics + | ^^^--------- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -55,7 +55,7 @@ error[E0107]: function takes 0 generic arguments but 1 generic argument was supp --> $DIR/no-explicit-const-params.rs:15:5 | LL | foo::(); - | ^^^-------- help: remove these generics + | ^^^-------- help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs index ab46d49073c7..9cd18d4566da 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs @@ -9,7 +9,6 @@ impl MyTrait for i32 { //~| ERROR functions in trait impls cannot be declared const //~| ERROR functions cannot be both `const` and `async` //~| ERROR method `bar` is not a member - //~| ERROR cycle detected when computing type main8().await; //~^ ERROR cannot find function } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr index 1f309e1e8544..90771c344b51 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr @@ -61,7 +61,7 @@ error: using `#![feature(effects)]` without enabling next trait solver globally = help: use `-Znext-solver` to enable error[E0425]: cannot find function `main8` in this scope - --> $DIR/ice-120503-async-const-method.rs:13:9 + --> $DIR/ice-120503-async-const-method.rs:12:9 | LL | main8().await; | ^^^^^ help: a function with a similar name exists: `main` @@ -69,38 +69,7 @@ LL | main8().await; LL | fn main() {} | --------- similarly named function `main` defined here -error[E0391]: cycle detected when computing type of opaque `::bar::{opaque#0}` - --> $DIR/ice-120503-async-const-method.rs:7:5 - | -LL | async const fn bar(&self) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires borrow-checking `::bar`... - --> $DIR/ice-120503-async-const-method.rs:7:5 - | -LL | async const fn bar(&self) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires promoting constants in MIR for `::bar`... - --> $DIR/ice-120503-async-const-method.rs:7:5 - | -LL | async const fn bar(&self) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const checking `::bar`... - --> $DIR/ice-120503-async-const-method.rs:7:5 - | -LL | async const fn bar(&self) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing whether `::bar::{opaque#0}` is freeze... - = note: ...which requires evaluating trait selection obligation `::bar::{opaque#0}: core::marker::Freeze`... - = note: ...which again requires computing type of opaque `::bar::{opaque#0}`, completing the cycle -note: cycle used when computing type of `::bar::{opaque#0}` - --> $DIR/ice-120503-async-const-method.rs:7:5 - | -LL | async const fn bar(&self) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +error: aborting due to 6 previous errors; 1 warning emitted -error: aborting due to 7 previous errors; 1 warning emitted - -Some errors have detailed explanations: E0379, E0391, E0407, E0425. +Some errors have detailed explanations: E0379, E0407, E0425. For more information about an error, try `rustc --explain E0379`. diff --git a/tests/ui/seq-args.stderr b/tests/ui/seq-args.stderr index a5b0f8e98dca..6e0d484d013d 100644 --- a/tests/ui/seq-args.stderr +++ b/tests/ui/seq-args.stderr @@ -2,7 +2,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/seq-args.rs:4:13 | LL | impl Seq for Vec { - | ^^^--- help: remove these generics + | ^^^--- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -16,7 +16,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/seq-args.rs:9:10 | LL | impl Seq for u32 { - | ^^^------ help: remove these generics + | ^^^------ help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/structs/struct-path-associated-type.stderr b/tests/ui/structs/struct-path-associated-type.stderr index 0c9d2aad5d82..de396e875b0c 100644 --- a/tests/ui/structs/struct-path-associated-type.stderr +++ b/tests/ui/structs/struct-path-associated-type.stderr @@ -8,7 +8,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w --> $DIR/struct-path-associated-type.rs:14:16 | LL | let z = T::A:: {}; - | ^------ help: remove these generics + | ^------ help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -34,7 +34,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w --> $DIR/struct-path-associated-type.rs:25:16 | LL | let z = T::A:: {}; - | ^------ help: remove these generics + | ^------ help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/structs/structure-constructor-type-mismatch.stderr b/tests/ui/structs/structure-constructor-type-mismatch.stderr index cb9574873473..819b65ffb716 100644 --- a/tests/ui/structs/structure-constructor-type-mismatch.stderr +++ b/tests/ui/structs/structure-constructor-type-mismatch.stderr @@ -68,7 +68,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su --> $DIR/structure-constructor-type-mismatch.rs:48:15 | LL | let pt3 = PointF:: { - | ^^^^^^------- help: remove these generics + | ^^^^^^------- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -104,7 +104,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su --> $DIR/structure-constructor-type-mismatch.rs:54:9 | LL | PointF:: { .. } => {} - | ^^^^^^------- help: remove these generics + | ^^^^^^------- help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/suggestions/issue-101421.stderr b/tests/ui/suggestions/issue-101421.stderr index ececba5fb1ba..12b4c04c2a33 100644 --- a/tests/ui/suggestions/issue-101421.stderr +++ b/tests/ui/suggestions/issue-101421.stderr @@ -2,7 +2,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli --> $DIR/issue-101421.rs:10:8 | LL | ().f::<()>(()); - | ^------ help: remove these generics + | ^------ help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/suggestions/issue-104287.stderr b/tests/ui/suggestions/issue-104287.stderr index ed59b2e7a2d3..d728e6c3d8c1 100644 --- a/tests/ui/suggestions/issue-104287.stderr +++ b/tests/ui/suggestions/issue-104287.stderr @@ -2,7 +2,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli --> $DIR/issue-104287.rs:10:5 | LL | foo::<()>(x); - | ^^^------ help: remove these generics + | ^^^------ help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/suggestions/issue-104961.fixed b/tests/ui/suggestions/issue-104961.fixed index 5def21b506e1..3019242880f8 100644 --- a/tests/ui/suggestions/issue-104961.fixed +++ b/tests/ui/suggestions/issue-104961.fixed @@ -2,12 +2,12 @@ fn foo(x: &str) -> bool { x.starts_with(&("hi".to_string() + " you")) - //~^ ERROR the trait bound `String: Pattern<'_>` is not satisfied [E0277] + //~^ ERROR the trait bound `String: Pattern` is not satisfied [E0277] } fn foo2(x: &str) -> bool { x.starts_with(&"hi".to_string()) - //~^ ERROR the trait bound `String: Pattern<'_>` is not satisfied [E0277] + //~^ ERROR the trait bound `String: Pattern` is not satisfied [E0277] } fn main() { diff --git a/tests/ui/suggestions/issue-104961.rs b/tests/ui/suggestions/issue-104961.rs index a09b8a887114..b315e9bab0d1 100644 --- a/tests/ui/suggestions/issue-104961.rs +++ b/tests/ui/suggestions/issue-104961.rs @@ -2,12 +2,12 @@ fn foo(x: &str) -> bool { x.starts_with("hi".to_string() + " you") - //~^ ERROR the trait bound `String: Pattern<'_>` is not satisfied [E0277] + //~^ ERROR the trait bound `String: Pattern` is not satisfied [E0277] } fn foo2(x: &str) -> bool { x.starts_with("hi".to_string()) - //~^ ERROR the trait bound `String: Pattern<'_>` is not satisfied [E0277] + //~^ ERROR the trait bound `String: Pattern` is not satisfied [E0277] } fn main() { diff --git a/tests/ui/suggestions/issue-104961.stderr b/tests/ui/suggestions/issue-104961.stderr index 3c5f86817f3a..0d229e6dada5 100644 --- a/tests/ui/suggestions/issue-104961.stderr +++ b/tests/ui/suggestions/issue-104961.stderr @@ -1,12 +1,12 @@ -error[E0277]: the trait bound `String: Pattern<'_>` is not satisfied +error[E0277]: the trait bound `String: Pattern` is not satisfied --> $DIR/issue-104961.rs:4:19 | LL | x.starts_with("hi".to_string() + " you") - | ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Pattern<'_>` is not implemented for `String` + | ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Pattern` is not implemented for `String` | | | required by a bound introduced by this call | - = note: required for `String` to implement `Pattern<'_>` + = note: required for `String` to implement `Pattern` note: required by a bound in `core::str::::starts_with` --> $SRC_DIR/core/src/str/mod.rs:LL:COL help: consider borrowing here @@ -14,15 +14,15 @@ help: consider borrowing here LL | x.starts_with(&("hi".to_string() + " you")) | ++ + -error[E0277]: the trait bound `String: Pattern<'_>` is not satisfied +error[E0277]: the trait bound `String: Pattern` is not satisfied --> $DIR/issue-104961.rs:9:19 | LL | x.starts_with("hi".to_string()) - | ----------- ^^^^^^^^^^^^^^^^ the trait `Pattern<'_>` is not implemented for `String` + | ----------- ^^^^^^^^^^^^^^^^ the trait `Pattern` is not implemented for `String` | | | required by a bound introduced by this call | - = note: required for `String` to implement `Pattern<'_>` + = note: required for `String` to implement `Pattern` note: required by a bound in `core::str::::starts_with` --> $SRC_DIR/core/src/str/mod.rs:LL:COL help: consider borrowing here diff --git a/tests/ui/suggestions/issue-62843.stderr b/tests/ui/suggestions/issue-62843.stderr index 84ab4a0edd39..c3c0360b3a9d 100644 --- a/tests/ui/suggestions/issue-62843.stderr +++ b/tests/ui/suggestions/issue-62843.stderr @@ -1,12 +1,12 @@ -error[E0277]: the trait bound `String: Pattern<'_>` is not satisfied +error[E0277]: the trait bound `String: Pattern` is not satisfied --> $DIR/issue-62843.rs:4:32 | LL | println!("{:?}", line.find(pattern)); - | ---- ^^^^^^^ the trait `Pattern<'_>` is not implemented for `String` + | ---- ^^^^^^^ the trait `Pattern` is not implemented for `String` | | | required by a bound introduced by this call | - = note: required for `String` to implement `Pattern<'_>` + = note: required for `String` to implement `Pattern` note: required by a bound in `core::str::::find` --> $SRC_DIR/core/src/str/mod.rs:LL:COL help: consider borrowing here diff --git a/tests/ui/suggestions/issue-89064.rs b/tests/ui/suggestions/issue-89064.rs index fa5fc899dc08..014d15a87f17 100644 --- a/tests/ui/suggestions/issue-89064.rs +++ b/tests/ui/suggestions/issue-89064.rs @@ -16,20 +16,20 @@ impl B for S {} fn main() { let _ = A::foo::(); //~^ ERROR - //~| HELP remove these generics + //~| HELP remove the unnecessary generics //~| HELP consider moving this generic argument let _ = B::bar::(); //~^ ERROR - //~| HELP remove these generics + //~| HELP remove the unnecessary generics //~| HELP consider moving these generic arguments let _ = A::::foo::(); //~^ ERROR - //~| HELP remove these generics + //~| HELP remove the unnecessary generics let _ = 42.into::>(); //~^ ERROR - //~| HELP remove these generics + //~| HELP remove the unnecessary generics //~| HELP consider moving this generic argument } diff --git a/tests/ui/suggestions/issue-89064.stderr b/tests/ui/suggestions/issue-89064.stderr index be09dd895120..837fef60d1e6 100644 --- a/tests/ui/suggestions/issue-89064.stderr +++ b/tests/ui/suggestions/issue-89064.stderr @@ -14,7 +14,7 @@ help: consider moving this generic argument to the `A` trait, which takes up to LL - let _ = A::foo::(); LL + let _ = A::::foo(); | -help: remove these generics +help: remove the unnecessary generics | LL - let _ = A::foo::(); LL + let _ = A::foo(); @@ -36,7 +36,7 @@ help: consider moving these generic arguments to the `B` trait, which takes up t LL - let _ = B::bar::(); LL + let _ = B::::bar(); | -help: remove these generics +help: remove the unnecessary generics | LL - let _ = B::bar::(); LL + let _ = B::bar(); @@ -46,7 +46,7 @@ error[E0107]: associated function takes 0 generic arguments but 1 generic argume --> $DIR/issue-89064.rs:27:21 | LL | let _ = A::::foo::(); - | ^^^----- help: remove these generics + | ^^^----- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -66,7 +66,7 @@ help: consider moving this generic argument to the `Into` trait, which takes up | LL | let _ = Into::>::into(42); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: remove these generics +help: remove the unnecessary generics | LL - let _ = 42.into::>(); LL + let _ = 42.into(); diff --git a/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.rs b/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.rs index 4066cd3b11a3..a719ddc4b16a 100644 --- a/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.rs +++ b/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.rs @@ -14,5 +14,5 @@ fn main() { 1.bar::(0); //~^ ERROR method takes 0 generic arguments but 1 generic argument was supplied //~| HELP consider moving this generic argument to the `Foo` trait, which takes up to 1 argument - //~| HELP remove these generics + //~| HELP remove the unnecessary generics } diff --git a/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr b/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr index aa11bc7cf1d9..cc735ef4c5ea 100644 --- a/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr +++ b/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr @@ -13,7 +13,7 @@ help: consider moving this generic argument to the `Foo` trait, which takes up t | LL | Foo::::bar(1, 0); | ~~~~~~~~~~~~~~~~~~~~~ -help: remove these generics +help: remove the unnecessary generics | LL - 1.bar::(0); LL + 1.bar(0); diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs new file mode 100644 index 000000000000..e6d7f74880fb --- /dev/null +++ b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs @@ -0,0 +1,39 @@ +// Regression test for #127441 + +// Tests that we make the correct suggestion +// in case there are more than one `?Sized` +// bounds on a function parameter + +use std::fmt::Debug; + +fn foo1(a: T) {} +//~^ ERROR he size for values of type `T` cannot be known at compilation time + +fn foo2(a: T) {} +//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~| ERROR the size for values of type `T` cannot be known at compilation time + +fn foo3(a: T) {} +//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~| ERROR he size for values of type `T` cannot be known at compilation time + +fn foo4(a: T) {} +//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~| ERROR the size for values of type `T` cannot be known at compilation time + +fn foo5(_: impl ?Sized) {} +//~^ ERROR the size for values of type `impl ?Sized` cannot be known at compilation time + +fn foo6(_: impl ?Sized + ?Sized) {} +//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~| ERROR the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation tim + +fn foo7(_: impl ?Sized + ?Sized + Debug) {} +//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~| ERROR the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time + +fn foo8(_: impl ?Sized + Debug + ?Sized ) {} +//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~| ERROR the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time + +fn main() {} diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr new file mode 100644 index 000000000000..3e8f45ee9fc2 --- /dev/null +++ b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr @@ -0,0 +1,192 @@ +error[E0203]: type parameter has more than one relaxed default bound, only one is supported + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:12 + | +LL | fn foo2(a: T) {} + | ^^^^^^ ^^^^^^ + +error[E0203]: type parameter has more than one relaxed default bound, only one is supported + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:12 + | +LL | fn foo3(a: T) {} + | ^^^^^^ ^^^^^^ + +error[E0203]: type parameter has more than one relaxed default bound, only one is supported + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:12 + | +LL | fn foo4(a: T) {} + | ^^^^^^ ^^^^^^ + +error[E0203]: type parameter has more than one relaxed default bound, only one is supported + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:17 + | +LL | fn foo6(_: impl ?Sized + ?Sized) {} + | ^^^^^^ ^^^^^^ + +error[E0203]: type parameter has more than one relaxed default bound, only one is supported + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:17 + | +LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {} + | ^^^^^^ ^^^^^^ + +error[E0203]: type parameter has more than one relaxed default bound, only one is supported + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:17 + | +LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {} + | ^^^^^^ ^^^^^^ + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:9:20 + | +LL | fn foo1(a: T) {} + | - ^ doesn't have a size known at compile-time + | | + | this type parameter needs to be `Sized` + | + = help: unsized fn params are gated as an unstable feature +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn foo1(a: T) {} +LL + fn foo1(a: T) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo1(a: &T) {} + | + + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:29 + | +LL | fn foo2(a: T) {} + | - ^ doesn't have a size known at compile-time + | | + | this type parameter needs to be `Sized` + | + = help: unsized fn params are gated as an unstable feature +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn foo2(a: T) {} +LL + fn foo2(a: T) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo2(a: &T) {} + | + + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:37 + | +LL | fn foo3(a: T) {} + | - ^ doesn't have a size known at compile-time + | | + | this type parameter needs to be `Sized` + | + = help: unsized fn params are gated as an unstable feature +help: consider restricting type parameters + | +LL - fn foo3(a: T) {} +LL + fn foo3(a: T) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo3(a: &T) {} + | + + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:38 + | +LL | fn foo4(a: T) {} + | - ^ doesn't have a size known at compile-time + | | + | this type parameter needs to be `Sized` + | + = help: unsized fn params are gated as an unstable feature +help: consider restricting type parameters + | +LL - fn foo4(a: T) {} +LL + fn foo4(a: T) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo4(a: &T) {} + | + + +error[E0277]: the size for values of type `impl ?Sized` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:24:9 + | +LL | fn foo5(_: impl ?Sized) {} + | ^ ----------- this type parameter needs to be `Sized` + | | + | doesn't have a size known at compile-time + | + = help: unsized fn params are gated as an unstable feature +help: consider replacing `?Sized` with `Sized` + | +LL - fn foo5(_: impl ?Sized) {} +LL + fn foo5(_: impl Sized) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo5(_: &impl ?Sized) {} + | + + +error[E0277]: the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:9 + | +LL | fn foo6(_: impl ?Sized + ?Sized) {} + | ^ -------------------- this type parameter needs to be `Sized` + | | + | doesn't have a size known at compile-time + | + = help: unsized fn params are gated as an unstable feature +help: consider restricting type parameters + | +LL - fn foo6(_: impl ?Sized + ?Sized) {} +LL + fn foo6(_: impl Sized) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo6(_: &impl ?Sized + ?Sized) {} + | + + +error[E0277]: the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:9 + | +LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {} + | ^ ---------------------------- this type parameter needs to be `Sized` + | | + | doesn't have a size known at compile-time + | + = help: unsized fn params are gated as an unstable feature +help: consider restricting type parameters + | +LL - fn foo7(_: impl ?Sized + ?Sized + Debug) {} +LL + fn foo7(_: impl Debug) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo7(_: &impl ?Sized + ?Sized + Debug) {} + | + + +error[E0277]: the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:9 + | +LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {} + | ^ ---------------------------- this type parameter needs to be `Sized` + | | + | doesn't have a size known at compile-time + | + = help: unsized fn params are gated as an unstable feature +help: consider restricting type parameters + | +LL - fn foo8(_: impl ?Sized + Debug + ?Sized ) {} +LL + fn foo8(_: impl Debug ) {} + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo8(_: &impl ?Sized + Debug + ?Sized ) {} + | + + +error: aborting due to 14 previous errors + +Some errors have detailed explanations: E0203, E0277. +For more information about an error, try `rustc --explain E0203`. diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr index 06e2fa5d4d1f..a22d88b7c59f 100644 --- a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr +++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr @@ -117,7 +117,7 @@ error[E0107]: struct takes 1 generic argument but 2 generic arguments were suppl --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:40:58 | LL | impl, U> YetAnotherTrait for Struct {} - | ^^^^^^ - help: remove this generic argument + | ^^^^^^ --- help: remove the unnecessary generic argument | | | expected 1 generic argument | diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs index 98825bd536e0..dc2de5bb715b 100644 --- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs +++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs @@ -1,11 +1,11 @@ fn strip_lf(s: &str) -> &str { s.strip_suffix(b'\n').unwrap_or(s) - //~^ ERROR expected a `FnMut(char)` closure, found `u8` - //~| NOTE expected an `FnMut(char)` closure, found `u8` - //~| HELP the trait `FnMut(char)` is not implemented for `u8` - //~| HELP the following other types implement trait `Pattern<'a>`: - //~| NOTE required for `u8` to implement `Pattern<'_>` - + //~^ ERROR the trait bound `u8: Pattern` is not satisfied + //~| NOTE required by a bound introduced by this call + //~| NOTE the trait `FnMut(char)` is not implemented for `u8`, which is required by `u8: Pattern` + //~| HELP the following other types implement trait `Pattern`: + //~| NOTE required for `u8` to implement `Pattern` + //~| NOTE required by a bound in `core::str::::strip_suffix` } fn main() {} diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr index 49272e7d357b..8351d15fdf3b 100644 --- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr +++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr @@ -1,11 +1,12 @@ -error[E0277]: expected a `FnMut(char)` closure, found `u8` - --> $DIR/assoc-fn-bound-root-obligation.rs:2:7 +error[E0277]: the trait bound `u8: Pattern` is not satisfied + --> $DIR/assoc-fn-bound-root-obligation.rs:2:20 | LL | s.strip_suffix(b'\n').unwrap_or(s) - | ^^^^^^^^^^^^ expected an `FnMut(char)` closure, found `u8` + | ------------ ^^^^^ the trait `FnMut(char)` is not implemented for `u8`, which is required by `u8: Pattern` + | | + | required by a bound introduced by this call | - = help: the trait `FnMut(char)` is not implemented for `u8`, which is required by `u8: Pattern<'_>` - = help: the following other types implement trait `Pattern<'a>`: + = help: the following other types implement trait `Pattern`: &'b String &'b [char; N] &'b [char] @@ -13,7 +14,9 @@ LL | s.strip_suffix(b'\n').unwrap_or(s) &'c &'b str [char; N] char - = note: required for `u8` to implement `Pattern<'_>` + = note: required for `u8` to implement `Pattern` +note: required by a bound in `core::str::::strip_suffix` + --> $SRC_DIR/core/src/str/mod.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/traits/object/vs-lifetime.stderr b/tests/ui/traits/object/vs-lifetime.stderr index a69cd140807f..916197ff0965 100644 --- a/tests/ui/traits/object/vs-lifetime.stderr +++ b/tests/ui/traits/object/vs-lifetime.stderr @@ -8,7 +8,7 @@ error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were sup --> $DIR/vs-lifetime.rs:11:12 | LL | let _: S<'static, 'static>; - | ^ ------- help: remove this lifetime argument + | ^ --------- help: remove the lifetime argument | | | expected 1 lifetime argument | diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.fixed b/tests/ui/traits/suggest-dereferences/root-obligation.fixed index 072296c6b154..ad0f184dc9a4 100644 --- a/tests/ui/traits/suggest-dereferences/root-obligation.fixed +++ b/tests/ui/traits/suggest-dereferences/root-obligation.fixed @@ -4,7 +4,7 @@ fn get_vowel_count(string: &str) -> usize { string .chars() .filter(|c| "aeiou".contains(*c)) - //~^ ERROR the trait bound `&char: Pattern<'_>` is not satisfied + //~^ ERROR the trait bound `&char: Pattern` is not satisfied .count() } diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.rs b/tests/ui/traits/suggest-dereferences/root-obligation.rs index e7025fe08254..a31a9955d313 100644 --- a/tests/ui/traits/suggest-dereferences/root-obligation.rs +++ b/tests/ui/traits/suggest-dereferences/root-obligation.rs @@ -4,7 +4,7 @@ fn get_vowel_count(string: &str) -> usize { string .chars() .filter(|c| "aeiou".contains(c)) - //~^ ERROR the trait bound `&char: Pattern<'_>` is not satisfied + //~^ ERROR the trait bound `&char: Pattern` is not satisfied .count() } diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.stderr b/tests/ui/traits/suggest-dereferences/root-obligation.stderr index bbfbb98fba77..2f5e1c5b5377 100644 --- a/tests/ui/traits/suggest-dereferences/root-obligation.stderr +++ b/tests/ui/traits/suggest-dereferences/root-obligation.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `&char: Pattern<'_>` is not satisfied +error[E0277]: the trait bound `&char: Pattern` is not satisfied --> $DIR/root-obligation.rs:6:38 | LL | .filter(|c| "aeiou".contains(c)) - | -------- ^ the trait `Fn(char)` is not implemented for `char`, which is required by `&char: Pattern<'_>` + | -------- ^ the trait `Fn(char)` is not implemented for `char`, which is required by `&char: Pattern` | | | required by a bound introduced by this call | = note: required for `&char` to implement `FnOnce(char)` - = note: required for `&char` to implement `Pattern<'_>` + = note: required for `&char` to implement `Pattern` note: required by a bound in `core::str::::contains` --> $SRC_DIR/core/src/str/mod.rs:LL:COL help: consider dereferencing here diff --git a/tests/ui/traits/test-2.stderr b/tests/ui/traits/test-2.stderr index 3972e539776c..0ee64cc09522 100644 --- a/tests/ui/traits/test-2.stderr +++ b/tests/ui/traits/test-2.stderr @@ -2,7 +2,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli --> $DIR/test-2.rs:9:8 | LL | 10.dup::(); - | ^^^------- help: remove these generics + | ^^^------- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -16,7 +16,7 @@ error[E0107]: method takes 1 generic argument but 2 generic arguments were suppl --> $DIR/test-2.rs:11:8 | LL | 10.blah::(); - | ^^^^ --- help: remove this generic argument + | ^^^^ ----- help: remove the unnecessary generic argument | | | expected 1 generic argument | diff --git a/tests/ui/transmutability/issue-101739-2.stderr b/tests/ui/transmutability/issue-101739-2.stderr index 519a374dc229..6b0a36a414bf 100644 --- a/tests/ui/transmutability/issue-101739-2.stderr +++ b/tests/ui/transmutability/issue-101739-2.stderr @@ -3,11 +3,13 @@ error[E0107]: trait takes at most 2 generic arguments but 5 generic arguments we | LL | Dst: BikeshedIntrinsicFrom< | ^^^^^^^^^^^^^^^^^^^^^ expected at most 2 generic arguments -... -LL | / ASSUME_LIFETIMES, +LL | Src, +LL | ASSUME_ALIGNMENT, + | _____________________________- +LL | | ASSUME_LIFETIMES, LL | | ASSUME_VALIDITY, LL | | ASSUME_VISIBILITY, - | |_____________________________- help: remove these generic arguments + | |_____________________________- help: remove the unnecessary generic arguments error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr b/tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr index 96a5c1327633..482a314db602 100644 --- a/tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr +++ b/tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr @@ -308,7 +308,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su --> $DIR/enum-variant-generic-args.rs:64:5 | LL | AliasFixed::<()>::TSVariant(()); - | ^^^^^^^^^^------ help: remove these generics + | ^^^^^^^^^^------ help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -322,7 +322,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su --> $DIR/enum-variant-generic-args.rs:66:5 | LL | AliasFixed::<()>::TSVariant::<()>(()); - | ^^^^^^^^^^------ help: remove these generics + | ^^^^^^^^^^------ help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -399,7 +399,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su --> $DIR/enum-variant-generic-args.rs:82:5 | LL | AliasFixed::<()>::SVariant { v: () }; - | ^^^^^^^^^^------ help: remove these generics + | ^^^^^^^^^^------ help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -413,7 +413,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su --> $DIR/enum-variant-generic-args.rs:84:5 | LL | AliasFixed::<()>::SVariant::<()> { v: () }; - | ^^^^^^^^^^------ help: remove these generics + | ^^^^^^^^^^------ help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -474,7 +474,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su --> $DIR/enum-variant-generic-args.rs:100:5 | LL | AliasFixed::<()>::UVariant; - | ^^^^^^^^^^------ help: remove these generics + | ^^^^^^^^^^------ help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -488,7 +488,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su --> $DIR/enum-variant-generic-args.rs:102:5 | LL | AliasFixed::<()>::UVariant::<()>; - | ^^^^^^^^^^------ help: remove these generics + | ^^^^^^^^^^------ help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.rs b/tests/ui/type-alias-impl-trait/in-where-clause.rs index 7c0de39c7c91..a089fdc90753 100644 --- a/tests/ui/type-alias-impl-trait/in-where-clause.rs +++ b/tests/ui/type-alias-impl-trait/in-where-clause.rs @@ -4,13 +4,13 @@ #![feature(type_alias_impl_trait)] type Bar = impl Sized; //~^ ERROR: cycle -//~| ERROR: cycle fn foo() -> Bar where Bar: Send, { [0; 1 + 2] + //~^ ERROR: type annotations needed: cannot satisfy `Bar: Send` } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.stderr b/tests/ui/type-alias-impl-trait/in-where-clause.stderr index 9c08b8f127d2..f1361b47c56e 100644 --- a/tests/ui/type-alias-impl-trait/in-where-clause.stderr +++ b/tests/ui/type-alias-impl-trait/in-where-clause.stderr @@ -10,7 +10,7 @@ note: ...which requires computing type of opaque `Bar::{opaque#0}`... LL | type Bar = impl Sized; | ^^^^^^^^^^ note: ...which requires type-checking `foo`... - --> $DIR/in-where-clause.rs:9:1 + --> $DIR/in-where-clause.rs:8:1 | LL | / fn foo() -> Bar LL | | where @@ -25,26 +25,23 @@ LL | type Bar = impl Sized; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of opaque `Bar::{opaque#0}` - --> $DIR/in-where-clause.rs:5:12 - | -LL | type Bar = impl Sized; - | ^^^^^^^^^^ - | -note: ...which requires type-checking `foo`... - --> $DIR/in-where-clause.rs:13:9 +error[E0283]: type annotations needed: cannot satisfy `Bar: Send` + --> $DIR/in-where-clause.rs:12:9 | LL | [0; 1 + 2] | ^^^^^ - = note: ...which requires evaluating trait selection obligation `Bar: core::marker::Send`... - = note: ...which again requires computing type of opaque `Bar::{opaque#0}`, completing the cycle -note: cycle used when computing type of `Bar::{opaque#0}` - --> $DIR/in-where-clause.rs:5:12 | -LL | type Bar = impl Sized; - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + = note: cannot satisfy `Bar: Send` +note: required by a bound in `foo` + --> $DIR/in-where-clause.rs:10:10 + | +LL | fn foo() -> Bar + | --- required by a bound in this function +LL | where +LL | Bar: Send, + | ^^^^ required by this bound in `foo` error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0391`. +Some errors have detailed explanations: E0283, E0391. +For more information about an error, try `rustc --explain E0283`. diff --git a/tests/ui/type-alias-impl-trait/reveal_local.rs b/tests/ui/type-alias-impl-trait/reveal_local.rs index 07fd989b0fa7..34f3788e2341 100644 --- a/tests/ui/type-alias-impl-trait/reveal_local.rs +++ b/tests/ui/type-alias-impl-trait/reveal_local.rs @@ -20,7 +20,7 @@ fn not_gooder() -> Foo { // while we could know this from the hidden type, it would // need extra roundabout logic to support it. is_send::(); - //~^ ERROR: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits + //~^ ERROR: type annotations needed: cannot satisfy `Foo: Send` x } diff --git a/tests/ui/type-alias-impl-trait/reveal_local.stderr b/tests/ui/type-alias-impl-trait/reveal_local.stderr index e1b320cc38e3..9829c58cf73b 100644 --- a/tests/ui/type-alias-impl-trait/reveal_local.stderr +++ b/tests/ui/type-alias-impl-trait/reveal_local.stderr @@ -16,18 +16,13 @@ note: required by a bound in `is_send` LL | fn is_send() {} | ^^^^ required by this bound in `is_send` -error: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits +error[E0283]: type annotations needed: cannot satisfy `Foo: Send` --> $DIR/reveal_local.rs:22:15 | LL | is_send::(); | ^^^ | - = note: fetching the hidden types of an opaque inside of the defining scope is not supported. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule -note: opaque type is declared here - --> $DIR/reveal_local.rs:5:12 - | -LL | type Foo = impl Debug; - | ^^^^^^^^^^ + = note: cannot satisfy `Foo: Send` note: required by a bound in `is_send` --> $DIR/reveal_local.rs:7:15 | @@ -36,3 +31,4 @@ LL | fn is_send() {} error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr b/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr index 9a9b2a68dbed..4235a14cdc00 100644 --- a/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr +++ b/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr @@ -2,7 +2,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/typeck-builtin-bound-type-parameters.rs:1:11 | LL | fn foo1, U>(x: T) {} - | ^^^^--- help: remove these generics + | ^^^^--- help: remove the unnecessary generics | | | expected 0 generic arguments @@ -10,7 +10,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/typeck-builtin-bound-type-parameters.rs:4:14 | LL | trait Trait: Copy {} - | ^^^^---------- help: remove these generics + | ^^^^---------- help: remove the unnecessary generics | | | expected 0 generic arguments @@ -18,7 +18,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/typeck-builtin-bound-type-parameters.rs:4:14 | LL | trait Trait: Copy {} - | ^^^^---------- help: remove these generics + | ^^^^---------- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -28,7 +28,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/typeck-builtin-bound-type-parameters.rs:4:14 | LL | trait Trait: Copy {} - | ^^^^---------- help: remove these generics + | ^^^^---------- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -38,7 +38,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/typeck-builtin-bound-type-parameters.rs:9:21 | LL | struct MyStruct1>(T); - | ^^^^--- help: remove these generics + | ^^^^--- help: remove the unnecessary generics | | | expected 0 generic arguments @@ -46,7 +46,7 @@ error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was suppl --> $DIR/typeck-builtin-bound-type-parameters.rs:12:25 | LL | struct MyStruct2<'a, T: Copy<'a>>(&'a T); - | ^^^^---- help: remove these generics + | ^^^^---- help: remove the unnecessary generics | | | expected 0 lifetime arguments @@ -54,7 +54,7 @@ error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was suppl --> $DIR/typeck-builtin-bound-type-parameters.rs:15:15 | LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} - | ^^^^ -- help: remove this lifetime argument + | ^^^^ -- help: remove the lifetime argument | | | expected 0 lifetime arguments @@ -62,7 +62,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/typeck-builtin-bound-type-parameters.rs:15:15 | LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} - | ^^^^ - help: remove this generic argument + | ^^^^ - help: remove the unnecessary generic argument | | | expected 0 generic arguments diff --git a/tests/ui/typeck/typeck_type_placeholder_lifetime_1.stderr b/tests/ui/typeck/typeck_type_placeholder_lifetime_1.stderr index e4b1c02c2014..bb1b6e4fc730 100644 --- a/tests/ui/typeck/typeck_type_placeholder_lifetime_1.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_lifetime_1.stderr @@ -2,7 +2,7 @@ error[E0107]: struct takes 1 generic argument but 2 generic arguments were suppl --> $DIR/typeck_type_placeholder_lifetime_1.rs:9:12 | LL | let c: Foo<_, _> = Foo { r: &5 }; - | ^^^ - help: remove this generic argument + | ^^^ --- help: remove the unnecessary generic argument | | | expected 1 generic argument | diff --git a/tests/ui/typeck/typeck_type_placeholder_lifetime_2.stderr b/tests/ui/typeck/typeck_type_placeholder_lifetime_2.stderr index fcb5ecc4042b..6b8f1e98d2c4 100644 --- a/tests/ui/typeck/typeck_type_placeholder_lifetime_2.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_lifetime_2.stderr @@ -2,7 +2,7 @@ error[E0107]: struct takes 1 generic argument but 2 generic arguments were suppl --> $DIR/typeck_type_placeholder_lifetime_2.rs:9:12 | LL | let c: Foo<_, usize> = Foo { r: &5 }; - | ^^^ ----- help: remove this generic argument + | ^^^ ------- help: remove the unnecessary generic argument | | | expected 1 generic argument | diff --git a/tests/ui/ufcs/ufcs-qpath-missing-params.stderr b/tests/ui/ufcs/ufcs-qpath-missing-params.stderr index 2338871218b1..048cf96bcc8e 100644 --- a/tests/ui/ufcs/ufcs-qpath-missing-params.stderr +++ b/tests/ui/ufcs/ufcs-qpath-missing-params.stderr @@ -34,7 +34,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli --> $DIR/ufcs-qpath-missing-params.rs:17:26 | LL | ::into_cow::("foo".to_string()); - | ^^^^^^^^------- help: remove these generics + | ^^^^^^^^------- help: remove the unnecessary generics | | | expected 0 generic arguments | diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr index 5a2de132d70e..a4e7232c8b35 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr @@ -2,7 +2,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:5:17 | LL | fn foo1(_: &dyn Zero()) { - | ^^^^-- help: remove these parenthetical generics + | ^^^^-- help: remove the unnecessary parenthetical generics | | | expected 0 generic arguments | @@ -22,7 +22,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:10:17 | LL | fn foo2(_: &dyn Zero) { - | ^^^^------- help: remove these generics + | ^^^^------- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -36,7 +36,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:14:17 | LL | fn foo3(_: &dyn Zero < usize >) { - | ^^^^-------------- help: remove these generics + | ^^^^-------------- help: remove the unnecessary generics | | | expected 0 generic arguments | @@ -50,7 +50,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:18:17 | LL | fn foo4(_: &dyn Zero(usize)) { - | ^^^^------- help: remove these parenthetical generics + | ^^^^------- help: remove the unnecessary parenthetical generics | | | expected 0 generic arguments | @@ -70,7 +70,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:23:17 | LL | fn foo5(_: &dyn Zero ( usize )) { - | ^^^^-------------- help: remove these parenthetical generics + | ^^^^-------------- help: remove the unnecessary parenthetical generics | | | expected 0 generic arguments | diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr index 130b193d69c9..f5ef58fc91ee 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr @@ -2,7 +2,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/unboxed-closure-sugar-wrong-trait.rs:5:8 | LL | fn f isize>(x: F) {} - | ^^^^^------- help: remove these parenthetical generics + | ^^^^^------- help: remove the unnecessary parenthetical generics | | | expected 0 generic arguments |