diff options
142 files changed, 2166 insertions, 1057 deletions
diff --git a/Cargo.lock b/Cargo.lock index e5025a1ba4f..c8d26559728 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -111,9 +111,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", diff --git a/RELEASES.md b/RELEASES.md index 40ddba6dbc5..54465621b73 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -670,13 +670,6 @@ Cargo - [Support `target.<triple>.rustdocflags` officially](https://github.com/rust-lang/cargo/pull/13197/) - [Stabilize global cache data tracking](https://github.com/rust-lang/cargo/pull/13492/) -<a id="1.78.0-Misc"></a> - -Misc ----- - -- [rustdoc: add `--test-builder-wrapper` arg to support wrappers such as RUSTC_WRAPPER when building doctests](https://github.com/rust-lang/rust/pull/114651/) - <a id="1.78.0-Compatibility-Notes"></a> Compatibility Notes diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index a09aa9ee665..811cb0be9f9 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -330,6 +330,10 @@ pub trait MutVisitor: Sized { fn visit_capture_by(&mut self, capture_by: &mut CaptureBy) { walk_capture_by(self, capture_by) } + + fn visit_fn_ret_ty(&mut self, fn_ret_ty: &mut FnRetTy) { + walk_fn_ret_ty(self, fn_ret_ty) + } } /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful @@ -609,7 +613,7 @@ fn walk_angle_bracketed_parameter_data<T: MutVisitor>(vis: &mut T, data: &mut An fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut ParenthesizedArgs) { let ParenthesizedArgs { inputs, output, span, inputs_span } = args; visit_thin_vec(inputs, |input| vis.visit_ty(input)); - walk_fn_ret_ty(vis, output); + vis.visit_fn_ret_ty(output); vis.visit_span(span); vis.visit_span(inputs_span); } @@ -911,7 +915,7 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) { fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut P<FnDecl>) { let FnDecl { inputs, output } = decl.deref_mut(); inputs.flat_map_in_place(|param| vis.flat_map_param(param)); - walk_fn_ret_ty(vis, output); + vis.visit_fn_ret_ty(output); } fn walk_fn_ret_ty<T: MutVisitor>(vis: &mut T, fn_ret_ty: &mut FnRetTy) { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 3500c215376..c121e7711ee 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -299,6 +299,12 @@ pub trait Visitor<'ast>: Sized { fn visit_coroutine_kind(&mut self, _coroutine_kind: &'ast CoroutineKind) -> Self::Result { Self::Result::output() } + fn visit_fn_decl(&mut self, fn_decl: &'ast FnDecl) -> Self::Result { + walk_fn_decl(self, fn_decl) + } + fn visit_qself(&mut self, qs: &'ast Option<P<QSelf>>) -> Self::Result { + walk_qself(self, qs) + } } pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result { @@ -434,13 +440,13 @@ impl WalkItemKind for ItemKind { body, from_glob: _, }) => { - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(path, *id)); visit_opt!(visitor, visit_ident, rename); visit_opt!(visitor, visit_block, body); } ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(prefix, id)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { @@ -518,10 +524,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { let BareFnTy { safety: _, ext: _, generic_params, decl, decl_span: _ } = &**function_declaration; walk_list!(visitor, visit_generic_param, generic_params); - try_visit!(walk_fn_decl(visitor, decl)); + try_visit!(visitor.visit_fn_decl(decl)); } TyKind::Path(maybe_qself, path) => { - try_visit!(walk_qself(visitor, maybe_qself)); + try_visit!(visitor.visit_qself(maybe_qself)); try_visit!(visitor.visit_path(path, *id)); } TyKind::Pat(ty, pat) => { @@ -652,16 +658,16 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res let Pat { id, kind, span: _, tokens: _ } = pattern; match kind { PatKind::TupleStruct(opt_qself, path, elems) => { - try_visit!(walk_qself(visitor, opt_qself)); + try_visit!(visitor.visit_qself(opt_qself)); try_visit!(visitor.visit_path(path, *id)); walk_list!(visitor, visit_pat, elems); } PatKind::Path(opt_qself, path) => { - try_visit!(walk_qself(visitor, opt_qself)); + try_visit!(visitor.visit_qself(opt_qself)); try_visit!(visitor.visit_path(path, *id)) } PatKind::Struct(opt_qself, path, fields, _rest) => { - try_visit!(walk_qself(visitor, opt_qself)); + try_visit!(visitor.visit_qself(opt_qself)); try_visit!(visitor.visit_path(path, *id)); walk_list!(visitor, visit_pat_field, fields); } @@ -846,13 +852,13 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu // Identifier and visibility are visited as a part of the item. try_visit!(visitor.visit_fn_header(header)); try_visit!(visitor.visit_generics(generics)); - try_visit!(walk_fn_decl(visitor, decl)); + try_visit!(visitor.visit_fn_decl(decl)); visit_opt!(visitor, visit_block, body); } FnKind::Closure(binder, coroutine_kind, decl, body) => { try_visit!(visitor.visit_closure_binder(binder)); visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref()); - try_visit!(walk_fn_decl(visitor, decl)); + try_visit!(visitor.visit_fn_decl(decl)); try_visit!(visitor.visit_expr(body)); } } @@ -902,13 +908,13 @@ impl WalkItemKind for AssocItemKind { body, from_glob: _, }) => { - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(path, *id)); visit_opt!(visitor, visit_ident, rename); visit_opt!(visitor, visit_block, body); } AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(prefix, id)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { @@ -1023,7 +1029,7 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>( visitor: &mut V, InlineAsmSym { id, qself, path }: &'a InlineAsmSym, ) -> V::Result { - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); visitor.visit_path(path, *id) } @@ -1055,7 +1061,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Struct(se) => { let StructExpr { qself, path, fields, rest } = &**se; - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(path, *id)); walk_list!(visitor, visit_expr_field, fields); match rest { @@ -1164,7 +1170,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Underscore => {} ExprKind::Path(maybe_qself, path) => { - try_visit!(walk_qself(visitor, maybe_qself)); + try_visit!(visitor.visit_qself(maybe_qself)); try_visit!(visitor.visit_path(path, *id)); } ExprKind::Break(opt_label, opt_expr) => { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index d53280751fc..0b2969a49ba 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2052,6 +2052,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } + /// Used when lowering a type argument that turned out to actually be a const argument. + /// + /// Only use for that purpose since otherwise it will create a duplicate def. #[instrument(level = "debug", skip(self))] fn lower_const_path_to_const_arg( &mut self, @@ -2060,51 +2063,58 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ty_id: NodeId, span: Span, ) -> &'hir hir::ConstArg<'hir> { - let ct_kind = match res { - Res::Def(DefKind::ConstParam, _) => { - let qpath = self.lower_qpath( - ty_id, - &None, - path, - ParamMode::Optional, - AllowReturnTypeNotation::No, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); - hir::ConstArgKind::Path(qpath) - } - _ => { - // Construct an AnonConst where the expr is the "ty"'s path. + let tcx = self.tcx; - let parent_def_id = self.current_def_id_parent; - let node_id = self.next_node_id(); - let span = self.lower_span(span); - - // Add a definition for the in-band const def. - let def_id = - self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span); - let hir_id = self.lower_node_id(node_id); + // FIXME(min_generic_const_args): we only allow one-segment const paths for now + let ct_kind = if path.is_potential_trivial_const_arg() + && (tcx.features().min_generic_const_args() + || matches!(res, Res::Def(DefKind::ConstParam, _))) + { + let qpath = self.lower_qpath( + ty_id, + &None, + path, + ParamMode::Optional, + AllowReturnTypeNotation::No, + // FIXME(min_generic_const_args): update for `fn foo() -> Bar<FOO<impl Trait>>` support + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + hir::ConstArgKind::Path(qpath) + } else { + // Construct an AnonConst where the expr is the "ty"'s path. + + let parent_def_id = self.current_def_id_parent; + let node_id = self.next_node_id(); + let span = self.lower_span(span); + + // Add a definition for the in-band const def. + // We're lowering a const argument that was originally thought to be a type argument, + // so the def collector didn't create the def ahead of time. That's why we have to do + // it here. + let def_id = + self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span); + let hir_id = self.lower_node_id(node_id); + + let path_expr = Expr { + id: ty_id, + kind: ExprKind::Path(None, path.clone()), + span, + attrs: AttrVec::new(), + tokens: None, + }; - let path_expr = Expr { - id: ty_id, - kind: ExprKind::Path(None, path.clone()), + let ct = self.with_new_scopes(span, |this| { + self.arena.alloc(hir::AnonConst { + def_id, + hir_id, + body: this.with_def_id_parent(def_id, |this| { + this.lower_const_body(path_expr.span, Some(&path_expr)) + }), span, - attrs: AttrVec::new(), - tokens: None, - }; - - let ct = self.with_new_scopes(span, |this| { - self.arena.alloc(hir::AnonConst { - def_id, - hir_id, - body: this.with_def_id_parent(def_id, |this| { - this.lower_const_body(path_expr.span, Some(&path_expr)) - }), - span, - }) - }); - hir::ConstArgKind::Anon(ct) - } + }) + }); + hir::ConstArgKind::Anon(ct) }; self.arena.alloc(hir::ConstArg { @@ -2122,6 +2132,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> { + let tcx = self.tcx; // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments // currently have to be wrapped in curly brackets, so it's necessary to special-case. let expr = if let ExprKind::Block(block, _) = &anon.value.kind @@ -2135,18 +2146,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let maybe_res = self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res()); - debug!("res={:?}", maybe_res); - // FIXME(min_generic_const_args): for now we only lower params to ConstArgKind::Path - if let Some(res) = maybe_res - && let Res::Def(DefKind::ConstParam, _) = res - && let ExprKind::Path(qself, path) = &expr.kind + // FIXME(min_generic_const_args): we only allow one-segment const paths for now + if let ExprKind::Path(None, path) = &expr.kind + && path.is_potential_trivial_const_arg() + && (tcx.features().min_generic_const_args() + || matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _)))) { let qpath = self.lower_qpath( expr.id, - qself, + &None, path, ParamMode::Optional, AllowReturnTypeNotation::No, + // FIXME(min_generic_const_args): update for `fn foo() -> Bar<FOO<impl Trait>>` support ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 88c6bde3106..86752da79ae 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -18,7 +18,6 @@ pub mod ast_validation; mod errors; pub mod feature_gate; -pub mod node_count; pub mod show_span; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs deleted file mode 100644 index 9e7204df8ad..00000000000 --- a/compiler/rustc_ast_passes/src/node_count.rs +++ /dev/null @@ -1,129 +0,0 @@ -// Simply gives a rough count of the number of nodes in an AST. - -use rustc_ast::visit::*; -use rustc_ast::*; -use rustc_span::Span; -use rustc_span::symbol::Ident; - -pub struct NodeCounter { - pub count: usize, -} - -impl NodeCounter { - pub fn new() -> NodeCounter { - NodeCounter { count: 0 } - } -} - -impl<'ast> Visitor<'ast> for NodeCounter { - fn visit_ident(&mut self, _ident: &Ident) { - self.count += 1; - } - fn visit_foreign_item(&mut self, i: &ForeignItem) { - self.count += 1; - walk_item(self, i) - } - fn visit_item(&mut self, i: &Item) { - self.count += 1; - walk_item(self, i) - } - fn visit_local(&mut self, l: &Local) { - self.count += 1; - walk_local(self, l) - } - fn visit_block(&mut self, b: &Block) { - self.count += 1; - walk_block(self, b) - } - fn visit_stmt(&mut self, s: &Stmt) { - self.count += 1; - walk_stmt(self, s) - } - fn visit_arm(&mut self, a: &Arm) { - self.count += 1; - walk_arm(self, a) - } - fn visit_pat(&mut self, p: &Pat) { - self.count += 1; - walk_pat(self, p) - } - fn visit_expr(&mut self, ex: &Expr) { - self.count += 1; - walk_expr(self, ex) - } - fn visit_ty(&mut self, t: &Ty) { - self.count += 1; - walk_ty(self, t) - } - fn visit_generic_param(&mut self, param: &GenericParam) { - self.count += 1; - walk_generic_param(self, param) - } - fn visit_generics(&mut self, g: &Generics) { - self.count += 1; - walk_generics(self, g) - } - fn visit_fn(&mut self, fk: visit::FnKind<'_>, _: Span, _: NodeId) { - self.count += 1; - walk_fn(self, fk) - } - fn visit_assoc_item(&mut self, ti: &AssocItem, ctxt: AssocCtxt) { - self.count += 1; - walk_assoc_item(self, ti, ctxt); - } - fn visit_trait_ref(&mut self, t: &TraitRef) { - self.count += 1; - walk_trait_ref(self, t) - } - fn visit_param_bound(&mut self, bounds: &GenericBound, _ctxt: BoundKind) { - self.count += 1; - walk_param_bound(self, bounds) - } - fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef) { - self.count += 1; - walk_poly_trait_ref(self, t) - } - fn visit_variant_data(&mut self, s: &VariantData) { - self.count += 1; - walk_struct_def(self, s) - } - fn visit_field_def(&mut self, s: &FieldDef) { - self.count += 1; - walk_field_def(self, s) - } - fn visit_enum_def(&mut self, enum_definition: &EnumDef) { - self.count += 1; - walk_enum_def(self, enum_definition) - } - fn visit_variant(&mut self, v: &Variant) { - self.count += 1; - walk_variant(self, v) - } - fn visit_lifetime(&mut self, lifetime: &Lifetime, _: visit::LifetimeCtxt) { - self.count += 1; - walk_lifetime(self, lifetime) - } - fn visit_mac_call(&mut self, mac: &MacCall) { - self.count += 1; - walk_mac(self, mac) - } - fn visit_path(&mut self, path: &Path, _id: NodeId) { - self.count += 1; - walk_path(self, path) - } - fn visit_use_tree(&mut self, use_tree: &UseTree, id: NodeId, _nested: bool) { - self.count += 1; - walk_use_tree(self, use_tree, id) - } - fn visit_generic_args(&mut self, generic_args: &GenericArgs) { - self.count += 1; - walk_generic_args(self, generic_args) - } - fn visit_assoc_item_constraint(&mut self, constraint: &AssocItemConstraint) { - self.count += 1; - walk_assoc_item_constraint(self, constraint) - } - fn visit_attribute(&mut self, _attr: &Attribute) { - self.count += 1; - } -} diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 0897d140d60..90d12ea8328 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -60,7 +60,7 @@ impl<'tcx> UniverseInfo<'tcx> { UniverseInfo::RelateTys { expected, found } => { let err = mbcx.infcx.err_ctxt().report_mismatched_types( &cause, - mbcx.param_env, + mbcx.infcx.param_env, expected, found, TypeError::RegionsPlaceholderMismatch, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 129a30661d6..c11103af476 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -266,7 +266,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - if self.param_env.caller_bounds().iter().any(|c| { + if self.infcx.param_env.caller_bounds().iter().any(|c| { c.as_trait_clause().is_some_and(|pred| { pred.skip_binder().self_ty() == ty && self.infcx.tcx.is_fn_trait(pred.def_id()) }) @@ -682,13 +682,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // Normalize before comparing to see through type aliases and projections. let old_ty = ty::EarlyBinder::bind(ty).instantiate(tcx, generic_args); let new_ty = ty::EarlyBinder::bind(ty).instantiate(tcx, new_args); - if let Ok(old_ty) = - tcx.try_normalize_erasing_regions(self.infcx.typing_env(self.param_env), old_ty) - && let Ok(new_ty) = tcx.try_normalize_erasing_regions( - self.infcx.typing_env(self.param_env), - new_ty, - ) - { + if let Ok(old_ty) = tcx.try_normalize_erasing_regions( + self.infcx.typing_env(self.infcx.param_env), + old_ty, + ) && let Ok(new_ty) = tcx.try_normalize_erasing_regions( + self.infcx.typing_env(self.infcx.param_env), + new_ty, + ) { old_ty == new_ty } else { false @@ -707,15 +707,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // Test the callee's predicates, substituting in `ref_ty` for the moved argument type. clauses.instantiate(tcx, new_args).predicates.iter().all(|&(mut clause)| { // Normalize before testing to see through type aliases and projections. - if let Ok(normalized) = - tcx.try_normalize_erasing_regions(self.infcx.typing_env(self.param_env), clause) - { + if let Ok(normalized) = tcx.try_normalize_erasing_regions( + self.infcx.typing_env(self.infcx.param_env), + clause, + ) { clause = normalized; } self.infcx.predicate_must_hold_modulo_regions(&Obligation::new( tcx, ObligationCause::dummy(), - self.param_env, + self.infcx.param_env, clause, )) }) @@ -904,7 +905,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let ty = moved_place.ty(self.body, self.infcx.tcx).ty; debug!("ty: {:?}, kind: {:?}", ty, ty.kind()); - let Some(assign_value) = self.infcx.err_ctxt().ty_kind_suggestion(self.param_env, ty) + let Some(assign_value) = self.infcx.err_ctxt().ty_kind_suggestion(self.infcx.param_env, ty) else { return; }; @@ -1304,7 +1305,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { pub(crate) fn implements_clone(&self, ty: Ty<'tcx>) -> bool { let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait() else { return false }; self.infcx - .type_implements_trait(clone_trait_def, [ty], self.param_env) + .type_implements_trait(clone_trait_def, [ty], self.infcx.param_env) .must_apply_modulo_regions() } @@ -1437,7 +1438,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let ocx = ObligationCtxt::new_with_diagnostics(self.infcx); let cause = ObligationCause::misc(span, self.mir_def_id()); - ocx.register_bound(cause, self.param_env, ty, def_id); + ocx.register_bound(cause, self.infcx.param_env, ty, def_id); let errors = ocx.select_all_or_error(); // Only emit suggestion if all required predicates are on generic @@ -1957,7 +1958,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { && let ty::Ref(_, inner, _) = rcvr_ty.kind() && let inner = inner.peel_refs() && (Holds { ty: inner }).visit_ty(local_ty).is_break() - && let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env) + && let None = + self.infcx.type_implements_trait_shallow(clone, inner, self.infcx.param_env) { err.span_label( span, @@ -1989,7 +1991,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let obligation = Obligation::new( self.infcx.tcx, ObligationCause::dummy(), - self.param_env, + self.infcx.param_env, trait_ref, ); self.infcx.err_ctxt().suggest_derive( @@ -3398,7 +3400,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) && self .infcx - .type_implements_trait(iter_trait, [return_ty], self.param_env) + .type_implements_trait(iter_trait, [return_ty], self.infcx.param_env) .must_apply_modulo_regions() { err.span_suggestion_hidden( @@ -3839,14 +3841,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { Instance::try_resolve( tcx, - self.infcx.typing_env(self.param_env), + self.infcx.typing_env(self.infcx.param_env), deref_target, method_args, ) .transpose() }); if let Some(Ok(instance)) = deref_target { - let deref_target_ty = instance.ty(tcx, self.infcx.typing_env(self.param_env)); + let deref_target_ty = + instance.ty(tcx, self.infcx.typing_env(self.infcx.param_env)); err.note(format!("borrow occurs due to deref coercion to `{deref_target_ty}`")); err.span_note(tcx.def_span(instance.def_id()), "deref defined here"); } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 6c63da819c7..bda96726738 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -864,7 +864,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let kind = call_kind( self.infcx.tcx, - self.infcx.typing_env(self.param_env), + self.infcx.typing_env(self.infcx.param_env), method_did, method_args, *fn_span, @@ -1160,7 +1160,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) { Some(def_id) => type_known_to_meet_bound_modulo_regions( self.infcx, - self.param_env, + self.infcx.param_env, Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty), def_id, ), @@ -1224,7 +1224,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { BoundRegionConversionTime::FnCall, tcx.fn_sig(method_did).instantiate(tcx, method_args).input(0), ) - && self.infcx.can_eq(self.param_env, ty, self_ty) + && self.infcx.can_eq(self.infcx.param_env, ty, self_ty) { err.subdiagnostic(CaptureReasonSuggest::FreshReborrow { span: move_span.shrink_to_hi(), @@ -1258,7 +1258,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let Some(errors) = self.infcx.type_implements_trait_shallow( clone_trait, ty, - self.param_env, + self.infcx.param_env, ) && !has_sugg { let msg = match &errors[..] { diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 15cc9c20ab7..4ba6b2e94ec 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -305,7 +305,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let Some(copy_trait_def) = self.infcx.tcx.lang_items().copy_trait() else { return false }; // This is only going to be ambiguous if there are incoherent impls, because otherwise // ambiguity should never happen in MIR. - self.infcx.type_implements_trait(copy_trait_def, [ty], self.param_env).may_apply() + self.infcx.type_implements_trait(copy_trait_def, [ty], self.infcx.param_env).may_apply() } fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'infcx> { diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index d064bf098e4..c5ebf3c547e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1242,7 +1242,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { .type_implements_trait_shallow( clone_trait, ty.peel_refs(), - self.param_env, + self.infcx.param_env, ) .as_deref() { @@ -1279,7 +1279,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let obligation = traits::Obligation::new( self.infcx.tcx, traits::ObligationCause::dummy(), - self.param_env, + self.infcx.param_env, trait_ref, ); self.infcx.err_ctxt().suggest_derive( diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index d4660d8af43..c38747f6675 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -952,7 +952,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let Ok(Some(instance)) = ty::Instance::try_resolve( tcx, - self.infcx.typing_env(self.param_env), + self.infcx.typing_env(self.infcx.param_env), *fn_did, self.infcx.resolve_vars_if_possible(args), ) { @@ -1091,7 +1091,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { peeled_ty = ref_ty; count += 1; } - if !self.infcx.type_is_copy_modulo_regions(self.param_env, peeled_ty) { + if !self.infcx.type_is_copy_modulo_regions(self.infcx.param_env, peeled_ty) { return; } @@ -1160,7 +1160,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let ocx = ObligationCtxt::new(&self.infcx); ocx.register_obligations(preds.iter().map(|(pred, span)| { trace!(?pred); - Obligation::misc(tcx, span, self.mir_def_id(), self.param_env, pred) + Obligation::misc(tcx, span, self.mir_def_id(), self.infcx.param_env, pred) })); if ocx.select_all_or_error().is_empty() && count > 0 { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 7eaf265d410..03f7b05d1e3 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -140,7 +140,6 @@ fn do_mir_borrowck<'tcx>( ) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) { let def = input_body.source.def_id().expect_local(); let infcx = BorrowckInferCtxt::new(tcx, def); - let param_env = tcx.param_env(def); let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); for var_debug_info in &input_body.var_debug_info { @@ -175,8 +174,7 @@ fn do_mir_borrowck<'tcx>( // will have a lifetime tied to the inference context. let mut body_owned = input_body.clone(); let mut promoted = input_promoted.to_owned(); - let free_regions = - nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted); + let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted); let body = &body_owned; // no further changes // FIXME(-Znext-solver): A bit dubious that we're only registering @@ -192,7 +190,7 @@ fn do_mir_borrowck<'tcx>( .iter_enumerated() .map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true))); - let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) + let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) .iterate_to_fixpoint(tcx, body, Some("borrowck")) .into_results_cursor(body); @@ -213,18 +211,12 @@ fn do_mir_borrowck<'tcx>( body, &promoted, &location_table, - param_env, - &mut flow_inits, + flow_inits, &move_data, &borrow_set, - tcx.closure_captures(def), consumer_options, ); - // `flow_inits` is large, so we drop it as soon as possible. This reduces - // peak memory usage significantly on some benchmarks. - drop(flow_inits); - // Dump MIR results into a file, if that is enabled. This let us // write unit-tests, as well as helping with debugging. nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set); @@ -251,7 +243,6 @@ fn do_mir_borrowck<'tcx>( let promoted_body = &promoted[idx]; let mut promoted_mbcx = MirBorrowckCtxt { infcx: &infcx, - param_env, body: promoted_body, move_data: &move_data, location_table: &location_table, // no need to create a real one for the promoted, it is not used @@ -291,7 +282,6 @@ fn do_mir_borrowck<'tcx>( let mut mbcx = MirBorrowckCtxt { infcx: &infcx, - param_env, body, move_data: &move_data, location_table: &location_table, @@ -448,12 +438,14 @@ fn get_flow_results<'a, 'tcx>( pub(crate) struct BorrowckInferCtxt<'tcx> { pub(crate) infcx: InferCtxt<'tcx>, pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>, + pub(crate) param_env: ParamEnv<'tcx>, } impl<'tcx> BorrowckInferCtxt<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, def_id)); - BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) } + let param_env = tcx.param_env(def_id); + BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env } } pub(crate) fn next_region_var<F>( @@ -532,7 +524,6 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> { struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { infcx: &'infcx BorrowckInferCtxt<'tcx>, - param_env: ParamEnv<'tcx>, body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>, diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index f76603d5679..be02e2f48df 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -30,7 +30,7 @@ use crate::diagnostics::RegionErrors; use crate::facts::{AllFacts, AllFactsExt, RustcFacts}; use crate::location::LocationTable; use crate::region_infer::RegionInferenceContext; -use crate::type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}; +use crate::type_check::{self, MirTypeckResults}; use crate::universal_regions::UniversalRegions; use crate::{BorrowckInferCtxt, polonius, renumber}; @@ -50,10 +50,9 @@ pub(crate) struct NllOutput<'tcx> { /// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal /// regions (e.g., region parameters) declared on the function. That set will need to be given to /// `compute_regions`. -#[instrument(skip(infcx, param_env, body, promoted), level = "debug")] +#[instrument(skip(infcx, body, promoted), level = "debug")] pub(crate) fn replace_regions_in_mir<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexSlice<Promoted, Body<'tcx>>, ) -> UniversalRegions<'tcx> { @@ -62,7 +61,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>( debug!(?def); // Compute named region information. This also renumbers the inputs/outputs. - let universal_regions = UniversalRegions::new(infcx, def, param_env); + let universal_regions = UniversalRegions::new(infcx, def); // Replace all remaining regions with fresh inference variables. renumber::renumber_mir(infcx, body, promoted); @@ -81,11 +80,9 @@ pub(crate) fn compute_regions<'a, 'tcx>( body: &Body<'tcx>, promoted: &IndexSlice<Promoted, Body<'tcx>>, location_table: &LocationTable, - param_env: ty::ParamEnv<'tcx>, - flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, + flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, - upvars: &[&ty::CapturedPlace<'tcx>], consumer_options: Option<ConsumerOptions>, ) -> NllOutput<'tcx> { let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled(); @@ -96,41 +93,27 @@ pub(crate) fn compute_regions<'a, 'tcx>( let mut all_facts = (polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default()); - let universal_regions = Rc::new(universal_regions); - let elements = Rc::new(DenseLocationMap::new(body)); // Run the MIR type-checker. let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = type_check::type_check( infcx, - param_env, body, promoted, - Rc::clone(&universal_regions), + universal_regions, location_table, borrow_set, &mut all_facts, flow_inits, move_data, Rc::clone(&elements), - upvars, ); // Create the region inference context, taking ownership of the // region inference data that was contained in `infcx`, and the // base constraints generated by the type-check. let var_origins = infcx.get_region_var_origins(); - let MirTypeckRegionConstraints { - placeholder_indices, - placeholder_index_to_region: _, - liveness_constraints, - mut outlives_constraints, - mut member_constraints, - universe_causes, - type_tests, - } = constraints; - let placeholder_indices = Rc::new(placeholder_indices); // If requested, emit legacy polonius facts. polonius::emit_facts( @@ -140,31 +123,14 @@ pub(crate) fn compute_regions<'a, 'tcx>( body, borrow_set, move_data, - &universal_regions, &universal_region_relations, ); - if let Some(guar) = universal_regions.tainted_by_errors() { - // Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all - // outlives bounds that we may end up checking. - outlives_constraints = Default::default(); - member_constraints = Default::default(); - - // Also taint the entire scope. - infcx.set_tainted_by_errors(guar); - } - let mut regioncx = RegionInferenceContext::new( infcx, var_origins, - universal_regions, - placeholder_indices, + constraints, universal_region_relations, - outlives_constraints, - member_constraints, - universe_causes, - type_tests, - liveness_constraints, elements, ); diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs index 6862eb13427..9fccc00bdaf 100644 --- a/compiler/rustc_borrowck/src/polonius/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/mod.rs @@ -12,7 +12,6 @@ use crate::borrow_set::BorrowSet; use crate::facts::{AllFacts, PoloniusRegionVid}; use crate::location::LocationTable; use crate::type_check::free_region_relations::UniversalRegionRelations; -use crate::universal_regions::UniversalRegions; mod loan_invalidations; mod loan_kills; @@ -32,7 +31,6 @@ pub(crate) fn emit_facts<'tcx>( body: &Body<'tcx>, borrow_set: &BorrowSet<'tcx>, move_data: &MoveData<'_>, - universal_regions: &UniversalRegions<'_>, universal_region_relations: &UniversalRegionRelations<'_>, ) { let Some(all_facts) = all_facts else { @@ -41,12 +39,7 @@ pub(crate) fn emit_facts<'tcx>( }; let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation"); emit_move_facts(all_facts, move_data, location_table, body); - emit_universal_region_facts( - all_facts, - borrow_set, - universal_regions, - universal_region_relations, - ); + emit_universal_region_facts(all_facts, borrow_set, universal_region_relations); emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set); emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set); } @@ -129,7 +122,6 @@ fn emit_move_facts( fn emit_universal_region_facts( all_facts: &mut AllFacts, borrow_set: &BorrowSet<'_>, - universal_regions: &UniversalRegions<'_>, universal_region_relations: &UniversalRegionRelations<'_>, ) { // 1: universal regions are modeled in Polonius as a pair: @@ -138,9 +130,10 @@ fn emit_universal_region_facts( // the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index // added to the existing number of loans, as if they succeeded them in the set. // + let universal_regions = &universal_region_relations.universal_regions; all_facts .universal_region - .extend(universal_regions.universal_regions().map(PoloniusRegionVid::from)); + .extend(universal_regions.universal_regions_iter().map(PoloniusRegionVid::from)); let borrow_count = borrow_set.len(); debug!( "emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}", @@ -148,7 +141,7 @@ fn emit_universal_region_facts( borrow_count ); - for universal_region in universal_regions.universal_regions() { + for universal_region in universal_regions.universal_regions_iter() { let universal_region_idx = universal_region.index(); let placeholder_loan_idx = borrow_count + universal_region_idx; all_facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into())); diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs index 6b8dd1a49e7..ef3d6309c19 100644 --- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs +++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs @@ -23,7 +23,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { for region in self.regions() { if let NllRegionVariableOrigin::FreeRegion = self.definitions[region].origin { - let classification = self.universal_regions.region_classification(region).unwrap(); + let classification = + self.universal_regions().region_classification(region).unwrap(); let outlived_by = self.universal_region_relations.regions_outlived_by(region); writeln!( out, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 7e317ea6554..0ddb4e110e3 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -31,11 +31,9 @@ use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo}; use crate::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}; use crate::nll::PoloniusOutput; use crate::region_infer::reverse_sccs::ReverseSccGraph; -use crate::region_infer::values::{ - LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex, -}; -use crate::type_check::Locations; +use crate::region_infer::values::{LivenessValues, RegionElement, RegionValues, ToElementIndex}; use crate::type_check::free_region_relations::UniversalRegionRelations; +use crate::type_check::{Locations, MirTypeckRegionConstraints}; use crate::universal_regions::UniversalRegions; mod dump_mir; @@ -191,10 +189,6 @@ pub struct RegionInferenceContext<'tcx> { /// Type constraints that we check after solving. type_tests: Vec<TypeTest<'tcx>>, - /// Information about the universally quantified regions in scope - /// on this function. - universal_regions: Rc<UniversalRegions<'tcx>>, - /// Information about how the universally quantified regions in /// scope on this function relate to one another. universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, @@ -399,21 +393,36 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn new( infcx: &BorrowckInferCtxt<'tcx>, var_infos: VarInfos, - universal_regions: Rc<UniversalRegions<'tcx>>, - placeholder_indices: Rc<PlaceholderIndices>, + constraints: MirTypeckRegionConstraints<'tcx>, universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, - mut outlives_constraints: OutlivesConstraintSet<'tcx>, - member_constraints_in: MemberConstraintSet<'tcx, RegionVid>, - universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>, - type_tests: Vec<TypeTest<'tcx>>, - liveness_constraints: LivenessValues, elements: Rc<DenseLocationMap>, ) -> Self { - debug!("universal_regions: {:#?}", universal_regions); + let universal_regions = &universal_region_relations.universal_regions; + let MirTypeckRegionConstraints { + placeholder_indices, + placeholder_index_to_region: _, + liveness_constraints, + mut outlives_constraints, + mut member_constraints, + universe_causes, + type_tests, + } = constraints; + + debug!("universal_regions: {:#?}", universal_region_relations.universal_regions); debug!("outlives constraints: {:#?}", outlives_constraints); debug!("placeholder_indices: {:#?}", placeholder_indices); debug!("type tests: {:#?}", type_tests); + if let Some(guar) = universal_region_relations.universal_regions.tainted_by_errors() { + // Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all + // outlives bounds that we may end up checking. + outlives_constraints = Default::default(); + member_constraints = Default::default(); + + // Also taint the entire scope. + infcx.set_tainted_by_errors(guar); + } + // Create a RegionDefinition for each inference variable. let definitions: IndexVec<_, _> = var_infos .iter() @@ -438,7 +447,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } let member_constraints = - Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r))); + Rc::new(member_constraints.into_mapped(|r| constraint_sccs.scc(r))); let mut result = Self { var_infos, @@ -453,7 +462,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { universe_causes, scc_values, type_tests, - universal_regions, universal_region_relations, }; @@ -518,7 +526,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn init_free_and_bound_regions(&mut self) { // Update the names (if any) // This iterator has unstable order but we collect it all into an IndexVec - for (external_name, variable) in self.universal_regions.named_universal_regions() { + for (external_name, variable) in + self.universal_region_relations.universal_regions.named_universal_regions_iter() + { debug!( "init_free_and_bound_regions: region {:?} has external name {:?}", variable, external_name @@ -562,7 +572,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// (Panics if `r` is not a registered universal region.) pub(crate) fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { - self.universal_regions.to_region_vid(r) + self.universal_regions().to_region_vid(r) } /// Returns an iterator over all the outlives constraints. @@ -574,7 +584,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`. pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, ()>) { - self.universal_regions.annotate(tcx, err) + self.universal_regions().annotate(tcx, err) } /// Returns `true` if the region `r` contains the point `p`. @@ -686,7 +696,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { if outlives_requirements.is_empty() { (None, errors_buffer) } else { - let num_external_vids = self.universal_regions.num_global_and_external_regions(); + let num_external_vids = self.universal_regions().num_global_and_external_regions(); ( Some(ClosureRegionRequirements { num_external_vids, outlives_requirements }), errors_buffer, @@ -989,7 +999,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // always be in the root universe. if let Some(p) = self.scc_values.placeholders_contained_in(r_scc).next() { debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p); - let static_r = self.universal_regions.fr_static; + let static_r = self.universal_regions().fr_static; propagated_outlives_requirements.push(ClosureOutlivesRequirement { subject, outlived_free_region: static_r, @@ -1032,8 +1042,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { // avoid potential non-determinism we approximate this by requiring // T: '1 and T: '2. for upper_bound in non_local_ub { - debug_assert!(self.universal_regions.is_universal_region(upper_bound)); - debug_assert!(!self.universal_regions.is_local_free_region(upper_bound)); + debug_assert!(self.universal_regions().is_universal_region(upper_bound)); + debug_assert!(!self.universal_regions().is_local_free_region(upper_bound)); let requirement = ClosureOutlivesRequirement { subject, @@ -1101,7 +1111,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // To do so, we simply check every candidate `u_r` for equality. self.scc_values .universal_regions_outlived_by(r_scc) - .filter(|&u_r| !self.universal_regions.is_local_free_region(u_r)) + .filter(|&u_r| !self.universal_regions().is_local_free_region(u_r)) .find(|&u_r| self.eval_equal(u_r, r_vid)) .map(|u_r| ty::Region::new_var(tcx, u_r)) // In case we could not find a named region to map to, @@ -1139,9 +1149,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Find the smallest universal region that contains all other // universal regions within `region`. - let mut lub = self.universal_regions.fr_fn_body; + let mut lub = self.universal_regions().fr_fn_body; let r_scc = self.constraint_sccs.scc(r); - let static_r = self.universal_regions.fr_static; + let static_r = self.universal_regions().fr_static; for ur in self.scc_values.universal_regions_outlived_by(r_scc) { let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur); debug!(?ur, ?lub, ?new_lub); @@ -1288,12 +1298,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!( "sup_region's value = {:?} universal={:?}", self.region_value_str(sup_region), - self.universal_regions.is_universal_region(sup_region), + self.universal_regions().is_universal_region(sup_region), ); debug!( "sub_region's value = {:?} universal={:?}", self.region_value_str(sub_region), - self.universal_regions.is_universal_region(sub_region), + self.universal_regions().is_universal_region(sub_region), ); let sub_region_scc = self.constraint_sccs.scc(sub_region); @@ -1308,7 +1318,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { by super `{sup_region_scc:?}`, promoting to static", ); - return self.eval_outlives(sup_region, self.universal_regions.fr_static); + return self.eval_outlives(sup_region, self.universal_regions().fr_static); } // Both the `sub_region` and `sup_region` consist of the union @@ -1332,7 +1342,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Now we have to compare all the points in the sub region and make // sure they exist in the sup region. - if self.universal_regions.is_universal_region(sup_region) { + if self.universal_regions().is_universal_region(sup_region) { // Micro-opt: universal regions contain all points. debug!("super is universal and hence contains all points"); return true; @@ -1736,7 +1746,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("provides_universal_region(r={:?}, fr1={:?}, fr2={:?})", r, fr1, fr2); let result = { r == fr2 || { - fr2 == self.universal_regions.fr_static && self.cannot_name_placeholder(fr1, r) + fr2 == self.universal_regions().fr_static && self.cannot_name_placeholder(fr1, r) } }; debug!("provides_universal_region: result = {:?}", result); @@ -1837,7 +1847,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // A constraint like `'r: 'x` can come from our constraint // graph. - let fr_static = self.universal_regions.fr_static; + let fr_static = self.universal_regions().fr_static; let outgoing_edges_from_graph = self.constraint_graph.outgoing_edges(r, &self.constraints, fr_static); @@ -1952,7 +1962,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } pub(crate) fn universal_regions(&self) -> &UniversalRegions<'tcx> { - self.universal_regions.as_ref() + &self.universal_region_relations.universal_regions } /// Tries to find the best constraint to blame for the fact that @@ -2212,7 +2222,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Access to the region graph, built from the outlives constraints. pub(crate) fn region_graph(&self) -> RegionGraph<'_, 'tcx, graph::Normal> { - self.constraint_graph.region_graph(&self.constraints, self.universal_regions.fr_static) + self.constraint_graph.region_graph(&self.constraints, self.universal_regions().fr_static) } /// Returns whether the given region is considered live at all points: whether it is a diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d676ce59cfe..993d5d86333 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -74,7 +74,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!(?opaque_type_key, ?concrete_type); let mut arg_regions: Vec<(ty::RegionVid, ty::Region<'_>)> = - vec![(self.universal_regions.fr_static, infcx.tcx.lifetimes.re_static)]; + vec![(self.universal_regions().fr_static, infcx.tcx.lifetimes.re_static)]; let opaque_type_key = opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |region| { @@ -88,12 +88,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { // the same name and simplifies subsequent handling. // See [rustc-dev-guide chapter] § "Semantic lifetime equality". NllRegionVariableOrigin::FreeRegion => self - .universal_regions .universal_regions() + .universal_regions_iter() .filter(|&ur| { // See [rustc-dev-guide chapter] § "Closure restrictions". !matches!( - self.universal_regions.region_classification(ur), + self.universal_regions().region_classification(ur), Some(RegionClassification::External) ) }) diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs index cfd5a92787e..d0cfe572d08 100644 --- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs +++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs @@ -45,8 +45,8 @@ impl RegionInferenceContext<'_> { let graph = self.constraint_sccs.reverse(); let mut paired_scc_regions = self - .universal_regions .universal_regions() + .universal_regions_iter() .map(|region| (self.constraint_sccs.scc(region), region)) .collect::<Vec<_>>(); paired_scc_regions.sort(); diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 519edfafda5..a16bce63839 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -258,10 +258,9 @@ impl PlaceholderIndices { /// Here, the variable `'0` would contain the free region `'a`, /// because (since it is returned) it must live for at least `'a`. But /// it would also contain various points from within the function. -#[derive(Clone)] pub(crate) struct RegionValues<N: Idx> { elements: Rc<DenseLocationMap>, - placeholder_indices: Rc<PlaceholderIndices>, + placeholder_indices: PlaceholderIndices, points: SparseIntervalMatrix<N, PointIndex>, free_regions: SparseBitMatrix<N, RegionVid>, @@ -277,7 +276,7 @@ impl<N: Idx> RegionValues<N> { pub(crate) fn new( elements: Rc<DenseLocationMap>, num_universal_regions: usize, - placeholder_indices: Rc<PlaceholderIndices>, + placeholder_indices: PlaceholderIndices, ) -> Self { let num_points = elements.num_points(); let num_placeholders = placeholder_indices.len(); diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index aee13ca8cd7..68b843d4d0d 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -132,7 +132,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory<'tcx>, ) { - let param_env = self.param_env; + let param_env = self.infcx.param_env; let predicate = predicate.upcast(self.tcx()); let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( locations, @@ -158,7 +158,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { where T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, { - let param_env = self.param_env; + let param_env = self.infcx.param_env; let result: Result<_, ErrorGuaranteed> = self.fully_perform_op( location.to_locations(), category, @@ -176,7 +176,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let tcx = self.tcx(); if self.infcx.next_trait_solver() { let body = self.body; - let param_env = self.param_env; + let param_env = self.infcx.param_env; self.fully_perform_op( location.to_locations(), ConstraintCategory::Boring, @@ -223,7 +223,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( Locations::All(span), ConstraintCategory::Boring, - self.param_env.and(type_op::ascribe_user_type::AscribeUserType { mir_ty, user_ty }), + self.infcx + .param_env + .and(type_op::ascribe_user_type::AscribeUserType { mir_ty, user_ty }), ); } @@ -250,7 +252,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let mir_ty = self.normalize(mir_ty, Locations::All(span)); let cause = ObligationCause::dummy_with_span(span); - let param_env = self.param_env; + let param_env = self.infcx.param_env; let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( Locations::All(span), ConstraintCategory::Boring, diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 6c86968389a..67915371b1f 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -37,7 +37,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> { region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, param_env: ty::ParamEnv<'tcx>, - known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], + known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>], locations: Locations, span: Span, category: ConstraintCategory<'tcx>, @@ -52,7 +52,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, param_env: ty::ParamEnv<'tcx>, - known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], + known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>], locations: Locations, span: Span, category: ConstraintCategory<'tcx>, diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 8e1faf025e2..ea965eb6545 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -1,5 +1,3 @@ -use std::rc::Rc; - use rustc_data_structures::frozen::Frozen; use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder}; use rustc_hir::def::DefKind; @@ -23,7 +21,7 @@ use crate::universal_regions::UniversalRegions; #[derive(Debug)] pub(crate) struct UniversalRegionRelations<'tcx> { - universal_regions: Rc<UniversalRegions<'tcx>>, + pub(crate) universal_regions: UniversalRegions<'tcx>, /// Stores the outlives relations that are known to hold from the /// implied bounds, in-scope where-clauses, and that sort of @@ -46,7 +44,7 @@ type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>; pub(crate) struct CreateResult<'tcx> { pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>, - pub(crate) known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], + pub(crate) known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>, pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>, } @@ -54,7 +52,7 @@ pub(crate) fn create<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, implicit_region_bound: ty::Region<'tcx>, - universal_regions: Rc<UniversalRegions<'tcx>>, + universal_regions: UniversalRegions<'tcx>, constraints: &mut MirTypeckRegionConstraints<'tcx>, ) -> CreateResult<'tcx> { UniversalRegionRelationsBuilder { @@ -184,7 +182,7 @@ impl UniversalRegionRelations<'_> { struct UniversalRegionRelationsBuilder<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - universal_regions: Rc<UniversalRegions<'tcx>>, + universal_regions: UniversalRegions<'tcx>, implicit_region_bound: ty::Region<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, @@ -220,7 +218,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // region `'r`, all of which are provided by our caller let fr_static = self.universal_regions.fr_static; let fr_fn_body = self.universal_regions.fr_fn_body; - for fr in self.universal_regions.universal_regions() { + for fr in self.universal_regions.universal_regions_iter() { debug!("build: relating free region {:?} to itself and to 'static", fr); self.relate_universal_regions(fr, fr); self.relate_universal_regions(fr_static, fr); @@ -236,7 +234,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // In the new solver, normalize the type-outlives obligation assumptions. if self.infcx.next_trait_solver() { match deeply_normalize( - self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env), + self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), param_env), outlives, ) { Ok(normalized_outlives) => { @@ -250,8 +248,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { known_type_outlives_obligations.push(outlives); } - let known_type_outlives_obligations = - self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations); let unnormalized_input_output_tys = self .universal_regions @@ -278,15 +274,15 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { if let Some(c) = constraints_unnorm { constraints.push(c) } - let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self - .param_env - .and(type_op::normalize::Normalize { value: ty }) - .fully_perform(self.infcx, span) - .unwrap_or_else(|guar| TypeOpOutput { - output: Ty::new_error(self.infcx.tcx, guar), - constraints: None, - error_info: None, - }); + let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = + param_env + .and(type_op::normalize::Normalize { value: ty }) + .fully_perform(self.infcx, span) + .unwrap_or_else(|guar| TypeOpOutput { + output: Ty::new_error(self.infcx.tcx, guar), + constraints: None, + error_info: None, + }); if let Some(c) = constraints_normalize { constraints.push(c) } @@ -316,8 +312,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // Add implied bounds from impl header. if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) { for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) { - let result: Result<_, ErrorGuaranteed> = self - .param_env + let result: Result<_, ErrorGuaranteed> = param_env .and(type_op::normalize::Normalize { value: ty }) .fully_perform(self.infcx, span); let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else { @@ -340,7 +335,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { &self.region_bound_pairs, self.implicit_region_bound, param_env, - known_type_outlives_obligations, + &known_type_outlives_obligations, Locations::All(span), span, ConstraintCategory::Internal, diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 7effd5c5a68..bbe2b55d8c4 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -19,7 +19,7 @@ use tracing::{debug, instrument}; use super::{Locations, TypeChecker}; use crate::renumber::RegionCtxt; -use crate::universal_regions::{DefiningTy, UniversalRegions}; +use crate::universal_regions::DefiningTy; impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// Check explicit closure signature annotation, @@ -124,11 +124,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - #[instrument(skip(self, body, universal_regions), level = "debug")] + #[instrument(skip(self, body), level = "debug")] pub(super) fn equate_inputs_and_outputs( &mut self, body: &Body<'tcx>, - universal_regions: &UniversalRegions<'tcx>, normalized_inputs_and_output: &[Ty<'tcx>], ) { let (&normalized_output_ty, normalized_input_tys) = @@ -161,7 +160,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Some(mir_yield_ty) = body.yield_ty() { let yield_span = body.local_decls[RETURN_PLACE].source_info.span; self.equate_normalized_input_or_output( - universal_regions.yield_ty.unwrap(), + self.universal_regions.yield_ty.unwrap(), mir_yield_ty, yield_span, ); @@ -170,7 +169,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Some(mir_resume_ty) = body.resume_ty() { let yield_span = body.local_decls[RETURN_PLACE].source_info.span; self.equate_normalized_input_or_output( - universal_regions.resume_ty.unwrap(), + self.universal_regions.resume_ty.unwrap(), mir_resume_ty, yield_span, ); diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index 84fb36dd32a..20d19a53752 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -32,14 +32,14 @@ pub(super) fn generate<'a, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, elements: &DenseLocationMap, - flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, + flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, ) { debug!("liveness::generate"); let free_regions = regions_that_outlive_free_regions( typeck.infcx.num_region_vars(), - typeck.universal_regions, + &typeck.universal_regions, &typeck.constraints.outlives_constraints, ); let (relevant_live_locals, boring_locals) = @@ -107,7 +107,7 @@ fn regions_that_outlive_free_regions<'tcx>( let rev_region_graph = rev_constraint_graph.region_graph(constraint_set, fr_static); // Stack for the depth-first search. Start out with all the free regions. - let mut stack: Vec<_> = universal_regions.universal_regions().collect(); + let mut stack: Vec<_> = universal_regions.universal_regions_iter().collect(); // Set of all free regions, plus anything that outlives them. Initially // just contains the free regions. diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 72f6a605279..3ec36c16cbf 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -38,7 +38,7 @@ pub(super) fn trace<'a, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, elements: &DenseLocationMap, - flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, + flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, relevant_live_locals: Vec<Local>, boring_locals: Vec<Local>, @@ -113,7 +113,7 @@ struct LivenessContext<'a, 'typeck, 'b, 'tcx> { /// Results of dataflow tracking which variables (and paths) have been /// initialized. - flow_inits: &'a mut ResultsCursor<'b, 'tcx, MaybeInitializedPlaces<'b, 'tcx>>, + flow_inits: ResultsCursor<'b, 'tcx, MaybeInitializedPlaces<'b, 'tcx>>, /// Index indicating where each variable is assigned, used, or /// dropped. @@ -608,7 +608,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { value.visit_with(&mut for_liveness::FreeRegionsVisitor { tcx: typeck.tcx(), - param_env: typeck.param_env, + param_env: typeck.infcx.param_env, op: |r| { let live_region_vid = typeck.universal_regions.to_region_vid(r); @@ -621,6 +621,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,); match typeck + .infcx .param_env .and(DropckOutlives { dropped_ty }) .fully_perform(typeck.infcx, DUMMY_SP) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index ac0219684d8..58a23b9e558 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -118,17 +118,15 @@ mod relate_tys; /// - `elements` -- MIR region map pub(crate) fn type_check<'a, 'tcx>( infcx: &BorrowckInferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, promoted: &IndexSlice<Promoted, Body<'tcx>>, - universal_regions: Rc<UniversalRegions<'tcx>>, + universal_regions: UniversalRegions<'tcx>, location_table: &LocationTable, borrow_set: &BorrowSet<'tcx>, all_facts: &mut Option<AllFacts>, - flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, + flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, elements: Rc<DenseLocationMap>, - upvars: &[&ty::CapturedPlace<'tcx>], ) -> MirTypeckResults<'tcx> { let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); let mut constraints = MirTypeckRegionConstraints { @@ -148,9 +146,9 @@ pub(crate) fn type_check<'a, 'tcx>( known_type_outlives_obligations, } = free_region_relations::create( infcx, - param_env, + infcx.param_env, implicit_region_bound, - Rc::clone(&universal_regions), + universal_regions, &mut constraints, ); @@ -158,29 +156,27 @@ pub(crate) fn type_check<'a, 'tcx>( let mut checker = TypeChecker { infcx, - param_env, last_span: body.span, body, user_type_annotations: &body.user_type_annotations, - region_bound_pairs: ®ion_bound_pairs, + region_bound_pairs, known_type_outlives_obligations, implicit_region_bound, reported_errors: Default::default(), - universal_regions: &universal_regions, + universal_regions: &universal_region_relations.universal_regions, location_table, all_facts, borrow_set, constraints: &mut constraints, - upvars, }; checker.check_user_type_annotations(); - let mut verifier = TypeVerifier::new(&mut checker, promoted); + let mut verifier = TypeVerifier { cx: &mut checker, promoted, last_span: body.span }; verifier.visit_body(body); checker.typeck_mir(body); - checker.equate_inputs_and_outputs(body, &universal_regions, &normalized_inputs_and_output); + checker.equate_inputs_and_outputs(body, &normalized_inputs_and_output); checker.check_signature_annotation(body); liveness::generate(&mut checker, body, &elements, flow_inits, move_data); @@ -467,13 +463,6 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { - fn new( - cx: &'a mut TypeChecker<'b, 'tcx>, - promoted: &'b IndexSlice<Promoted, Body<'tcx>>, - ) -> Self { - TypeVerifier { promoted, last_span: cx.body.span, cx } - } - fn body(&self) -> &Body<'tcx> { self.cx.body } @@ -837,14 +826,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { /// NLL region checking. struct TypeChecker<'a, 'tcx> { infcx: &'a BorrowckInferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, last_span: Span, body: &'a Body<'tcx>, /// User type annotations are shared between the main MIR and the MIR of /// all of the promoted items. user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, - region_bound_pairs: &'a RegionBoundPairs<'tcx>, - known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], + region_bound_pairs: RegionBoundPairs<'tcx>, + known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>, implicit_region_bound: ty::Region<'tcx>, reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, universal_regions: &'a UniversalRegions<'tcx>, @@ -852,7 +840,6 @@ struct TypeChecker<'a, 'tcx> { all_facts: &'a mut Option<AllFacts>, borrow_set: &'a BorrowSet<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, - upvars: &'a [&'a ty::CapturedPlace<'tcx>], } /// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions @@ -1025,10 +1012,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { constraint_conversion::ConstraintConversion::new( self.infcx, self.universal_regions, - self.region_bound_pairs, + &self.region_bound_pairs, self.implicit_region_bound, - self.param_env, - self.known_type_outlives_obligations, + self.infcx.param_env, + &self.known_type_outlives_obligations, locations, locations.span(self.body), category, @@ -1527,9 +1514,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // The signature in this call can reference region variables, // so erase them before calling a query. let output_ty = self.tcx().erase_regions(sig.output()); - if !output_ty - .is_privately_uninhabited(self.tcx(), self.infcx.typing_env(self.param_env)) - { + if !output_ty.is_privately_uninhabited( + self.tcx(), + self.infcx.typing_env(self.infcx.param_env), + ) { span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); } } @@ -1739,7 +1727,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // `Sized` bound in no way depends on precise regions, so this // shouldn't affect `is_sized`. let erased_ty = tcx.erase_regions(ty); - if !erased_ty.is_sized(tcx, self.param_env) { + if !erased_ty.is_sized(tcx, self.infcx.param_env) { // in current MIR construction, all non-control-flow rvalue // expressions evaluate through `as_temp` or `into` a return // slot or local, so to find all unsized rvalues it is enough @@ -2631,8 +2619,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); let tcx = self.infcx.tcx; + let def = self.body.source.def_id().expect_local(); + let upvars = tcx.closure_captures(def); let field = - path_utils::is_upvar_field_projection(tcx, self.upvars, borrowed_place.as_ref(), body); + path_utils::is_upvar_field_projection(tcx, upvars, borrowed_place.as_ref(), body); let category = if let Some(field) = field { ConstraintCategory::ClosureUpvar(field) } else { @@ -2787,10 +2777,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { constraint_conversion::ConstraintConversion::new( self.infcx, self.universal_regions, - self.region_bound_pairs, + &self.region_bound_pairs, self.implicit_region_bound, - self.param_env, - self.known_type_outlives_obligations, + self.infcx.param_env, + &self.known_type_outlives_obligations, locations, self.body.span, // irrelevant; will be overridden. ConstraintCategory::Boring, // same as above. diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index e2f3e065bc0..752b2bf1a24 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -522,7 +522,7 @@ impl<'b, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_ } fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.type_checker.param_env + self.type_checker.infcx.param_env } fn register_predicates( diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index b63144f560f..f1c23aa26a9 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -248,12 +248,8 @@ impl<'tcx> UniversalRegions<'tcx> { /// MIR -- that is, all the regions that appear in the function's /// signature. This will also compute the relationships that are /// known between those regions. - pub(crate) fn new( - infcx: &BorrowckInferCtxt<'tcx>, - mir_def: LocalDefId, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - UniversalRegionsBuilder { infcx, mir_def, param_env }.build() + pub(crate) fn new(infcx: &BorrowckInferCtxt<'tcx>, mir_def: LocalDefId) -> Self { + UniversalRegionsBuilder { infcx, mir_def }.build() } /// Given a reference to a closure type, extracts all the values @@ -312,7 +308,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// Returns an iterator over all the RegionVids corresponding to /// universally quantified free regions. - pub(crate) fn universal_regions(&self) -> impl Iterator<Item = RegionVid> { + pub(crate) fn universal_regions_iter(&self) -> impl Iterator<Item = RegionVid> { (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::from_usize) } @@ -336,7 +332,7 @@ impl<'tcx> UniversalRegions<'tcx> { } /// Gets an iterator over all the early-bound regions that have names. - pub(crate) fn named_universal_regions<'s>( + pub(crate) fn named_universal_regions_iter<'s>( &'s self, ) -> impl Iterator<Item = (ty::Region<'tcx>, ty::RegionVid)> + 's { self.indices.indices.iter().map(|(&r, &v)| (r, v)) @@ -426,7 +422,6 @@ impl<'tcx> UniversalRegions<'tcx> { struct UniversalRegionsBuilder<'infcx, 'tcx> { infcx: &'infcx BorrowckInferCtxt<'tcx>, mir_def: LocalDefId, - param_env: ty::ParamEnv<'tcx>, } const FR: NllRegionVariableOrigin = NllRegionVariableOrigin::FreeRegion; @@ -435,7 +430,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { fn build(self) -> UniversalRegions<'tcx> { debug!("build(mir_def={:?})", self.mir_def); - let param_env = self.param_env; + let param_env = self.infcx.param_env; debug!("build: param_env={:?}", param_env); assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars()); diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index 2f13b0b9cb8..5b3f2a91207 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -38,6 +38,11 @@ local-rebuild = true codegen-backends = ["cranelift"] deny-warnings = false verbose-tests = false +# The cg_clif sysroot doesn't contain llvm tools and unless llvm_tools is +# disabled bootstrap will crash trying to copy llvm tools for the bootstrap +# compiler. +llvm_tools = false + EOF popd diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 6686413bf02..1271d9d2d0d 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -152,13 +152,20 @@ where let span = span.substitute_dummy(our_span); let err = mk(span, frames); let mut err = tcx.dcx().create_err(err); + let can_be_spurious = matches!(error, InterpErrorKind::ResourceExhaustion(_)); let msg = error.diagnostic_message(); error.add_args(&mut err); // Use *our* span to label the interp error err.span_label(our_span, msg); - ErrorHandled::Reported(err.emit().into(), span) + let g = err.emit(); + let reported = if can_be_spurious { + ReportedErrorInfo::spurious(g) + } else { + ReportedErrorInfo::from(g) + }; + ErrorHandled::Reported(reported, span) } } } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 70a696e3e3e..4f413c84615 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -588,6 +588,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // const-eval will return "tainted" errors if e.g. the layout cannot // be computed as the type references non-existing names. // See <https://github.com/rust-lang/rust/issues/124348>. + } else if reported.can_be_spurious() { + // These errors can just sometimes happen, even when the expression + // is nominally "infallible", e.g. when running out of memory. } else { // Looks like the const is not captured by `required_consts`, that's bad. span_bug!(span, "interpret const eval failure of {val:?} which is not in required_consts"); diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index bede4c49703..65d586124b3 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -21,6 +21,7 @@ #![feature(auto_traits)] #![feature(cfg_match)] #![feature(core_intrinsics)] +#![feature(dropck_eyepatch)] #![feature(extend_one)] #![feature(file_buffered)] #![feature(hash_raw_entry)] @@ -78,6 +79,7 @@ pub mod thinvec; pub mod transitive_relation; pub mod unhash; pub mod unord; +pub mod vec_cache; pub mod work_queue; mod atomic_ref; diff --git a/compiler/rustc_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs new file mode 100644 index 00000000000..eb251b587c8 --- /dev/null +++ b/compiler/rustc_data_structures/src/vec_cache.rs @@ -0,0 +1,324 @@ +//! VecCache maintains a mapping from K -> (V, I) pairing. K and I must be roughly u32-sized, and V +//! must be Copy. +//! +//! VecCache supports efficient concurrent put/get across the key space, with write-once semantics +//! (i.e., a given key can only be put once). Subsequent puts will panic. +//! +//! This is currently used for query caching. + +use std::fmt::Debug; +use std::marker::PhantomData; +use std::sync::atomic::{AtomicPtr, AtomicU32, AtomicUsize, Ordering}; + +use rustc_index::Idx; + +struct Slot<V> { + // We never construct &Slot<V> so it's fine for this to not be in an UnsafeCell. + value: V, + // This is both an index and a once-lock. + // + // 0: not yet initialized. + // 1: lock held, initializing. + // 2..u32::MAX - 2: initialized. + index_and_lock: AtomicU32, +} + +/// This uniquely identifies a single `Slot<V>` entry in the buckets map, and provides accessors for +/// either getting the value or putting a value. +#[derive(Copy, Clone, Debug)] +struct SlotIndex { + // the index of the bucket in VecCache (0 to 20) + bucket_idx: usize, + // number of entries in that bucket + entries: usize, + // the index of the slot within the bucket + index_in_bucket: usize, +} + +// This makes sure the counts are consistent with what we allocate, precomputing each bucket a +// compile-time. Visiting all powers of two is enough to hit all the buckets. +// +// We confirm counts are accurate in the slot_index_exhaustive test. +const ENTRIES_BY_BUCKET: [usize; 21] = { + let mut entries = [0; 21]; + let mut key = 0; + loop { + let si = SlotIndex::from_index(key); + entries[si.bucket_idx] = si.entries; + if key == 0 { + key = 1; + } else if key == (1 << 31) { + break; + } else { + key <<= 1; + } + } + entries +}; + +impl SlotIndex { + // This unpacks a flat u32 index into identifying which bucket it belongs to and the offset + // within that bucket. As noted in the VecCache docs, buckets double in size with each index. + // Typically that would mean 31 buckets (2^0 + 2^1 ... + 2^31 = u32::MAX - 1), but to reduce + // the size of the VecCache struct and avoid uselessly small allocations, we instead have the + // first bucket have 2**12 entries. To simplify the math, the second bucket also 2**12 entries, + // and buckets double from there. + // + // We assert that [0, 2**32 - 1] uniquely map through this function to individual, consecutive + // slots (see `slot_index_exhaustive` in tests). + #[inline] + const fn from_index(idx: u32) -> Self { + let mut bucket = match idx.checked_ilog2() { + Some(x) => x as usize, + None => 0, + }; + let entries; + let running_sum; + if bucket <= 11 { + entries = 1 << 12; + running_sum = 0; + bucket = 0; + } else { + entries = 1 << bucket; + running_sum = entries; + bucket = bucket - 11; + } + SlotIndex { bucket_idx: bucket, entries, index_in_bucket: idx as usize - running_sum } + } + + // SAFETY: Buckets must be managed solely by functions here (i.e., get/put on SlotIndex) and + // `self` comes from SlotIndex::from_index + #[inline] + unsafe fn get<V: Copy>(&self, buckets: &[AtomicPtr<Slot<V>>; 21]) -> Option<(V, u32)> { + // SAFETY: `bucket_idx` is ilog2(u32).saturating_sub(11), which is at most 21, i.e., + // in-bounds of buckets. See `from_index` for computation. + let bucket = unsafe { buckets.get_unchecked(self.bucket_idx) }; + let ptr = bucket.load(Ordering::Acquire); + // Bucket is not yet initialized: then we obviously won't find this entry in that bucket. + if ptr.is_null() { + return None; + } + assert!(self.index_in_bucket < self.entries); + // SAFETY: `bucket` was allocated (so <= isize in total bytes) to hold `entries`, so this + // must be inbounds. + let slot = unsafe { ptr.add(self.index_in_bucket) }; + + // SAFETY: initialized bucket has zeroed all memory within the bucket, so we are valid for + // AtomicU32 access. + let index_and_lock = unsafe { &(*slot).index_and_lock }; + let current = index_and_lock.load(Ordering::Acquire); + let index = match current { + 0 => return None, + // Treat "initializing" as actually just not initialized at all. + // The only reason this is a separate state is that `complete` calls could race and + // we can't allow that, but from load perspective there's no difference. + 1 => return None, + _ => current - 2, + }; + + // SAFETY: + // * slot is a valid pointer (buckets are always valid for the index we get). + // * value is initialized since we saw a >= 2 index above. + // * `V: Copy`, so safe to read. + let value = unsafe { (*slot).value }; + Some((value, index)) + } + + fn bucket_ptr<V>(&self, bucket: &AtomicPtr<Slot<V>>) -> *mut Slot<V> { + let ptr = bucket.load(Ordering::Acquire); + if ptr.is_null() { self.initialize_bucket(bucket) } else { ptr } + } + + #[cold] + fn initialize_bucket<V>(&self, bucket: &AtomicPtr<Slot<V>>) -> *mut Slot<V> { + static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(()); + + // If we are initializing the bucket, then acquire a global lock. + // + // This path is quite cold, so it's cheap to use a global lock. This ensures that we never + // have multiple allocations for the same bucket. + let _allocator_guard = LOCK.lock().unwrap_or_else(|e| e.into_inner()); + + let ptr = bucket.load(Ordering::Acquire); + + // OK, now under the allocator lock, if we're still null then it's definitely us that will + // initialize this bucket. + if ptr.is_null() { + let bucket_layout = + std::alloc::Layout::array::<Slot<V>>(self.entries as usize).unwrap(); + // This is more of a sanity check -- this code is very cold, so it's safe to pay a + // little extra cost here. + assert!(bucket_layout.size() > 0); + // SAFETY: Just checked that size is non-zero. + let allocated = unsafe { std::alloc::alloc_zeroed(bucket_layout).cast::<Slot<V>>() }; + if allocated.is_null() { + std::alloc::handle_alloc_error(bucket_layout); + } + bucket.store(allocated, Ordering::Release); + allocated + } else { + // Otherwise some other thread initialized this bucket after we took the lock. In that + // case, just return early. + ptr + } + } + + /// Returns true if this successfully put into the map. + #[inline] + fn put<V>(&self, buckets: &[AtomicPtr<Slot<V>>; 21], value: V, extra: u32) -> bool { + // SAFETY: `bucket_idx` is ilog2(u32).saturating_sub(11), which is at most 21, i.e., + // in-bounds of buckets. + let bucket = unsafe { buckets.get_unchecked(self.bucket_idx) }; + let ptr = self.bucket_ptr(bucket); + + assert!(self.index_in_bucket < self.entries); + // SAFETY: `bucket` was allocated (so <= isize in total bytes) to hold `entries`, so this + // must be inbounds. + let slot = unsafe { ptr.add(self.index_in_bucket) }; + + // SAFETY: initialized bucket has zeroed all memory within the bucket, so we are valid for + // AtomicU32 access. + let index_and_lock = unsafe { &(*slot).index_and_lock }; + match index_and_lock.compare_exchange(0, 1, Ordering::AcqRel, Ordering::Acquire) { + Ok(_) => { + // We have acquired the initialization lock. It is our job to write `value` and + // then set the lock to the real index. + + unsafe { + (&raw mut (*slot).value).write(value); + } + + index_and_lock.store(extra.checked_add(2).unwrap(), Ordering::Release); + + true + } + + // Treat "initializing" as the caller's fault. Callers are responsible for ensuring that + // there are no races on initialization. In the compiler's current usage for query + // caches, that's the "active query map" which ensures each query actually runs once + // (even if concurrently started). + Err(1) => panic!("caller raced calls to put()"), + + // This slot was already populated. Also ignore, currently this is the same as + // "initializing". + Err(_) => false, + } + } +} + +pub struct VecCache<K: Idx, V, I> { + // Entries per bucket: + // Bucket 0: 4096 2^12 + // Bucket 1: 4096 2^12 + // Bucket 2: 8192 + // Bucket 3: 16384 + // ... + // Bucket 19: 1073741824 + // Bucket 20: 2147483648 + // The total number of entries if all buckets are initialized is u32::MAX-1. + buckets: [AtomicPtr<Slot<V>>; 21], + + // In the compiler's current usage these are only *read* during incremental and self-profiling. + // They are an optimization over iterating the full buckets array. + present: [AtomicPtr<Slot<()>>; 21], + len: AtomicUsize, + + key: PhantomData<(K, I)>, +} + +impl<K: Idx, V, I> Default for VecCache<K, V, I> { + fn default() -> Self { + VecCache { + buckets: Default::default(), + key: PhantomData, + len: Default::default(), + present: Default::default(), + } + } +} + +// SAFETY: No access to `V` is made. +unsafe impl<K: Idx, #[may_dangle] V, I> Drop for VecCache<K, V, I> { + fn drop(&mut self) { + // We have unique ownership, so no locks etc. are needed. Since `K` and `V` are both `Copy`, + // we are also guaranteed to just need to deallocate any large arrays (not iterate over + // contents). + // + // Confirm no need to deallocate invidual entries. Note that `V: Copy` is asserted on + // insert/lookup but not necessarily construction, primarily to avoid annoyingly propagating + // the bounds into struct definitions everywhere. + assert!(!std::mem::needs_drop::<K>()); + assert!(!std::mem::needs_drop::<V>()); + + for (idx, bucket) in self.buckets.iter().enumerate() { + let bucket = bucket.load(Ordering::Acquire); + if !bucket.is_null() { + let layout = std::alloc::Layout::array::<Slot<V>>(ENTRIES_BY_BUCKET[idx]).unwrap(); + unsafe { + std::alloc::dealloc(bucket.cast(), layout); + } + } + } + + for (idx, bucket) in self.present.iter().enumerate() { + let bucket = bucket.load(Ordering::Acquire); + if !bucket.is_null() { + let layout = std::alloc::Layout::array::<Slot<()>>(ENTRIES_BY_BUCKET[idx]).unwrap(); + unsafe { + std::alloc::dealloc(bucket.cast(), layout); + } + } + } + } +} + +impl<K, V, I> VecCache<K, V, I> +where + K: Eq + Idx + Copy + Debug, + V: Copy, + I: Idx + Copy, +{ + #[inline(always)] + pub fn lookup(&self, key: &K) -> Option<(V, I)> { + let key = u32::try_from(key.index()).unwrap(); + let slot_idx = SlotIndex::from_index(key); + match unsafe { slot_idx.get(&self.buckets) } { + Some((value, idx)) => Some((value, I::new(idx as usize))), + None => None, + } + } + + #[inline] + pub fn complete(&self, key: K, value: V, index: I) { + let key = u32::try_from(key.index()).unwrap(); + let slot_idx = SlotIndex::from_index(key); + if slot_idx.put(&self.buckets, value, index.index() as u32) { + let present_idx = self.len.fetch_add(1, Ordering::Relaxed); + let slot = SlotIndex::from_index(present_idx as u32); + // We should always be uniquely putting due to `len` fetch_add returning unique values. + assert!(slot.put(&self.present, (), key)); + } + } + + pub fn iter(&self, f: &mut dyn FnMut(&K, &V, I)) { + for idx in 0..self.len.load(Ordering::Acquire) { + let key = SlotIndex::from_index(idx as u32); + match unsafe { key.get(&self.present) } { + // This shouldn't happen in our current usage (iter is really only + // used long after queries are done running), but if we hit this in practice it's + // probably fine to just break early. + None => unreachable!(), + Some(((), key)) => { + let key = K::new(key as usize); + // unwrap() is OK: present entries are always written only after we put the real + // entry. + let value = self.lookup(&key).unwrap(); + f(&key, &value.0, value.1); + } + } + } + } +} + +#[cfg(test)] +mod tests; diff --git a/compiler/rustc_data_structures/src/vec_cache/tests.rs b/compiler/rustc_data_structures/src/vec_cache/tests.rs new file mode 100644 index 00000000000..a05f2741362 --- /dev/null +++ b/compiler/rustc_data_structures/src/vec_cache/tests.rs @@ -0,0 +1,95 @@ +use super::*; + +#[test] +#[cfg(not(miri))] +fn vec_cache_empty() { + let cache: VecCache<u32, u32, u32> = VecCache::default(); + for key in 0..u32::MAX { + assert!(cache.lookup(&key).is_none()); + } +} + +#[test] +fn vec_cache_insert_and_check() { + let cache: VecCache<u32, u32, u32> = VecCache::default(); + cache.complete(0, 1, 2); + assert_eq!(cache.lookup(&0), Some((1, 2))); +} + +#[test] +fn sparse_inserts() { + let cache: VecCache<u32, u8, u32> = VecCache::default(); + let end = if cfg!(target_pointer_width = "64") && cfg!(target_os = "linux") { + // For paged memory, 64-bit systems we should be able to sparsely allocate all of the pages + // needed for these inserts cheaply (without needing to actually have gigabytes of resident + // memory). + 31 + } else { + // Otherwise, still run the test but scaled back: + // + // Each slot is 5 bytes, so 2^25 entries (on non-virtual memory systems, like e.g. Windows) will + // mean 160 megabytes of allocated memory. Going beyond that is probably not reasonable for + // tests. + 25 + }; + for shift in 0..end { + let key = 1u32 << shift; + cache.complete(key, shift, key); + assert_eq!(cache.lookup(&key), Some((shift, key))); + } +} + +#[test] +fn concurrent_stress_check() { + let cache: VecCache<u32, u32, u32> = VecCache::default(); + std::thread::scope(|s| { + for idx in 0..100 { + let cache = &cache; + s.spawn(move || { + cache.complete(idx, idx, idx); + }); + } + }); + + for idx in 0..100 { + assert_eq!(cache.lookup(&idx), Some((idx, idx))); + } +} + +#[test] +fn slot_entries_table() { + assert_eq!(ENTRIES_BY_BUCKET, [ + 4096, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, + 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, + 2147483648 + ]); +} + +#[test] +#[cfg(not(miri))] +fn slot_index_exhaustive() { + let mut buckets = [0u32; 21]; + for idx in 0..=u32::MAX { + buckets[SlotIndex::from_index(idx).bucket_idx] += 1; + } + let mut prev = None::<SlotIndex>; + for idx in 0..=u32::MAX { + let slot_idx = SlotIndex::from_index(idx); + if let Some(p) = prev { + if p.bucket_idx == slot_idx.bucket_idx { + assert_eq!(p.index_in_bucket + 1, slot_idx.index_in_bucket); + } else { + assert_eq!(slot_idx.index_in_bucket, 0); + } + } else { + assert_eq!(idx, 0); + assert_eq!(slot_idx.index_in_bucket, 0); + assert_eq!(slot_idx.bucket_idx, 0); + } + + assert_eq!(buckets[slot_idx.bucket_idx], slot_idx.entries as u32); + assert_eq!(ENTRIES_BY_BUCKET[slot_idx.bucket_idx], slot_idx.entries, "{}", idx); + + prev = Some(slot_idx); + } +} diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index a67a5776449..2acebebb419 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -529,6 +529,8 @@ declare_features! ( (unstable, macro_metavar_expr_concat, "1.81.0", Some(124225)), /// Allows `#[marker]` on certain traits allowing overlapping implementations. (unstable, marker_trait_attr, "1.30.0", Some(29864)), + /// Enables the generic const args MVP (only bare paths, not arbitrary computation). + (incomplete, min_generic_const_args, "CURRENT_RUSTC_VERSION", Some(132980)), /// A minimal, sound subset of specialization intended to be used by the /// standard library until the soundness issues with specialization /// are fixed. diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 63a0e7d31c3..1a925597c6c 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -46,7 +46,7 @@ use tracing::{debug, instrument}; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::errors; -use crate::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; +use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason}; pub(crate) mod dump; mod generics_of; @@ -88,6 +88,7 @@ pub fn provide(providers: &mut Providers) { coroutine_for_closure, opaque_ty_origin, rendered_precise_capturing_args, + const_param_default, ..*providers }; } @@ -1790,3 +1791,23 @@ fn rendered_precise_capturing_args<'tcx>( _ => None, }) } + +fn const_param_default<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> ty::EarlyBinder<'tcx, Const<'tcx>> { + let default_ct = match tcx.hir_node_by_def_id(def_id) { + hir::Node::GenericParam(hir::GenericParam { + kind: hir::GenericParamKind::Const { default: Some(ct), .. }, + .. + }) => ct, + _ => span_bug!( + tcx.def_span(def_id), + "`const_param_default` expected a generic parameter with a constant" + ), + }; + let icx = ItemCtxt::new(tcx, def_id); + // FIXME(const_generics): investigate which places do and don't need const ty feeding + let ct = icx.lowerer().lower_const_arg(default_ct, FeedConstTy::No); + ty::EarlyBinder::bind(ct) +} diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 7ce12d48160..0f37d61beb0 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -223,11 +223,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen trace!(?predicates); } hir::GenericParamKind::Const { .. } => { + let param_def_id = param.def_id.to_def_id(); let ct_ty = tcx - .type_of(param.def_id.to_def_id()) + .type_of(param_def_id) .no_bound_vars() .expect("const parameters cannot be generic"); - let ct = icx.lowerer().lower_const_param(param.hir_id); + let ct = icx.lowerer().lower_const_param(param_def_id, param.hir_id); predicates .insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span)); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 1cade402c54..6ebe1cedcaf 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -19,7 +19,9 @@ use tracing::{debug, instrument}; use super::errors::GenericsArgsErrExtend; use crate::bounds::Bounds; use crate::errors; -use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer, PredicateFilter, RegionInferReason}; +use crate::hir_ty_lowering::{ + AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason, +}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Add a `Sized` bound to the `bounds` if appropriate. @@ -346,9 +348,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::AssocItemConstraintKind::Equality { term } => { let term = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), - hir::Term::Const(ct) => { - ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No).into() - } + hir::Term::Const(ct) => self.lower_const_arg(ct, FeedConstTy::No).into(), }; // Find any late-bound regions declared in `ty` that are not diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 6e8a9ded4f3..ae1279d428c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -115,17 +115,22 @@ fn generic_arg_mismatch_err( } } (GenericArg::Const(cnst), GenericParamDefKind::Type { .. }) => { - // FIXME(min_generic_const_args): once ConstArgKind::Path is used for non-params too, - // this should match against that instead of ::Anon - if let hir::ConstArgKind::Anon(anon) = cnst.kind + if let hir::ConstArgKind::Path(qpath) = cnst.kind + && let rustc_hir::QPath::Resolved(_, path) = qpath + && let Res::Def(DefKind::Fn { .. }, id) = path.res + { + err.help(format!("`{}` is a function item, not a type", tcx.item_name(id))); + err.help("function item types cannot be named directly"); + } else if let hir::ConstArgKind::Anon(anon) = cnst.kind && let body = tcx.hir().body(anon.body) && let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body.value.kind + && let Res::Def(DefKind::Fn { .. }, id) = path.res { - if let Res::Def(DefKind::Fn { .. }, id) = path.res { - err.help(format!("`{}` is a function item, not a type", tcx.item_name(id))); - err.help("function item types cannot be named directly"); - } + // FIXME(min_generic_const_args): this branch is dead once new const path lowering + // (for single-segment paths) is no longer gated + err.help(format!("`{}` is a function item, not a type", tcx.item_name(id))); + err.help("function item types cannot be named directly"); } } _ => {} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index ed39708981b..01276abec22 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -30,7 +30,7 @@ use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err, }; use rustc_hir as hir; -use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; +use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{GenericArg, GenericArgs, HirId}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; @@ -217,6 +217,23 @@ impl AssocItemQSelf { } } +/// In some cases, [`hir::ConstArg`]s that are being used in the type system +/// through const generics need to have their type "fed" to them +/// using the query system. +/// +/// Use this enum with `<dyn HirTyLowerer>::lower_const_arg` to instruct it with the +/// desired behavior. +#[derive(Debug, Clone, Copy)] +pub enum FeedConstTy { + /// Feed the type. + /// + /// The `DefId` belongs to the const param that we are supplying + /// this (anon) const arg to. + Param(DefId), + /// Don't feed the type. + No, +} + /// New-typed boolean indicating whether explicit late-bound lifetimes /// are present in a set of generic arguments. /// @@ -500,8 +517,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { handle_ty_args(has_default, &inf.to_ty()) } (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { - ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::Param(param.def_id)) - .into() + self.lowerer.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into() } (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { self.lowerer.ct_infer(Some(param), inf.span).into() @@ -979,8 +995,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let term: ty::Term<'_> = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), hir::Term::Const(ct) => { - ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No) - .into() + self.lower_const_arg(ct, FeedConstTy::No).into() } }; // FIXME(#97583): This isn't syntactically well-formed! @@ -2025,23 +2040,138 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// Early-bound const parameters get lowered to [`ty::ConstKind::Param`] /// and late-bound ones to [`ty::ConstKind::Bound`]. - pub(crate) fn lower_const_param(&self, hir_id: HirId) -> Const<'tcx> { + pub(crate) fn lower_const_param(&self, param_def_id: DefId, path_hir_id: HirId) -> Const<'tcx> { let tcx = self.tcx(); - match tcx.named_bound_var(hir_id) { - Some(rbv::ResolvedArg::EarlyBound(def_id)) => { + + match tcx.named_bound_var(path_hir_id) { + Some(rbv::ResolvedArg::EarlyBound(_)) => { // Find the name and index of the const parameter by indexing the generics of // the parent item and construct a `ParamConst`. - let item_def_id = tcx.local_parent(def_id); + let item_def_id = tcx.parent(param_def_id); let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id.to_def_id()]; - let name = tcx.item_name(def_id.to_def_id()); + let index = generics.param_def_id_to_index[¶m_def_id]; + let name = tcx.item_name(param_def_id); ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) } Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index)) } Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar), - arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id), + arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", path_hir_id), + } + } + + /// Convert a [`hir::ConstArg`] to a [`ty::Const`](Const). + #[instrument(skip(self), level = "debug")] + pub fn lower_const_arg( + &self, + const_arg: &hir::ConstArg<'tcx>, + feed: FeedConstTy, + ) -> Const<'tcx> { + let tcx = self.tcx(); + + if let FeedConstTy::Param(param_def_id) = feed + && let hir::ConstArgKind::Anon(anon) = &const_arg.kind + { + tcx.feed_anon_const_type(anon.def_id, tcx.type_of(param_def_id)); + } + + let hir_id = const_arg.hir_id; + match const_arg.kind { + hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { + debug!(?maybe_qself, ?path); + let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); + self.lower_const_path_resolved(opt_self_ty, path, hir_id) + } + hir::ConstArgKind::Path(qpath) => ty::Const::new_error_with_message( + tcx, + qpath.span(), + format!("Const::lower_const_arg: invalid qpath {qpath:?}"), + ), + hir::ConstArgKind::Anon(anon) => Const::from_anon_const(tcx, anon.def_id), + } + } + + fn lower_const_path_resolved( + &self, + opt_self_ty: Option<Ty<'tcx>>, + path: &hir::Path<'tcx>, + hir_id: HirId, + ) -> Const<'tcx> { + let tcx = self.tcx(); + let span = path.span; + match path.res { + Res::Def(DefKind::ConstParam, def_id) => { + assert_eq!(opt_self_ty, None); + let _ = self.prohibit_generic_args( + path.segments.iter(), + GenericsArgsErrExtend::Param(def_id), + ); + self.lower_const_param(def_id, hir_id) + } + Res::Def(DefKind::Const | DefKind::Ctor(_, CtorKind::Const), did) => { + assert_eq!(opt_self_ty, None); + let _ = self.prohibit_generic_args( + path.segments.split_last().unwrap().1.iter(), + GenericsArgsErrExtend::None, + ); + let args = self.lower_generic_args_of_path_segment( + span, + did, + path.segments.last().unwrap(), + ); + ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args)) + } + Res::Def(DefKind::Static { .. }, _) => { + span_bug!(span, "use of bare `static` ConstArgKind::Path's not yet supported") + } + // FIXME(const_generics): create real const to allow fn items as const paths + Res::Def(DefKind::Fn | DefKind::AssocFn, _) => ty::Const::new_error_with_message( + tcx, + span, + "fn items cannot be used as const args", + ), + + // Exhaustive match to be clear about what exactly we're considering to be + // an invalid Res for a const path. + Res::Def( + DefKind::Mod + | DefKind::Enum + | DefKind::Variant + | DefKind::Ctor(CtorOf::Variant, CtorKind::Fn) + | DefKind::Struct + | DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) + | DefKind::OpaqueTy + | DefKind::TyAlias + | DefKind::TraitAlias + | DefKind::AssocTy + | DefKind::Union + | DefKind::Trait + | DefKind::ForeignTy + | DefKind::AssocConst + | DefKind::TyParam + | DefKind::Macro(_) + | DefKind::LifetimeParam + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::Field + | DefKind::Impl { .. } + | DefKind::Closure + | DefKind::ExternCrate + | DefKind::GlobalAsm + | DefKind::SyntheticCoroutineBody, + _, + ) + | Res::PrimTy(_) + | Res::SelfTyParam { .. } + | Res::SelfTyAlias { .. } + | Res::SelfCtor(_) + | Res::Local(_) + | Res::ToolMod + | Res::NonMacroAttr(_) + | Res::Err => Const::new_error_with_message(tcx, span, "invalid Res for const path"), } } @@ -2053,14 +2183,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Lower a type from the HIR to our internal notion of a type given some extra data for diagnostics. - /// - /// Extra diagnostic data: - /// - /// 1. `borrowed`: Whether trait object types are borrowed like in `&dyn Trait`. - /// Used to avoid emitting redundant errors. - /// 2. `in_path`: Whether the type appears inside of a path. - /// Used to provide correct diagnostics for bare trait object types. + /// Lower a type from the HIR to our internal notion of a type. #[instrument(level = "debug", skip(self), ret)] pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { let tcx = self.tcx(); @@ -2189,7 +2312,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let length = match length { hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), hir::ArrayLen::Body(constant) => { - ty::Const::from_const_arg(tcx, constant, ty::FeedConstTy::No) + self.lower_const_arg(constant, FeedConstTy::No) } }; @@ -2247,7 +2370,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .type_of(def_id) .no_bound_vars() .expect("const parameter types cannot be generic"); - let ct = self.lower_const_param(expr.hir_id); + let ct = self.lower_const_param(def_id, expr.hir_id); (ct, ty) } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 5830636c6e8..564e45c677d 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -97,12 +97,14 @@ use rustc_hir::def::DefKind; use rustc_middle::middle; use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::parse::feature_err; use rustc_span::Span; use rustc_span::symbol::sym; use rustc_trait_selection::traits; +use self::hir_ty_lowering::{FeedConstTy, HirTyLowerer}; + rustc_fluent_macro::fluent_messages! { "../messages.ftl" } fn require_c_abi_if_c_variadic( @@ -226,3 +228,14 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id); collect::ItemCtxt::new(tcx, env_def_id.def_id).lower_ty(hir_ty) } + +/// This is for rustdoc. +// FIXME(const_generics): having special methods for rustdoc in `rustc_hir_analysis` is cursed +pub fn lower_const_arg_for_rustdoc<'tcx>( + tcx: TyCtxt<'tcx>, + hir_ct: &hir::ConstArg<'tcx>, + feed: FeedConstTy, +) -> Const<'tcx> { + let env_def_id = tcx.hir().get_parent_item(hir_ct.hir_id); + collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed) +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index f0738491609..ce6ce0381a9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -14,8 +14,8 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{ check_generic_arg_count_for_call, lower_generic_args, }; use rustc_hir_analysis::hir_ty_lowering::{ - ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer, - GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, + ExplicitLateBound, FeedConstTy, GenericArgCountMismatch, GenericArgCountResult, + GenericArgsLowerer, GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, }; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; @@ -491,7 +491,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), hir::ArrayLen::Body(const_arg) => { let span = const_arg.span(); - let c = ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::No); + let c = self.lowerer().lower_const_arg(const_arg, FeedConstTy::No); self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None)); self.normalize(span, c) } @@ -503,8 +503,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { const_arg: &'tcx hir::ConstArg<'tcx>, param_def_id: DefId, ) -> ty::Const<'tcx> { - let ct = - ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::Param(param_def_id)); + let ct = self.lowerer().lower_const_arg(const_arg, FeedConstTy::Param(param_def_id)); self.register_wf_obligation( ct.into(), self.tcx.hir().span(const_arg.hir_id), diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 7e629c1d18f..43a98782016 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use std::sync::{Arc, LazyLock}; use std::{env, fs, iter}; -use rustc_ast::{self as ast, visit}; +use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; use rustc_data_structures::steal::Steal; @@ -24,7 +24,7 @@ use rustc_middle::util::Providers; use rustc_parse::{ new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr, }; -use rustc_passes::{abi_test, hir_stats, layout_test}; +use rustc_passes::{abi_test, input_stats, layout_test}; use rustc_resolve::Resolver; use rustc_session::code_stats::VTableSizeInfo; use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; @@ -54,28 +54,17 @@ pub(crate) fn parse<'a>(sess: &'a Session) -> Result<ast::Crate> { }) .map_err(|parse_error| parse_error.emit())?; - if sess.opts.unstable_opts.input_stats { - eprintln!("Lines of code: {}", sess.source_map().count_lines()); - eprintln!("Pre-expansion node count: {}", count_nodes(&krate)); - } - if let Some(ref s) = sess.opts.unstable_opts.show_span { rustc_ast_passes::show_span::run(sess.dcx(), s, &krate); } - if sess.opts.unstable_opts.hir_stats { - hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1"); + if sess.opts.unstable_opts.input_stats { + input_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1"); } Ok(krate) } -fn count_nodes(krate: &ast::Crate) -> usize { - let mut counter = rustc_ast_passes::node_count::NodeCounter::new(); - visit::walk_crate(&mut counter, krate); - counter.count -} - fn pre_expansion_lint<'a>( sess: &Session, features: &Features, @@ -290,11 +279,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { let mut lint_buffer = resolver.lint_buffer.steal(); if sess.opts.unstable_opts.input_stats { - eprintln!("Post-expansion node count: {}", count_nodes(krate)); - } - - if sess.opts.unstable_opts.hir_stats { - hir_stats::print_ast_stats(krate, "POST EXPANSION AST STATS", "ast-stats-2"); + input_stats::print_ast_stats(krate, "POST EXPANSION AST STATS", "ast-stats-2"); } // Needs to go *after* expansion to be able to check the results of macro expansion. @@ -820,8 +805,8 @@ pub(crate) fn create_global_ctxt<'tcx>( /// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses. /// This function never fails. fn run_required_analyses(tcx: TyCtxt<'_>) { - if tcx.sess.opts.unstable_opts.hir_stats { - rustc_passes::hir_stats::print_hir_stats(tcx); + if tcx.sess.opts.unstable_opts.input_stats { + rustc_passes::input_stats::print_hir_stats(tcx); } #[cfg(debug_assertions)] rustc_passes::hir_id_validator::check_crate(tcx); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 2361231b3fb..e48c4d46b59 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -698,7 +698,6 @@ fn test_unstable_options_tracking_hash() { untracked!(dylib_lto, true); untracked!(emit_stack_sizes, true); untracked!(future_incompat_test, true); - untracked!(hir_stats, true); untracked!(identify_regions, true); untracked!(incremental_info, true); untracked!(incremental_verify_ich, true); diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index f9f2a14dbd2..bcb103957ba 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -57,11 +57,10 @@ impl Token { /// Enum representing common lexeme types. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum TokenKind { - // Multi-char tokens: - /// "// comment" + /// A line comment, e.g. `// comment`. LineComment { doc_style: Option<DocStyle> }, - /// `/* block comment */` + /// A block comment, e.g. `/* block comment */`. /// /// Block comments can be recursive, so a sequence like `/* /* */` /// will not be considered terminated and will result in a parsing error. @@ -70,18 +69,17 @@ pub enum TokenKind { /// Any whitespace character sequence. Whitespace, - /// "ident" or "continue" - /// - /// At this step, keywords are also considered identifiers. + /// An identifier or keyword, e.g. `ident` or `continue`. Ident, - /// Like the above, but containing invalid unicode codepoints. + /// An identifier that is invalid because it contains emoji. InvalidIdent, - /// "r#ident" + /// A raw identifier, e.g. "r#ident". RawIdent, - /// An unknown prefix, like `foo#`, `foo'`, `foo"`. + /// An unknown literal prefix, like `foo#`, `foo'`, `foo"`. Excludes + /// literal prefixes that contain emoji, which are considered "invalid". /// /// Note that only the /// prefix (`foo`) is included in the token, not the separator (which is @@ -93,87 +91,83 @@ pub enum TokenKind { /// An unknown prefix in a lifetime, like `'foo#`. /// - /// Note that like above, only the `'` and prefix are included in the token + /// Like `UnknownPrefix`, only the `'` and prefix are included in the token /// and not the separator. UnknownPrefixLifetime, - /// `'r#lt`, which in edition < 2021 is split into several tokens: `'r # lt`. + /// A raw lifetime, e.g. `'r#foo`. In edition < 2021 it will be split into + /// several tokens: `'r` and `#` and `foo`. RawLifetime, - /// Similar to the above, but *always* an error on every edition. This is used - /// for emoji identifier recovery, as those are not meant to be ever accepted. - InvalidPrefix, - /// Guarded string literal prefix: `#"` or `##`. /// /// Used for reserving "guarded strings" (RFC 3598) in edition 2024. /// Split into the component tokens on older editions. GuardedStrPrefix, - /// Examples: `12u8`, `1.0e-40`, `b"123"`. Note that `_` is an invalid + /// Literals, e.g. `12u8`, `1.0e-40`, `b"123"`. Note that `_` is an invalid /// suffix, but may be present here on string and float literals. Users of /// this type will need to check for and reject that case. /// /// See [LiteralKind] for more details. Literal { kind: LiteralKind, suffix_start: u32 }, - /// "'a" + /// A lifetime, e.g. `'a`. Lifetime { starts_with_number: bool }, - // One-char tokens: - /// ";" + /// `;` Semi, - /// "," + /// `,` Comma, - /// "." + /// `.` Dot, - /// "(" + /// `(` OpenParen, - /// ")" + /// `)` CloseParen, - /// "{" + /// `{` OpenBrace, - /// "}" + /// `}` CloseBrace, - /// "[" + /// `[` OpenBracket, - /// "]" + /// `]` CloseBracket, - /// "@" + /// `@` At, - /// "#" + /// `#` Pound, - /// "~" + /// `~` Tilde, - /// "?" + /// `?` Question, - /// ":" + /// `:` Colon, - /// "$" + /// `$` Dollar, - /// "=" + /// `=` Eq, - /// "!" + /// `!` Bang, - /// "<" + /// `<` Lt, - /// ">" + /// `>` Gt, - /// "-" + /// `-` Minus, - /// "&" + /// `&` And, - /// "|" + /// `|` Or, - /// "+" + /// `+` Plus, - /// "*" + /// `*` Star, - /// "/" + /// `/` Slash, - /// "^" + /// `^` Caret, - /// "%" + /// `%` Percent, /// Unknown token, not expected by the lexer, e.g. "â„–" @@ -468,7 +462,7 @@ impl Cursor<'_> { Literal { kind, suffix_start } } // Identifier starting with an emoji. Only lexed for graceful error recovery. - c if !c.is_ascii() && c.is_emoji_char() => self.fake_ident_or_unknown_prefix(), + c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(), _ => Unknown, }; let res = Token::new(token_kind, self.pos_within_token()); @@ -552,24 +546,22 @@ impl Cursor<'_> { // we see a prefix here, it is definitely an unknown prefix. match self.first() { '#' | '"' | '\'' => UnknownPrefix, - c if !c.is_ascii() && c.is_emoji_char() => self.fake_ident_or_unknown_prefix(), + c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(), _ => Ident, } } - fn fake_ident_or_unknown_prefix(&mut self) -> TokenKind { + fn invalid_ident(&mut self) -> TokenKind { // Start is already eaten, eat the rest of identifier. self.eat_while(|c| { - unicode_xid::UnicodeXID::is_xid_continue(c) - || (!c.is_ascii() && c.is_emoji_char()) - || c == '\u{200d}' + const ZERO_WIDTH_JOINER: char = '\u{200d}'; + is_id_continue(c) || (!c.is_ascii() && c.is_emoji_char()) || c == ZERO_WIDTH_JOINER }); - // Known prefixes must have been handled earlier. So if - // we see a prefix here, it is definitely an unknown prefix. - match self.first() { - '#' | '"' | '\'' => InvalidPrefix, - _ => InvalidIdent, - } + // An invalid identifier followed by '#' or '"' or '\'' could be + // interpreted as an invalid literal prefix. We don't bother doing that + // because the treatment of invalid identifiers and invalid prefixes + // would be the same. + InvalidIdent } fn c_or_byte_string( diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index efdb4b077e9..313a7badf19 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3185,6 +3185,7 @@ declare_lint! { pub UNEXPECTED_CFGS, Warn, "detects unexpected names and values in `#[cfg]` conditions", + report_in_external_macro } declare_lint! { diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 8ec7e1851a5..08afa33c6b4 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -59,22 +59,33 @@ impl ErrorHandled { pub struct ReportedErrorInfo { error: ErrorGuaranteed, is_tainted_by_errors: bool, + /// Whether this is the kind of error that can sometimes occur, and sometimes not. + /// Used for resource exhaustion errors. + can_be_spurious: bool, } impl ReportedErrorInfo { #[inline] pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo { - ReportedErrorInfo { is_tainted_by_errors: true, error } + ReportedErrorInfo { is_tainted_by_errors: true, can_be_spurious: false, error } } + #[inline] + pub fn spurious(error: ErrorGuaranteed) -> ReportedErrorInfo { + ReportedErrorInfo { can_be_spurious: true, is_tainted_by_errors: false, error } + } + pub fn is_tainted_by_errors(&self) -> bool { self.is_tainted_by_errors } + pub fn can_be_spurious(&self) -> bool { + self.can_be_spurious + } } impl From<ErrorGuaranteed> for ReportedErrorInfo { #[inline] fn from(error: ErrorGuaranteed) -> ReportedErrorInfo { - ReportedErrorInfo { is_tainted_by_errors: false, error } + ReportedErrorInfo { is_tainted_by_errors: false, can_be_spurious: false, error } } } diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 9cb11cdd3b7..d2fab8e78d5 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -2,6 +2,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId}; use rustc_hir::hir_id::{HirId, OwnerId}; +use rustc_query_system::dep_graph::DepNodeIndex; use rustc_query_system::query::{DefIdCache, DefaultCache, SingleCache, VecCache}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{DUMMY_SP, Span}; @@ -111,7 +112,7 @@ impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { } impl Key for CrateNum { - type Cache<V> = VecCache<Self, V>; + type Cache<V> = VecCache<Self, V, DepNodeIndex>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -128,7 +129,7 @@ impl AsLocalKey for CrateNum { } impl Key for OwnerId { - type Cache<V> = VecCache<Self, V>; + type Cache<V> = VecCache<Self, V, DepNodeIndex>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) @@ -140,7 +141,7 @@ impl Key for OwnerId { } impl Key for LocalDefId { - type Cache<V> = VecCache<Self, V>; + type Cache<V> = VecCache<Self, V, DepNodeIndex>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 3bd09fc91c6..d853edb34c9 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,13 +1,14 @@ +use std::borrow::Cow; + use rustc_data_structures::intern::Interned; use rustc_error_messages::MultiSpan; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, HirId}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{self as hir}; use rustc_macros::HashStable; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; use tracing::{debug, instrument}; -use crate::middle::resolve_bound_vars as rbv; use crate::mir::interpret::{LitToConstInput, Scalar}; use crate::ty::{self, GenericArgs, Ty, TyCtxt, TypeVisitableExt}; @@ -142,7 +143,7 @@ impl<'tcx> Const<'tcx> { pub fn new_error_with_message<S: Into<MultiSpan>>( tcx: TyCtxt<'tcx>, span: S, - msg: &'static str, + msg: impl Into<Cow<'static, str>>, ) -> Const<'tcx> { let reported = tcx.dcx().span_delayed_bug(span, msg); Const::new_error(tcx, reported) @@ -183,46 +184,8 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> { } } -/// In some cases, [`hir::ConstArg`]s that are being used in the type system -/// through const generics need to have their type "fed" to them -/// using the query system. -/// -/// Use this enum with [`Const::from_const_arg`] to instruct it with the -/// desired behavior. -#[derive(Debug, Clone, Copy)] -pub enum FeedConstTy { - /// Feed the type. - /// - /// The `DefId` belongs to the const param that we are supplying - /// this (anon) const arg to. - Param(DefId), - /// Don't feed the type. - No, -} - impl<'tcx> Const<'tcx> { - /// Convert a [`hir::ConstArg`] to a [`ty::Const`](Self). - #[instrument(skip(tcx), level = "debug")] - pub fn from_const_arg( - tcx: TyCtxt<'tcx>, - const_arg: &'tcx hir::ConstArg<'tcx>, - feed: FeedConstTy, - ) -> Self { - if let FeedConstTy::Param(param_def_id) = feed - && let hir::ConstArgKind::Anon(anon) = &const_arg.kind - { - tcx.feed_anon_const_type(anon.def_id, tcx.type_of(param_def_id)); - } - - match const_arg.kind { - hir::ConstArgKind::Path(qpath) => { - // FIXME(min_generic_const_args): for now only params are lowered to ConstArgKind::Path - Self::from_param(tcx, qpath, const_arg.hir_id) - } - hir::ConstArgKind::Anon(anon) => Self::from_anon_const(tcx, anon.def_id), - } - } - + // FIXME: move this and try_from_lit to hir_ty_lowering like lower_const_arg/from_const_arg /// Literals and const generic parameters are eagerly converted to a constant, everything else /// becomes `Unevaluated`. #[instrument(skip(tcx), level = "debug")] @@ -240,7 +203,7 @@ impl<'tcx> Const<'tcx> { let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic"); - match Self::try_from_lit_or_param(tcx, ty, expr) { + match Self::try_from_lit(tcx, ty, expr) { Some(v) => v, None => ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst { def: def.to_def_id(), @@ -249,40 +212,8 @@ impl<'tcx> Const<'tcx> { } } - /// Lower a const param to a [`Const`]. - /// - /// IMPORTANT: `qpath` must be a const param, otherwise this will panic - fn from_param(tcx: TyCtxt<'tcx>, qpath: hir::QPath<'tcx>, hir_id: HirId) -> Self { - let hir::QPath::Resolved(_, &hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. }) = - qpath - else { - span_bug!(qpath.span(), "non-param {qpath:?} passed to Const::from_param") - }; - - match tcx.named_bound_var(hir_id) { - Some(rbv::ResolvedArg::EarlyBound(_)) => { - // Find the name and index of the const parameter by indexing the generics of - // the parent item and construct a `ParamConst`. - let item_def_id = tcx.parent(def_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - let name = tcx.item_name(def_id); - ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) - } - Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { - ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index)) - } - Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar), - arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id), - } - } - #[instrument(skip(tcx), level = "debug")] - fn try_from_lit_or_param( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - expr: &'tcx hir::Expr<'tcx>, - ) -> Option<Self> { + fn try_from_lit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>) -> Option<Self> { // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments // currently have to be wrapped in curly brackets, so it's necessary to special-case. let expr = match &expr.kind { @@ -321,7 +252,7 @@ impl<'tcx> Const<'tcx> { Err(e) => { tcx.dcx().span_delayed_bug( expr.span, - format!("Const::from_anon_const: couldn't lit_to_const {e:?}"), + format!("Const::try_from_lit: couldn't lit_to_const {e:?}"), ); } } @@ -414,20 +345,3 @@ impl<'tcx> Const<'tcx> { matches!(self.kind(), ty::ConstKind::Infer(_)) } } - -pub fn const_param_default<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, -) -> ty::EarlyBinder<'tcx, Const<'tcx>> { - let default_ct = match tcx.hir_node_by_def_id(def_id) { - hir::Node::GenericParam(hir::GenericParam { - kind: hir::GenericParamKind::Const { default: Some(ct), .. }, - .. - }) => ct, - _ => span_bug!( - tcx.def_span(def_id), - "`const_param_default` expected a generic parameter with a constant" - ), - }; - ty::EarlyBinder::bind(Const::from_const_arg(tcx, default_ct, FeedConstTy::No)) -} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2ba1bf2822f..68c3b064eee 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -30,7 +30,7 @@ use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan, }; use rustc_hir as hir; -use rustc_hir::def::DefKind; +use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::definitions::Definitions; use rustc_hir::intravisit::Visitor; @@ -230,7 +230,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> { DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy, DefKind::TyAlias => ty::AliasTermKind::WeakTy, DefKind::AssocConst => ty::AliasTermKind::ProjectionConst, - DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst, + DefKind::AnonConst | DefKind::Const | DefKind::Ctor(_, CtorKind::Const) => { + ty::AliasTermKind::UnevaluatedConst + } kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index cddd6110c23..965a8c8c95e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -62,7 +62,7 @@ pub use self::closure::{ place_to_string_for_capture, }; pub use self::consts::{ - Const, ConstInt, ConstKind, Expr, ExprKind, FeedConstTy, ScalarInt, UnevaluatedConst, ValTree, + Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, @@ -2249,7 +2249,6 @@ pub fn provide(providers: &mut Providers) { incoherent_impls: trait_def::incoherent_impls_provider, trait_impls_in_crate: trait_def::trait_impls_in_crate_provider, traits: trait_def::traits_provider, - const_param_default: consts::const_param_default, vtable_allocation: vtable::vtable_allocation_provider, ..*providers }; diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 226de65445c..5023e83bd67 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -213,7 +213,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let ident = Symbol::intern(lifetime_name); token::Lifetime(ident, IdentIsRaw::No) } - rustc_lexer::TokenKind::InvalidIdent | rustc_lexer::TokenKind::InvalidPrefix + rustc_lexer::TokenKind::InvalidIdent // Do not recover an identifier with emoji if the codepoint is a confusable // with a recoverable substitution token, like `âž–`. if !UNICODE_ARRAY.iter().any(|&(c, _, _)| { @@ -359,8 +359,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent), rustc_lexer::TokenKind::Unknown - | rustc_lexer::TokenKind::InvalidIdent - | rustc_lexer::TokenKind::InvalidPrefix => { + | rustc_lexer::TokenKind::InvalidIdent => { // Don't emit diagnostics for sequences of the same invalid token if swallow_next_invalid > 0 { swallow_next_invalid -= 1; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 50a8b6542df..042ee96bbe8 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -641,9 +641,10 @@ impl<'a> Parser<'a> { return true; } + // Do an ASCII case-insensitive match, because all keywords are ASCII. if case == Case::Insensitive && let Some((ident, IdentIsRaw::No)) = self.token.ident() - && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() + && ident.as_str().eq_ignore_ascii_case(kw.as_str()) { true } else { diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 55fdbac8ad6..db34189be2a 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -126,6 +126,7 @@ impl<'k> StatCollector<'k> { }); let total_size = nodes.iter().map(|(_, node)| node.stats.count * node.stats.size).sum(); + let total_count = nodes.iter().map(|(_, node)| node.stats.count).sum(); eprintln!("{prefix} {title}"); eprintln!( @@ -167,7 +168,13 @@ impl<'k> StatCollector<'k> { } } eprintln!("{prefix} ----------------------------------------------------------------"); - eprintln!("{} {:<18}{:>10}", prefix, "Total", to_readable_str(total_size)); + eprintln!( + "{} {:<18}{:>10} {:>14}", + prefix, + "Total", + to_readable_str(total_size), + to_readable_str(total_count), + ); eprintln!("{prefix}"); } } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 664da65068d..8f53b71319d 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -27,7 +27,7 @@ pub mod entry; mod errors; #[cfg(debug_assertions)] pub mod hir_id_validator; -pub mod hir_stats; +pub mod input_stats; mod lang_items; pub mod layout_test; mod lib_features; diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index ba7a631fb54..a85e8a55a21 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -2,6 +2,7 @@ #![allow(rustc::potential_query_instability, internal_features)] #![feature(assert_matches)] #![feature(core_intrinsics)] +#![feature(dropck_eyepatch)] #![feature(hash_raw_entry)] #![feature(let_chains)] #![feature(min_specialization)] diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index a4ced3d2c24..e6f3d97742d 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -3,9 +3,10 @@ use std::hash::Hash; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sharded::{self, Sharded}; -use rustc_data_structures::sync::{Lock, OnceLock}; +use rustc_data_structures::sync::OnceLock; +pub use rustc_data_structures::vec_cache::VecCache; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_index::{Idx, IndexVec}; +use rustc_index::Idx; use rustc_span::def_id::{DefId, DefIndex}; use crate::dep_graph::DepNodeIndex; @@ -100,52 +101,10 @@ where } } -pub struct VecCache<K: Idx, V> { - cache: Lock<IndexVec<K, Option<(V, DepNodeIndex)>>>, -} - -impl<K: Idx, V> Default for VecCache<K, V> { - fn default() -> Self { - VecCache { cache: Default::default() } - } -} - -impl<K, V> QueryCache for VecCache<K, V> -where - K: Eq + Idx + Copy + Debug, - V: Copy, -{ - type Key = K; - type Value = V; - - #[inline(always)] - fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> { - let lock = self.cache.lock(); - if let Some(Some(value)) = lock.get(*key) { Some(*value) } else { None } - } - - #[inline] - fn complete(&self, key: K, value: V, index: DepNodeIndex) { - let mut lock = self.cache.lock(); - lock.insert(key, (value, index)); - } - - fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { - for (k, v) in self.cache.lock().iter_enumerated() { - if let Some(v) = v { - f(&k, &v.0, v.1); - } - } - } -} - pub struct DefIdCache<V> { /// Stores the local DefIds in a dense map. Local queries are much more often dense, so this is /// a win over hashing query keys at marginal memory cost (~5% at most) compared to FxHashMap. - /// - /// The second element of the tuple is the set of keys actually present in the IndexVec, used - /// for faster iteration in `iter()`. - local: Lock<(IndexVec<DefIndex, Option<(V, DepNodeIndex)>>, Vec<DefIndex>)>, + local: VecCache<DefIndex, V, DepNodeIndex>, foreign: DefaultCache<DefId, V>, } @@ -165,8 +124,7 @@ where #[inline(always)] fn lookup(&self, key: &DefId) -> Option<(V, DepNodeIndex)> { if key.krate == LOCAL_CRATE { - let cache = self.local.lock(); - cache.0.get(key.index).and_then(|v| *v) + self.local.lookup(&key.index) } else { self.foreign.lookup(key) } @@ -175,27 +133,39 @@ where #[inline] fn complete(&self, key: DefId, value: V, index: DepNodeIndex) { if key.krate == LOCAL_CRATE { - let mut cache = self.local.lock(); - let (cache, present) = &mut *cache; - let slot = cache.ensure_contains_elem(key.index, Default::default); - if slot.is_none() { - // FIXME: Only store the present set when running in incremental mode. `iter` is not - // used outside of saving caches to disk and self-profile. - present.push(key.index); - } - *slot = Some((value, index)); + self.local.complete(key.index, value, index) } else { self.foreign.complete(key, value, index) } } fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { - let guard = self.local.lock(); - let (cache, present) = &*guard; - for &idx in present.iter() { - let value = cache[idx].unwrap(); - f(&DefId { krate: LOCAL_CRATE, index: idx }, &value.0, value.1); - } + self.local.iter(&mut |key, value, index| { + f(&DefId { krate: LOCAL_CRATE, index: *key }, value, index); + }); self.foreign.iter(f); } } + +impl<K, V> QueryCache for VecCache<K, V, DepNodeIndex> +where + K: Idx + Eq + Hash + Copy + Debug, + V: Copy, +{ + type Key = K; + type Value = V; + + #[inline(always)] + fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> { + self.lookup(key) + } + + #[inline] + fn complete(&self, key: K, value: V, index: DepNodeIndex) { + self.complete(key, value, index) + } + + fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { + self.iter(f) + } +} diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 5437ca65935..5b78acd904a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -535,14 +535,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { filter_fn: &impl Fn(Res) -> bool, ctxt: Option<SyntaxContext>, ) { - for (key, resolution) in self.resolutions(module).borrow().iter() { - if let Some(binding) = resolution.borrow().binding { - let res = binding.res(); - if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) { - names.push(TypoSuggestion::typo_from_ident(key.ident, res)); - } + module.for_each_child(self, |_this, ident, _ns, binding| { + let res = binding.res(); + if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == ident.span.ctxt()) { + names.push(TypoSuggestion::typo_from_ident(ident, res)); } - } + }); } /// Combines an error with provided span and emits it. diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index b80e0e196ca..ad825d7813d 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -38,6 +38,12 @@ impl From<UsePrelude> for bool { } } +#[derive(Debug, PartialEq)] +enum Shadowing { + Restricted, + Unrestricted, +} + impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// A generic scope visitor. /// Visits scopes in order to resolve some identifier in them or perform other actions. @@ -311,13 +317,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Walk backwards up the ribs in scope. let mut module = self.graph_root; - for i in (0..ribs.len()).rev() { - debug!("walk rib\n{:?}", ribs[i].bindings); + for (i, rib) in ribs.iter().enumerate().rev() { + debug!("walk rib\n{:?}", rib.bindings); // Use the rib kind to determine whether we are resolving parameters // (macro 2.0 hygiene) or local variables (`macro_rules` hygiene). - let rib_ident = if ribs[i].kind.contains_params() { normalized_ident } else { ident }; - if let Some((original_rib_ident_def, res)) = ribs[i].bindings.get_key_value(&rib_ident) - { + let rib_ident = if rib.kind.contains_params() { normalized_ident } else { ident }; + if let Some((original_rib_ident_def, res)) = rib.bindings.get_key_value(&rib_ident) { // The ident resolves to a type parameter or local variable. return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs( i, @@ -329,7 +334,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ))); } - module = match ribs[i].kind { + module = match rib.kind { RibKind::Module(module) => module, RibKind::MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => { // If an invocation of this macro created `ident`, give up on `ident` @@ -350,6 +355,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, ns, parent_scope, + Shadowing::Unrestricted, finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), ignore_binding, None, @@ -494,7 +500,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::CrateRoot => { let root_ident = Ident::new(kw::PathRoot, ident.span); let root_module = this.resolve_crate_root(root_ident); - let binding = this.resolve_ident_in_module_ext( + let binding = this.resolve_ident_in_module( ModuleOrUniformRoot::Module(root_module), ident, ns, @@ -516,12 +522,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::Module(module, derive_fallback_lint_id) => { let adjusted_parent_scope = &ParentScope { module, ..*parent_scope }; - let binding = this.resolve_ident_in_module_unadjusted_ext( + let binding = this.resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, adjusted_parent_scope, - !matches!(scope_set, ScopeSet::Late(..)), + if matches!(scope_set, ScopeSet::Late(..)) { + Shadowing::Unrestricted + } else { + Shadowing::Restricted + }, finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), ignore_binding, ignore_import, @@ -590,6 +600,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, ns, parent_scope, + Shadowing::Unrestricted, None, ignore_binding, ignore_import, @@ -748,7 +759,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, ignore_import: Option<Import<'ra>>, ) -> Result<NameBinding<'ra>, Determinacy> { - self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, None, ignore_import) + self.resolve_ident_in_module(module, ident, ns, parent_scope, None, None, ignore_import) .map_err(|(determinacy, _)| determinacy) } @@ -756,29 +767,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn resolve_ident_in_module( &mut self, module: ModuleOrUniformRoot<'ra>, - ident: Ident, - ns: Namespace, - parent_scope: &ParentScope<'ra>, - finalize: Option<Finalize>, - ignore_binding: Option<NameBinding<'ra>>, - ignore_import: Option<Import<'ra>>, - ) -> Result<NameBinding<'ra>, Determinacy> { - self.resolve_ident_in_module_ext( - module, - ident, - ns, - parent_scope, - finalize, - ignore_binding, - ignore_import, - ) - .map_err(|(determinacy, _)| determinacy) - } - - #[instrument(level = "debug", skip(self))] - fn resolve_ident_in_module_ext( - &mut self, - module: ModuleOrUniformRoot<'ra>, mut ident: Ident, ns: Namespace, parent_scope: &ParentScope<'ra>, @@ -803,52 +791,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // No adjustments } } - self.resolve_ident_in_module_unadjusted_ext( + self.resolve_ident_in_module_unadjusted( module, ident, ns, adjusted_parent_scope, - false, + Shadowing::Unrestricted, finalize, ignore_binding, ignore_import, ) } - #[instrument(level = "debug", skip(self))] - fn resolve_ident_in_module_unadjusted( - &mut self, - module: ModuleOrUniformRoot<'ra>, - ident: Ident, - ns: Namespace, - parent_scope: &ParentScope<'ra>, - finalize: Option<Finalize>, - ignore_binding: Option<NameBinding<'ra>>, - ignore_import: Option<Import<'ra>>, - ) -> Result<NameBinding<'ra>, Determinacy> { - self.resolve_ident_in_module_unadjusted_ext( - module, - ident, - ns, - parent_scope, - false, - finalize, - ignore_binding, - ignore_import, - ) - .map_err(|(determinacy, _)| determinacy) - } - /// Attempts to resolve `ident` in namespaces `ns` of `module`. /// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete. #[instrument(level = "debug", skip(self))] - fn resolve_ident_in_module_unadjusted_ext( + fn resolve_ident_in_module_unadjusted( &mut self, module: ModuleOrUniformRoot<'ra>, ident: Ident, ns: Namespace, parent_scope: &ParentScope<'ra>, - restricted_shadowing: bool, + shadowing: Shadowing, finalize: Option<Finalize>, // This binding should be ignored during in-module resolution, so that we don't get // "self-confirming" import resolutions during import validation and checking. @@ -858,7 +822,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let module = match module { ModuleOrUniformRoot::Module(module) => module, ModuleOrUniformRoot::CrateRootAndExternPrelude => { - assert!(!restricted_shadowing); + assert_eq!(shadowing, Shadowing::Unrestricted); let binding = self.early_resolve_ident_in_lexical_scope( ident, ScopeSet::AbsolutePath(ns), @@ -871,7 +835,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return binding.map_err(|determinacy| (determinacy, Weak::No)); } ModuleOrUniformRoot::ExternPrelude => { - assert!(!restricted_shadowing); + assert_eq!(shadowing, Shadowing::Unrestricted); return if ns != TypeNS { Err((Determined, Weak::No)) } else if let Some(binding) = self.extern_prelude_get(ident, finalize.is_some()) { @@ -884,7 +848,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; } ModuleOrUniformRoot::CurrentScope => { - assert!(!restricted_shadowing); + assert_eq!(shadowing, Shadowing::Unrestricted); if ns == TypeNS { if ident.name == kw::Crate || ident.name == kw::DollarCrate { let module = self.resolve_crate_root(ident); @@ -943,7 +907,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Forbid expanded shadowing to avoid time travel. if let Some(shadowed_glob) = resolution.shadowed_glob - && restricted_shadowing + && shadowing == Shadowing::Restricted && binding.expansion != LocalExpnId::ROOT && binding.res() != shadowed_glob.res() { @@ -958,7 +922,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); } - if !restricted_shadowing + if shadowing == Shadowing::Unrestricted && binding.expansion != LocalExpnId::ROOT && let NameBindingKind::Import { import, .. } = binding.kind && matches!(import.kind, ImportKind::MacroExport) @@ -1047,13 +1011,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_binding, ignore_import, ) { - Err(Determined) => continue, + Err((Determined, _)) => continue, Ok(binding) if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) => { continue; } - Ok(_) | Err(Undetermined) => return Err((Undetermined, Weak::No)), + Ok(_) | Err((Undetermined, _)) => return Err((Undetermined, Weak::No)), } } @@ -1070,7 +1034,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // and prohibit access to macro-expanded `macro_export` macros instead (unless restricted // shadowing is enabled, see `macro_expanded_macro_export_errors`). if let Some(binding) = binding { - if binding.determined() || ns == MacroNS || restricted_shadowing { + if binding.determined() || ns == MacroNS || shadowing == Shadowing::Restricted { return check_usable(self, binding); } else { return Err((Undetermined, Weak::No)); @@ -1122,19 +1086,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, ns, adjusted_parent_scope, + Shadowing::Unrestricted, None, ignore_binding, ignore_import, ); match result { - Err(Determined) => continue, + Err((Determined, _)) => continue, Ok(binding) if !self.is_accessible_from(binding.vis, glob_import.parent_scope.module) => { continue; } - Ok(_) | Err(Undetermined) => return Err((Undetermined, Weak::Yes)), + Ok(_) | Err((Undetermined, _)) => return Err((Undetermined, Weak::Yes)), } } @@ -1200,7 +1165,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Still doesn't deal with upvars if let Some(span) = finalize { let (span, resolution_error) = match item { - None if rib_ident.as_str() == "self" => (span, LowercaseSelf), + None if rib_ident.name == kw::SelfLower => { + (span, LowercaseSelf) + } None => { // If we have a `let name = expr;`, we have the span for // `name` and use that to see if it is followed by a type @@ -1563,6 +1530,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_binding, ignore_import, ) + .map_err(|(determinacy, _)| determinacy) } else if let Some(ribs) = ribs && let Some(TypeNS | ValueNS) = opt_ns { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f4a85c358e3..26b345f5941 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1688,9 +1688,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } + let normalized_ident = ident.normalize_to_macros_2_0(); let mut outer_res = None; for rib in lifetime_rib_iter { - let normalized_ident = ident.normalize_to_macros_2_0(); if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) { outer_res = Some(outer); break; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9abb3180388..e382295b8f6 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1082,8 +1082,6 @@ pub struct Resolver<'ra, 'tcx> { binding_parent_modules: FxHashMap<NameBinding<'ra>, Module<'ra>>, underscore_disambiguator: u32, - /// Disambiguator for anonymous adts. - empty_disambiguator: u32, /// Maps glob imports to the names of items actually imported. glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>, @@ -1462,7 +1460,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module_children: Default::default(), trait_map: NodeMap::default(), underscore_disambiguator: 0, - empty_disambiguator: 0, empty_module, module_map, block_map: Default::default(), @@ -1809,12 +1806,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { assoc_item: Option<(Symbol, Namespace)>, ) -> bool { match (trait_module, assoc_item) { - (Some(trait_module), Some((name, ns))) => { - self.resolutions(trait_module).borrow().iter().any(|resolution| { - let (&BindingKey { ident: assoc_ident, ns: assoc_ns, .. }, _) = resolution; - assoc_ns == ns && assoc_ident.name == name - }) - } + (Some(trait_module), Some((name, ns))) => self + .resolutions(trait_module) + .borrow() + .iter() + .any(|(key, _name_resolution)| key.ns == ns && key.ident.name == name), _ => true, } } @@ -1842,9 +1838,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let disambiguator = if ident.name == kw::Underscore { self.underscore_disambiguator += 1; self.underscore_disambiguator - } else if ident.name == kw::Empty { - self.empty_disambiguator += 1; - self.empty_disambiguator } else { 0 }; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f485e8cace5..d94b503de18 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1805,8 +1805,6 @@ options! { environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"), has_thread_local: Option<bool> = (None, parse_opt_bool, [TRACKED], "explicitly enable the `cfg(target_thread_local)` directive"), - hir_stats: bool = (false, parse_bool, [UNTRACKED], - "print some statistics about AST and HIR (default: no)"), human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], "generate human-readable, predictable names for codegen units (default: no)"), identify_regions: bool = (false, parse_bool, [UNTRACKED], @@ -1838,7 +1836,7 @@ options! { inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED], "a default MIR inlining threshold (default: 50)"), input_stats: bool = (false, parse_bool, [UNTRACKED], - "gather statistics about the input (default: no)"), + "print some statistics about AST and HIR (default: no)"), instrument_mcount: bool = (false, parse_bool, [TRACKED], "insert function instrument code for mcount-based tracing (default: no)"), instrument_xray: Option<InstrumentXRay> = (None, parse_instrument_xray, [TRACKED], diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a562d34abde..e4261822040 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1226,6 +1226,7 @@ symbols! { min_const_generics, min_const_unsafe_fn, min_exhaustive_patterns, + min_generic_const_args, min_specialization, min_type_alias_impl_trait, minnumf128, diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 66353ccfa47..213924d1d02 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -677,7 +677,11 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { } } - /// Returns the key-value pair corresponding to the supplied key. + /// Returns the key-value pair corresponding to the supplied key. This is + /// potentially useful: + /// - for key types where non-identical keys can be considered equal; + /// - for getting the `&K` stored key value from a borrowed `&Q` lookup key; or + /// - for getting a reference to a key with the same lifetime as the collection. /// /// The supplied key may be any borrowed form of the map's key type, but the ordering /// on the borrowed form *must* match the ordering on the key type. @@ -685,12 +689,46 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { /// # Examples /// /// ``` + /// use std::cmp::Ordering; /// use std::collections::BTreeMap; /// + /// #[derive(Clone, Copy, Debug)] + /// struct S { + /// id: u32, + /// # #[allow(unused)] // prevents a "field `name` is never read" error + /// name: &'static str, // ignored by equality and ordering operations + /// } + /// + /// impl PartialEq for S { + /// fn eq(&self, other: &S) -> bool { + /// self.id == other.id + /// } + /// } + /// + /// impl Eq for S {} + /// + /// impl PartialOrd for S { + /// fn partial_cmp(&self, other: &S) -> Option<Ordering> { + /// self.id.partial_cmp(&other.id) + /// } + /// } + /// + /// impl Ord for S { + /// fn cmp(&self, other: &S) -> Ordering { + /// self.id.cmp(&other.id) + /// } + /// } + /// + /// let j_a = S { id: 1, name: "Jessica" }; + /// let j_b = S { id: 1, name: "Jess" }; + /// let p = S { id: 2, name: "Paul" }; + /// assert_eq!(j_a, j_b); + /// /// let mut map = BTreeMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); - /// assert_eq!(map.get_key_value(&2), None); + /// map.insert(j_a, "Paris"); + /// assert_eq!(map.get_key_value(&j_a), Some((&j_a, &"Paris"))); + /// assert_eq!(map.get_key_value(&j_b), Some((&j_a, &"Paris"))); // the notable case + /// assert_eq!(map.get_key_value(&p), None); /// ``` #[stable(feature = "map_get_key_value", since = "1.40.0")] pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)> diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index 6922ea9b79b..d3dbd10c863 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -19,6 +19,40 @@ impl<'a, T> Iter<'a, T> { pub(super) fn new(i1: slice::Iter<'a, T>, i2: slice::Iter<'a, T>) -> Self { Self { i1, i2 } } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// This has the same lifetime as the original `VecDeque`, and so the + /// iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter(); + /// iter.next(); + /// iter.next_back(); + /// + /// assert_eq!(iter.as_slices(), (&[9, 10][..], &[0, 1][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn as_slices(&self) -> (&'a [T], &'a [T]) { + (self.i1.as_slice(), self.i2.as_slice()) + } } #[stable(feature = "collection_debug", since = "1.17.0")] diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index 84b74109580..0c5f06e752b 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -19,6 +19,113 @@ impl<'a, T> IterMut<'a, T> { pub(super) fn new(i1: slice::IterMut<'a, T>, i2: slice::IterMut<'a, T>) -> Self { Self { i1, i2 } } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// To avoid creating `&mut` references that alias, this is forced to + /// consume the iterator. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter_mut(); + /// iter.next(); + /// iter.next_back(); + /// + /// let slices = iter.into_slices(); + /// slices.0[0] = 42; + /// slices.1[0] = 24; + /// assert_eq!(deque.as_slices(), (&[8, 42, 10][..], &[24, 1, 2][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn into_slices(self) -> (&'a mut [T], &'a mut [T]) { + (self.i1.into_slice(), self.i2.into_slice()) + } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// To avoid creating `&mut [T]` references that alias, the returned slices + /// borrow their lifetimes from the iterator the method is applied on. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter_mut(); + /// iter.next(); + /// iter.next_back(); + /// + /// assert_eq!(iter.as_slices(), (&[9, 10][..], &[0, 1][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn as_slices(&self) -> (&[T], &[T]) { + (self.i1.as_slice(), self.i2.as_slice()) + } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// To avoid creating `&mut [T]` references that alias, the returned slices + /// borrow their lifetimes from the iterator the method is applied on. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter_mut(); + /// iter.next(); + /// iter.next_back(); + /// + /// iter.as_mut_slices().0[0] = 42; + /// iter.as_mut_slices().1[0] = 24; + /// assert_eq!(deque.as_slices(), (&[8, 42, 10][..], &[24, 1, 2][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { + (self.i1.as_mut_slice(), self.i2.as_mut_slice()) + } } #[stable(feature = "collection_debug", since = "1.17.0")] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index dd9dfa3f5e2..7839fe04b8d 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -143,6 +143,7 @@ #![feature(sized_type_properties)] #![feature(slice_from_ptr_range)] #![feature(slice_index_methods)] +#![feature(slice_iter_mut_as_mut_slice)] #![feature(slice_ptr_get)] #![feature(slice_range)] #![feature(std_internals)] diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index e702056f00a..179aadf0c28 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -215,7 +215,7 @@ pub macro const_panic { #[noinline] if const #[track_caller] #[inline] { // Inline this, to prevent codegen $crate::panic!($const_msg) - } else #[track_caller] { // Do not inline this, it makes perf worse + } else #[track_caller] #[cfg_attr(bootstrap, inline)] { // Do not inline this, it makes perf worse $crate::panic!($runtime_msg) } ) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index ded4f404d78..24bbc2f32cf 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -880,7 +880,11 @@ where self.base.get(k) } - /// Returns the key-value pair corresponding to the supplied key. + /// Returns the key-value pair corresponding to the supplied key. This is + /// potentially useful: + /// - for key types where non-identical keys can be considered equal; + /// - for getting the `&K` stored key value from a borrowed `&Q` lookup key; or + /// - for getting a reference to a key with the same lifetime as the collection. /// /// The supplied key may be any borrowed form of the map's key type, but /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for @@ -890,11 +894,39 @@ where /// /// ``` /// use std::collections::HashMap; + /// use std::hash::{Hash, Hasher}; + /// + /// #[derive(Clone, Copy, Debug)] + /// struct S { + /// id: u32, + /// # #[allow(unused)] // prevents a "field `name` is never read" error + /// name: &'static str, // ignored by equality and hashing operations + /// } + /// + /// impl PartialEq for S { + /// fn eq(&self, other: &S) -> bool { + /// self.id == other.id + /// } + /// } + /// + /// impl Eq for S {} + /// + /// impl Hash for S { + /// fn hash<H: Hasher>(&self, state: &mut H) { + /// self.id.hash(state); + /// } + /// } + /// + /// let j_a = S { id: 1, name: "Jessica" }; + /// let j_b = S { id: 1, name: "Jess" }; + /// let p = S { id: 2, name: "Paul" }; + /// assert_eq!(j_a, j_b); /// /// let mut map = HashMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); - /// assert_eq!(map.get_key_value(&2), None); + /// map.insert(j_a, "Paris"); + /// assert_eq!(map.get_key_value(&j_a), Some((&j_a, &"Paris"))); + /// assert_eq!(map.get_key_value(&j_b), Some((&j_a, &"Paris"))); // the notable case + /// assert_eq!(map.get_key_value(&p), None); /// ``` #[inline] #[stable(feature = "map_get_key_value", since = "1.40.0")] diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 76fdb1a4ffd..555e8804eab 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2738,6 +2738,10 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { /// Removes an empty directory. /// +/// If you want to remove a directory that is not empty, as well as all +/// of its contents recursively, consider using [`remove_dir_all`] +/// instead. +/// /// # Platform-specific behavior /// /// This function currently corresponds to the `rmdir` function on Unix diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs index 02ac1c85b91..29cad4400f1 100644 --- a/library/std/src/sync/rwlock/tests.rs +++ b/library/std/src/sync/rwlock/tests.rs @@ -550,6 +550,9 @@ fn test_downgrade_observe() { } #[test] +// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue. +// See <https://github.com/rust-lang/rust/issues/121950> for details. +#[cfg_attr(all(miri, target_os = "macos"), ignore)] fn test_downgrade_atomic() { const NEW_VALUE: i32 = -1; diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 227ee9d64f3..2c2cc58a9dd 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -188,6 +188,11 @@ mod current; pub use current::current; pub(crate) use current::{current_id, drop_current, set_current, try_current}; +mod spawnhook; + +#[unstable(feature = "thread_spawn_hook", issue = "132951")] +pub use spawnhook::add_spawn_hook; + //////////////////////////////////////////////////////////////////////////////// // Thread-local storage //////////////////////////////////////////////////////////////////////////////// @@ -259,6 +264,8 @@ pub struct Builder { name: Option<String>, // The size of the stack for the spawned thread in bytes stack_size: Option<usize>, + // Skip running and inheriting the thread spawn hooks + no_hooks: bool, } impl Builder { @@ -282,7 +289,7 @@ impl Builder { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Builder { - Builder { name: None, stack_size: None } + Builder { name: None, stack_size: None, no_hooks: false } } /// Names the thread-to-be. Currently the name is used for identification @@ -338,6 +345,16 @@ impl Builder { self } + /// Disables running and inheriting [spawn hooks](add_spawn_hook). + /// + /// Use this if the parent thread is in no way relevant for the child thread. + /// For example, when lazily spawning threads for a thread pool. + #[unstable(feature = "thread_spawn_hook", issue = "132951")] + pub fn no_hooks(mut self) -> Builder { + self.no_hooks = true; + self + } + /// Spawns a new thread by taking ownership of the `Builder`, and returns an /// [`io::Result`] to its [`JoinHandle`]. /// @@ -460,7 +477,7 @@ impl Builder { F: Send, T: Send, { - let Builder { name, stack_size } = self; + let Builder { name, stack_size, no_hooks } = self; let stack_size = stack_size.unwrap_or_else(|| { static MIN: AtomicUsize = AtomicUsize::new(0); @@ -485,6 +502,13 @@ impl Builder { Some(name) => Thread::new(id, name.into()), None => Thread::new_unnamed(id), }; + + let hooks = if no_hooks { + spawnhook::ChildSpawnHooks::default() + } else { + spawnhook::run_spawn_hooks(&my_thread) + }; + let their_thread = my_thread.clone(); let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet { @@ -494,9 +518,6 @@ impl Builder { }); let their_packet = my_packet.clone(); - let output_capture = crate::io::set_output_capture(None); - crate::io::set_output_capture(output_capture.clone()); - // Pass `f` in `MaybeUninit` because actually that closure might *run longer than the lifetime of `F`*. // See <https://github.com/rust-lang/rust/issues/101983> for more details. // To prevent leaks we use a wrapper that drops its contents. @@ -534,10 +555,9 @@ impl Builder { imp::Thread::set_name(name); } - crate::io::set_output_capture(output_capture); - let f = f.into_inner(); let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { + crate::sys::backtrace::__rust_begin_short_backtrace(|| hooks.run()); crate::sys::backtrace::__rust_begin_short_backtrace(f) })); // SAFETY: `their_packet` as been built just above and moved by the diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs new file mode 100644 index 00000000000..99b5ad9cb9f --- /dev/null +++ b/library/std/src/thread/spawnhook.rs @@ -0,0 +1,148 @@ +use crate::cell::Cell; +use crate::iter; +use crate::sync::Arc; +use crate::thread::Thread; + +crate::thread_local! { + /// A thread local linked list of spawn hooks. + /// + /// It is a linked list of Arcs, such that it can very cheaply be inhereted by spawned threads. + /// + /// (That technically makes it a set of linked lists with shared tails, so a linked tree.) + static SPAWN_HOOKS: Cell<SpawnHooks> = const { Cell::new(SpawnHooks { first: None }) }; +} + +#[derive(Default, Clone)] +struct SpawnHooks { + first: Option<Arc<SpawnHook>>, +} + +// Manually implement drop to prevent deep recursion when dropping linked Arc list. +impl Drop for SpawnHooks { + fn drop(&mut self) { + let mut next = self.first.take(); + while let Some(SpawnHook { hook, next: n }) = next.and_then(|n| Arc::into_inner(n)) { + drop(hook); + next = n; + } + } +} + +struct SpawnHook { + hook: Box<dyn Send + Sync + Fn(&Thread) -> Box<dyn Send + FnOnce()>>, + next: Option<Arc<SpawnHook>>, +} + +/// Registers a function to run for every newly thread spawned. +/// +/// The hook is executed in the parent thread, and returns a function +/// that will be executed in the new thread. +/// +/// The hook is called with the `Thread` handle for the new thread. +/// +/// The hook will only be added for the current thread and is inherited by the threads it spawns. +/// In other words, adding a hook has no effect on already running threads (other than the current +/// thread) and the threads they might spawn in the future. +/// +/// Hooks can only be added, not removed. +/// +/// The hooks will run in reverse order, starting with the most recently added. +/// +/// # Usage +/// +/// ``` +/// #![feature(thread_spawn_hook)] +/// +/// std::thread::add_spawn_hook(|_| { +/// ..; // This will run in the parent (spawning) thread. +/// move || { +/// ..; // This will run it the child (spawned) thread. +/// } +/// }); +/// ``` +/// +/// # Example +/// +/// A spawn hook can be used to "inherit" a thread local from the parent thread: +/// +/// ``` +/// #![feature(thread_spawn_hook)] +/// +/// use std::cell::Cell; +/// +/// thread_local! { +/// static X: Cell<u32> = Cell::new(0); +/// } +/// +/// // This needs to be done once in the main thread before spawning any threads. +/// std::thread::add_spawn_hook(|_| { +/// // Get the value of X in the spawning thread. +/// let value = X.get(); +/// // Set the value of X in the newly spawned thread. +/// move || X.set(value) +/// }); +/// +/// X.set(123); +/// +/// std::thread::spawn(|| { +/// assert_eq!(X.get(), 123); +/// }).join().unwrap(); +/// ``` +#[unstable(feature = "thread_spawn_hook", issue = "132951")] +pub fn add_spawn_hook<F, G>(hook: F) +where + F: 'static + Send + Sync + Fn(&Thread) -> G, + G: 'static + Send + FnOnce(), +{ + SPAWN_HOOKS.with(|h| { + let mut hooks = h.take(); + let next = hooks.first.take(); + hooks.first = Some(Arc::new(SpawnHook { + hook: Box::new(move |thread| Box::new(hook(thread))), + next, + })); + h.set(hooks); + }); +} + +/// Runs all the spawn hooks. +/// +/// Called on the parent thread. +/// +/// Returns the functions to be called on the newly spawned thread. +pub(super) fn run_spawn_hooks(thread: &Thread) -> ChildSpawnHooks { + // Get a snapshot of the spawn hooks. + // (Increments the refcount to the first node.) + let hooks = SPAWN_HOOKS.with(|hooks| { + let snapshot = hooks.take(); + hooks.set(snapshot.clone()); + snapshot + }); + // Iterate over the hooks, run them, and collect the results in a vector. + let to_run: Vec<_> = iter::successors(hooks.first.as_deref(), |hook| hook.next.as_deref()) + .map(|hook| (hook.hook)(thread)) + .collect(); + // Pass on the snapshot of the hooks and the results to the new thread, + // which will then run SpawnHookResults::run(). + ChildSpawnHooks { hooks, to_run } +} + +/// The results of running the spawn hooks. +/// +/// This struct is sent to the new thread. +/// It contains the inherited hooks and the closures to be run. +#[derive(Default)] +pub(super) struct ChildSpawnHooks { + hooks: SpawnHooks, + to_run: Vec<Box<dyn FnOnce() + Send>>, +} + +impl ChildSpawnHooks { + // This is run on the newly spawned thread, directly at the start. + pub(super) fn run(self) { + SPAWN_HOOKS.set(self.hooks); + for run in self.to_run { + run(); + } + } +} diff --git a/library/stdarch b/library/stdarch -Subproject ff9a4445038eae46fd095188740946808581bc0 +Subproject e5e00aab0a8c8fa35fb7865e88fa82366f615c5 diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 30ccfe2af8d..47407df909b 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -24,6 +24,7 @@ #![feature(process_exitcode_internals)] #![feature(panic_can_unwind)] #![feature(test)] +#![feature(thread_spawn_hook)] #![allow(internal_features)] #![warn(rustdoc::unescaped_backticks)] @@ -134,6 +135,16 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt } }); panic::set_hook(hook); + // Use a thread spawning hook to make new threads inherit output capturing. + std::thread::add_spawn_hook(|_| { + // Get and clone the output capture of the current thread. + let output_capture = io::set_output_capture(None); + io::set_output_capture(output_capture.clone()); + // Set the output capture of the new thread. + || { + io::set_output_capture(output_capture); + } + }); } let res = console::run_tests_console(&opts, tests); // Prevent Valgrind from reporting reachable blocks in users' unit tests. diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 95b1303fa71..e706aba977b 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1255,6 +1255,10 @@ impl Config { }, out: PathBuf::from("build"), + // This is needed by codegen_ssa on macOS to ship `llvm-objcopy` aliased to + // `rust-objcopy` to workaround bad `strip`s on macOS. + llvm_tools_enabled: true, + ..Default::default() } } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 1d05f94e3be..7f62ffb20db 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -300,4 +300,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "`download-rustc='if-unchanged'` is now a default option for library profile.", }, + ChangeInfo { + change_id: 133207, + severity: ChangeSeverity::Info, + summary: "`rust.llvm-tools` is now enabled by default when no `config.toml` is provided.", + }, ]; diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 340dfd67b7d..80ae62d7ac0 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -465,7 +465,7 @@ auto: SCRIPT: python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift - <<: *job-windows-8c + <<: *job-windows - image: dist-aarch64-msvc env: diff --git a/src/doc/edition-guide b/src/doc/edition-guide -Subproject 2d482e203eb6d6e353814cf1415c5f94e590b9e +Subproject 915f9b319c2823f310430ecdecd86264a7870d7 diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject 456b904f791751892b01282fd2757904993c4c2 +Subproject eac89a3cbe6c4714e5029ae8b5a1c556fd4e8c4 diff --git a/src/doc/reference b/src/doc/reference -Subproject da0f6dad767670da0e8cd5af8a7090db3272f62 +Subproject 41ccb0e6478305401dad92e8fd3d04a4304edb4 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject 6a5accdaf10255882b1e6c59dfe5f1c79ac9548 +Subproject b679e71c2d66c6fe13e06b99ac61773b866213f diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 18f76ac6fe0..f3d8a4edd6c 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -72,6 +72,8 @@ - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md) - [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md) + - [s390x-unknown-linux-gnu](platform-support/s390x-unknown-linux-gnu.md) + - [s390x-unknown-linux-musl](platform-support/s390x-unknown-linux-musl.md) - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md) - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) - [\*-nto-qnx-\*](platform-support/nto-qnx.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 500eaafb63f..243cb3b2fc8 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -99,7 +99,7 @@ target | notes `powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17) [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29) [`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3) -`s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17) +[`s390x-unknown-linux-gnu`](platform-support/s390x-unknown-linux-gnu.md) | S390x Linux (kernel 3.2, glibc 2.17) `x86_64-unknown-freebsd` | 64-bit FreeBSD `x86_64-unknown-illumos` | illumos `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3 @@ -367,7 +367,7 @@ target | std | host | notes [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64 [`riscv64-linux-android`](platform-support/android.md) | | | RISC-V 64-bit Android [`riscv64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | -`s390x-unknown-linux-musl` | | | S390x Linux (kernel 3.2, musl 1.2.3) +[`s390x-unknown-linux-musl`](platform-support/s390x-unknown-linux-musl.md) | | | S390x Linux (kernel 3.2, musl 1.2.3) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux [`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * | | Bare 32-bit SPARC V7+ [`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64 diff --git a/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md new file mode 100644 index 00000000000..60e06c404c0 --- /dev/null +++ b/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md @@ -0,0 +1,113 @@ +# `s390x-unknown-linux-gnu` + +**Tier: 2 (with Host Tools)** + +IBM z/Architecture (s390x) targets (including IBM Z and LinuxONE) running Linux. + +## Target maintainers + +- Ulrich Weigand, <ulrich.weigand@de.ibm.com>, [@uweigand](https://github.com/uweigand) +- Josh Stone, <jistone@redhat.com>, [@cuviper](https://github.com/cuviper) + +## Requirements + +This target requires: + +* Linux Kernel version 3.2 or later +* glibc 2.17 or later + +Code generated by the target uses the z/Architecture ISA assuming a minimum +architecture level of z10 (Eighth Edition of the z/Architecture Principles +of Operation), and is compliant with the s390x ELF ABI. + +Reference material: + +* [z/Architecture Principles of Operation][s390x-isa] +* [z/Architecture ELF Application Binary Interface][s390x-abi] + +[s390x-isa]: https://publibfp.dhe.ibm.com/epubs/pdf/a227832d.pdf +[s390x-abi]: https://github.com/IBM/s390x-abi + +## Building the target + +This target is distributed through `rustup`, and otherwise requires no +special configuration. + +If you need to build your own Rust for some reason though, the target can be +enabled in `config.toml`. For example: + +```toml +[build] +target = ["s390x-unknown-linux-gnu"] +``` + +## Building Rust programs + +On a s390x Linux host, the `s390x-unknown-linux-gnu` target should be +automatically installed and used by default. + +On a non-s390x host, add the target: + +```bash +rustup target add s390x-unknown-linux-gnu +``` + +Then cross compile crates with: + +```bash +cargo build --target s390x-unknown-linux-gnu +``` + +## Testing + +There are no special requirements for testing and running the target. +For testing cross builds on the host, please refer to the "Cross-compilation +toolchains and C code" section below. + +## Cross-compilation toolchains and C code + +Rust code built using the target is compatible with C code compiled with +GCC or Clang using the `s390x-unknown-linux-gnu` target triple (via either +native or cross-compilation). + +On Ubuntu, a s390x cross-toolchain can be installed with: + +```bash +apt install gcc-s390x-linux-gnu g++-s390x-linux-gnu libc6-dev-s390x-cross +``` + +Depending on your system, you may need to configure the target to use the GNU +GCC linker. To use it, add the following to your `.cargo/config.toml`: + +```toml +[target.s390x-unknown-linux-gnu] +linker = "s390x-linux-gnu-gcc" +``` + +If your `s390x-linux-gnu-*` toolchain is not in your `PATH` you may need to +configure additional settings: + +```toml +[target.s390x-unknown-linux-gnu] +# Adjust the paths to point at your toolchain +cc = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-gcc" +cxx = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-g++" +ar = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-ar" +ranlib = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-ranlib" +linker = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-gcc" +``` + +To test cross compiled binaries on a non-s390x host, you can use +[`qemu`](https://www.qemu.org/docs/master/system/target-s390x.html). +On Ubuntu, a s390x emulator can be obtained with: + +```bash +apt install qemu-system-s390x +``` + +Then, in `.cargo/config.toml` set the `runner`: + +```toml +[target.s390x-unknown-linux-gnu] +runner = "qemu-s390x-static -L /usr/s390x-linux-gnu" +``` diff --git a/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md new file mode 100644 index 00000000000..e00f8db7f8e --- /dev/null +++ b/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md @@ -0,0 +1,83 @@ +# `s390x-unknown-linux-musl` + +**Tier: 3** + +IBM z/Architecture (s390x) targets (including IBM Z and LinuxONE) running Linux. + +## Target maintainers + +- Ulrich Weigand, <ulrich.weigand@de.ibm.com>, [@uweigand](https://github.com/uweigand) + +## Requirements + +This target requires: + +* Linux Kernel version 3.2 or later +* musl 1.2.3 or later + +Code generated by the target uses the z/Architecture ISA assuming a minimum +architecture level of z10 (Eighth Edition of the z/Architecture Principles +of Operation), and is compliant with the s390x ELF ABI. + +Reference material: + +* [z/Architecture Principles of Operation][s390x-isa] +* [z/Architecture ELF Application Binary Interface][s390x-abi] + +[s390x-isa]: https://publibfp.dhe.ibm.com/epubs/pdf/a227832d.pdf +[s390x-abi]: https://github.com/IBM/s390x-abi + +## Building the target + +Because it is Tier 3, Rust does not yet ship pre-compiled artifacts for this +target. + +Therefore, you can build Rust with support for the target by adding it to the +target list in `config.toml`, a sample configuration is shown below. + +```toml +[build] +target = ["s390x-unknown-linux-musl"] +``` + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will first need to build Rust with the target enabled (see +"Building the target" above). + +## Testing + +There are no special requirements for testing and running the target. +For testing cross builds on the host, please refer to the "Cross-compilation +toolchains and C code" section below. + +## Cross-compilation toolchains and C code + +Rust code built using the target is compatible with C code compiled with +GCC or Clang using the `s390x-unknown-linux-musl` target triple (via either +native or cross-compilation). + +Depending on your system, you may need to configure the target to use the GNU +GCC linker. To use it, add the following to your `.cargo/config.toml`: + +```toml +[target.s390x-unknown-linux-musl] +linker = "s390x-linux-musl-gcc" +``` + +If your `s390x-linux-musl-*` toolchain is not in your `PATH` you may need to +configure additional settings: + +```toml +[target.s390x-unknown-linux-musl] +# Adjust the paths to point at your toolchain +cc = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-gcc" +cxx = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-g++" +ar = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-ar" +ranlib = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-ranlib" +linker = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-gcc" +``` + +To test cross compiled binaries on a non-s390x host, you can use +[`qemu`](https://www.qemu.org/docs/master/system/target-s390x.html). diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip2.md b/src/doc/rustc/src/platform-support/wasm32-wasip2.md index bb2348b201e..40049ecfa5f 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip2.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip2.md @@ -1,6 +1,6 @@ # `wasm32-wasip2` -**Tier: 3** +**Tier: 2** The `wasm32-wasip2` target is a new and still (as of January 2024) an experimental target. This target is an extension to `wasm32-wasip1` target, diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index f8fb5284472..1af5e2b0e1d 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -447,32 +447,3 @@ This flag is **deprecated** and **has no effect**. Rustdoc only supports Rust source code and Markdown input formats. If the file ends in `.md` or `.markdown`, `rustdoc` treats it as a Markdown file. Otherwise, it assumes that the input file is Rust. - -## `--test-builder`: `rustc`-like program to build tests - -Using this flag looks like this: - -```bash -$ rustdoc --test-builder /path/to/rustc src/lib.rs -``` - -Rustdoc will use the provided program to compile tests instead of the default `rustc` program from -the sysroot. - -## `--test-builder-wrapper`: wrap calls to the test builder - -Using this flag looks like this: - -```bash -$ rustdoc --test-builder-wrapper /path/to/rustc-wrapper src/lib.rs -$ rustdoc \ - --test-builder-wrapper rustc-wrapper1 \ - --test-builder-wrapper rustc-wrapper2 \ - --test-builder rustc \ - src/lib.rs -``` - -Similar to cargo `build.rustc-wrapper` option, this flag takes a `rustc` wrapper program. -The first argument to the program will be the test builder program. - -This flag can be passed multiple times to nest wrappers. diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index ebbe141b6f5..e9524c0b78d 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -627,3 +627,36 @@ add the `--scrape-tests` flag. This flag enables the generation of links in the source code pages which allow the reader to jump to a type definition. + +### `--test-builder`: `rustc`-like program to build tests + + * Tracking issue: [#102981](https://github.com/rust-lang/rust/issues/102981) + +Using this flag looks like this: + +```bash +$ rustdoc --test-builder /path/to/rustc src/lib.rs +``` + +Rustdoc will use the provided program to compile tests instead of the default `rustc` program from +the sysroot. + +### `--test-builder-wrapper`: wrap calls to the test builder + + * Tracking issue: [#102981](https://github.com/rust-lang/rust/issues/102981) + +Using this flag looks like this: + +```bash +$ rustdoc -Zunstable-options --test-builder-wrapper /path/to/rustc-wrapper src/lib.rs +$ rustdoc -Zunstable-options \ + --test-builder-wrapper rustc-wrapper1 \ + --test-builder-wrapper rustc-wrapper2 \ + --test-builder rustc \ + src/lib.rs +``` + +Similar to cargo `build.rustc-wrapper` option, this flag takes a `rustc` wrapper program. +The first argument to the program will be the test builder program. + +This flag can be passed multiple times to nest wrappers. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f0787d286fd..e42350dc5e6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -42,7 +42,8 @@ use rustc_errors::{FatalError, struct_span_code_err}; use rustc_hir::PredicateOrigin; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId}; -use rustc_hir_analysis::lower_ty; +use rustc_hir_analysis::hir_ty_lowering::FeedConstTy; +use rustc_hir_analysis::{lower_const_arg_for_rustdoc, lower_ty}; use rustc_middle::metadata::Reexport; use rustc_middle::middle::resolve_bound_vars as rbv; use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode}; @@ -435,10 +436,10 @@ fn clean_middle_term<'tcx>( fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term { match term { hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)), - hir::Term::Const(c) => Term::Constant(clean_middle_const( - ty::Binder::dummy(ty::Const::from_const_arg(cx.tcx, c, ty::FeedConstTy::No)), - cx, - )), + hir::Term::Const(c) => { + let ct = lower_const_arg_for_rustdoc(cx.tcx, c, FeedConstTy::No); + Term::Constant(clean_middle_const(ty::Binder::dummy(ct), cx)) + } } } @@ -625,7 +626,7 @@ fn clean_generic_param<'tcx>( (param.name.ident().name, GenericParamDefKind::Const { ty: Box::new(clean_ty(ty, cx)), default: default.map(|ct| { - Box::new(ty::Const::from_const_arg(cx.tcx, ct, ty::FeedConstTy::No).to_string()) + Box::new(lower_const_arg_for_rustdoc(cx.tcx, ct, FeedConstTy::No).to_string()) }), synthetic, }) @@ -1813,7 +1814,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T // `const_eval_poly` tries to first substitute generic parameters which // results in an ICE while manually constructing the constant and using `eval` // does nothing for `ConstKind::Param`. - let ct = ty::Const::from_const_arg(cx.tcx, const_arg, ty::FeedConstTy::No); + let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); let ct = if let hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) = const_arg.kind { diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 4def80764ea..29f6f92a6b2 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -861,10 +861,9 @@ impl<'src> Classifier<'src> { }, Some(c) => c, }, - TokenKind::RawIdent - | TokenKind::UnknownPrefix - | TokenKind::InvalidPrefix - | TokenKind::InvalidIdent => Class::Ident(self.new_span(before, text)), + TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => { + Class::Ident(self.new_span(before, text)) + } TokenKind::Lifetime { .. } | TokenKind::RawLifetime | TokenKind::UnknownPrefixLifetime => Class::Lifetime, diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index b314b060368..d4cca562d6c 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -36,7 +36,7 @@ pub(crate) enum LinkFromSrc { /// It returns the `krate`, the source code files and the `span` correspondence map. /// /// Note about the `span` correspondence map: the keys are actually `(lo, hi)` of `span`s. We don't -/// need the `span` context later on, only their position, so instead of keep a whole `Span`, we +/// need the `span` context later on, only their position, so instead of keeping a whole `Span`, we /// only keep the `lo` and `hi`. pub(crate) fn collect_spans_and_sources( tcx: TyCtxt<'_>, @@ -45,9 +45,9 @@ pub(crate) fn collect_spans_and_sources( include_sources: bool, generate_link_to_definition: bool, ) -> (FxIndexMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) { - let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() }; - if include_sources { + let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() }; + if generate_link_to_definition { tcx.hir().walk_toplevel_module(&mut visitor); } @@ -76,7 +76,22 @@ impl<'tcx> SpanMapVisitor<'tcx> { } else { LinkFromSrc::External(def_id) }; - self.matches.insert(path.span, link); + // In case the path ends with generics, we remove them from the span. + let span = path + .segments + .last() + .map(|last| { + // In `use` statements, the included item is not in the path segments. + // However, it doesn't matter because you can't have generics on `use` + // statements. + if path.span.contains(last.ident.span) { + path.span.with_hi(last.ident.span.hi()) + } else { + path.span + } + }) + .unwrap_or(path.span); + self.matches.insert(span, link); } Res::Local(_) => { if let Some(span) = self.tcx.hir().res_span(path.res) { diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index c1a021e9f8d..9e5cf497211 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -988,6 +988,12 @@ class VlqHexDecoder { } class RoaringBitmap { constructor(str) { + // https://github.com/RoaringBitmap/RoaringFormatSpec + // + // Roaring bitmaps are used for flags that can be kept in their + // compressed form, even when loaded into memory. This decoder + // turns the containers into objects, but uses byte array + // slices of the original format for the data payload. const strdecoded = atob(str); const u8array = new Uint8Array(strdecoded.length); for (let j = 0; j < strdecoded.length; ++j) { @@ -1053,9 +1059,24 @@ class RoaringBitmap { contains(keyvalue) { const key = keyvalue >> 16; const value = keyvalue & 0xFFFF; - for (let i = 0; i < this.keys.length; ++i) { - if (this.keys[i] === key) { - return this.containers[i].contains(value); + // Binary search algorithm copied from + // https://en.wikipedia.org/wiki/Binary_search#Procedure + // + // Format is required by specification to be sorted. + // Because keys are 16 bits and unique, length can't be + // bigger than 2**16, and because we have 32 bits of safe int, + // left + right can't overflow. + let left = 0; + let right = this.keys.length - 1; + while (left <= right) { + const mid = Math.floor((left + right) / 2); + const x = this.keys[mid]; + if (x < key) { + left = mid + 1; + } else if (x > key) { + right = mid - 1; + } else { + return this.containers[mid].contains(value); } } return false; @@ -1068,11 +1089,23 @@ class RoaringBitmapRun { this.array = array; } contains(value) { - const l = this.runcount * 4; - for (let i = 0; i < l; i += 4) { + // Binary search algorithm copied from + // https://en.wikipedia.org/wiki/Binary_search#Procedure + // + // Since runcount is stored as 16 bits, left + right + // can't overflow. + let left = 0; + let right = this.runcount - 1; + while (left <= right) { + const mid = Math.floor((left + right) / 2); + const i = mid * 4; const start = this.array[i] | (this.array[i + 1] << 8); const lenm1 = this.array[i + 2] | (this.array[i + 3] << 8); - if (value >= start && value <= (start + lenm1)) { + if ((start + lenm1) < value) { + left = mid + 1; + } else if (start > value) { + right = mid - 1; + } else { return true; } } @@ -1085,10 +1118,22 @@ class RoaringBitmapArray { this.array = array; } contains(value) { - const l = this.cardinality * 2; - for (let i = 0; i < l; i += 2) { - const start = this.array[i] | (this.array[i + 1] << 8); - if (value === start) { + // Binary search algorithm copied from + // https://en.wikipedia.org/wiki/Binary_search#Procedure + // + // Since cardinality can't be higher than 4096, left + right + // cannot overflow. + let left = 0; + let right = this.cardinality - 1; + while (left <= right) { + const mid = Math.floor((left + right) / 2); + const i = mid * 2; + const x = this.array[i] | (this.array[i + 1] << 8); + if (x < value) { + left = mid + 1; + } else if (x > value) { + right = mid - 1; + } else { return true; } } diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock index 8dad30df6d1..0c0fe477cdd 100644 --- a/src/tools/miri/miri-script/Cargo.lock +++ b/src/tools/miri/miri-script/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "anyhow" @@ -521,15 +521,15 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] name = "xshell" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437" +checksum = "9e7290c623014758632efe00737145b6867b66292c42167f2ec381eb566a373d" dependencies = [ "xshell-macros", ] [[package]] name = "xshell-macros" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852" +checksum = "32ac00cd3f8ec9c1d33fb3e7958a82df6989c42d747bd326c822b1d625283547" diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index 3c0eb1b42a6..c97596d5097 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -183,7 +183,7 @@ impl<'a> Converter<'a> { rustc_lexer::TokenKind::Ident => { SyntaxKind::from_keyword(token_text, self.edition).unwrap_or(IDENT) } - rustc_lexer::TokenKind::InvalidPrefix | rustc_lexer::TokenKind::InvalidIdent => { + rustc_lexer::TokenKind::InvalidIdent => { err = "Ident contains invalid characters"; IDENT } diff --git a/tests/crashes/130687.rs b/tests/crashes/130687.rs deleted file mode 100644 index 361be0905df..00000000000 --- a/tests/crashes/130687.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #130687 -//@ only-x86_64 -pub struct Data([u8; usize::MAX >> 16]); -const _: &'static Data = &Data([0; usize::MAX >> 16]); diff --git a/tests/crashes/132985.rs b/tests/crashes/132985.rs new file mode 100644 index 00000000000..2735074f44d --- /dev/null +++ b/tests/crashes/132985.rs @@ -0,0 +1,17 @@ +//@ known-bug: #132985 +//@ aux-build:aux132985.rs + +#![allow(incomplete_features)] +#![feature(min_generic_const_args)] +#![feature(adt_const_params)] + +extern crate aux132985; +use aux132985::Foo; + +fn bar<const N: Foo>() {} + +fn baz() { + bar::<{ Foo }>(); +} + +fn main() {} diff --git a/tests/crashes/auxiliary/aux132985.rs b/tests/crashes/auxiliary/aux132985.rs new file mode 100644 index 00000000000..7ae5567bdc5 --- /dev/null +++ b/tests/crashes/auxiliary/aux132985.rs @@ -0,0 +1,6 @@ +#![feature(adt_const_params)] + +use std::marker::ConstParamTy; + +#[derive(Eq, PartialEq, ConstParamTy)] +pub struct Foo; diff --git a/tests/rustdoc/link-on-path-with-generics.rs b/tests/rustdoc/link-on-path-with-generics.rs new file mode 100644 index 00000000000..22ba36c9f15 --- /dev/null +++ b/tests/rustdoc/link-on-path-with-generics.rs @@ -0,0 +1,14 @@ +// This test ensures that paths with generics still get their link to their definition +// correctly generated. + +//@ compile-flags: -Zunstable-options --generate-link-to-definition +#![crate_name = "foo"] + +//@ has 'src/foo/link-on-path-with-generics.rs.html' + +pub struct Soyo<T>(T); +pub struct Saya; + +//@ has - '//pre[@class="rust"]//a[@href="#9"]' 'Soyo' +//@ has - '//pre[@class="rust"]//a[@href="#10"]' 'Saya' +pub fn bar<T>(s: Soyo<T>, x: Saya) {} diff --git a/tests/ui/check-cfg/auxiliary/cfg_macro.rs b/tests/ui/check-cfg/auxiliary/cfg_macro.rs new file mode 100644 index 00000000000..d68accd9202 --- /dev/null +++ b/tests/ui/check-cfg/auxiliary/cfg_macro.rs @@ -0,0 +1,11 @@ +// Inspired by https://github.com/rust-lang/cargo/issues/14775 + +pub fn my_lib_func() {} + +#[macro_export] +macro_rules! my_lib_macro { + () => { + #[cfg(my_lib_cfg)] + $crate::my_lib_func() + }; +} diff --git a/tests/ui/check-cfg/report-in-external-macros.rs b/tests/ui/check-cfg/report-in-external-macros.rs new file mode 100644 index 00000000000..56550b04af3 --- /dev/null +++ b/tests/ui/check-cfg/report-in-external-macros.rs @@ -0,0 +1,12 @@ +// This test checks that we emit the `unexpected_cfgs` lint even in code +// coming from an external macro. + +//@ check-pass +//@ no-auto-check-cfg +//@ aux-crate: cfg_macro=cfg_macro.rs +//@ compile-flags: --check-cfg=cfg() + +fn main() { + cfg_macro::my_lib_macro!(); + //~^ WARNING unexpected `cfg` condition name +} diff --git a/tests/ui/check-cfg/report-in-external-macros.stderr b/tests/ui/check-cfg/report-in-external-macros.stderr new file mode 100644 index 00000000000..11300a4e402 --- /dev/null +++ b/tests/ui/check-cfg/report-in-external-macros.stderr @@ -0,0 +1,14 @@ +warning: unexpected `cfg` condition name: `my_lib_cfg` + --> $DIR/report-in-external-macros.rs:10:5 + | +LL | cfg_macro::my_lib_macro!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `fmt_debug`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` + = help: to expect this configuration use `--check-cfg=cfg(my_lib_cfg)` + = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + = note: this warning originates in the macro `cfg_macro::my_lib_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/tests/ui/const-generics/auxiliary/xcrate-const-ctor-a.rs b/tests/ui/const-generics/auxiliary/xcrate-const-ctor-a.rs new file mode 100644 index 00000000000..7ae5567bdc5 --- /dev/null +++ b/tests/ui/const-generics/auxiliary/xcrate-const-ctor-a.rs @@ -0,0 +1,6 @@ +#![feature(adt_const_params)] + +use std::marker::ConstParamTy; + +#[derive(Eq, PartialEq, ConstParamTy)] +pub struct Foo; diff --git a/tests/ui/const-generics/using-static-as-const-arg.rs b/tests/ui/const-generics/using-static-as-const-arg.rs new file mode 100644 index 00000000000..2e8a2a14484 --- /dev/null +++ b/tests/ui/const-generics/using-static-as-const-arg.rs @@ -0,0 +1,7 @@ +//@ check-pass + +pub static STATIC: u32 = 0; +pub struct Foo<const N: u32>; +pub const FOO: Foo<{STATIC}> = Foo; + +fn main() {} diff --git a/tests/ui/const-generics/xcrate-const-ctor-b.rs b/tests/ui/const-generics/xcrate-const-ctor-b.rs new file mode 100644 index 00000000000..dce2e43b316 --- /dev/null +++ b/tests/ui/const-generics/xcrate-const-ctor-b.rs @@ -0,0 +1,15 @@ +//@ check-pass +//@ aux-build:xcrate-const-ctor-a.rs + +#![feature(adt_const_params)] + +extern crate xcrate_const_ctor_a; +use xcrate_const_ctor_a::Foo; + +fn bar<const N: Foo>() {} + +fn baz() { + bar::<{ Foo }>(); +} + +fn main() {} diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs new file mode 100644 index 00000000000..b923a768cbf --- /dev/null +++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs @@ -0,0 +1,12 @@ +//! Ensure we do not ICE when a promoted fails to evaluate due to running out of memory. +//! Also see <https://github.com/rust-lang/rust/issues/130687>. + +// Needs the max type size to be much bigger than the RAM people typically have. +//@ only-64bit + +pub struct Data([u8; (1 << 47) - 1]); +const _: &'static Data = &Data([0; (1 << 47) - 1]); +//~^ERROR: evaluation of constant value failed +//~| tried to allocate more memory than available to compiler + +fn main() {} diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr new file mode 100644 index 00000000000..50e920f05f9 --- /dev/null +++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/promoted_running_out_of_memory_issue-130687.rs:8:32 + | +LL | const _: &'static Data = &Data([0; (1 << 47) - 1]); + | ^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler + +note: erroneous constant encountered + --> $DIR/promoted_running_out_of_memory_issue-130687.rs:8:26 + | +LL | const _: &'static Data = &Data([0; (1 << 47) - 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs b/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs index 1d946a14aff..a46c856d38e 100644 --- a/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs +++ b/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs @@ -1,3 +1,5 @@ +//@ reference: attributes.diagnostic.namespace.unknown-invalid-syntax + #![deny(unknown_or_malformed_diagnostic_attributes)] #[diagnostic::unknown_attribute] diff --git a/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr b/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr index a646d3613de..32be9db5317 100644 --- a/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr +++ b/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr @@ -1,11 +1,11 @@ error: unknown diagnostic attribute - --> $DIR/deny_malformed_attribute.rs:3:15 + --> $DIR/deny_malformed_attribute.rs:5:15 | LL | #[diagnostic::unknown_attribute] | ^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/deny_malformed_attribute.rs:1:9 + --> $DIR/deny_malformed_attribute.rs:3:9 | LL | #![deny(unknown_or_malformed_diagnostic_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs index 8b7467a17d0..b90dd0c7c94 100644 --- a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs +++ b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs @@ -1,5 +1,6 @@ //@ edition:2021 //@ aux-build:bad_on_unimplemented.rs +//@ reference: attributes.diagnostic.on_unimplemented.syntax // Do not ICE when encountering a malformed `#[diagnostic::on_unimplemented]` annotation in a // dependency when incorrectly used (#124651). diff --git a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr index c3e56550b70..f1258ad6b9a 100644 --- a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr +++ b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `(): bad_on_unimplemented::MissingAttr` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:22:18 + --> $DIR/malformed_foreign_on_unimplemented.rs:23:18 | LL | missing_attr(()); | ------------ ^^ the trait `bad_on_unimplemented::MissingAttr` is not implemented for `()` @@ -7,13 +7,13 @@ LL | missing_attr(()); | required by a bound introduced by this call | note: required by a bound in `missing_attr` - --> $DIR/malformed_foreign_on_unimplemented.rs:11:20 + --> $DIR/malformed_foreign_on_unimplemented.rs:12:20 | LL | fn missing_attr<T: MissingAttr>(_: T) {} | ^^^^^^^^^^^ required by this bound in `missing_attr` error[E0277]: the trait bound `(): bad_on_unimplemented::DuplicateAttr` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:23:20 + --> $DIR/malformed_foreign_on_unimplemented.rs:24:20 | LL | duplicate_attr(()); | -------------- ^^ a @@ -22,13 +22,13 @@ LL | duplicate_attr(()); | = help: the trait `bad_on_unimplemented::DuplicateAttr` is not implemented for `()` note: required by a bound in `duplicate_attr` - --> $DIR/malformed_foreign_on_unimplemented.rs:12:22 + --> $DIR/malformed_foreign_on_unimplemented.rs:13:22 | LL | fn duplicate_attr<T: DuplicateAttr>(_: T) {} | ^^^^^^^^^^^^^ required by this bound in `duplicate_attr` error[E0277]: the trait bound `(): bad_on_unimplemented::NotMetaList` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:24:19 + --> $DIR/malformed_foreign_on_unimplemented.rs:25:19 | LL | not_meta_list(()); | ------------- ^^ the trait `bad_on_unimplemented::NotMetaList` is not implemented for `()` @@ -36,13 +36,13 @@ LL | not_meta_list(()); | required by a bound introduced by this call | note: required by a bound in `not_meta_list` - --> $DIR/malformed_foreign_on_unimplemented.rs:13:21 + --> $DIR/malformed_foreign_on_unimplemented.rs:14:21 | LL | fn not_meta_list<T: NotMetaList>(_: T) {} | ^^^^^^^^^^^ required by this bound in `not_meta_list` error[E0277]: the trait bound `(): bad_on_unimplemented::Empty` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:25:11 + --> $DIR/malformed_foreign_on_unimplemented.rs:26:11 | LL | empty(()); | ----- ^^ the trait `bad_on_unimplemented::Empty` is not implemented for `()` @@ -50,13 +50,13 @@ LL | empty(()); | required by a bound introduced by this call | note: required by a bound in `empty` - --> $DIR/malformed_foreign_on_unimplemented.rs:14:13 + --> $DIR/malformed_foreign_on_unimplemented.rs:15:13 | LL | fn empty<T: Empty>(_: T) {} | ^^^^^ required by this bound in `empty` error[E0277]: the trait bound `(): bad_on_unimplemented::WrongDelim` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:26:17 + --> $DIR/malformed_foreign_on_unimplemented.rs:27:17 | LL | wrong_delim(()); | ----------- ^^ the trait `bad_on_unimplemented::WrongDelim` is not implemented for `()` @@ -64,13 +64,13 @@ LL | wrong_delim(()); | required by a bound introduced by this call | note: required by a bound in `wrong_delim` - --> $DIR/malformed_foreign_on_unimplemented.rs:15:19 + --> $DIR/malformed_foreign_on_unimplemented.rs:16:19 | LL | fn wrong_delim<T: WrongDelim>(_: T) {} | ^^^^^^^^^^ required by this bound in `wrong_delim` error[E0277]: the trait bound `(): bad_on_unimplemented::BadFormatter<()>` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:27:19 + --> $DIR/malformed_foreign_on_unimplemented.rs:28:19 | LL | bad_formatter(()); | ------------- ^^ () @@ -79,13 +79,13 @@ LL | bad_formatter(()); | = help: the trait `bad_on_unimplemented::BadFormatter<()>` is not implemented for `()` note: required by a bound in `bad_formatter` - --> $DIR/malformed_foreign_on_unimplemented.rs:16:21 + --> $DIR/malformed_foreign_on_unimplemented.rs:17:21 | LL | fn bad_formatter<T: BadFormatter<()>>(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `bad_formatter` error[E0277]: the trait bound `(): bad_on_unimplemented::NoImplicitArgs` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:28:22 + --> $DIR/malformed_foreign_on_unimplemented.rs:29:22 | LL | no_implicit_args(()); | ---------------- ^^ test {} @@ -94,13 +94,13 @@ LL | no_implicit_args(()); | = help: the trait `bad_on_unimplemented::NoImplicitArgs` is not implemented for `()` note: required by a bound in `no_implicit_args` - --> $DIR/malformed_foreign_on_unimplemented.rs:17:24 + --> $DIR/malformed_foreign_on_unimplemented.rs:18:24 | LL | fn no_implicit_args<T: NoImplicitArgs>(_: T) {} | ^^^^^^^^^^^^^^ required by this bound in `no_implicit_args` error[E0277]: the trait bound `(): bad_on_unimplemented::MissingArg` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:29:17 + --> $DIR/malformed_foreign_on_unimplemented.rs:30:17 | LL | missing_arg(()); | ----------- ^^ {missing} @@ -109,13 +109,13 @@ LL | missing_arg(()); | = help: the trait `bad_on_unimplemented::MissingArg` is not implemented for `()` note: required by a bound in `missing_arg` - --> $DIR/malformed_foreign_on_unimplemented.rs:18:19 + --> $DIR/malformed_foreign_on_unimplemented.rs:19:19 | LL | fn missing_arg<T: MissingArg>(_: T) {} | ^^^^^^^^^^ required by this bound in `missing_arg` error[E0277]: the trait bound `(): bad_on_unimplemented::BadArg` is not satisfied - --> $DIR/malformed_foreign_on_unimplemented.rs:30:13 + --> $DIR/malformed_foreign_on_unimplemented.rs:31:13 | LL | bad_arg(()); | ------- ^^ {_} @@ -124,7 +124,7 @@ LL | bad_arg(()); | = help: the trait `bad_on_unimplemented::BadArg` is not implemented for `()` note: required by a bound in `bad_arg` - --> $DIR/malformed_foreign_on_unimplemented.rs:19:15 + --> $DIR/malformed_foreign_on_unimplemented.rs:20:15 | LL | fn bad_arg<T: BadArg>(_: T) {} | ^^^^^^ required by this bound in `bad_arg` diff --git a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs index f6957b1448d..02c1352482c 100644 --- a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs +++ b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs @@ -1,4 +1,5 @@ //@ check-pass +//@ reference: attributes.diagnostic.namespace.unknown-invalid-syntax #[diagnostic::non_existing_attribute] //~^WARN unknown diagnostic attribute pub trait Bar { diff --git a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr index c073ec9b103..753077b365e 100644 --- a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr +++ b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr @@ -1,5 +1,5 @@ warning: unknown diagnostic attribute - --> $DIR/non_existing_attributes_accepted.rs:2:15 + --> $DIR/non_existing_attributes_accepted.rs:3:15 | LL | #[diagnostic::non_existing_attribute] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[diagnostic::non_existing_attribute] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: unknown diagnostic attribute - --> $DIR/non_existing_attributes_accepted.rs:7:15 + --> $DIR/non_existing_attributes_accepted.rs:8:15 | LL | #[diagnostic::non_existing_attribute(with_option = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs index 3ca58b28181..44f269eb967 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs @@ -1,3 +1,4 @@ +//@ reference: attributes.diagnostic.on_unimplemented.invalid-string #[diagnostic::on_unimplemented(message = "{{Test } thing")] //~^WARN unmatched `}` found //~|WARN unmatched `}` found diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr index b4ed06cb63d..7fd51c7527f 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr @@ -1,5 +1,5 @@ warning: unmatched `}` found - --> $DIR/broken_format.rs:1:32 + --> $DIR/broken_format.rs:2:32 | LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: positional format arguments are not allowed here - --> $DIR/broken_format.rs:6:32 + --> $DIR/broken_format.rs:7:32 | LL | #[diagnostic::on_unimplemented(message = "Test {}")] | ^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {}")] = help: only named format arguments with the name of one of the generic types are allowed in this context warning: positional format arguments are not allowed here - --> $DIR/broken_format.rs:11:32 + --> $DIR/broken_format.rs:12:32 | LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] | ^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] = help: only named format arguments with the name of one of the generic types are allowed in this context warning: invalid format specifier - --> $DIR/broken_format.rs:16:32 + --> $DIR/broken_format.rs:17:32 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,19 +31,19 @@ LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] = help: no format specifier are supported in this position warning: expected `}`, found `!` - --> $DIR/broken_format.rs:21:32 + --> $DIR/broken_format.rs:22:32 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unmatched `}` found - --> $DIR/broken_format.rs:21:32 + --> $DIR/broken_format.rs:22:32 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unmatched `}` found - --> $DIR/broken_format.rs:1:32 + --> $DIR/broken_format.rs:2:32 | LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -51,7 +51,7 @@ LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: {{Test } thing - --> $DIR/broken_format.rs:35:13 + --> $DIR/broken_format.rs:36:13 | LL | check_1(()); | ------- ^^ the trait `ImportantTrait1` is not implemented for `()` @@ -59,18 +59,18 @@ LL | check_1(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/broken_format.rs:4:1 + --> $DIR/broken_format.rs:5:1 | LL | trait ImportantTrait1 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_1` - --> $DIR/broken_format.rs:28:20 + --> $DIR/broken_format.rs:29:20 | LL | fn check_1(_: impl ImportantTrait1) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_1` warning: positional format arguments are not allowed here - --> $DIR/broken_format.rs:6:32 + --> $DIR/broken_format.rs:7:32 | LL | #[diagnostic::on_unimplemented(message = "Test {}")] | ^^^^^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Test {} - --> $DIR/broken_format.rs:37:13 + --> $DIR/broken_format.rs:38:13 | LL | check_2(()); | ------- ^^ the trait `ImportantTrait2` is not implemented for `()` @@ -87,18 +87,18 @@ LL | check_2(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/broken_format.rs:9:1 + --> $DIR/broken_format.rs:10:1 | LL | trait ImportantTrait2 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_2` - --> $DIR/broken_format.rs:29:20 + --> $DIR/broken_format.rs:30:20 | LL | fn check_2(_: impl ImportantTrait2) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_2` warning: positional format arguments are not allowed here - --> $DIR/broken_format.rs:11:32 + --> $DIR/broken_format.rs:12:32 | LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] | ^^^^^^^^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Test {1} - --> $DIR/broken_format.rs:39:13 + --> $DIR/broken_format.rs:40:13 | LL | check_3(()); | ------- ^^ the trait `ImportantTrait3` is not implemented for `()` @@ -115,18 +115,18 @@ LL | check_3(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/broken_format.rs:14:1 + --> $DIR/broken_format.rs:15:1 | LL | trait ImportantTrait3 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_3` - --> $DIR/broken_format.rs:30:20 + --> $DIR/broken_format.rs:31:20 | LL | fn check_3(_: impl ImportantTrait3) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_3` warning: invalid format specifier - --> $DIR/broken_format.rs:16:32 + --> $DIR/broken_format.rs:17:32 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Test () - --> $DIR/broken_format.rs:41:13 + --> $DIR/broken_format.rs:42:13 | LL | check_4(()); | ------- ^^ the trait `ImportantTrait4` is not implemented for `()` @@ -143,18 +143,18 @@ LL | check_4(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/broken_format.rs:19:1 + --> $DIR/broken_format.rs:20:1 | LL | trait ImportantTrait4 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_4` - --> $DIR/broken_format.rs:31:20 + --> $DIR/broken_format.rs:32:20 | LL | fn check_4(_: impl ImportantTrait4) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_4` warning: expected `}`, found `!` - --> $DIR/broken_format.rs:21:32 + --> $DIR/broken_format.rs:22:32 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: unmatched `}` found - --> $DIR/broken_format.rs:21:32 + --> $DIR/broken_format.rs:22:32 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,7 +170,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Test {Self:!} - --> $DIR/broken_format.rs:43:13 + --> $DIR/broken_format.rs:44:13 | LL | check_5(()); | ------- ^^ the trait `ImportantTrait5` is not implemented for `()` @@ -178,12 +178,12 @@ LL | check_5(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/broken_format.rs:26:1 + --> $DIR/broken_format.rs:27:1 | LL | trait ImportantTrait5 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_5` - --> $DIR/broken_format.rs:32:20 + --> $DIR/broken_format.rs:33:20 | LL | fn check_5(_: impl ImportantTrait5) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_5` diff --git a/tests/ui/traits/custom-on-unimplemented-diagnostic.rs b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs index d7e257ef3bb..1173c939038 100644 --- a/tests/ui/traits/custom-on-unimplemented-diagnostic.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs @@ -1,3 +1,5 @@ +//@ reference: attributes.diagnostic.on_unimplemented.intro +//@ reference: attributes.diagnostic.on_unimplemented.keys #[diagnostic::on_unimplemented(message = "my message", label = "my label", note = "my note")] pub trait ProviderLt {} diff --git a/tests/ui/traits/custom-on-unimplemented-diagnostic.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr index f9788360d06..4c1838620b3 100644 --- a/tests/ui/traits/custom-on-unimplemented-diagnostic.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr @@ -1,5 +1,5 @@ error[E0599]: my message - --> $DIR/custom-on-unimplemented-diagnostic.rs:15:7 + --> $DIR/custom-on-unimplemented-diagnostic.rs:17:7 | LL | struct B; | -------- method `request` not found for this struct because it doesn't satisfy `B: ProviderExt` or `B: ProviderLt` @@ -8,7 +8,7 @@ LL | B.request(); | ^^^^^^^ my label | note: trait bound `B: ProviderLt` was not satisfied - --> $DIR/custom-on-unimplemented-diagnostic.rs:10:18 + --> $DIR/custom-on-unimplemented-diagnostic.rs:12:18 | LL | impl<T: ?Sized + ProviderLt> ProviderExt for T {} | ^^^^^^^^^^ ----------- - @@ -16,13 +16,13 @@ LL | impl<T: ?Sized + ProviderLt> ProviderExt for T {} | unsatisfied trait bound introduced here = note: my note note: the trait `ProviderLt` must be implemented - --> $DIR/custom-on-unimplemented-diagnostic.rs:2:1 + --> $DIR/custom-on-unimplemented-diagnostic.rs:4:1 | LL | pub trait ProviderLt {} | ^^^^^^^^^^^^^^^^^^^^ = help: items from traits can only be used if the trait is implemented and in scope note: `ProviderExt` defines an item `request`, perhaps you need to implement it - --> $DIR/custom-on-unimplemented-diagnostic.rs:4:1 + --> $DIR/custom-on-unimplemented-diagnostic.rs:6:1 | LL | pub trait ProviderExt { | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs index 30a85ff2199..b76b550fcb2 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs @@ -1,3 +1,7 @@ +//@ reference: attributes.diagnostic.on_unimplemented.format-parameters +//@ reference: attributes.diagnostic.on_unimplemented.keys +//@ reference: attributes.diagnostic.on_unimplemented.syntax +//@ reference: attributes.diagnostic.on_unimplemented.invalid-formats #[diagnostic::on_unimplemented( on(_Self = "&str"), //~^WARN malformed `on_unimplemented` attribute diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr index e34b917f67e..bb455d92940 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr @@ -1,5 +1,5 @@ warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:22:1 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:26:1 | LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:2:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:6:5 | LL | on(_Self = "&str"), | ^^^^^^^^^^^^^^^^^^ invalid option found here @@ -15,7 +15,7 @@ LL | on(_Self = "&str"), = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:8:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:12:5 | LL | parent_label = "in this scope", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -23,7 +23,7 @@ LL | parent_label = "in this scope", = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:11:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:15:5 | LL | append_const_msg | ^^^^^^^^^^^^^^^^ invalid option found here @@ -31,7 +31,7 @@ LL | append_const_msg = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:17:32 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:21:32 | LL | #[diagnostic::on_unimplemented = "Message"] | ^^^^^^^^^^^ invalid option found here @@ -39,7 +39,7 @@ LL | #[diagnostic::on_unimplemented = "Message"] = help: only `message`, `note` and `label` are allowed as options warning: there is no parameter `from_desugaring` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `direct` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `cause` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `integral` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `integer` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `float` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `_Self` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `crate_local` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `Trait` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -111,7 +111,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `ItemContext` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:2:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:6:5 | LL | on(_Self = "&str"), | ^^^^^^^^^^^^^^^^^^ invalid option found here @@ -128,7 +128,7 @@ LL | on(_Self = "&str"), = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:8:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:12:5 | LL | parent_label = "in this scope", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -137,7 +137,7 @@ LL | parent_label = "in this scope", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:11:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:15:5 | LL | append_const_msg | ^^^^^^^^^^^^^^^^ invalid option found here @@ -146,7 +146,7 @@ LL | append_const_msg = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: trait has `()` and `i32` as params - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:59:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:63:15 | LL | takes_foo(()); | --------- ^^ trait has `()` and `i32` as params @@ -156,18 +156,18 @@ LL | takes_foo(()); = help: the trait `Foo<i32>` is not implemented for `()` = note: trait has `()` and `i32` as params help: this trait has no implementations, consider adding one - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:15:1 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:19:1 | LL | trait Foo<T> {} | ^^^^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:54:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:58:22 | LL | fn takes_foo(_: impl Foo<i32>) {} | ^^^^^^^^ required by this bound in `takes_foo` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:17:32 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:21:32 | LL | #[diagnostic::on_unimplemented = "Message"] | ^^^^^^^^^^^ invalid option found here @@ -176,7 +176,7 @@ LL | #[diagnostic::on_unimplemented = "Message"] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `(): Bar` is not satisfied - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:61:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:65:15 | LL | takes_bar(()); | --------- ^^ the trait `Bar` is not implemented for `()` @@ -185,13 +185,13 @@ LL | takes_bar(()); | = help: the trait `Bar` is implemented for `i32` note: required by a bound in `takes_bar` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:55:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:59:22 | LL | fn takes_bar(_: impl Bar) {} | ^^^ required by this bound in `takes_bar` warning: there is no parameter `from_desugaring` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -200,7 +200,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `direct` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,7 +209,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `cause` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -218,7 +218,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `integral` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -227,7 +227,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `integer` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -236,7 +236,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `float` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -245,7 +245,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `_Self` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -254,7 +254,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `crate_local` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +263,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `Trait` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -272,7 +272,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `ItemContext` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -281,7 +281,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer} - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:63:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:67:15 | LL | takes_baz(()); | --------- ^^ {float}{_Self}{crate_local}{Trait}{ItemContext} @@ -290,12 +290,12 @@ LL | takes_baz(()); | = help: the trait `Baz` is not implemented for `()` help: this trait has no implementations, consider adding one - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:52:1 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:56:1 | LL | trait Baz {} | ^^^^^^^^^ note: required by a bound in `takes_baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:56:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:60:22 | LL | fn takes_baz(_: impl Baz) {} | ^^^ required by this bound in `takes_baz` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs index b4234066bb1..8328c10d2a0 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs @@ -1,3 +1,5 @@ +//@ reference: attributes.diagnostic.on_unimplemented.syntax +//@ reference: attributes.diagnostic.on_unimplemented.unknown-keys #[diagnostic::on_unimplemented(unsupported = "foo")] //~^WARN malformed `on_unimplemented` attribute //~|WARN malformed `on_unimplemented` attribute diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr index dc0c1948236..11263580b15 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr @@ -1,5 +1,5 @@ warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:6:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:8:1 | LL | #[diagnostic::on_unimplemented(message = "Baz")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[diagnostic::on_unimplemented(message = "Baz")] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:1:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32 | LL | #[diagnostic::on_unimplemented(unsupported = "foo")] | ^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -15,7 +15,7 @@ LL | #[diagnostic::on_unimplemented(unsupported = "foo")] = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:10:50 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] | ^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -23,7 +23,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:15:50 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -31,7 +31,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:20:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:32 | LL | #[diagnostic::on_unimplemented = "boom"] | ^^^^^^^^ invalid option found here @@ -39,7 +39,7 @@ LL | #[diagnostic::on_unimplemented = "boom"] = help: only `message`, `note` and `label` are allowed as options warning: missing options for `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:24:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1 | LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | #[diagnostic::on_unimplemented] = help: at least one of the `message`, `note` and `label` options are expected warning: there is no parameter `DoesNotExist` on trait `Test` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32 | LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] = help: expect either a generic argument name or `{Self}` as format argument warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:1:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32 | LL | #[diagnostic::on_unimplemented(unsupported = "foo")] | ^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -64,7 +64,7 @@ LL | #[diagnostic::on_unimplemented(unsupported = "foo")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `i32: Foo` is not satisfied - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:41:14 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:14 | LL | take_foo(1_i32); | -------- ^^^^^ the trait `Foo` is not implemented for `i32` @@ -72,18 +72,18 @@ LL | take_foo(1_i32); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:4:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:6:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `take_foo` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:21 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:36:21 | LL | fn take_foo(_: impl Foo) {} | ^^^ required by this bound in `take_foo` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:10:50 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] | ^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -92,7 +92,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Boom - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:14 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:45:14 | LL | take_baz(1_i32); | -------- ^^^^^ the trait `Baz` is not implemented for `i32` @@ -100,18 +100,18 @@ LL | take_baz(1_i32); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:13:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:15:1 | LL | trait Baz {} | ^^^^^^^^^ note: required by a bound in `take_baz` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:21 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:21 | LL | fn take_baz(_: impl Baz) {} | ^^^ required by this bound in `take_baz` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:15:50 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -120,7 +120,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Boom - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:45:15 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:47:15 | LL | take_boom(1_i32); | --------- ^^^^^ the trait `Boom` is not implemented for `i32` @@ -128,18 +128,18 @@ LL | take_boom(1_i32); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:18:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:20:1 | LL | trait Boom {} | ^^^^^^^^^^ note: required by a bound in `take_boom` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:36:22 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:38:22 | LL | fn take_boom(_: impl Boom) {} | ^^^^ required by this bound in `take_boom` warning: missing options for `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:24:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1 | LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +148,7 @@ LL | #[diagnostic::on_unimplemented] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `i32: Whatever` is not satisfied - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:47:19 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:49:19 | LL | take_whatever(1_i32); | ------------- ^^^^^ the trait `Whatever` is not implemented for `i32` @@ -156,18 +156,18 @@ LL | take_whatever(1_i32); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:27:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:1 | LL | trait Whatever {} | ^^^^^^^^^^^^^^ note: required by a bound in `take_whatever` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:26 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:39:26 | LL | fn take_whatever(_: impl Whatever) {} | ^^^^^^^^ required by this bound in `take_whatever` warning: there is no parameter `DoesNotExist` on trait `Test` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32 | LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -176,7 +176,7 @@ LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: {DoesNotExist} - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:49:15 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:51:15 | LL | take_test(()); | --------- ^^ the trait `Test` is not implemented for `()` @@ -184,12 +184,12 @@ LL | take_test(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:32:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:1 | LL | trait Test {} | ^^^^^^^^^^ note: required by a bound in `take_test` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:38:22 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:40:22 | LL | fn take_test(_: impl Test) {} | ^^^^ required by this bound in `take_test` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs index 7eaff73dca1..dff209d4761 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs @@ -1,4 +1,5 @@ //@ aux-build:other.rs +//@ reference: attributes.diagnostic.on_unimplemented.intro extern crate other; diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr index a9968538d0d..c0dd6d9628a 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr @@ -1,5 +1,5 @@ error[E0277]: Message - --> $DIR/error_is_shown_in_downstream_crates.rs:10:14 + --> $DIR/error_is_shown_in_downstream_crates.rs:11:14 | LL | take_foo(()); | -------- ^^ label @@ -9,7 +9,7 @@ LL | take_foo(()); = help: the trait `Foo` is not implemented for `()` = note: Note note: required by a bound in `take_foo` - --> $DIR/error_is_shown_in_downstream_crates.rs:7:21 + --> $DIR/error_is_shown_in_downstream_crates.rs:8:21 | LL | fn take_foo(_: impl Foo) {} | ^^^ required by this bound in `take_foo` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs index 5b25fb234bc..c638681173d 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs @@ -1,3 +1,5 @@ +//@ reference: attributes.diagnostic.on_unimplemented.repetition +//@ reference: attributes.diagnostic.on_unimplemented.syntax #[diagnostic::on_unimplemented( if(Self = "()"), //~^WARN malformed `on_unimplemented` attribute diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr index 56d125e20e5..e00846da77b 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr @@ -1,5 +1,5 @@ warning: malformed `on_unimplemented` attribute - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:2:5 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5 | LL | if(Self = "()"), | ^^^^^^^^^^^^^^^ invalid option found here @@ -8,7 +8,7 @@ LL | if(Self = "()"), = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: `message` is ignored due to previous definition of `message` - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:8:32 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:10:32 | LL | message = "custom message", | -------------------------- `message` is first declared here @@ -17,7 +17,7 @@ LL | #[diagnostic::on_unimplemented(message = "fallback!!")] | ^^^^^^^^^^^^^^^^^^^^^^ `message` is already declared here warning: malformed `on_unimplemented` attribute - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:2:5 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5 | LL | if(Self = "()"), | ^^^^^^^^^^^^^^^ invalid option found here @@ -26,7 +26,7 @@ LL | if(Self = "()"), = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: `message` is ignored due to previous definition of `message` - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:8:32 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:10:32 | LL | message = "custom message", | -------------------------- `message` is first declared here @@ -37,7 +37,7 @@ LL | #[diagnostic::on_unimplemented(message = "fallback!!")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: custom message - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:18:15 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:20:15 | LL | takes_foo(()); | --------- ^^ fallback label @@ -48,12 +48,12 @@ LL | takes_foo(()); = note: custom note = note: fallback note help: this trait has no implementations, consider adding one - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:13:1 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:22 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:17:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^ required by this bound in `takes_foo` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs index a5982f6492c..dc0f850031e 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs @@ -1,3 +1,4 @@ +//@ reference: attributes.diagnostic.on_unimplemented.note-repetition #[diagnostic::on_unimplemented(message = "Foo", label = "Bar", note = "Baz", note = "Boom")] trait Foo {} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr index 93a0d0b3f41..6567269be3b 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr @@ -1,5 +1,5 @@ error[E0277]: Foo - --> $DIR/multiple_notes.rs:12:15 + --> $DIR/multiple_notes.rs:13:15 | LL | takes_foo(()); | --------- ^^ Bar @@ -10,18 +10,18 @@ LL | takes_foo(()); = note: Baz = note: Boom help: this trait has no implementations, consider adding one - --> $DIR/multiple_notes.rs:2:1 + --> $DIR/multiple_notes.rs:3:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/multiple_notes.rs:8:22 + --> $DIR/multiple_notes.rs:9:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^ required by this bound in `takes_foo` error[E0277]: Bar - --> $DIR/multiple_notes.rs:14:15 + --> $DIR/multiple_notes.rs:15:15 | LL | takes_bar(()); | --------- ^^ Foo @@ -32,12 +32,12 @@ LL | takes_bar(()); = note: Baz = note: Baz2 help: this trait has no implementations, consider adding one - --> $DIR/multiple_notes.rs:6:1 + --> $DIR/multiple_notes.rs:7:1 | LL | trait Bar {} | ^^^^^^^^^ note: required by a bound in `takes_bar` - --> $DIR/multiple_notes.rs:9:22 + --> $DIR/multiple_notes.rs:10:22 | LL | fn takes_bar(_: impl Bar) {} | ^^^ required by this bound in `takes_bar` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs index 7ca03127759..e584077c643 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs @@ -1,3 +1,5 @@ +//@ reference: attributes.diagnostic.on_unimplemented.intro +//@ reference: attributes.diagnostic.on_unimplemented.keys #[diagnostic::on_unimplemented(message = "Foo", label = "Bar", note = "Baz")] trait Foo {} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr index 6b17f40c6dd..de57f7044bf 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr @@ -1,5 +1,5 @@ error[E0277]: Foo - --> $DIR/on_unimplemented_simple.rs:7:15 + --> $DIR/on_unimplemented_simple.rs:9:15 | LL | takes_foo(()); | --------- ^^ Bar @@ -9,12 +9,12 @@ LL | takes_foo(()); = help: the trait `Foo` is not implemented for `()` = note: Baz help: this trait has no implementations, consider adding one - --> $DIR/on_unimplemented_simple.rs:2:1 + --> $DIR/on_unimplemented_simple.rs:4:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/on_unimplemented_simple.rs:4:22 + --> $DIR/on_unimplemented_simple.rs:6:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^ required by this bound in `takes_foo` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs index 8c0b8150417..d0eb608c40f 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs @@ -1,3 +1,4 @@ +//@ reference: attributes.diagnostic.on_unimplemented.repetition #[diagnostic::on_unimplemented( message = "first message", label = "first label", diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr index 43ab6bf25a1..feafe2cee76 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr @@ -1,5 +1,5 @@ warning: `message` is ignored due to previous definition of `message` - --> $DIR/report_warning_on_duplicated_options.rs:7:5 + --> $DIR/report_warning_on_duplicated_options.rs:8:5 | LL | message = "first message", | ------------------------- `message` is first declared here @@ -10,7 +10,7 @@ LL | message = "second message", = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: `label` is ignored due to previous definition of `label` - --> $DIR/report_warning_on_duplicated_options.rs:10:5 + --> $DIR/report_warning_on_duplicated_options.rs:11:5 | LL | label = "first label", | --------------------- `label` is first declared here @@ -19,7 +19,7 @@ LL | label = "second label", | ^^^^^^^^^^^^^^^^^^^^^^ `label` is already declared here warning: `message` is ignored due to previous definition of `message` - --> $DIR/report_warning_on_duplicated_options.rs:7:5 + --> $DIR/report_warning_on_duplicated_options.rs:8:5 | LL | message = "first message", | ------------------------- `message` is first declared here @@ -30,7 +30,7 @@ LL | message = "second message", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: `label` is ignored due to previous definition of `label` - --> $DIR/report_warning_on_duplicated_options.rs:10:5 + --> $DIR/report_warning_on_duplicated_options.rs:11:5 | LL | label = "first label", | --------------------- `label` is first declared here @@ -41,7 +41,7 @@ LL | label = "second label", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: first message - --> $DIR/report_warning_on_duplicated_options.rs:21:15 + --> $DIR/report_warning_on_duplicated_options.rs:22:15 | LL | takes_foo(()); | --------- ^^ first label @@ -52,12 +52,12 @@ LL | takes_foo(()); = note: custom note = note: second note help: this trait has no implementations, consider adding one - --> $DIR/report_warning_on_duplicated_options.rs:15:1 + --> $DIR/report_warning_on_duplicated_options.rs:16:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/report_warning_on_duplicated_options.rs:18:22 + --> $DIR/report_warning_on_duplicated_options.rs:19:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^ required by this bound in `takes_foo` diff --git a/tests/ui/diagnostic_namespace/suggest_typos.rs b/tests/ui/diagnostic_namespace/suggest_typos.rs index b25f097a8ad..6fa4f800462 100644 --- a/tests/ui/diagnostic_namespace/suggest_typos.rs +++ b/tests/ui/diagnostic_namespace/suggest_typos.rs @@ -1,3 +1,4 @@ +//@ reference: attributes.diagnostic.namespace.unknown-invalid-syntax #![deny(unknown_or_malformed_diagnostic_attributes)] #[diagnostic::onunimplemented] diff --git a/tests/ui/diagnostic_namespace/suggest_typos.stderr b/tests/ui/diagnostic_namespace/suggest_typos.stderr index 307311258f2..ff4ee9717d4 100644 --- a/tests/ui/diagnostic_namespace/suggest_typos.stderr +++ b/tests/ui/diagnostic_namespace/suggest_typos.stderr @@ -1,11 +1,11 @@ error: unknown diagnostic attribute - --> $DIR/suggest_typos.rs:3:15 + --> $DIR/suggest_typos.rs:4:15 | LL | #[diagnostic::onunimplemented] | ^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/suggest_typos.rs:1:9 + --> $DIR/suggest_typos.rs:2:9 | LL | #![deny(unknown_or_malformed_diagnostic_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | #[diagnostic::on_unimplemented] | ~~~~~~~~~~~~~~~~ error: unknown diagnostic attribute - --> $DIR/suggest_typos.rs:8:15 + --> $DIR/suggest_typos.rs:9:15 | LL | #[diagnostic::un_onimplemented] | ^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | #[diagnostic::on_unimplemented] | ~~~~~~~~~~~~~~~~ error: unknown diagnostic attribute - --> $DIR/suggest_typos.rs:13:15 + --> $DIR/suggest_typos.rs:14:15 | LL | #[diagnostic::on_implemented] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-min-generic-const-args.rs b/tests/ui/feature-gates/feature-gate-min-generic-const-args.rs new file mode 100644 index 00000000000..171509876d1 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-min-generic-const-args.rs @@ -0,0 +1,11 @@ +trait Trait { + const ASSOC: usize; +} + +// FIXME(min_generic_const_args): implement support for this, behind the feature gate +fn foo<T: Trait>() -> [u8; <T as Trait>::ASSOC] { + //~^ ERROR generic parameters may not be used in const operations + loop {} +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-min-generic-const-args.stderr b/tests/ui/feature-gates/feature-gate-min-generic-const-args.stderr new file mode 100644 index 00000000000..04d96b4c11e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-min-generic-const-args.stderr @@ -0,0 +1,11 @@ +error: generic parameters may not be used in const operations + --> $DIR/feature-gate-min-generic-const-args.rs:6:29 + | +LL | fn foo<T: Trait>() -> [u8; <T as Trait>::ASSOC] { + | ^ cannot perform const operation using `T` + | + = note: type parameters may not be used in const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: aborting due to 1 previous error + diff --git a/tests/ui/stats/hir-stats.rs b/tests/ui/stats/input-stats.rs index 7c5da8cf554..f19a53cc610 100644 --- a/tests/ui/stats/hir-stats.rs +++ b/tests/ui/stats/input-stats.rs @@ -1,6 +1,6 @@ //@ check-pass -//@ compile-flags: -Zhir-stats -//@ only-x86_64 +//@ compile-flags: -Zinput-stats +//@ only-64bit // layout randomization affects the hir stat output //@ needs-deterministic-layouts @@ -11,7 +11,7 @@ // The aim here is to include at least one of every different type of top-level -// AST/HIR node reported by `-Zhir-stats`. +// AST/HIR node reported by `-Zinput-stats`. #![allow(dead_code)] diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/input-stats.stderr index bd0c8cbc3b1..2cc2c8019fa 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -53,7 +53,7 @@ ast-stats-1 - Enum 136 ( 2.0%) 1 ast-stats-1 - Fn 272 ( 4.1%) 2 ast-stats-1 - Use 408 ( 6.1%) 3 ast-stats-1 ---------------------------------------------------------------- -ast-stats-1 Total 6_640 +ast-stats-1 Total 6_640 116 ast-stats-1 ast-stats-2 POST EXPANSION AST STATS ast-stats-2 Name Accumulated Size Count Item Size @@ -113,7 +113,7 @@ ast-stats-2 - ForeignMod 136 ( 1.9%) 1 ast-stats-2 - Fn 272 ( 3.7%) 2 ast-stats-2 - Use 544 ( 7.5%) 4 ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 Total 7_288 +ast-stats-2 Total 7_288 127 ast-stats-2 hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size @@ -174,5 +174,5 @@ hir-stats - Use 352 ( 3.9%) 4 hir-stats Path 1_240 (13.7%) 31 40 hir-stats PathSegment 1_920 (21.3%) 40 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 9_024 +hir-stats Total 9_024 180 hir-stats diff --git a/tests/ui/traits/negative-bounds/on-unimplemented.rs b/tests/ui/traits/negative-bounds/on-unimplemented.rs index 34582590861..5f2a705ed56 100644 --- a/tests/ui/traits/negative-bounds/on-unimplemented.rs +++ b/tests/ui/traits/negative-bounds/on-unimplemented.rs @@ -1,3 +1,5 @@ +//@ reference: attributes.diagnostic.on_unimplemented.intro + #![feature(negative_bounds)] #[diagnostic::on_unimplemented(message = "this ain't fooing")] diff --git a/tests/ui/traits/negative-bounds/on-unimplemented.stderr b/tests/ui/traits/negative-bounds/on-unimplemented.stderr index ed473d57917..8a295611010 100644 --- a/tests/ui/traits/negative-bounds/on-unimplemented.stderr +++ b/tests/ui/traits/negative-bounds/on-unimplemented.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `NotFoo: !Foo` is not satisfied - --> $DIR/on-unimplemented.rs:7:15 + --> $DIR/on-unimplemented.rs:9:15 | LL | fn hello() -> impl !Foo { | ^^^^^^^^^ the trait bound `NotFoo: !Foo` is not satisfied diff --git a/triagebot.toml b/triagebot.toml index 6154ffedc14..2483bfc4a41 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -901,7 +901,7 @@ message = "This PR changes a file inside `tests/crashes`. If a crash was fixed, message = "Changes to the code generated for builtin derived traits." cc = ["@nnethercote"] -[mentions."tests/ui/stats/hir-stats.stderr"] +[mentions."tests/ui/stats/input-stats.stderr"] message = "Changes to the size of AST and/or HIR nodes." cc = ["@nnethercote"] |
