diff options
753 files changed, 21219 insertions, 5822 deletions
diff --git a/Cargo.lock b/Cargo.lock index b98c4fd0642..51e21f6dc82 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", @@ -3270,6 +3270,7 @@ name = "rustc_ast_lowering" version = "0.0.0" dependencies = [ "rustc_ast", + "rustc_ast_pretty", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -3684,6 +3685,8 @@ version = "0.0.0" dependencies = [ "rustc_data_structures", "rustc_span", + "serde", + "serde_json", ] [[package]] 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_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index 062447ea03f..d188750bfe1 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -209,6 +209,24 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { } } + pub fn is_single_vector_element<C>(self, cx: &C, expected_size: Size) -> bool + where + Ty: TyAbiInterface<'a, C>, + C: HasDataLayout, + { + match self.backend_repr { + BackendRepr::Vector { .. } => self.size == expected_size, + BackendRepr::Memory { .. } => { + if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { + self.field(cx, 0).is_single_vector_element(cx, expected_size) + } else { + false + } + } + _ => false, + } + } + pub fn is_adt<C>(self) -> bool where Ty: TyAbiInterface<'a, C>, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 44bb44cb728..61f2f91635d 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -23,7 +23,7 @@ use crate::ast::*; use crate::ptr::P; use crate::token::{self, Token}; use crate::tokenstream::*; -use crate::visit::{AssocCtxt, BoundKind}; +use crate::visit::{AssocCtxt, BoundKind, FnCtxt}; pub trait ExpectOne<A: Array> { fn expect_one(self, err: &'static str) -> A::Item; @@ -37,7 +37,16 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> { } pub trait WalkItemKind { - fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor); + type Ctxt; + fn walk( + &mut self, + span: Span, + id: NodeId, + ident: &mut Ident, + visibility: &mut Visibility, + ctxt: Self::Ctxt, + visitor: &mut impl MutVisitor, + ); } pub trait MutVisitor: Sized { @@ -95,8 +104,16 @@ pub trait MutVisitor: Sized { walk_use_tree(self, use_tree); } + fn visit_foreign_item(&mut self, ni: &mut P<ForeignItem>) { + walk_item(self, ni); + } + fn flat_map_foreign_item(&mut self, ni: P<ForeignItem>) -> SmallVec<[P<ForeignItem>; 1]> { - walk_flat_map_item(self, ni) + walk_flat_map_foreign_item(self, ni) + } + + fn visit_item(&mut self, i: &mut P<Item>) { + walk_item(self, i); } fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> { @@ -107,16 +124,24 @@ pub trait MutVisitor: Sized { walk_fn_header(self, header); } + fn visit_field_def(&mut self, fd: &mut FieldDef) { + walk_field_def(self, fd); + } + fn flat_map_field_def(&mut self, fd: FieldDef) -> SmallVec<[FieldDef; 1]> { walk_flat_map_field_def(self, fd) } + fn visit_assoc_item(&mut self, i: &mut P<AssocItem>, ctxt: AssocCtxt) { + walk_assoc_item(self, i, ctxt) + } + fn flat_map_assoc_item( &mut self, i: P<AssocItem>, - _ctxt: AssocCtxt, + ctxt: AssocCtxt, ) -> SmallVec<[P<AssocItem>; 1]> { - walk_flat_map_item(self, i) + walk_flat_map_assoc_item(self, i, ctxt) } fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) { @@ -144,6 +169,10 @@ pub trait MutVisitor: Sized { walk_flat_map_stmt(self, s) } + fn visit_arm(&mut self, arm: &mut Arm) { + walk_arm(self, arm); + } + fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> { walk_flat_map_arm(self, arm) } @@ -190,6 +219,10 @@ pub trait MutVisitor: Sized { walk_foreign_mod(self, nm); } + fn visit_variant(&mut self, v: &mut Variant) { + walk_variant(self, v); + } + fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> { walk_flat_map_variant(self, v) } @@ -242,6 +275,10 @@ pub trait MutVisitor: Sized { walk_attribute(self, at); } + fn visit_param(&mut self, param: &mut Param) { + walk_param(self, param); + } + fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> { walk_flat_map_param(self, param) } @@ -262,6 +299,10 @@ pub trait MutVisitor: Sized { walk_variant_data(self, vdata); } + fn visit_generic_param(&mut self, param: &mut GenericParam) { + walk_generic_param(self, param) + } + fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> { walk_flat_map_generic_param(self, param) } @@ -278,6 +319,10 @@ pub trait MutVisitor: Sized { walk_mt(self, mt); } + fn visit_expr_field(&mut self, f: &mut ExprField) { + walk_expr_field(self, f); + } + fn flat_map_expr_field(&mut self, f: ExprField) -> SmallVec<[ExprField; 1]> { walk_flat_map_expr_field(self, f) } @@ -302,6 +347,10 @@ pub trait MutVisitor: Sized { // Do nothing. } + fn visit_pat_field(&mut self, fp: &mut PatField) { + walk_pat_field(self, fp) + } + fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> { walk_flat_map_pat_field(self, fp) } @@ -321,6 +370,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 @@ -416,16 +469,20 @@ pub fn visit_delim_span<T: MutVisitor>(vis: &mut T, DelimSpan { open, close }: & vis.visit_span(close); } -pub fn walk_flat_map_pat_field<T: MutVisitor>( - vis: &mut T, - mut fp: PatField, -) -> SmallVec<[PatField; 1]> { - let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = &mut fp; +pub fn walk_pat_field<T: MutVisitor>(vis: &mut T, fp: &mut PatField) { + let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = fp; vis.visit_id(id); visit_attrs(vis, attrs); vis.visit_ident(ident); vis.visit_pat(pat); vis.visit_span(span); +} + +pub fn walk_flat_map_pat_field<T: MutVisitor>( + vis: &mut T, + mut fp: PatField, +) -> SmallVec<[PatField; 1]> { + vis.visit_pat_field(&mut fp); smallvec![fp] } @@ -446,14 +503,18 @@ fn walk_use_tree<T: MutVisitor>(vis: &mut T, use_tree: &mut UseTree) { vis.visit_span(span); } -pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> { - let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm; +pub fn walk_arm<T: MutVisitor>(vis: &mut T, arm: &mut Arm) { + let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = arm; vis.visit_id(id); visit_attrs(vis, attrs); vis.visit_pat(pat); visit_opt(guard, |guard| vis.visit_expr(guard)); visit_opt(body, |body| vis.visit_expr(body)); vis.visit_span(span); +} + +pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> { + vis.visit_arm(&mut arm); smallvec![arm] } @@ -530,11 +591,8 @@ fn walk_foreign_mod<T: MutVisitor>(vis: &mut T, foreign_mod: &mut ForeignMod) { items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); } -pub fn walk_flat_map_variant<T: MutVisitor>( - visitor: &mut T, - mut variant: Variant, -) -> SmallVec<[Variant; 1]> { - let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant; +pub fn walk_variant<T: MutVisitor>(visitor: &mut T, variant: &mut Variant) { + let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = variant; visitor.visit_id(id); visit_attrs(visitor, attrs); visitor.visit_vis(vis); @@ -542,6 +600,13 @@ pub fn walk_flat_map_variant<T: MutVisitor>( visitor.visit_variant_data(data); visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr)); visitor.visit_span(span); +} + +pub fn walk_flat_map_variant<T: MutVisitor>( + vis: &mut T, + mut variant: Variant, +) -> SmallVec<[Variant; 1]> { + vis.visit_variant(&mut variant); smallvec![variant] } @@ -600,7 +665,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); } @@ -672,13 +737,17 @@ fn walk_meta_item<T: MutVisitor>(vis: &mut T, mi: &mut MetaItem) { vis.visit_span(span); } -pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> { - let Param { attrs, id, pat, span, ty, is_placeholder: _ } = &mut param; +pub fn walk_param<T: MutVisitor>(vis: &mut T, param: &mut Param) { + let Param { attrs, id, pat, span, ty, is_placeholder: _ } = param; vis.visit_id(id); visit_attrs(vis, attrs); vis.visit_pat(pat); vis.visit_ty(ty); vis.visit_span(span); +} + +pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> { + vis.visit_param(&mut param); smallvec![param] } @@ -880,7 +949,7 @@ fn walk_coroutine_kind<T: MutVisitor>(vis: &mut T, coroutine_kind: &mut Coroutin fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) { match kind { - FnKind::Fn(FnSig { header, decl, span }, generics, body) => { + FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span }, _visibility, generics, body) => { // Identifier and visibility are visited as a part of the item. vis.visit_fn_header(header); vis.visit_generics(generics); @@ -890,8 +959,9 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) { } vis.visit_span(span); } - FnKind::Closure(binder, decl, body) => { + FnKind::Closure(binder, coroutine_kind, decl, body) => { vis.visit_closure_binder(binder); + coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind)); vis.visit_fn_decl(decl); vis.visit_expr(body); } @@ -901,7 +971,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) { @@ -936,11 +1006,8 @@ fn walk_precise_capturing_arg<T: MutVisitor>(vis: &mut T, arg: &mut PreciseCaptu } } -pub fn walk_flat_map_generic_param<T: MutVisitor>( - vis: &mut T, - mut param: GenericParam, -) -> SmallVec<[GenericParam; 1]> { - let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = &mut param; +pub fn walk_generic_param<T: MutVisitor>(vis: &mut T, param: &mut GenericParam) { + let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = param; vis.visit_id(id); visit_attrs(vis, attrs); vis.visit_ident(ident); @@ -958,6 +1025,13 @@ pub fn walk_flat_map_generic_param<T: MutVisitor>( if let Some(colon_span) = colon_span { vis.visit_span(colon_span); } +} + +pub fn walk_flat_map_generic_param<T: MutVisitor>( + vis: &mut T, + mut param: GenericParam, +) -> SmallVec<[GenericParam; 1]> { + vis.visit_generic_param(&mut param); smallvec![param] } @@ -1040,30 +1114,38 @@ fn walk_poly_trait_ref<T: MutVisitor>(vis: &mut T, p: &mut PolyTraitRef) { vis.visit_span(span); } -pub fn walk_flat_map_field_def<T: MutVisitor>( - visitor: &mut T, - mut fd: FieldDef, -) -> SmallVec<[FieldDef; 1]> { - let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut fd; +pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) { + let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = fd; visitor.visit_id(id); visit_attrs(visitor, attrs); visitor.visit_vis(vis); visit_opt(ident, |ident| visitor.visit_ident(ident)); visitor.visit_ty(ty); visitor.visit_span(span); - smallvec![fd] } -pub fn walk_flat_map_expr_field<T: MutVisitor>( +pub fn walk_flat_map_field_def<T: MutVisitor>( vis: &mut T, - mut f: ExprField, -) -> SmallVec<[ExprField; 1]> { - let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = &mut f; + mut fd: FieldDef, +) -> SmallVec<[FieldDef; 1]> { + vis.visit_field_def(&mut fd); + smallvec![fd] +} + +pub fn walk_expr_field<T: MutVisitor>(vis: &mut T, f: &mut ExprField) { + let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = f; vis.visit_id(id); visit_attrs(vis, attrs); vis.visit_ident(ident); vis.visit_expr(expr); vis.visit_span(span); +} + +pub fn walk_flat_map_expr_field<T: MutVisitor>( + vis: &mut T, + mut f: ExprField, +) -> SmallVec<[ExprField; 1]> { + vis.visit_expr_field(&mut f); smallvec![f] } @@ -1079,17 +1161,29 @@ pub fn walk_block<T: MutVisitor>(vis: &mut T, block: &mut P<Block>) { vis.visit_span(span); } -pub fn walk_item_kind( - kind: &mut impl WalkItemKind, +pub fn walk_item_kind<K: WalkItemKind>( + kind: &mut K, span: Span, id: NodeId, + ident: &mut Ident, + visibility: &mut Visibility, + ctxt: K::Ctxt, vis: &mut impl MutVisitor, ) { - kind.walk(span, id, vis) + kind.walk(span, id, ident, visibility, ctxt, vis) } impl WalkItemKind for ItemKind { - fn walk(&mut self, span: Span, id: NodeId, vis: &mut impl MutVisitor) { + type Ctxt = (); + fn walk( + &mut self, + span: Span, + id: NodeId, + ident: &mut Ident, + visibility: &mut Visibility, + _ctxt: Self::Ctxt, + vis: &mut impl MutVisitor, + ) { match self { ItemKind::ExternCrate(_orig_name) => {} ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), @@ -1102,7 +1196,11 @@ impl WalkItemKind for ItemKind { } ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { visit_defaultness(vis, defaultness); - vis.visit_fn(FnKind::Fn(sig, generics, body), span, id); + vis.visit_fn( + FnKind::Fn(FnCtxt::Free, ident, sig, visibility, generics, body), + span, + id, + ); } ItemKind::Mod(safety, mod_kind) => { visit_safety(vis, safety); @@ -1201,14 +1299,27 @@ impl WalkItemKind for ItemKind { } impl WalkItemKind for AssocItemKind { - fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) { + type Ctxt = AssocCtxt; + fn walk( + &mut self, + span: Span, + id: NodeId, + ident: &mut Ident, + visibility: &mut Visibility, + ctxt: Self::Ctxt, + visitor: &mut impl MutVisitor, + ) { match self { AssocItemKind::Const(item) => { visit_const_item(item, visitor); } AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { visit_defaultness(visitor, defaultness); - visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id); + visitor.visit_fn( + FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, visibility, generics, body), + span, + id, + ); } AssocItemKind::Type(box TyAlias { defaultness, @@ -1288,24 +1399,62 @@ pub fn walk_crate<T: MutVisitor>(vis: &mut T, krate: &mut Crate) { vis.visit_span(inject_use_span); } -/// Mutates one item, returning the item again. -pub fn walk_flat_map_item<K: WalkItemKind>( +pub fn walk_item(visitor: &mut impl MutVisitor, item: &mut P<Item<impl WalkItemKind<Ctxt = ()>>>) { + walk_item_ctxt(visitor, item, ()) +} + +pub fn walk_assoc_item(visitor: &mut impl MutVisitor, item: &mut P<AssocItem>, ctxt: AssocCtxt) { + walk_item_ctxt(visitor, item, ctxt) +} + +fn walk_item_ctxt<K: WalkItemKind>( visitor: &mut impl MutVisitor, - mut item: P<Item<K>>, -) -> SmallVec<[P<Item<K>>; 1]> { + item: &mut P<Item<K>>, + ctxt: K::Ctxt, +) { let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut(); visitor.visit_id(id); visit_attrs(visitor, attrs); visitor.visit_vis(vis); visitor.visit_ident(ident); - kind.walk(*span, *id, visitor); + kind.walk(*span, *id, ident, vis, ctxt, visitor); visit_lazy_tts(visitor, tokens); visitor.visit_span(span); +} + +pub fn walk_flat_map_item(vis: &mut impl MutVisitor, mut item: P<Item>) -> SmallVec<[P<Item>; 1]> { + vis.visit_item(&mut item); + smallvec![item] +} + +pub fn walk_flat_map_foreign_item( + vis: &mut impl MutVisitor, + mut item: P<ForeignItem>, +) -> SmallVec<[P<ForeignItem>; 1]> { + vis.visit_foreign_item(&mut item); + smallvec![item] +} + +pub fn walk_flat_map_assoc_item( + vis: &mut impl MutVisitor, + mut item: P<AssocItem>, + ctxt: AssocCtxt, +) -> SmallVec<[P<AssocItem>; 1]> { + vis.visit_assoc_item(&mut item, ctxt); smallvec![item] } impl WalkItemKind for ForeignItemKind { - fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) { + type Ctxt = (); + fn walk( + &mut self, + span: Span, + id: NodeId, + ident: &mut Ident, + visibility: &mut Visibility, + _ctxt: Self::Ctxt, + visitor: &mut impl MutVisitor, + ) { match self { ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => { visitor.visit_ty(ty); @@ -1313,7 +1462,11 @@ impl WalkItemKind for ForeignItemKind { } ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { visit_defaultness(visitor, defaultness); - visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id); + visitor.visit_fn( + FnKind::Fn(FnCtxt::Foreign, ident, sig, visibility, generics, body), + span, + id, + ); } ForeignItemKind::TyAlias(box TyAlias { defaultness, @@ -1522,9 +1675,8 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token fn_arg_span, }) => { visit_constness(vis, constness); - coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind)); vis.visit_capture_by(capture_clause); - vis.visit_fn(FnKind::Closure(binder, fn_decl, body), *span, *id); + vis.visit_fn(FnKind::Closure(binder, coroutine_kind, fn_decl, body), *span, *id); vis.visit_span(fn_decl_span); vis.visit_span(fn_arg_span); } @@ -1785,8 +1937,20 @@ impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNo #[derive(Debug)] pub enum FnKind<'a> { /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. - Fn(&'a mut FnSig, &'a mut Generics, &'a mut Option<P<Block>>), + Fn( + FnCtxt, + &'a mut Ident, + &'a mut FnSig, + &'a mut Visibility, + &'a mut Generics, + &'a mut Option<P<Block>>, + ), /// E.g., `|x, y| body`. - Closure(&'a mut ClosureBinder, &'a mut P<FnDecl>, &'a mut P<Expr>), + Closure( + &'a mut ClosureBinder, + &'a mut Option<CoroutineKind>, + &'a mut P<FnDecl>, + &'a mut P<Expr>, + ), } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 2f8115441de..0302c9fa7f8 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -66,7 +66,7 @@ impl BoundKind { #[derive(Copy, Clone, Debug)] pub enum FnKind<'a> { /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. - Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>), + Fn(FnCtxt, &'a Ident, &'a FnSig, &'a Visibility, &'a Generics, &'a Option<P<Block>>), /// E.g., `|x, y| body`. Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr), @@ -112,11 +112,15 @@ pub enum LifetimeCtxt { GenericArg, } -pub trait WalkItemKind: Sized { +pub trait WalkItemKind { + type Ctxt; fn walk<'a, V: Visitor<'a>>( &'a self, - item: &'a Item<Self>, - ctxt: AssocCtxt, + span: Span, + id: NodeId, + ident: &'a Ident, + visibility: &'a Visibility, + ctxt: Self::Ctxt, visitor: &mut V, ) -> V::Result; } @@ -200,8 +204,8 @@ pub trait Visitor<'ast>: Sized { fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) -> Self::Result { walk_param_bound(self, bounds) } - fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) { - walk_precise_capturing_arg(self, arg); + fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) -> Self::Result { + walk_precise_capturing_arg(self, arg) } fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) -> Self::Result { walk_poly_trait_ref(self, t) @@ -268,8 +272,8 @@ pub trait Visitor<'ast>: Sized { fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FnRetTy) -> Self::Result { walk_fn_ret_ty(self, ret_ty) } - fn visit_fn_header(&mut self, _header: &'ast FnHeader) -> Self::Result { - Self::Result::output() + fn visit_fn_header(&mut self, header: &'ast FnHeader) -> Self::Result { + walk_fn_header(self, header) } fn visit_expr_field(&mut self, f: &'ast ExprField) -> Self::Result { walk_expr_field(self, f) @@ -292,6 +296,15 @@ pub trait Visitor<'ast>: Sized { fn visit_capture_by(&mut self, _capture_by: &'ast CaptureBy) -> Self::Result { Self::Result::output() } + 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 { @@ -337,16 +350,19 @@ pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitR } impl WalkItemKind for ItemKind { + type Ctxt = (); fn walk<'a, V: Visitor<'a>>( &'a self, - item: &'a Item<Self>, - _ctxt: AssocCtxt, + span: Span, + id: NodeId, + ident: &'a Ident, + vis: &'a Visibility, + _ctxt: Self::Ctxt, visitor: &mut V, ) -> V::Result { - let Item { id, span, vis, ident, .. } = item; match self { ItemKind::ExternCrate(_rename) => {} - ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, *id, false)), + ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, id, false)), ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); @@ -357,8 +373,8 @@ impl WalkItemKind for ItemKind { visit_opt!(visitor, visit_expr, expr); } ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => { - let kind = FnKind::Fn(FnCtxt::Free, *ident, sig, vis, generics, body.as_deref()); - try_visit!(visitor.visit_fn(kind, *span, *id)); + let kind = FnKind::Fn(FnCtxt::Free, ident, sig, vis, generics, body); + try_visit!(visitor.visit_fn(kind, span, id)); } ItemKind::Mod(_unsafety, mod_kind) => match mod_kind { ModKind::Loaded(items, _inline, _inner_span) => { @@ -415,7 +431,7 @@ impl WalkItemKind for ItemKind { walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); } ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), - ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, *id)), + ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, id)), ItemKind::Delegation(box Delegation { id, qself, @@ -424,14 +440,14 @@ 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_path(prefix, *id)); + try_visit!(visitor.visit_qself(qself)); + try_visit!(visitor.visit_path(prefix, id)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { visitor.visit_ident(ident); @@ -447,13 +463,6 @@ impl WalkItemKind for ItemKind { } } -pub fn walk_item<'a, V: Visitor<'a>>( - visitor: &mut V, - item: &'a Item<impl WalkItemKind>, -) -> V::Result { - walk_assoc_item(visitor, item, AssocCtxt::Trait /*ignored*/) -} - pub fn walk_enum_def<'a, V: Visitor<'a>>( visitor: &mut V, EnumDef { variants }: &'a EnumDef, @@ -508,10 +517,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) => { @@ -642,16 +651,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); } @@ -681,20 +690,23 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res } impl WalkItemKind for ForeignItemKind { + type Ctxt = (); fn walk<'a, V: Visitor<'a>>( &'a self, - item: &'a Item<Self>, - _ctxt: AssocCtxt, + span: Span, + id: NodeId, + ident: &'a Ident, + vis: &'a Visibility, + _ctxt: Self::Ctxt, visitor: &mut V, ) -> V::Result { - let &Item { id, span, ident, ref vis, .. } = item; match self { ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); } ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => { - let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref()); + let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body); try_visit!(visitor.visit_fn(kind, span, id)); } ForeignItemKind::TyAlias(box TyAlias { @@ -730,14 +742,10 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB pub fn walk_precise_capturing_arg<'a, V: Visitor<'a>>( visitor: &mut V, arg: &'a PreciseCapturingArg, -) { +) -> V::Result { match arg { - PreciseCapturingArg::Lifetime(lt) => { - visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg); - } - PreciseCapturingArg::Arg(path, id) => { - visitor.visit_path(path, *id); - } + PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg), + PreciseCapturingArg::Arg(path, id) => visitor.visit_path(path, *id), } } @@ -817,6 +825,12 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FnRetTy) V::Result::output() } +pub fn walk_fn_header<'a, V: Visitor<'a>>(visitor: &mut V, fn_header: &'a FnHeader) -> V::Result { + let FnHeader { safety: _, coroutine_kind, constness: _, ext: _ } = fn_header; + visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref()); + V::Result::output() +} + pub fn walk_fn_decl<'a, V: Visitor<'a>>( visitor: &mut V, FnDecl { inputs, output }: &'a FnDecl, @@ -831,12 +845,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) => { + FnKind::Closure(binder, coroutine_kind, decl, body) => { try_visit!(visitor.visit_closure_binder(binder)); - try_visit!(walk_fn_decl(visitor, decl)); + visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref()); + try_visit!(visitor.visit_fn_decl(decl)); try_visit!(visitor.visit_expr(body)); } } @@ -844,13 +859,16 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu } impl WalkItemKind for AssocItemKind { + type Ctxt = AssocCtxt; fn walk<'a, V: Visitor<'a>>( &'a self, - item: &'a Item<Self>, - ctxt: AssocCtxt, + span: Span, + id: NodeId, + ident: &'a Ident, + vis: &'a Visibility, + ctxt: Self::Ctxt, visitor: &mut V, ) -> V::Result { - let &Item { id, span, ident, ref vis, .. } = item; match self { AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => { try_visit!(visitor.visit_generics(generics)); @@ -858,8 +876,7 @@ impl WalkItemKind for AssocItemKind { visit_opt!(visitor, visit_expr, expr); } AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => { - let kind = - FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref()); + let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body); try_visit!(visitor.visit_fn(kind, span, id)); } AssocItemKind::Type(box TyAlias { @@ -884,13 +901,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 { @@ -907,16 +924,31 @@ impl WalkItemKind for AssocItemKind { } } +pub fn walk_item<'a, V: Visitor<'a>>( + visitor: &mut V, + item: &'a Item<impl WalkItemKind<Ctxt = ()>>, +) -> V::Result { + walk_item_ctxt(visitor, item, ()) +} + pub fn walk_assoc_item<'a, V: Visitor<'a>>( visitor: &mut V, - item: &'a Item<impl WalkItemKind>, + item: &'a AssocItem, ctxt: AssocCtxt, ) -> V::Result { - let Item { id: _, span: _, ident, vis, attrs, kind, tokens: _ } = item; + walk_item_ctxt(visitor, item, ctxt) +} + +fn walk_item_ctxt<'a, V: Visitor<'a>, K: WalkItemKind>( + visitor: &mut V, + item: &'a Item<K>, + ctxt: K::Ctxt, +) -> V::Result { + let Item { id, span, ident, vis, attrs, kind, tokens: _ } = item; walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_vis(vis)); try_visit!(visitor.visit_ident(ident)); - try_visit!(kind.walk(item, ctxt, visitor)); + try_visit!(kind.walk(*span, *id, ident, vis, ctxt, visitor)); V::Result::output() } @@ -1005,7 +1037,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) } @@ -1037,7 +1069,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 { @@ -1146,7 +1178,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/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index c47c12b4fd1..8cc4521e0a7 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -9,6 +9,7 @@ doctest = false [dependencies] # tidy-alphabetical-start rustc_ast = { path = "../rustc_ast" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index a5ee6713be8..f704320c71d 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -103,6 +103,12 @@ ast_lowering_invalid_asm_template_modifier_reg_class = ast_lowering_invalid_asm_template_modifier_sym = asm template modifiers are not allowed for `sym` arguments +ast_lowering_invalid_legacy_const_generic_arg = + invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + +ast_lowering_invalid_legacy_const_generic_arg_suggestion = + try using a const generic argument instead + ast_lowering_invalid_register = invalid register `{$reg}`: {$error} diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 6b39c2d3955..e6a3f939f2d 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -451,3 +451,26 @@ pub(crate) struct YieldInClosure { #[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")] pub suggestion: Option<Span>, } + +#[derive(Diagnostic)] +#[diag(ast_lowering_invalid_legacy_const_generic_arg)] +pub(crate) struct InvalidLegacyConstGenericArg { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub suggestion: UseConstGenericArg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + ast_lowering_invalid_legacy_const_generic_arg_suggestion, + applicability = "maybe-incorrect" +)] +pub(crate) struct UseConstGenericArg { + #[suggestion_part(code = "::<{const_args}>")] + pub end_of_fn: Span, + pub const_args: String, + pub other_args: String, + #[suggestion_part(code = "{other_args}")] + pub call_args: Span, +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index b7cf2d252dc..3af29838b72 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,18 +1,22 @@ use std::assert_matches::assert_matches; +use std::ops::ControlFlow; use rustc_ast::ptr::P as AstP; use rustc_ast::*; +use rustc_ast_pretty::pprust::expr_to_string; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::HirId; use rustc_hir::def::{DefKind, Res}; use rustc_middle::span_bug; +use rustc_middle::ty::TyCtxt; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{Spanned, respan}; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, DesugaringKind, Span}; use thin_vec::{ThinVec, thin_vec}; +use visit::{Visitor, walk_expr}; use super::errors::{ AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, @@ -23,9 +27,32 @@ use super::errors::{ use super::{ GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt, }; -use crate::errors::YieldInClosure; +use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure}; use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, fluent_generated}; +struct WillCreateDefIdsVisitor {} + +impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor { + type Result = ControlFlow<Span>; + + fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result { + ControlFlow::Break(c.value.span) + } + + fn visit_item(&mut self, item: &'v Item) -> Self::Result { + ControlFlow::Break(item.span) + } + + fn visit_expr(&mut self, ex: &'v Expr) -> Self::Result { + match ex.kind { + ExprKind::Gen(..) | ExprKind::ConstBlock(..) | ExprKind::Closure(..) => { + ControlFlow::Break(ex.span) + } + _ => walk_expr(self, ex), + } + } +} + impl<'hir> LoweringContext<'_, 'hir> { fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] { self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x))) @@ -396,10 +423,34 @@ impl<'hir> LoweringContext<'_, 'hir> { unreachable!(); }; + let mut error = None; + let mut invalid_expr_error = |tcx: TyCtxt<'_>, span| { + // Avoid emitting the error multiple times. + if error.is_none() { + let mut const_args = vec![]; + let mut other_args = vec![]; + for (idx, arg) in args.iter().enumerate() { + if legacy_args_idx.contains(&idx) { + const_args.push(format!("{{ {} }}", expr_to_string(arg))); + } else { + other_args.push(expr_to_string(arg)); + } + } + let suggestion = UseConstGenericArg { + end_of_fn: f.span.shrink_to_hi(), + const_args: const_args.join(", "), + other_args: other_args.join(", "), + call_args: args[0].span.to(args.last().unwrap().span), + }; + error = Some(tcx.dcx().emit_err(InvalidLegacyConstGenericArg { span, suggestion })); + } + error.unwrap() + }; + // Split the arguments into const generics and normal arguments let mut real_args = vec![]; let mut generic_args = ThinVec::new(); - for (idx, arg) in args.into_iter().enumerate() { + for (idx, arg) in args.iter().cloned().enumerate() { if legacy_args_idx.contains(&idx) { let parent_def_id = self.current_def_id_parent; let node_id = self.next_node_id(); @@ -410,7 +461,20 @@ impl<'hir> LoweringContext<'_, 'hir> { self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span); } - let anon_const = AnonConst { id: node_id, value: arg }; + let mut visitor = WillCreateDefIdsVisitor {}; + let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) { + AstP(Expr { + id: self.next_node_id(), + kind: ExprKind::Err(invalid_expr_error(self.tcx, span)), + span: f.span, + attrs: [].into(), + tokens: None, + }) + } else { + arg + }; + + let anon_const = AnonConst { id: node_id, value: const_value }; generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const))); } else { real_args.push(arg); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5a0e9e8aec0..0b2969a49ba 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -738,7 +738,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { allow_internal_unstable: Option<Lrc<[Symbol]>>, ) -> Span { self.tcx.with_stable_hashing_context(|hcx| { - span.mark_with_reason(allow_internal_unstable, reason, self.tcx.sess.edition(), hcx) + span.mark_with_reason(allow_internal_unstable, reason, span.edition(), hcx) }) } @@ -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/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index dee48586f34..07a6f4e5ee7 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -946,8 +946,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.visit_vis(&item.vis); self.visit_ident(&item.ident); - let kind = - FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref()); + let kind = FnKind::Fn(FnCtxt::Free, &item.ident, sig, &item.vis, generics, body); self.visit_fn(kind, item.span, item.id); walk_list!(self, visit_attribute, &item.attrs); return; // Avoid visiting again. @@ -1476,14 +1475,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { { self.visit_vis(&item.vis); self.visit_ident(&item.ident); - let kind = FnKind::Fn( - FnCtxt::Assoc(ctxt), - item.ident, - sig, - &item.vis, - generics, - body.as_deref(), - ); + let kind = + FnKind::Fn(FnCtxt::Assoc(ctxt), &item.ident, sig, &item.vis, generics, body); walk_list!(self, visit_attribute, &item.attrs); self.visit_fn(kind, item.span, item.id); } 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/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index d832decc170..452038bc328 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -1,93 +1,171 @@ +use std::fmt; + use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph; use rustc_index::bit_set::BitSet; -use rustc_middle::mir::{self, BasicBlock, Body, Location, Place, TerminatorEdges}; +use rustc_middle::mir::{ + self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges, +}; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}; -use rustc_mir_dataflow::{Analysis, Forward, GenKill, Results, ResultsVisitable}; +use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects}; use tracing::debug; use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict}; -/// The results of the dataflow analyses used by the borrow checker. -pub(crate) struct BorrowckResults<'a, 'tcx> { - pub(crate) borrows: Results<'tcx, Borrows<'a, 'tcx>>, - pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'a, 'tcx>>, - pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'a, 'tcx>>, -} - -/// The transient state of the dataflow analyses used by the borrow checker. -#[derive(Debug)] -pub(crate) struct BorrowckDomain<'a, 'tcx> { - pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain, - pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain, - pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain, +// This analysis is different to most others. Its results aren't computed with +// `iterate_to_fixpoint`, but are instead composed from the results of three sub-analyses that are +// computed individually with `iterate_to_fixpoint`. +pub(crate) struct Borrowck<'a, 'tcx> { + pub(crate) borrows: Borrows<'a, 'tcx>, + pub(crate) uninits: MaybeUninitializedPlaces<'a, 'tcx>, + pub(crate) ever_inits: EverInitializedPlaces<'a, 'tcx>, } -impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> { - type Direction = Forward; +impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { type Domain = BorrowckDomain<'a, 'tcx>; + const NAME: &'static str = "borrowck"; + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { BorrowckDomain { - borrows: self.borrows.analysis.bottom_value(body), - uninits: self.uninits.analysis.bottom_value(body), - ever_inits: self.ever_inits.analysis.bottom_value(body), + borrows: self.borrows.bottom_value(body), + uninits: self.uninits.bottom_value(body), + ever_inits: self.ever_inits.bottom_value(body), } } - fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) { - state.borrows.clone_from(self.borrows.entry_set_for_block(block)); - state.uninits.clone_from(self.uninits.entry_set_for_block(block)); - state.ever_inits.clone_from(self.ever_inits.entry_set_for_block(block)); + fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _state: &mut Self::Domain) { + // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use. + unreachable!(); } - fn reconstruct_before_statement_effect( + fn apply_before_statement_effect( &mut self, state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { - self.borrows.analysis.apply_before_statement_effect(&mut state.borrows, stmt, loc); - self.uninits.analysis.apply_before_statement_effect(&mut state.uninits, stmt, loc); - self.ever_inits.analysis.apply_before_statement_effect(&mut state.ever_inits, stmt, loc); + self.borrows.apply_before_statement_effect(&mut state.borrows, stmt, loc); + self.uninits.apply_before_statement_effect(&mut state.uninits, stmt, loc); + self.ever_inits.apply_before_statement_effect(&mut state.ever_inits, stmt, loc); } - fn reconstruct_statement_effect( + fn apply_statement_effect( &mut self, state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { - self.borrows.analysis.apply_statement_effect(&mut state.borrows, stmt, loc); - self.uninits.analysis.apply_statement_effect(&mut state.uninits, stmt, loc); - self.ever_inits.analysis.apply_statement_effect(&mut state.ever_inits, stmt, loc); + self.borrows.apply_statement_effect(&mut state.borrows, stmt, loc); + self.uninits.apply_statement_effect(&mut state.uninits, stmt, loc); + self.ever_inits.apply_statement_effect(&mut state.ever_inits, stmt, loc); } - fn reconstruct_before_terminator_effect( + fn apply_before_terminator_effect( &mut self, state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, ) { - self.borrows.analysis.apply_before_terminator_effect(&mut state.borrows, term, loc); - self.uninits.analysis.apply_before_terminator_effect(&mut state.uninits, term, loc); - self.ever_inits.analysis.apply_before_terminator_effect(&mut state.ever_inits, term, loc); + self.borrows.apply_before_terminator_effect(&mut state.borrows, term, loc); + self.uninits.apply_before_terminator_effect(&mut state.uninits, term, loc); + self.ever_inits.apply_before_terminator_effect(&mut state.ever_inits, term, loc); } - fn reconstruct_terminator_effect( + fn apply_terminator_effect<'mir>( &mut self, state: &mut Self::Domain, - term: &mir::Terminator<'tcx>, + term: &'mir mir::Terminator<'tcx>, loc: Location, + ) -> TerminatorEdges<'mir, 'tcx> { + self.borrows.apply_terminator_effect(&mut state.borrows, term, loc); + self.uninits.apply_terminator_effect(&mut state.uninits, term, loc); + self.ever_inits.apply_terminator_effect(&mut state.ever_inits, term, loc); + + // This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this + // analysis doesn't use. + TerminatorEdges::None + } + + fn apply_call_return_effect( + &mut self, + _state: &mut Self::Domain, + _block: BasicBlock, + _return_places: CallReturnPlaces<'_, 'tcx>, + ) { + // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use. + unreachable!(); + } + + fn apply_switch_int_edge_effects( + &mut self, + _block: BasicBlock, + _discr: &mir::Operand<'tcx>, + _apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>, ) { - self.borrows.analysis.apply_terminator_effect(&mut state.borrows, term, loc); - self.uninits.analysis.apply_terminator_effect(&mut state.uninits, term, loc); - self.ever_inits.analysis.apply_terminator_effect(&mut state.ever_inits, term, loc); + // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use. + unreachable!(); } } +impl JoinSemiLattice for BorrowckDomain<'_, '_> { + fn join(&mut self, _other: &Self) -> bool { + // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use. + unreachable!(); + } +} + +impl<'tcx, C> DebugWithContext<C> for BorrowckDomain<'_, 'tcx> +where + C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("borrows: ")?; + self.borrows.fmt_with(ctxt, f)?; + f.write_str(" uninits: ")?; + self.uninits.fmt_with(ctxt, f)?; + f.write_str(" ever_inits: ")?; + self.ever_inits.fmt_with(ctxt, f)?; + Ok(()) + } + + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self == old { + return Ok(()); + } + + if self.borrows != old.borrows { + f.write_str("borrows: ")?; + self.borrows.fmt_diff_with(&old.borrows, ctxt, f)?; + f.write_str("\n")?; + } + + if self.uninits != old.uninits { + f.write_str("uninits: ")?; + self.uninits.fmt_diff_with(&old.uninits, ctxt, f)?; + f.write_str("\n")?; + } + + if self.ever_inits != old.ever_inits { + f.write_str("ever_inits: ")?; + self.ever_inits.fmt_diff_with(&old.ever_inits, ctxt, f)?; + f.write_str("\n")?; + } + + Ok(()) + } +} + +/// The transient state of the dataflow analyses used by the borrow checker. +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) struct BorrowckDomain<'a, 'tcx> { + pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain, + pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain, + pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain, +} + rustc_index::newtype_index! { #[orderable] #[debug_format = "bw{}"] @@ -563,6 +641,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { | mir::StatementKind::Coverage(..) | mir::StatementKind::Intrinsic(..) | mir::StatementKind::ConstEvalCounter + | mir::StatementKind::BackwardIncompatibleDropHint { .. } | mir::StatementKind::Nop => {} } } 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 454fd14ea74..c11103af476 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -27,7 +27,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ - self, ClauseKind, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast, + self, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast, suggest_constraining_type_params, }; use rustc_middle::util::CallKind; @@ -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()) }) @@ -649,11 +649,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ) -> Option<ty::Mutability> { let tcx = self.infcx.tcx; let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder(); - let clauses = tcx.predicates_of(callee_did).instantiate_identity(self.infcx.tcx).predicates; + let clauses = tcx.predicates_of(callee_did); // First, is there at least one method on one of `param`'s trait bounds? // This keeps us from suggesting borrowing the argument to `mem::drop`, e.g. - if !clauses.iter().any(|clause| { + if !clauses.instantiate_identity(tcx).predicates.iter().any(|clause| { clause.as_trait_clause().is_some_and(|tc| { tc.self_ty().skip_binder().is_param(param.index) && tc.polarity() == ty::PredicatePolarity::Positive @@ -682,9 +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.param_env, old_ty) - && let Ok(new_ty) = tcx.try_normalize_erasing_regions(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 @@ -700,23 +704,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { return false; } - // Test the callee's predicates, substituting a reference in for the self ty - // in bounds on `param`. - clauses.iter().all(|&clause| { - let clause_for_ref = clause.kind().map_bound(|kind| match kind { - ClauseKind::Trait(c) if c.self_ty().is_param(param.index) => { - ClauseKind::Trait(c.with_self_ty(tcx, ref_ty)) - } - ClauseKind::Projection(c) if c.self_ty().is_param(param.index) => { - ClauseKind::Projection(c.with_self_ty(tcx, ref_ty)) - } - _ => kind, - }); + // 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.infcx.param_env), + clause, + ) { + clause = normalized; + } self.infcx.predicate_must_hold_modulo_regions(&Obligation::new( tcx, ObligationCause::dummy(), - self.param_env, - ty::EarlyBinder::bind(clause_for_ref).instantiate(tcx, generic_args), + 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( @@ -3837,11 +3839,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if tcx.is_diagnostic_item(sym::deref_method, method_did) { let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { - Instance::try_resolve(tcx, self.param_env, deref_target, method_args) - .transpose() + Instance::try_resolve( + tcx, + 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.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 0797bb49bf9..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.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 807b5576976..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.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 657e6e0907c..16a4f699177 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -36,13 +36,13 @@ use rustc_middle::mir::*; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; -use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::impls::{ EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, }; use rustc_mir_dataflow::move_paths::{ InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex, }; +use rustc_mir_dataflow::{Analysis, EntrySets, Results, ResultsVisitor, visit_results}; use rustc_session::lint::builtin::UNUSED_MUT; use rustc_span::{Span, Symbol}; use smallvec::SmallVec; @@ -50,7 +50,7 @@ use tracing::{debug, instrument}; use crate::borrow_set::{BorrowData, BorrowSet}; use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions}; -use crate::dataflow::{BorrowIndex, BorrowckDomain, BorrowckResults, Borrows}; +use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows}; use crate::diagnostics::{AccessKind, IllegalMoveOriginKind, MoveError, RegionName}; use crate::location::LocationTable; use crate::nll::PoloniusOutput; @@ -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,11 +211,9 @@ 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, ); @@ -229,27 +225,6 @@ fn do_mir_borrowck<'tcx>( // information. nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req, &opaque_type_values, diags); - // The various `flow_*` structures can be large. We drop `flow_inits` here - // so it doesn't overlap with the others below. This reduces peak memory - // usage significantly on some benchmarks. - drop(flow_inits); - - let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set).iterate_to_fixpoint( - tcx, - body, - Some("borrowck"), - ); - let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint( - tcx, - body, - Some("borrowck"), - ); - let flow_ever_inits = EverInitializedPlaces::new(body, &move_data).iterate_to_fixpoint( - tcx, - body, - Some("borrowck"), - ); - let movable_coroutine = // The first argument is the coroutine type passed by value if let Some(local) = body.local_decls.raw.get(1) @@ -268,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 @@ -308,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, @@ -334,16 +307,11 @@ fn do_mir_borrowck<'tcx>( // Compute and report region errors, if any. mbcx.report_region_errors(nll_errors); - let mut results = BorrowckResults { - ever_inits: flow_ever_inits, - uninits: flow_uninits, - borrows: flow_borrows, - }; - - rustc_mir_dataflow::visit_results( + let mut flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx); + visit_results( body, traversal::reverse_postorder(body).map(|(bb, _)| bb), - &mut results, + &mut flow_results, &mut mbcx, ); @@ -426,15 +394,58 @@ fn do_mir_borrowck<'tcx>( (result, body_with_facts) } +fn get_flow_results<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + move_data: &'a MoveData<'tcx>, + borrow_set: &'a BorrowSet<'tcx>, + regioncx: &RegionInferenceContext<'tcx>, +) -> Results<'tcx, Borrowck<'a, 'tcx>> { + // We compute these three analyses individually, but them combine them into + // a single results so that `mbcx` can visit them all together. + let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint( + tcx, + body, + Some("borrowck"), + ); + let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint( + tcx, + body, + Some("borrowck"), + ); + let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint( + tcx, + body, + Some("borrowck"), + ); + + let analysis = Borrowck { + borrows: borrows.analysis, + uninits: uninits.analysis, + ever_inits: ever_inits.analysis, + }; + + assert_eq!(borrows.entry_sets.len(), uninits.entry_sets.len()); + assert_eq!(borrows.entry_sets.len(), ever_inits.entry_sets.len()); + let entry_sets: EntrySets<'_, Borrowck<'_, '_>> = + itertools::izip!(borrows.entry_sets, uninits.entry_sets, ever_inits.entry_sets) + .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits }) + .collect(); + + Results { analysis, entry_sets } +} + 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>( @@ -513,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>, @@ -588,14 +598,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { // 2. loans made in overlapping scopes do not conflict // 3. assignments do not affect things loaned out as immutable // 4. moves do not affect things loaned out in any way -impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> - for MirBorrowckCtxt<'a, '_, 'tcx> -{ - type Domain = BorrowckDomain<'a, 'tcx>; - +impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> { fn visit_statement_before_primary_effect( &mut self, - _results: &mut R, + _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, state: &BorrowckDomain<'a, 'tcx>, stmt: &'a Statement<'tcx>, location: Location, @@ -646,6 +652,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> | StatementKind::Coverage(..) // These do not actually affect borrowck | StatementKind::ConstEvalCounter + // This do not affect borrowck + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::StorageLive(..) => {} StatementKind::StorageDead(local) => { self.access_place( @@ -667,7 +675,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> fn visit_terminator_before_primary_effect( &mut self, - _results: &mut R, + _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, state: &BorrowckDomain<'a, 'tcx>, term: &'a Terminator<'tcx>, loc: Location, @@ -780,7 +788,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> fn visit_terminator_after_primary_effect( &mut self, - _results: &mut R, + _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, state: &BorrowckDomain<'a, 'tcx>, term: &'a Terminator<'tcx>, loc: Location, 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/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs index d1b65943199..f646beeecf7 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs @@ -88,6 +88,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> { | StatementKind::Nop | StatementKind::Retag { .. } | StatementKind::Deinit(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::SetDiscriminant { .. } => { bug!("Statement not allowed in this MIR phase") } 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 0fe6a4b5fce..3a7ed711f68 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, @@ -1265,6 +1252,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | StatementKind::Coverage(..) | StatementKind::ConstEvalCounter | StatementKind::PlaceMention(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => { bug!("Statement not allowed in this MIR phase") @@ -1527,7 +1515,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.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); } } @@ -1737,7 +1728,8 @@ 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) { + // FIXME(#132279): Using `Ty::is_sized` causes us to incorrectly handle opaques here. + if !erased_ty.is_sized(tcx, self.infcx.typing_env(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 @@ -2629,8 +2621,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 { @@ -2785,10 +2779,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_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index b686a8cf935..d46a1bd3d31 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -39,50 +39,10 @@ pub(crate) fn cfg_eval( let features = Some(features); CfgEval(StripUnconfigured { sess, features, config_tokens: true, lint_node_id }) .configure_annotatable(annotatable) - // Since the item itself has already been configured by the `InvocationCollector`, - // we know that fold result vector will contain exactly one element. - .unwrap() } struct CfgEval<'a>(StripUnconfigured<'a>); -fn flat_map_annotatable( - vis: &mut impl MutVisitor, - annotatable: Annotatable, -) -> Option<Annotatable> { - match annotatable { - Annotatable::Item(item) => vis.flat_map_item(item).pop().map(Annotatable::Item), - Annotatable::AssocItem(item, ctxt) => { - Some(Annotatable::AssocItem(vis.flat_map_assoc_item(item, ctxt).pop()?, ctxt)) - } - Annotatable::ForeignItem(item) => { - vis.flat_map_foreign_item(item).pop().map(Annotatable::ForeignItem) - } - Annotatable::Stmt(stmt) => { - vis.flat_map_stmt(stmt.into_inner()).pop().map(P).map(Annotatable::Stmt) - } - Annotatable::Expr(mut expr) => { - vis.visit_expr(&mut expr); - Some(Annotatable::Expr(expr)) - } - Annotatable::Arm(arm) => vis.flat_map_arm(arm).pop().map(Annotatable::Arm), - Annotatable::ExprField(field) => { - vis.flat_map_expr_field(field).pop().map(Annotatable::ExprField) - } - Annotatable::PatField(fp) => vis.flat_map_pat_field(fp).pop().map(Annotatable::PatField), - Annotatable::GenericParam(param) => { - vis.flat_map_generic_param(param).pop().map(Annotatable::GenericParam) - } - Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param), - Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef), - Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant), - Annotatable::Crate(mut krate) => { - vis.visit_crate(&mut krate); - Some(Annotatable::Crate(krate)) - } - } -} - fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool { struct CfgFinder; @@ -106,14 +66,7 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool { Annotatable::ForeignItem(item) => CfgFinder.visit_foreign_item(item), Annotatable::Stmt(stmt) => CfgFinder.visit_stmt(stmt), Annotatable::Expr(expr) => CfgFinder.visit_expr(expr), - Annotatable::Arm(arm) => CfgFinder.visit_arm(arm), - Annotatable::ExprField(field) => CfgFinder.visit_expr_field(field), - Annotatable::PatField(field) => CfgFinder.visit_pat_field(field), - Annotatable::GenericParam(param) => CfgFinder.visit_generic_param(param), - Annotatable::Param(param) => CfgFinder.visit_param(param), - Annotatable::FieldDef(field) => CfgFinder.visit_field_def(field), - Annotatable::Variant(variant) => CfgFinder.visit_variant(variant), - Annotatable::Crate(krate) => CfgFinder.visit_crate(krate), + _ => unreachable!(), }; res.is_break() } @@ -123,11 +76,11 @@ impl CfgEval<'_> { self.0.configure(node) } - fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option<Annotatable> { + fn configure_annotatable(mut self, annotatable: Annotatable) -> Annotatable { // Tokenizing and re-parsing the `Annotatable` can have a significant // performance impact, so try to avoid it if possible if !has_cfg_or_cfg_attr(&annotatable) { - return Some(annotatable); + return annotatable; } // The majority of parsed attribute targets will never need to have early cfg-expansion @@ -140,39 +93,6 @@ impl CfgEval<'_> { // the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization // process is lossless, so this process is invisible to proc-macros. - let parse_annotatable_with: for<'a> fn(&mut Parser<'a>) -> PResult<'a, _> = - match annotatable { - Annotatable::Item(_) => { - |parser| Ok(Annotatable::Item(parser.parse_item(ForceCollect::Yes)?.unwrap())) - } - Annotatable::AssocItem(_, AssocCtxt::Trait) => |parser| { - Ok(Annotatable::AssocItem( - parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap(), - AssocCtxt::Trait, - )) - }, - Annotatable::AssocItem(_, AssocCtxt::Impl) => |parser| { - Ok(Annotatable::AssocItem( - parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap(), - AssocCtxt::Impl, - )) - }, - Annotatable::ForeignItem(_) => |parser| { - Ok(Annotatable::ForeignItem( - parser.parse_foreign_item(ForceCollect::Yes)?.unwrap().unwrap(), - )) - }, - Annotatable::Stmt(_) => |parser| { - Ok(Annotatable::Stmt(P(parser - .parse_stmt_without_recovery(false, ForceCollect::Yes)? - .unwrap()))) - }, - Annotatable::Expr(_) => { - |parser| Ok(Annotatable::Expr(parser.parse_expr_force_collect()?)) - } - _ => unreachable!(), - }; - // 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`) // to `None`-delimited groups containing the corresponding tokens. This // is normally delayed until the proc-macro server actually needs to @@ -191,19 +111,56 @@ impl CfgEval<'_> { // Re-parse the tokens, setting the `capture_cfg` flag to save extra information // to the captured `AttrTokenStream` (specifically, we capture // `AttrTokenTree::AttrsTarget` for all occurrences of `#[cfg]` and `#[cfg_attr]`) + // + // After that we have our re-parsed `AttrTokenStream`, recursively configuring + // our attribute target will correctly configure the tokens as well. let mut parser = Parser::new(&self.0.sess.psess, orig_tokens, None); parser.capture_cfg = true; - match parse_annotatable_with(&mut parser) { - Ok(a) => annotatable = a, + let res: PResult<'_, Annotatable> = try { + match annotatable { + Annotatable::Item(_) => { + let item = parser.parse_item(ForceCollect::Yes)?.unwrap(); + Annotatable::Item(self.flat_map_item(item).pop().unwrap()) + } + Annotatable::AssocItem(_, AssocCtxt::Trait) => { + let item = parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap(); + Annotatable::AssocItem( + self.flat_map_assoc_item(item, AssocCtxt::Trait).pop().unwrap(), + AssocCtxt::Trait, + ) + } + Annotatable::AssocItem(_, AssocCtxt::Impl) => { + let item = parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap(); + Annotatable::AssocItem( + self.flat_map_assoc_item(item, AssocCtxt::Impl).pop().unwrap(), + AssocCtxt::Impl, + ) + } + Annotatable::ForeignItem(_) => { + let item = parser.parse_foreign_item(ForceCollect::Yes)?.unwrap().unwrap(); + Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap()) + } + Annotatable::Stmt(_) => { + let stmt = + parser.parse_stmt_without_recovery(false, ForceCollect::Yes)?.unwrap(); + Annotatable::Stmt(P(self.flat_map_stmt(stmt).pop().unwrap())) + } + Annotatable::Expr(_) => { + let mut expr = parser.parse_expr_force_collect()?; + self.visit_expr(&mut expr); + Annotatable::Expr(expr) + } + _ => unreachable!(), + } + }; + + match res { + Ok(ann) => ann, Err(err) => { err.emit(); - return Some(annotatable); + annotatable } } - - // Now that we have our re-parsed `AttrTokenStream`, recursively configuring - // our attribute target will correctly configure the tokens as well. - flat_map_annotatable(self, annotatable) } } @@ -247,10 +204,10 @@ impl MutVisitor for CfgEval<'_> { fn flat_map_assoc_item( &mut self, item: P<ast::AssocItem>, - _ctxt: AssocCtxt, + ctxt: AssocCtxt, ) -> SmallVec<[P<ast::AssocItem>; 1]> { let item = configure!(self, item); - mut_visit::walk_flat_map_item(self, item) + mut_visit::walk_flat_map_assoc_item(self, item, ctxt) } fn flat_map_foreign_item( @@ -258,7 +215,7 @@ impl MutVisitor for CfgEval<'_> { foreign_item: P<ast::ForeignItem>, ) -> SmallVec<[P<ast::ForeignItem>; 1]> { let foreign_item = configure!(self, foreign_item); - mut_visit::walk_flat_map_item(self, foreign_item) + mut_visit::walk_flat_map_foreign_item(self, foreign_item) } fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 95348453308..b2048c534a4 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -1,6 +1,6 @@ // Code that generates a test runner to run all the tests in a crate -use std::{iter, mem}; +use std::mem; use rustc_ast as ast; use rustc_ast::entry::EntryPointType; @@ -19,7 +19,7 @@ use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency}; use rustc_span::symbol::{Ident, Symbol, sym}; use rustc_span::{DUMMY_SP, Span}; use rustc_target::spec::PanicStrategy; -use smallvec::{SmallVec, smallvec}; +use smallvec::smallvec; use thin_vec::{ThinVec, thin_vec}; use tracing::debug; @@ -129,8 +129,9 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { c.items.push(mk_main(&mut self.cx)); } - fn flat_map_item(&mut self, mut i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> { - let item = &mut *i; + fn visit_item(&mut self, item: &mut P<ast::Item>) { + let item = &mut **item; + if let Some(name) = get_test_name(&item) { debug!("this is a test item"); @@ -144,13 +145,20 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { item.kind { let prev_tests = mem::take(&mut self.tests); - walk_item_kind(&mut item.kind, item.span, item.id, self); + walk_item_kind( + &mut item.kind, + item.span, + item.id, + &mut item.ident, + &mut item.vis, + (), + self, + ); self.add_test_cases(item.id, span, prev_tests); } else { // But in those cases, we emit a lint to warn the user of these missing tests. walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item); } - smallvec![i] } } @@ -190,40 +198,30 @@ struct EntryPointCleaner<'a> { } impl<'a> MutVisitor for EntryPointCleaner<'a> { - fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> { + fn visit_item(&mut self, item: &mut P<ast::Item>) { self.depth += 1; - let item = walk_flat_map_item(self, i).expect_one("noop did something"); + ast::mut_visit::walk_item(self, item); self.depth -= 1; // Remove any #[rustc_main] or #[start] from the AST so it doesn't // clash with the one we're going to add, but mark it as // #[allow(dead_code)] to avoid printing warnings. - let item = match entry_point_type(&item, self.depth == 0) { + match entry_point_type(&item, self.depth == 0) { EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => { - item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| { - let allow_dead_code = attr::mk_attr_nested_word( - &self.sess.psess.attr_id_generator, - ast::AttrStyle::Outer, - ast::Safety::Default, - sym::allow, - sym::dead_code, - self.def_site, - ); - let attrs = attrs - .into_iter() - .filter(|attr| { - !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start) - }) - .chain(iter::once(allow_dead_code)) - .collect(); - - ast::Item { id, ident, attrs, kind, vis, span, tokens } - }) + let allow_dead_code = attr::mk_attr_nested_word( + &self.sess.psess.attr_id_generator, + ast::AttrStyle::Outer, + ast::Safety::Default, + sym::allow, + sym::dead_code, + self.def_site, + ); + item.attrs + .retain(|attr| !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start)); + item.attrs.push(allow_dead_code); } - EntryPointType::None | EntryPointType::OtherMain => item, + EntryPointType::None | EntryPointType::OtherMain => {} }; - - smallvec![item] } } @@ -284,7 +282,7 @@ fn generate_test_harness( /// Most of the Ident have the usual def-site hygiene for the AST pass. The /// exception is the `test_const`s. These have a syntax context that has two /// opaque marks: one from the expansion of `test` or `test_case`, and one -/// generated in `TestHarnessGenerator::flat_map_item`. When resolving this +/// generated in `TestHarnessGenerator::visit_item`. When resolving this /// identifier after failing to find a matching identifier in the root module /// we remove the outer mark, and try resolving at its def-site, which will /// then resolve to `test_const`. 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_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index f647ee36c48..7dd2139cf90 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -376,7 +376,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( let instance = if let ty::FnDef(def_id, fn_args) = *func.layout().ty.kind() { let instance = ty::Instance::expect_resolve( fx.tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), def_id, fn_args, source_info.span, diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index da3818ca25e..70b7d92ce15 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -11,7 +11,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::InlineAsmMacro; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::layout::FnAbiOf; +use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv}; use rustc_middle::ty::print::with_no_trimmed_paths; use crate::constant::ConstantCx; @@ -666,7 +666,7 @@ fn codegen_stmt<'tcx>( let func_ref = fx.get_function_ref( Instance::resolve_for_fn_ptr( fx.tcx, - ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), def_id, args, ) @@ -841,14 +841,18 @@ fn codegen_stmt<'tcx>( lval.write_cvalue(fx, CValue::by_val(operand, box_layout)); } Rvalue::NullaryOp(ref null_op, ty) => { - assert!(lval.layout().ty.is_sized(fx.tcx, ParamEnv::reveal_all())); + assert!(lval.layout().ty.is_sized(fx.tcx, fx.typing_env())); let layout = fx.layout_of(fx.monomorphize(ty)); let val = match null_op { NullOp::SizeOf => layout.size.bytes(), NullOp::AlignOf => layout.align.abi.bytes(), NullOp::OffsetOf(fields) => fx .tcx - .offset_of_subfield(ParamEnv::reveal_all(), layout, fields.iter()) + .offset_of_subfield( + ty::TypingEnv::fully_monomorphized(), + layout, + fields.iter(), + ) .bytes(), NullOp::UbChecks => { let val = fx.tcx.sess.ub_checks(); @@ -920,6 +924,7 @@ fn codegen_stmt<'tcx>( | StatementKind::FakeRead(..) | StatementKind::Retag { .. } | StatementKind::PlaceMention(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::AscribeUserType(..) => {} StatementKind::Coverage { .. } => unreachable!(), diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 27e71b92561..c663fa32965 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -103,11 +103,11 @@ fn clif_pair_type_from_ty<'tcx>( /// Is a pointer to this type a wide ptr? pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - if ty.is_sized(tcx, ParamEnv::reveal_all()) { + if ty.is_sized(tcx, ty::TypingEnv::fully_monomorphized()) { return false; } - let tail = tcx.struct_tail_for_codegen(ty, ParamEnv::reveal_all()); + let tail = tcx.struct_tail_for_codegen(ty, ty::TypingEnv::fully_monomorphized()); match tail.kind() { ty::Foreign(..) => false, ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, @@ -339,9 +339,9 @@ impl<'tcx> rustc_abi::HasDataLayout for FunctionCx<'_, '_, 'tcx> { } } -impl<'tcx> layout::HasParamEnv<'tcx> for FunctionCx<'_, '_, 'tcx> { - fn param_env(&self) -> ParamEnv<'tcx> { - ParamEnv::reveal_all() +impl<'tcx> layout::HasTypingEnv<'tcx> for FunctionCx<'_, '_, 'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + ty::TypingEnv::fully_monomorphized() } } @@ -358,7 +358,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { { self.instance.instantiate_mir_and_normalize_erasing_regions( self.tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), ty::EarlyBinder::bind(value), ) } @@ -497,9 +497,9 @@ impl<'tcx> rustc_abi::HasDataLayout for RevealAllLayoutCx<'tcx> { } } -impl<'tcx> layout::HasParamEnv<'tcx> for RevealAllLayoutCx<'tcx> { - fn param_env(&self) -> ParamEnv<'tcx> { - ParamEnv::reveal_all() +impl<'tcx> layout::HasTypingEnv<'tcx> for RevealAllLayoutCx<'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + ty::TypingEnv::fully_monomorphized() } } diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index ab78584332a..abe6085b04f 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -78,7 +78,7 @@ pub(crate) fn eval_mir_constant<'tcx>( let cv = fx.monomorphize(constant.const_); // This cannot fail because we checked all required_consts in advance. let val = cv - .eval(fx.tcx, ty::ParamEnv::reveal_all(), constant.span) + .eval(fx.tcx, ty::TypingEnv::fully_monomorphized(), constant.span) .expect("erroneous constant missed by mono item collection"); (val, cv.ty()) } @@ -265,8 +265,13 @@ fn data_id_for_static( assert!(!definition); assert!(!tcx.is_mutable_static(def_id)); - let ty = instance.ty(tcx, ParamEnv::reveal_all()); - let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes(); + let ty = instance.ty(tcx, ty::TypingEnv::fully_monomorphized()); + let align = tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) + .unwrap() + .align + .pref + .bytes(); let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak || import_linkage == rustc_middle::mir::mono::Linkage::WeakAny @@ -578,6 +583,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( | StatementKind::PlaceMention(..) | StatementKind::Coverage(_) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} } } diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 9025ea97b81..f3a8623e216 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -210,7 +210,7 @@ impl DebugContext { type_names::push_generic_params( tcx, - tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args), + tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), args), &mut name, ); @@ -275,8 +275,10 @@ impl DebugContext { let span = tcx.def_span(def_id); let (file_id, line, _column) = self.get_span_loc(tcx, span, span); - let static_type = Instance::mono(tcx, def_id).ty(tcx, ty::ParamEnv::reveal_all()); - let static_layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(static_type)).unwrap(); + let static_type = Instance::mono(tcx, def_id).ty(tcx, ty::TypingEnv::fully_monomorphized()); + let static_layout = tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(static_type)) + .unwrap(); // FIXME use the actual type layout let type_id = self.debug_type(tcx, type_dbg, static_type); diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index a3f816f70a9..0df1a30fc0a 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -92,7 +92,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( if let ty::FnDef(def_id, args) = *const_.ty().kind() { let instance = ty::Instance::resolve_for_fn_ptr( fx.tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), def_id, args, ) @@ -227,11 +227,11 @@ pub(crate) fn codegen_naked_asm<'tcx>( InlineAsmOperand::Const { ref value } => { let cv = instance.instantiate_mir_and_normalize_erasing_regions( tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), ty::EarlyBinder::bind(value.const_), ); let const_value = cv - .eval(tcx, ty::ParamEnv::reveal_all(), value.span) + .eval(tcx, ty::TypingEnv::fully_monomorphized(), value.span) .expect("erroneous constant missed by mono item collection"); let value = rustc_codegen_ssa::common::asm_const_to_str( @@ -250,13 +250,13 @@ pub(crate) fn codegen_naked_asm<'tcx>( let const_ = instance.instantiate_mir_and_normalize_erasing_regions( tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), ty::EarlyBinder::bind(value.const_), ); if let ty::FnDef(def_id, args) = *const_.ty().kind() { let instance = ty::Instance::resolve_for_fn_ptr( tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), def_id, args, ) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 1e2e41b3122..3318c0797ec 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -20,7 +20,7 @@ mod simd; use cranelift_codegen::ir::AtomicRmwOp; use rustc_middle::ty; use rustc_middle::ty::GenericArgsRef; -use rustc_middle::ty::layout::{HasParamEnv, ValidityRequirement}; +use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{Symbol, sym}; @@ -453,11 +453,6 @@ fn codegen_regular_intrinsic_call<'tcx>( fx.bcx.ins().trap(TrapCode::user(2).unwrap()); return Ok(()); } - sym::likely | sym::unlikely => { - intrinsic_args!(fx, args => (a); intrinsic); - - ret.write_cvalue(fx, a); - } sym::breakpoint => { intrinsic_args!(fx, args => (); intrinsic); @@ -687,7 +682,10 @@ fn codegen_regular_intrinsic_call<'tcx>( if let Some(requirement) = requirement { let do_panic = !fx .tcx - .check_validity_requirement((requirement, fx.param_env().and(ty))) + .check_validity_requirement(( + requirement, + ty::TypingEnv::fully_monomorphized().as_query_input(ty), + )) .expect("expect to have layout during codegen"); if do_panic { @@ -746,7 +744,11 @@ fn codegen_regular_intrinsic_call<'tcx>( let const_val = fx .tcx - .const_eval_instance(ParamEnv::reveal_all(), instance, source_info.span) + .const_eval_instance( + ty::TypingEnv::fully_monomorphized(), + instance, + source_info.span, + ) .unwrap(); let val = crate::constant::codegen_const_value(fx, const_val, ret.layout().ty); ret.write_cvalue(fx, val); @@ -1267,6 +1269,11 @@ fn codegen_regular_intrinsic_call<'tcx>( ); } + sym::cold_path => { + // This is a no-op. The intrinsic is just a hint to the optimizer. + // We still have an impl here to avoid it being turned into a call. + } + // Unimplemented intrinsics must have a fallback body. The fallback body is obtained // by converting the `InstanceKind::Intrinsic` to an `InstanceKind::Item`. _ => { diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index b506b1f5731..e6f6ae30581 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -98,7 +98,7 @@ mod prelude { pub(crate) use rustc_middle::mir::{self, *}; pub(crate) use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; pub(crate) use rustc_middle::ty::{ - self, FloatTy, Instance, InstanceKind, IntTy, ParamEnv, Ty, TyCtxt, UintTy, + self, FloatTy, Instance, InstanceKind, IntTy, Ty, TyCtxt, UintTy, }; pub(crate) use rustc_span::Span; diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index df92bc58bf5..2ee4ff5cec7 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -49,7 +49,7 @@ pub(crate) fn maybe_create_entry_wrapper( // regions must appear in the argument // listing. let main_ret_ty = tcx.normalize_erasing_regions( - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), main_ret_ty.no_bound_vars().unwrap(), ); @@ -113,7 +113,7 @@ pub(crate) fn maybe_create_entry_wrapper( .unwrap(); let report = Instance::expect_resolve( tcx, - ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), report.def_id, tcx.mk_args(&[GenericArg::from(main_ret_ty)]), DUMMY_SP, @@ -139,7 +139,7 @@ pub(crate) fn maybe_create_entry_wrapper( let start_def_id = tcx.require_lang_item(LangItem::Start, None); let start_instance = Instance::expect_resolve( tcx, - ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), start_def_id, tcx.mk_args(&[main_ret_ty.into()]), DUMMY_SP, diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 336934354e1..2843e5bbdfb 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -3,6 +3,7 @@ //! [`PointerCoercion::Unsize`]: `rustc_middle::ty::adjustment::PointerCoercion::Unsize` use rustc_codegen_ssa::base::validate_trivial_unsize; +use rustc_middle::ty::layout::HasTypingEnv; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use crate::base::codegen_panic_nounwind; @@ -23,7 +24,7 @@ pub(crate) fn unsized_info<'tcx>( old_info: Option<Value>, ) -> Value { let (source, target) = - fx.tcx.struct_lockstep_tails_for_codegen(source, target, ParamEnv::reveal_all()); + fx.tcx.struct_lockstep_tails_for_codegen(source, target, fx.typing_env()); match (&source.kind(), &target.kind()) { (&ty::Array(_, len), &ty::Slice(_)) => fx.bcx.ins().iconst( fx.pointer_type, diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 900d7e69714..6676e684ca0 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -4,6 +4,7 @@ use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::immediates::Offset32; use cranelift_frontend::Variable; use rustc_middle::ty::FnSig; +use rustc_middle::ty::layout::HasTypingEnv; use crate::prelude::*; @@ -884,19 +885,17 @@ pub(crate) fn assert_assignable<'tcx>( assert_assignable(fx, *a, *b, limit - 1); } (ty::FnPtr(..), ty::FnPtr(..)) => { - let from_sig = fx.tcx.normalize_erasing_late_bound_regions( - ParamEnv::reveal_all(), - from_ty.fn_sig(fx.tcx), - ); + let from_sig = fx + .tcx + .normalize_erasing_late_bound_regions(fx.typing_env(), from_ty.fn_sig(fx.tcx)); let FnSig { inputs_and_output: types_from, c_variadic: c_variadic_from, safety: unsafety_from, abi: abi_from, } = from_sig; - let to_sig = fx - .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to_ty.fn_sig(fx.tcx)); + let to_sig = + fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), to_ty.fn_sig(fx.tcx)); let FnSig { inputs_and_output: types_to, c_variadic: c_variadic_to, @@ -932,9 +931,8 @@ pub(crate) fn assert_assignable<'tcx>( (&ty::Dynamic(from_traits, _, _from_kind), &ty::Dynamic(to_traits, _, _to_kind)) => { // FIXME(dyn-star): Do the right thing with DynKinds for (from, to) in from_traits.iter().zip(to_traits) { - let from = - fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from); - let to = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to); + let from = fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), from); + let to = fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), to); assert_eq!( from, to, "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}", diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index e6ae7cf174d..9a142326ad1 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -24,9 +24,9 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{ - FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, + FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers, }; -use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_span::Span; use rustc_span::def_id::DefId; use rustc_target::abi::call::FnAbi; @@ -2319,9 +2319,9 @@ impl<'a, 'gcc, 'tcx> StaticBuilderMethods for Builder<'a, 'gcc, 'tcx> { } } -impl<'tcx> HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> { - fn param_env(&self) -> ParamEnv<'tcx> { - self.cx.param_env() +impl<'tcx> HasTypingEnv<'tcx> for Builder<'_, '_, 'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + self.cx.typing_env() } } diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 07c7a54de1c..6dc2f4ed668 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -215,7 +215,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let gcc_type = if nested { self.type_i8() } else { - let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); + let ty = instance.ty(self.tcx, ty::TypingEnv::fully_monomorphized()); self.layout_of(ty).gcc_type(self) }; diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 707b35967a6..3846d025537 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -11,10 +11,10 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::mono::CodegenUnit; use rustc_middle::span_bug; use rustc_middle::ty::layout::{ - FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, + FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers, }; -use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; use rustc_span::source_map::respan; use rustc_span::{DUMMY_SP, Span}; @@ -144,7 +144,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { supports_f128_type: bool, ) -> Self { let create_type = |ctype, rust_type| { - let layout = tcx.layout_of(ParamEnv::reveal_all().and(rust_type)).unwrap(); + let layout = tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(rust_type)) + .unwrap(); let align = layout.align.abi.bytes(); #[cfg(feature = "master")] { @@ -459,7 +461,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { Some(def_id) if !wants_msvc_seh(self.sess()) => { let instance = ty::Instance::expect_resolve( tcx, - ty::ParamEnv::reveal_all(), + self.typing_env(), def_id, ty::List::empty(), DUMMY_SP, @@ -583,9 +585,9 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { } } -impl<'tcx, 'gcc> HasParamEnv<'tcx> for CodegenCx<'gcc, 'tcx> { - fn param_env(&self) -> ParamEnv<'tcx> { - ParamEnv::reveal_all() +impl<'tcx, 'gcc> HasTypingEnv<'tcx> for CodegenCx<'gcc, 'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + ty::TypingEnv::fully_monomorphized() } } diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index 5d8c5c199b1..6aeb656c1ab 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -113,15 +113,15 @@ fn make_mir_scope<'gcc, 'tcx>( let scope_data = &mir.source_scopes[scope]; let parent_scope = if let Some(parent) = scope_data.parent_scope { make_mir_scope(cx, _instance, mir, variables, debug_context, instantiated, parent); - debug_context.scopes[parent] + debug_context.scopes[parent].unwrap() } else { // The root is the function itself. let file = cx.sess().source_map().lookup_source_file(mir.span.lo()); - debug_context.scopes[scope] = DebugScope { + debug_context.scopes[scope] = Some(DebugScope { file_start_pos: file.start_pos, file_end_pos: file.end_position(), - ..debug_context.scopes[scope] - }; + ..debug_context.scopes[scope].unwrap() + }); instantiated.insert(scope); return; }; @@ -130,7 +130,7 @@ fn make_mir_scope<'gcc, 'tcx>( if !vars.contains(scope) && scope_data.inlined.is_none() { // Do not create a DIScope if there are no variables defined in this // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. - debug_context.scopes[scope] = parent_scope; + debug_context.scopes[scope] = Some(parent_scope); instantiated.insert(scope); return; } @@ -157,12 +157,12 @@ fn make_mir_scope<'gcc, 'tcx>( // TODO(tempdragon): dbg_scope: Add support for scope extension here. inlined_at.or(p_inlined_at); - debug_context.scopes[scope] = DebugScope { + debug_context.scopes[scope] = Some(DebugScope { dbg_scope, inlined_at, file_start_pos: loc.file.start_pos, file_end_pos: loc.file.end_position(), - }; + }); instantiated.insert(scope); } @@ -232,12 +232,12 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } // Initialize fn debug context (including scopes). - let empty_scope = DebugScope { + let empty_scope = Some(DebugScope { dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)), inlined_at: None, file_start_pos: BytePos(0), file_end_pos: BytePos(0), - }; + }); let mut fn_debug_context = FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, mir.source_scopes.as_slice()), inlined_function_scopes: Default::default(), diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index 5ca440f4c9b..02b760dc733 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -5,7 +5,7 @@ use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, BuilderMethods, OverflowOp}; -use rustc_middle::ty::{ParamEnv, Ty}; +use rustc_middle::ty::{self, Ty}; use rustc_target::abi::Endian; use rustc_target::abi::call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode}; use rustc_target::spec; @@ -380,7 +380,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let overflow_field = self.context.new_field(self.location, self.bool_type, "overflow"); let ret_ty = Ty::new_tup(self.tcx, &[self.tcx.types.i128, self.tcx.types.bool]); - let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ret_ty)).unwrap(); + let layout = self + .tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ret_ty)) + .unwrap(); let arg_abi = ArgAbi { layout, mode: PassMode::Direct(ArgAttributes::new()) }; let mut fn_abi = FnAbi { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index b0298a35cb0..69326f409bb 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -21,7 +21,7 @@ use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, MiscCodegenMethods}; use rustc_middle::bug; use rustc_middle::ty::layout::LayoutOf; #[cfg(feature = "master")] -use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; +use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv}; use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{Span, Symbol, sym}; use rustc_target::abi::HasDataLayout; @@ -107,7 +107,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc span: Span, ) -> Result<(), Instance<'tcx>> { let tcx = self.tcx; - let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); + let callee_ty = instance.ty(tcx, self.typing_env()); let (def_id, fn_args) = match *callee_ty.kind() { ty::FnDef(def_id, fn_args) => (def_id, fn_args), @@ -115,7 +115,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc }; let sig = callee_ty.fn_sig(tcx); - let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); + let sig = tcx.normalize_erasing_late_bound_regions(self.typing_env(), sig); let arg_tys = sig.inputs(); let ret_ty = sig.output(); let name = tcx.item_name(def_id); @@ -139,8 +139,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), ) } - sym::likely => self.expect(args[0].immediate(), true), - sym::unlikely => self.expect(args[0].immediate(), false), sym::is_val_statically_known => { let a = args[0].immediate(); let builtin = self.context.get_builtin_function("__builtin_constant_p"); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 43dbfafa871..604678a9af4 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -55,8 +55,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( } let tcx = bx.tcx(); - let sig = - tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx)); + let sig = tcx.normalize_erasing_late_bound_regions( + ty::TypingEnv::fully_monomorphized(), + callee_ty.fn_sig(tcx), + ); let arg_tys = sig.inputs(); if name == sym::simd_select_bitmask { @@ -478,7 +480,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( match *in_elem.kind() { ty::RawPtr(p_ty, _) => { let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { - bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) + bx.tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty) }); require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer { span, @@ -493,7 +495,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( match *out_elem.kind() { ty::RawPtr(p_ty, _) => { let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { - bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) + bx.tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty) }); require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer { span, diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs index b7b282bf2a6..239902df7f0 100644 --- a/compiler/rustc_codegen_gcc/src/mono_item.rs +++ b/compiler/rustc_codegen_gcc/src/mono_item.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::mono::{Linkage, Visibility}; -use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; +use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use crate::context::CodegenCx; @@ -27,11 +27,8 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() }; // Nested statics do not have a type, so pick a dummy type and let `codegen_static` figure out // the gcc type from the actual evaluated initializer. - let ty = if nested { - self.tcx.types.unit - } else { - instance.ty(self.tcx, ty::ParamEnv::reveal_all()) - }; + let ty = + if nested { self.tcx.types.unit } else { instance.ty(self.tcx, self.typing_env()) }; let gcc_type = self.layout_of(ty).gcc_type(self); let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index ac76b781218..b5bb7630ca6 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -14,7 +14,7 @@ use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{ - FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers, + FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers, TyAndLayout, }; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; @@ -81,9 +81,9 @@ impl<'tcx> ty::layout::HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> { } } -impl<'tcx> ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> { - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.cx.param_env() +impl<'tcx> ty::layout::HasTypingEnv<'tcx> for Builder<'_, '_, 'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + self.cx.typing_env() } } @@ -472,7 +472,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { #[instrument(level = "trace", skip(self))] fn load_operand(&mut self, place: PlaceRef<'tcx, &'ll Value>) -> OperandRef<'tcx, &'ll Value> { if place.layout.is_unsized() { - let tail = self.tcx.struct_tail_for_codegen(place.layout.ty, self.param_env()); + let tail = self.tcx.struct_tail_for_codegen(place.layout.ty, self.typing_env()); if matches!(tail.kind(), ty::Foreign(..)) { // Unsized locals and, at least conceptually, even unsized arguments must be copied // around, which requires dynamically determining their size. Therefore, we cannot diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index dcea9d3b391..e0a2de3366c 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -5,7 +5,7 @@ //! closure. use rustc_codegen_ssa::common; -use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; +use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use tracing::debug; @@ -28,12 +28,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t } let sym = tcx.symbol_name(instance).name; - debug!( - "get_fn({:?}: {:?}) => {}", - instance, - instance.ty(cx.tcx(), ty::ParamEnv::reveal_all()), - sym - ); + debug!("get_fn({:?}: {:?}) => {}", instance, instance.ty(cx.tcx(), cx.typing_env()), sym); let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 7ab4f45cd73..6f5ffbb4b34 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -13,8 +13,8 @@ use rustc_middle::mir::interpret::{ read_target_uint, }; use rustc_middle::mir::mono::MonoItem; -use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, Instance}; +use rustc_middle::ty::Instance; +use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::{bug, span_bug}; use rustc_session::config::Lto; use tracing::{debug, instrument, trace}; @@ -244,7 +244,7 @@ impl<'ll> CodegenCx<'ll, '_> { let llty = if nested { self.type_i8() } else { - let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); + let ty = instance.ty(self.tcx, self.typing_env()); trace!(?ty); self.layout_of(ty).llvm_type(self) }; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 3a7c7efe03b..841c110b3c8 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -15,7 +15,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::PatchableFunctionEntry; use rustc_middle::mir::mono::CodegenUnit; use rustc_middle::ty::layout::{ - FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers, + FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers, }; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -658,7 +658,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let llfn = match tcx.lang_items().eh_personality() { Some(def_id) if name.is_none() => self.get_fn_addr(ty::Instance::expect_resolve( tcx, - ty::ParamEnv::reveal_all(), + self.typing_env(), def_id, ty::List::empty(), DUMMY_SP, @@ -1162,9 +1162,9 @@ impl<'tcx> ty::layout::HasTyCtxt<'tcx> for CodegenCx<'_, 'tcx> { } } -impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> { - fn param_env(&self) -> ty::ParamEnv<'tcx> { - ty::ParamEnv::reveal_all() +impl<'tcx, 'll> HasTypingEnv<'tcx> for CodegenCx<'ll, 'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + ty::TypingEnv::fully_monomorphized() } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index 0f1909486ec..07bd0f4d1c1 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -6,10 +6,10 @@ use rustc_data_structures::fx::FxHashMap; use rustc_index::Idx; use rustc_index::bit_set::BitSet; use rustc_middle::mir::{Body, SourceScope}; -use rustc_middle::ty::layout::FnAbiOf; +use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv}; use rustc_middle::ty::{self, Instance}; use rustc_session::config::DebugInfo; -use rustc_span::BytePos; +use rustc_span::{BytePos, hygiene}; use super::metadata::file_metadata; use super::utils::DIB; @@ -85,15 +85,23 @@ fn make_mir_scope<'ll, 'tcx>( discriminators, parent, ); - debug_context.scopes[parent] + if let Some(parent_scope) = debug_context.scopes[parent] { + parent_scope + } else { + // If the parent scope could not be represented then no children + // can be either. + debug_context.scopes[scope] = None; + instantiated.insert(scope); + return; + } } else { // The root is the function itself. let file = cx.sess().source_map().lookup_source_file(mir.span.lo()); - debug_context.scopes[scope] = DebugScope { + debug_context.scopes[scope] = Some(DebugScope { file_start_pos: file.start_pos, file_end_pos: file.end_position(), - ..debug_context.scopes[scope] - }; + ..debug_context.scopes[scope].unwrap() + }); instantiated.insert(scope); return; }; @@ -104,7 +112,7 @@ fn make_mir_scope<'ll, 'tcx>( { // Do not create a DIScope if there are no variables defined in this // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. - debug_context.scopes[scope] = parent_scope; + debug_context.scopes[scope] = Some(parent_scope); instantiated.insert(scope); return; } @@ -118,7 +126,7 @@ fn make_mir_scope<'ll, 'tcx>( // if this is moved to `rustc_codegen_ssa::mir::debuginfo`. let callee = cx.tcx.instantiate_and_normalize_erasing_regions( instance.args, - ty::ParamEnv::reveal_all(), + cx.typing_env(), ty::EarlyBinder::bind(callee), ); debug_context.inlined_function_scopes.entry(callee).or_insert_with(|| { @@ -137,14 +145,20 @@ fn make_mir_scope<'ll, 'tcx>( }, }; - let inlined_at = scope_data.inlined.map(|(_, callsite_span)| { - // FIXME(eddyb) this doesn't account for the macro-related - // `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does. + let mut debug_scope = Some(DebugScope { + dbg_scope, + inlined_at: parent_scope.inlined_at, + file_start_pos: loc.file.start_pos, + file_end_pos: loc.file.end_position(), + }); + + if let Some((_, callsite_span)) = scope_data.inlined { + let callsite_span = hygiene::walk_chain_collapsed(callsite_span, mir.span); let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span); let loc = cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span); // NB: In order to produce proper debug info for variables (particularly - // arguments) in multiply-inline functions, LLVM expects to see a single + // arguments) in multiply-inlined functions, LLVM expects to see a single // DILocalVariable with multiple different DILocations in the IR. While // the source information for each DILocation would be identical, their // inlinedAt attributes will be unique to the particular callsite. @@ -152,7 +166,7 @@ fn make_mir_scope<'ll, 'tcx>( // We generate DILocations here based on the callsite's location in the // source code. A single location in the source code usually can't // produce multiple distinct calls so this mostly works, until - // proc-macros get involved. A proc-macro can generate multiple calls + // macros get involved. A macro can generate multiple calls // at the same span, which breaks the assumption that we're going to // produce a unique DILocation for every scope we process here. We // have to explicitly add discriminators if we see inlines into the @@ -161,24 +175,29 @@ fn make_mir_scope<'ll, 'tcx>( // Note further that we can't key this hashtable on the span itself, // because these spans could have distinct SyntaxContexts. We have // to key on exactly what we're giving to LLVM. - match discriminators.entry(callsite_span.lo()) { + let inlined_at = match discriminators.entry(callsite_span.lo()) { Entry::Occupied(mut o) => { *o.get_mut() += 1; unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, *o.get()) } - .expect("Failed to encode discriminator in DILocation") } Entry::Vacant(v) => { v.insert(0); - loc + Some(loc) + } + }; + match inlined_at { + Some(inlined_at) => { + debug_scope.as_mut().unwrap().inlined_at = Some(inlined_at); + } + None => { + // LLVM has a maximum discriminator that it can encode (currently + // it uses 12 bits for 4096 possible values). If we exceed that + // there is little we can do but drop the debug info. + debug_scope = None; } } - }); + } - debug_context.scopes[scope] = DebugScope { - dbg_scope, - inlined_at: inlined_at.or(parent_scope.inlined_at), - file_start_pos: loc.file.start_pos, - file_end_pos: loc.file.end_position(), - }; + debug_context.scopes[scope] = debug_scope; instantiated.insert(scope); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 151923a3bd2..ef16e5bb459 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -11,10 +11,9 @@ use rustc_codegen_ssa::traits::*; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::bug; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{ - self, AdtKind, CoroutineArgsExt, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt, - Visibility, + self, AdtKind, CoroutineArgsExt, Instance, PolyExistentialTraitRef, Ty, TyCtxt, Visibility, }; use rustc_session::config::{self, DebugInfo, Lto}; use rustc_span::symbol::Symbol; @@ -301,9 +300,8 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( .insert(unique_type_id, recursion_marker_type_di_node(cx)); let fn_ty = unique_type_id.expect_ty(); - let signature = cx - .tcx - .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), fn_ty.fn_sig(cx.tcx)); + let signature = + cx.tcx.normalize_erasing_late_bound_regions(cx.typing_env(), fn_ty.fn_sig(cx.tcx)); let signature_di_nodes: SmallVec<_> = iter::once( // return type @@ -1109,9 +1107,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>( } }; - assert!( - up_var_tys.iter().all(|t| t == cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t)) - ); + assert!(up_var_tys.iter().all(|t| t == cx.tcx.normalize_erasing_regions(cx.typing_env(), t))); let capture_names = cx.tcx.closure_saved_names_of_captured_variables(def_id); let layout = cx.layout_of(closure_or_coroutine_ty); @@ -1272,8 +1268,7 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>( let template_params: SmallVec<_> = iter::zip(args, names) .filter_map(|(kind, name)| { kind.as_type().map(|ty| { - let actual_type = - cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); + let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); let actual_type_di_node = type_di_node(cx, actual_type); let name = name.as_str(); unsafe { @@ -1341,7 +1336,7 @@ pub(crate) fn build_global_var_di_node<'ll>( if nested { return; } - let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all()); + let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, cx.typing_env()); let type_di_node = type_di_node(cx, variable_type); let var_name = tcx.item_name(def_id); let var_name = var_name.as_str(); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index 5120b63d173..4e461476040 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable; use rustc_middle::bug; -use rustc_middle::ty::{ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, PolyExistentialTraitRef, Ty, TyCtxt}; use super::{SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata}; use crate::common::{AsCCharPtr, CodegenCx}; @@ -49,12 +49,15 @@ pub(super) enum UniqueTypeId<'tcx> { impl<'tcx> UniqueTypeId<'tcx> { pub(crate) fn for_ty(tcx: TyCtxt<'tcx>, t: Ty<'tcx>) -> Self { - assert_eq!(t, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t)); + assert_eq!(t, tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), t)); UniqueTypeId::Ty(t, private::HiddenZst) } pub(crate) fn for_enum_variant_part(tcx: TyCtxt<'tcx>, enum_ty: Ty<'tcx>) -> Self { - assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty)); + assert_eq!( + enum_ty, + tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), enum_ty) + ); UniqueTypeId::VariantPart(enum_ty, private::HiddenZst) } @@ -63,7 +66,10 @@ impl<'tcx> UniqueTypeId<'tcx> { enum_ty: Ty<'tcx>, variant_idx: VariantIdx, ) -> Self { - assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty)); + assert_eq!( + enum_ty, + tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), enum_ty) + ); UniqueTypeId::VariantStructType(enum_ty, variant_idx, private::HiddenZst) } @@ -72,7 +78,10 @@ impl<'tcx> UniqueTypeId<'tcx> { enum_ty: Ty<'tcx>, variant_idx: VariantIdx, ) -> Self { - assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty)); + assert_eq!( + enum_ty, + tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), enum_ty) + ); UniqueTypeId::VariantStructTypeCppLikeWrapper(enum_ty, variant_idx, private::HiddenZst) } @@ -81,10 +90,13 @@ impl<'tcx> UniqueTypeId<'tcx> { self_type: Ty<'tcx>, implemented_trait: Option<PolyExistentialTraitRef<'tcx>>, ) -> Self { - assert_eq!(self_type, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), self_type)); + assert_eq!( + self_type, + tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), self_type) + ); assert_eq!( implemented_trait, - tcx.normalize_erasing_regions(ParamEnv::reveal_all(), implemented_trait) + tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), implemented_trait) ); UniqueTypeId::VTableTy(self_type, implemented_trait, private::HiddenZst) } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 89492e4b9fe..a8fdfbed592 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -15,8 +15,8 @@ use rustc_data_structures::unord::UnordMap; use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_index::IndexVec; use rustc_middle::mir; -use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, GenericArgsRef, Instance, ParamEnv, Ty, TypeVisitableExt}; +use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; +use rustc_middle::ty::{self, GenericArgsRef, Instance, Ty, TypeVisitableExt}; use rustc_session::Session; use rustc_session::config::{self, DebugInfo}; use rustc_span::symbol::Symbol; @@ -294,12 +294,12 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } // Initialize fn debug context (including scopes). - let empty_scope = DebugScope { + let empty_scope = Some(DebugScope { dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)), inlined_at: None, file_start_pos: BytePos(0), file_end_pos: BytePos(0), - }; + }); let mut fn_debug_context = FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes), inlined_function_scopes: Default::default(), @@ -344,7 +344,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { type_names::push_generic_params( tcx, - tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args), + tcx.normalize_erasing_regions(self.typing_env(), args), &mut name, ); @@ -481,8 +481,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { iter::zip(args, names) .filter_map(|(kind, name)| { kind.as_type().map(|ty| { - let actual_type = - cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); + let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); let actual_type_metadata = type_di_node(cx, actual_type); let name = name.as_str(); unsafe { @@ -526,7 +525,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { if cx.tcx.trait_id_of_impl(impl_def_id).is_none() { let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions( instance.args, - ty::ParamEnv::reveal_all(), + cx.typing_env(), cx.tcx.type_of(impl_def_id), ); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index 960487ada16..6e841293477 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -1,7 +1,7 @@ // Utility Functions. use rustc_hir::def_id::DefId; -use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; +use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Ty}; use tracing::trace; @@ -62,7 +62,7 @@ pub(crate) fn wide_pointer_kind<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, pointee_ty: Ty<'tcx>, ) -> Option<WidePtrKind> { - let pointee_tail_ty = cx.tcx.struct_tail_for_codegen(pointee_ty, cx.param_env()); + let pointee_tail_ty = cx.tcx.struct_tail_for_codegen(pointee_ty, cx.typing_env()); let layout = cx.layout_of(pointee_tail_ty); trace!( "wide_pointer_kind: {:?} has layout {:?} (is_unsized? {})", diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e9c687d75e3..da7f94e8cf7 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -10,7 +10,7 @@ use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::*; use rustc_hir as hir; use rustc_middle::mir::BinOp; -use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf}; +use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, GenericArgsRef, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; @@ -163,14 +163,14 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { span: Span, ) -> Result<(), ty::Instance<'tcx>> { let tcx = self.tcx; - let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); + let callee_ty = instance.ty(tcx, self.typing_env()); let ty::FnDef(def_id, fn_args) = *callee_ty.kind() else { bug!("expected fn item type, found {}", callee_ty); }; let sig = callee_ty.fn_sig(tcx); - let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); + let sig = tcx.normalize_erasing_late_bound_regions(self.typing_env(), sig); let arg_tys = sig.inputs(); let ret_ty = sig.output(); let name = tcx.item_name(def_id); @@ -192,7 +192,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { Some(instance), ) } - sym::likely => self.expect(args[0].immediate(), true), sym::is_val_statically_known => { let intrinsic_type = args[0].layout.immediate_llvm_type(self.cx); let kind = self.type_kind(intrinsic_type); @@ -213,7 +212,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { self.const_bool(false) } } - sym::unlikely => self.expect(args[0].immediate(), false), sym::select_unpredictable => { let cond = args[0].immediate(); assert_eq!(args[1].layout, args[2].layout); @@ -1154,8 +1152,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } let tcx = bx.tcx(); - let sig = - tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx)); + let sig = tcx.normalize_erasing_late_bound_regions(bx.typing_env(), callee_ty.fn_sig(tcx)); let arg_tys = sig.inputs(); // Sanity-check: all vector arguments must be immediates. @@ -2189,7 +2186,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( match in_elem.kind() { ty::RawPtr(p_ty, _) => { let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { - bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) + bx.tcx.normalize_erasing_regions(bx.typing_env(), ty) }); require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer { span, @@ -2204,7 +2201,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( match out_elem.kind() { ty::RawPtr(p_ty, _) => { let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { - bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) + bx.tcx.normalize_erasing_regions(bx.typing_env(), ty) }); require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer { span, diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index ea8857b4739..33789c6261f 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -3,7 +3,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::bug; use rustc_middle::mir::mono::{Linkage, Visibility}; -use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; +use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use rustc_session::config::CrateType; use rustc_target::spec::RelocModel; @@ -26,11 +26,8 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() }; // Nested statics do not have a type, so pick a dummy type and let `codegen_static` figure // out the llvm type from the actual evaluated initializer. - let ty = if nested { - self.tcx.types.unit - } else { - instance.ty(self.tcx, ty::ParamEnv::reveal_all()) - }; + let ty = + if nested { self.tcx.types.unit } else { instance.ty(self.tcx, self.typing_env()) }; let llty = self.layout_of(ty).llvm_type(self); let g = self.define_global(symbol_name, llty).unwrap_or_else(|| { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 4f3664a503d..6ee599c9964 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1279,7 +1279,7 @@ impl<'a> WasmLd<'a> { let mut wasm_ld = WasmLd { cmd, sess }; if sess.target_features.contains(&sym::atomics) { wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]); - if sess.target.os == "unknown" { + if sess.target.os == "unknown" || sess.target.os == "none" { wasm_ld.link_args(&[ "--export=__wasm_init_tls", "--export=__tls_size", @@ -1403,7 +1403,7 @@ impl<'a> Linker for WasmLd<'a> { // symbols explicitly passed via the `--export` flags above and hides all // others. Various bits and pieces of wasm32-unknown-unknown tooling use // this, so be sure these symbols make their way out of the linker as well. - if self.sess.target.os == "unknown" { + if self.sess.target.os == "unknown" || self.sess.target.os == "none" { self.link_args(&["--export=__heap_base", "--export=__data_end"]); } } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 850d36872dd..d9152c5d080 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -595,8 +595,10 @@ pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>( let (conv, args) = instance .map(|i| { - tcx.fn_abi_of_instance(ty::ParamEnv::reveal_all().and((i, ty::List::empty()))) - .unwrap_or_else(|_| bug!("fn_abi_of_instance({i:?}) failed")) + tcx.fn_abi_of_instance( + ty::TypingEnv::fully_monomorphized().as_query_input((i, ty::List::empty())), + ) + .unwrap_or_else(|_| bug!("fn_abi_of_instance({i:?}) failed")) }) .map(|fnabi| (fnabi.conv, &fnabi.args[..])) .unwrap_or((Conv::Rust, &[])); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index ef95ab94062..27c9cb0b31e 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -21,8 +21,8 @@ use rustc_middle::middle::{exported_symbols, lang_items}; use rustc_middle::mir::BinOp; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; use rustc_middle::query::Providers; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::Session; use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; use rustc_span::symbol::sym; @@ -119,7 +119,8 @@ pub fn validate_trivial_unsize<'tcx>( ) -> bool { match (source_data.principal(), target_data.principal()) { (Some(hr_source_principal), Some(hr_target_principal)) => { - let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); + let (infcx, param_env) = + tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized()); let universe = infcx.universe(); let ocx = ObligationCtxt::new(&infcx); infcx.enter_forall(hr_target_principal, |target_principal| { @@ -130,7 +131,7 @@ pub fn validate_trivial_unsize<'tcx>( ); let Ok(()) = ocx.eq_trace( &ObligationCause::dummy(), - ty::ParamEnv::reveal_all(), + param_env, ToTrace::to_trace( &ObligationCause::dummy(), hr_target_principal, @@ -165,7 +166,7 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ) -> Bx::Value { let cx = bx.cx(); let (source, target) = - cx.tcx().struct_lockstep_tails_for_codegen(source, target, bx.param_env()); + cx.tcx().struct_lockstep_tails_for_codegen(source, target, bx.typing_env()); match (source.kind(), target.kind()) { (&ty::Array(_, len), &ty::Slice(_)) => cx.const_usize( len.try_to_target_usize(cx.tcx()).expect("expected monomorphic const in codegen"), @@ -466,10 +467,9 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // late-bound regions, since late-bound // regions must appear in the argument // listing. - let main_ret_ty = cx.tcx().normalize_erasing_regions( - ty::ParamEnv::reveal_all(), - main_ret_ty.no_bound_vars().unwrap(), - ); + let main_ret_ty = cx + .tcx() + .normalize_erasing_regions(cx.typing_env(), main_ret_ty.no_bound_vars().unwrap()); let Some(llfn) = cx.declare_c_main(llfty) else { // FIXME: We should be smart and show a better diagnostic here. @@ -495,7 +495,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None); let start_instance = ty::Instance::expect_resolve( cx.tcx(), - ty::ParamEnv::reveal_all(), + cx.typing_env(), start_def_id, cx.tcx().mk_args(&[main_ret_ty.into()]), DUMMY_SP, diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 27bc58516c0..6c4f6d37972 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -21,9 +21,7 @@ use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathD use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Mutability}; use rustc_middle::bug; use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; -use rustc_middle::ty::{ - self, ExistentialProjection, GenericArgKind, GenericArgsRef, ParamEnv, Ty, TyCtxt, -}; +use rustc_middle::ty::{self, ExistentialProjection, GenericArgKind, GenericArgsRef, Ty, TyCtxt}; use smallvec::SmallVec; use crate::debuginfo::wants_c_like_enum_debuginfo; @@ -82,7 +80,7 @@ fn push_debuginfo_type_name<'tcx>( ty::Adt(def, args) => { // `layout_for_cpp_like_fallback` will be `Some` if we want to use the fallback encoding. let layout_for_cpp_like_fallback = if cpp_like_debuginfo && def.is_enum() { - match tcx.layout_of(ParamEnv::reveal_all().and(t)) { + match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(t)) { Ok(layout) => { if !wants_c_like_enum_debuginfo(tcx, layout) { Some(layout) @@ -248,8 +246,10 @@ fn push_debuginfo_type_name<'tcx>( }; if let Some(principal) = trait_data.principal() { - let principal = - tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal); + let principal = tcx.normalize_erasing_late_bound_regions( + ty::TypingEnv::fully_monomorphized(), + principal, + ); push_item_name(tcx, principal.def_id, qualified, output); let principal_has_generic_params = push_generic_params_internal(tcx, principal.args, output, visited); @@ -350,8 +350,10 @@ fn push_debuginfo_type_name<'tcx>( return; } - let sig = - tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), t.fn_sig(tcx)); + let sig = tcx.normalize_erasing_late_bound_regions( + ty::TypingEnv::fully_monomorphized(), + t.fn_sig(tcx), + ); if cpp_like_debuginfo { // Format as a C++ function pointer: return_type (*)(params...) @@ -415,7 +417,8 @@ fn push_debuginfo_type_name<'tcx>( // In the case of cpp-like debuginfo, the name additionally gets wrapped inside of // an artificial `enum2$<>` type, as defined in msvc_enum_fallback(). if cpp_like_debuginfo && t.is_coroutine() { - let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap(); + let ty_and_layout = + tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(t)).unwrap(); msvc_enum_fallback( tcx, ty_and_layout, @@ -529,8 +532,8 @@ pub fn compute_debuginfo_vtable_name<'tcx>( } if let Some(trait_ref) = trait_ref { - let trait_ref = - tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref); + let trait_ref = tcx + .normalize_erasing_late_bound_regions(ty::TypingEnv::fully_monomorphized(), trait_ref); push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name); visited.clear(); push_generic_params_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited); @@ -639,7 +642,7 @@ fn push_generic_params_internal<'tcx>( output: &mut String, visited: &mut FxHashSet<Ty<'tcx>>, ) -> bool { - assert_eq!(args, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args)); + assert_eq!(args, tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), args)); let mut args = args.non_erasable_generics().peekable(); if args.peek().is_none() { return false; @@ -678,14 +681,14 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S // FIXME: directly extract the bits from a valtree instead of evaluating an // already evaluated `Const` in order to get the bits. let bits = ct - .try_to_bits(tcx, ty::ParamEnv::reveal_all()) + .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected monomorphic const in codegen"); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; write!(output, "{val}") } ty::Uint(_) => { let val = ct - .try_to_bits(tcx, ty::ParamEnv::reveal_all()) + .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected monomorphic const in codegen"); write!(output, "{val}") } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 027d80350e4..e3ed12b5ce6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -377,20 +377,32 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // If there are two targets (one conditional, one fallback), emit `br` instead of // `switch`. let (test_value, target) = target_iter.next().unwrap(); - let lltrue = helper.llbb_with_cleanup(self, target); - let llfalse = helper.llbb_with_cleanup(self, targets.otherwise()); + let otherwise = targets.otherwise(); + let lltarget = helper.llbb_with_cleanup(self, target); + let llotherwise = helper.llbb_with_cleanup(self, otherwise); + let target_cold = self.cold_blocks[target]; + let otherwise_cold = self.cold_blocks[otherwise]; + // If `target_cold == otherwise_cold`, the branches have the same weight + // so there is no expectation. If they differ, the `target` branch is expected + // when the `otherwise` branch is cold. + let expect = if target_cold == otherwise_cold { None } else { Some(otherwise_cold) }; if switch_ty == bx.tcx().types.bool { // Don't generate trivial icmps when switching on bool. match test_value { - 0 => bx.cond_br(discr_value, llfalse, lltrue), - 1 => bx.cond_br(discr_value, lltrue, llfalse), + 0 => { + let expect = expect.map(|e| !e); + bx.cond_br_with_expect(discr_value, llotherwise, lltarget, expect); + } + 1 => { + bx.cond_br_with_expect(discr_value, lltarget, llotherwise, expect); + } _ => bug!(), } } else { let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty)); let llval = bx.const_uint_big(switch_llty, test_value); let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval); - bx.cond_br(cmp, lltrue, llfalse); + bx.cond_br_with_expect(cmp, lltarget, llotherwise, expect); } } else if self.cx.sess().opts.optimize == OptLevel::No && target_iter.len() == 2 @@ -765,7 +777,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let do_panic = !bx .tcx() - .check_validity_requirement((requirement, bx.param_env().and(ty))) + .check_validity_requirement((requirement, bx.typing_env().as_query_input(ty))) .expect("expect to have layout during codegen"); let layout = bx.layout_of(ty); @@ -836,14 +848,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (instance, mut llfn) = match *callee.layout.ty.kind() { ty::FnDef(def_id, args) => ( Some( - ty::Instance::expect_resolve( - bx.tcx(), - ty::ParamEnv::reveal_all(), - def_id, - args, - fn_span, - ) - .polymorphize(bx.tcx()), + ty::Instance::expect_resolve(bx.tcx(), bx.typing_env(), def_id, args, fn_span) + .polymorphize(bx.tcx()), ), None, ), @@ -1179,7 +1185,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if let ty::FnDef(def_id, args) = *const_.ty().kind() { let instance = ty::Instance::resolve_for_fn_ptr( bx.tcx(), - ty::ParamEnv::reveal_all(), + bx.typing_env(), def_id, args, ) diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 54b9c9cc89f..7676e1e171a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -1,6 +1,6 @@ use rustc_abi::BackendRepr; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::ty::layout::HasTyCtxt; +use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv}; use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, mir, span_bug}; @@ -24,7 +24,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // `MirUsedCollector` visited all required_consts before codegen began, so if we got here // there can be no more constants that fail to evaluate. self.monomorphize(constant.const_) - .eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), constant.span) + .eval(self.cx.tcx(), self.cx.typing_env(), constant.span) .expect("erroneous constant missed by mono item collection") } @@ -57,7 +57,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { other => span_bug!(constant.span, "{other:#?}"), }; let uv = self.monomorphize(uv); - self.cx.tcx().const_eval_resolve_for_typeck(ty::ParamEnv::reveal_all(), uv, constant.span) + self.cx.tcx().const_eval_resolve_for_typeck(self.cx.typing_env(), uv, constant.span) } /// process constant containing SIMD shuffle indices & constant vectors diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 21d20475408..d4d7f16db55 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -20,7 +20,9 @@ use crate::traits::*; pub struct FunctionDebugContext<'tcx, S, L> { /// Maps from source code to the corresponding debug info scope. - pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>, + /// May be None if the backend is not capable of representing the scope for + /// some reason. + pub scopes: IndexVec<mir::SourceScope, Option<DebugScope<S, L>>>, /// Maps from an inlined function to its debug info declaration. pub inlined_function_scopes: FxHashMap<Instance<'tcx>, S>, @@ -231,7 +233,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &self, source_info: mir::SourceInfo, ) -> Option<(Bx::DIScope, Option<Bx::DILocation>, Span)> { - let scope = &self.debug_context.as_ref()?.scopes[source_info.scope]; + let scope = &self.debug_context.as_ref()?.scopes[source_info.scope]?; let span = hygiene::walk_chain_collapsed(source_info.span, self.mir.span); Some((scope.adjust_dbg_scope_for_span(self.cx, span), scope.inlined_at, span)) } diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index c9e38bb80c2..299b98c0a4f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -59,14 +59,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { llresult: Bx::Value, span: Span, ) -> Result<(), ty::Instance<'tcx>> { - let callee_ty = instance.ty(bx.tcx(), ty::ParamEnv::reveal_all()); + let callee_ty = instance.ty(bx.tcx(), bx.typing_env()); let ty::FnDef(def_id, fn_args) = *callee_ty.kind() else { bug!("expected fn item type, found {}", callee_ty); }; let sig = callee_ty.fn_sig(bx.tcx()); - let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); + let sig = bx.tcx().normalize_erasing_late_bound_regions(bx.typing_env(), sig); let arg_tys = sig.inputs(); let ret_ty = sig.output(); let name = bx.tcx().item_name(def_id); @@ -146,10 +146,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { | sym::type_id | sym::type_name | sym::variant_count => { - let value = bx - .tcx() - .const_eval_instance(ty::ParamEnv::reveal_all(), instance, span) - .unwrap(); + let value = bx.tcx().const_eval_instance(bx.typing_env(), instance, span).unwrap(); OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx) } sym::arith_offset => { @@ -498,6 +495,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + sym::cold_path => { + // This is a no-op. The intrinsic is just a hint to the optimizer. + return Ok(()); + } + _ => { // Need to use backend-specific things in the implementation. return bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 20fd08923ec..0cbc5c45736 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -4,7 +4,7 @@ use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::{UnwindTerminateReason, traversal}; -use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout}; +use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_middle::{bug, mir, span_bug}; use rustc_target::callconv::{FnAbi, PassMode}; @@ -91,6 +91,10 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { /// Cached terminate upon unwinding block and its reason terminate_block: Option<(Bx::BasicBlock, UnwindTerminateReason)>, + /// A bool flag for each basic block indicating whether it is a cold block. + /// A cold block is a block that is unlikely to be executed at runtime. + cold_blocks: IndexVec<mir::BasicBlock, bool>, + /// The location where each MIR arg/var/tmp/ret is stored. This is /// usually an `PlaceRef` representing an alloca, but not always: /// sometimes we can skip the alloca and just store the value @@ -124,7 +128,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { debug!("monomorphize: self.instance={:?}", self.instance); self.instance.instantiate_mir_and_normalize_erasing_regions( self.cx.tcx(), - ty::ParamEnv::reveal_all(), + self.cx.typing_env(), ty::EarlyBinder::bind(value), ) } @@ -207,6 +211,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cleanup_kinds, landing_pads: IndexVec::from_elem(None, &mir.basic_blocks), funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()), + cold_blocks: find_cold_blocks(cx.tcx(), mir), locals: locals::Locals::empty(), debug_context, per_local_var_debug_info: None, @@ -477,3 +482,39 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( args } + +fn find_cold_blocks<'tcx>( + tcx: TyCtxt<'tcx>, + mir: &mir::Body<'tcx>, +) -> IndexVec<mir::BasicBlock, bool> { + let local_decls = &mir.local_decls; + + let mut cold_blocks: IndexVec<mir::BasicBlock, bool> = + IndexVec::from_elem(false, &mir.basic_blocks); + + // Traverse all basic blocks from end of the function to the start. + for (bb, bb_data) in traversal::postorder(mir) { + let terminator = bb_data.terminator(); + + // If a BB ends with a call to a cold function, mark it as cold. + if let mir::TerminatorKind::Call { ref func, .. } = terminator.kind + && let ty::FnDef(def_id, ..) = *func.ty(local_decls, tcx).kind() + && let attrs = tcx.codegen_fn_attrs(def_id) + && attrs.flags.contains(CodegenFnAttrFlags::COLD) + { + cold_blocks[bb] = true; + continue; + } + + // If all successors of a BB are cold and there's at least one of them, mark this BB as cold + let mut succ = terminator.successors(); + if let Some(first) = succ.next() + && cold_blocks[first] + && succ.all(|s| cold_blocks[s]) + { + cold_blocks[bb] = true; + } + } + + cold_blocks +} diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 0e1cd662f91..f63b2d139c5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -474,7 +474,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ty::FnDef(def_id, args) => { let instance = ty::Instance::resolve_for_fn_ptr( bx.tcx(), - ty::ParamEnv::reveal_all(), + bx.typing_env(), def_id, args, ) @@ -709,7 +709,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::NullOp::OffsetOf(fields) => { let val = bx .tcx() - .offset_of_subfield(bx.param_env(), layout, fields.iter()) + .offset_of_subfield(bx.typing_env(), layout, fields.iter()) .bytes(); bx.cx().const_usize(val) } @@ -727,7 +727,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::ThreadLocalRef(def_id) => { assert!(bx.cx().tcx().is_static(def_id)); - let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id)); + let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id, bx.typing_env())); let static_ = if !def_id.is_local() && bx.cx().tcx().needs_thread_local_shim(def_id) { let instance = ty::Instance { diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 1681ea1de5f..cd55a838a75 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -92,6 +92,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { | mir::StatementKind::AscribeUserType(..) | mir::StatementKind::ConstEvalCounter | mir::StatementKind::PlaceMention(..) + | mir::StatementKind::BackwardIncompatibleDropHint { .. } | mir::StatementKind::Nop => {} } } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 74cd522a30f..b0138ac8bfe 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -84,6 +84,26 @@ pub trait BuilderMethods<'a, 'tcx>: then_llbb: Self::BasicBlock, else_llbb: Self::BasicBlock, ); + + // Conditional with expectation. + // + // This function is opt-in for back ends. + // + // The default implementation calls `self.expect()` before emiting the branch + // by calling `self.cond_br()` + fn cond_br_with_expect( + &mut self, + mut cond: Self::Value, + then_llbb: Self::BasicBlock, + else_llbb: Self::BasicBlock, + expect: Option<bool>, + ) { + if let Some(expect) = expect { + cond = self.expect(cond, expect); + } + self.cond_br(cond, then_llbb, else_llbb) + } + fn switch( &mut self, v: Self::Value, diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 44ba2262149..6292d321f6b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -1,6 +1,6 @@ use rustc_abi::{AddressSpace, Float, Integer}; use rustc_middle::bug; -use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; +use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, TyAndLayout}; use rustc_middle::ty::{self, Ty}; use rustc_target::callconv::{ArgAbi, CastTarget, FnAbi, Reg}; @@ -41,7 +41,7 @@ pub trait BaseTypeCodegenMethods<'tcx>: BackendTypes { } pub trait DerivedTypeCodegenMethods<'tcx>: - BaseTypeCodegenMethods<'tcx> + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + BaseTypeCodegenMethods<'tcx> + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> { fn type_int(&self) -> Self::Type { match &self.sess().target.c_int_width[..] { @@ -74,24 +74,23 @@ pub trait DerivedTypeCodegenMethods<'tcx>: } fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { - ty.needs_drop(self.tcx(), ty::ParamEnv::reveal_all()) + ty.needs_drop(self.tcx(), self.typing_env()) } fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - ty.is_sized(self.tcx(), ty::ParamEnv::reveal_all()) + ty.is_sized(self.tcx(), self.typing_env()) } fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(self.tcx(), ty::ParamEnv::reveal_all()) + ty.is_freeze(self.tcx(), self.typing_env()) } fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { - let param_env = ty::ParamEnv::reveal_all(); - if ty.is_sized(self.tcx(), param_env) { + if ty.is_sized(self.tcx(), self.typing_env()) { return false; } - let tail = self.tcx().struct_tail_for_codegen(ty, param_env); + let tail = self.tcx().struct_tail_for_codegen(ty, self.typing_env()); match tail.kind() { ty::Foreign(..) => false, ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, @@ -101,7 +100,10 @@ pub trait DerivedTypeCodegenMethods<'tcx>: } impl<'tcx, T> DerivedTypeCodegenMethods<'tcx> for T where - Self: BaseTypeCodegenMethods<'tcx> + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + Self: BaseTypeCodegenMethods<'tcx> + + MiscCodegenMethods<'tcx> + + HasTyCtxt<'tcx> + + HasTypingEnv<'tcx> { } diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 15027ae0c18..f93f4d36e45 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -403,7 +403,7 @@ const_eval_uninhabited_enum_variant_written = const_eval_unmarked_const_fn_exposed = `{$def_path}` cannot be (indirectly) exposed to stable .help = either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` const_eval_unmarked_intrinsic_exposed = intrinsic `{$def_path}` cannot be (indirectly) exposed to stable - .help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) + .help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_intrinsic_const_stable_indirect]` (but this requires team approval) const_eval_unreachable = entering unreachable code const_eval_unreachable_unwind = diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index c3efca28c68..1129b5caec5 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -272,9 +272,18 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { /// context. pub fn check_op_spanned<O: NonConstOp<'tcx>>(&mut self, op: O, span: Span) { let gate = match op.status_in_item(self.ccx) { - Status::Unstable { gate, safe_to_expose_on_stable, is_function_call } - if self.tcx.features().enabled(gate) => - { + Status::Unstable { + gate, + safe_to_expose_on_stable, + is_function_call, + gate_already_checked, + } if gate_already_checked || self.tcx.features().enabled(gate) => { + if gate_already_checked { + assert!( + !safe_to_expose_on_stable, + "setting `gate_already_checked` without `safe_to_expose_on_stable` makes no sense" + ); + } // Generally this is allowed since the feature gate is enabled -- except // if this function wants to be safe-to-expose-on-stable. if !safe_to_expose_on_stable @@ -379,7 +388,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { return false; } - let infcx = tcx.infer_ctxt().build(self.body.typing_mode(tcx)); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(self.body.typing_env(tcx)); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let body_id = self.body.source.def_id().expect_local(); @@ -389,11 +398,8 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { ty::BoundConstness::Const } }; - let const_conditions = ocx.normalize( - &ObligationCause::misc(call_span, body_id), - self.param_env, - const_conditions, - ); + let const_conditions = + ocx.normalize(&ObligationCause::misc(call_span, body_id), param_env, const_conditions); ocx.register_obligations(const_conditions.into_iter().map(|(trait_ref, span)| { Obligation::new( tcx, @@ -402,7 +408,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { body_id, ObligationCauseCode::WhereClause(callee, span), ), - self.param_env, + param_env, trait_ref.to_host_effect_clause(tcx, host_polarity), ) })); @@ -603,6 +609,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | StatementKind::Coverage(..) | StatementKind::Intrinsic(..) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} } } @@ -745,13 +752,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { self.check_op(ops::IntrinsicUnstable { name: intrinsic.name, feature, - const_stable: is_const_stable, + const_stable_indirect: is_const_stable, }); } Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { // All good. Note that a `#[rustc_const_stable]` intrinsic (meaning it // can be *directly* invoked from stable const code) does not always - // have the `#[rustc_const_stable_intrinsic]` attribute (which controls + // have the `#[rustc_intrinsic_const_stable_indirect]` attribute (which controls // exposing an intrinsic indirectly); we accept this call anyway. } } @@ -800,6 +807,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if // the callee is safe to expose, to avoid bypassing recursive stability. + // This is not ideal since it means the user sees an error, not the macro + // author, but that's also the case if one forgets to set + // `#[allow_internal_unstable]` in the first place. Note that this cannot be + // integrated in the check below since we want to enforce + // `callee_safe_to_expose_on_stable` even if + // `!self.enforce_recursive_const_stability()`. if (self.span.allows_unstable(feature) || implied_feature.is_some_and(|f| self.span.allows_unstable(f))) && callee_safe_to_expose_on_stable @@ -830,15 +843,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { && issue == NonZero::new(27812) && self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked }; - // We do *not* honor this if we are in the "danger zone": we have to enforce - // recursive const-stability and the callee is not safe-to-expose. In that - // case we need `check_op` to do the check. - let danger_zone = !callee_safe_to_expose_on_stable - && self.enforce_recursive_const_stability(); - if danger_zone || !feature_enabled { + // Even if the feature is enabled, we still need check_op to double-check + // this if the callee is not safe to expose on stable. + if !feature_enabled || !callee_safe_to_expose_on_stable { self.check_op(ops::FnCallUnstable { def_id: callee, feature, + feature_enabled, safe_to_expose_on_stable: callee_safe_to_expose_on_stable, }); } diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index ebdd55a4f70..80d3c6448aa 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -24,17 +24,15 @@ mod resolver; pub struct ConstCx<'mir, 'tcx> { pub body: &'mir mir::Body<'tcx>, pub tcx: TyCtxt<'tcx>, - pub param_env: ty::ParamEnv<'tcx>, + pub typing_env: ty::TypingEnv<'tcx>, pub const_kind: Option<hir::ConstContext>, } impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self { - let def_id = body.source.def_id().expect_local(); - let param_env = tcx.param_env(def_id); - + let typing_env = body.typing_env(tcx); let const_kind = tcx.hir().body_const_context(body.source.def_id().expect_local()); - ConstCx { body, tcx, param_env, const_kind } + ConstCx { body, tcx, typing_env, const_kind } } pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> { diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 036ca763280..8ba6b89aad4 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -28,6 +28,9 @@ pub enum Status { Unstable { /// The feature that must be enabled to use this operation. gate: Symbol, + /// Whether the feature gate was already checked (because the logic is a bit more + /// complicated than just checking a single gate). + gate_already_checked: bool, /// Whether it is allowed to use this operation from stable `const fn`. /// This will usually be `false`. safe_to_expose_on_stable: bool, @@ -82,6 +85,7 @@ impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> { // We use the `const_trait_impl` gate for all conditionally-const calls. Status::Unstable { gate: sym::const_trait_impl, + gate_already_checked: false, safe_to_expose_on_stable: false, // We don't want the "mark the callee as `#[rustc_const_stable_indirect]`" hint is_function_call: false, @@ -116,7 +120,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { #[allow(rustc::untranslatable_diagnostic)] fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> { let FnCallNonConst { callee, args, span, call_source } = *self; - let ConstCx { tcx, param_env, .. } = *ccx; + let ConstCx { tcx, typing_env, .. } = *ccx; let caller = ccx.def_id(); let diag_trait = |err, self_ty: Ty<'_>, trait_id| { @@ -142,13 +146,11 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { } } ty::Adt(..) => { + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref); - - let infcx = tcx.infer_ctxt().build(ccx.body.typing_mode(tcx)); let mut selcx = SelectionContext::new(&infcx); let implsrc = selcx.select(&obligation); - if let Ok(Some(ImplSource::UserDefined(data))) = implsrc { // FIXME(const_trait_impl) revisit this if !tcx.is_const_trait_impl(data.impl_def_id) { @@ -162,7 +164,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { }; let call_kind = - call_kind(tcx, ccx.param_env, callee, args, span, call_source.from_hir_call(), None); + call_kind(tcx, ccx.typing_env, callee, args, span, call_source.from_hir_call(), None); debug!(?call_kind); @@ -330,6 +332,9 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { pub(crate) struct FnCallUnstable { pub def_id: DefId, pub feature: Symbol, + /// If this is true, then the feature is enabled, but we need to still check if it is safe to + /// expose on stable. + pub feature_enabled: bool, pub safe_to_expose_on_stable: bool, } @@ -337,12 +342,14 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { Status::Unstable { gate: self.feature, + gate_already_checked: self.feature_enabled, safe_to_expose_on_stable: self.safe_to_expose_on_stable, is_function_call: true, } } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { + assert!(!self.feature_enabled); let mut err = ccx.dcx().create_err(errors::UnstableConstFn { span, def_path: ccx.tcx.def_path_str(self.def_id), @@ -376,14 +383,15 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst { pub(crate) struct IntrinsicUnstable { pub name: Symbol, pub feature: Symbol, - pub const_stable: bool, + pub const_stable_indirect: bool, } impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable { fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { Status::Unstable { gate: self.feature, - safe_to_expose_on_stable: self.const_stable, + gate_already_checked: false, + safe_to_expose_on_stable: self.const_stable_indirect, // We do *not* want to suggest to mark the intrinsic as `const_stable_indirect`, // that's not a trivial change! is_function_call: false, @@ -410,6 +418,7 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine { { Status::Unstable { gate: sym::const_async_blocks, + gate_already_checked: false, safe_to_expose_on_stable: false, is_function_call: false, } diff --git a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs index 0173a528c22..f6eb130fbd3 100644 --- a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs @@ -32,17 +32,15 @@ pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool { /// This is separate from the rest of the const checking logic because it must run after drop /// elaboration. pub fn check_live_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) { - let def_id = body.source.def_id().expect_local(); - let const_kind = tcx.hir().body_const_context(def_id); - if const_kind.is_none() { + let ccx = ConstCx::new(tcx, body); + if ccx.const_kind.is_none() { return; } - if tcx.has_attr(def_id, sym::rustc_do_not_const_check) { + if tcx.has_attr(body.source.def_id(), sym::rustc_do_not_const_check) { return; } - let ccx = ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def_id) }; if !checking_enabled(&ccx) { return; } diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 29a08579175..bc416acc58d 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -106,20 +106,24 @@ impl Qualif for HasMutInterior { // Instead we invoke an obligation context manually, and provide the opaque type inference settings // that allow the trait solver to just error out instead of cycling. let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, Some(cx.body.span)); - + // FIXME(#132279): Once we've got a typing mode which reveals opaque types using the HIR + // typeck results without causing query cycles, we should use this here instead of defining + // opaque types. + let typing_env = ty::TypingEnv { + typing_mode: ty::TypingMode::analysis_in_body( + cx.tcx, + cx.body.source.def_id().expect_local(), + ), + param_env: cx.typing_env.param_env, + }; + let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(typing_env); + let ocx = ObligationCtxt::new(&infcx); let obligation = Obligation::new( cx.tcx, ObligationCause::dummy_with_span(cx.body.span), - cx.param_env, + param_env, ty::TraitRef::new(cx.tcx, freeze_def_id, [ty::GenericArg::from(ty)]), ); - - // FIXME(#132279): This should eventually use the already defined hidden types. - let infcx = cx.tcx.infer_ctxt().build(ty::TypingMode::analysis_in_body( - cx.tcx, - cx.body.source.def_id().expect_local(), - )); - let ocx = ObligationCtxt::new(&infcx); ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); !errors.is_empty() @@ -156,7 +160,7 @@ impl Qualif for NeedsDrop { } fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.needs_drop(cx.tcx, cx.param_env) + ty.needs_drop(cx.tcx, cx.typing_env) } fn in_adt_inherently<'tcx>( diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index 74eb6b37fbb..0f9a460ca1b 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -120,7 +120,7 @@ where /// /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134 fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool { - !place.ty(self.ccx.body, self.ccx.tcx).ty.is_freeze(self.ccx.tcx, self.ccx.param_env) + !place.ty(self.ccx.body, self.ccx.tcx).ty.is_freeze(self.ccx.tcx, self.ccx.typing_env) } } 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/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index a430d9dc797..647d880e2bf 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -7,8 +7,7 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo}; use rustc_middle::mir::{self, ConstAlloc, ConstValue}; use rustc_middle::query::TyCtxtAt; -use rustc_middle::traits::Reveal; -use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; @@ -31,7 +30,6 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( cid: GlobalId<'tcx>, body: &'tcx mir::Body<'tcx>, ) -> InterpResult<'tcx, R> { - trace!(?ecx.param_env); let tcx = *ecx.tcx; assert!( cid.promoted.is_some() @@ -126,14 +124,14 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>( tcx: TyCtxt<'tcx>, root_span: Span, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, can_access_mut_global: CanAccessMutGlobal, ) -> CompileTimeInterpCx<'tcx> { - debug!("mk_eval_cx: {:?}", param_env); + debug!("mk_eval_cx: {:?}", typing_env); InterpCx::new( tcx, root_span, - param_env, + typing_env, CompileTimeMachine::new(can_access_mut_global, CheckAlignment::No), ) } @@ -142,11 +140,11 @@ pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>( /// Returns both the context and an `OpTy` that represents the constant. pub fn mk_eval_cx_for_const_val<'tcx>( tcx: TyCtxtAt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, val: mir::ConstValue<'tcx>, ty: Ty<'tcx>, ) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> { - let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No); + let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, typing_env, CanAccessMutGlobal::No); // FIXME: is it a problem to discard the error here? let op = ecx.const_val_to_op(val, ty, None).discard_err()?; Some((ecx, op)) @@ -221,7 +219,7 @@ pub(super) fn op_to_const<'tcx>( let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs debug_assert!( matches!( - ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.param_env).kind(), + ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env()).kind(), ty::Str | ty::Slice(..), ), "`ConstValue::Slice` is for slice-tailed types only, but got {}", @@ -245,7 +243,7 @@ pub(super) fn op_to_const<'tcx>( pub(crate) fn turn_into_const_value<'tcx>( tcx: TyCtxt<'tcx>, constant: ConstAlloc<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, + key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>, ) -> ConstValue<'tcx> { let cid = key.value; let def_id = cid.instance.def.def_id(); @@ -254,7 +252,7 @@ pub(crate) fn turn_into_const_value<'tcx>( let ecx = mk_eval_cx_to_read_const_val( tcx, tcx.def_span(key.value.instance.def_id()), - key.param_env, + key.typing_env, CanAccessMutGlobal::from(is_static), ); @@ -274,21 +272,16 @@ pub(crate) fn turn_into_const_value<'tcx>( #[instrument(skip(tcx), level = "debug")] pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, + key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { - // Const eval always happens in Reveal::All mode in order to be able to use the hidden types of - // opaque types. This is needed for trivial things like `size_of`, but also for using associated - // types that are not specified in the opaque type. - assert_eq!(key.param_env.reveal(), Reveal::All); - // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. // Catch such calls and evaluate them instead of trying to load a constant's MIR. if let ty::InstanceKind::Intrinsic(def_id) = key.value.instance.def { - let ty = key.value.instance.ty(tcx, key.param_env); + let ty = key.value.instance.ty(tcx, key.typing_env); let ty::FnDef(_, args) = ty.kind() else { bug!("intrinsic with type {:?}", ty); }; - return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).report_err().map_err( + return eval_nullary_intrinsic(tcx, key.typing_env, def_id, args).report_err().map_err( |error| { let span = tcx.def_span(def_id); @@ -315,7 +308,7 @@ pub fn eval_static_initializer_provider<'tcx>( let instance = ty::Instance::mono(tcx, def_id.to_def_id()); let cid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None }; - eval_in_interpreter(tcx, cid, ty::ParamEnv::reveal_all()) + eval_in_interpreter(tcx, cid, ty::TypingEnv::fully_monomorphized()) } pub trait InterpretationResult<'tcx> { @@ -340,16 +333,14 @@ impl<'tcx> InterpretationResult<'tcx> for ConstAlloc<'tcx> { #[instrument(skip(tcx), level = "debug")] pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, + key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { // This shouldn't be used for statics, since statics are conceptually places, // not values -- so what we do here could break pointer identity. assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id())); - // Const eval always happens in Reveal::All mode in order to be able to use the hidden types of - // opaque types. This is needed for trivial things like `size_of`, but also for using associated - // types that are not specified in the opaque type. - - assert_eq!(key.param_env.reveal(), Reveal::All); + // Const eval always happens in PostAnalysis mode . See the comment in + // `InterpCx::new` for more details. + debug_assert_eq!(key.typing_env.typing_mode, ty::TypingMode::PostAnalysis); if cfg!(debug_assertions) { // Make sure we format the instance even if we do not print it. // This serves as a regression test against an ICE on printing. @@ -360,13 +351,13 @@ pub fn eval_to_allocation_raw_provider<'tcx>( trace!("const eval: {:?} ({})", key, instance); } - eval_in_interpreter(tcx, key.value, key.param_env) + eval_in_interpreter(tcx, key.value, key.typing_env) } fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( tcx: TyCtxt<'tcx>, cid: GlobalId<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> Result<R, ErrorHandled> { let def = cid.instance.def.def_id(); let is_static = tcx.is_static(def); @@ -374,7 +365,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( let mut ecx = InterpCx::new( tcx, tcx.def_span(def), - param_env, + typing_env, // Statics (and promoteds inside statics) may access mutable global memory, because unlike consts // they do not have to behave "as if" they were evaluated at runtime. // For consts however we want to ensure they behave "as if" they were evaluated at runtime, diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 62115aef4a7..b27e3606f38 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem}; use rustc_middle::mir::AssertMessage; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::Span; @@ -249,9 +249,10 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) { // For panic_fmt, call const_panic_fmt instead. let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None); + // FIXME(@lcnr): why does this use an empty env if we've got a `param_env` right here. let new_instance = ty::Instance::expect_resolve( *self.tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), const_def_id, instance.args, self.cur_span(), @@ -263,6 +264,12 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { } /// See documentation on the `ptr_guaranteed_cmp` intrinsic. + /// Returns `2` if the result is unknown. + /// Returns `1` if the pointers are guaranteed equal. + /// Returns `0` if the pointers are guaranteed inequal. + /// + /// Note that this intrinsic is exposed on stable for comparison with null. In other words, any + /// change to this function that affects comparison with null is insta-stable! fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> { interp_ok(match (a, b) { // Comparisons between integers are always known. @@ -660,7 +667,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { .is_some_and(|p| !p.immutable()) { // That next check is expensive, that's why we have all the guards above. - let is_immutable = ty.is_freeze(*ecx.tcx, ecx.param_env); + let is_immutable = ty.is_freeze(*ecx.tcx, ecx.typing_env()); let place = ecx.ref_to_mplace(val)?; let new_place = if is_immutable { place.map_provenance(CtfeProvenance::as_immutable) diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index d5012236c34..8cbdcd68e13 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -38,8 +38,8 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( val: mir::ConstValue<'tcx>, ty: Ty<'tcx>, ) -> Option<mir::DestructuredConstant<'tcx>> { - let param_env = ty::ParamEnv::reveal_all(); - let (ecx, op) = mk_eval_cx_for_const_val(tcx, param_env, val, ty)?; + let typing_env = ty::TypingEnv::fully_monomorphized(); + let (ecx, op) = mk_eval_cx_for_const_val(tcx, typing_env, val, ty)?; // We go to `usize` as we cannot allocate anything bigger anyway. let (field_count, variant, down) = match ty.kind() { @@ -76,10 +76,12 @@ pub fn tag_for_variant_provider<'tcx>( ) -> Option<ty::ScalarInt> { assert!(ty.is_enum()); + // FIXME: This uses an empty `TypingEnv` even though + // it may be used by a generic CTFE. let ecx = InterpCx::new( tcx, ty.default_span(tcx), - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), crate::const_eval::DummyMachine, ); diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index ea88b2ed22e..515028e6826 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -228,16 +228,19 @@ fn create_valtree_place<'tcx>( /// Evaluates a constant and turns it into a type-level constant value. pub(crate) fn eval_to_valtree<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, cid: GlobalId<'tcx>, ) -> EvalToValTreeResult<'tcx> { - let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?; + // Const eval always happens in PostAnalysis mode . See the comment in + // `InterpCx::new` for more details. + debug_assert_eq!(typing_env.typing_mode, ty::TypingMode::PostAnalysis); + let const_alloc = tcx.eval_to_allocation_raw(typing_env.as_query_input(cid))?; // FIXME Need to provide a span to `eval_to_valtree` let ecx = mk_eval_cx_to_read_const_val( tcx, DUMMY_SP, - param_env, + typing_env, // It is absolutely crucial for soundness that // we do not read from mutable memory. CanAccessMutGlobal::No, @@ -272,7 +275,8 @@ pub(crate) fn eval_to_valtree<'tcx>( #[instrument(skip(tcx), level = "debug", ret)] pub fn valtree_to_const_value<'tcx>( tcx: TyCtxt<'tcx>, - param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, + typing_env: ty::TypingEnv<'tcx>, + ty: Ty<'tcx>, valtree: ty::ValTree<'tcx>, ) -> mir::ConstValue<'tcx> { // Basic idea: We directly construct `Scalar` values from trivial `ValTree`s @@ -281,9 +285,6 @@ pub fn valtree_to_const_value<'tcx>( // the `ValTree` and using `place_projection` and `place_field` to // create inner `MPlace`s which are filled recursively. // FIXME Does this need an example? - - let (param_env, ty) = param_env_ty.into_parts(); - match *ty.kind() { ty::FnDef(..) => { assert!(valtree.unwrap_branch().is_empty()); @@ -297,16 +298,17 @@ pub fn valtree_to_const_value<'tcx>( ), } } - ty::Pat(ty, _) => valtree_to_const_value(tcx, param_env.and(ty), valtree), + ty::Pat(ty, _) => valtree_to_const_value(tcx, typing_env, ty, valtree), ty::Ref(_, inner_ty, _) => { let mut ecx = - mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); + mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No); let imm = valtree_to_ref(&mut ecx, valtree, inner_ty); - let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap()); + let imm = + ImmTy::from_immediate(imm, tcx.layout_of(typing_env.as_query_input(ty)).unwrap()); op_to_const(&ecx, &imm.into(), /* for diagnostics */ false) } ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => { - let layout = tcx.layout_of(param_env_ty).unwrap(); + let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap(); if layout.is_zst() { // Fast path to avoid some allocations. return mir::ConstValue::ZeroSized; @@ -319,16 +321,16 @@ pub fn valtree_to_const_value<'tcx>( let branches = valtree.unwrap_branch(); // Find the non-ZST field. (There can be aligned ZST!) for (i, &inner_valtree) in branches.iter().enumerate() { - let field = layout.field(&LayoutCx::new(tcx, param_env), i); + let field = layout.field(&LayoutCx::new(tcx, typing_env), i); if !field.is_zst() { - return valtree_to_const_value(tcx, param_env.and(field.ty), inner_valtree); + return valtree_to_const_value(tcx, typing_env, field.ty, inner_valtree); } } bug!("could not find non-ZST field during in {layout:#?}"); } let mut ecx = - mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); + mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No); // Need to create a place for this valtree. let place = create_valtree_place(&mut ecx, layout, valtree); diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index ef0902e4226..ed4a1a9e647 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -215,7 +215,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Even if `ty` is normalized, the search for the unsized tail will project // to fields, which can yield non-normalized types. So we need to provide a // normalization function. - let normalize = |ty| self.tcx.normalize_erasing_regions(self.param_env, ty); + let normalize = |ty| self.tcx.normalize_erasing_regions(self.typing_env, ty); ty.ptr_metadata_ty(*self.tcx, normalize) }; return interp_ok(meta_ty(caller) == meta_ty(callee)); @@ -662,7 +662,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`. // (For that reason we also cannot use `unpack_dyn_trait`.) let receiver_tail = - self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.param_env); + self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.typing_env); let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else { span_bug!( self.cur_span(), @@ -704,7 +704,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let concrete_method = Instance::expect_resolve_for_vtable( tcx, - self.param_env, + self.typing_env, def_id, instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args), self.cur_span(), diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 49559059265..c95e51f0a1f 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -83,7 +83,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ty::FnDef(def_id, args) => { let instance = ty::Instance::resolve_for_fn_ptr( *self.tcx, - self.param_env, + self.typing_env, def_id, args, ) @@ -384,7 +384,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx> { // A<Struct> -> A<Trait> conversion let (src_pointee_ty, dest_pointee_ty) = - self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.param_env); + self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.typing_env); match (src_pointee_ty.kind(), dest_pointee_ty.kind()) { (&ty::Array(_, length), &ty::Slice(_)) => { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index ff6d5b28b3b..fe93a48c2f2 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1,18 +1,18 @@ +use std::assert_matches::debug_assert_matches; + use either::{Left, Right}; use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout}; use rustc_errors::DiagCtxtHandle; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::at::ToTrace; -use rustc_infer::traits::{ObligationCause, Reveal}; +use rustc_infer::traits::ObligationCause; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout, }; -use rustc_middle::ty::{ - self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypingMode, Variance, -}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance}; use rustc_middle::{mir, span_bug}; use rustc_session::Limit; use rustc_span::Span; @@ -38,8 +38,9 @@ pub struct InterpCx<'tcx, M: Machine<'tcx>> { /// we are evaluating (if this is CTFE). pub tcx: TyCtxtAt<'tcx>, - /// Bounds in scope for polymorphic evaluations. - pub(crate) param_env: ty::ParamEnv<'tcx>, + /// The current context in case we're evaluating in a + /// polymorphic context. This always uses `ty::TypingMode::PostAnalysis`. + pub(super) typing_env: ty::TypingEnv<'tcx>, /// The virtual memory system. pub memory: Memory<'tcx, M>, @@ -65,12 +66,12 @@ where } } -impl<'tcx, M> layout::HasParamEnv<'tcx> for InterpCx<'tcx, M> +impl<'tcx, M> layout::HasTypingEnv<'tcx> for InterpCx<'tcx, M> where M: Machine<'tcx>, { - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + self.typing_env } } @@ -116,8 +117,7 @@ impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { /// This test should be symmetric, as it is primarily about layout compatibility. pub(super) fn mir_assign_valid_types<'tcx>( tcx: TyCtxt<'tcx>, - typing_mode: TypingMode<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: TypingEnv<'tcx>, src: TyAndLayout<'tcx>, dest: TyAndLayout<'tcx>, ) -> bool { @@ -125,7 +125,7 @@ pub(super) fn mir_assign_valid_types<'tcx>( // all normal lifetimes are erased, higher-ranked types with their // late-bound lifetimes are still around and can lead to type // differences. - if util::relate_types(tcx, typing_mode, param_env, Variance::Covariant, src.ty, dest.ty) { + if util::relate_types(tcx, typing_env, Variance::Covariant, src.ty, dest.ty) { // Make sure the layout is equal, too -- just to be safe. Miri really // needs layout equality. For performance reason we skip this check when // the types are equal. Equal types *can* have different layouts when @@ -145,8 +145,7 @@ pub(super) fn mir_assign_valid_types<'tcx>( #[cfg_attr(not(debug_assertions), inline(always))] pub(super) fn from_known_layout<'tcx>( tcx: TyCtxtAt<'tcx>, - typing_mode: TypingMode<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: TypingEnv<'tcx>, known_layout: Option<TyAndLayout<'tcx>>, compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, TyAndLayout<'tcx>> { @@ -155,13 +154,7 @@ pub(super) fn from_known_layout<'tcx>( Some(known_layout) => { if cfg!(debug_assertions) { let check_layout = compute()?; - if !mir_assign_valid_types( - tcx.tcx, - typing_mode, - param_env, - check_layout, - known_layout, - ) { + if !mir_assign_valid_types(tcx.tcx, typing_env, check_layout, known_layout) { span_bug!( tcx.span, "expected type differs from actual type.\nexpected: {}\nactual: {}", @@ -199,23 +192,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn new( tcx: TyCtxt<'tcx>, root_span: Span, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, machine: M, ) -> Self { + // Const eval always happens in post analysis mode in order to be able to use the hidden types of + // opaque types. This is needed for trivial things like `size_of`, but also for using associated + // types that are not specified in the opaque type. We also use MIR bodies whose opaque types have + // already been revealed, so we'd be able to at least partially observe the hidden types anyways. + debug_assert_matches!(typing_env.typing_mode, ty::TypingMode::PostAnalysis); InterpCx { machine, tcx: tcx.at(root_span), - param_env, + typing_env, memory: Memory::new(), recursion_limit: tcx.recursion_limit(), } } - pub fn typing_mode(&self) -> TypingMode<'tcx> { - debug_assert_eq!(self.param_env.reveal(), Reveal::All); - TypingMode::PostAnalysis - } - /// Returns the span of the currently executed statement/terminator. /// This is the span typically used for error reporting. #[inline(always)] @@ -258,7 +251,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { #[inline] pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(*self.tcx, self.param_env) + ty.is_freeze(*self.tcx, self.typing_env) } pub fn load_mir( @@ -304,22 +297,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { .instance .try_instantiate_mir_and_normalize_erasing_regions( *self.tcx, - self.param_env, + self.typing_env, ty::EarlyBinder::bind(value), ) .map_err(|_| ErrorHandled::TooGeneric(self.cur_span())) } - /// The `args` are assumed to already be in our interpreter "universe" (param_env). + /// The `args` are assumed to already be in our interpreter "universe". pub(super) fn resolve( &self, def: DefId, args: GenericArgsRef<'tcx>, ) -> InterpResult<'tcx, ty::Instance<'tcx>> { trace!("resolve: {:?}, {:#?}", def, args); - trace!("param_env: {:#?}", self.param_env); + trace!("typing_env: {:#?}", self.typing_env); trace!("args: {:#?}", args); - match ty::Instance::try_resolve(*self.tcx, self.param_env, def, args) { + match ty::Instance::try_resolve(*self.tcx, self.typing_env, def, args) { Ok(Some(instance)) => interp_ok(instance), Ok(None) => throw_inval!(TooGeneric), @@ -328,7 +321,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - /// Check if the two things are equal in the current param_env, using an infctx to get proper + /// Check if the two things are equal in the current param_env, using an infcx to get proper /// equality checks. #[instrument(level = "trace", skip(self), ret)] pub(super) fn eq_in_param_env<T>(&self, a: T, b: T) -> bool @@ -340,14 +333,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return true; } // Slow path: spin up an inference context to check if these traits are sufficiently equal. - let infcx = self.tcx.infer_ctxt().build(self.typing_mode()); + let (infcx, param_env) = self.tcx.infer_ctxt().build_with_typing_env(self.typing_env); let ocx = ObligationCtxt::new(&infcx); let cause = ObligationCause::dummy_with_span(self.cur_span()); // equate the two trait refs after normalization - let a = ocx.normalize(&cause, self.param_env, a); - let b = ocx.normalize(&cause, self.param_env, b); + let a = ocx.normalize(&cause, param_env, a); + let b = ocx.normalize(&cause, param_env, b); - if let Err(terr) = ocx.eq(&cause, self.param_env, a, b) { + if let Err(terr) = ocx.eq(&cause, param_env, a, b) { trace!(?terr); return false; } @@ -572,10 +565,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let val = if self.tcx.is_static(gid.instance.def_id()) { let alloc_id = self.tcx.reserve_and_set_static_alloc(gid.instance.def_id()); - let ty = instance.ty(self.tcx.tcx, self.param_env); + let ty = instance.ty(self.tcx.tcx, self.typing_env); mir::ConstAlloc { alloc_id, ty } } else { - self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(self.param_env.and(gid)))? + self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(self.typing_env.as_query_input(gid)))? }; self.raw_const_to_mplace(val) } @@ -587,7 +580,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { layout: Option<TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { M::eval_mir_constant(self, *val, span, layout, |ecx, val, span, layout| { - let const_val = val.eval(*ecx.tcx, ecx.param_env, span).map_err(|err| { + let const_val = val.eval(*ecx.tcx, ecx.typing_env, span).map_err(|err| { if M::ALL_CONSTS_ARE_PRECHECKED { match err { ErrorHandled::TooGeneric(..) => {}, @@ -596,6 +589,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_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 7a1b92601a4..0cbb3b157f3 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -165,7 +165,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval InternKind::Static(Mutability::Not) => { ( // Outermost allocation is mutable if `!Freeze`. - if ret.layout.ty.is_freeze(*ecx.tcx, ecx.param_env) { + if ret.layout.ty.is_freeze(*ecx.tcx, ecx.typing_env) { Mutability::Not } else { Mutability::Mut diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index c7a56a80e81..a79923e8555 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -34,7 +34,7 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll /// inside an `InterpCx` and instead have their value computed directly from rustc internal info. pub(crate) fn eval_nullary_intrinsic<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>, ) -> InterpResult<'tcx, ConstValue<'tcx>> { @@ -48,11 +48,13 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( } sym::needs_drop => { ensure_monomorphic_enough(tcx, tp_ty)?; - ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env)) + ConstValue::from_bool(tp_ty.needs_drop(tcx, typing_env)) } sym::pref_align_of => { // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. - let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(*e)))?; + let layout = tcx + .layout_of(typing_env.as_query_input(tp_ty)) + .map_err(|e| err_inval!(Layout(*e)))?; ConstValue::from_target_usize(layout.align.pref.bytes(), &tcx) } sym::type_id => { @@ -149,8 +151,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sym::type_name => Ty::new_static_str(self.tcx.tcx), _ => bug!(), }; - let val = - self.ctfe_query(|tcx| tcx.const_eval_global_id(self.param_env, gid, tcx.span))?; + let val = self + .ctfe_query(|tcx| tcx.const_eval_global_id(self.typing_env, gid, tcx.span))?; let val = self.const_val_to_op(val, ty, Some(dest.layout))?; self.copy_op(&val, dest)?; } @@ -355,7 +357,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let should_panic = !self .tcx - .check_validity_requirement((requirement, self.param_env.and(ty))) + .check_validity_requirement((requirement, self.typing_env.as_query_input(ty))) .map_err(|_| err_inval!(TooGeneric))?; if should_panic { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 09635c96e57..277d293597a 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -859,8 +859,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // # Global allocations if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) { - let (size, align) = global_alloc.size_and_align(*self.tcx, self.param_env); - let mutbl = global_alloc.mutability(*self.tcx, self.param_env); + let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env); + let mutbl = global_alloc.mutability(*self.tcx, self.typing_env); let kind = match global_alloc { GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData, GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"), diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index a130ae89bcb..0157e6c2125 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -8,7 +8,7 @@ use rustc_abi as abi; use rustc_abi::{BackendRepr, HasDataLayout, Size}; use rustc_hir::def::Namespace; use rustc_middle::mir::interpret::ScalarSizeMismatch; -use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug, ty}; @@ -297,21 +297,25 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self { - let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(tcx.types.bool)).unwrap(); + let layout = tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tcx.types.bool)) + .unwrap(); Self::from_scalar(Scalar::from_bool(b), layout) } #[inline] pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self { let ty = tcx.ty_ordering_enum(None); - let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap(); + let layout = + tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap(); Self::from_scalar(Scalar::from_i8(c as i8), layout) } pub fn from_pair(a: Self, b: Self, tcx: TyCtxt<'tcx>) -> Self { let layout = tcx .layout_of( - ty::ParamEnv::reveal_all().and(Ty::new_tup(tcx, &[a.layout.ty, b.layout.ty])), + ty::TypingEnv::fully_monomorphized() + .as_query_input(Ty::new_tup(tcx, &[a.layout.ty, b.layout.ty])), ) .unwrap(); Self::from_scalar_pair(a.to_scalar(), b.to_scalar(), layout) @@ -341,7 +345,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn to_pair(self, cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>)) -> (Self, Self) { + pub fn to_pair(self, cx: &(impl HasTyCtxt<'tcx> + HasTypingEnv<'tcx>)) -> (Self, Self) { let layout = self.layout; let (val0, val1) = self.to_scalar_pair(); ( @@ -773,8 +777,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { )?; if !mir_assign_valid_types( *self.tcx, - self.typing_mode(), - self.param_env, + self.typing_env(), self.layout_of(normalized_place_ty)?, op.layout, ) { @@ -833,9 +836,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }) }; let layout = - from_known_layout(self.tcx, self.typing_mode(), self.param_env, layout, || { - self.layout_of(ty).into() - })?; + from_known_layout(self.tcx, self.typing_env(), layout, || self.layout_of(ty).into())?; let imm = match val_val { mir::ConstValue::Indirect { alloc_id, offset } => { // This is const data, no mutation allowed. diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index fbc85d37953..1fa5dcbd24f 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -533,7 +533,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } OffsetOf(fields) => { let val = - self.tcx.offset_of_subfield(self.param_env, layout, fields.iter()).bytes(); + self.tcx.offset_of_subfield(self.typing_env, layout, fields.iter()).bytes(); ImmTy::from_uint(val, usize_layout()) } UbChecks => ImmTy::from_bool(M::ub_checks(self)?, *self.tcx), diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index cc8d1db6cfb..2beec544fad 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -540,8 +540,7 @@ where )?; if !mir_assign_valid_types( *self.tcx, - self.typing_mode(), - self.param_env, + self.typing_env, self.layout_of(normalized_place_ty)?, place.layout, ) { @@ -871,13 +870,8 @@ where ) -> InterpResult<'tcx> { // We do NOT compare the types for equality, because well-typed code can // actually "transmute" `&mut T` to `&T` in an assignment without a cast. - let layout_compat = mir_assign_valid_types( - *self.tcx, - self.typing_mode(), - self.param_env, - src.layout(), - dest.layout(), - ); + let layout_compat = + mir_assign_valid_types(*self.tcx, self.typing_env, src.layout(), dest.layout()); if !allow_transmute && !layout_compat { span_bug!( self.cur_span(), diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 50c0446b3cd..8ce11c71b8b 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -379,7 +379,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { for &const_ in body.required_consts() { let c = self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?; - c.eval(*self.tcx, self.param_env, const_.span).map_err(|err| { + c.eval(*self.tcx, self.typing_env, const_.span).map_err(|err| { err.emit_note(*self.tcx); err })?; @@ -596,13 +596,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return interp_ok(layout); } - let layout = - from_known_layout(self.tcx, self.typing_mode(), self.param_env, layout, || { - let local_ty = frame.body.local_decls[local].ty; - let local_ty = - self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?; - self.layout_of(local_ty).into() - })?; + let layout = from_known_layout(self.tcx, self.typing_env, layout, || { + let local_ty = frame.body.local_decls[local].ty; + let local_ty = + self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?; + self.layout_of(local_ty).into() + })?; // Layouts of locals are requested a lot, so we cache them. state.layout.set(Some(layout)); diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 18cff2c5e0f..b61865be667 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -143,6 +143,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Defined to do nothing. These are added by optimization passes, to avoid changing the // size of MIR constantly. Nop => {} + + // Only used for temporary lifetime lints + BackwardIncompatibleDropHint { .. } => {} } interp_ok(()) @@ -418,7 +421,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { .collect::<InterpResult<'tcx, Vec<_>>>()?; let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx); - let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder); + let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.typing_env, fn_sig_binder); let extra_args = &args[fn_sig.inputs().len()..]; let extra_args = self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout().ty)); diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 3a68db9f7f7..273eaf42d87 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -448,7 +448,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { meta: MemPlaceMeta<M::Provenance>, pointee: TyAndLayout<'tcx>, ) -> InterpResult<'tcx> { - let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.param_env); + let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.typing_env); match tail.kind() { ty::Dynamic(data, _, ty::Dyn) => { let vtable = meta.unwrap_meta().to_pointer(self.ecx)?; @@ -568,7 +568,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind }); }; let (size, _align) = - global_alloc.size_and_align(*self.ecx.tcx, self.ecx.param_env); + global_alloc.size_and_align(*self.ecx.tcx, self.ecx.typing_env); if let GlobalAlloc::Static(did) = global_alloc { let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { @@ -619,7 +619,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { }; // Determine what it actually points to. let alloc_actual_mutbl = - global_alloc.mutability(*self.ecx.tcx, self.ecx.param_env); + global_alloc.mutability(*self.ecx.tcx, self.ecx.typing_env); // Mutable pointer to immutable memory is no good. if ptr_expected_mutbl == Mutability::Mut && alloc_actual_mutbl == Mutability::Not @@ -848,7 +848,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) { let tcx = *self.ecx.tcx; // Everything must be already interned. - let mutbl = tcx.global_alloc(alloc_id).mutability(tcx, self.ecx.param_env); + let mutbl = tcx.global_alloc(alloc_id).mutability(tcx, self.ecx.typing_env); if let Some((_, alloc)) = self.ecx.memory.alloc_map.get(alloc_id) { assert_eq!(alloc.mutability, mutbl); } @@ -955,7 +955,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { ) -> Cow<'e, RangeSet> { assert!(layout.ty.is_union()); assert!(layout.is_sized(), "there are no unsized unions"); - let layout_cx = LayoutCx::new(*ecx.tcx, ecx.param_env); + let layout_cx = LayoutCx::new(*ecx.tcx, ecx.typing_env); return M::cached_union_data_range(ecx, layout.ty, || { let mut out = RangeSet(Vec::new()); union_data_range_uncached(&layout_cx, layout, Size::ZERO, &mut out); @@ -1085,7 +1085,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, ) -> InterpResult<'tcx> { // Special check for CTFE validation, preventing `UnsafeCell` inside unions in immutable memory. if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) { - if !val.layout.is_zst() && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) { + if !val.layout.is_zst() && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.typing_env) + { if !self.in_mutable_memory(val) { throw_validation_failure!(self.path, UnsafeCellInImmutable); } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 0490195caf4..2a7408f1c70 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -40,14 +40,13 @@ pub fn provide(providers: &mut Providers) { providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; providers.eval_static_initializer = const_eval::eval_static_initializer_provider; providers.hooks.const_caller_location = util::caller_location::const_caller_location_provider; - providers.eval_to_valtree = |tcx, param_env_and_value| { - let (param_env, raw) = param_env_and_value.into_parts(); - const_eval::eval_to_valtree(tcx, param_env, raw) + providers.eval_to_valtree = |tcx, ty::PseudoCanonicalInput { typing_env, value }| { + const_eval::eval_to_valtree(tcx, typing_env, value) }; providers.hooks.try_destructure_mir_constant_for_user_output = const_eval::try_destructure_mir_constant_for_user_output; providers.valtree_to_const_val = |tcx, (ty, valtree)| { - const_eval::valtree_to_const_value(tcx, ty::ParamEnv::empty().and(ty), valtree) + const_eval::valtree_to_const_value(tcx, ty::TypingEnv::fully_monomorphized(), ty, valtree) }; providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| { util::check_validity_requirement(tcx, init_kind, param_env_and_ty) diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs index 6fa7d369229..9507b24f603 100644 --- a/compiler/rustc_const_eval/src/util/alignment.rs +++ b/compiler/rustc_const_eval/src/util/alignment.rs @@ -9,7 +9,7 @@ use tracing::debug; pub fn is_disaligned<'tcx, L>( tcx: TyCtxt<'tcx>, local_decls: &L, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, place: Place<'tcx>, ) -> bool where @@ -22,8 +22,8 @@ where }; let ty = place.ty(local_decls, tcx).ty; - let unsized_tail = || tcx.struct_tail_for_codegen(ty, param_env); - match tcx.layout_of(param_env.and(ty)) { + let unsized_tail = || tcx.struct_tail_for_codegen(ty, typing_env); + match tcx.layout_of(typing_env.as_query_input(ty)) { Ok(layout) if layout.align.abi <= pack && (layout.is_sized() diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index 7f4c36835e4..9bf16d4fe16 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -60,7 +60,7 @@ pub(crate) fn const_caller_location_provider( let mut ecx = mk_eval_cx_to_read_const_val( tcx.tcx, tcx.span, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), CanAccessMutGlobal::No, ); diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index f743525f359..651a797e97c 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -3,7 +3,7 @@ use rustc_middle::bug; use rustc_middle::ty::layout::{ HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement, }; -use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; +use rustc_middle::ty::{PseudoCanonicalInput, Ty, TyCtxt}; use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeMachine}; use crate::interpret::{InterpCx, MemoryKind}; @@ -23,16 +23,16 @@ use crate::interpret::{InterpCx, MemoryKind}; pub fn check_validity_requirement<'tcx>( tcx: TyCtxt<'tcx>, kind: ValidityRequirement, - param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>, + input: PseudoCanonicalInput<'tcx, Ty<'tcx>>, ) -> Result<bool, &'tcx LayoutError<'tcx>> { - let layout = tcx.layout_of(param_env_and_ty)?; + let layout = tcx.layout_of(input)?; // There is nothing strict or lax about inhabitedness. if kind == ValidityRequirement::Inhabited { return Ok(!layout.is_uninhabited()); } - let layout_cx = LayoutCx::new(tcx, param_env_and_ty.param_env); + let layout_cx = LayoutCx::new(tcx, input.typing_env); if kind == ValidityRequirement::Uninit || tcx.sess.opts.unstable_opts.strict_init_checks { check_validity_requirement_strict(layout, &layout_cx, kind) } else { @@ -49,7 +49,7 @@ fn check_validity_requirement_strict<'tcx>( ) -> Result<bool, &'tcx LayoutError<'tcx>> { let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error); - let mut cx = InterpCx::new(cx.tcx(), rustc_span::DUMMY_SP, cx.param_env, machine); + let mut cx = InterpCx::new(cx.tcx(), rustc_span::DUMMY_SP, cx.typing_env, machine); let allocated = cx .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap)) diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs index 0cf27d30c36..9eed1a20f15 100644 --- a/compiler/rustc_const_eval/src/util/compare_types.rs +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -5,18 +5,17 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, TypingMode, Variance}; +use rustc_middle::ty::{Ty, TyCtxt, TypingEnv, Variance}; use rustc_trait_selection::traits::ObligationCtxt; /// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`. pub fn sub_types<'tcx>( tcx: TyCtxt<'tcx>, - typing_mode: TypingMode<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: TypingEnv<'tcx>, src: Ty<'tcx>, dest: Ty<'tcx>, ) -> bool { - relate_types(tcx, typing_mode, param_env, Variance::Covariant, src, dest) + relate_types(tcx, typing_env, Variance::Covariant, src, dest) } /// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`. @@ -26,8 +25,7 @@ pub fn sub_types<'tcx>( /// because we want to check for type equality. pub fn relate_types<'tcx>( tcx: TyCtxt<'tcx>, - typing_mode: TypingMode<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: TypingEnv<'tcx>, variance: Variance, src: Ty<'tcx>, dest: Ty<'tcx>, @@ -36,8 +34,7 @@ pub fn relate_types<'tcx>( return true; } - let mut builder = tcx.infer_ctxt().ignoring_regions(); - let infcx = builder.build(typing_mode); + let (infcx, param_env) = tcx.infer_ctxt().ignoring_regions().build_with_typing_env(typing_env); let ocx = ObligationCtxt::new(&infcx); let cause = ObligationCause::dummy(); let src = ocx.normalize(&cause, param_env, src); 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/unord.rs b/compiler/rustc_data_structures/src/unord.rs index bafb16a8b5e..34895d3efe6 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -602,6 +602,11 @@ impl<K: Eq + Hash, V> UnordMap<K, V> { .into_iter() .map(|(_, v)| v) } + + #[inline] + pub fn clear(&mut self) { + self.inner.clear() + } } impl<K, Q: ?Sized, V> Index<&Q> for UnordMap<K, V> 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_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl index 31837e01764..05e11c4527f 100644 --- a/compiler/rustc_driver_impl/messages.ftl +++ b/compiler/rustc_driver_impl/messages.ftl @@ -23,3 +23,5 @@ driver_impl_rlink_rustc_version_mismatch = .rlink file was produced by rustc ver driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}` driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file + +driver_impl_unstable_feature_usage = cannot dump feature usage metrics: {$error} diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index b6f7abed6f3..c270ce16726 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -15,6 +15,7 @@ #![feature(panic_update_hook)] #![feature(result_flattening)] #![feature(rustdoc_internals)] +#![feature(try_blocks)] #![warn(unreachable_pub)] // tidy-alphabetical-end @@ -50,6 +51,7 @@ use rustc_interface::{Linker, Queries, interface, passes}; use rustc_lint::unerased_lint_store; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::locator; +use rustc_middle::ty::TyCtxt; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::config::{ CG_OPTIONS, ErrorOutputType, Input, OutFileName, OutputType, UnstableOptions, Z_OPTIONS, @@ -102,7 +104,7 @@ mod signal_handler { use crate::session_diagnostics::{ RLinkEmptyVersionNumber, RLinkEncodingVersionMismatch, RLinkRustcVersionMismatch, - RLinkWrongFileType, RlinkCorruptFile, RlinkNotAFile, RlinkUnableToRead, + RLinkWrongFileType, RlinkCorruptFile, RlinkNotAFile, RlinkUnableToRead, UnstableFeatureUsage, }; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } @@ -430,6 +432,10 @@ fn run_compiler( // Make sure name resolution and macro expansion is run. queries.global_ctxt()?.enter(|tcx| tcx.resolver_for_lowering()); + if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir { + queries.global_ctxt()?.enter(|tcxt| dump_feature_usage_metrics(tcxt, metrics_dir)); + } + if callbacks.after_expansion(compiler, queries) == Compilation::Stop { return early_exit(); } @@ -474,6 +480,23 @@ fn run_compiler( }) } +fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &PathBuf) { + let output_filenames = tcxt.output_filenames(()); + let mut metrics_file_name = std::ffi::OsString::from("unstable_feature_usage_metrics-"); + let mut metrics_path = output_filenames.with_directory_and_extension(metrics_dir, "json"); + let metrics_file_stem = + metrics_path.file_name().expect("there should be a valid default output filename"); + metrics_file_name.push(metrics_file_stem); + metrics_path.pop(); + metrics_path.push(metrics_file_name); + if let Err(error) = tcxt.features().dump_feature_usage_metrics(metrics_path) { + // FIXME(yaahc): once metrics can be enabled by default we will want "failure to emit + // default metrics" to only produce a warning when metrics are enabled by default and emit + // an error only when the user manually enables metrics + tcxt.dcx().emit_err(UnstableFeatureUsage { error }); + } +} + // Extract output directory and file from matches. fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<OutFileName>) { let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o)); @@ -564,71 +587,63 @@ fn handle_explain(early_dcx: &EarlyDiagCtxt, registry: Registry, code: &str, col } } -/// If color is always or auto, print formatted & colorized markdown. If color is never or -/// if formatted printing fails, print the raw text. +/// If `color` is `always` or `auto`, try to print pretty (formatted & colorized) markdown. If +/// that fails or `color` is `never`, print the raw markdown. /// -/// Prefers a pager, falls back standard print +/// Uses a pager if possible, falls back to stdout. fn show_md_content_with_pager(content: &str, color: ColorConfig) { - let mut fallback_to_println = false; let pager_name = env::var_os("PAGER").unwrap_or_else(|| { if cfg!(windows) { OsString::from("more.com") } else { OsString::from("less") } }); let mut cmd = Command::new(&pager_name); - // FIXME: find if other pagers accept color options - let mut print_formatted = if pager_name == "less" { - cmd.arg("-r"); - true - } else { - ["bat", "catbat", "delta"].iter().any(|v| *v == pager_name) - }; - - if color == ColorConfig::Never { - print_formatted = false; - } else if color == ColorConfig::Always { - print_formatted = true; - } - - let mdstream = markdown::MdStream::parse_str(content); - let bufwtr = markdown::create_stdout_bufwtr(); - let mut mdbuf = bufwtr.buffer(); - if mdstream.write_termcolor_buf(&mut mdbuf).is_err() { - print_formatted = false; + if pager_name == "less" { + cmd.arg("-R"); // allows color escape sequences } - if let Ok(mut pager) = cmd.stdin(Stdio::piped()).spawn() { - if let Some(pipe) = pager.stdin.as_mut() { - let res = if print_formatted { - pipe.write_all(mdbuf.as_slice()) - } else { - pipe.write_all(content.as_bytes()) - }; - - if res.is_err() { - fallback_to_println = true; - } + let pretty_on_pager = match color { + ColorConfig::Auto => { + // Add other pagers that accept color escape sequences here. + ["less", "bat", "batcat", "delta"].iter().any(|v| *v == pager_name) } + ColorConfig::Always => true, + ColorConfig::Never => false, + }; - if pager.wait().is_err() { - fallback_to_println = true; - } - } else { - fallback_to_println = true; - } + // Try to prettify the raw markdown text. The result can be used by the pager or on stdout. + let pretty_data = { + let mdstream = markdown::MdStream::parse_str(content); + let bufwtr = markdown::create_stdout_bufwtr(); + let mut mdbuf = bufwtr.buffer(); + if mdstream.write_termcolor_buf(&mut mdbuf).is_ok() { Some((bufwtr, mdbuf)) } else { None } + }; + + // Try to print via the pager, pretty output if possible. + let pager_res: Option<()> = try { + let mut pager = cmd.stdin(Stdio::piped()).spawn().ok()?; - // If pager fails for whatever reason, we should still print the content - // to standard output - if fallback_to_println { - let fmt_success = match color { - ColorConfig::Auto => io::stdout().is_terminal() && bufwtr.print(&mdbuf).is_ok(), - ColorConfig::Always => bufwtr.print(&mdbuf).is_ok(), - ColorConfig::Never => false, + let pager_stdin = pager.stdin.as_mut()?; + if pretty_on_pager && let Some((_, mdbuf)) = &pretty_data { + pager_stdin.write_all(mdbuf.as_slice()).ok()?; + } else { + pager_stdin.write_all(content.as_bytes()).ok()?; }; - if !fmt_success { - safe_print!("{content}"); - } + pager.wait().ok()?; + }; + if pager_res.is_some() { + return; + } + + // The pager failed. Try to print pretty output to stdout. + if let Some((bufwtr, mdbuf)) = &pretty_data + && bufwtr.print(&mdbuf).is_ok() + { + return; } + + // Everything failed. Print the raw markdown text. + safe_print!("{content}"); } fn process_rlink(sess: &Session, compiler: &interface::Compiler) { diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs index 449878f28c4..e06c56539d1 100644 --- a/compiler/rustc_driver_impl/src/session_diagnostics.rs +++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs @@ -1,3 +1,5 @@ +use std::error::Error; + use rustc_macros::{Diagnostic, Subdiagnostic}; #[derive(Diagnostic)] @@ -93,3 +95,9 @@ pub(crate) struct IceFlags { #[derive(Diagnostic)] #[diag(driver_impl_ice_exclude_cargo_defaults)] pub(crate) struct IceExcludeCargoDefaults; + +#[derive(Diagnostic)] +#[diag(driver_impl_unstable_feature_usage)] +pub(crate) struct UnstableFeatureUsage { + pub error: Box<dyn Error>, +} diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 04ac7891023..19c2d466f7c 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1303,7 +1303,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> fragment.make_trait_items() } fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_item(visitor, self.wrapped) + walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Trait) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) @@ -1344,7 +1344,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> fragment.make_impl_items() } fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_item(visitor, self.wrapped) + walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Impl) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) @@ -1382,7 +1382,7 @@ impl InvocationCollectorNode for P<ast::ForeignItem> { fragment.make_foreign_items() } fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_item(visitor, self) + walk_flat_map_foreign_item(visitor, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, ForeignItemKind::MacCall(..)) diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 610c69e9d21..bae16a18bcb 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -286,7 +286,7 @@ impl MutVisitor for PlaceholderExpander { AssocCtxt::Impl => it.make_impl_items(), } } - _ => walk_flat_map_item(self, item), + _ => walk_flat_map_assoc_item(self, item, ctxt), } } @@ -296,7 +296,7 @@ impl MutVisitor for PlaceholderExpander { ) -> SmallVec<[P<ast::ForeignItem>; 1]> { match item.kind { ast::ForeignItemKind::MacCall(_) => self.remove(item.id).make_foreign_items(), - _ => walk_flat_map_item(self, item), + _ => walk_flat_map_foreign_item(self, item), } } diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml index 9df320e1279..77de7fabd4f 100644 --- a/compiler/rustc_feature/Cargo.toml +++ b/compiler/rustc_feature/Cargo.toml @@ -7,4 +7,6 @@ edition = "2021" # tidy-alphabetical-start rustc_data_structures = { path = "../rustc_data_structures" } rustc_span = { path = "../rustc_span" } +serde = { version = "1.0.125", features = [ "derive" ] } +serde_json = "1.0.59" # tidy-alphabetical-end diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index a4820ba8b72..fd08b35d242 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -838,7 +838,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL, ), rustc_attr!( - rustc_const_stable_intrinsic, Normal, + rustc_intrinsic_const_stable_indirect, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL, ), gated!( @@ -880,6 +880,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "lang items are subject to change", ), rustc_attr!( + rustc_as_ptr, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::Yes, + "#[rustc_as_ptr] is used to mark functions returning pointers to their inner allocations." + ), + rustc_attr!( rustc_pass_by_value, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference." diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 9f42d3ec45c..5d27b8f542c 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -74,14 +74,19 @@ impl UnstableFeatures { // Returns whether `krate` should be counted as unstable let is_unstable_crate = |var: &str| krate.is_some_and(|name| var.split(',').any(|new_krate| new_krate == name)); - // `true` if we should enable unstable features for bootstrapping. - let bootstrap = - std::env::var("RUSTC_BOOTSTRAP").is_ok_and(|var| var == "1" || is_unstable_crate(&var)); - match (disable_unstable_features, bootstrap) { - (_, true) => UnstableFeatures::Cheat, - (true, _) => UnstableFeatures::Disallow, - (false, _) => UnstableFeatures::Allow, + + let bootstrap = std::env::var("RUSTC_BOOTSTRAP").ok(); + if let Some(val) = bootstrap.as_deref() { + match val { + val if val == "1" || is_unstable_crate(val) => return UnstableFeatures::Cheat, + // Hypnotize ourselves so that we think we are a stable compiler and thus don't + // allow any unstable features. + "-1" => return UnstableFeatures::Disallow, + _ => {} + } } + + if disable_unstable_features { UnstableFeatures::Disallow } else { UnstableFeatures::Allow } } pub fn is_nightly_build(&self) -> bool { diff --git a/compiler/rustc_feature/src/tests.rs b/compiler/rustc_feature/src/tests.rs index 50433e44b13..cc0e1f31209 100644 --- a/compiler/rustc_feature/src/tests.rs +++ b/compiler/rustc_feature/src/tests.rs @@ -18,6 +18,16 @@ fn rustc_bootstrap_parsing() { assert!(!is_bootstrap("x,y,z", Some("a"))); assert!(!is_bootstrap("x,y,z", None)); - // this is technically a breaking change, but there are no stability guarantees for RUSTC_BOOTSTRAP + // `RUSTC_BOOTSTRAP=0` is not recognized. assert!(!is_bootstrap("0", None)); + + // `RUSTC_BOOTSTRAP=-1` is force-stable, no unstable features allowed. + let is_force_stable = |krate| { + std::env::set_var("RUSTC_BOOTSTRAP", "-1"); + matches!(UnstableFeatures::from_environment(krate), UnstableFeatures::Disallow) + }; + assert!(is_force_stable(None)); + // Does not support specifying any crate. + assert!(is_force_stable(Some("x"))); + assert!(is_force_stable(Some("x,y,z"))); } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 8326d0031ea..e3dc73c1401 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -1,5 +1,7 @@ //! List of the unstable feature gates. +use std::path::PathBuf; + use rustc_data_structures::fx::FxHashSet; use rustc_span::Span; use rustc_span::symbol::{Symbol, sym}; @@ -54,7 +56,7 @@ pub struct EnabledLangFeature { pub stable_since: Option<Symbol>, } -/// Information abhout an enabled library feature. +/// Information about an enabled library feature. #[derive(Debug, Copy, Clone)] pub struct EnabledLibFeature { pub gate_name: Symbol, @@ -529,6 +531,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. @@ -649,6 +653,54 @@ declare_features! ( // ------------------------------------------------------------------------- ); +impl Features { + pub fn dump_feature_usage_metrics( + &self, + metrics_path: PathBuf, + ) -> Result<(), Box<dyn std::error::Error>> { + #[derive(serde::Serialize)] + struct LibFeature { + symbol: String, + } + + #[derive(serde::Serialize)] + struct LangFeature { + symbol: String, + since: Option<String>, + } + + #[derive(serde::Serialize)] + struct FeatureUsage { + lib_features: Vec<LibFeature>, + lang_features: Vec<LangFeature>, + } + + let metrics_file = std::fs::File::create(metrics_path)?; + let metrics_file = std::io::BufWriter::new(metrics_file); + + let lib_features = self + .enabled_lib_features + .iter() + .map(|EnabledLibFeature { gate_name, .. }| LibFeature { symbol: gate_name.to_string() }) + .collect(); + + let lang_features = self + .enabled_lang_features + .iter() + .map(|EnabledLangFeature { gate_name, stable_since, .. }| LangFeature { + symbol: gate_name.to_string(), + since: stable_since.map(|since| since.to_string()), + }) + .collect(); + + let feature_usage = FeatureUsage { lib_features, lang_features }; + + serde_json::to_writer(metrics_file, &feature_usage)?; + + Ok(()) + } +} + /// Some features are not allowed to be used together at the same time, if /// the two are present, produce an error. /// diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 6e8ba51612e..64a30e633cf 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -448,6 +448,11 @@ hir_analysis_rpitit_refined = impl trait in impl method signature does not match .note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate .feedback_note = we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information +hir_analysis_rpitit_refined_lifetimes = impl trait in impl method captures fewer lifetimes than in trait + .suggestion = modify the `use<..>` bound to capture the same lifetimes that the trait does + .note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate + .feedback_note = we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information + hir_analysis_self_in_impl_self = `Self` is not valid in the self type of an impl block .note = replace `Self` with a different type diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 3080d8b3510..cf3f3003bf5 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -21,8 +21,7 @@ use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt}; use rustc_middle::ty::{ - AdtDef, GenericArgKind, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, + AdtDef, GenericArgKind, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; use rustc_session::lint::builtin::UNINHABITED_STATIC; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; @@ -91,38 +90,38 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b fn allowed_union_field<'tcx>( ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> bool { // We don't just accept all !needs_drop fields, due to semver concerns. match ty.kind() { ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check) ty::Tuple(tys) => { // allow tuples of allowed types - tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env)) + tys.iter().all(|ty| allowed_union_field(ty, tcx, typing_env)) } ty::Array(elem, _len) => { // Like `Copy`, we do *not* special-case length 0. - allowed_union_field(*elem, tcx, param_env) + allowed_union_field(*elem, tcx, typing_env) } _ => { // Fallback case: allow `ManuallyDrop` and things that are `Copy`, // also no need to report an error if the type is unresolved. ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop()) - || ty.is_copy_modulo_regions(tcx, param_env) + || ty.is_copy_modulo_regions(tcx, typing_env) || ty.references_error() } } } - let param_env = tcx.param_env(item_def_id); + let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id); for field in &def.non_enum_variant().fields { - let Ok(field_ty) = tcx.try_normalize_erasing_regions(param_env, field.ty(tcx, args)) + let Ok(field_ty) = tcx.try_normalize_erasing_regions(typing_env, field.ty(tcx, args)) else { tcx.dcx().span_delayed_bug(span, "could not normalize field type"); continue; }; - if !allowed_union_field(field_ty, tcx, param_env) { + if !allowed_union_field(field_ty, tcx, typing_env) { let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { // We are currently checking the type this field came from, so it must be local. Some(Node::Field(field)) => (field.span, field.ty.span), @@ -137,7 +136,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b note: (), }); return false; - } else if field_ty.needs_drop(tcx, param_env) { + } else if field_ty.needs_drop(tcx, typing_env) { // This should never happen. But we can get here e.g. in case of name resolution errors. tcx.dcx() .span_delayed_bug(span, "we should never accept maybe-dropping union fields"); @@ -158,7 +157,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { // reason to allow any statics to be uninhabited. let ty = tcx.type_of(def_id).instantiate_identity(); let span = tcx.def_span(def_id); - let layout = match tcx.layout_of(ParamEnv::reveal_all().and(ty)) { + let layout = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) { Ok(l) => l, // Foreign statics that overflow their allowed size should emit an error Err(LayoutError::SizeOverflow(_)) @@ -237,7 +236,10 @@ pub(super) fn check_opaque_for_cycles<'tcx>( // And also look for cycle errors in the layout of coroutines. if let Err(&LayoutError::Cycle(guar)) = - tcx.layout_of(tcx.param_env(def_id).and(Ty::new_opaque(tcx, def_id.to_def_id(), args))) + tcx.layout_of( + ty::TypingEnv::post_analysis(tcx, def_id.to_def_id()) + .as_query_input(Ty::new_opaque(tcx, def_id.to_def_id(), args)), + ) { return Err(guar); } @@ -337,6 +339,8 @@ fn check_opaque_meets_bounds<'tcx>( let misc_cause = ObligationCause::misc(span, def_id); // FIXME: We should just register the item bounds here, rather than equating. + // FIXME(const_trait_impl): When we do that, please make sure to also register + // the `~const` bounds. match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) { Ok(()) => {} Err(ty_err) => { @@ -1307,8 +1311,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) // "known" respecting #[non_exhaustive] attributes. let field_infos = adt.all_fields().map(|field| { let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did)); - let param_env = tcx.param_env(field.did); - let layout = tcx.layout_of(param_env.and(ty)); + let typing_env = ty::TypingEnv::non_body_analysis(tcx, field.did); + let layout = tcx.layout_of(typing_env.as_query_input(ty)); // We are currently checking the type this field came from, so it must be local let span = tcx.hir().span_if_local(field.did).unwrap(); let trivial = layout.is_ok_and(|layout| layout.is_1zst()); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 77c324183c3..bd0b0ceb92d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1193,9 +1193,9 @@ fn compare_self_type<'tcx>( ty::AssocItemContainer::Trait => tcx.types.self_param, }; let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().input(0); - let param_env = ty::ParamEnv::reveal_all(); - - let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); + let (infcx, param_env) = tcx + .infer_ctxt() + .build_with_typing_env(ty::TypingEnv::non_body_analysis(tcx, method.def_id)); let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty); let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty); match ExplicitSelf::determine(self_arg_ty, can_eq_self) { @@ -2083,7 +2083,7 @@ pub(super) fn check_type_bounds<'tcx>( // Only in a const implementation do we need to check that the `~const` item bounds hold. if tcx.is_conditionally_const(impl_ty_def_id) { obligations.extend( - tcx.implied_const_bounds(trait_ty.def_id) + tcx.explicit_implied_const_bounds(trait_ty.def_id) .iter_instantiated_copied(tcx, rebased_args) .map(|(c, span)| { traits::Obligation::new( diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 646c104f1f5..25ba52b4d7b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -1,6 +1,7 @@ +use itertools::Itertools as _; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE}; @@ -75,6 +76,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( let mut trait_bounds = vec![]; // Bounds that we find on the RPITITs in the impl signature. let mut impl_bounds = vec![]; + // Pairs of trait and impl opaques. + let mut pairs = vec![]; for trait_projection in collector.types.into_iter().rev() { let impl_opaque_args = trait_projection.args.rebase_onto(tcx, trait_m.def_id, impl_m_args); @@ -121,6 +124,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( tcx.explicit_item_bounds(impl_opaque.def_id) .iter_instantiated_copied(tcx, impl_opaque.args), )); + + pairs.push((trait_projection, impl_opaque)); } let hybrid_preds = tcx @@ -212,6 +217,39 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( return; } } + + // Make sure that the RPITIT doesn't capture fewer regions than + // the trait definition. We hard-error if it captures *more*, since that + // is literally unrepresentable in the type system; however, we may be + // promising stronger outlives guarantees if we capture *fewer* regions. + for (trait_projection, impl_opaque) in pairs { + let impl_variances = tcx.variances_of(impl_opaque.def_id); + let impl_captures: FxIndexSet<_> = impl_opaque + .args + .iter() + .zip_eq(impl_variances) + .filter(|(_, v)| **v == ty::Invariant) + .map(|(arg, _)| arg) + .collect(); + + let trait_variances = tcx.variances_of(trait_projection.def_id); + let mut trait_captures = FxIndexSet::default(); + for (arg, variance) in trait_projection.args.iter().zip_eq(trait_variances) { + if *variance != ty::Invariant { + continue; + } + arg.visit_with(&mut CollectParams { params: &mut trait_captures }); + } + + if !trait_captures.iter().all(|arg| impl_captures.contains(arg)) { + report_mismatched_rpitit_captures( + tcx, + impl_opaque.def_id.expect_local(), + trait_captures, + is_internal, + ); + } + } } struct ImplTraitInTraitCollector<'tcx> { @@ -342,3 +380,65 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Anonymize<'tcx> { self.tcx.anonymize_bound_vars(t) } } + +struct CollectParams<'a, 'tcx> { + params: &'a mut FxIndexSet<ty::GenericArg<'tcx>>, +} +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CollectParams<'_, 'tcx> { + fn visit_ty(&mut self, ty: Ty<'tcx>) { + if let ty::Param(_) = ty.kind() { + self.params.insert(ty.into()); + } else { + ty.super_visit_with(self); + } + } + fn visit_region(&mut self, r: ty::Region<'tcx>) { + match r.kind() { + ty::ReEarlyParam(_) | ty::ReLateParam(_) => { + self.params.insert(r.into()); + } + _ => {} + } + } + fn visit_const(&mut self, ct: ty::Const<'tcx>) { + if let ty::ConstKind::Param(_) = ct.kind() { + self.params.insert(ct.into()); + } else { + ct.super_visit_with(self); + } + } +} + +fn report_mismatched_rpitit_captures<'tcx>( + tcx: TyCtxt<'tcx>, + impl_opaque_def_id: LocalDefId, + mut trait_captured_args: FxIndexSet<ty::GenericArg<'tcx>>, + is_internal: bool, +) { + let Some(use_bound_span) = + tcx.hir_node_by_def_id(impl_opaque_def_id).expect_opaque_ty().bounds.iter().find_map( + |bound| match *bound { + rustc_hir::GenericBound::Use(_, span) => Some(span), + hir::GenericBound::Trait(_) | hir::GenericBound::Outlives(_) => None, + }, + ) + else { + // I have no idea when you would ever undercapture without a `use<..>`. + tcx.dcx().delayed_bug("expected use<..> to undercapture in an impl opaque"); + return; + }; + + trait_captured_args + .sort_by_cached_key(|arg| !matches!(arg.unpack(), ty::GenericArgKind::Lifetime(_))); + let suggestion = format!("use<{}>", trait_captured_args.iter().join(", ")); + + tcx.emit_node_span_lint( + if is_internal { REFINING_IMPL_TRAIT_INTERNAL } else { REFINING_IMPL_TRAIT_REACHABLE }, + tcx.local_def_id_to_hir_id(impl_opaque_def_id), + use_bound_span, + crate::errors::ReturnPositionImplTraitInTraitRefinedLifetimes { + suggestion_span: use_bound_span, + suggestion, + }, + ); +} diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index cb954b0adcb..3e33120901f 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -109,9 +109,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - | sym::three_way_compare | sym::discriminant_value | sym::type_id - | sym::likely - | sym::unlikely | sym::select_unpredictable + | sym::cold_path | sym::ptr_guaranteed_cmp | sym::minnumf16 | sym::minnumf32 @@ -489,9 +488,8 @@ pub fn check_intrinsic_type( sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)), sym::assume => (0, 0, vec![tcx.types.bool], tcx.types.unit), - sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool), - sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool), sym::select_unpredictable => (1, 0, vec![tcx.types.bool, param(0), param(0)], param(0)), + sym::cold_path => (0, 0, vec![], tcx.types.unit), sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), sym::write_via_move => { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index e95669c9d40..dfddf93a5c2 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -15,7 +15,7 @@ use rustc_target::asm::{ pub struct InlineAsmCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, get_operand_ty: Box<dyn Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a>, } @@ -23,24 +23,29 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self { InlineAsmCtxt { tcx, - param_env: ty::ParamEnv::empty(), + typing_env: ty::TypingEnv { + typing_mode: ty::TypingMode::non_body_analysis(), + param_env: ty::ParamEnv::empty(), + }, get_operand_ty: Box::new(|e| bug!("asm operand in global asm: {e:?}")), } } + // FIXME(#132279): This likely causes us to incorrectly handle opaque types in their + // defining scope. pub fn new_in_fn( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, get_operand_ty: impl Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a, ) -> Self { - InlineAsmCtxt { tcx, param_env, get_operand_ty: Box::new(get_operand_ty) } + InlineAsmCtxt { tcx, typing_env, get_operand_ty: Box::new(get_operand_ty) } } // FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()` fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool { // Type still may have region variables, but `Sized` does not depend // on those, so just erase them before querying. - if ty.is_sized(self.tcx, self.param_env) { + if ty.is_sized(self.tcx, self.typing_env) { return true; } if let ty::Foreign(..) = ty.kind() { @@ -171,7 +176,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // Check that the type implements Copy. The only case where this can // possibly fail is for SIMD types which don't #[derive(Copy)]. - if !ty.is_copy_modulo_regions(self.tcx, self.param_env) { + if !ty.is_copy_modulo_regions(self.tcx, self.typing_env) { let msg = "arguments for inline assembly must be copyable"; self.tcx .dcx() diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 679f6ccb816..b9cb48cafdc 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -17,6 +17,7 @@ use rustc_index::Idx; use rustc_middle::bug; use rustc_middle::middle::region::*; use rustc_middle::ty::TyCtxt; +use rustc_session::lint; use rustc_span::source_map; use tracing::debug; @@ -167,8 +168,23 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h } } if let Some(tail_expr) = blk.expr { - if blk.span.edition().at_least_rust_2024() { - visitor.terminating_scopes.insert(tail_expr.hir_id.local_id); + let local_id = tail_expr.hir_id.local_id; + let edition = blk.span.edition(); + if edition.at_least_rust_2024() { + visitor.terminating_scopes.insert(local_id); + } else if !visitor + .tcx + .lints_that_dont_need_to_run(()) + .contains(&lint::LintId::of(lint::builtin::TAIL_EXPR_DROP_ORDER)) + { + // If this temporary scope will be changing once the codebase adopts Rust 2024, + // and we are linting about possible semantic changes that would result, + // then record this node-id in the field `backwards_incompatible_scope` + // for future reference. + visitor + .scope_tree + .backwards_incompatible_scope + .insert(local_id, Scope { id: local_id, data: ScopeData::Node }); } visitor.visit_expr(tail_expr); } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 1802f00bc1f..20bc34b8c79 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1126,7 +1126,7 @@ fn check_type_defn<'tcx>( let ty = tcx.type_of(variant.tail().did).instantiate_identity(); let ty = tcx.erase_regions(ty); assert!(!ty.has_infer()); - ty.needs_drop(tcx, tcx.param_env(item.owner_id)) + ty.needs_drop(tcx, wfcx.infcx.typing_env(wfcx.param_env)) } }; // All fields (except for possibly the last) should be sized. @@ -1281,7 +1281,8 @@ fn check_item_type( UnsizedHandling::Forbid => true, UnsizedHandling::Allow => false, UnsizedHandling::AllowIfForeignTail => { - let tail = tcx.struct_tail_for_codegen(item_ty, wfcx.param_env); + let tail = + tcx.struct_tail_for_codegen(item_ty, wfcx.infcx.typing_env(wfcx.param_env)); !matches!(tail.kind(), ty::Foreign(_)) } }; diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 5ff52376837..3b49bc41ffe 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -37,22 +37,19 @@ pub(super) fn check_trait<'tcx>( ) -> Result<(), ErrorGuaranteed> { let lang_items = tcx.lang_items(); let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header }; - let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop); - res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy)); - res = res.and(checker.check(lang_items.const_param_ty_trait(), |checker| { + checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?; + checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?; + checker.check(lang_items.const_param_ty_trait(), |checker| { visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy) - })); - res = res.and(checker.check(lang_items.unsized_const_param_ty_trait(), |checker| { + })?; + checker.check(lang_items.unsized_const_param_ty_trait(), |checker| { visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy) - })); - - res = res.and( - checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized), - ); - res.and( - checker - .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn), - ) + })?; + checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?; + checker + .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?; + checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?; + Ok(()) } struct Checker<'tcx> { @@ -259,7 +256,9 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() let ty_a = field.ty(tcx, args_a); let ty_b = field.ty(tcx, args_b); - if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) { + if let Ok(layout) = + tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a)) + { if layout.is_1zst() { // ignore 1-ZST fields return false; @@ -661,3 +660,63 @@ fn infringing_fields_error<'tcx>( err.emit() } + +fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { + let tcx = checker.tcx; + let typing_env = ty::TypingEnv::non_body_analysis(tcx, checker.impl_def_id); + let impl_span = tcx.def_span(checker.impl_def_id); + let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty(); + + // If an ADT is repr(transparent)... + if let ty::Adt(def, args) = *self_ty.kind() + && def.repr().transparent() + { + // FIXME(compiler-errors): This should and could be deduplicated into a query. + // Find the nontrivial field. + let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, def.did()); + let nontrivial_field = def.all_fields().find(|field_def| { + let field_ty = tcx.type_of(field_def.did).instantiate_identity(); + !tcx.layout_of(adt_typing_env.as_query_input(field_ty)) + .is_ok_and(|layout| layout.layout.is_1zst()) + }); + + if let Some(nontrivial_field) = nontrivial_field { + // Check that the nontrivial field implements `PointerLike`. + let nontrivial_field = nontrivial_field.ty(tcx, args); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + let ocx = ObligationCtxt::new(&infcx); + ocx.register_bound( + ObligationCause::misc(impl_span, checker.impl_def_id), + param_env, + nontrivial_field, + tcx.lang_items().pointer_like().unwrap(), + ); + // FIXME(dyn-star): We should regionck this implementation. + if ocx.select_all_or_error().is_empty() { + return Ok(()); + } + } + } + + let is_permitted_primitive = match *self_ty.kind() { + ty::Adt(def, _) => def.is_box(), + ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true, + _ => false, + }; + + if is_permitted_primitive + && let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty)) + && layout.layout.is_pointer_like(&tcx.data_layout) + { + return Ok(()); + } + + Err(tcx + .dcx() + .struct_span_err( + impl_span, + "implementation must be applied to type that has the same ABI as a pointer, \ + or is `repr(transparent)` and whose field is `PointerLike`", + ) + .emit()) +} diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 8a1a887766c..eca85c22a40 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -172,7 +172,7 @@ pub(crate) fn orphan_check_impl( // impl<T> AutoTrait for T {} // impl<T: ?Sized> AutoTrait for T {} ty::Param(..) => ( - if self_ty.is_sized(tcx, tcx.param_env(impl_def_id)) { + if self_ty.is_sized(tcx, ty::TypingEnv::non_body_analysis(tcx, impl_def_id)) { LocalImpl::Allow } else { LocalImpl::Disallow { problematic_kind: "generic type" } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 63a0e7d31c3..73b73afb0a5 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; @@ -78,7 +78,7 @@ pub fn provide(providers: &mut Providers) { predicates_of::explicit_supertraits_containing_assoc_item, trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds, const_conditions: predicates_of::const_conditions, - implied_const_bounds: predicates_of::implied_const_bounds, + explicit_implied_const_bounds: predicates_of::explicit_implied_const_bounds, type_param_predicates: predicates_of::type_param_predicates, trait_def, adt_def, @@ -88,6 +88,7 @@ pub fn provide(providers: &mut Providers) { coroutine_for_closure, opaque_ty_origin, rendered_precise_capturing_args, + const_param_default, ..*providers }; } @@ -339,6 +340,10 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { self.tcx.ensure().explicit_item_super_predicates(def_id); self.tcx.ensure().item_bounds(def_id); self.tcx.ensure().item_super_predicates(def_id); + if self.tcx.is_conditionally_const(def_id) { + self.tcx.ensure().explicit_implied_const_bounds(def_id); + self.tcx.ensure().const_conditions(def_id); + } intravisit::walk_opaque_ty(self, opaque); } @@ -681,6 +686,10 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { tcx.ensure().generics_of(item.owner_id); tcx.ensure().type_of(item.owner_id); tcx.ensure().predicates_of(item.owner_id); + if tcx.is_conditionally_const(def_id) { + tcx.ensure().explicit_implied_const_bounds(def_id); + tcx.ensure().const_conditions(def_id); + } match item.kind { hir::ForeignItemKind::Fn(..) => { tcx.ensure().codegen_fn_attrs(item.owner_id); @@ -1790,3 +1799,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..b5dee5bd021 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)); } @@ -958,6 +959,12 @@ pub(super) fn const_conditions<'tcx>( hir::ForeignItemKind::Fn(_, _, generics) => (generics, None, false), _ => bug!("const_conditions called on wrong item: {def_id:?}"), }, + Node::OpaqueTy(opaque) => match opaque.origin { + hir::OpaqueTyOrigin::FnReturn { parent, .. } => return tcx.const_conditions(parent), + hir::OpaqueTyOrigin::AsyncFn { .. } | hir::OpaqueTyOrigin::TyAlias { .. } => { + unreachable!() + } + }, // N.B. Tuple ctors are unconditionally constant. Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(), _ => bug!("const_conditions called on wrong item: {def_id:?}"), @@ -1017,7 +1024,7 @@ pub(super) fn const_conditions<'tcx>( } } -pub(super) fn implied_const_bounds<'tcx>( +pub(super) fn explicit_implied_const_bounds<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> { @@ -1033,10 +1040,11 @@ pub(super) fn implied_const_bounds<'tcx>( PredicateFilter::SelfConstIfConst, ) } - Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) => { + Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) + | Node::OpaqueTy(_) => { explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst) } - _ => bug!("implied_const_bounds called on wrong item: {def_id:?}"), + _ => bug!("explicit_implied_const_bounds called on wrong item: {def_id:?}"), }; bounds.map_bound(|bounds| { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index cc55f57c46c..b4b3ef31f97 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -177,6 +177,7 @@ enum Scope<'a> { LateBoundary { s: ScopeRef<'a>, what: &'static str, + deny_late_regions: bool, }, Root { @@ -234,9 +235,11 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { .field("s", &"..") .finish(), Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(), - Scope::LateBoundary { s: _, what } => { - f.debug_struct("LateBoundary").field("what", what).finish() - } + Scope::LateBoundary { s: _, what, deny_late_regions } => f + .debug_struct("LateBoundary") + .field("what", what) + .field("deny_late_regions", deny_late_regions) + .finish(), Scope::Root { opt_parent_item } => { f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish() } @@ -573,17 +576,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // give, we will reverse the IndexMap after early captures. let mut late_depth = 0; let mut scope = self.scope; - let mut crossed_late_boundary = None; let mut opaque_capture_scopes = vec![(opaque.def_id, &captures)]; loop { match *scope { Scope::Binder { ref bound_vars, scope_type, s, .. } => { for (&original_lifetime, &def) in bound_vars.iter().rev() { - if let ResolvedArg::LateBound(..) = def - && crossed_late_boundary.is_some() - { - continue; - } if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) { let def = def.shifted(late_depth); let ident = lifetime_ident(original_lifetime); @@ -624,12 +621,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => { - scope = s; - } - - Scope::LateBoundary { s, what, .. } => { - crossed_late_boundary = Some(what); + | Scope::TraitRefBoundary { s, .. } + | Scope::LateBoundary { s, .. } => { scope = s; } } @@ -640,7 +633,16 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope }; self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque)) + this.with(scope, |this| { + let scope = Scope::LateBoundary { + s: this.scope, + what: "nested `impl Trait`", + // We can capture late-bound regions; we just don't duplicate + // lifetime or const params, so we can't allow those. + deny_late_regions: false, + }; + this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque)) + }) }); let captures = captures.into_inner().into_iter().collect(); @@ -997,9 +999,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { - self.with(Scope::LateBoundary { s: self.scope, what: "constant" }, |this| { - intravisit::walk_anon_const(this, c); - }); + self.with( + Scope::LateBoundary { s: self.scope, what: "constant", deny_late_regions: true }, + |this| { + intravisit::walk_anon_const(this, c); + }, + ); } fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) { @@ -1291,8 +1296,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { scope = s; } - Scope::LateBoundary { s, what } => { - crossed_late_boundary = Some(what); + Scope::LateBoundary { s, what, deny_late_regions } => { + if deny_late_regions { + crossed_late_boundary = Some(what); + } scope = s; } } @@ -1508,7 +1515,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { scope = s; } - Scope::LateBoundary { s, what } => { + Scope::LateBoundary { s, what, deny_late_regions: _ } => { crossed_late_boundary = Some(what); scope = s; } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index a92a5e4278c..07d3273b09c 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1153,6 +1153,16 @@ pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> { pub return_ty: Ty<'tcx>, } +#[derive(LintDiagnostic)] +#[diag(hir_analysis_rpitit_refined_lifetimes)] +#[note] +#[note(hir_analysis_feedback_note)] +pub(crate) struct ReturnPositionImplTraitInTraitRefinedLifetimes { + #[suggestion(applicability = "maybe-incorrect", code = "{suggestion}")] + pub suggestion_span: Span, + pub suggestion: String, +} + #[derive(Diagnostic)] #[diag(hir_analysis_inherent_ty_outside, code = E0390)] #[help] 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/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 92f38a7dde0..39471931461 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -3,7 +3,7 @@ use rustc_errors::{DiagCtxtHandle, E0781, struct_span_code_err}; use rustc_hir::{self as hir, HirId}; use rustc_middle::bug; use rustc_middle::ty::layout::LayoutError; -use rustc_middle::ty::{self, ParamEnv, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use crate::errors; @@ -130,7 +130,7 @@ fn is_valid_cmse_inputs<'tcx>( let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig); for (index, ty) in fn_sig.inputs().iter().enumerate() { - let layout = tcx.layout_of(ParamEnv::reveal_all().and(*ty))?; + let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty))?; let align = layout.layout.align().abi.bytes(); let size = layout.layout.size().bytes(); @@ -158,8 +158,10 @@ fn is_valid_cmse_output<'tcx>( // this type is only used for layout computation, which does not rely on regions let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig); + let typing_env = ty::TypingEnv::fully_monomorphized(); + let mut ret_ty = fn_sig.output(); - let layout = tcx.layout_of(ParamEnv::reveal_all().and(ret_ty))?; + let layout = tcx.layout_of(typing_env.as_query_input(ret_ty))?; let size = layout.layout.size().bytes(); if size <= 4 { @@ -182,7 +184,7 @@ fn is_valid_cmse_output<'tcx>( for variant_def in adt_def.variants() { for field_def in variant_def.fields.iter() { let ty = field_def.ty(tcx, args); - let layout = tcx.layout_of(ParamEnv::reveal_all().and(ty))?; + let layout = tcx.layout_of(typing_env.as_query_input(ty))?; if !layout.layout.is_1zst() { ret_ty = ty; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index dd0f250a8e2..4e5a8271e9e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -1106,7 +1106,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .collect::<String>() ), [(only, _)] => only.to_string(), - [] => "this type".to_string(), + [] => bug!("expected one segment to deny"), }; let arg_spans: Vec<Span> = segments @@ -1136,7 +1136,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { "s", ), [only] => (only.to_string(), ""), - [] => unreachable!("expected at least one generic to prohibit"), + [] => bug!("expected at least one generic to prohibit"), }; let last_span = *arg_spans.last().unwrap(); let span: MultiSpan = arg_spans.into(); 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..0a26b6776bb 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( @@ -188,8 +190,8 @@ pub fn check_crate(tcx: TyCtxt<'_>) { DefKind::Const if tcx.generics_of(item_def_id).is_empty() => { let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty()); let cid = GlobalId { instance, promoted: None }; - let param_env = ty::ParamEnv::reveal_all(); - tcx.ensure().eval_to_const_value_raw(param_env.and(cid)); + let typing_env = ty::TypingEnv::fully_monomorphized(); + tcx.ensure().eval_to_const_value_raw(typing_env.as_query_input(cid)); } _ => (), } @@ -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/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 354993513da..1610848958e 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2357,8 +2357,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Only assoc fns that return `Self` let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder(); let ret_ty = fn_sig.output(); - let ret_ty = - self.tcx.normalize_erasing_late_bound_regions(self.param_env, ret_ty); + let ret_ty = self.tcx.normalize_erasing_late_bound_regions( + self.typing_env(self.param_env), + ret_ty, + ); if !self.can_eq(self.param_env, ret_ty, adt_ty) { return None; } diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 59bef8315d8..2a00530c434 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -228,7 +228,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { } fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool { - ty.is_copy_modulo_regions(self.0.tcx, self.0.param_env) + ty.is_copy_modulo_regions(self.0.tcx, self.0.typing_env()) } fn body_owner_def_id(&self) -> LocalDefId { 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_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 50d1322eba6..961526831fb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -105,8 +105,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.erase_regions(ty) } }; - InlineAsmCtxt::new_in_fn(self.tcx, self.param_env, get_operand_ty) - .check_asm(asm, enclosing_id); + InlineAsmCtxt::new_in_fn( + self.tcx, + self.infcx.typing_env(self.param_env), + get_operand_ty, + ) + .check_asm(asm, enclosing_id); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 919e83724d7..c4c4c2f200b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2648,15 +2648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let make_sugg = |expr: &Expr<'_>, span: Span, sugg: &str| { - let needs_parens = match expr.kind { - // parenthesize if needed (Issue #46756) - hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, - // parenthesize borrows of range literals (Issue #54505) - _ if is_range_literal(expr) => true, - _ => false, - }; - - if needs_parens { + if self.needs_parentheses(expr) { ( vec![ (span.shrink_to_lo(), format!("{prefix}{sugg}(")), @@ -2869,6 +2861,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } + if self.needs_parentheses(expr) { + return Some(( + vec![ + (span, format!("{suggestion}(")), + (expr.span.shrink_to_hi(), ")".to_string()), + ], + message, + Applicability::MachineApplicable, + true, + false, + )); + } + return Some(( vec![(span, suggestion)], message, @@ -2897,6 +2902,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } + fn needs_parentheses(&self, expr: &hir::Expr<'_>) -> bool { + match expr.kind { + // parenthesize if needed (Issue #46756) + hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, + // parenthesize borrows of range literals (Issue #54505) + _ if is_range_literal(expr) => true, + _ => false, + } + } + pub(crate) fn suggest_cast( &self, err: &mut Diag<'_>, diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index a754f7fddc9..789530d35dd 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let span = tcx.hir().span(hir_id); let normalize = |ty| { let ty = self.resolve_vars_if_possible(ty); - self.tcx.normalize_erasing_regions(self.param_env, ty) + self.tcx.normalize_erasing_regions(self.typing_env(self.param_env), ty) }; let from = normalize(from); let to = normalize(to); @@ -62,7 +62,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env); + let skel = |ty| SizeSkeleton::compute(ty, tcx, self.typing_env(self.param_env)); let sk_from = skel(from); let sk_to = skel(to); trace!(?sk_from, ?sk_to); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 8772599e316..cff2aa68993 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -31,6 +31,7 @@ use rustc_span::symbol::{Ident, kw, sym}; use rustc_span::{ DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, MacroKind, Span, Symbol, edit_distance, }; +use rustc_trait_selection::error_reporting::traits::DefIdOrName; use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedNote; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -45,50 +46,6 @@ use crate::errors::{self, CandidateTraitNote, NoAssociatedItem}; use crate::{Expectation, FnCtxt}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool { - let tcx = self.tcx; - match ty.kind() { - // Not all of these (e.g., unsafe fns) implement `FnOnce`, - // so we look for these beforehand. - // FIXME(async_closures): These don't impl `FnOnce` by default. - ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(..) => true, - // If it's not a simple function, look for things which implement `FnOnce`. - _ => { - let Some(fn_once) = tcx.lang_items().fn_once_trait() else { - return false; - }; - - // This conditional prevents us from asking to call errors and unresolved types. - // It might seem that we can use `predicate_must_hold_modulo_regions`, - // but since a Dummy binder is used to fill in the FnOnce trait's arguments, - // type resolution always gives a "maybe" here. - if self.autoderef(span, ty).silence_errors().any(|(ty, _)| { - info!("check deref {:?} error", ty); - matches!(ty.kind(), ty::Error(_) | ty::Infer(_)) - }) { - return false; - } - - self.autoderef(span, ty).silence_errors().any(|(ty, _)| { - info!("check deref {:?} impl FnOnce", ty); - self.probe(|_| { - let trait_ref = - ty::TraitRef::new(tcx, fn_once, [ty, self.next_ty_var(span)]); - let poly_trait_ref = ty::Binder::dummy(trait_ref); - let obligation = Obligation::misc( - tcx, - span, - self.body_id, - self.param_env, - poly_trait_ref, - ); - self.predicate_may_hold(&obligation) - }) - }) - } - } - } - fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool { self.autoderef(span, ty) .silence_errors() @@ -2367,12 +2324,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let is_accessible = field.vis.is_accessible_from(scope, tcx); if is_accessible { - if self.is_fn_ty(field_ty, span) { + if let Some((what, _, _)) = self.extract_callable_info(field_ty) { + let what = match what { + DefIdOrName::DefId(def_id) => self.tcx.def_descr(def_id), + DefIdOrName::Name(what) => what, + }; let expr_span = expr.span.to(item_name.span); err.multipart_suggestion( format!( - "to call the function stored in `{item_name}`, \ - surround the field access with parentheses", + "to call the {what} stored in `{item_name}`, \ + surround the field access with parentheses", ), vec![ (expr_span.shrink_to_lo(), '('.to_string()), diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 175fca327f3..d50eff0deb0 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -1257,7 +1257,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Option<FxIndexSet<UpvarMigrationInfo>> { let ty = self.resolve_vars_if_possible(self.node_ty(var_hir_id)); - if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id)) { + // FIXME(#132279): Using `non_body_analysis` here feels wrong. + if !ty.has_significant_drop( + self.tcx, + ty::TypingEnv::non_body_analysis(self.tcx, closure_def_id), + ) { debug!("does not have significant drop"); return None; } @@ -1535,8 +1539,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_path_ty: Ty<'tcx>, captured_by_move_projs: Vec<&[Projection<'tcx>]>, ) -> bool { - let needs_drop = - |ty: Ty<'tcx>| ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id)); + // FIXME(#132279): Using `non_body_analysis` here feels wrong. + let needs_drop = |ty: Ty<'tcx>| { + ty.has_significant_drop( + self.tcx, + ty::TypingEnv::non_body_analysis(self.tcx, closure_def_id), + ) + }; let is_drop_defined_for_ty = |ty: Ty<'tcx>| { let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, Some(closure_span)); diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 391e640f8bc..2f436ce77a4 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -831,8 +831,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { // Normalize consts in writeback, because GCE doesn't normalize eagerly. if tcx.features().generic_const_exprs() { - value = - value.fold_with(&mut EagerlyNormalizeConsts { tcx, param_env: self.fcx.param_env }); + value = value.fold_with(&mut EagerlyNormalizeConsts::new(self.fcx)); } value @@ -873,14 +872,22 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> { struct EagerlyNormalizeConsts<'tcx> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, } +impl<'tcx> EagerlyNormalizeConsts<'tcx> { + fn new(fcx: &FnCtxt<'_, 'tcx>) -> Self { + // FIXME(#132279, generic_const_exprs): Using `try_normalize_erasing_regions` here + // means we can't handle opaque types in their defining scope. + EagerlyNormalizeConsts { tcx: fcx.tcx, typing_env: fcx.typing_env(fcx.param_env) } + } +} + impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerlyNormalizeConsts<'tcx> { fn cx(&self) -> TyCtxt<'tcx> { self.tcx } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - self.tcx.try_normalize_erasing_regions(self.param_env, ct).unwrap_or(ct) + self.tcx.try_normalize_erasing_regions(self.typing_env, ct).unwrap_or(ct) } } diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index c2b9cae680b..a9239489222 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -460,6 +460,10 @@ impl<T: Idx> ChunkedBitSet<T> { self.chunks.iter().map(|chunk| chunk.count()).sum() } + pub fn is_empty(&self) -> bool { + self.chunks.iter().all(|chunk| matches!(chunk, Chunk::Zeros(..) | Chunk::Ones(0))) + } + /// Returns `true` if `self` contains `elem`. #[inline] pub fn contains(&self, elem: T) -> bool { @@ -668,12 +672,140 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> { changed } - fn subtract(&mut self, _other: &ChunkedBitSet<T>) -> bool { - unimplemented!("implement if/when necessary"); + fn subtract(&mut self, other: &ChunkedBitSet<T>) -> bool { + assert_eq!(self.domain_size, other.domain_size); + debug_assert_eq!(self.chunks.len(), other.chunks.len()); + + let mut changed = false; + for (mut self_chunk, other_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) { + match (&mut self_chunk, &other_chunk) { + (Zeros(..), _) | (_, Zeros(..)) => {} + ( + Ones(self_chunk_domain_size) | Mixed(self_chunk_domain_size, _, _), + Ones(other_chunk_domain_size), + ) => { + debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size); + changed = true; + *self_chunk = Zeros(*self_chunk_domain_size); + } + ( + Ones(self_chunk_domain_size), + Mixed(other_chunk_domain_size, other_chunk_count, other_chunk_words), + ) => { + debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size); + changed = true; + let num_words = num_words(*self_chunk_domain_size as usize); + debug_assert!(num_words > 0 && num_words <= CHUNK_WORDS); + let mut tail_mask = + 1 << (*other_chunk_domain_size - ((num_words - 1) * WORD_BITS) as u16) - 1; + let mut self_chunk_words = **other_chunk_words; + for word in self_chunk_words[0..num_words].iter_mut().rev() { + *word = !*word & tail_mask; + tail_mask = u64::MAX; + } + let self_chunk_count = *self_chunk_domain_size - *other_chunk_count; + debug_assert_eq!( + self_chunk_count, + self_chunk_words[0..num_words] + .iter() + .map(|w| w.count_ones() as ChunkSize) + .sum() + ); + *self_chunk = + Mixed(*self_chunk_domain_size, self_chunk_count, Rc::new(self_chunk_words)); + } + ( + Mixed( + self_chunk_domain_size, + ref mut self_chunk_count, + ref mut self_chunk_words, + ), + Mixed(_other_chunk_domain_size, _other_chunk_count, other_chunk_words), + ) => { + // See [`<Self as BitRelations<ChunkedBitSet<T>>>::union`] for the explanation + let op = |a: u64, b: u64| a & !b; + let num_words = num_words(*self_chunk_domain_size as usize); + if bitwise_changes( + &self_chunk_words[0..num_words], + &other_chunk_words[0..num_words], + op, + ) { + let self_chunk_words = Rc::make_mut(self_chunk_words); + let has_changed = bitwise( + &mut self_chunk_words[0..num_words], + &other_chunk_words[0..num_words], + op, + ); + debug_assert!(has_changed); + *self_chunk_count = self_chunk_words[0..num_words] + .iter() + .map(|w| w.count_ones() as ChunkSize) + .sum(); + if *self_chunk_count == 0 { + *self_chunk = Zeros(*self_chunk_domain_size); + } + changed = true; + } + } + } + } + changed } - fn intersect(&mut self, _other: &ChunkedBitSet<T>) -> bool { - unimplemented!("implement if/when necessary"); + fn intersect(&mut self, other: &ChunkedBitSet<T>) -> bool { + assert_eq!(self.domain_size, other.domain_size); + debug_assert_eq!(self.chunks.len(), other.chunks.len()); + + let mut changed = false; + for (mut self_chunk, other_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) { + match (&mut self_chunk, &other_chunk) { + (Zeros(..), _) | (_, Ones(..)) => {} + ( + Ones(self_chunk_domain_size), + Zeros(other_chunk_domain_size) | Mixed(other_chunk_domain_size, ..), + ) + | (Mixed(self_chunk_domain_size, ..), Zeros(other_chunk_domain_size)) => { + debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size); + changed = true; + *self_chunk = other_chunk.clone(); + } + ( + Mixed( + self_chunk_domain_size, + ref mut self_chunk_count, + ref mut self_chunk_words, + ), + Mixed(_other_chunk_domain_size, _other_chunk_count, other_chunk_words), + ) => { + // See [`<Self as BitRelations<ChunkedBitSet<T>>>::union`] for the explanation + let op = |a, b| a & b; + let num_words = num_words(*self_chunk_domain_size as usize); + if bitwise_changes( + &self_chunk_words[0..num_words], + &other_chunk_words[0..num_words], + op, + ) { + let self_chunk_words = Rc::make_mut(self_chunk_words); + let has_changed = bitwise( + &mut self_chunk_words[0..num_words], + &other_chunk_words[0..num_words], + op, + ); + debug_assert!(has_changed); + *self_chunk_count = self_chunk_words[0..num_words] + .iter() + .map(|w| w.count_ones() as ChunkSize) + .sum(); + if *self_chunk_count == 0 { + *self_chunk = Zeros(*self_chunk_domain_size); + } + changed = true; + } + } + } + } + + changed } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 12df4a10e63..b29dc7f909d 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -38,7 +38,8 @@ use rustc_middle::ty::fold::{ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef, - GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode, + GenericParamDefKind, InferConst, IntVid, PseudoCanonicalInput, Ty, TyCtxt, TyVid, + TypeVisitable, TypingEnv, TypingMode, }; use rustc_span::Span; use rustc_span::symbol::Symbol; @@ -565,6 +566,13 @@ impl<'tcx> InferCtxtBuilder<'tcx> { (infcx, value, args) } + pub fn build_with_typing_env( + mut self, + TypingEnv { typing_mode, param_env }: TypingEnv<'tcx>, + ) -> (InferCtxt<'tcx>, ty::ParamEnv<'tcx>) { + (self.build(typing_mode), param_env) + } + pub fn build(&mut self, typing_mode: TypingMode<'tcx>) -> InferCtxt<'tcx> { let InferCtxtBuilder { tcx, considering_regions, skip_leak_check, next_trait_solver } = *self; @@ -1278,6 +1286,42 @@ impl<'tcx> InferCtxt<'tcx> { u } + /// Extract [`ty::TypingMode`] of this inference context to get a `TypingEnv` + /// which contains the necessary information to use the trait system without + /// using canonicalization or carrying this inference context around. + pub fn typing_env(&self, param_env: ty::ParamEnv<'tcx>) -> ty::TypingEnv<'tcx> { + let typing_mode = match self.typing_mode(param_env) { + ty::TypingMode::Coherence => ty::TypingMode::Coherence, + // FIXME(#132279): This erases the `defining_opaque_types` as it isn't possible + // to handle them without proper canonicalization. This means we may cause cycle + // errors and fail to reveal opaques while inside of bodies. We should rename this + // function and require explicit comments on all use-sites in the future. + ty::TypingMode::Analysis { defining_opaque_types: _ } => { + TypingMode::non_body_analysis() + } + ty::TypingMode::PostAnalysis => ty::TypingMode::PostAnalysis, + }; + ty::TypingEnv { typing_mode, param_env } + } + + /// Similar to [`Self::canonicalize_query`], except that it returns + /// a [`PseudoCanonicalInput`] and requires both the `value` and the + /// `param_env` to not contain any inference variables or placeholders. + pub fn pseudo_canonicalize_query<V>( + &self, + param_env: ty::ParamEnv<'tcx>, + value: V, + ) -> PseudoCanonicalInput<'tcx, V> + where + V: TypeVisitable<TyCtxt<'tcx>>, + { + debug_assert!(!value.has_infer()); + debug_assert!(!value.has_placeholders()); + debug_assert!(!param_env.has_infer()); + debug_assert!(!param_env.has_placeholders()); + self.typing_env(param_env).as_query_input(value) + } + /// The returned function is used in a fast path. If it returns `true` the variable is /// unchanged, `false` indicates that the status is unknown. #[inline] diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index d65ed72a8e8..0aff4620314 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -574,9 +574,8 @@ impl<'tcx> InferCtxt<'tcx> { // unexpected region errors. goals.push(Goal::new(tcx, param_env, ty::ClauseKind::WellFormed(hidden_ty.into()))); - let item_bounds = tcx.explicit_item_bounds(def_id); - for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) { - let predicate = predicate.fold_with(&mut BottomUpFolder { + let replace_opaques_in = |clause: ty::Clause<'tcx>, goals: &mut Vec<_>| { + clause.fold_with(&mut BottomUpFolder { tcx, ty_op: |ty| match *ty.kind() { // We can't normalize associated types from `rustc_infer`, @@ -612,11 +611,31 @@ impl<'tcx> InferCtxt<'tcx> { }, lt_op: |lt| lt, ct_op: |ct| ct, - }); + }) + }; + + let item_bounds = tcx.explicit_item_bounds(def_id); + for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) { + let predicate = replace_opaques_in(predicate, goals); // Require that the predicate holds for the concrete type. debug!(?predicate); goals.push(Goal::new(self.tcx, param_env, predicate)); } + + // If this opaque is being defined and it's conditionally const, + if self.tcx.is_conditionally_const(def_id) { + let item_bounds = tcx.explicit_implied_const_bounds(def_id); + for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) { + let predicate = replace_opaques_in( + predicate.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe), + goals, + ); + + // Require that the predicate holds for the concrete type. + debug!(?predicate); + goals.push(Goal::new(self.tcx, param_env, predicate)); + } + } } } 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/messages.ftl b/compiler/rustc_lint/messages.ftl index 6e35d89b488..69fd7f2d8b2 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -772,9 +772,6 @@ lint_suspicious_double_ref_clone = lint_suspicious_double_ref_deref = using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type -lint_tail_expr_drop_order = these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 - .label = these values have significant drop implementation and will observe changes in drop order under Edition 2024 - lint_trailing_semi_macro = trailing semicolon in macro used in expression position .note1 = macro invocations at the end of a block are treated as expressions .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}` diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 130f3cb7c2a..bda982a3675 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -32,7 +32,7 @@ use rustc_middle::bug; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, VariantDef}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef}; use rustc_session::lint::FutureIncompatibilityReason; // hardwired lints from rustc_lint_defs pub use rustc_session::lint::builtin::*; @@ -586,10 +586,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { return; } } - if ty.is_copy_modulo_regions(cx.tcx, cx.param_env) { + if ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()) { return; } - if type_implements_negative_copy_modulo_regions(cx.tcx, ty, cx.param_env) { + if type_implements_negative_copy_modulo_regions(cx.tcx, ty, cx.typing_env()) { return; } if def.is_variant_list_non_exhaustive() @@ -637,8 +637,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { fn type_implements_negative_copy_modulo_regions<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> bool { + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, None), [ty]); let pred = ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Negative }; let obligation = traits::Obligation { @@ -647,10 +648,7 @@ fn type_implements_negative_copy_modulo_regions<'tcx>( recursion_depth: 0, predicate: pred.upcast(tcx), }; - - tcx.infer_ctxt() - .build(TypingMode::non_body_analysis()) - .predicate_must_hold_modulo_regions(&obligation) + infcx.predicate_must_hold_modulo_regions(&obligation) } declare_lint! { @@ -2485,7 +2483,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { }); // Check if this ADT has a constrained layout (like `NonNull` and friends). - if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) { + if let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty)) { if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) = &layout.backend_repr { @@ -2521,7 +2519,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { ty: Ty<'tcx>, init: InitKind, ) -> Option<InitError> { - let ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty); + let ty = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty).unwrap_or(ty); use rustc_type_ir::TyKind::*; match ty.kind() { @@ -2568,7 +2566,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { let definitely_inhabited = match variant .inhabited_predicate(cx.tcx, *adt_def) .instantiate(cx.tcx, args) - .apply_any_module(cx.tcx, cx.param_env) + .apply_any_module(cx.tcx, cx.typing_env()) { // Entirely skip uninhabited variants. Some(false) => return None, diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index aa7ec2659d0..6eec32beab0 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -19,7 +19,7 @@ use rustc_middle::bug; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths}; -use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode}; use rustc_session::lint::{ BuiltinLintDiag, FutureIncompatibleInfo, Level, Lint, LintBuffer, LintExpectationId, LintId, }; @@ -708,6 +708,10 @@ impl<'tcx> LateContext<'tcx> { TypingMode::non_body_analysis() } + pub fn typing_env(&self) -> TypingEnv<'tcx> { + TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env } + } + /// Gets the type-checking results for the current body, /// or `None` if outside a body. pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> { @@ -906,7 +910,7 @@ impl<'tcx> LateContext<'tcx> { .find_by_name_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id) .and_then(|assoc| { let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]); - tcx.try_normalize_erasing_regions(self.param_env, proj).ok() + tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok() }) } @@ -1010,10 +1014,10 @@ impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> { } } -impl<'tcx> ty::layout::HasParamEnv<'tcx> for LateContext<'tcx> { +impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> { #[inline] - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + self.typing_env() } } diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index a34c3e26778..e3e51ba263d 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -43,13 +43,10 @@ declare_lint! { } /// FIXME: false negatives (i.e. the lint is not emitted when it should be) -/// 1. Method calls that are not checked for: -/// - [`temporary_unsafe_cell.get()`][`core::cell::UnsafeCell::get()`] -/// - [`temporary_sync_unsafe_cell.get()`][`core::cell::SyncUnsafeCell::get()`] -/// 2. Ways to get a temporary that are not recognized: +/// 1. Ways to get a temporary that are not recognized: /// - `owning_temporary.field` /// - `owning_temporary[index]` -/// 3. No checks for ref-to-ptr conversions: +/// 2. No checks for ref-to-ptr conversions: /// - `&raw [mut] temporary` /// - `&temporary as *(const|mut) _` /// - `ptr::from_ref(&temporary)` and friends @@ -133,10 +130,11 @@ impl DanglingPointerSearcher<'_, '_> { fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind - && matches!(method.ident.name, sym::as_ptr | sym::as_mut_ptr) + && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && cx.tcx.has_attr(fn_id, sym::rustc_as_ptr) && is_temporary_rvalue(receiver) && let ty = cx.typeck_results().expr_ty(receiver) - && is_interesting(cx.tcx, ty) + && owns_allocation(cx.tcx, ty) { // FIXME: use `emit_node_lint` when `#[primary_span]` is added. cx.tcx.emit_node_span_lint( @@ -199,24 +197,25 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool { } } -// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>, -// or any of the above in arbitrary many nested Box'es. -fn is_interesting(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { +// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>, UnsafeCell, +// SyncUnsafeCell, or any of the above in arbitrary many nested Box'es. +fn owns_allocation(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { if ty.is_array() { true } else if let Some(inner) = ty.boxed_ty() { inner.is_slice() || inner.is_str() || inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr)) - || is_interesting(tcx, inner) + || owns_allocation(tcx, inner) } else if let Some(def) = ty.ty_adt_def() { - for lang_item in [LangItem::String, LangItem::MaybeUninit] { + for lang_item in [LangItem::String, LangItem::MaybeUninit, LangItem::UnsafeCell] { if tcx.is_lang_item(def.did(), lang_item) { return true; } } - tcx.get_diagnostic_name(def.did()) - .is_some_and(|name| matches!(name, sym::cstring_type | sym::Vec | sym::Cell)) + tcx.get_diagnostic_name(def.did()).is_some_and(|name| { + matches!(name, sym::cstring_type | sym::Vec | sym::Cell | sym::SyncUnsafeCell) + }) } else { false } diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs index 364c6fd488a..8fe86738658 100644 --- a/compiler/rustc_lint/src/drop_forget_useless.rs +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { && let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id) { let arg_ty = cx.typeck_results().expr_ty(arg); - let is_copy = arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env); + let is_copy = arg_ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()); let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); let let_underscore_ignore_sugg = || { if let Some((_, node)) = cx.tcx.hir().parent_iter(expr.hir_id).nth(0) diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index acccff77a10..4f3184f1d7c 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -68,6 +68,10 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { } impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> { + fn visit_coroutine_kind(&mut self, coroutine_kind: &'a ast::CoroutineKind) -> Self::Result { + self.check_id(coroutine_kind.closure_id()); + } + fn visit_param(&mut self, param: &'a ast::Param) { self.with_lint_attrs(param.id, ¶m.attrs, |cx| { lint_callback!(cx, check_param, param); @@ -111,17 +115,6 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> self.with_lint_attrs(e.id, &e.attrs, |cx| { lint_callback!(cx, check_expr, e); ast_visit::walk_expr(cx, e); - // Explicitly check for lints associated with 'closure_id', since - // it does not have a corresponding AST node - match e.kind { - ast::ExprKind::Closure(box ast::Closure { - coroutine_kind: Some(coroutine_kind), - .. - }) => { - cx.check_id(coroutine_kind.closure_id()); - } - _ => {} - } lint_callback!(cx, check_expr_post, e); }) } @@ -156,14 +149,6 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> lint_callback!(self, check_fn, fk, span, id); self.check_id(id); ast_visit::walk_fn(self, fk); - - // Explicitly check for lints associated with 'closure_id', since - // it does not have a corresponding AST node - if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk { - if let Some(coroutine_kind) = sig.header.coroutine_kind { - self.check_id(coroutine_kind.closure_id()); - } - } } fn visit_variant_data(&mut self, s: &'a ast::VariantData) { @@ -245,15 +230,16 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> } fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: ast_visit::AssocCtxt) { - self.with_lint_attrs(item.id, &item.attrs, |cx| match ctxt { - ast_visit::AssocCtxt::Trait => { - lint_callback!(cx, check_trait_item, item); - ast_visit::walk_assoc_item(cx, item, ctxt); - } - ast_visit::AssocCtxt::Impl => { - lint_callback!(cx, check_impl_item, item); - ast_visit::walk_assoc_item(cx, item, ctxt); + self.with_lint_attrs(item.id, &item.attrs, |cx| { + match ctxt { + ast_visit::AssocCtxt::Trait => { + lint_callback!(cx, check_trait_item, item); + } + ast_visit::AssocCtxt::Impl => { + lint_callback!(cx, check_impl_item, item); + } } + ast_visit::walk_assoc_item(cx, item, ctxt); }); } diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index cf68e41243f..dbc920ea5ae 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -166,7 +166,7 @@ fn suggest_question_mark<'tcx>( } let ty = args.type_at(0); - let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); + let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(cx.typing_env()); let ocx = ObligationCtxt::new(&infcx); let body_def_id = cx.tcx.hir().body_owner_def_id(body_id); @@ -175,7 +175,7 @@ fn suggest_question_mark<'tcx>( ocx.register_bound( cause, - cx.param_env, + param_env, // Erase any region vids from the type, which may not be resolved infcx.tcx.erase_regions(ty), into_iterator_did, diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 394ea798d3e..45b188205d2 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -131,7 +131,7 @@ impl ClashingExternDeclarations { // Check that the declarations match. if !structurally_same_type( tcx, - tcx.param_env(this_fi.owner_id), + ty::TypingEnv::non_body_analysis(tcx, this_fi.owner_id), existing_decl_ty, this_decl_ty, types::CItemKind::Declaration, @@ -205,18 +205,18 @@ fn get_relevant_span(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> Span { /// with the same members (as the declarations shouldn't clash). fn structurally_same_type<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>, ckind: types::CItemKind, ) -> bool { let mut seen_types = UnordSet::default(); - let result = structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind); + let result = structurally_same_type_impl(&mut seen_types, tcx, typing_env, a, b, ckind); if cfg!(debug_assertions) && result { // Sanity-check: must have same ABI, size and alignment. // `extern` blocks cannot be generic, so we'll always get a layout here. - let a_layout = tcx.layout_of(param_env.and(a)).unwrap(); - let b_layout = tcx.layout_of(param_env.and(b)).unwrap(); + let a_layout = tcx.layout_of(typing_env.as_query_input(a)).unwrap(); + let b_layout = tcx.layout_of(typing_env.as_query_input(b)).unwrap(); assert_eq!(a_layout.backend_repr, b_layout.backend_repr); assert_eq!(a_layout.size, b_layout.size); assert_eq!(a_layout.align, b_layout.align); @@ -227,7 +227,7 @@ fn structurally_same_type<'tcx>( fn structurally_same_type_impl<'tcx>( seen_types: &mut UnordSet<(Ty<'tcx>, Ty<'tcx>)>, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>, ckind: types::CItemKind, @@ -303,7 +303,7 @@ fn structurally_same_type_impl<'tcx>( structurally_same_type_impl( seen_types, tcx, - param_env, + typing_env, tcx.type_of(a_did).instantiate(tcx, a_gen_args), tcx.type_of(b_did).instantiate(tcx, b_gen_args), ckind, @@ -315,23 +315,23 @@ fn structurally_same_type_impl<'tcx>( // For arrays, we also check the length. a_len == b_len && structurally_same_type_impl( - seen_types, tcx, param_env, *a_ty, *b_ty, ckind, + seen_types, tcx, typing_env, *a_ty, *b_ty, ckind, ) } (Slice(a_ty), Slice(b_ty)) => { - structurally_same_type_impl(seen_types, tcx, param_env, *a_ty, *b_ty, ckind) + structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty, ckind) } (RawPtr(a_ty, a_mutbl), RawPtr(b_ty, b_mutbl)) => { a_mutbl == b_mutbl && structurally_same_type_impl( - seen_types, tcx, param_env, *a_ty, *b_ty, ckind, + seen_types, tcx, typing_env, *a_ty, *b_ty, ckind, ) } (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => { // For structural sameness, we don't need the region to be same. a_mut == b_mut && structurally_same_type_impl( - seen_types, tcx, param_env, *a_ty, *b_ty, ckind, + seen_types, tcx, typing_env, *a_ty, *b_ty, ckind, ) } (FnDef(..), FnDef(..)) => { @@ -346,12 +346,12 @@ fn structurally_same_type_impl<'tcx>( (a_sig.abi, a_sig.safety, a_sig.c_variadic) == (b_sig.abi, b_sig.safety, b_sig.c_variadic) && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| { - structurally_same_type_impl(seen_types, tcx, param_env, *a, *b, ckind) + structurally_same_type_impl(seen_types, tcx, typing_env, *a, *b, ckind) }) && structurally_same_type_impl( seen_types, tcx, - param_env, + typing_env, a_sig.output(), b_sig.output(), ckind, @@ -379,14 +379,14 @@ fn structurally_same_type_impl<'tcx>( // An Adt and a primitive or pointer type. This can be FFI-safe if non-null // enum layout optimisation is being applied. (Adt(..), _) if is_primitive_or_pointer(b) => { - if let Some(a_inner) = types::repr_nullable_ptr(tcx, param_env, a, ckind) { + if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a, ckind) { a_inner == b } else { false } } (_, Adt(..)) if is_primitive_or_pointer(a) => { - if let Some(b_inner) = types::repr_nullable_ptr(tcx, param_env, b, ckind) { + if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b, ckind) { b_inner == a } else { false diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index afcfbebc14b..0e874669043 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -368,7 +368,7 @@ impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> { .cx .typeck_results() .expr_ty(expr) - .has_significant_drop(self.cx.tcx, self.cx.param_env) + .has_significant_drop(self.cx.tcx, self.cx.typing_env()) { return ControlFlow::Break(expr.span); } diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 036e0381a06..1aacdbd448c 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::relate::{ Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys, }; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::FutureIncompatibilityReason; @@ -186,8 +186,8 @@ fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) { functional_variances.variances }), outlives_env: LazyCell::new(|| { - let param_env = tcx.param_env(parent_def_id); - let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); + let typing_env = ty::TypingEnv::non_body_analysis(tcx, parent_def_id); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); let ocx = ObligationCtxt::new(&infcx); let assumed_wf_tys = ocx.assumed_wf_types(param_env, parent_def_id).unwrap_or_default(); let implied_bounds = @@ -262,7 +262,11 @@ where // If it's owned by this function && let opaque = self.tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty() - && let hir::OpaqueTyOrigin::FnReturn { parent, .. } = opaque.origin + // We want to recurse into RPITs and async fns, even though the latter + // doesn't overcapture on its own, it may mention additional RPITs + // in its bounds. + && let hir::OpaqueTyOrigin::FnReturn { parent, .. } + | hir::OpaqueTyOrigin::AsyncFn { parent, .. } = opaque.origin && parent == self.parent_def_id { let opaque_span = self.tcx.def_span(opaque_def_id); diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 2f338f42f19..38c38b59bc5 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -103,7 +103,8 @@ declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY, UNTRACKED_QUE impl LateLintPass<'_> for QueryStability { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { let Some((span, def_id, args)) = typeck_results_of_method_fn(cx, expr) else { return }; - if let Ok(Some(instance)) = ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, args) { + if let Ok(Some(instance)) = ty::Instance::try_resolve(cx.tcx, cx.typing_env(), def_id, args) + { let def_id = instance.def_id(); if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) { cx.emit_span_lint(POTENTIAL_QUERY_INSTABILITY, span, QueryInstability { @@ -544,7 +545,7 @@ impl Diagnostics { ) { // Is the callee marked with `#[rustc_lint_diagnostics]`? let Some(inst) = - ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, fn_gen_args).ok().flatten() + ty::Instance::try_resolve(cx.tcx, cx.typing_env(), def_id, fn_gen_args).ok().flatten() else { return; }; diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index abee9ee7869..9e4e8333164 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { // If the type has a trivial Drop implementation, then it doesn't // matter that we drop the value immediately. - if !ty.needs_drop(cx.tcx, cx.param_env) { + if !ty.needs_drop(cx.tcx, cx.typing_env()) { return; } // Lint for patterns like `mutex.lock()`, which returns `Result<MutexGuard, _>` as well. diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 97a95787422..4b1dafbdbee 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -123,17 +123,19 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> { let dont_need_to_run: FxIndexSet<LintId> = store .get_lints() .into_iter() + .filter(|lint| { + // Lints that show up in future-compat reports must always be run. + let has_future_breakage = + lint.future_incompatible.is_some_and(|fut| fut.reason.has_future_breakage()); + !has_future_breakage && !lint.eval_always + }) .filter_map(|lint| { - if !lint.eval_always { - let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID); - if matches!(lint_level, (Level::Allow, ..)) - || (matches!(lint_level, (.., LintLevelSource::Default))) - && lint.default_level(tcx.sess.edition()) == Level::Allow - { - Some(LintId::of(lint)) - } else { - None - } + let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID); + if matches!(lint_level, (Level::Allow, ..)) + || (matches!(lint_level, (.., LintLevelSource::Default))) + && lint.default_level(tcx.sess.edition()) == Level::Allow + { + Some(LintId::of(lint)) } else { None } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 86112277504..4cf5c7b4ff9 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -75,7 +75,6 @@ mod redundant_semicolon; mod reference_casting; mod shadowed_into_iter; mod static_mut_refs; -mod tail_expr_drop_order; mod traits; mod types; mod unit_bindings; @@ -116,7 +115,6 @@ use rustc_middle::ty::TyCtxt; use shadowed_into_iter::ShadowedIntoIter; pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; use static_mut_refs::*; -use tail_expr_drop_order::TailExprDropOrder; use traits::*; use types::*; use unit_bindings::*; @@ -240,7 +238,6 @@ late_lint_methods!( AsyncFnInTrait: AsyncFnInTrait, NonLocalDefinitions: NonLocalDefinitions::default(), ImplTraitOvercaptures: ImplTraitOvercaptures, - TailExprDropOrder: TailExprDropOrder, IfLetRescope: IfLetRescope::default(), StaticMutRefs: StaticMutRefs, UnqualifiedLocalImports: UnqualifiedLocalImports, diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index cf25ec99e67..36b1ff59c67 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -157,15 +157,17 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc Some(ty_def) if cx.tcx.is_lang_item(ty_def.did(), LangItem::String), ); - let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); + let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(cx.typing_env()); let suggest_display = is_str - || cx.tcx.get_diagnostic_item(sym::Display).is_some_and(|t| { - infcx.type_implements_trait(t, [ty], cx.param_env).may_apply() - }); + || cx + .tcx + .get_diagnostic_item(sym::Display) + .is_some_and(|t| infcx.type_implements_trait(t, [ty], param_env).may_apply()); let suggest_debug = !suggest_display - && cx.tcx.get_diagnostic_item(sym::Debug).is_some_and(|t| { - infcx.type_implements_trait(t, [ty], cx.param_env).may_apply() - }); + && cx + .tcx + .get_diagnostic_item(sym::Debug) + .is_some_and(|t| infcx.type_implements_trait(t, [ty], param_env).may_apply()); let suggest_panic_any = !is_str && panic == sym::std_panic_macro; diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 4890a93fa76..76dc96ae00f 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -94,9 +94,9 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { let args = cx .tcx - .normalize_erasing_regions(cx.param_env, cx.typeck_results().node_args(expr.hir_id)); + .normalize_erasing_regions(cx.typing_env(), cx.typeck_results().node_args(expr.hir_id)); // Resolve the trait method instance. - let Ok(Some(i)) = ty::Instance::try_resolve(cx.tcx, cx.param_env, did, args) else { + let Ok(Some(i)) = ty::Instance::try_resolve(cx.tcx, cx.typing_env(), did, args) else { return; }; // (Re)check that it implements the noop diagnostic. diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 45d97403d60..7c6656f91c9 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -168,7 +168,7 @@ fn is_cast_from_ref_to_mut_ptr<'tcx>( // Except on the presence of non concrete skeleton types (ie generics) // since there is no way to make it safe for arbitrary types. let inner_ty_has_interior_mutability = - !inner_ty.is_freeze(cx.tcx, cx.param_env) && inner_ty.has_concrete_skeleton(); + !inner_ty.is_freeze(cx.tcx, cx.typing_env()) && inner_ty.has_concrete_skeleton(); (!need_check_freeze || !inner_ty_has_interior_mutability) .then_some(inner_ty_has_interior_mutability) } else { diff --git a/compiler/rustc_lint/src/tail_expr_drop_order.rs b/compiler/rustc_lint/src/tail_expr_drop_order.rs deleted file mode 100644 index 89763059877..00000000000 --- a/compiler/rustc_lint/src/tail_expr_drop_order.rs +++ /dev/null @@ -1,305 +0,0 @@ -use std::mem::swap; - -use rustc_ast::UnOp; -use rustc_hir::def::Res; -use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, Block, Expr, ExprKind, LetStmt, Pat, PatKind, QPath, StmtKind}; -use rustc_macros::LintDiagnostic; -use rustc_middle::ty; -use rustc_session::lint::FutureIncompatibilityReason; -use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::Span; -use rustc_span::edition::Edition; - -use crate::{LateContext, LateLintPass}; - -declare_lint! { - /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location, - /// that runs a custom `Drop` destructor. - /// Some of them may be dropped earlier in Edition 2024 that they used to in Edition 2021 and prior. - /// This lint detects those cases and provides you information on those values and their custom destructor implementations. - /// Your discretion on this information is required. - /// - /// ### Example - /// ```rust,edition2021 - /// #![warn(tail_expr_drop_order)] - /// struct Droppy(i32); - /// impl Droppy { - /// fn get(&self) -> i32 { - /// self.0 - /// } - /// } - /// impl Drop for Droppy { - /// fn drop(&mut self) { - /// // This is a custom destructor and it induces side-effects that is observable - /// // especially when the drop order at a tail expression changes. - /// println!("loud drop {}", self.0); - /// } - /// } - /// fn edition_2021() -> i32 { - /// let another_droppy = Droppy(0); - /// Droppy(1).get() - /// } - /// fn main() { - /// edition_2021(); - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// In tail expression of blocks or function bodies, - /// values of type with significant `Drop` implementation has an ill-specified drop order - /// before Edition 2024 so that they are dropped only after dropping local variables. - /// Edition 2024 introduces a new rule with drop orders for them, - /// so that they are dropped first before dropping local variables. - /// - /// A significant `Drop::drop` destructor here refers to an explicit, arbitrary - /// implementation of the `Drop` trait on the type, with exceptions including `Vec`, - /// `Box`, `Rc`, `BTreeMap` and `HashMap` that are marked by the compiler otherwise - /// so long that the generic types have no significant destructor recursively. - /// In other words, a type has a significant drop destructor when it has a `Drop` implementation - /// or its destructor invokes a significant destructor on a type. - /// Since we cannot completely reason about the change by just inspecting the existence of - /// a significant destructor, this lint remains only a suggestion and is set to `allow` by default. - /// - /// This lint only points out the issue with `Droppy`, which will be dropped before `another_droppy` - /// does in Edition 2024. - /// No fix will be proposed by this lint. - /// However, the most probable fix is to hoist `Droppy` into its own local variable binding. - /// ```rust - /// struct Droppy(i32); - /// impl Droppy { - /// fn get(&self) -> i32 { - /// self.0 - /// } - /// } - /// fn edition_2024() -> i32 { - /// let value = Droppy(0); - /// let another_droppy = Droppy(1); - /// value.get() - /// } - /// ``` - pub TAIL_EXPR_DROP_ORDER, - Allow, - "Detect and warn on significant change in drop order in tail expression location", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), - reference: "issue #123739 <https://github.com/rust-lang/rust/issues/123739>", - }; -} - -declare_lint_pass!(TailExprDropOrder => [TAIL_EXPR_DROP_ORDER]); - -impl TailExprDropOrder { - fn check_fn_or_closure<'tcx>( - cx: &LateContext<'tcx>, - fn_kind: hir::intravisit::FnKind<'tcx>, - body: &'tcx hir::Body<'tcx>, - def_id: rustc_span::def_id::LocalDefId, - ) { - let mut locals = vec![]; - if matches!(fn_kind, hir::intravisit::FnKind::Closure) { - for &capture in cx.tcx.closure_captures(def_id) { - if matches!(capture.info.capture_kind, ty::UpvarCapture::ByValue) - && capture.place.ty().has_significant_drop(cx.tcx, cx.param_env) - { - locals.push(capture.var_ident.span); - } - } - } - for param in body.params { - if cx - .typeck_results() - .node_type(param.hir_id) - .has_significant_drop(cx.tcx, cx.param_env) - { - locals.push(param.span); - } - } - if let hir::ExprKind::Block(block, _) = body.value.kind { - LintVisitor { cx, locals }.check_block_inner(block); - } else { - LintTailExpr { cx, locals: &locals, is_root_tail_expr: true }.visit_expr(body.value); - } - } -} - -impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder { - fn check_fn( - &mut self, - cx: &LateContext<'tcx>, - fn_kind: hir::intravisit::FnKind<'tcx>, - _: &'tcx hir::FnDecl<'tcx>, - body: &'tcx hir::Body<'tcx>, - _: Span, - def_id: rustc_span::def_id::LocalDefId, - ) { - if !body.value.span.edition().at_least_rust_2024() { - Self::check_fn_or_closure(cx, fn_kind, body, def_id); - } - } -} - -struct LintVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - // We only record locals that have significant drops - locals: Vec<Span>, -} - -struct LocalCollector<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - locals: &'a mut Vec<Span>, -} - -impl<'a, 'tcx> Visitor<'tcx> for LocalCollector<'a, 'tcx> { - type Result = (); - fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) { - if let PatKind::Binding(_binding_mode, id, ident, pat) = pat.kind { - let ty = self.cx.typeck_results().node_type(id); - if ty.has_significant_drop(self.cx.tcx, self.cx.param_env) { - self.locals.push(ident.span); - } - if let Some(pat) = pat { - self.visit_pat(pat); - } - } else { - intravisit::walk_pat(self, pat); - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for LintVisitor<'a, 'tcx> { - fn visit_block(&mut self, block: &'tcx Block<'tcx>) { - let mut locals = <_>::default(); - swap(&mut locals, &mut self.locals); - self.check_block_inner(block); - swap(&mut locals, &mut self.locals); - } - fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) { - LocalCollector { cx: self.cx, locals: &mut self.locals }.visit_local(local); - } -} - -impl<'a, 'tcx> LintVisitor<'a, 'tcx> { - fn check_block_inner(&mut self, block: &Block<'tcx>) { - if block.span.at_least_rust_2024() { - // We only lint up to Edition 2021 - return; - } - let Some(tail_expr) = block.expr else { return }; - for stmt in block.stmts { - match stmt.kind { - StmtKind::Let(let_stmt) => self.visit_local(let_stmt), - StmtKind::Item(_) => {} - StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e), - } - } - if self.locals.is_empty() { - return; - } - LintTailExpr { cx: self.cx, locals: &self.locals, is_root_tail_expr: true } - .visit_expr(tail_expr); - } -} - -struct LintTailExpr<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - is_root_tail_expr: bool, - locals: &'a [Span], -} - -impl<'a, 'tcx> LintTailExpr<'a, 'tcx> { - fn expr_eventually_point_into_local(mut expr: &Expr<'tcx>) -> bool { - loop { - match expr.kind { - ExprKind::Index(access, _, _) | ExprKind::Field(access, _) => expr = access, - ExprKind::AddrOf(_, _, referee) | ExprKind::Unary(UnOp::Deref, referee) => { - expr = referee - } - ExprKind::Path(_) - if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind - && let [local, ..] = path.segments - && let Res::Local(_) = local.res => - { - return true; - } - _ => return false, - } - } - } - - fn expr_generates_nonlocal_droppy_value(&self, expr: &Expr<'tcx>) -> bool { - if Self::expr_eventually_point_into_local(expr) { - return false; - } - self.cx.typeck_results().expr_ty(expr).has_significant_drop(self.cx.tcx, self.cx.param_env) - } -} - -impl<'a, 'tcx> Visitor<'tcx> for LintTailExpr<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if self.is_root_tail_expr { - self.is_root_tail_expr = false; - } else if self.expr_generates_nonlocal_droppy_value(expr) { - self.cx.tcx.emit_node_span_lint( - TAIL_EXPR_DROP_ORDER, - expr.hir_id, - expr.span, - TailExprDropOrderLint { spans: self.locals.to_vec() }, - ); - return; - } - match expr.kind { - ExprKind::Match(scrutinee, _, _) => self.visit_expr(scrutinee), - - ExprKind::ConstBlock(_) - | ExprKind::Array(_) - | ExprKind::Break(_, _) - | ExprKind::Continue(_) - | ExprKind::Ret(_) - | ExprKind::Become(_) - | ExprKind::Yield(_, _) - | ExprKind::InlineAsm(_) - | ExprKind::If(_, _, _) - | ExprKind::Loop(_, _, _, _) - | ExprKind::Closure(_) - | ExprKind::DropTemps(_) - | ExprKind::OffsetOf(_, _) - | ExprKind::Assign(_, _, _) - | ExprKind::AssignOp(_, _, _) - | ExprKind::Lit(_) - | ExprKind::Err(_) => {} - - ExprKind::MethodCall(_, _, _, _) - | ExprKind::Call(_, _) - | ExprKind::Type(_, _) - | ExprKind::Tup(_) - | ExprKind::Binary(_, _, _) - | ExprKind::Unary(_, _) - | ExprKind::Path(_) - | ExprKind::Let(_) - | ExprKind::Cast(_, _) - | ExprKind::Field(_, _) - | ExprKind::Index(_, _, _) - | ExprKind::AddrOf(_, _, _) - | ExprKind::Struct(_, _, _) - | ExprKind::Repeat(_, _) => intravisit::walk_expr(self, expr), - - ExprKind::Block(_, _) => { - // We do not lint further because the drop order stays the same inside the block - } - } - } - fn visit_block(&mut self, block: &'tcx Block<'tcx>) { - LintVisitor { cx: self.cx, locals: <_>::default() }.check_block_inner(block); - } -} - -#[derive(LintDiagnostic)] -#[diag(lint_tail_expr_drop_order)] -struct TailExprDropOrderLint { - #[label] - pub spans: Vec<Span>, -} diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index be70149b664..b1d7d4ab689 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -292,7 +292,7 @@ fn lint_wide_pointer<'tcx>( _ => return None, }; - (!ty.is_sized(cx.tcx, cx.param_env)) + (!ty.is_sized(cx.tcx, cx.typing_env())) .then(|| (refs, modifiers, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn)))) }; @@ -613,10 +613,11 @@ pub(crate) fn transparent_newtype_field<'a, 'tcx>( tcx: TyCtxt<'tcx>, variant: &'a ty::VariantDef, ) -> Option<&'a ty::FieldDef> { - let param_env = tcx.param_env(variant.def_id); + let typing_env = ty::TypingEnv::non_body_analysis(tcx, variant.def_id); variant.fields.iter().find(|field| { let field_ty = tcx.type_of(field.did).instantiate_identity(); - let is_1zst = tcx.layout_of(param_env.and(field_ty)).is_ok_and(|layout| layout.is_1zst()); + let is_1zst = + tcx.layout_of(typing_env.as_query_input(field_ty)).is_ok_and(|layout| layout.is_1zst()); !is_1zst }) } @@ -624,11 +625,11 @@ pub(crate) fn transparent_newtype_field<'a, 'tcx>( /// Is type known to be non-null? fn ty_is_known_nonnull<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, mode: CItemKind, ) -> bool { - let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty); + let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); match ty.kind() { ty::FnPtr(..) => true, @@ -649,7 +650,7 @@ fn ty_is_known_nonnull<'tcx>( def.variants() .iter() .filter_map(|variant| transparent_newtype_field(tcx, variant)) - .any(|field| ty_is_known_nonnull(tcx, param_env, field.ty(tcx, args), mode)) + .any(|field| ty_is_known_nonnull(tcx, typing_env, field.ty(tcx, args), mode)) } _ => false, } @@ -659,10 +660,10 @@ fn ty_is_known_nonnull<'tcx>( /// If the type passed in was not scalar, returns None. fn get_nullable_type<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, ) -> Option<Ty<'tcx>> { - let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty); + let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); Some(match *ty.kind() { ty::Adt(field_def, field_args) => { @@ -679,7 +680,7 @@ fn get_nullable_type<'tcx>( .expect("No non-zst fields in transparent type.") .ty(tcx, field_args) }; - return get_nullable_type(tcx, param_env, inner_field_ty); + return get_nullable_type(tcx, typing_env, inner_field_ty); } ty::Int(ty) => Ty::new_int(tcx, ty), ty::Uint(ty) => Ty::new_uint(tcx, ty), @@ -708,10 +709,10 @@ fn get_nullable_type<'tcx>( /// - Does not have the `#[non_exhaustive]` attribute. fn is_niche_optimization_candidate<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, ) -> bool { - if tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| !layout.is_1zst()) { + if tcx.layout_of(typing_env.as_query_input(ty)).is_ok_and(|layout| !layout.is_1zst()) { return false; } @@ -734,7 +735,7 @@ fn is_niche_optimization_candidate<'tcx>( /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes. pub(crate) fn repr_nullable_ptr<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, ckind: CItemKind, ) -> Option<Ty<'tcx>> { @@ -747,9 +748,9 @@ pub(crate) fn repr_nullable_ptr<'tcx>( let ty1 = field1.ty(tcx, args); let ty2 = field2.ty(tcx, args); - if is_niche_optimization_candidate(tcx, param_env, ty1) { + if is_niche_optimization_candidate(tcx, typing_env, ty1) { ty2 - } else if is_niche_optimization_candidate(tcx, param_env, ty2) { + } else if is_niche_optimization_candidate(tcx, typing_env, ty2) { ty1 } else { return None; @@ -760,20 +761,20 @@ pub(crate) fn repr_nullable_ptr<'tcx>( _ => return None, }; - if !ty_is_known_nonnull(tcx, param_env, field_ty, ckind) { + if !ty_is_known_nonnull(tcx, typing_env, field_ty, ckind) { return None; } // At this point, the field's type is known to be nonnull and the parent enum is Option-like. // If the computed size for the field and the enum are different, the nonnull optimization isn't // being applied (and we've got a problem somewhere). - let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, param_env).ok(); + let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, typing_env).ok(); if !compute_size_skeleton(ty)?.same_size(compute_size_skeleton(field_ty)?) { bug!("improper_ctypes: Option nonnull optimization not applied?"); } // Return the nullable type this Option-like enum can be safely represented with. - let field_ty_layout = tcx.layout_of(param_env.and(field_ty)); + let field_ty_layout = tcx.layout_of(typing_env.as_query_input(field_ty)); if field_ty_layout.is_err() && !field_ty.has_non_region_param() { bug!("should be able to compute the layout of non-polymorphic type"); } @@ -784,10 +785,10 @@ pub(crate) fn repr_nullable_ptr<'tcx>( WrappingRange { start: 0, end } if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => { - return Some(get_nullable_type(tcx, param_env, field_ty).unwrap()); + return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); } WrappingRange { start: 1, .. } => { - return Some(get_nullable_type(tcx, param_env, field_ty).unwrap()); + return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); } WrappingRange { start, end } => { unreachable!("Unhandled start and end range: ({}, {})", start, end) @@ -825,7 +826,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let field_ty = self .cx .tcx - .try_normalize_erasing_regions(self.cx.param_env, field_ty) + .try_normalize_erasing_regions(self.cx.typing_env(), field_ty) .unwrap_or(field_ty); self.check_type_for_ffi(acc, field_ty) } @@ -903,7 +904,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if let Some(boxed) = ty.boxed_ty() && matches!(self.mode, CItemKind::Definition) { - if boxed.is_sized(tcx, self.cx.param_env) { + if boxed.is_sized(tcx, self.cx.typing_env()) { return FfiSafe; } else { return FfiUnsafe { @@ -988,7 +989,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { { // Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>` if let Some(ty) = - repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode) + repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty, self.mode) { return self.check_type_for_ffi(acc, ty); } @@ -1068,7 +1069,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::RawPtr(ty, _) | ty::Ref(_, ty, _) if { matches!(self.mode, CItemKind::Definition) - && ty.is_sized(self.cx.tcx, self.cx.param_env) + && ty.is_sized(self.cx.tcx, self.cx.typing_env()) } => { FfiSafe @@ -1196,7 +1197,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if let Some(ty) = self .cx .tcx - .try_normalize_erasing_regions(self.cx.param_env, ty) + .try_normalize_erasing_regions(self.cx.typing_env(), ty) .unwrap_or(ty) .visit_with(&mut ProhibitOpaqueTypes) .break_value() @@ -1220,7 +1221,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return; } - let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.param_env, ty).unwrap_or(ty); + let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.typing_env(), ty).unwrap_or(ty); // C doesn't really support passing arrays by value - the only way to pass an array by value // is through a struct. So, first test that the top level isn't an array, and then diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index b50a95e7d2b..5ec920d39f4 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -272,7 +272,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { || !ty.is_inhabited_from( cx.tcx, cx.tcx.parent_module(expr.hir_id).to_def_id(), - cx.param_env, + cx.typing_env(), ) { return Some(MustUsePath::Suppressed); @@ -556,7 +556,7 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements { if let hir::StmtKind::Semi(expr) = s.kind { if let hir::ExprKind::Path(_) = expr.kind { let ty = cx.typeck_results().expr_ty(expr); - if ty.needs_drop(cx.tcx, cx.param_env) { + if ty.needs_drop(cx.tcx, cx.typing_env()) { let sub = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) { PathStatementDropSub::Suggestion { span: s.span, snippet } @@ -584,6 +584,7 @@ enum UnusedDelimsCtx { MatchScrutineeExpr, ReturnValue, BlockRetValue, + BreakValue, LetScrutineeExpr, ArrayLenExpr, AnonConst, @@ -605,6 +606,7 @@ impl From<UnusedDelimsCtx> for &'static str { UnusedDelimsCtx::MatchScrutineeExpr => "`match` scrutinee expression", UnusedDelimsCtx::ReturnValue => "`return` value", UnusedDelimsCtx::BlockRetValue => "block return value", + UnusedDelimsCtx::BreakValue => "`break` value", UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression", UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression", UnusedDelimsCtx::MatchArmExpr => "match arm expression", @@ -913,6 +915,10 @@ trait UnusedDelimLint { (value, UnusedDelimsCtx::ReturnValue, false, Some(left), None, true) } + Break(_, Some(ref value)) => { + (value, UnusedDelimsCtx::BreakValue, false, None, None, true) + } + Index(_, ref value, _) => (value, UnusedDelimsCtx::IndexExpr, false, None, None, false), Assign(_, ref value, _) | AssignOp(.., ref value) => { @@ -1063,6 +1069,9 @@ impl UnusedDelimLint for UnusedParens { _, _, ) if node.is_lazy())) + && !((ctx == UnusedDelimsCtx::ReturnValue + || ctx == UnusedDelimsCtx::BreakValue) + && matches!(inner.kind, ast::ExprKind::Assign(_, _, _))) { self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw) } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 51146cfd2e9..9036741e078 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -101,6 +101,7 @@ declare_lint_pass! { SINGLE_USE_LIFETIMES, SOFT_UNSTABLE, STABLE_FEATURES, + TAIL_EXPR_DROP_ORDER, TEST_UNSTABLE_LINT, TEXT_DIRECTION_CODEPOINT_IN_COMMENT, TRIVIAL_CASTS, @@ -3185,6 +3186,7 @@ declare_lint! { pub UNEXPECTED_CFGS, Warn, "detects unexpected names and values in `#[cfg]` conditions", + report_in_external_macro } declare_lint! { @@ -4185,7 +4187,7 @@ declare_lint! { Warn, "never type fallback affecting unsafe function calls", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange, + reason: FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(Edition::Edition2024), reference: "issue #123748 <https://github.com/rust-lang/rust/issues/123748>", }; @edition Edition2024 => Deny; @@ -4239,7 +4241,7 @@ declare_lint! { Warn, "never type fallback affecting unsafe function calls", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::EditionAndFutureReleaseError(Edition::Edition2024), reference: "issue #123748 <https://github.com/rust-lang/rust/issues/123748>", }; report_in_external_macro @@ -4994,6 +4996,83 @@ declare_lint! { } declare_lint! { + /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location, + /// that runs a custom `Drop` destructor. + /// Some of them may be dropped earlier in Edition 2024 that they used to in Edition 2021 and prior. + /// This lint detects those cases and provides you information on those values and their custom destructor implementations. + /// Your discretion on this information is required. + /// + /// ### Example + /// ```rust,edition2021 + /// #![warn(tail_expr_drop_order)] + /// struct Droppy(i32); + /// impl Droppy { + /// fn get(&self) -> i32 { + /// self.0 + /// } + /// } + /// impl Drop for Droppy { + /// fn drop(&mut self) { + /// // This is a custom destructor and it induces side-effects that is observable + /// // especially when the drop order at a tail expression changes. + /// println!("loud drop {}", self.0); + /// } + /// } + /// fn edition_2021() -> i32 { + /// let another_droppy = Droppy(0); + /// Droppy(1).get() + /// } + /// fn main() { + /// edition_2021(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In tail expression of blocks or function bodies, + /// values of type with significant `Drop` implementation has an ill-specified drop order + /// before Edition 2024 so that they are dropped only after dropping local variables. + /// Edition 2024 introduces a new rule with drop orders for them, + /// so that they are dropped first before dropping local variables. + /// + /// A significant `Drop::drop` destructor here refers to an explicit, arbitrary + /// implementation of the `Drop` trait on the type, with exceptions including `Vec`, + /// `Box`, `Rc`, `BTreeMap` and `HashMap` that are marked by the compiler otherwise + /// so long that the generic types have no significant destructor recursively. + /// In other words, a type has a significant drop destructor when it has a `Drop` implementation + /// or its destructor invokes a significant destructor on a type. + /// Since we cannot completely reason about the change by just inspecting the existence of + /// a significant destructor, this lint remains only a suggestion and is set to `allow` by default. + /// + /// This lint only points out the issue with `Droppy`, which will be dropped before `another_droppy` + /// does in Edition 2024. + /// No fix will be proposed by this lint. + /// However, the most probable fix is to hoist `Droppy` into its own local variable binding. + /// ```rust + /// struct Droppy(i32); + /// impl Droppy { + /// fn get(&self) -> i32 { + /// self.0 + /// } + /// } + /// fn edition_2024() -> i32 { + /// let value = Droppy(0); + /// let another_droppy = Droppy(1); + /// value.get() + /// } + /// ``` + pub TAIL_EXPR_DROP_ORDER, + Allow, + "Detect and warn on significant change in drop order in tail expression location", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), + reference: "issue #123739 <https://github.com/rust-lang/rust/issues/123739>", + }; +} + +declare_lint! { /// The `rust_2024_guarded_string_incompatible_syntax` lint detects `#` tokens /// that will be parsed as part of a guarded string literal in Rust 2024. /// diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 0caf6ef3a6d..c74fceeedba 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -381,6 +381,8 @@ pub enum FutureIncompatibilityReason { /// hard errors (and the lint removed). Preferably when there is some /// confidence that the number of impacted projects is very small (few /// should have a broken dependency in their dependency tree). + /// + /// [`EditionAndFutureReleaseError`]: FutureIncompatibilityReason::EditionAndFutureReleaseError FutureReleaseErrorReportInDeps, /// Code that changes meaning in some way in a /// future release. @@ -419,6 +421,28 @@ pub enum FutureIncompatibilityReason { /// slightly changes the text of the diagnostic, but is otherwise the /// same. EditionSemanticsChange(Edition), + /// This will be an error in the provided edition *and* in a future + /// release. + /// + /// This variant a combination of [`FutureReleaseErrorDontReportInDeps`] + /// and [`EditionError`]. This is useful in rare cases when we + /// want to have "preview" of a breaking change in an edition, but do a + /// breaking change later on all editions anyway. + /// + /// [`EditionError`]: FutureIncompatibilityReason::EditionError + /// [`FutureReleaseErrorDontReportInDeps`]: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps + EditionAndFutureReleaseError(Edition), + /// This will change meaning in the provided edition *and* in a future + /// release. + /// + /// This variant a combination of [`FutureReleaseSemanticsChange`] + /// and [`EditionSemanticsChange`]. This is useful in rare cases when we + /// want to have "preview" of a breaking change in an edition, but do a + /// breaking change later on all editions anyway. + /// + /// [`EditionSemanticsChange`]: FutureIncompatibilityReason::EditionSemanticsChange + /// [`FutureReleaseSemanticsChange`]: FutureIncompatibilityReason::FutureReleaseSemanticsChange + EditionAndFutureReleaseSemanticsChange(Edition), /// A custom reason. /// /// Choose this variant if the built-in text of the diagnostic of the @@ -431,9 +455,29 @@ pub enum FutureIncompatibilityReason { impl FutureIncompatibilityReason { pub fn edition(self) -> Option<Edition> { match self { - Self::EditionError(e) => Some(e), - Self::EditionSemanticsChange(e) => Some(e), - _ => None, + Self::EditionError(e) + | Self::EditionSemanticsChange(e) + | Self::EditionAndFutureReleaseError(e) + | Self::EditionAndFutureReleaseSemanticsChange(e) => Some(e), + + FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps + | FutureIncompatibilityReason::FutureReleaseErrorReportInDeps + | FutureIncompatibilityReason::FutureReleaseSemanticsChange + | FutureIncompatibilityReason::Custom(_) => None, + } + } + + pub fn has_future_breakage(self) -> bool { + match self { + FutureIncompatibilityReason::FutureReleaseErrorReportInDeps => true, + + FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps + | FutureIncompatibilityReason::FutureReleaseSemanticsChange + | FutureIncompatibilityReason::EditionError(_) + | FutureIncompatibilityReason::EditionSemanticsChange(_) + | FutureIncompatibilityReason::EditionAndFutureReleaseError(_) + | FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(_) + | FutureIncompatibilityReason::Custom(_) => false, } } } diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 493db498b7c..ace46891f83 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -6,7 +6,7 @@ use rustc_ast::CRATE_NODE_ID; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; use rustc_middle::query::LocalCrate; -use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; +use rustc_middle::ty::{self, List, Ty, TyCtxt}; use rustc_session::Session; use rustc_session::config::CrateType; use rustc_session::cstore::{ @@ -613,7 +613,7 @@ impl<'tcx> Collector<'tcx> { .map(|ty| { let layout = self .tcx - .layout_of(ParamEnvAnd { param_env: ParamEnv::empty(), value: ty }) + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) .expect("layout") .layout; // In both stdcall and fastcall, we always round up the argument size to the diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 045fd0565ba..a89096beb8c 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -275,7 +275,7 @@ provide! { tcx, def_id, other, cdata, defaultness => { table_direct } constness => { table_direct } const_conditions => { table } - implied_const_bounds => { table_defaulted_array } + explicit_implied_const_bounds => { table_defaulted_array } coerce_unsized_info => { Ok(cdata .root diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b5391247cea..8378e7c6e9b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1463,8 +1463,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record_array!(self.tables.module_children_non_reexports[def_id] <- module_children.iter().map(|child| child.res.def_id().index)); if self.tcx.is_const_trait(def_id) { - record_defaulted_array!(self.tables.implied_const_bounds[def_id] - <- self.tcx.implied_const_bounds(def_id).skip_binder()); + record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id] + <- self.tcx.explicit_implied_const_bounds(def_id).skip_binder()); } } if let DefKind::TraitAlias = def_kind { @@ -1532,6 +1532,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_explicit_item_super_predicates(def_id); record!(self.tables.opaque_ty_origin[def_id] <- self.tcx.opaque_ty_origin(def_id)); self.encode_precise_capturing_args(def_id); + if tcx.is_conditionally_const(def_id) { + record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id] + <- tcx.explicit_implied_const_bounds(def_id).skip_binder()); + } } if tcx.impl_method_has_trait_impl_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) @@ -1654,8 +1658,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_explicit_item_bounds(def_id); self.encode_explicit_item_super_predicates(def_id); if tcx.is_conditionally_const(def_id) { - record_defaulted_array!(self.tables.implied_const_bounds[def_id] - <- self.tcx.implied_const_bounds(def_id).skip_binder()); + record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id] + <- self.tcx.explicit_implied_const_bounds(def_id).skip_binder()); } } } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 58f58efb116..4a8f8521b4f 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -391,7 +391,7 @@ define_tables! { inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, explicit_super_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, explicit_implied_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, - implied_const_bounds: Table<DefIndex, LazyArray<(ty::PolyTraitRef<'static>, Span)>>, + explicit_implied_const_bounds: Table<DefIndex, LazyArray<(ty::PolyTraitRef<'static>, Span)>>, inherent_impls: Table<DefIndex, LazyArray<DefIndex>>, associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>, opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>, diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index b5862565e8e..971d036fa69 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -290,12 +290,7 @@ pub fn lint_level( let has_future_breakage = future_incompatible.map_or( // Default allow lints trigger too often for testing. sess.opts.unstable_opts.future_incompat_test && lint.default_level != Level::Allow, - |incompat| { - matches!( - incompat.reason, - FutureIncompatibilityReason::FutureReleaseErrorReportInDeps - ) - }, + |incompat| incompat.reason.has_future_breakage(), ); // Convert lint level to error level. @@ -382,6 +377,17 @@ pub fn lint_level( FutureIncompatibilityReason::EditionSemanticsChange(edition) => { format!("this changes meaning in Rust {edition}") } + FutureIncompatibilityReason::EditionAndFutureReleaseError(edition) => { + format!( + "this was previously accepted by the compiler but is being phased out; \ + it will become a hard error in Rust {edition} and in a future release in all editions!" + ) + } + FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(edition) => { + format!( + "this changes meaning in Rust {edition} and in a future release in all editions!" + ) + } FutureIncompatibilityReason::Custom(reason) => reason.to_owned(), }; diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 4e44de33611..114211b27c1 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -236,6 +236,11 @@ pub struct ScopeTree { /// during type check based on a traversal of the AST. pub rvalue_candidates: HirIdMap<RvalueCandidateType>, + /// Backwards incompatible scoping that will be introduced in future editions. + /// This information is used later for linting to identify locals and + /// temporary values that will receive backwards-incompatible drop orders. + pub backwards_incompatible_scope: UnordMap<hir::ItemLocalId, Scope>, + /// If there are any `yield` nested within a scope, this map /// stores the `Span` of the last one and its index in the /// postorder of the Visitor traversal on the HIR. diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index e6b36299d7f..94d13021612 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -10,7 +10,6 @@ use rustc_attr::{ use rustc_data_structures::unord::UnordMap; use rustc_errors::{Applicability, Diag, EmissionGuarantee}; use rustc_feature::GateIssue; -use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_hir::{self as hir, HirId}; use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic}; @@ -24,7 +23,7 @@ use rustc_span::symbol::{Symbol, sym}; use tracing::debug; pub use self::StabilityLevel::*; -use crate::ty::{self, TyCtxt}; +use crate::ty::TyCtxt; #[derive(PartialEq, Clone, Copy, Debug)] pub enum StabilityLevel { @@ -273,22 +272,6 @@ pub enum EvalResult { Unmarked, } -// See issue #38412. -fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - if tcx.def_kind(def_id) == DefKind::TyParam { - // Have no visibility, considered public for the purpose of this check. - return false; - } - match tcx.visibility(def_id) { - // Must check stability for `pub` items. - ty::Visibility::Public => false, - - // These are not visible outside crate; therefore - // stability markers are irrelevant, if even present. - ty::Visibility::Restricted(..) => true, - } -} - // See issue #83250. fn suggestion_for_allocator_api( tcx: TyCtxt<'_>, @@ -407,11 +390,6 @@ impl<'tcx> TyCtxt<'tcx> { def_id, span, stability ); - // Issue #38412: private items lack stability markers. - if skip_stability_check_due_to_privacy(self, def_id) { - return EvalResult::Allow; - } - match stability { Some(Stability { level: attr::Unstable { reason, issue, is_soft, implied_by }, @@ -495,11 +473,6 @@ impl<'tcx> TyCtxt<'tcx> { "body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}" ); - // Issue #38412: private items lack stability markers. - if skip_stability_check_due_to_privacy(self, def_id) { - return EvalResult::Allow; - } - match stability { Some(DefaultBodyStability { level: attr::Unstable { reason, issue, is_soft, .. }, diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index f95635370dc..a51370369b8 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -102,10 +102,11 @@ impl<'tcx> ConstValue<'tcx> { pub fn try_to_bits_for_ty( &self, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, ) -> Option<u128> { - let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; + let size = + tcx.layout_of(typing_env.with_reveal_all_normalized(tcx).as_query_input(ty)).ok()?.size; self.try_to_bits(size) } @@ -314,7 +315,7 @@ impl<'tcx> Const<'tcx> { pub fn eval( self, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, span: Span, ) -> Result<ConstValue<'tcx>, ErrorHandled> { match self { @@ -333,7 +334,7 @@ impl<'tcx> Const<'tcx> { } Const::Unevaluated(uneval, _) => { // FIXME: We might want to have a `try_eval`-like function on `Unevaluated` - tcx.const_eval_resolve(param_env, uneval, span) + tcx.const_eval_resolve(typing_env, uneval, span) } Const::Val(val, _) => Ok(val), } @@ -343,7 +344,7 @@ impl<'tcx> Const<'tcx> { pub fn try_eval_scalar( self, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> Option<Scalar> { if let Const::Ty(_, c) = self && let ty::ConstKind::Value(ty, val) = c.kind() @@ -354,7 +355,7 @@ impl<'tcx> Const<'tcx> { // pointer here, which valtrees don't represent.) Some(val.unwrap_leaf().into()) } else { - self.eval(tcx, param_env, DUMMY_SP).ok()?.try_to_scalar() + self.eval(tcx, typing_env, DUMMY_SP).ok()?.try_to_scalar() } } @@ -362,23 +363,29 @@ impl<'tcx> Const<'tcx> { pub fn try_eval_scalar_int( self, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> Option<ScalarInt> { - self.try_eval_scalar(tcx, param_env)?.try_to_scalar_int().ok() + self.try_eval_scalar(tcx, typing_env)?.try_to_scalar_int().ok() } #[inline] - pub fn try_eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<u128> { - let int = self.try_eval_scalar_int(tcx, param_env)?; - let size = - tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size; + pub fn try_eval_bits( + &self, + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + ) -> Option<u128> { + let int = self.try_eval_scalar_int(tcx, typing_env)?; + let size = tcx + .layout_of(typing_env.with_reveal_all_normalized(tcx).as_query_input(self.ty())) + .ok()? + .size; Some(int.to_bits(size)) } /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type. #[inline] - pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u128 { - self.try_eval_bits(tcx, param_env) + pub fn eval_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> u128 { + self.try_eval_bits(tcx, typing_env) .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self)) } @@ -386,21 +393,21 @@ impl<'tcx> Const<'tcx> { pub fn try_eval_target_usize( self, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> Option<u64> { - Some(self.try_eval_scalar_int(tcx, param_env)?.to_target_usize(tcx)) + Some(self.try_eval_scalar_int(tcx, typing_env)?.to_target_usize(tcx)) } #[inline] /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`. - pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u64 { - self.try_eval_target_usize(tcx, param_env) + pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> u64 { + self.try_eval_target_usize(tcx, typing_env) .unwrap_or_else(|| bug!("expected usize, got {:#?}", self)) } #[inline] - pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> { - self.try_eval_scalar_int(tcx, param_env)?.try_into().ok() + pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<bool> { + self.try_eval_scalar_int(tcx, typing_env)?.try_into().ok() } #[inline] @@ -411,17 +418,16 @@ impl<'tcx> Const<'tcx> { pub fn from_bits( tcx: TyCtxt<'tcx>, bits: u128, - param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, + typing_env: ty::TypingEnv<'tcx>, + ty: Ty<'tcx>, ) -> Self { let size = tcx - .layout_of(param_env_ty) - .unwrap_or_else(|e| { - bug!("could not compute layout for {:?}: {:?}", param_env_ty.value, e) - }) + .layout_of(typing_env.as_query_input(ty)) + .unwrap_or_else(|e| bug!("could not compute layout for {ty:?}: {e:?}")) .size; let cv = ConstValue::Scalar(Scalar::from_uint(bits, size)); - Self::Val(cv, param_env_ty.value) + Self::Val(cv, ty) } #[inline] @@ -438,7 +444,8 @@ impl<'tcx> Const<'tcx> { pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self { let ty = tcx.types.usize; - Self::from_bits(tcx, n as u128, ty::ParamEnv::empty().and(ty)) + let typing_env = ty::TypingEnv::fully_monomorphized(); + Self::from_bits(tcx, n as u128, typing_env, ty) } #[inline] 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/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index f225ad94aa7..8d73c9e76de 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -46,7 +46,7 @@ pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance}; pub use self::value::Scalar; use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; -use crate::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; +use crate::ty::{self, Instance, Ty, TyCtxt}; /// Uniquely identifies one of the following: /// - A constant @@ -312,7 +312,7 @@ impl<'tcx> GlobalAlloc<'tcx> { } } - pub fn mutability(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Mutability { + pub fn mutability(&self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Mutability { // Let's see what kind of memory we are. match self { GlobalAlloc::Static(did) => { @@ -334,7 +334,7 @@ impl<'tcx> GlobalAlloc<'tcx> { .type_of(did) .no_bound_vars() .expect("statics should not have generic parameters") - .is_freeze(tcx, param_env) => + .is_freeze(tcx, typing_env) => { Mutability::Mut } @@ -351,7 +351,11 @@ impl<'tcx> GlobalAlloc<'tcx> { } } - pub fn size_and_align(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> (Size, Align) { + pub fn size_and_align( + &self, + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + ) -> (Size, Align) { match self { GlobalAlloc::Static(def_id) => { let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { @@ -374,7 +378,7 @@ impl<'tcx> GlobalAlloc<'tcx> { .type_of(def_id) .no_bound_vars() .expect("statics should not have generic parameters"); - let layout = tcx.layout_of(param_env.and(ty)).unwrap(); + let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap(); assert!(layout.is_sized()); (layout.size, layout.align.abi) } diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 2ecf1d0bcf8..6eeafe18b35 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -25,8 +25,8 @@ impl<'tcx> TyCtxt<'tcx> { let args = GenericArgs::identity_for_item(self, def_id); let instance = ty::Instance::new(def_id, args); let cid = GlobalId { instance, promoted: None }; - let param_env = self.param_env(def_id).with_reveal_all_normalized(self); - self.const_eval_global_id(param_env, cid, DUMMY_SP) + let typing_env = ty::TypingEnv::post_analysis(self, def_id); + self.const_eval_global_id(typing_env, cid, DUMMY_SP) } /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts @@ -41,8 +41,8 @@ impl<'tcx> TyCtxt<'tcx> { let args = GenericArgs::identity_for_item(self, def_id); let instance = ty::Instance::new(def_id, args); let cid = GlobalId { instance, promoted: None }; - let param_env = self.param_env(def_id).with_reveal_all_normalized(self); - let inputs = self.erase_regions(param_env.and(cid)); + let typing_env = ty::TypingEnv::post_analysis(self, def_id); + let inputs = self.erase_regions(typing_env.as_query_input(cid)); self.eval_to_allocation_raw(inputs) } @@ -58,7 +58,7 @@ impl<'tcx> TyCtxt<'tcx> { #[instrument(level = "debug", skip(self))] pub fn const_eval_resolve( self, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ct: mir::UnevaluatedConst<'tcx>, span: Span, ) -> EvalToConstValueResult<'tcx> { @@ -72,14 +72,11 @@ impl<'tcx> TyCtxt<'tcx> { bug!("did not expect inference variables here"); } - match ty::Instance::try_resolve( - self, param_env, - // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst? - ct.def, ct.args, - ) { + // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst? + match ty::Instance::try_resolve(self, typing_env, ct.def, ct.args) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted: ct.promoted }; - self.const_eval_global_id(param_env, cid, span) + self.const_eval_global_id(typing_env, cid, span) } // For errors during resolution, we deliberately do not point at the usage site of the constant, // since for these errors the place the constant is used shouldn't matter. @@ -91,7 +88,7 @@ impl<'tcx> TyCtxt<'tcx> { #[instrument(level = "debug", skip(self))] pub fn const_eval_resolve_for_typeck( self, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ct: ty::UnevaluatedConst<'tcx>, span: Span, ) -> EvalToValTreeResult<'tcx> { @@ -105,10 +102,10 @@ impl<'tcx> TyCtxt<'tcx> { bug!("did not expect inference variables here"); } - match ty::Instance::try_resolve(self, param_env, ct.def, ct.args) { + match ty::Instance::try_resolve(self, typing_env, ct.def, ct.args) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted: None }; - self.const_eval_global_id_for_typeck(param_env, cid, span).inspect(|_| { + self.const_eval_global_id_for_typeck(typing_env, cid, span).inspect(|_| { // We are emitting the lint here instead of in `is_const_evaluatable` // as we normalize obligations before checking them, and normalization // uses this function to evaluate this constant. @@ -147,24 +144,25 @@ impl<'tcx> TyCtxt<'tcx> { pub fn const_eval_instance( self, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, instance: ty::Instance<'tcx>, span: Span, ) -> EvalToConstValueResult<'tcx> { - self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span) + self.const_eval_global_id(typing_env, GlobalId { instance, promoted: None }, span) } /// Evaluate a constant to a `ConstValue`. #[instrument(skip(self), level = "debug")] pub fn const_eval_global_id( self, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, cid: GlobalId<'tcx>, span: Span, ) -> EvalToConstValueResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. - let inputs = self.erase_regions(param_env.with_reveal_all_normalized(self).and(cid)); + let inputs = + self.erase_regions(typing_env.with_reveal_all_normalized(self).as_query_input(cid)); if !span.is_dummy() { // The query doesn't know where it is being invoked, so we need to fix the span. self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span)) @@ -177,13 +175,14 @@ impl<'tcx> TyCtxt<'tcx> { #[instrument(skip(self), level = "debug")] pub fn const_eval_global_id_for_typeck( self, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, cid: GlobalId<'tcx>, span: Span, ) -> EvalToValTreeResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. - let inputs = self.erase_regions(param_env.with_reveal_all_normalized(self).and(cid)); + let inputs = + self.erase_regions(typing_env.with_reveal_all_normalized(self).as_query_input(cid)); debug!(?inputs); if !span.is_dummy() { // The query doesn't know where it is being invoked, so we need to fix the span. @@ -205,12 +204,12 @@ impl<'tcx> TyCtxtEnsure<'tcx> { // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are // encountered. let args = GenericArgs::identity_for_item(self.tcx, def_id); - let instance = ty::Instance::new(def_id, args); + let instance = ty::Instance::new(def_id, self.tcx.erase_regions(args)); let cid = GlobalId { instance, promoted: None }; - let param_env = self.tcx.param_env(def_id).with_reveal_all_normalized(self.tcx); + let typing_env = ty::TypingEnv::post_analysis(self.tcx, def_id); // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. - let inputs = self.tcx.erase_regions(param_env.and(cid)); + let inputs = self.tcx.erase_regions(typing_env.as_query_input(cid)); self.eval_to_const_value_raw(inputs) } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 260c6543f98..e2379f282ec 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -39,7 +39,7 @@ use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths}; use crate::ty::visit::TypeVisitableExt; use crate::ty::{ - self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypingMode, + self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypingEnv, UserTypeAnnotationIndex, }; @@ -452,12 +452,14 @@ impl<'tcx> Body<'tcx> { self.basic_blocks.as_mut() } - pub fn typing_mode(&self, _tcx: TyCtxt<'tcx>) -> TypingMode<'tcx> { + pub fn typing_env(&self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> { match self.phase { - // FIXME(#132279): the MIR is quite clearly inside of a body, so we - // should instead reveal opaques defined by that body here. - MirPhase::Built | MirPhase::Analysis(_) => TypingMode::non_body_analysis(), - MirPhase::Runtime(_) => TypingMode::PostAnalysis, + // FIXME(#132279): we should reveal the opaques defined in the body during analysis. + MirPhase::Built | MirPhase::Analysis(_) => TypingEnv { + typing_mode: ty::TypingMode::non_body_analysis(), + param_env: tcx.param_env(self.source.def_id()), + }, + MirPhase::Runtime(_) => TypingEnv::post_analysis(tcx, self.source.def_id()), } } @@ -618,7 +620,7 @@ impl<'tcx> Body<'tcx> { } /// If this basic block ends with a [`TerminatorKind::SwitchInt`] for which we can evaluate the - /// dimscriminant in monomorphization, we return the discriminant bits and the + /// discriminant in monomorphization, we return the discriminant bits and the /// [`SwitchTargets`], just so the caller doesn't also have to match on the terminator. fn try_const_mono_switchint<'a>( tcx: TyCtxt<'tcx>, @@ -627,13 +629,15 @@ impl<'tcx> Body<'tcx> { ) -> Option<(u128, &'a SwitchTargets)> { // There are two places here we need to evaluate a constant. let eval_mono_const = |constant: &ConstOperand<'tcx>| { - let env = ty::ParamEnv::reveal_all(); + // FIXME(#132279): what is this, why are we using an empty environment with + // `RevealAll` here. + let typing_env = ty::TypingEnv::fully_monomorphized(); let mono_literal = instance.instantiate_mir_and_normalize_erasing_regions( tcx, - env, + typing_env, crate::ty::EarlyBinder::bind(constant.const_), ); - mono_literal.try_eval_bits(tcx, env) + mono_literal.try_eval_bits(tcx, typing_env) }; let TerminatorKind::SwitchInt { discr, targets } = &block.terminator().kind else { diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index d8d99deeb2c..244d22d082f 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -46,7 +46,7 @@ pub enum InstantiationMode { LocalCopy, } -#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, HashStable)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, HashStable, TyEncodable, TyDecodable)] pub enum MonoItem<'tcx> { Fn(Instance<'tcx>), Static(DefId), @@ -66,20 +66,7 @@ impl<'tcx> MonoItem<'tcx> { // change NON_INCR_MIN_CGU_SIZE as well. pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize { match *self { - MonoItem::Fn(instance) => { - match instance.def { - // "Normal" functions size estimate: the number of - // statements, plus one for the terminator. - InstanceKind::Item(..) - | InstanceKind::DropGlue(..) - | InstanceKind::AsyncDropGlueCtorShim(..) => { - let mir = tcx.instance_mir(instance.def); - mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum() - } - // Other compiler-generated shims size estimate: 1 - _ => 1, - } - } + MonoItem::Fn(instance) => tcx.size_estimate(instance), // Conservatively estimate the size of a static declaration or // assembly item to be 1. MonoItem::Static(_) | MonoItem::GlobalAsm(_) => 1, @@ -556,3 +543,21 @@ impl<'tcx> CodegenUnitNameBuilder<'tcx> { Symbol::intern(&cgu_name) } } + +/// See module-level docs of `rustc_monomorphize::collector` on some context for "mentioned" items. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] +pub enum CollectionMode { + /// Collect items that are used, i.e., actually needed for codegen. + /// + /// Which items are used can depend on optimization levels, as MIR optimizations can remove + /// uses. + UsedItems, + /// Collect items that are mentioned. The goal of this mode is that it is independent of + /// optimizations: the set of "mentioned" items is computed before optimizations are run. + /// + /// The exact contents of this set are *not* a stable guarantee. (For instance, it is currently + /// computed after drop-elaboration. If we ever do some optimizations even in debug builds, we + /// might decide to run them before computing mentioned items.) The key property of this set is + /// that it is optimization-independent. + MentionedItems, +} diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f0e2b7a376c..2bfcd0a6227 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -834,6 +834,11 @@ impl Debug for Statement<'_> { Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"), ConstEvalCounter => write!(fmt, "ConstEvalCounter"), Nop => write!(fmt, "nop"), + BackwardIncompatibleDropHint { ref place, reason: _ } => { + // For now, we don't record the reason because there is only one use case, + // which is to report breaking change in drop order by Edition 2024 + write!(fmt, "backward incompatible drop({place:?})") + } } } } diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 88ed90c3114..1ce735cec63 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -332,9 +332,9 @@ impl<'tcx> Operand<'tcx> { span: Span, ) -> Operand<'tcx> { debug_assert!({ - let param_env_and_ty = ty::ParamEnv::empty().and(ty); + let typing_env = ty::TypingEnv::fully_monomorphized(); let type_size = tcx - .layout_of(param_env_and_ty) + .layout_of(typing_env.as_query_input(ty)) .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}")) .size; let scalar_size = match val { diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index f01ac305d3f..fea940ea47c 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -20,7 +20,7 @@ use smallvec::SmallVec; use super::{BasicBlock, Const, Local, UserTypeProjection}; use crate::mir::coverage::CoverageKind; use crate::ty::adjustment::PointerCoercion; -use crate::ty::{self, GenericArgsRef, List, Region, Ty, TyCtxt, UserTypeAnnotationIndex}; +use crate::ty::{self, GenericArgsRef, List, Region, Ty, UserTypeAnnotationIndex}; /// Represents the "flavors" of MIR. /// @@ -100,13 +100,6 @@ impl MirPhase { MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized", } } - - pub fn param_env<'tcx>(&self, tcx: TyCtxt<'tcx>, body_def_id: DefId) -> ty::ParamEnv<'tcx> { - match self { - MirPhase::Built | MirPhase::Analysis(_) => tcx.param_env(body_def_id), - MirPhase::Runtime(_) => tcx.param_env_reveal_all_normalized(body_def_id), - } - } } /// See [`MirPhase::Analysis`]. @@ -439,6 +432,18 @@ pub enum StatementKind<'tcx> { /// No-op. Useful for deleting instructions without affecting statement indices. Nop, + + /// Marker statement indicating where `place` would be dropped. + /// This is semantically equivalent to `Nop`, so codegen and MIRI should interpret this + /// statement as such. + /// The only use case of this statement is for linting in MIR to detect temporary lifetime + /// changes. + BackwardIncompatibleDropHint { + /// Place to drop + place: Box<Place<'tcx>>, + /// Reason for backward incompatibility + reason: BackwardIncompatibleDropReason, + }, } impl StatementKind<'_> { @@ -459,6 +464,7 @@ impl StatementKind<'_> { StatementKind::Intrinsic(..) => "Intrinsic", StatementKind::ConstEvalCounter => "ConstEvalCounter", StatementKind::Nop => "Nop", + StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint", } } } @@ -904,6 +910,21 @@ pub enum TerminatorKind<'tcx> { }, } +#[derive( + Clone, + Debug, + TyEncodable, + TyDecodable, + Hash, + HashStable, + PartialEq, + TypeFoldable, + TypeVisitable +)] +pub enum BackwardIncompatibleDropReason { + Edition2024, +} + impl TerminatorKind<'_> { /// Returns a simple string representation of a `TerminatorKind` variant, independent of any /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`). diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 9f9ee8497b6..62c340d99e3 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -452,6 +452,7 @@ macro_rules! make_mir_visitor { } StatementKind::ConstEvalCounter => {} StatementKind::Nop => {} + StatementKind::BackwardIncompatibleDropHint { .. } => {} } } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 1d4c36e28bd..013847f0b2d 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -216,6 +216,10 @@ impl<T0, T1> EraseType for (&'_ T0, &'_ [T1]) { type Result = [u8; size_of::<(&'static (), &'static [()])>()]; } +impl<T0, T1> EraseType for (&'_ [T0], &'_ [T1]) { + type Result = [u8; size_of::<(&'static [()], &'static [()])>()]; +} + impl<T0> EraseType for (&'_ T0, Result<(), ErrorGuaranteed>) { type Result = [u8; size_of::<(&'static (), Result<(), ErrorGuaranteed>)>()]; } diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index fe28ef0f70c..970dc72e1ff 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -2,11 +2,13 @@ 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}; use crate::infer::canonical::CanonicalQueryInput; +use crate::mir::mono::CollectionMode; use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::{TyAndLayout, ValidityRequirement}; use crate::ty::{self, GenericArg, GenericArgsRef, Ty, TyCtxt}; @@ -110,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 @@ -127,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) @@ -139,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) @@ -358,6 +360,14 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) { } } +impl<'tcx> Key for ty::ParamEnvAnd<'tcx, Ty<'tcx>> { + type Cache<V> = DefaultCache<Self, V>; + + fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl<'tcx> Key for ty::TraitRef<'tcx> { type Cache<V> = DefaultCache<Self, V>; @@ -454,7 +464,7 @@ impl<'tcx> Key for ty::ParamEnv<'tcx> { } } -impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { +impl<'tcx, T: Key> Key for ty::PseudoCanonicalInput<'tcx, T> { type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { @@ -574,7 +584,7 @@ impl Key for (LocalDefId, HirId) { } } -impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) { +impl<'tcx> Key for (ValidityRequirement, ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) { type Cache<V> = DefaultCache<Self, V>; // Just forward to `Ty<'tcx>` @@ -590,3 +600,11 @@ impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) { } } } + +impl<'tcx> Key for (ty::Instance<'tcx>, CollectionMode) { + type Cache<V> = DefaultCache<Self, V>; + + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + self.0.default_span(tcx) + } +} diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 4e3668822ec..76338be33aa 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -40,6 +40,7 @@ use rustc_session::cstore::{ }; use rustc_session::lint::LintExpectationId; use rustc_span::def_id::LOCAL_CRATE; +use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; use rustc_span::{DUMMY_SP, Span}; use rustc_target::spec::PanicStrategy; @@ -59,7 +60,7 @@ use crate::mir::interpret::{ EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId, LitToConstError, LitToConstInput, }; -use crate::mir::mono::CodegenUnit; +use crate::mir::mono::{CodegenUnit, CollectionMode, MonoItem}; use crate::query::erase::{Erase, erase, restore}; use crate::query::plumbing::{ CyclePlaceholder, DynamicQuery, query_ensure, query_ensure_error_guaranteed, query_get_at, @@ -80,8 +81,8 @@ use crate::ty::layout::ValidityRequirement; use crate::ty::print::{PrintTraitRefExt, describe_as_module}; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::{ - self, CrateInherentImpls, GenericArg, GenericArgsRef, ParamEnvAnd, Ty, TyCtxt, TyCtxtFeed, - UnusedGenericParams, + self, CrateInherentImpls, GenericArg, GenericArgsRef, PseudoCanonicalInput, Ty, TyCtxt, + TyCtxtFeed, UnusedGenericParams, }; use crate::{dep_graph, mir, thir}; @@ -696,7 +697,7 @@ rustc_queries! { separate_provide_extern } - query implied_const_bounds( + query explicit_implied_const_bounds( key: DefId ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> { desc { |tcx| "computing the implied `~const` bounds for `{}`", @@ -1094,7 +1095,7 @@ rustc_queries! { /// Evaluates a constant and returns the computed allocation. /// /// **Do not use this** directly, use the `eval_to_const_value` or `eval_to_valtree` instead. - query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + query eval_to_allocation_raw(key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>) -> EvalToAllocationRawResult<'tcx> { desc { |tcx| "const-evaluating + checking `{}`", @@ -1120,7 +1121,7 @@ rustc_queries! { /// /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`, /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`. - query eval_to_const_value_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + query eval_to_const_value_raw(key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>) -> EvalToConstValueResult<'tcx> { desc { |tcx| "simplifying constant for the type system `{}`", @@ -1132,7 +1133,7 @@ rustc_queries! { /// Evaluate a constant and convert it to a type level constant or /// return `None` if that is not possible. query eval_to_valtree( - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>> + key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>> ) -> EvalToValTreeResult<'tcx> { desc { "evaluating type-level constant" } } @@ -1340,10 +1341,10 @@ rustc_queries! { } query codegen_select_candidate( - key: (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) + key: PseudoCanonicalInput<'tcx, ty::TraitRef<'tcx>> ) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> { cache_on_disk_if { true } - desc { |tcx| "computing candidate for `{}`", key.1 } + desc { |tcx| "computing candidate for `{}`", key.value } } /// Return all `impl` blocks in the current crate. @@ -1389,31 +1390,31 @@ rustc_queries! { /// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`, /// `ty.is_copy()`, etc, since that will prune the environment where possible. - query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + query is_copy_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Copy`", env.value } } /// Query backing `Ty::is_sized`. - query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + query is_sized_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Sized`", env.value } } /// Query backing `Ty::is_freeze`. - query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + query is_freeze_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is freeze", env.value } } /// Query backing `Ty::is_unpin`. - query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + query is_unpin_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Unpin`", env.value } } /// Query backing `Ty::needs_drop`. - query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + query needs_drop_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` needs drop", env.value } } /// Query backing `Ty::needs_async_drop`. - query needs_async_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + query needs_async_drop_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` needs async drop", env.value } } /// Query backing `Ty::has_significant_drop_raw`. - query has_significant_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + query has_significant_drop_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` has a significant drop", env.value } } @@ -1447,10 +1448,32 @@ rustc_queries! { cache_on_disk_if { false } } + /// Returns a list of types which (a) have a potentially significant destructor + /// and (b) may be dropped as a result of dropping a value of some type `ty` + /// (in the given environment). + /// + /// The idea of "significant" drop is somewhat informal and is used only for + /// diagnostics and edition migrations. The idea is that a significant drop may have + /// some visible side-effect on execution; freeing memory is NOT considered a side-effect. + /// The rules are as follows: + /// * Type with no explicit drop impl do not have significant drop. + /// * Types with a drop impl are assumed to have significant drop unless they have a `#[rustc_insignificant_dtor]` annotation. + /// + /// Note that insignificant drop is a "shallow" property. A type like `Vec<LockGuard>` does not + /// have significant drop but the type `LockGuard` does, and so if `ty = Vec<LockGuard>` + /// then the return value would be `&[LockGuard]`. + /// *IMPORTANT*: *DO NOT* run this query before promoted MIR body is constructed, + /// because this query partially depends on that query. + /// Otherwise, there is a risk of query cycles. + query list_significant_drop_tys(ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> &'tcx ty::List<Ty<'tcx>> { + desc { |tcx| "computing when `{}` has a significant destructor", ty.value } + cache_on_disk_if { false } + } + /// Computes the layout of a type. Note that this implicitly /// executes in "reveal all" mode, and will normalize the input type. query layout_of( - key: ty::ParamEnvAnd<'tcx, Ty<'tcx>> + key: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>> ) -> Result<ty::layout::TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> { depth_limit desc { "computing layout of `{}`", key.value } @@ -1463,7 +1486,7 @@ rustc_queries! { /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance` /// instead, where the instance is an `InstanceKind::Virtual`. query fn_abi_of_fn_ptr( - key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)> + key: ty::PseudoCanonicalInput<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)> ) -> Result<&'tcx rustc_target::callconv::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> { desc { "computing call ABI of `{}` function pointers", key.value.0 } } @@ -1474,7 +1497,7 @@ rustc_queries! { /// NB: that includes virtual calls, which are represented by "direct calls" /// to an `InstanceKind::Virtual` instance (of `<dyn Trait as Trait>::fn`). query fn_abi_of_instance( - key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)> + key: ty::PseudoCanonicalInput<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)> ) -> Result<&'tcx rustc_target::callconv::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> { desc { "computing call ABI of `{}`", key.value.0 } } @@ -2087,7 +2110,7 @@ rustc_queries! { /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead. query try_normalize_generic_arg_after_erasing_regions( - goal: ParamEnvAnd<'tcx, GenericArg<'tcx>> + goal: PseudoCanonicalInput<'tcx, GenericArg<'tcx>> ) -> Result<GenericArg<'tcx>, NoSolution> { desc { "normalizing `{}`", goal.value } } @@ -2244,7 +2267,7 @@ rustc_queries! { /// from `Ok(None)` to avoid misleading diagnostics when an error /// has already been/will be emitted, for the original cause. query resolve_instance_raw( - key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)> + key: ty::PseudoCanonicalInput<'tcx, (DefId, GenericArgsRef<'tcx>)> ) -> Result<Option<ty::Instance<'tcx>>, ErrorGuaranteed> { desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } } @@ -2282,7 +2305,7 @@ rustc_queries! { desc { "computing the backend features for CLI flags" } } - query check_validity_requirement(key: (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, &'tcx ty::layout::LayoutError<'tcx>> { + query check_validity_requirement(key: (ValidityRequirement, ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>)) -> Result<bool, &'tcx ty::layout::LayoutError<'tcx>> { desc { "checking validity requirement for `{}`: {}", key.1.value, key.0 } } @@ -2339,6 +2362,16 @@ rustc_queries! { arena_cache desc { "functions to skip for move-size check" } } + + query items_of_instance(key: (ty::Instance<'tcx>, CollectionMode)) -> (&'tcx [Spanned<MonoItem<'tcx>>], &'tcx [Spanned<MonoItem<'tcx>>]) { + desc { "collecting items used by `{}`", key.0 } + cache_on_disk_if { true } + } + + query size_estimate(key: ty::Instance<'tcx>) -> usize { + desc { "estimating codegen size of `{}`", key } + cache_on_disk_if { true } + } } rustc_query_append! { define_callbacks! } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 8b77a4a81ca..3849cb72668 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -12,6 +12,7 @@ use rustc_index::{Idx, IndexVec}; use rustc_macros::{Decodable, Encodable}; use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; +use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::{self, interpret}; use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -22,7 +23,7 @@ use rustc_session::Session; use rustc_span::hygiene::{ ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData, }; -use rustc_span::source_map::SourceMap; +use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::{ BytePos, CachingSourceMapView, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span, SpanDecoder, SpanEncoder, StableSourceFileId, Symbol, @@ -773,6 +774,13 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [rustc_ast::InlineAsm } } +impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [Spanned<MonoItem<'tcx>>] { + #[inline] + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { + RefDecodable::decode(d) + } +} + impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx crate::traits::specialization_graph::Graph { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 45ceb0a555d..9cf6bc1b777 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -247,13 +247,24 @@ pub struct Expr<'tcx> { pub ty: Ty<'tcx>, /// The lifetime of this expression if it should be spilled into a - /// temporary; should be `None` only if in a constant context - pub temp_lifetime: Option<region::Scope>, + /// temporary + pub temp_lifetime: TempLifetime, /// span of the expression in the source pub span: Span, } +/// Temporary lifetime information for THIR expressions +#[derive(Clone, Copy, Debug, HashStable)] +pub struct TempLifetime { + /// Lifetime for temporaries as expected. + /// This should be `None` in a constant context. + pub temp_lifetime: Option<region::Scope>, + /// If `Some(lt)`, indicates that the lifetime of this temporary will change to `lt` in a future edition. + /// If `None`, then no changes are expected, or lints are disabled. + pub backwards_incompatible: Option<region::Scope>, +} + #[derive(Clone, Debug, HashStable)] pub enum ExprKind<'tcx> { /// `Scope`s are used to explicitly mark destruction scopes, @@ -645,7 +656,7 @@ impl<'tcx> Pat<'tcx> { | Binding { subpattern: Some(subpattern), .. } | Deref { subpattern } | DerefPattern { subpattern, .. } - | InlineConstant { subpattern, .. } => subpattern.walk_(it), + | ExpandedConstant { subpattern, .. } => subpattern.walk_(it), Leaf { subpatterns } | Variant { subpatterns, .. } => { subpatterns.iter().for_each(|field| field.pattern.walk_(it)) } @@ -788,12 +799,17 @@ pub enum PatKind<'tcx> { value: mir::Const<'tcx>, }, - /// Inline constant found while lowering a pattern. - InlineConstant { - /// [LocalDefId] of the constant, we need this so that we have a + /// Pattern obtained by converting a constant (inline or named) to its pattern + /// representation using `const_to_pat`. + ExpandedConstant { + /// [DefId] of the constant, we need this so that we have a /// reference that can be used by unsafety checking to visit nested - /// unevaluated constants. - def: LocalDefId, + /// unevaluated constants and for diagnostics. If the `DefId` doesn't + /// correspond to a local crate, it points at the `const` item. + def_id: DefId, + /// If `false`, then `def_id` points at a `const` item, otherwise it + /// corresponds to a local inline const. + is_inline: bool, /// If the inline constant is used in a range pattern, this subpattern /// represents the range (if both ends are inline constants, there will /// be multiple InlineConstant wrappers). @@ -905,7 +921,7 @@ impl<'tcx> PatRange<'tcx> { &self, value: mir::Const<'tcx>, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> Option<bool> { use Ordering::*; debug_assert_eq!(self.ty, value.ty()); @@ -913,10 +929,10 @@ impl<'tcx> PatRange<'tcx> { let value = PatRangeBoundary::Finite(value); // For performance, it's important to only do the second comparison if necessary. Some( - match self.lo.compare_with(value, ty, tcx, param_env)? { + match self.lo.compare_with(value, ty, tcx, typing_env)? { Less | Equal => true, Greater => false, - } && match value.compare_with(self.hi, ty, tcx, param_env)? { + } && match value.compare_with(self.hi, ty, tcx, typing_env)? { Less => true, Equal => self.end == RangeEnd::Included, Greater => false, @@ -929,17 +945,17 @@ impl<'tcx> PatRange<'tcx> { &self, other: &Self, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> Option<bool> { use Ordering::*; debug_assert_eq!(self.ty, other.ty); // For performance, it's important to only do the second comparison if necessary. Some( - match other.lo.compare_with(self.hi, self.ty, tcx, param_env)? { + match other.lo.compare_with(self.hi, self.ty, tcx, typing_env)? { Less => true, Equal => self.end == RangeEnd::Included, Greater => false, - } && match self.lo.compare_with(other.hi, self.ty, tcx, param_env)? { + } && match self.lo.compare_with(other.hi, self.ty, tcx, typing_env)? { Less => true, Equal => other.end == RangeEnd::Included, Greater => false, @@ -985,9 +1001,14 @@ impl<'tcx> PatRangeBoundary<'tcx> { Self::NegInfinity | Self::PosInfinity => None, } } - pub fn eval_bits(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u128 { + pub fn eval_bits( + self, + ty: Ty<'tcx>, + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + ) -> u128 { match self { - Self::Finite(value) => value.eval_bits(tcx, param_env), + Self::Finite(value) => value.eval_bits(tcx, typing_env), Self::NegInfinity => { // Unwrap is ok because the type is known to be numeric. ty.numeric_min_and_max_as_bits(tcx).unwrap().0 @@ -999,13 +1020,13 @@ impl<'tcx> PatRangeBoundary<'tcx> { } } - #[instrument(skip(tcx, param_env), level = "debug", ret)] + #[instrument(skip(tcx, typing_env), level = "debug", ret)] pub fn compare_with( self, other: Self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> Option<Ordering> { use PatRangeBoundary::*; match (self, other) { @@ -1034,8 +1055,8 @@ impl<'tcx> PatRangeBoundary<'tcx> { _ => {} } - let a = self.eval_bits(ty, tcx, param_env); - let b = other.eval_bits(ty, tcx, param_env); + let a = self.eval_bits(ty, tcx, typing_env); + let b = other.eval_bits(ty, tcx, typing_env); match ty.kind() { ty::Float(ty::FloatTy::F16) => { @@ -1082,7 +1103,7 @@ mod size_asserts { use super::*; // tidy-alphabetical-start static_assert_size!(Block, 48); - static_assert_size!(Expr<'_>, 64); + static_assert_size!(Expr<'_>, 72); static_assert_size!(ExprKind<'_>, 40); static_assert_size!(Pat<'_>, 64); static_assert_size!(PatKind<'_>, 48); diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 36f0e3d890c..81202a6eaad 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -247,7 +247,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( } } Constant { value: _ } => {} - InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern), + ExpandedConstant { def_id: _, is_inline: _, subpattern } => visitor.visit_pat(subpattern), Range(_) => {} Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { for subpattern in prefix.iter() { diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 0773eb7a3be..79d56702be2 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -498,12 +498,13 @@ impl<'tcx> AdtDef<'tcx> { expr_did: DefId, ) -> Result<Discr<'tcx>, ErrorGuaranteed> { assert!(self.is_enum()); - let param_env = tcx.param_env(expr_did); + let repr_type = self.repr().discr_type(); match tcx.const_eval_poly(expr_did) { Ok(val) => { + let typing_env = ty::TypingEnv::post_analysis(tcx, expr_did); let ty = repr_type.to_ty(tcx); - if let Some(b) = val.try_to_bits_for_ty(tcx, param_env, ty) { + if let Some(b) = val.try_to_bits_for_ty(tcx, typing_env, ty) { trace!("discriminants: {} ({:?})", b, repr_type); Ok(Discr { val: b, ty }) } else { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index b5358f0ca35..47a84d4b258 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -13,9 +13,11 @@ use std::marker::DiscriminantKind; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; +use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::TyCtxt; use rustc_serialize::{Decodable, Encodable}; use rustc_span::Span; +use rustc_span::source_map::Spanned; pub use rustc_type_ir::{TyDecoder, TyEncoder}; use crate::arena::ArenaAllocatable; @@ -397,6 +399,15 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> } } +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [Spanned<MonoItem<'tcx>>] { + fn decode(decoder: &mut D) -> &'tcx Self { + decoder + .interner() + .arena + .alloc_from_iter((0..decoder.read_usize()).map(|_| Decodable::decode(decoder))) + } +} + impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::BoundVariableKind> { diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 5689f3d4265..d853edb34c9 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,15 +1,16 @@ +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, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; +use crate::ty::{self, GenericArgs, Ty, TyCtxt, TypeVisitableExt}; mod int; mod kind; @@ -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:?}"), ); } } @@ -330,17 +261,22 @@ impl<'tcx> Const<'tcx> { None } - #[inline] /// Creates a constant with the given integer value and interns it. - pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Self { + #[inline] + pub fn from_bits( + tcx: TyCtxt<'tcx>, + bits: u128, + typing_env: ty::TypingEnv<'tcx>, + ty: Ty<'tcx>, + ) -> Self { let size = tcx - .layout_of(ty) + .layout_of(typing_env.as_query_input(ty)) .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}")) .size; ty::Const::new_value( tcx, ty::ValTree::from_scalar_int(ScalarInt::try_from_uint(bits, size).unwrap()), - ty.value, + ty, ) } @@ -353,13 +289,13 @@ impl<'tcx> Const<'tcx> { #[inline] /// Creates an interned bool constant. pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self { - Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool)) + Self::from_bits(tcx, v as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.bool) } #[inline] /// Creates an interned usize constant. pub fn from_target_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self { - Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize)) + Self::from_bits(tcx, n as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.usize) } /// Panics if self.kind != ty::ConstKind::Value @@ -393,15 +329,15 @@ impl<'tcx> Const<'tcx> { self.try_to_valtree()?.0.try_to_target_usize(tcx) } - #[inline] /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it /// contains const generic parameters or pointers). - pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> { + #[inline] + pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> { let (scalar, ty) = self.try_to_scalar()?; let scalar = scalar.try_to_scalar_int().ok()?; - let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; - // if `ty` does not depend on generic parameters, use an empty param_env + let input = typing_env.with_reveal_all_normalized(tcx).as_query_input(ty); + let size = tcx.layout_of(input).ok()?.size; Some(scalar.to_bits(size)) } @@ -409,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 84ac281c258..55c29825fbc 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:?}"), } } @@ -374,7 +376,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.explicit_implied_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied()) } - fn is_const_impl(self, def_id: DefId) -> bool { + fn impl_is_const(self, def_id: DefId) -> bool { + self.is_conditionally_const(def_id) + } + + fn fn_is_const(self, def_id: DefId) -> bool { self.is_conditionally_const(def_id) } @@ -387,12 +393,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) } - fn implied_const_bounds( + fn explicit_implied_const_bounds( self, def_id: DefId, ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>>> { ty::EarlyBinder::bind( - self.implied_const_bounds(def_id).iter_identity_copied().map(|(c, _)| c), + self.explicit_implied_const_bounds(def_id).iter_identity_copied().map(|(c, _)| c), ) } @@ -596,11 +602,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.coroutine_is_async_gen(coroutine_def_id) } - fn layout_is_pointer_like(self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { - self.layout_of(self.erase_regions(param_env.and(ty))) - .is_ok_and(|layout| layout.layout.is_pointer_like(&self.data_layout)) - } - type UnsizingParams = &'tcx rustc_index::bit_set::BitSet<u32>; fn unsizing_params_for_adt(self, adt_def_id: DefId) -> Self::UnsizingParams { self.unsizing_params_for_adt(adt_def_id) @@ -674,7 +675,6 @@ bidirectional_lang_item_map! { Metadata, Option, PointeeTrait, - PointerLike, Poll, Sized, TransmuteTrait, diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index bf741f63a3d..505c7278176 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -3,7 +3,7 @@ use smallvec::SmallVec; use tracing::instrument; use crate::ty::context::TyCtxt; -use crate::ty::{self, DefId, OpaqueTypeKey, ParamEnv, Ty}; +use crate::ty::{self, DefId, OpaqueTypeKey, Ty, TypingEnv}; /// Represents whether some type is inhabited in a given context. /// Examples of uninhabited types are `!`, `enum Void {}`, or a struct @@ -35,8 +35,13 @@ pub enum InhabitedPredicate<'tcx> { impl<'tcx> InhabitedPredicate<'tcx> { /// Returns true if the corresponding type is inhabited in the given `ParamEnv` and module. - pub fn apply(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, module_def_id: DefId) -> bool { - self.apply_revealing_opaque(tcx, param_env, module_def_id, &|_| None) + pub fn apply( + self, + tcx: TyCtxt<'tcx>, + typing_env: TypingEnv<'tcx>, + module_def_id: DefId, + ) -> bool { + self.apply_revealing_opaque(tcx, typing_env, module_def_id, &|_| None) } /// Returns true if the corresponding type is inhabited in the given `ParamEnv` and module, @@ -44,13 +49,13 @@ impl<'tcx> InhabitedPredicate<'tcx> { pub fn apply_revealing_opaque( self, tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: TypingEnv<'tcx>, module_def_id: DefId, reveal_opaque: &impl Fn(OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>>, ) -> bool { let Ok(result) = self.apply_inner::<!>( tcx, - param_env, + typing_env, &mut Default::default(), &|id| Ok(tcx.is_descendant_of(module_def_id, id)), reveal_opaque, @@ -59,25 +64,25 @@ impl<'tcx> InhabitedPredicate<'tcx> { } /// Same as `apply`, but returns `None` if self contains a module predicate - pub fn apply_any_module(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> { - self.apply_inner(tcx, param_env, &mut Default::default(), &|_| Err(()), &|_| None).ok() + pub fn apply_any_module(self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>) -> Option<bool> { + self.apply_inner(tcx, typing_env, &mut Default::default(), &|_| Err(()), &|_| None).ok() } /// Same as `apply`, but `NotInModule(_)` predicates yield `false`. That is, /// privately uninhabited types are considered always uninhabited. - pub fn apply_ignore_module(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> bool { + pub fn apply_ignore_module(self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>) -> bool { let Ok(result) = - self.apply_inner::<!>(tcx, param_env, &mut Default::default(), &|_| Ok(true), &|_| { + self.apply_inner::<!>(tcx, typing_env, &mut Default::default(), &|_| Ok(true), &|_| { None }); result } - #[instrument(level = "debug", skip(tcx, param_env, in_module, reveal_opaque), ret)] + #[instrument(level = "debug", skip(tcx, typing_env, in_module, reveal_opaque), ret)] fn apply_inner<E: std::fmt::Debug>( self, tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: TypingEnv<'tcx>, eval_stack: &mut SmallVec<[Ty<'tcx>; 1]>, // for cycle detection in_module: &impl Fn(DefId) -> Result<bool, E>, reveal_opaque: &impl Fn(OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>>, @@ -94,7 +99,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { // we have a param_env available, we can do better. Self::GenericType(t) => { let normalized_pred = tcx - .try_normalize_erasing_regions(param_env, t) + .try_normalize_erasing_regions(typing_env, t) .map_or(self, |t| t.inhabited_predicate(tcx)); match normalized_pred { // We don't have more information than we started with, so consider inhabited. @@ -107,7 +112,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { } eval_stack.push(t); let ret = - pred.apply_inner(tcx, param_env, eval_stack, in_module, reveal_opaque); + pred.apply_inner(tcx, typing_env, eval_stack, in_module, reveal_opaque); eval_stack.pop(); ret } @@ -126,7 +131,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { eval_stack.push(t); let ret = t.inhabited_predicate(tcx).apply_inner( tcx, - param_env, + typing_env, eval_stack, in_module, reveal_opaque, @@ -136,10 +141,10 @@ impl<'tcx> InhabitedPredicate<'tcx> { } }, Self::And([a, b]) => try_and(a, b, |x| { - x.apply_inner(tcx, param_env, eval_stack, in_module, reveal_opaque) + x.apply_inner(tcx, typing_env, eval_stack, in_module, reveal_opaque) }), Self::Or([a, b]) => try_or(a, b, |x| { - x.apply_inner(tcx, param_env, eval_stack, in_module, reveal_opaque) + x.apply_inner(tcx, typing_env, eval_stack, in_module, reveal_opaque) }), } } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index dd00db8635f..4a5f6d80f24 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -181,18 +181,18 @@ impl<'tcx> Ty<'tcx> { self, tcx: TyCtxt<'tcx>, module: DefId, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> bool { - self.inhabited_predicate(tcx).apply(tcx, param_env, module) + self.inhabited_predicate(tcx).apply(tcx, typing_env, module) } /// Returns true if the type is uninhabited without regard to visibility pub fn is_privately_uninhabited( self, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> bool { - !self.inhabited_predicate(tcx).apply_ignore_module(tcx, param_env) + !self.inhabited_predicate(tcx).apply_ignore_module(tcx, typing_env) } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 0d1c56f0d38..dab3e18de33 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -178,9 +178,9 @@ pub enum InstanceKind<'tcx> { impl<'tcx> Instance<'tcx> { /// Returns the `Ty` corresponding to this `Instance`, with generic instantiations applied and /// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization. - pub fn ty(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> { + pub fn ty(&self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Ty<'tcx> { let ty = tcx.type_of(self.def.def_id()); - tcx.instantiate_and_normalize_erasing_regions(self.args, param_env, ty) + tcx.instantiate_and_normalize_erasing_regions(self.args, typing_env, ty) } /// Finds a crate that contains a monomorphization of this instance that @@ -519,7 +519,7 @@ impl<'tcx> Instance<'tcx> { #[instrument(level = "debug", skip(tcx), ret)] pub fn try_resolve( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>, ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> { @@ -537,17 +537,12 @@ impl<'tcx> Instance<'tcx> { // All regions in the result of this query are erased, so it's // fine to erase all of the input regions. - - // HACK(eddyb) erase regions in `args` first, so that `param_env.and(...)` - // below is more likely to ignore the bounds in scope (e.g. if the only - // generic parameters mentioned by `args` were lifetime ones). - let args = tcx.erase_regions(args); - tcx.resolve_instance_raw(tcx.erase_regions(param_env.and((def_id, args)))) + tcx.resolve_instance_raw(tcx.erase_regions(typing_env.as_query_input((def_id, args)))) } pub fn expect_resolve( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>, span: Span, @@ -558,7 +553,7 @@ impl<'tcx> Instance<'tcx> { let span_or_local_def_span = || if span.is_dummy() && def_id.is_local() { tcx.def_span(def_id) } else { span }; - match ty::Instance::try_resolve(tcx, param_env, def_id, args) { + match ty::Instance::try_resolve(tcx, typing_env, def_id, args) { Ok(Some(instance)) => instance, Ok(None) => { let type_length = type_length(args); @@ -600,7 +595,7 @@ impl<'tcx> Instance<'tcx> { pub fn resolve_for_fn_ptr( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>, ) -> Option<Instance<'tcx>> { @@ -608,7 +603,7 @@ impl<'tcx> Instance<'tcx> { // Use either `resolve_closure` or `resolve_for_vtable` assert!(!tcx.is_closure_like(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}"); let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::FnPtr); - Instance::try_resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { + Instance::try_resolve(tcx, typing_env, def_id, args).ok().flatten().map(|mut resolved| { match resolved.def { InstanceKind::Item(def) if resolved.def.requires_caller_location(tcx) => { debug!(" => fn pointer created for function with #[track_caller]"); @@ -648,7 +643,7 @@ impl<'tcx> Instance<'tcx> { pub fn expect_resolve_for_vtable( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>, span: Span, @@ -664,7 +659,7 @@ impl<'tcx> Instance<'tcx> { return Instance { def: InstanceKind::VTableShim(def_id), args }; } - let mut resolved = Instance::expect_resolve(tcx, param_env, def_id, args, span); + let mut resolved = Instance::expect_resolve(tcx, typing_env, def_id, args, span); let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable); match resolved.def { @@ -743,7 +738,7 @@ impl<'tcx> Instance<'tcx> { let args = tcx.mk_args(&[ty.into()]); Instance::expect_resolve( tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), def_id, args, ty.ty_adt_def().and_then(|adt| tcx.hir().span_if_local(adt.did())).unwrap_or(DUMMY_SP), @@ -755,7 +750,7 @@ impl<'tcx> Instance<'tcx> { let args = tcx.mk_args(&[ty.into()]); Instance::expect_resolve( tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), def_id, args, ty.ty_adt_def().and_then(|adt| tcx.hir().span_if_local(adt.did())).unwrap_or(DUMMY_SP), @@ -883,16 +878,16 @@ impl<'tcx> Instance<'tcx> { pub fn instantiate_mir_and_normalize_erasing_regions<T>( &self, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, v: EarlyBinder<'tcx, T>, ) -> T where T: TypeFoldable<TyCtxt<'tcx>>, { if let Some(args) = self.args_for_mir_body() { - tcx.instantiate_and_normalize_erasing_regions(args, param_env, v) + tcx.instantiate_and_normalize_erasing_regions(args, typing_env, v) } else { - tcx.normalize_erasing_regions(param_env, v.instantiate_identity()) + tcx.normalize_erasing_regions(typing_env, v.instantiate_identity()) } } @@ -901,21 +896,21 @@ impl<'tcx> Instance<'tcx> { pub fn try_instantiate_mir_and_normalize_erasing_regions<T>( &self, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, v: EarlyBinder<'tcx, T>, ) -> Result<T, NormalizationError<'tcx>> where T: TypeFoldable<TyCtxt<'tcx>>, { if let Some(args) = self.args_for_mir_body() { - tcx.try_instantiate_and_normalize_erasing_regions(args, param_env, v) + tcx.try_instantiate_and_normalize_erasing_regions(args, typing_env, v) } else { // We're using `instantiate_identity` as e.g. // `FnPtrShim` is separately generated for every // instantiation of the `FnDef`, so the MIR body // is already instantiated. Any generic parameters it // contains are generic parameters from the caller. - tcx.try_normalize_erasing_regions(param_env, v.instantiate_identity()) + tcx.try_normalize_erasing_regions(typing_env, v.instantiate_identity()) } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index a0eb9029319..fc29b438d3a 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -297,12 +297,12 @@ impl<'tcx> IntoDiagArg for LayoutError<'tcx> { #[derive(Clone, Copy)] pub struct LayoutCx<'tcx> { pub calc: abi::LayoutCalculator<TyCtxt<'tcx>>, - pub param_env: ty::ParamEnv<'tcx>, + pub typing_env: ty::TypingEnv<'tcx>, } impl<'tcx> LayoutCx<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { - Self { calc: abi::LayoutCalculator::new(tcx), param_env } + pub fn new(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Self { + Self { calc: abi::LayoutCalculator::new(tcx), typing_env } } } @@ -337,12 +337,12 @@ impl<'tcx> SizeSkeleton<'tcx> { pub fn compute( ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> Result<SizeSkeleton<'tcx>, &'tcx LayoutError<'tcx>> { debug_assert!(!ty.has_non_region_infer()); // First try computing a static layout. - let err = match tcx.layout_of(param_env.and(ty)) { + let err = match tcx.layout_of(typing_env.as_query_input(ty)) { Ok(layout) => { if layout.is_sized() { return Ok(SizeSkeleton::Known(layout.size, Some(layout.align.abi))); @@ -367,7 +367,7 @@ impl<'tcx> SizeSkeleton<'tcx> { let tail = tcx.struct_tail_raw( pointee, - |ty| match tcx.try_normalize_erasing_regions(param_env, ty) { + |ty| match tcx.try_normalize_erasing_regions(typing_env, ty) { Ok(ty) => ty, Err(e) => Ty::new_error_with_message( tcx, @@ -402,7 +402,7 @@ impl<'tcx> SizeSkeleton<'tcx> { return Ok(SizeSkeleton::Known(Size::from_bytes(0), None)); } - match SizeSkeleton::compute(inner, tcx, param_env)? { + match SizeSkeleton::compute(inner, tcx, typing_env)? { // This may succeed because the multiplication of two types may overflow // but a single size of a nested array will not. SizeSkeleton::Known(s, a) => { @@ -432,7 +432,7 @@ impl<'tcx> SizeSkeleton<'tcx> { let i = VariantIdx::from_usize(i); let fields = def.variant(i).fields.iter().map(|field| { - SizeSkeleton::compute(field.ty(tcx, args), tcx, param_env) + SizeSkeleton::compute(field.ty(tcx, args), tcx, typing_env) }); let mut ptr = None; for field in fields { @@ -491,11 +491,11 @@ impl<'tcx> SizeSkeleton<'tcx> { } ty::Alias(..) => { - let normalized = tcx.normalize_erasing_regions(param_env, ty); + let normalized = tcx.normalize_erasing_regions(typing_env, ty); if ty == normalized { Err(err) } else { - SizeSkeleton::compute(normalized, tcx, param_env) + SizeSkeleton::compute(normalized, tcx, typing_env) } } @@ -521,8 +521,14 @@ pub trait HasTyCtxt<'tcx>: HasDataLayout { fn tcx(&self) -> TyCtxt<'tcx>; } -pub trait HasParamEnv<'tcx> { - fn param_env(&self) -> ty::ParamEnv<'tcx>; +pub trait HasTypingEnv<'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx>; + + /// FIXME(#132279): This method should not be used as in the future + /// everything should take a `TypingEnv` instead. Remove it as that point. + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.typing_env().param_env + } } impl<'tcx> HasDataLayout for TyCtxt<'tcx> { @@ -577,9 +583,9 @@ impl<'tcx> HasTyCtxt<'tcx> for TyCtxtAt<'tcx> { } } -impl<'tcx> HasParamEnv<'tcx> for LayoutCx<'tcx> { - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env +impl<'tcx> HasTypingEnv<'tcx> for LayoutCx<'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + self.typing_env } } @@ -646,7 +652,7 @@ pub type TyAndLayout<'tcx> = rustc_abi::TyAndLayout<'tcx, Ty<'tcx>>; /// Trait for contexts that want to be able to compute layouts of types. /// This automatically gives access to `LayoutOf`, through a blanket `impl`. -pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasParamEnv<'tcx> { +pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> { /// The `TyAndLayout`-wrapping type (or `TyAndLayout` itself), which will be /// returned from `layout_of` (see also `handle_layout_err`). type LayoutOfResult: MaybeResult<TyAndLayout<'tcx>> = TyAndLayout<'tcx>; @@ -692,7 +698,7 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> { let tcx = self.tcx().at(span); MaybeResult::from( - tcx.layout_of(self.param_env().and(ty)) + tcx.layout_of(self.typing_env().as_query_input(ty)) .map_err(|err| self.handle_layout_err(*err, span, ty)), ) } @@ -716,7 +722,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx> { impl<'tcx, C> TyAbiInterface<'tcx, C> for Ty<'tcx> where - C: HasTyCtxt<'tcx> + HasParamEnv<'tcx>, + C: HasTyCtxt<'tcx> + HasTypingEnv<'tcx>, { fn ty_and_layout_for_variant( this: TyAndLayout<'tcx>, @@ -736,10 +742,10 @@ where Variants::Single { index } => { let tcx = cx.tcx(); - let param_env = cx.param_env(); + let typing_env = cx.typing_env(); // Deny calling for_variant more than once for non-Single enums. - if let Ok(original_layout) = tcx.layout_of(param_env.and(this.ty)) { + if let Ok(original_layout) = tcx.layout_of(typing_env.as_query_input(this.ty)) { assert_eq!(original_layout.variants, Variants::Single { index }); } @@ -780,7 +786,7 @@ where fn field_ty_or_layout<'tcx>( this: TyAndLayout<'tcx>, - cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>), + cx: &(impl HasTyCtxt<'tcx> + HasTypingEnv<'tcx>), i: usize, ) -> TyMaybeWithLayout<'tcx> { let tcx = cx.tcx(); @@ -823,12 +829,13 @@ where Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, nil) }; - // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing - // the `Result` should always work because the type is - // always either `*mut ()` or `&'static mut ()`. + // NOTE: using an fully monomorphized typing env and `unwrap`-ing + // the `Result` should always work because the type is always either + // `*mut ()` or `&'static mut ()`. + let typing_env = ty::TypingEnv::fully_monomorphized(); return TyMaybeWithLayout::TyAndLayout(TyAndLayout { ty: this.ty, - ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap() + ..tcx.layout_of(typing_env.as_query_input(unit_ptr_ty)).unwrap() }); } @@ -848,7 +855,7 @@ where && !pointee.references_error() { let metadata = tcx.normalize_erasing_regions( - cx.param_env(), + cx.typing_env(), Ty::new_projection(tcx, metadata_def_id, [pointee]), ); @@ -865,7 +872,7 @@ where metadata } } else { - match tcx.struct_tail_for_codegen(pointee, cx.param_env()).kind() { + match tcx.struct_tail_for_codegen(pointee, cx.typing_env()).kind() { ty::Slice(_) | ty::Str => tcx.types.usize, ty::Dynamic(data, _, ty::Dyn) => mk_dyn_vtable(data.principal()), _ => bug!("TyAndLayout::field({:?}): not applicable", this), @@ -953,7 +960,7 @@ where match field_ty_or_layout(this, cx, i) { TyMaybeWithLayout::Ty(field_ty) => { - cx.tcx().layout_of(cx.param_env().and(field_ty)).unwrap_or_else(|e| { + cx.tcx().layout_of(cx.typing_env().as_query_input(field_ty)).unwrap_or_else(|e| { bug!( "failed to get layout for `{field_ty}`: {e:?},\n\ despite it being a field (#{i}) of an existing layout: {this:#?}", @@ -972,18 +979,18 @@ where offset: Size, ) -> Option<PointeeInfo> { let tcx = cx.tcx(); - let param_env = cx.param_env(); + let typing_env = cx.typing_env(); let pointee_info = match *this.ty.kind() { ty::RawPtr(p_ty, _) if offset.bytes() == 0 => { - tcx.layout_of(param_env.and(p_ty)).ok().map(|layout| PointeeInfo { + tcx.layout_of(typing_env.as_query_input(p_ty)).ok().map(|layout| PointeeInfo { size: layout.size, align: layout.align.abi, safe: None, }) } ty::FnPtr(..) if offset.bytes() == 0 => { - tcx.layout_of(param_env.and(this.ty)).ok().map(|layout| PointeeInfo { + tcx.layout_of(typing_env.as_query_input(this.ty)).ok().map(|layout| PointeeInfo { size: layout.size, align: layout.align.abi, safe: None, @@ -995,15 +1002,15 @@ where // attributes in LLVM have compile-time cost even in unoptimized builds). let optimize = tcx.sess.opts.optimize != OptLevel::No; let kind = match mt { - hir::Mutability::Not => PointerKind::SharedRef { - frozen: optimize && ty.is_freeze(tcx, cx.param_env()), - }, - hir::Mutability::Mut => PointerKind::MutableRef { - unpin: optimize && ty.is_unpin(tcx, cx.param_env()), - }, + hir::Mutability::Not => { + PointerKind::SharedRef { frozen: optimize && ty.is_freeze(tcx, typing_env) } + } + hir::Mutability::Mut => { + PointerKind::MutableRef { unpin: optimize && ty.is_unpin(tcx, typing_env) } + } }; - tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo { + tcx.layout_of(typing_env.as_query_input(ty)).ok().map(|layout| PointeeInfo { size: layout.size, align: layout.align.abi, safe: Some(kind), @@ -1093,7 +1100,7 @@ where debug_assert!(pointee.safe.is_none()); let optimize = tcx.sess.opts.optimize != OptLevel::No; pointee.safe = Some(PointerKind::Box { - unpin: optimize && boxed_ty.is_unpin(tcx, cx.param_env()), + unpin: optimize && boxed_ty.is_unpin(tcx, typing_env), global: this.ty.is_box_global(tcx), }); } @@ -1304,9 +1311,11 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { let span = self.layout_tcx_at_span(); let tcx = self.tcx().at(span); - MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err( - |err| self.handle_fn_abi_err(*err, span, FnAbiRequest::OfFnPtr { sig, extra_args }), - )) + MaybeResult::from( + tcx.fn_abi_of_fn_ptr(self.typing_env().as_query_input((sig, extra_args))).map_err( + |err| self.handle_fn_abi_err(*err, span, FnAbiRequest::OfFnPtr { sig, extra_args }), + ), + ) } /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for @@ -1326,17 +1335,19 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { let tcx = self.tcx().at(span); MaybeResult::from( - tcx.fn_abi_of_instance(self.param_env().and((instance, extra_args))).map_err(|err| { - // HACK(eddyb) at least for definitions of/calls to `Instance`s, - // we can get some kind of span even if one wasn't provided. - // However, we don't do this early in order to avoid calling - // `def_span` unconditionally (which may have a perf penalty). - let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) }; - self.handle_fn_abi_err(*err, span, FnAbiRequest::OfInstance { - instance, - extra_args, - }) - }), + tcx.fn_abi_of_instance(self.typing_env().as_query_input((instance, extra_args))) + .map_err(|err| { + // HACK(eddyb) at least for definitions of/calls to `Instance`s, + // we can get some kind of span even if one wasn't provided. + // However, we don't do this early in order to avoid calling + // `def_span` unconditionally (which may have a perf penalty). + let span = + if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) }; + self.handle_fn_abi_err(*err, span, FnAbiRequest::OfInstance { + instance, + extra_args, + }) + }), ) } } @@ -1346,14 +1357,14 @@ impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {} impl<'tcx> TyCtxt<'tcx> { pub fn offset_of_subfield<I>( self, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, mut layout: TyAndLayout<'tcx>, indices: I, ) -> Size where I: Iterator<Item = (VariantIdx, FieldIdx)>, { - let cx = LayoutCx::new(self, param_env); + let cx = LayoutCx::new(self, typing_env); let mut offset = Size::ZERO; for (variant, field) in indices { @@ -1363,7 +1374,7 @@ impl<'tcx> TyCtxt<'tcx> { layout = layout.field(&cx, index); if !layout.is_sized() { // If it is not sized, then the tail must still have at least a known static alignment. - let tail = self.struct_tail_for_codegen(layout.ty, param_env); + let tail = self.struct_tail_for_codegen(layout.ty, typing_env); if !matches!(tail.kind(), ty::Slice(..)) { bug!( "offset of not-statically-aligned field (type {:?}) cannot be computed statically", diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 7fda0662a34..2bc055453a4 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, @@ -103,7 +103,7 @@ use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; use crate::metadata::ModChild; use crate::middle::privacy::EffectiveVisibilities; use crate::mir::{Body, CoroutineLayout}; -use crate::query::Providers; +use crate::query::{IntoQueryParam, Providers}; use crate::traits::{self, Reveal}; use crate::ty; pub use crate::ty::diagnostics::*; @@ -1122,6 +1122,98 @@ impl<'tcx, T> ParamEnvAnd<'tcx, T> { } } +/// The environment in which to do trait solving. +/// +/// Most of the time you only need to care about the `ParamEnv` +/// as the `TypingMode` is simply stored in the `InferCtxt`. +/// +/// However, there are some places which rely on trait solving +/// without using an `InferCtxt` themselves. For these to be +/// able to use the trait system they have to be able to initialize +/// such an `InferCtxt` with the right `typing_mode`, so they need +/// to track both. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] +#[derive(TypeVisitable, TypeFoldable)] +pub struct TypingEnv<'tcx> { + pub typing_mode: TypingMode<'tcx>, + pub param_env: ParamEnv<'tcx>, +} + +impl<'tcx> TypingEnv<'tcx> { + /// Create a typing environment with no where-clauses in scope + /// where all opaque types and default associated items are revealed. + /// + /// This is only suitable for monomorphized, post-typeck environments. + /// Do not use this for MIR optimizations, as even though they also + /// use `TypingMode::PostAnalysis`, they may still have where-clauses + /// in scope. + pub fn fully_monomorphized() -> TypingEnv<'tcx> { + TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env: ParamEnv::reveal_all() } + } + + /// Create a typing environment for use during analysis outside of a body. + /// + /// Using a typing environment inside of bodies is not supported as the body + /// may define opaque types. In this case the used functions have to be + /// converted to use proper canonical inputs instead. + pub fn non_body_analysis( + tcx: TyCtxt<'tcx>, + def_id: impl IntoQueryParam<DefId>, + ) -> TypingEnv<'tcx> { + TypingEnv { typing_mode: TypingMode::non_body_analysis(), param_env: tcx.param_env(def_id) } + } + + pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryParam<DefId>) -> TypingEnv<'tcx> { + TypingEnv { + typing_mode: TypingMode::PostAnalysis, + param_env: tcx.param_env_reveal_all_normalized(def_id), + } + } + + /// Modify the `typing_mode` to `PostAnalysis` and eagerly reveal all + /// opaque types in the `param_env`. + pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> { + let TypingEnv { typing_mode: _, param_env } = self; + let param_env = param_env.with_reveal_all_normalized(tcx); + TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env } + } + + /// Combine this typing environment with the given `value` to be used by + /// not (yet) canonicalized queries. This only works if the value does not + /// contain anything local to some `InferCtxt`, i.e. inference variables or + /// placeholders. + pub fn as_query_input<T>(self, value: T) -> PseudoCanonicalInput<'tcx, T> + where + T: TypeVisitable<TyCtxt<'tcx>>, + { + // FIXME(#132279): We should assert that the value does not contain any placeholders + // as these placeholders are also local to the current inference context. However, we + // currently use pseudo-canonical queries in the trait solver which replaces params with + // placeholders. We should also simply not use pseudo-canonical queries in the trait + // solver, at which point we can readd this assert. As of writing this comment, this is + // only used by `fn layout_is_pointer_like` when calling `layout_of`. + // + // debug_assert!(!value.has_placeholders()); + PseudoCanonicalInput { typing_env: self, value } + } +} + +/// Similar to `CanonicalInput`, this carries the `typing_mode` and the environment +/// necessary to do any kind of trait solving inside of nested queries. +/// +/// Unlike proper canonicalization, this requires the `param_env` and the `value` to not +/// contain anything local to the `infcx` of the caller, so we don't actually canonicalize +/// anything. +/// +/// This should be created by using `infcx.pseudo_canonicalize_query(param_env, value)` +/// or by using `typing_env.as_query_input(value)`. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable, TypeVisitable, TypeFoldable)] +pub struct PseudoCanonicalInput<'tcx, T> { + pub typing_env: TypingEnv<'tcx>, + pub value: T, +} + #[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)] pub struct Destructor { /// The `DefId` of the destructor method @@ -2018,7 +2110,13 @@ impl<'tcx> TyCtxt<'tcx> { _ => bug!("unexpected parent item of associated item: {parent_def_id:?}"), } } - DefKind::Closure | DefKind::OpaqueTy => { + DefKind::OpaqueTy => match self.opaque_ty_origin(def_id) { + hir::OpaqueTyOrigin::FnReturn { parent, .. } => self.is_conditionally_const(parent), + hir::OpaqueTyOrigin::AsyncFn { .. } => false, + // FIXME(const_trait_impl): ATPITs could be conditionally const? + hir::OpaqueTyOrigin::TyAlias { .. } => false, + }, + DefKind::Closure => { // Closures and RPITs will eventually have const conditions // for `~const` bounds. false @@ -2150,7 +2248,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_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index e51d2201922..f611b69905c 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -35,16 +35,16 @@ impl<'tcx> TyCtxt<'tcx> { /// /// This should only be used outside of type inference. For example, /// it assumes that normalization will succeed. - #[tracing::instrument(level = "debug", skip(self, param_env), ret)] - pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T + #[tracing::instrument(level = "debug", skip(self, typing_env), ret)] + pub fn normalize_erasing_regions<T>(self, typing_env: ty::TypingEnv<'tcx>, value: T) -> T where T: TypeFoldable<TyCtxt<'tcx>>, { debug!( - "normalize_erasing_regions::<{}>(value={:?}, param_env={:?})", + "normalize_erasing_regions::<{}>(value={:?}, typing_env={:?})", std::any::type_name::<T>(), value, - param_env, + typing_env, ); // Erase first before we do the real query -- this keeps the @@ -55,7 +55,7 @@ impl<'tcx> TyCtxt<'tcx> { if !value.has_aliases() { value } else { - value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env }) + value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, typing_env }) } } @@ -66,17 +66,17 @@ impl<'tcx> TyCtxt<'tcx> { /// succeeds. pub fn try_normalize_erasing_regions<T>( self, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, value: T, ) -> Result<T, NormalizationError<'tcx>> where T: TypeFoldable<TyCtxt<'tcx>>, { debug!( - "try_normalize_erasing_regions::<{}>(value={:?}, param_env={:?})", + "try_normalize_erasing_regions::<{}>(value={:?}, typing_env={:?})", std::any::type_name::<T>(), value, - param_env, + typing_env, ); // Erase first before we do the real query -- this keeps the @@ -87,7 +87,7 @@ impl<'tcx> TyCtxt<'tcx> { if !value.has_aliases() { Ok(value) } else { - let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, param_env); + let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, typing_env); value.try_fold_with(&mut folder) } } @@ -103,17 +103,17 @@ impl<'tcx> TyCtxt<'tcx> { // FIXME(@lcnr): This method should not be necessary, we now normalize // inside of binders. We should be able to only use // `tcx.instantiate_bound_regions_with_erased`. - #[tracing::instrument(level = "debug", skip(self, param_env))] + #[tracing::instrument(level = "debug", skip(self, typing_env))] pub fn normalize_erasing_late_bound_regions<T>( self, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, value: ty::Binder<'tcx, T>, ) -> T where T: TypeFoldable<TyCtxt<'tcx>>, { let value = self.instantiate_bound_regions_with_erased(value); - self.normalize_erasing_regions(param_env, value) + self.normalize_erasing_regions(typing_env, value) } /// Monomorphizes a type from the AST by first applying the @@ -125,14 +125,14 @@ impl<'tcx> TyCtxt<'tcx> { pub fn instantiate_and_normalize_erasing_regions<T>( self, param_args: GenericArgsRef<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, value: EarlyBinder<'tcx, T>, ) -> T where T: TypeFoldable<TyCtxt<'tcx>>, { let instantiated = value.instantiate(self, param_args); - self.normalize_erasing_regions(param_env, instantiated) + self.normalize_erasing_regions(typing_env, instantiated) } /// Monomorphizes a type from the AST by first applying the @@ -143,20 +143,20 @@ impl<'tcx> TyCtxt<'tcx> { pub fn try_instantiate_and_normalize_erasing_regions<T>( self, param_args: GenericArgsRef<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, value: EarlyBinder<'tcx, T>, ) -> Result<T, NormalizationError<'tcx>> where T: TypeFoldable<TyCtxt<'tcx>>, { let instantiated = value.instantiate(self, param_args); - self.try_normalize_erasing_regions(param_env, instantiated) + self.try_normalize_erasing_regions(typing_env, instantiated) } } struct NormalizeAfterErasingRegionsFolder<'tcx> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, } impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> { @@ -164,8 +164,7 @@ impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> { &self, arg: ty::GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { - let arg = self.param_env.and(arg); - + let arg = self.typing_env.as_query_input(arg); self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!( "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead", arg.value @@ -189,12 +188,12 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for NormalizeAfterErasingRegionsFolder<'tcx> struct TryNormalizeAfterErasingRegionsFolder<'tcx> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, } impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> { - fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { - TryNormalizeAfterErasingRegionsFolder { tcx, param_env } + fn new(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Self { + TryNormalizeAfterErasingRegionsFolder { tcx, typing_env } } #[instrument(skip(self), level = "debug")] @@ -202,10 +201,8 @@ impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> { &self, arg: ty::GenericArg<'tcx>, ) -> Result<ty::GenericArg<'tcx>, NoSolution> { - let arg = self.param_env.and(arg); - debug!(?arg); - - self.tcx.try_normalize_generic_arg_after_erasing_regions(arg) + let input = self.typing_env.as_query_input(arg); + self.tcx.try_normalize_generic_arg_after_erasing_regions(input) } } diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs index 37dcf7c0d64..57c2d7623d2 100644 --- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs +++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs @@ -18,15 +18,17 @@ impl RvalueScopes { } /// Returns the scope when the temp created by `expr_id` will be cleaned up. + /// It also emits a lint on potential backwards incompatible change to the temporary scope + /// which is *for now* always shortening. pub fn temporary_scope( &self, region_scope_tree: &ScopeTree, expr_id: hir::ItemLocalId, - ) -> Option<Scope> { + ) -> (Option<Scope>, Option<Scope>) { // Check for a designated rvalue scope. if let Some(&s) = self.map.get(&expr_id) { debug!("temporary_scope({expr_id:?}) = {s:?} [custom]"); - return s; + return (s, None); } // Otherwise, locate the innermost terminating scope @@ -34,27 +36,40 @@ impl RvalueScopes { // have an enclosing scope, hence no scope will be // returned. let mut id = Scope { id: expr_id, data: ScopeData::Node }; + let mut backwards_incompatible = None; while let Some(&(p, _)) = region_scope_tree.parent_map.get(&id) { match p.data { ScopeData::Destruction => { debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]"); - return Some(id); + return (Some(id), backwards_incompatible); } ScopeData::IfThenRescope => { debug!("temporary_scope({expr_id:?}) = {p:?} [enclosing]"); - return Some(p); + return (Some(p), backwards_incompatible); } ScopeData::Node | ScopeData::CallSite | ScopeData::Arguments | ScopeData::IfThen - | ScopeData::Remainder(_) => id = p, + | ScopeData::Remainder(_) => { + // If we haven't already passed through a backwards-incompatible node, + // then check if we are passing through one now and record it if so. + // This is for now only working for cases where a temporary lifetime is + // *shortened*. + if backwards_incompatible.is_none() { + backwards_incompatible = region_scope_tree + .backwards_incompatible_scope + .get(&p.item_local_id()) + .copied(); + } + id = p + } } } debug!("temporary_scope({expr_id:?}) = None"); - None + (None, backwards_incompatible) } /// Make an association between a sub-expression and an extended lifetime diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 3c6e34160f4..20c3f84bb4d 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -18,6 +18,7 @@ use rustc_span::sym; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; +use super::TypingEnv; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::query::Providers; use crate::ty::layout::{FloatExt, IntegerExt}; @@ -177,9 +178,13 @@ impl<'tcx> TyCtxt<'tcx> { /// Should only be called if `ty` has no inference variables and does not /// need its lifetimes preserved (e.g. as part of codegen); otherwise /// normalization attempt may cause compiler bugs. - pub fn struct_tail_for_codegen(self, ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> { + pub fn struct_tail_for_codegen( + self, + ty: Ty<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + ) -> Ty<'tcx> { let tcx = self; - tcx.struct_tail_raw(ty, |ty| tcx.normalize_erasing_regions(param_env, ty), || {}) + tcx.struct_tail_raw(ty, |ty| tcx.normalize_erasing_regions(typing_env, ty), || {}) } /// Returns the deeply last field of nested structures, or the same type if @@ -271,11 +276,11 @@ impl<'tcx> TyCtxt<'tcx> { self, source: Ty<'tcx>, target: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> (Ty<'tcx>, Ty<'tcx>) { let tcx = self; tcx.struct_lockstep_tails_raw(source, target, |ty| { - tcx.normalize_erasing_regions(param_env, ty) + tcx.normalize_erasing_regions(typing_env, ty) }) } @@ -420,10 +425,10 @@ impl<'tcx> TyCtxt<'tcx> { // Async drop glue morphology is an internal detail, so reveal_all probably // should be fine - let param_env = ty::ParamEnv::reveal_all(); - if ty.needs_async_drop(self, param_env) { + let typing_env = ty::TypingEnv::fully_monomorphized(); + if ty.needs_async_drop(self, typing_env) { AsyncDropGlueMorphology::Custom - } else if ty.needs_drop(self, param_env) { + } else if ty.needs_drop(self, typing_env) { AsyncDropGlueMorphology::DeferredDropInPlace } else { AsyncDropGlueMorphology::Noop @@ -683,12 +688,10 @@ impl<'tcx> TyCtxt<'tcx> { } /// Get the type of the pointer to the static that we use in MIR. - pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> { + pub fn static_ptr_ty(self, def_id: DefId, typing_env: ty::TypingEnv<'tcx>) -> Ty<'tcx> { // Make sure that any constants in the static's type are evaluated. - let static_ty = self.normalize_erasing_regions( - ty::ParamEnv::empty(), - self.type_of(def_id).instantiate_identity(), - ); + let static_ty = + self.normalize_erasing_regions(typing_env, self.type_of(def_id).instantiate_identity()); // Make sure that accesses to unsafe statics end up using raw pointers. // For thread-locals, this needs to be kept in sync with `Rvalue::ty`. @@ -1157,15 +1160,17 @@ impl<'tcx> Ty<'tcx> { /// Returns the maximum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> { + let typing_env = TypingEnv::fully_monomorphized(); self.numeric_min_and_max_as_bits(tcx) - .map(|(_, max)| ty::Const::from_bits(tcx, max, ty::ParamEnv::empty().and(self))) + .map(|(_, max)| ty::Const::from_bits(tcx, max, typing_env, self)) } /// Returns the minimum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> { + let typing_env = TypingEnv::fully_monomorphized(); self.numeric_min_and_max_as_bits(tcx) - .map(|(min, _)| ty::Const::from_bits(tcx, min, ty::ParamEnv::empty().and(self))) + .map(|(min, _)| ty::Const::from_bits(tcx, min, typing_env, self)) } /// Checks whether values of this type `T` are *moved* or *copied* @@ -1175,8 +1180,12 @@ impl<'tcx> Ty<'tcx> { /// does copies even when the type actually doesn't satisfy the /// full requirements for the `Copy` trait (cc #29149) -- this /// winds up being reported as an error during NLL borrow check. - pub fn is_copy_modulo_regions(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_pure_clone_copy() || tcx.is_copy_raw(param_env.and(self)) + pub fn is_copy_modulo_regions( + self, + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + ) -> bool { + self.is_trivially_pure_clone_copy() || tcx.is_copy_raw(typing_env.as_query_input(self)) } /// Checks whether values of this type `T` have a size known at @@ -1185,8 +1194,8 @@ impl<'tcx> Ty<'tcx> { /// over-approximation in generic contexts, where one can have /// strange rules like `<T as Foo<'static>>::Bar: Sized` that /// actually carry lifetime requirements. - pub fn is_sized(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_sized(tcx) || tcx.is_sized_raw(param_env.and(self)) + pub fn is_sized(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { + self.is_trivially_sized(tcx) || tcx.is_sized_raw(typing_env.as_query_input(self)) } /// Checks whether values of this type `T` implement the `Freeze` @@ -1196,8 +1205,8 @@ impl<'tcx> Ty<'tcx> { /// optimization as well as the rules around static values. Note /// that the `Freeze` trait is not exposed to end users and is /// effectively an implementation detail. - pub fn is_freeze(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_freeze() || tcx.is_freeze_raw(param_env.and(self)) + pub fn is_freeze(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { + self.is_trivially_freeze() || tcx.is_freeze_raw(typing_env.as_query_input(self)) } /// Fast path helper for testing if a type is `Freeze`. @@ -1236,8 +1245,8 @@ impl<'tcx> Ty<'tcx> { } /// Checks whether values of this type `T` implement the `Unpin` trait. - pub fn is_unpin(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_unpin() || tcx.is_unpin_raw(param_env.and(self)) + pub fn is_unpin(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { + self.is_trivially_unpin() || tcx.is_unpin_raw(typing_env.as_query_input(self)) } /// Fast path helper for testing if a type is `Unpin`. @@ -1345,7 +1354,7 @@ impl<'tcx> Ty<'tcx> { /// /// Note that this method is used to check eligible types in unions. #[inline] - pub fn needs_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + pub fn needs_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { // Avoid querying in simple cases. match needs_drop_components(tcx, self) { Err(AlwaysRequiresDrop) => true, @@ -1359,14 +1368,13 @@ impl<'tcx> Ty<'tcx> { }; // This doesn't depend on regions, so try to minimize distinct - // query keys used. - // If normalization fails, we just use `query_ty`. - debug_assert!(!param_env.has_infer()); + // query keys used. If normalization fails, we just use `query_ty`. + debug_assert!(!typing_env.param_env.has_infer()); let query_ty = tcx - .try_normalize_erasing_regions(param_env, query_ty) + .try_normalize_erasing_regions(typing_env, query_ty) .unwrap_or_else(|_| tcx.erase_regions(query_ty)); - tcx.needs_drop_raw(param_env.and(query_ty)) + tcx.needs_drop_raw(typing_env.as_query_input(query_ty)) } } } @@ -1385,7 +1393,7 @@ impl<'tcx> Ty<'tcx> { // FIXME(zetanumbers): Note that this method is used to check eligible types // in unions. #[inline] - pub fn needs_async_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + pub fn needs_async_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { // Avoid querying in simple cases. match needs_drop_components(tcx, self) { Err(AlwaysRequiresDrop) => true, @@ -1401,12 +1409,12 @@ impl<'tcx> Ty<'tcx> { // This doesn't depend on regions, so try to minimize distinct // query keys used. // If normalization fails, we just use `query_ty`. - debug_assert!(!param_env.has_infer()); + debug_assert!(!typing_env.has_infer()); let query_ty = tcx - .try_normalize_erasing_regions(param_env, query_ty) + .try_normalize_erasing_regions(typing_env, query_ty) .unwrap_or_else(|_| tcx.erase_regions(query_ty)); - tcx.needs_async_drop_raw(param_env.and(query_ty)) + tcx.needs_async_drop_raw(typing_env.as_query_input(query_ty)) } } } @@ -1420,7 +1428,7 @@ impl<'tcx> Ty<'tcx> { /// Note that this method is used to check for change in drop order for /// 2229 drop reorder migration analysis. #[inline] - pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { // Avoid querying in simple cases. match needs_drop_components(tcx, self) { Err(AlwaysRequiresDrop) => true, @@ -1443,8 +1451,8 @@ impl<'tcx> Ty<'tcx> { // This doesn't depend on regions, so try to minimize distinct // query keys used. - let erased = tcx.normalize_erasing_regions(param_env, query_ty); - tcx.has_significant_drop_raw(param_env.and(erased)) + let erased = tcx.normalize_erasing_regions(typing_env, query_ty); + tcx.has_significant_drop_raw(typing_env.as_query_input(erased)) } } } @@ -1793,7 +1801,7 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Intrinsi Some(ty::IntrinsicDef { name: tcx.item_name(def_id.into()), must_be_overridden: tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden), - const_stable: tcx.has_attr(def_id, sym::rustc_const_stable_intrinsic), + const_stable: tcx.has_attr(def_id, sym::rustc_intrinsic_const_stable_indirect), }) } else { None diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 963fa12a8c7..e5eeb23be25 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -97,7 +97,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( assert!(vtable_entries.len() >= vtable_min_entries(tcx, poly_trait_ref)); let layout = tcx - .layout_of(ty::ParamEnv::reveal_all().and(ty)) + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) .expect("failed to build vtable representation"); assert!(layout.is_sized(), "can't create a vtable for an unsized type"); let size = layout.size.bytes(); @@ -117,7 +117,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( let idx: u64 = u64::try_from(idx).unwrap(); let scalar = match entry { VtblEntry::MetadataDropInPlace => { - if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) { + if ty.needs_drop(tcx, ty::TypingEnv::fully_monomorphized()) { let instance = ty::Instance::resolve_drop_in_place(tcx, ty); let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT); let fn_ptr = Pointer::from(fn_alloc_id); diff --git a/compiler/rustc_middle/src/util/call_kind.rs b/compiler/rustc_middle/src/util/call_kind.rs index ed27a880562..acfb78b3f6e 100644 --- a/compiler/rustc_middle/src/util/call_kind.rs +++ b/compiler/rustc_middle/src/util/call_kind.rs @@ -8,7 +8,7 @@ use rustc_span::symbol::Ident; use rustc_span::{DesugaringKind, Span, sym}; use tracing::debug; -use crate::ty::{AssocItemContainer, GenericArgsRef, Instance, ParamEnv, Ty, TyCtxt}; +use crate::ty::{AssocItemContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv}; #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum CallDesugaringKind { @@ -62,7 +62,7 @@ pub enum CallKind<'tcx> { pub fn call_kind<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: TypingEnv<'tcx>, method_did: DefId, method_args: GenericArgsRef<'tcx>, fn_call_span: Span, @@ -98,10 +98,10 @@ pub fn call_kind<'tcx>( Some(CallKind::Operator { self_arg, trait_id, self_ty: method_args.type_at(0) }) } else if is_deref { let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { - Instance::try_resolve(tcx, param_env, deref_target, method_args).transpose() + Instance::try_resolve(tcx, typing_env, deref_target, method_args).transpose() }); if let Some(Ok(instance)) = deref_target { - let deref_target_ty = instance.ty(tcx, param_env); + let deref_target_ty = instance.ty(tcx, typing_env); Some(CallKind::DerefCoercion { deref_target: tcx.def_span(instance.def_id()), deref_target_ty, diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs index 4815db47b16..e809c9a23f3 100644 --- a/compiler/rustc_mir_build/src/build/custom/mod.rs +++ b/compiler/rustc_mir_build/src/build/custom/mod.rs @@ -25,7 +25,7 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::thir::*; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; mod parse; @@ -77,7 +77,7 @@ pub(super) fn build_custom_mir<'tcx>( let mut pctxt = ParseCtxt { tcx, - param_env: tcx.param_env(did), + typing_env: body.typing_env(tcx), thir, source_scope: OUTERMOST_SOURCE_SCOPE, body: &mut body, @@ -136,7 +136,7 @@ fn parse_attribute(attr: &Attribute) -> MirPhase { struct ParseCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, thir: &'a Thir<'tcx>, source_scope: SourceScope, body: &'a mut Body<'tcx>, diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 07964e304b9..c3e9bd302de 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -144,14 +144,22 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let mut targets = Vec::new(); for arm in rest { let arm = &self.thir[*arm]; - let PatKind::Constant { value } = arm.pattern.kind else { - return Err(ParseError { - span: arm.pattern.span, - item_description: format!("{:?}", arm.pattern.kind), - expected: "constant pattern".to_string(), - }); + let value = match arm.pattern.kind { + PatKind::Constant { value } => value, + PatKind::ExpandedConstant { ref subpattern, def_id: _, is_inline: false } + if let PatKind::Constant { value } = subpattern.kind => + { + value + } + _ => { + return Err(ParseError { + span: arm.pattern.span, + item_description: format!("{:?}", arm.pattern.kind), + expected: "constant pattern".to_string(), + }); + } }; - values.push(value.eval_bits(self.tcx, self.param_env)); + values.push(value.eval_bits(self.tcx, self.typing_env)); targets.push(self.parse_block(arm.body)?); } @@ -385,7 +393,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { | ExprKind::NonHirLiteral { .. } | ExprKind::ConstBlock { .. } => Ok({ let value = as_constant_inner(expr, |_| None, self.tcx); - value.const_.eval_bits(self.tcx, self.param_env) + value.const_.eval_bits(self.tcx, self.typing_env) }), ) } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 3f2e3b956fc..640408cb9c8 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -114,8 +114,7 @@ fn lit_to_mir_constant<'tcx>( ) -> Result<Const<'tcx>, LitToConstError> { let LitToConstInput { lit, ty, neg } = lit_input; let trunc = |n| { - let param_ty = ty::ParamEnv::reveal_all().and(ty); - let width = match tcx.layout_of(param_ty) { + let width = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) { Ok(layout) => layout.size, Err(_) => { tcx.dcx().bug(format!("couldn't compute width of literal: {:?}", lit_input.lit)) diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index 112eac32264..0cab853196b 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -1,6 +1,5 @@ //! See docs in build/expr/mod.rs -use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::thir::*; use tracing::{debug, instrument}; @@ -9,6 +8,12 @@ use crate::build::expr::category::Category; use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary}; impl<'a, 'tcx> Builder<'a, 'tcx> { + /// Construct a temporary lifetime restricted to just the local scope + pub(crate) fn local_temp_lifetime(&self) -> TempLifetime { + let local_scope = self.local_scope(); + TempLifetime { temp_lifetime: Some(local_scope), backwards_incompatible: None } + } + /// Returns an operand suitable for use until the end of the current /// scope expression. /// @@ -21,8 +26,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block: BasicBlock, expr_id: ExprId, ) -> BlockAnd<Operand<'tcx>> { - let local_scope = self.local_scope(); - self.as_operand(block, Some(local_scope), expr_id, LocalInfo::Boring, NeedsTemporary::Maybe) + self.as_operand( + block, + self.local_temp_lifetime(), + expr_id, + LocalInfo::Boring, + NeedsTemporary::Maybe, + ) } /// Returns an operand suitable for use until the end of the current scope expression and @@ -80,8 +90,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block: BasicBlock, expr: ExprId, ) -> BlockAnd<Operand<'tcx>> { - let local_scope = self.local_scope(); - self.as_call_operand(block, Some(local_scope), expr) + self.as_call_operand(block, self.local_temp_lifetime(), expr) } /// Compile `expr` into a value that can be used as an operand. @@ -102,7 +111,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn as_operand( &mut self, mut block: BasicBlock, - scope: Option<region::Scope>, + scope: TempLifetime, expr_id: ExprId, local_info: LocalInfo<'tcx>, needs_temporary: NeedsTemporary, @@ -123,7 +132,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match category { Category::Constant if matches!(needs_temporary, NeedsTemporary::No) - || !expr.ty.needs_drop(this.tcx, this.param_env) => + || !expr.ty.needs_drop(this.tcx, this.typing_env()) => { let constant = this.as_constant(expr); block.and(Operand::Constant(Box::new(constant))) @@ -146,7 +155,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn as_call_operand( &mut self, mut block: BasicBlock, - scope: Option<region::Scope>, + scope: TempLifetime, expr_id: ExprId, ) -> BlockAnd<Operand<'tcx>> { let this = self; @@ -165,11 +174,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if tcx.features().unsized_fn_params() { let ty = expr.ty; - let param_env = this.param_env; - - if !ty.is_sized(tcx, param_env) { + if !ty.is_sized(tcx, this.typing_env()) { // !sized means !copy, so this is an unsized move - assert!(!ty.is_copy_modulo_regions(tcx, param_env)); + assert!(!ty.is_copy_modulo_regions(tcx, this.typing_env())); // As described above, detect the case where we are passing a value of unsized // type, and that value is coming from the deref of a box. diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 9f6e0735b48..6ce88cdc39d 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -6,7 +6,6 @@ use std::iter; use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use rustc_hir::def_id::LocalDefId; use rustc_middle::hir::place::{Projection as HirProjection, ProjectionKind as HirProjectionKind}; -use rustc_middle::middle::region; use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; use rustc_middle::thir::*; @@ -598,7 +597,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { index: ExprId, mutability: Mutability, fake_borrow_temps: Option<&mut Vec<Local>>, - temp_lifetime: Option<region::Scope>, + temp_lifetime: TempLifetime, expr_span: Span, source_info: SourceInfo, ) -> BlockAnd<PlaceBuilder<'tcx>> { diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 1985dd3fca0..3f89e337781 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -33,14 +33,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_id: ExprId, ) -> BlockAnd<Rvalue<'tcx>> { let local_scope = self.local_scope(); - self.as_rvalue(block, Some(local_scope), expr_id) + self.as_rvalue( + block, + TempLifetime { temp_lifetime: Some(local_scope), backwards_incompatible: None }, + expr_id, + ) } /// Compile `expr`, yielding an rvalue. pub(crate) fn as_rvalue( &mut self, mut block: BasicBlock, - scope: Option<region::Scope>, + scope: TempLifetime, expr_id: ExprId, ) -> BlockAnd<Rvalue<'tcx>> { let this = self; @@ -171,7 +175,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, kind: StatementKind::StorageLive(result), }); - if let Some(scope) = scope { + if let Some(scope) = scope.temp_lifetime { // schedule a shallow free of that memory, lest we unwind: this.schedule_drop_storage_and_value(expr_span, scope, result); } @@ -197,7 +201,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { { let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx); let temp = unpack!(block = this.as_temp(block, scope, source, Mutability::Not)); - let layout = this.tcx.layout_of(this.param_env.and(source_expr.ty)); + let layout = + this.tcx.layout_of(this.typing_env().as_query_input(source_expr.ty)); let discr = this.temp(discr_ty, source_expr.span); this.cfg.push_assign( block, @@ -226,10 +231,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if range.start <= range.end { BinOp::BitAnd } else { BinOp::BitOr }; let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> { + // We can use `ty::TypingEnv::fully_monomorphized()`` here + // as we only need it to compute the layout of a primitive. let range_val = Const::from_bits( this.tcx, range, - ty::ParamEnv::empty().and(unsigned_ty), + ty::TypingEnv::fully_monomorphized(), + unsigned_ty, ); let lit_op = this.literal_operand(expr.span, range_val); let is_bin_op = this.temp(bool_ty, expr_span); @@ -441,7 +449,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = this.limit_capture_mutability( upvar_expr.span, upvar_expr.ty, - scope, + scope.temp_lifetime, block, arg, ) @@ -701,7 +709,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut block: BasicBlock, value: ExprId, - scope: Option<region::Scope>, + scope: TempLifetime, outer_source_info: SourceInfo, ) -> BlockAnd<Rvalue<'tcx>> { let this = self; @@ -812,9 +820,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Helper to get a `-1` value of the appropriate type fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { - let param_ty = ty::ParamEnv::empty().and(ty); - let size = self.tcx.layout_of(param_ty).unwrap().size; - let literal = Const::from_bits(self.tcx, size.unsigned_int_max(), param_ty); + let typing_env = ty::TypingEnv::fully_monomorphized(); + let size = self.tcx.layout_of(typing_env.as_query_input(ty)).unwrap().size; + let literal = Const::from_bits(self.tcx, size.unsigned_int_max(), typing_env, ty); self.literal_operand(span, literal) } @@ -822,10 +830,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Helper to get the minimum value of the appropriate type fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { assert!(ty.is_signed()); - let param_ty = ty::ParamEnv::empty().and(ty); - let bits = self.tcx.layout_of(param_ty).unwrap().size.bits(); + let typing_env = ty::TypingEnv::fully_monomorphized(); + let bits = self.tcx.layout_of(typing_env.as_query_input(ty)).unwrap().size.bits(); let n = 1 << (bits - 1); - let literal = Const::from_bits(self.tcx, n, param_ty); + let literal = Const::from_bits(self.tcx, n, typing_env, ty); self.literal_operand(span, literal) } diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index b8b5e4634ed..466f67b1ba4 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -2,7 +2,6 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::HirId; -use rustc_middle::middle::region; use rustc_middle::middle::region::{Scope, ScopeData}; use rustc_middle::mir::*; use rustc_middle::thir::*; @@ -17,7 +16,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn as_temp( &mut self, block: BasicBlock, - temp_lifetime: Option<region::Scope>, + temp_lifetime: TempLifetime, expr_id: ExprId, mutability: Mutability, ) -> BlockAnd<Local> { @@ -31,7 +30,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn as_temp_inner( &mut self, mut block: BasicBlock, - temp_lifetime: Option<region::Scope>, + temp_lifetime: TempLifetime, expr_id: ExprId, mutability: Mutability, ) -> BlockAnd<Local> { @@ -47,8 +46,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let expr_ty = expr.ty; - let deduplicate_temps = - this.fixed_temps_scope.is_some() && this.fixed_temps_scope == temp_lifetime; + let deduplicate_temps = this.fixed_temps_scope.is_some() + && this.fixed_temps_scope == temp_lifetime.temp_lifetime; let temp = if deduplicate_temps && let Some(temp_index) = this.fixed_temps.get(&expr_id) { *temp_index } else { @@ -76,7 +75,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { LocalInfo::BlockTailTemp(tail_info) } - _ if let Some(Scope { data: ScopeData::IfThenRescope, id }) = temp_lifetime => { + _ if let Some(Scope { data: ScopeData::IfThenRescope, id }) = + temp_lifetime.temp_lifetime => + { LocalInfo::IfThenRescopeTemp { if_then: HirId { owner: this.hir_id.owner, local_id: id }, } @@ -117,7 +118,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Anything with a shorter lifetime (e.g the `&foo()` in // `bar(&foo())` or anything within a block will keep the // regular drops just like runtime code. - if let Some(temp_lifetime) = temp_lifetime { + if let Some(temp_lifetime) = temp_lifetime.temp_lifetime { this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Storage); } } @@ -125,10 +126,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = this.expr_into_dest(temp_place, block, expr_id).into_block(); - if let Some(temp_lifetime) = temp_lifetime { + if let Some(temp_lifetime) = temp_lifetime.temp_lifetime { this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value); } + if let Some(backwards_incompatible) = temp_lifetime.backwards_incompatible { + this.schedule_backwards_incompatible_drop(expr_span, backwards_incompatible, temp); + } + block.and(temp) } } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index dc317feb20c..bebb44faba6 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -139,7 +139,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // (#66975) Source could be a const of type `!`, so has to // exist in the generated MIR. unpack!( - block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut) + block = + this.as_temp(block, this.local_temp_lifetime(), source, Mutability::Mut) ); // This is an optimization. If the expression was a call then we already have an @@ -266,7 +267,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // that makes the call. target: expr .ty - .is_inhabited_from(this.tcx, this.parent_module, this.param_env) + .is_inhabited_from( + this.tcx, + this.parent_module, + this.infcx.typing_env(this.param_env), + ) .then_some(success), call_source: if from_hir_call { CallSource::Normal @@ -317,7 +322,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let is_union = adt_def.is_union(); let active_field_index = is_union.then(|| fields[0].name); - let scope = this.local_scope(); + let scope = this.local_temp_lifetime(); // first process the set of fields that were provided // (evaluating them in order given by user) @@ -329,7 +334,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unpack!( block = this.as_operand( block, - Some(scope), + scope, f.expr, LocalInfo::AggregateTemp, NeedsTemporary::Maybe, @@ -544,15 +549,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Yield { value } => { - let scope = this.local_scope(); + let scope = this.local_temp_lifetime(); let value = unpack!( - block = this.as_operand( - block, - Some(scope), - value, - LocalInfo::Boring, - NeedsTemporary::No - ) + block = + this.as_operand(block, scope, value, LocalInfo::Boring, NeedsTemporary::No) ); let resume = this.cfg.start_new_block(); this.cfg.terminate(block, source_info, TerminatorKind::Yield { diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index 76034c03b4b..15ee6dd014c 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -42,7 +42,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Generate better code for things that don't need to be // dropped. - if lhs_expr.ty.needs_drop(this.tcx, this.param_env) { + if lhs_expr.ty.needs_drop(this.tcx, this.typing_env()) { let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); let lhs = unpack!(block = this.as_place(block, lhs)); block = @@ -172,8 +172,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None }; - let temp = - unpack!(block = this.as_temp(block, statement_scope, expr_id, Mutability::Not)); + let temp = unpack!( + block = this.as_temp( + block, + TempLifetime { + temp_lifetime: statement_scope, + backwards_incompatible: None + }, + expr_id, + Mutability::Not + ) + ); if let Some(span) = adjusted_span { this.local_decls[temp].source_info.span = span; diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs index 6df50057ee8..2815b390375 100644 --- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs @@ -162,7 +162,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { TestCase::Irrefutable { ascription: None, binding } } - PatKind::InlineConstant { subpattern: ref pattern, def, .. } => { + PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => { + subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx)); + default_irrefutable() + } + PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => { // Apply a type ascription for the inline constant to the value at `match_pair.place` let ascription = place.map(|source| { let span = pattern.span; @@ -173,7 +177,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { }) .args; let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( - def.to_def_id(), + def_id, ty::UserArgs { args, user_self_ty: None }, )); let annotation = ty::CanonicalUserTypeAnnotation { @@ -214,7 +218,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { || !v .inhabited_predicate(cx.tcx, adt_def) .instantiate(cx.tcx, args) - .apply_ignore_module(cx.tcx, cx.param_env) + .apply_ignore_module(cx.tcx, cx.infcx.typing_env(cx.param_env)) }) && (adt_def.did().is_local() || !adt_def.is_variant_list_non_exhaustive()); if irrefutable { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index a62d4e9d873..5791460a6b1 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -202,8 +202,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Increment the decision depth, in case we encounter boolean expressions // further down. this.mcdc_increment_depth_if_enabled(); - let place = - unpack!(block = this.as_temp(block, Some(temp_scope), expr_id, mutability)); + let place = unpack!( + block = this.as_temp( + block, + TempLifetime { + temp_lifetime: Some(temp_scope), + backwards_incompatible: None + }, + expr_id, + mutability + ) + ); this.mcdc_decrement_depth_if_enabled(); let operand = Operand::Move(Place::from(place)); @@ -917,7 +926,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.visit_primary_bindings(subpattern, subpattern_user_ty, f) } - PatKind::InlineConstant { ref subpattern, .. } => { + PatKind::ExpandedConstant { ref subpattern, .. } => { self.visit_primary_bindings(subpattern, pattern_user_ty, f) } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 37cedd8cf5c..4f7bbc4ce3e 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -567,7 +567,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // not to add such values here. let is_covering_range = |test_case: &TestCase<'_, 'tcx>| { test_case.as_range().is_some_and(|range| { - matches!(range.contains(value, self.tcx, self.param_env), None | Some(true)) + matches!( + range.contains(value, self.tcx, self.typing_env()), + None | Some(true) + ) }) }; let is_conflicting_candidate = |candidate: &&mut Candidate<'_, 'tcx>| { @@ -584,7 +587,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None } else { fully_matched = true; - let bits = value.eval_bits(self.tcx, self.param_env); + let bits = value.eval_bits(self.tcx, self.typing_env()); Some(TestBranch::Constant(value, bits)) } } @@ -596,7 +599,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fully_matched = false; let not_contained = sorted_candidates.keys().filter_map(|br| br.as_constant()).copied().all( - |val| matches!(range.contains(val, self.tcx, self.param_env), Some(false)), + |val| { + matches!(range.contains(val, self.tcx, self.typing_env()), Some(false)) + }, ); not_contained.then(|| { @@ -608,7 +613,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (TestKind::If, TestCase::Constant { value }) => { fully_matched = true; - let value = value.try_eval_bool(self.tcx, self.param_env).unwrap_or_else(|| { + let value = value.try_eval_bool(self.tcx, self.typing_env()).unwrap_or_else(|| { span_bug!(test.span, "expected boolean value but got {value:?}") }); Some(if value { TestBranch::Success } else { TestBranch::Failure }) @@ -688,7 +693,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fully_matched = false; // If the testing range does not overlap with pattern range, // the pattern can be matched only if this test fails. - if !test.overlaps(pat, self.tcx, self.param_env)? { + if !test.overlaps(pat, self.tcx, self.typing_env())? { Some(TestBranch::Failure) } else { None @@ -697,7 +702,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } (TestKind::Range(range), &TestCase::Constant { value }) => { fully_matched = false; - if !range.contains(value, self.tcx, self.param_env)? { + if !range.contains(value, self.tcx, self.typing_env())? { // `value` is not contained in the testing range, // so `value` can be matched only if this test fails. Some(TestBranch::Failure) diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs index 53cb99d44e8..a14dcad6573 100644 --- a/compiler/rustc_mir_build/src/build/misc.rs +++ b/compiler/rustc_mir_build/src/build/misc.rs @@ -32,7 +32,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Returns a zero literal operand for the appropriate type, works for /// bool, char and integers. pub(crate) fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { - let literal = Const::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty)); + let literal = Const::from_bits(self.tcx, 0, ty::TypingEnv::fully_monomorphized(), ty); self.literal_operand(span, literal) } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 46be2aee637..3317f3b7f8a 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -148,6 +148,10 @@ struct BlockContext(Vec<BlockFrame>); struct Builder<'a, 'tcx> { tcx: TyCtxt<'tcx>, + // FIXME(@lcnr): Why does this use an `infcx`, there should be + // no shared type inference going on here. I feel like it would + // clearer to manually construct one where necessary or to provide + // a nice API for non-type inference trait system checks. infcx: InferCtxt<'tcx>, region_scope_tree: &'tcx region::ScopeTree, param_env: ty::ParamEnv<'tcx>, @@ -230,6 +234,10 @@ struct Capture<'tcx> { } impl<'a, 'tcx> Builder<'a, 'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + self.infcx.typing_env(self.param_env) + } + fn is_bound_var_in_guard(&self, id: LocalVarId) -> bool { self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id)) } diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index a7e56b8f589..636e47b7ad2 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -89,7 +89,7 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::thir::{ExprId, LintLevel}; -use rustc_middle::{bug, span_bug}; +use rustc_middle::{bug, span_bug, ty}; use rustc_session::lint::Level; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span}; @@ -151,6 +151,9 @@ struct DropData { /// Whether this is a value Drop or a StorageDead. kind: DropKind, + + /// Whether this is a backwards-incompatible drop lint + backwards_incompatible_lint: bool, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -274,8 +277,12 @@ impl DropTree { // represents the block in the tree that should be jumped to once all // of the required drops have been performed. let fake_source_info = SourceInfo::outermost(DUMMY_SP); - let fake_data = - DropData { source_info: fake_source_info, local: Local::MAX, kind: DropKind::Storage }; + let fake_data = DropData { + source_info: fake_source_info, + local: Local::MAX, + kind: DropKind::Storage, + backwards_incompatible_lint: false, + }; let drops = IndexVec::from_raw(vec![DropNode { data: fake_data, next: DropIdx::MAX }]); Self { drops, entry_points: Vec::new(), existing_drops_map: FxHashMap::default() } } @@ -763,7 +770,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let local = place.as_local().unwrap_or_else(|| bug!("projection in tail call args")); - Some(DropData { source_info, local, kind: DropKind::Value }) + Some(DropData { + source_info, + local, + kind: DropKind::Value, + backwards_incompatible_lint: false, + }) } Operand::Constant(_) => None, }) @@ -1010,7 +1022,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) { let needs_drop = match drop_kind { DropKind::Value => { - if !self.local_decls[local].ty.needs_drop(self.tcx, self.param_env) { + if !self.local_decls[local].ty.needs_drop(self.tcx, self.typing_env()) { return; } true @@ -1019,9 +1031,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if local.index() <= self.arg_count { span_bug!( span, - "`schedule_drop` called with local {:?} and arg_count {}", + "`schedule_drop` called with body argument {:?} \ + but its storage does not require a drop", local, - self.arg_count, ) } false @@ -1089,6 +1101,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info: SourceInfo { span: scope_end, scope: scope.source_scope }, local, kind: drop_kind, + backwards_incompatible_lint: false, }); return; @@ -1098,6 +1111,45 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local); } + /// Schedule emission of a backwards incompatible drop lint hint. + /// Applicable only to temporary values for now. + pub(crate) fn schedule_backwards_incompatible_drop( + &mut self, + span: Span, + region_scope: region::Scope, + local: Local, + ) { + if !self.local_decls[local].ty.has_significant_drop(self.tcx, ty::TypingEnv { + typing_mode: ty::TypingMode::non_body_analysis(), + param_env: self.param_env, + }) { + return; + } + for scope in self.scopes.scopes.iter_mut().rev() { + // Since we are inserting linting MIR statement, we have to invalidate the caches + scope.invalidate_cache(); + if scope.region_scope == region_scope { + let region_scope_span = region_scope.span(self.tcx, self.region_scope_tree); + let scope_end = self.tcx.sess.source_map().end_point(region_scope_span); + + scope.drops.push(DropData { + source_info: SourceInfo { span: scope_end, scope: scope.source_scope }, + local, + kind: DropKind::Value, + backwards_incompatible_lint: true, + }); + + return; + } + } + span_bug!( + span, + "region scope {:?} not in scope to drop {:?} for linting", + region_scope, + local + ); + } + /// Indicates that the "local operand" stored in `local` is /// *moved* at some point during execution (see `local_scope` for /// more information about what a "local operand" is -- in short, @@ -1378,16 +1430,25 @@ fn build_scope_drops<'tcx>( continue; } - unwind_drops.add_entry_point(block, unwind_to); - - let next = cfg.start_new_block(); - cfg.terminate(block, source_info, TerminatorKind::Drop { - place: local.into(), - target: next, - unwind: UnwindAction::Continue, - replace: false, - }); - block = next; + if drop_data.backwards_incompatible_lint { + cfg.push(block, Statement { + source_info, + kind: StatementKind::BackwardIncompatibleDropHint { + place: Box::new(local.into()), + reason: BackwardIncompatibleDropReason::Edition2024, + }, + }); + } else { + unwind_drops.add_entry_point(block, unwind_to); + let next = cfg.start_new_block(); + cfg.terminate(block, source_info, TerminatorKind::Drop { + place: local.into(), + target: next, + unwind: UnwindAction::Continue, + replace: false, + }); + block = next; + } } DropKind::Storage => { if storage_dead_on_unwind { diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 33e194fa246..b497e54d480 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -11,7 +11,7 @@ use rustc_middle::span_bug; use rustc_middle::thir::visit::Visitor; use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::Level; use rustc_session::lint::builtin::{DEPRECATED_SAFE_2024, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_span::def_id::{DefId, LocalDefId}; @@ -37,7 +37,7 @@ struct UnsafetyVisitor<'a, 'tcx> { /// of the LHS and the span of the assignment expression. assignment_info: Option<Ty<'tcx>>, in_union_destructure: bool, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, inside_adt: bool, warnings: &'a mut Vec<UnusedUnsafeWarning>, @@ -213,7 +213,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { body_target_features: self.body_target_features, assignment_info: self.assignment_info, in_union_destructure: false, - param_env: self.param_env, + typing_env: self.typing_env, inside_adt: false, warnings: self.warnings, suggest_unsafe_block: self.suggest_unsafe_block, @@ -332,7 +332,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { PatKind::Wild | // these just wrap other patterns, which we recurse on below. PatKind::Or { .. } | - PatKind::InlineConstant { .. } | + PatKind::ExpandedConstant { .. } | PatKind::AscribeUserType { .. } | PatKind::Error(_) => {} } @@ -370,7 +370,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { }; match rm { Mutability::Not => { - if !ty.is_freeze(self.tcx, self.param_env) { + if !ty.is_freeze(self.tcx, self.typing_env) { self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField); } } @@ -386,8 +386,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_pat(self, pat); self.inside_adt = old_inside_adt; } - PatKind::InlineConstant { def, .. } => { - self.visit_inner_body(*def); + PatKind::ExpandedConstant { def_id, is_inline, .. } => { + if let Some(def) = def_id.as_local() + && *is_inline + { + self.visit_inner_body(def); + } visit::walk_pat(self, pat); } _ => { @@ -533,8 +537,45 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { self.requires_unsafe(expr.span, DerefOfRawPointer); } } - ExprKind::InlineAsm { .. } => { + ExprKind::InlineAsm(box InlineAsmExpr { + asm_macro: _, + ref operands, + template: _, + options: _, + line_spans: _, + }) => { self.requires_unsafe(expr.span, UseOfInlineAssembly); + + // For inline asm, do not use `walk_expr`, since we want to handle the label block + // specially. + for op in &**operands { + use rustc_middle::thir::InlineAsmOperand::*; + match op { + In { expr, reg: _ } + | Out { expr: Some(expr), reg: _, late: _ } + | InOut { expr, reg: _, late: _ } => self.visit_expr(&self.thir()[*expr]), + SplitInOut { in_expr, out_expr, reg: _, late: _ } => { + self.visit_expr(&self.thir()[*in_expr]); + if let Some(out_expr) = out_expr { + self.visit_expr(&self.thir()[*out_expr]); + } + } + Out { expr: None, reg: _, late: _ } + | Const { value: _, span: _ } + | SymFn { value: _, span: _ } + | SymStatic { def_id: _ } => {} + Label { block } => { + // Label blocks are safe context. + // `asm!()` is forced to be wrapped inside unsafe. If there's no special + // treatment, the label blocks would also always be unsafe with no way + // of opting out. + self.in_safety_context(SafetyContext::Safe, |this| { + visit::walk_block(this, &this.thir()[*block]) + }); + } + } + } + return; } ExprKind::Adt(box AdtExpr { adt_def, @@ -566,7 +607,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { && adt_def.is_union() { if let Some(assigned_ty) = self.assignment_info { - if assigned_ty.needs_drop(self.tcx, self.param_env) { + if assigned_ty.needs_drop(self.tcx, self.typing_env) { // This would be unsafe, but should be outright impossible since we // reject such unions. assert!( @@ -606,7 +647,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { if visitor.found { match borrow_kind { BorrowKind::Fake(_) | BorrowKind::Shared - if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) => + if !self.thir[arg].ty.is_freeze(self.tcx, self.typing_env) => { self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField) } @@ -1024,7 +1065,8 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { body_target_features, assignment_info: None, in_union_destructure: false, - param_env: tcx.param_env(def), + // FIXME(#132279): we're clearly in a body here. + typing_env: ty::TypingEnv::non_body_analysis(tcx, def), inside_adt: false, warnings: &mut warnings, suggest_unsafe_block: true, diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 00f65e0c7d0..676f7c98b8f 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -528,7 +528,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo } if let ty::Ref(_, sub_ty, _) = self.ty.kind() { - if !sub_ty.is_inhabited_from(self.cx.tcx, self.cx.module, self.cx.param_env) { + if !sub_ty.is_inhabited_from(self.cx.tcx, self.cx.module, self.cx.typing_env()) { diag.note(fluent::mir_build_reference_note); } } @@ -860,8 +860,10 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { pub(crate) uncovered: Uncovered, #[subdiagnostic] pub(crate) inform: Option<Inform>, + #[label(mir_build_confused)] + pub(crate) interpreted_as_const: Option<Span>, #[subdiagnostic] - pub(crate) interpreted_as_const: Option<InterpretedAsConst>, + pub(crate) interpreted_as_const_sugg: Option<InterpretedAsConst>, #[subdiagnostic] pub(crate) adt_defined_here: Option<AdtDefinedHere<'tcx>>, #[note(mir_build_privately_uninhabited)] @@ -911,9 +913,9 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { #[suggestion( mir_build_interpreted_as_const, code = "{variable}_var", - applicability = "maybe-incorrect" + applicability = "maybe-incorrect", + style = "verbose" )] -#[label(mir_build_confused)] pub(crate) struct InterpretedAsConst { #[primary_span] pub(crate) span: Span, diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index cb9a4e2604e..5cf33868ade 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -132,15 +132,15 @@ impl<'tcx> TerminatorClassifier<'tcx> for CallRecursion<'tcx> { return false; } let caller = body.source.def_id(); - let param_env = tcx.param_env(caller); + let typing_env = body.typing_env(tcx); let func_ty = func.ty(body, tcx); if let ty::FnDef(callee, args) = *func_ty.kind() { - let Ok(normalized_args) = tcx.try_normalize_erasing_regions(param_env, args) else { + let Ok(normalized_args) = tcx.try_normalize_erasing_regions(typing_env, args) else { return false; }; let (callee, call_args) = if let Ok(Some(instance)) = - Instance::try_resolve(tcx, param_env, callee, normalized_args) + Instance::try_resolve(tcx, typing_env, callee, normalized_args) { (instance.def_id(), instance.args) } else { diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index b8877a64e47..3fa0e4def82 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -2,7 +2,7 @@ use rustc_ast as ast; use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; -use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt}; +use rustc_middle::ty::{self, ScalarInt, TyCtxt}; use tracing::trace; use crate::build::parse_float_into_scalar; @@ -14,8 +14,7 @@ pub(crate) fn lit_to_const<'tcx>( let LitToConstInput { lit, ty, neg } = lit_input; let trunc = |n| { - let param_ty = ParamEnv::reveal_all().and(ty); - let width = match tcx.layout_of(param_ty) { + let width = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) { Ok(layout) => layout.size, Err(_) => { tcx.dcx().bug(format!("couldn't compute width of literal: {:?}", lit_input.lit)) diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 64457031997..47b7f332951 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -23,7 +23,6 @@ use tracing::{debug, info, instrument, trace}; use crate::errors; use crate::thir::cx::Cx; -use crate::thir::cx::region::Scope; use crate::thir::util::UserAnnotatedTyHelpers; impl<'tcx> Cx<'tcx> { @@ -240,7 +239,7 @@ impl<'tcx> Cx<'tcx> { fn mirror_expr_cast( &mut self, source: &'tcx hir::Expr<'tcx>, - temp_lifetime: Option<Scope>, + temp_lifetime: TempLifetime, span: Span, ) -> ExprKind<'tcx> { let tcx = self.tcx; @@ -284,10 +283,9 @@ impl<'tcx> Cx<'tcx> { let ty = adt_def.repr().discr_type(); let discr_ty = ty.to_ty(tcx); - let param_env_ty = self.param_env.and(discr_ty); let size = tcx - .layout_of(param_env_ty) - .unwrap_or_else(|e| panic!("could not compute layout for {param_env_ty:?}: {e:?}")) + .layout_of(self.typing_env().as_query_input(discr_ty)) + .unwrap_or_else(|e| panic!("could not compute layout for {discr_ty:?}: {e:?}")) .size; let (lit, overflowing) = ScalarInt::truncate_from_uint(discr_offset as u128, size); @@ -326,7 +324,7 @@ impl<'tcx> Cx<'tcx> { fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { let tcx = self.tcx; let expr_ty = self.typeck_results().expr_ty(expr); - let temp_lifetime = + let (temp_lifetime, backwards_incompatible) = self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id); let kind = match expr.kind { @@ -362,7 +360,7 @@ impl<'tcx> Cx<'tcx> { let arg_tys = args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e)); let tupled_args = Expr { ty: Ty::new_tup_from_iter(tcx, arg_tys), - temp_lifetime, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, span: expr.span, kind: ExprKind::Tuple { fields: self.mirror_exprs(args) }, }; @@ -392,7 +390,10 @@ impl<'tcx> Cx<'tcx> { && let [value] = args { return Expr { - temp_lifetime, + temp_lifetime: TempLifetime { + temp_lifetime, + backwards_incompatible, + }, ty: expr_ty, span: expr.span, kind: ExprKind::Box { value: self.mirror_expr(value) }, @@ -812,13 +813,13 @@ impl<'tcx> Cx<'tcx> { }, hir::ExprKind::Loop(body, ..) => { let block_ty = self.typeck_results().node_type(body.hir_id); - let temp_lifetime = self + let (temp_lifetime, backwards_incompatible) = self .rvalue_scopes .temporary_scope(self.region_scope_tree, body.hir_id.local_id); let block = self.mirror_block(body); let body = self.thir.exprs.push(Expr { ty: block_ty, - temp_lifetime, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, span: self.thir[block].span, kind: ExprKind::Block { block }, }); @@ -839,13 +840,17 @@ impl<'tcx> Cx<'tcx> { expr, cast_ty.hir_id, user_ty, ); - let cast = self.mirror_expr_cast(source, temp_lifetime, expr.span); + let cast = self.mirror_expr_cast( + source, + TempLifetime { temp_lifetime, backwards_incompatible }, + expr.span, + ); if let Some(user_ty) = user_ty { // NOTE: Creating a new Expr and wrapping a Cast inside of it may be // inefficient, revisit this when performance becomes an issue. let cast_expr = self.thir.exprs.push(Expr { - temp_lifetime, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, ty: expr_ty, span: expr.span, kind: cast, @@ -888,7 +893,12 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::Err(_) => unreachable!("cannot lower a `hir::ExprKind::Err` to THIR"), }; - Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind } + Expr { + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + ty: expr_ty, + span: expr.span, + kind, + } } fn user_args_applied_to_res( @@ -932,7 +942,7 @@ impl<'tcx> Cx<'tcx> { span: Span, overloaded_callee: Option<Ty<'tcx>>, ) -> Expr<'tcx> { - let temp_lifetime = + let (temp_lifetime, backwards_incompatible) = self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id); let (ty, user_ty) = match overloaded_callee { Some(fn_def) => (fn_def, None), @@ -953,7 +963,12 @@ impl<'tcx> Cx<'tcx> { ) } }; - Expr { temp_lifetime, ty, span, kind: ExprKind::ZstLiteral { user_ty } } + Expr { + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + ty, + span, + kind: ExprKind::ZstLiteral { user_ty }, + } } fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId { @@ -1025,8 +1040,8 @@ impl<'tcx> Cx<'tcx> { // but distinguish between &STATIC and &THREAD_LOCAL as they have different semantics Res::Def(DefKind::Static { .. }, id) => { // this is &raw for extern static or static mut, and & for other statics - let ty = self.tcx.static_ptr_ty(id); - let temp_lifetime = self + let ty = self.tcx.static_ptr_ty(id, self.typing_env()); + let (temp_lifetime, backwards_incompatible) = self .rvalue_scopes .temporary_scope(self.region_scope_tree, expr.hir_id.local_id); let kind = if self.tcx.is_thread_local_static(id) { @@ -1036,7 +1051,12 @@ impl<'tcx> Cx<'tcx> { ExprKind::StaticRef { alloc_id, ty, def_id: id } }; ExprKind::Deref { - arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }), + arg: self.thir.exprs.push(Expr { + ty, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + span: expr.span, + kind, + }), } } @@ -1107,13 +1127,13 @@ impl<'tcx> Cx<'tcx> { // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type - let temp_lifetime = + let (temp_lifetime, backwards_incompatible) = self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id); let fun = self.method_callee(expr, span, overloaded_callee); let fun = self.thir.exprs.push(fun); let fun_ty = self.thir[fun].ty; let ref_expr = self.thir.exprs.push(Expr { - temp_lifetime, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, ty: ref_ty, span, kind: ExprKind::Call { ty: fun_ty, fun, args, from_hir_call: false, fn_span: span }, @@ -1128,7 +1148,7 @@ impl<'tcx> Cx<'tcx> { closure_expr: &'tcx hir::Expr<'tcx>, place: HirPlace<'tcx>, ) -> Expr<'tcx> { - let temp_lifetime = self + let (temp_lifetime, backwards_incompatible) = self .rvalue_scopes .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id); let var_ty = place.base_ty; @@ -1144,7 +1164,7 @@ impl<'tcx> Cx<'tcx> { }; let mut captured_place_expr = Expr { - temp_lifetime, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, ty: var_ty, span: closure_expr.span, kind: self.convert_var(var_hir_id), @@ -1169,8 +1189,12 @@ impl<'tcx> Cx<'tcx> { } }; - captured_place_expr = - Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind }; + captured_place_expr = Expr { + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + ty: proj.ty, + span: closure_expr.span, + kind, + }; } captured_place_expr @@ -1185,7 +1209,7 @@ impl<'tcx> Cx<'tcx> { let upvar_capture = captured_place.info.capture_kind; let captured_place_expr = self.convert_captured_hir_place(closure_expr, captured_place.place.clone()); - let temp_lifetime = self + let (temp_lifetime, backwards_incompatible) = self .rvalue_scopes .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id); @@ -1202,7 +1226,7 @@ impl<'tcx> Cx<'tcx> { } }; Expr { - temp_lifetime, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, ty: upvar_ty, span: closure_expr.span, kind: ExprKind::Borrow { diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 377931e3be7..d47f7154c4b 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -12,6 +12,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::bug; use rustc_middle::middle::region; use rustc_middle::thir::*; +use rustc_middle::ty::solve::Reveal; use rustc_middle::ty::{self, RvalueScopes, TyCtxt}; use tracing::instrument; @@ -109,9 +110,20 @@ impl<'tcx> Cx<'tcx> { } } + fn typing_mode(&self) -> ty::TypingMode<'tcx> { + debug_assert_eq!(self.param_env.reveal(), Reveal::UserFacing); + // FIXME(#132279): In case we're in a body, we should use a typing + // mode which reveals the opaque types defined by that body. + ty::TypingMode::non_body_analysis() + } + + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + ty::TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env } + } + #[instrument(level = "debug", skip(self))] fn pattern_from_hir(&mut self, p: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> { - pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p) + pat_from_hir(self.tcx, self.typing_env(), self.typeck_results(), p) } fn closure_env_param(&self, owner_def: LocalDefId, expr_id: HirId) -> Option<Param<'tcx>> { diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index f222a869c03..27920008c80 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -7,6 +7,7 @@ use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_e use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; use rustc_hir::{self as hir, BindingMode, ByRef, HirId}; +use rustc_infer::traits::Reveal; use rustc_middle::bug; use rustc_middle::middle::limits::get_limit_size; use rustc_middle::thir::visit::Visitor; @@ -191,6 +192,15 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { } impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + // FIXME(#132279): We're in a body, should handle opaques. + debug_assert_eq!(self.param_env.reveal(), Reveal::UserFacing); + ty::TypingEnv { + typing_mode: ty::TypingMode::non_body_analysis(), + param_env: self.param_env, + } + } + #[instrument(level = "trace", skip(self, f))] fn with_let_source(&mut self, let_source: LetSource, f: impl FnOnce(&mut Self)) { let old_let_source = self.let_source; @@ -668,8 +678,25 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let mut let_suggestion = None; let mut misc_suggestion = None; let mut interpreted_as_const = None; + let mut interpreted_as_const_sugg = None; - if let PatKind::Constant { .. } + if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } + | PatKind::AscribeUserType { + subpattern: + box Pat { kind: PatKind::ExpandedConstant { def_id, is_inline: false, .. }, .. }, + .. + } = pat.kind + && let DefKind::Const = self.tcx.def_kind(def_id) + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) + // We filter out paths with multiple path::segments. + && snippet.chars().all(|c| c.is_alphanumeric() || c == '_') + { + let span = self.tcx.def_span(def_id); + let variable = self.tcx.item_name(def_id).to_string(); + // When we encounter a constant as the binding name, point at the `const` definition. + interpreted_as_const = Some(span); + interpreted_as_const_sugg = Some(InterpretedAsConst { span: pat.span, variable }); + } else if let PatKind::Constant { .. } | PatKind::AscribeUserType { subpattern: box Pat { kind: PatKind::Constant { .. }, .. }, .. @@ -682,9 +709,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { misc_suggestion = Some(MiscPatternSuggestion::AttemptedIntegerLiteral { start_span: pat.span.shrink_to_lo(), }); - } else if snippet.chars().all(|c| c.is_alphanumeric() || c == '_') { - interpreted_as_const = - Some(InterpretedAsConst { span: pat.span, variable: snippet }); } } @@ -721,8 +745,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { .variant(*variant_index) .inhabited_predicate(self.tcx, *adt) .instantiate(self.tcx, args); - variant_inhabited.apply(self.tcx, cx.param_env, cx.module) - && !variant_inhabited.apply_ignore_module(self.tcx, cx.param_env) + variant_inhabited.apply(self.tcx, cx.typing_env(), cx.module) + && !variant_inhabited.apply_ignore_module(self.tcx, cx.typing_env()) } else { false }; @@ -733,6 +757,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { uncovered: Uncovered::new(pat.span, &cx, witnesses), inform, interpreted_as_const, + interpreted_as_const_sugg, witness_1_is_privately_uninhabited, _p: (), pattern_ty, @@ -760,7 +785,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat: return; }; - let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); + let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()); let sess = cx.tcx.sess; @@ -1102,13 +1127,13 @@ fn report_non_exhaustive_match<'p, 'tcx>( if ty.is_ptr_sized_integral() { if ty.inner() == cx.tcx.types.usize { err.note(format!( - "`{ty}` does not have a fixed maximum value, so half-open ranges are necessary to match \ - exhaustively", + "`{ty}` does not have a fixed maximum value, so half-open ranges are \ + necessary to match exhaustively", )); } else if ty.inner() == cx.tcx.types.isize { err.note(format!( - "`{ty}` does not have fixed minimum and maximum values, so half-open ranges are necessary to match \ - exhaustively", + "`{ty}` does not have fixed minimum and maximum values, so half-open \ + ranges are necessary to match exhaustively", )); } } else if ty.inner() == cx.tcx.types.str_ { @@ -1124,11 +1149,36 @@ fn report_non_exhaustive_match<'p, 'tcx>( } if let ty::Ref(_, sub_ty, _) = scrut_ty.kind() { - if !sub_ty.is_inhabited_from(cx.tcx, cx.module, cx.param_env) { + if !sub_ty.is_inhabited_from(cx.tcx, cx.module, cx.typing_env()) { err.note("references are always considered inhabited"); } } + for &arm in arms { + let arm = &thir.arms[arm]; + if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind + && let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(arm.pattern.span) + // We filter out paths with multiple path::segments. + && snippet.chars().all(|c| c.is_alphanumeric() || c == '_') + { + let const_name = cx.tcx.item_name(def_id); + err.span_label( + arm.pattern.span, + format!( + "this pattern doesn't introduce a new catch-all binding, but rather pattern \ + matches against the value of constant `{const_name}`", + ), + ); + err.span_note(cx.tcx.def_span(def_id), format!("constant `{const_name}` defined here")); + err.span_suggestion_verbose( + arm.pattern.span.shrink_to_hi(), + "if you meant to introduce a binding, use a different name", + "_var".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + // Whether we suggest the actual missing patterns or `_`. let suggest_the_witnesses = witnesses.len() < 4; let suggested_arm = if suggest_the_witnesses { diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 82632350af5..a40134e44e7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -2,11 +2,11 @@ use rustc_abi::{FieldIdx, VariantIdx}; use rustc_apfloat::Float; use rustc_hir as hir; use rustc_index::Idx; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir::{FieldPat, Pat, PatKind}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, ValTree}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree}; use rustc_middle::{mir, span_bug}; use rustc_span::Span; use rustc_trait_selection::traits::ObligationCause; @@ -35,10 +35,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { id: hir::HirId, span: Span, ) -> Box<Pat<'tcx>> { - // FIXME(#132279): We likely want to be able to reveal the hidden types - // of opaques defined in this function here. - let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis()); - let mut convert = ConstToPat::new(self, id, span, infcx); + let mut convert = ConstToPat::new(self, id, span); match c.kind() { ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty), @@ -49,27 +46,20 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } struct ConstToPat<'tcx> { + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, span: Span, - param_env: ty::ParamEnv<'tcx>, - - // inference context used for checking `T: Structural` bounds. - infcx: InferCtxt<'tcx>, treat_byte_string_as_slice: bool, } impl<'tcx> ConstToPat<'tcx> { - fn new( - pat_ctxt: &PatCtxt<'_, 'tcx>, - id: hir::HirId, - span: Span, - infcx: InferCtxt<'tcx>, - ) -> Self { + fn new(pat_ctxt: &PatCtxt<'_, 'tcx>, id: hir::HirId, span: Span) -> Self { trace!(?pat_ctxt.typeck_results.hir_owner); ConstToPat { + tcx: pat_ctxt.tcx, + typing_env: pat_ctxt.typing_env, span, - infcx, - param_env: pat_ctxt.param_env, treat_byte_string_as_slice: pat_ctxt .typeck_results .treat_byte_string_as_slice @@ -77,12 +67,8 @@ impl<'tcx> ConstToPat<'tcx> { } } - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { - ty.is_structural_eq_shallow(self.infcx.tcx) + ty.is_structural_eq_shallow(self.tcx) } fn unevaluated_to_pat( @@ -100,22 +86,22 @@ impl<'tcx> ConstToPat<'tcx> { // // FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All` // instead of having this logic here - let param_env = - self.tcx().erase_regions(self.param_env).with_reveal_all_normalized(self.tcx()); - let uv = self.tcx().erase_regions(uv); + let typing_env = + self.tcx.erase_regions(self.typing_env).with_reveal_all_normalized(self.tcx); + let uv = self.tcx.erase_regions(uv); // try to resolve e.g. associated constants to their definition on an impl, and then // evaluate the const. - let valtree = match self.infcx.tcx.const_eval_resolve_for_typeck(param_env, uv, self.span) { + let valtree = match self.tcx.const_eval_resolve_for_typeck(typing_env, uv, self.span) { Ok(Ok(c)) => c, Err(ErrorHandled::Reported(_, _)) => { // Let's tell the use where this failing const occurs. - let e = self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span }); + let e = self.tcx.dcx().emit_err(CouldNotEvalConstPattern { span: self.span }); return pat_from_kind(PatKind::Error(e)); } Err(ErrorHandled::TooGeneric(_)) => { let e = self - .tcx() + .tcx .dcx() .emit_err(ConstPatternDependsOnGenericParameter { span: self.span }); return pat_from_kind(PatKind::Error(e)); @@ -125,13 +111,13 @@ impl<'tcx> ConstToPat<'tcx> { let e = match bad_ty.kind() { ty::Adt(def, ..) => { assert!(def.is_union()); - self.tcx().dcx().emit_err(UnionPattern { span: self.span }) + self.tcx.dcx().emit_err(UnionPattern { span: self.span }) } ty::FnPtr(..) | ty::RawPtr(..) => { - self.tcx().dcx().emit_err(PointerPattern { span: self.span }) + self.tcx.dcx().emit_err(PointerPattern { span: self.span }) } _ => self - .tcx() + .tcx .dcx() .emit_err(InvalidPattern { span: self.span, non_sm_ty: bad_ty }), }; @@ -146,7 +132,7 @@ impl<'tcx> ConstToPat<'tcx> { // Always check for `PartialEq` if we had no other errors yet. if !self.type_has_partial_eq_impl(ty) { let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty }; - let e = self.tcx().dcx().emit_err(err); + let e = self.tcx.dcx().emit_err(err); return pat_from_kind(PatKind::Error(e)); } } @@ -156,18 +142,19 @@ impl<'tcx> ConstToPat<'tcx> { #[instrument(level = "trace", skip(self), ret)] fn type_has_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool { - let tcx = self.tcx(); + let (infcx, param_env) = self.tcx.infer_ctxt().build_with_typing_env(self.typing_env); // double-check there even *is* a semantic `PartialEq` to dispatch to. // // (If there isn't, then we can safely issue a hard // error, because that's never worked, due to compiler // using `PartialEq::eq` in this scenario in the past.) - let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, Some(self.span)); + let partial_eq_trait_id = + self.tcx.require_lang_item(hir::LangItem::PartialEq, Some(self.span)); let partial_eq_obligation = Obligation::new( - tcx, + self.tcx, ObligationCause::dummy(), - self.param_env, - ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]), + param_env, + ty::TraitRef::new(self.tcx, partial_eq_trait_id, [ty, ty]), ); // This *could* accept a type that isn't actually `PartialEq`, because region bounds get @@ -176,7 +163,7 @@ impl<'tcx> ConstToPat<'tcx> { // `PartialEq` for some lifetime but *not* for `'static`? If this ever becomes a problem // we'll need to leave some sort of trace of this requirement in the MIR so that borrowck // can ensure that the type really implements `PartialEq`. - self.infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation) + infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation) } fn field_pats( @@ -187,7 +174,7 @@ impl<'tcx> ConstToPat<'tcx> { .map(|(idx, (val, ty))| { let field = FieldIdx::new(idx); // Patterns can only use monomorphic types. - let ty = self.tcx().normalize_erasing_regions(self.param_env, ty); + let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty); FieldPat { field, pattern: self.valtree_to_pat(val, ty) } }) .collect() @@ -197,14 +184,12 @@ impl<'tcx> ConstToPat<'tcx> { #[instrument(skip(self), level = "debug")] fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> { let span = self.span; - let tcx = self.tcx(); - let param_env = self.param_env; - + let tcx = self.tcx; let kind = match ty.kind() { ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => { // Extremely important check for all ADTs! Make sure they opted-in to be used in // patterns. - debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,); + debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty); let err = TypeNotStructural { span, non_sm_ty: ty }; let e = tcx.dcx().emit_err(err); // We errored. Signal that in the pattern, so that follow up errors can be silenced. @@ -222,7 +207,7 @@ impl<'tcx> ConstToPat<'tcx> { adt_def.variants()[variant_index] .fields .iter() - .map(|field| field.ty(self.tcx(), args)), + .map(|field| field.ty(self.tcx, args)), ), ), } @@ -230,14 +215,9 @@ impl<'tcx> ConstToPat<'tcx> { ty::Adt(def, args) => { assert!(!def.is_union()); // Valtree construction would never succeed for unions. PatKind::Leaf { - subpatterns: self.field_pats( - cv.unwrap_branch().iter().copied().zip( - def.non_enum_variant() - .fields - .iter() - .map(|field| field.ty(self.tcx(), args)), - ), - ), + subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip( + def.non_enum_variant().fields.iter().map(|field| field.ty(self.tcx, args)), + )), } } ty::Tuple(fields) => PatKind::Leaf { @@ -271,7 +251,7 @@ impl<'tcx> ConstToPat<'tcx> { // convert the dereferenced constant to a pattern that is the sub-pattern of the // deref pattern. _ => { - if !pointee_ty.is_sized(tcx, param_env) && !pointee_ty.is_slice() { + if !pointee_ty.is_sized(tcx, self.typing_env) && !pointee_ty.is_slice() { let err = UnsizedPattern { span, non_sm_ty: *pointee_ty }; let e = tcx.dcx().emit_err(err); // We errored. Signal that in the pattern, so that follow up errors can be silenced. diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index ec852add94d..08c6b4abd3b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -30,7 +30,7 @@ use crate::thir::util::UserAnnotatedTyHelpers; struct PatCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, /// Used by the Rust 2024 migration lint. @@ -39,13 +39,13 @@ struct PatCtxt<'a, 'tcx> { pub(super) fn pat_from_hir<'a, 'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, pat: &'tcx hir::Pat<'tcx>, ) -> Box<Pat<'tcx>> { let mut pcx = PatCtxt { tcx, - param_env, + typing_env, typeck_results, rust_2024_migration_suggestion: typeck_results .rust_2024_migration_desugared_pats() @@ -149,21 +149,30 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { None => Ok((None, None, None)), Some(expr) => { let (kind, ascr, inline_const) = match self.lower_lit(expr) { - PatKind::InlineConstant { subpattern, def } => { - (subpattern.kind, None, Some(def)) + PatKind::ExpandedConstant { subpattern, def_id, is_inline: true } => { + (subpattern.kind, None, def_id.as_local()) + } + PatKind::ExpandedConstant { subpattern, is_inline: false, .. } => { + (subpattern.kind, None, None) } PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => { (kind, Some(ascription), None) } kind => (kind, None, None), }; - let value = if let PatKind::Constant { value } = kind { - value - } else { - let msg = format!( - "found bad range pattern endpoint `{expr:?}` outside of error recovery" - ); - return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg)); + let value = match kind { + PatKind::Constant { value } => value, + PatKind::ExpandedConstant { subpattern, .. } + if let PatKind::Constant { value } = subpattern.kind => + { + value + } + _ => { + let msg = format!( + "found bad range pattern endpoint `{expr:?}` outside of error recovery" + ); + return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg)); + } }; Ok((Some(PatRangeBoundary::Finite(value)), ascr, inline_const)) } @@ -242,7 +251,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let lo = lo.unwrap_or(PatRangeBoundary::NegInfinity); let hi = hi.unwrap_or(PatRangeBoundary::PosInfinity); - let cmp = lo.compare_with(hi, ty, self.tcx, self.param_env); + let cmp = lo.compare_with(hi, ty, self.tcx, self.typing_env); let mut kind = PatKind::Range(Box::new(PatRange { lo, hi, end, ty })); match (end, cmp) { // `x..y` where `x < y`. @@ -288,7 +297,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }; } for def in [lo_inline, hi_inline].into_iter().flatten() { - kind = PatKind::InlineConstant { def, subpattern: Box::new(Pat { span, ty, kind }) }; + kind = PatKind::ExpandedConstant { + def_id: def.to_def_id(), + is_inline: true, + subpattern: Box::new(Pat { span, ty, kind }), + }; } Ok(kind) } @@ -562,7 +575,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let args = self.typeck_results.node_args(id); let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args }); - let pattern = self.const_to_pat(c, ty, id, span); + let subpattern = self.const_to_pat(c, ty, id, span); + let pattern = Box::new(Pat { + span, + ty, + kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false }, + }); if !is_associated_const { return pattern; @@ -637,7 +655,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args }; let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span); - PatKind::InlineConstant { subpattern, def: def_id } + PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true } } /// Converts literals, paths and negation of literals to patterns. diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index dae13df4054..6be0ed5fb31 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -707,9 +707,10 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::InlineConstant { def, subpattern } => { - print_indented!(self, "InlineConstant {", depth_lvl + 1); - print_indented!(self, format!("def: {:?}", def), depth_lvl + 2); + PatKind::ExpandedConstant { def_id, is_inline, subpattern } => { + print_indented!(self, "ExpandedConstant {", depth_lvl + 1); + print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2); + print_indented!(self, format!("is_inline: {is_inline:?}"), depth_lvl + 2); print_indented!(self, "subpattern:", depth_lvl + 2); self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 9a1f000d39d..494b7d54d8a 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -6,7 +6,6 @@ use rustc_index::Idx; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; use rustc_middle::span_bug; -use rustc_middle::traits::Reveal; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; use rustc_span::DUMMY_SP; @@ -111,7 +110,7 @@ pub trait DropElaborator<'a, 'tcx>: fmt::Debug { fn patch(&mut self) -> &mut MirPatch<'tcx>; fn body(&self) -> &'a Body<'tcx>; fn tcx(&self) -> TyCtxt<'tcx>; - fn param_env(&self) -> ty::ParamEnv<'tcx>; + fn typing_env(&self) -> ty::TypingEnv<'tcx>; // Drop logic @@ -273,9 +272,9 @@ where let subpath = self.elaborator.field_subpath(variant_path, field); let tcx = self.tcx(); - assert_eq!(self.elaborator.param_env().reveal(), Reveal::All); + assert_eq!(self.elaborator.typing_env().typing_mode, ty::TypingMode::PostAnalysis); let field_ty = - tcx.normalize_erasing_regions(self.elaborator.param_env(), f.ty(tcx, args)); + tcx.normalize_erasing_regions(self.elaborator.typing_env(), f.ty(tcx, args)); (tcx.mk_place_field(base_place, field, field_ty), subpath) }) @@ -372,7 +371,7 @@ where let mut fields = fields; fields.retain(|&(place, _)| { - self.place_ty(place).needs_drop(self.tcx(), self.elaborator.param_env()) + self.place_ty(place).needs_drop(self.tcx(), self.elaborator.typing_env()) }); debug!("drop_ladder - fields needing drop: {:?}", fields); @@ -544,11 +543,11 @@ where } else { have_otherwise = true; - let param_env = self.elaborator.param_env(); + let typing_env = self.elaborator.typing_env(); let have_field_with_drop_glue = variant .fields .iter() - .any(|field| field.ty(tcx, args).needs_drop(tcx, param_env)); + .any(|field| field.ty(tcx, args).needs_drop(tcx, typing_env)); if have_field_with_drop_glue { have_otherwise_with_drop_glue = true; } diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 3e01f0512c4..9a5cf9d4e84 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -4,8 +4,8 @@ use rustc_middle::mir::{ self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges, }; -use super::visitor::{ResultsVisitable, ResultsVisitor}; -use super::{Analysis, Effect, EffectIndex, SwitchIntTarget}; +use super::visitor::ResultsVisitor; +use super::{Analysis, Effect, EffectIndex, Results, SwitchIntTarget}; pub trait Direction { const IS_FORWARD: bool; @@ -33,14 +33,14 @@ pub trait Direction { where A: Analysis<'tcx>; - fn visit_results_in_block<'mir, 'tcx, D, R>( - state: &mut D, + fn visit_results_in_block<'mir, 'tcx, A>( + state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>, + results: &mut Results<'tcx, A>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, A>, ) where - R: ResultsVisitable<'tcx, Domain = D>; + A: Analysis<'tcx>; fn join_state_into_successors_of<'tcx, A>( analysis: &mut A, @@ -53,7 +53,7 @@ pub trait Direction { A: Analysis<'tcx>; } -/// Dataflow that runs from the exit of a block (the terminator), to its entry (the first statement). +/// Dataflow that runs from the exit of a block (terminator), to its entry (the first statement). pub struct Backward; impl Direction for Backward { @@ -157,32 +157,32 @@ impl Direction for Backward { analysis.apply_statement_effect(state, statement, location); } - fn visit_results_in_block<'mir, 'tcx, D, R>( - state: &mut D, + fn visit_results_in_block<'mir, 'tcx, A>( + state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>, + results: &mut Results<'tcx, A>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, A>, ) where - R: ResultsVisitable<'tcx, Domain = D>, + A: Analysis<'tcx>, { - results.reset_to_block_entry(state, block); + state.clone_from(results.entry_set_for_block(block)); vis.visit_block_end(state); // Terminator let loc = Location { block, statement_index: block_data.statements.len() }; let term = block_data.terminator(); - results.reconstruct_before_terminator_effect(state, term, loc); + results.analysis.apply_before_terminator_effect(state, term, loc); vis.visit_terminator_before_primary_effect(results, state, term, loc); - results.reconstruct_terminator_effect(state, term, loc); + results.analysis.apply_terminator_effect(state, term, loc); vis.visit_terminator_after_primary_effect(results, state, term, loc); for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() { let loc = Location { block, statement_index }; - results.reconstruct_before_statement_effect(state, stmt, loc); + results.analysis.apply_before_statement_effect(state, stmt, loc); vis.visit_statement_before_primary_effect(results, state, stmt, loc); - results.reconstruct_statement_effect(state, stmt, loc); + results.analysis.apply_statement_effect(state, stmt, loc); vis.visit_statement_after_primary_effect(results, state, stmt, loc); } @@ -389,32 +389,32 @@ impl Direction for Forward { } } - fn visit_results_in_block<'mir, 'tcx, F, R>( - state: &mut F, + fn visit_results_in_block<'mir, 'tcx, A>( + state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = F>, + results: &mut Results<'tcx, A>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, A>, ) where - R: ResultsVisitable<'tcx, Domain = F>, + A: Analysis<'tcx>, { - results.reset_to_block_entry(state, block); + state.clone_from(results.entry_set_for_block(block)); vis.visit_block_start(state); for (statement_index, stmt) in block_data.statements.iter().enumerate() { let loc = Location { block, statement_index }; - results.reconstruct_before_statement_effect(state, stmt, loc); + results.analysis.apply_before_statement_effect(state, stmt, loc); vis.visit_statement_before_primary_effect(results, state, stmt, loc); - results.reconstruct_statement_effect(state, stmt, loc); + results.analysis.apply_statement_effect(state, stmt, loc); vis.visit_statement_after_primary_effect(results, state, stmt, loc); } let loc = Location { block, statement_index: block_data.statements.len() }; let term = block_data.terminator(); - results.reconstruct_before_terminator_effect(state, term, loc); + results.analysis.apply_before_terminator_effect(state, term, loc); vis.visit_terminator_before_primary_effect(results, state, term, loc); - results.reconstruct_terminator_effect(state, term, loc); + results.analysis.apply_terminator_effect(state, term, loc); vis.visit_terminator_after_primary_effect(results, state, term, loc); vis.visit_block_end(state); diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index bac75b972f9..98a4f58cb5d 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -544,20 +544,18 @@ impl<D> StateDiffCollector<D> { } } -impl<'tcx, A> ResultsVisitor<'_, 'tcx, Results<'tcx, A>> for StateDiffCollector<A::Domain> +impl<'tcx, A> ResultsVisitor<'_, 'tcx, A> for StateDiffCollector<A::Domain> where A: Analysis<'tcx>, A::Domain: DebugWithContext<A>, { - type Domain = A::Domain; - - fn visit_block_start(&mut self, state: &Self::Domain) { + fn visit_block_start(&mut self, state: &A::Domain) { if A::Direction::IS_FORWARD { self.prev_state.clone_from(state); } } - fn visit_block_end(&mut self, state: &Self::Domain) { + fn visit_block_end(&mut self, state: &A::Domain) { if A::Direction::IS_BACKWARD { self.prev_state.clone_from(state); } @@ -566,7 +564,7 @@ where fn visit_statement_before_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::Domain, + state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { @@ -579,7 +577,7 @@ where fn visit_statement_after_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::Domain, + state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { @@ -590,7 +588,7 @@ where fn visit_terminator_before_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::Domain, + state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, ) { @@ -603,7 +601,7 @@ where fn visit_terminator_after_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::Domain, + state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 8f81da8bb04..244dfe26ad3 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -55,8 +55,8 @@ mod visitor; pub use self::cursor::ResultsCursor; pub use self::direction::{Backward, Direction, Forward}; pub use self::lattice::{JoinSemiLattice, MaybeReachable}; -pub use self::results::Results; -pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results}; +pub use self::results::{EntrySets, Results}; +pub use self::visitor::{ResultsVisitor, visit_results}; /// Analysis domains are all bitsets of various kinds. This trait holds /// operations needed by all of them. diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs index 366fcbf33ba..ff6cafbfbae 100644 --- a/compiler/rustc_mir_dataflow/src/framework/results.rs +++ b/compiler/rustc_mir_dataflow/src/framework/results.rs @@ -18,7 +18,7 @@ use crate::errors::{ DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter, }; -type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>; +pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>; /// A dataflow analysis that has converged to fixpoint. #[derive(Clone)] @@ -27,7 +27,7 @@ where A: Analysis<'tcx>, { pub analysis: A, - pub(super) entry_sets: EntrySets<'tcx, A>, + pub entry_sets: EntrySets<'tcx, A>, } impl<'tcx, A> Results<'tcx, A> @@ -51,7 +51,7 @@ where &mut self, body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator<Item = BasicBlock>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, A>, ) { visit_results(body, blocks, self, vis) } @@ -59,7 +59,7 @@ where pub fn visit_reachable_with<'mir>( &mut self, body: &'mir mir::Body<'tcx>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, A>, ) { let blocks = traversal::reachable(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index 3d6b008a684..5c7539eed4d 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -4,15 +4,15 @@ use super::{Analysis, Direction, Results}; /// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the /// dataflow state at that location. -pub fn visit_results<'mir, 'tcx, D, R>( +pub fn visit_results<'mir, 'tcx, A>( body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator<Item = BasicBlock>, - results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>, + results: &mut Results<'tcx, A>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, A>, ) where - R: ResultsVisitable<'tcx, Domain = D>, + A: Analysis<'tcx>, { - let mut state = results.bottom_value(body); + let mut state = results.analysis.bottom_value(body); #[cfg(debug_assertions)] let reachable_blocks = mir::traversal::reachable_as_bitset(body); @@ -22,23 +22,23 @@ pub fn visit_results<'mir, 'tcx, D, R>( assert!(reachable_blocks.contains(block)); let block_data = &body[block]; - R::Direction::visit_results_in_block(&mut state, block, block_data, results, vis); + A::Direction::visit_results_in_block(&mut state, block, block_data, results, vis); } } -/// A visitor over the results of an `Analysis`. The type parameter `R` is the results type being -/// visited. -pub trait ResultsVisitor<'mir, 'tcx, R> { - type Domain; - - fn visit_block_start(&mut self, _state: &Self::Domain) {} +/// A visitor over the results of an `Analysis`. +pub trait ResultsVisitor<'mir, 'tcx, A> +where + A: Analysis<'tcx>, +{ + fn visit_block_start(&mut self, _state: &A::Domain) {} /// Called with the `before_statement_effect` of the given statement applied to `state` but not /// its `statement_effect`. fn visit_statement_before_primary_effect( &mut self, - _results: &mut R, - _state: &Self::Domain, + _results: &mut Results<'tcx, A>, + _state: &A::Domain, _statement: &'mir mir::Statement<'tcx>, _location: Location, ) { @@ -48,19 +48,19 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { /// statement applied to `state`. fn visit_statement_after_primary_effect( &mut self, - _results: &mut R, - _state: &Self::Domain, + _results: &mut Results<'tcx, A>, + _state: &A::Domain, _statement: &'mir mir::Statement<'tcx>, _location: Location, ) { } - /// Called with the `before_terminator_effect` of the given terminator applied to `state` but not - /// its `terminator_effect`. + /// Called with the `before_terminator_effect` of the given terminator applied to `state` but + /// not its `terminator_effect`. fn visit_terminator_before_primary_effect( &mut self, - _results: &mut R, - _state: &Self::Domain, + _results: &mut Results<'tcx, A>, + _state: &A::Domain, _terminator: &'mir mir::Terminator<'tcx>, _location: Location, ) { @@ -72,109 +72,12 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { /// The `call_return_effect` (if one exists) will *not* be applied to `state`. fn visit_terminator_after_primary_effect( &mut self, - _results: &mut R, - _state: &Self::Domain, + _results: &mut Results<'tcx, A>, + _state: &A::Domain, _terminator: &'mir mir::Terminator<'tcx>, _location: Location, ) { } - fn visit_block_end(&mut self, _state: &Self::Domain) {} -} - -/// Things that can be visited by a `ResultsVisitor`. -/// -/// This trait exists so that we can visit the results of one or more dataflow analyses -/// simultaneously. -pub trait ResultsVisitable<'tcx> { - type Direction: Direction; - type Domain; - - /// Creates an empty `Domain` to hold the transient state for these dataflow results. - /// - /// The value of the newly created `Domain` will be overwritten by `reset_to_block_entry` - /// before it can be observed by a `ResultsVisitor`. - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain; - - fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock); - - fn reconstruct_before_statement_effect( - &mut self, - state: &mut Self::Domain, - statement: &mir::Statement<'tcx>, - location: Location, - ); - - fn reconstruct_statement_effect( - &mut self, - state: &mut Self::Domain, - statement: &mir::Statement<'tcx>, - location: Location, - ); - - fn reconstruct_before_terminator_effect( - &mut self, - state: &mut Self::Domain, - terminator: &mir::Terminator<'tcx>, - location: Location, - ); - - fn reconstruct_terminator_effect( - &mut self, - state: &mut Self::Domain, - terminator: &mir::Terminator<'tcx>, - location: Location, - ); -} - -impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A> -where - A: Analysis<'tcx>, -{ - type Domain = A::Domain; - type Direction = A::Direction; - - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { - self.analysis.bottom_value(body) - } - - fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) { - state.clone_from(self.entry_set_for_block(block)); - } - - fn reconstruct_before_statement_effect( - &mut self, - state: &mut Self::Domain, - stmt: &mir::Statement<'tcx>, - loc: Location, - ) { - self.analysis.apply_before_statement_effect(state, stmt, loc); - } - - fn reconstruct_statement_effect( - &mut self, - state: &mut Self::Domain, - stmt: &mir::Statement<'tcx>, - loc: Location, - ) { - self.analysis.apply_statement_effect(state, stmt, loc); - } - - fn reconstruct_before_terminator_effect( - &mut self, - state: &mut Self::Domain, - term: &mir::Terminator<'tcx>, - loc: Location, - ) { - self.analysis.apply_before_terminator_effect(state, term, loc); - } - - fn reconstruct_terminator_effect( - &mut self, - state: &mut Self::Domain, - term: &mir::Terminator<'tcx>, - loc: Location, - ) { - self.analysis.apply_terminator_effect(state, term, loc); - } + fn visit_block_end(&mut self, _state: &A::Domain) {} } diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index e06c1f2bb49..fd7254a0210 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -253,6 +253,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { | StatementKind::Coverage(..) | StatementKind::Intrinsic(..) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => None, }; if let Some(destination) = destination { diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index c5fd2a631ff..576289e228a 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -157,6 +157,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { | StatementKind::Nop | StatementKind::Retag(..) | StatementKind::Intrinsic(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::StorageLive(..) => {} } } diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index b404e3bfb72..ab1453f1ed0 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -18,8 +18,8 @@ pub use self::drop_flag_effects::{ move_path_children_matching, on_all_children_bits, on_lookup_result_bits, }; pub use self::framework::{ - Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results, - ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice, + Analysis, Backward, Direction, EntrySets, Forward, GenKill, JoinSemiLattice, MaybeReachable, + Results, ResultsCursor, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice, visit_results, }; use self::move_paths::MoveData; diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index fd8e403ebc2..0880364bfca 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -385,6 +385,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { | StatementKind::Coverage(..) | StatementKind::Intrinsic(..) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs index 73abb669a11..10f1e009855 100644 --- a/compiler/rustc_mir_dataflow/src/points.rs +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -3,7 +3,7 @@ use rustc_index::interval::SparseIntervalMatrix; use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::{self, BasicBlock, Body, Location}; -use crate::framework::{ResultsVisitable, ResultsVisitor, visit_results}; +use crate::framework::{Analysis, Results, ResultsVisitor, visit_results}; /// Maps between a `Location` and a `PointIndex` (and vice versa). pub struct DenseLocationMap { @@ -95,14 +95,14 @@ rustc_index::newtype_index! { } /// Add points depending on the result of the given dataflow analysis. -pub fn save_as_intervals<'tcx, N, R>( +pub fn save_as_intervals<'tcx, N, A>( elements: &DenseLocationMap, body: &mir::Body<'tcx>, - mut results: R, + mut results: Results<'tcx, A>, ) -> SparseIntervalMatrix<N, PointIndex> where N: Idx, - R: ResultsVisitable<'tcx, Domain = BitSet<N>>, + A: Analysis<'tcx, Domain = BitSet<N>>, { let values = SparseIntervalMatrix::new(elements.num_points()); let mut visitor = Visitor { elements, values }; @@ -120,16 +120,15 @@ struct Visitor<'a, N: Idx> { values: SparseIntervalMatrix<N, PointIndex>, } -impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N> +impl<'mir, 'tcx, A, N> ResultsVisitor<'mir, 'tcx, A> for Visitor<'_, N> where + A: Analysis<'tcx, Domain = BitSet<N>>, N: Idx, { - type Domain = BitSet<N>; - fn visit_statement_after_primary_effect( &mut self, - _results: &mut R, - state: &Self::Domain, + _results: &mut Results<'tcx, A>, + state: &A::Domain, _statement: &'mir mir::Statement<'tcx>, location: Location, ) { @@ -142,8 +141,8 @@ where fn visit_terminator_after_primary_effect( &mut self, - _results: &mut R, - state: &Self::Domain, + _results: &mut Results<'tcx, A>, + state: &A::Domain, _terminator: &'mir mir::Terminator<'tcx>, location: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index af2d514fc76..ed8678de1eb 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -462,7 +462,7 @@ impl<'tcx> Map<'tcx> { drop(assignments); // Create values for places whose type have scalar layout. - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let typing_env = body.typing_env(tcx); for place_info in self.places.iter_mut() { // The user requires a bound on the number of created values. if let Some(value_limit) = value_limit @@ -471,13 +471,13 @@ impl<'tcx> Map<'tcx> { break; } - if let Ok(ty) = tcx.try_normalize_erasing_regions(param_env, place_info.ty) { + if let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, place_info.ty) { place_info.ty = ty; } // Allocate a value slot if it doesn't have one, and the user requested one. assert!(place_info.value_index.is_none()); - if let Ok(layout) = tcx.layout_of(param_env.and(place_info.ty)) + if let Ok(layout) = tcx.layout_of(typing_env.as_query_input(place_info.ty)) && layout.backend_repr.is_scalar() { place_info.value_index = Some(self.value_count.into()); @@ -874,7 +874,7 @@ impl<V, T> TryFrom<ProjectionElem<V, T>> for TrackElem { pub fn iter_fields<'tcx>( ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, mut f: impl FnMut(Option<VariantIdx>, FieldIdx, Ty<'tcx>), ) { match ty.kind() { @@ -892,20 +892,20 @@ pub fn iter_fields<'tcx>( for (f_index, f_def) in v_def.fields.iter().enumerate() { let field_ty = f_def.ty(tcx, args); let field_ty = tcx - .try_normalize_erasing_regions(param_env, field_ty) + .try_normalize_erasing_regions(typing_env, field_ty) .unwrap_or_else(|_| tcx.erase_regions(field_ty)); f(variant, f_index.into(), field_ty); } } } ty::Closure(_, args) => { - iter_fields(args.as_closure().tupled_upvars_ty(), tcx, param_env, f); + iter_fields(args.as_closure().tupled_upvars_ty(), tcx, typing_env, f); } ty::Coroutine(_, args) => { - iter_fields(args.as_coroutine().tupled_upvars_ty(), tcx, param_env, f); + iter_fields(args.as_coroutine().tupled_upvars_ty(), tcx, typing_env, f); } ty::CoroutineClosure(_, args) => { - iter_fields(args.as_coroutine_closure().tupled_upvars_ty(), tcx, param_env, f); + iter_fields(args.as_coroutine_closure().tupled_upvars_ty(), tcx, typing_env, f); } _ => (), } diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index 9bbfae17fd9..d00bfc66a6a 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -25,6 +25,31 @@ mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspen .help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point mir_transform_operation_will_panic = this operation will panic at runtime +mir_transform_tail_expr_drop_order = relative drop order changing in Rust 2024 + .temporaries = in Rust 2024, this temporary value will be dropped first + .observers = in Rust 2024, this local variable or temporary value will be dropped second + .note_dtors = + dropping the temporary value runs this custom `Drop` impl, which we could not prove to be side-effect free + .note_observer_dtors = + dropping the local runs this custom `Drop` impl, which we could not prove to be side-effect free + .drop_location = + now the temporary value is dropped here, before the local variables in the block or statement + .note_epilogue = most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + .label_local_epilogue = {$is_dropped_first_edition_2024 -> + [true] up until Edition 2021 `{$name}` is dropped last but will be dropped earlier in Edition 2024 + *[false] `{$name}` will be dropped later as of Edition 2024 + } + +mir_transform_tail_expr_dtor = {$dtor_kind -> + [dyn] `{$name}` may invoke a custom destructor because it contains a trait object + *[concrete] `{$name}` invokes this custom destructor + } + +mir_transform_tail_expr_local = {$is_generated_name -> + [true] this value will be stored in a temporary; let us call it `{$name}` + *[false] `{$name}` calls a custom destructor + } + mir_transform_unaligned_packed_ref = reference to packed field is unaligned .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs index 559df222a50..12a2fe23b14 100644 --- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs +++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs @@ -1,6 +1,6 @@ use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, TyCtxt}; use tracing::debug; use crate::util; @@ -40,10 +40,10 @@ pub(super) struct AddMovesForPackedDrops; impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span); - - let def_id = body.source.def_id(); let mut patch = MirPatch::new(body); - let param_env = tcx.param_env(def_id); + // FIXME(#132279): This is used during the phase transition from analysis + // to runtime, so we have to manually specify the correct typing mode. + let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id()); for (bb, data) in body.basic_blocks.iter_enumerated() { let loc = Location { block: bb, statement_index: data.statements.len() }; @@ -51,7 +51,7 @@ impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops { match terminator.kind { TerminatorKind::Drop { place, .. } - if util::is_disaligned(tcx, body, param_env, place) => + if util::is_disaligned(tcx, body, typing_env, place) => { add_move_for_packed_drop( tcx, diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index a9600f77c0b..1b7c89fd251 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -3,7 +3,7 @@ use rustc_index::IndexVec; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::Session; use tracing::{debug, trace}; @@ -25,9 +25,9 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment { return; } + let typing_env = body.typing_env(tcx); let basic_blocks = body.basic_blocks.as_mut(); let local_decls = &mut body.local_decls; - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); // This pass inserts new blocks. Each insertion changes the Location for all // statements/blocks after. Iterating or visiting the MIR in order would require updating @@ -41,7 +41,7 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment { let source_info = statement.source_info; let mut finder = - PointerFinder { tcx, local_decls, param_env, pointers: Vec::new() }; + PointerFinder { tcx, local_decls, typing_env, pointers: Vec::new() }; finder.visit_statement(statement, location); for (local, ty) in finder.pointers { @@ -65,7 +65,7 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment { struct PointerFinder<'a, 'tcx> { tcx: TyCtxt<'tcx>, local_decls: &'a mut LocalDecls<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, pointers: Vec<(Place<'tcx>, Ty<'tcx>)>, } @@ -107,7 +107,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> { let pointee_ty = pointer_ty.builtin_deref(true).expect("no builtin_deref for an unsafe pointer"); // Ideally we'd support this in the future, but for now we are limited to sized types. - if !pointee_ty.is_sized(self.tcx, self.param_env) { + if !pointee_ty.is_sized(self.tcx, self.typing_env) { debug!("Unsafe pointer, but pointee is not known to be sized: {:?}", pointer_ty); return; } diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 1922d4fef25..e9b85ba6e9d 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -9,9 +9,9 @@ pub(super) struct CheckPackedRef; impl<'tcx> crate::MirLint<'tcx> for CheckPackedRef { fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - let param_env = tcx.param_env(body.source.def_id()); + let typing_env = body.typing_env(tcx); let source_info = SourceInfo::outermost(body.span); - let mut checker = PackedRefChecker { body, tcx, param_env, source_info }; + let mut checker = PackedRefChecker { body, tcx, typing_env, source_info }; checker.visit_body(body); } } @@ -19,7 +19,7 @@ impl<'tcx> crate::MirLint<'tcx> for CheckPackedRef { struct PackedRefChecker<'a, 'tcx> { body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, source_info: SourceInfo, } @@ -37,7 +37,8 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { } fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { - if context.is_borrow() && util::is_disaligned(self.tcx, self.body, self.param_env, *place) { + if context.is_borrow() && util::is_disaligned(self.tcx, self.body, self.typing_env, *place) + { let def_id = self.body.source.instance.def_id(); if let Some(impl_def_id) = self.tcx.impl_of_method(def_id) && self.tcx.is_builtin_derived(impl_def_id) diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 7d6ae9843b1..9b3443d3209 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -28,8 +28,8 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!(def_id = ?body.source.def_id()); - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - let ssa = SsaLocals::new(tcx, body, param_env); + let typing_env = body.typing_env(tcx); + let ssa = SsaLocals::new(tcx, body, typing_env); let fully_moved = fully_moved_locals(&ssa, body); debug!(?fully_moved); diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 063f220501f..8295a806d71 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -68,11 +68,11 @@ use rustc_middle::ty::{ self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode, }; use rustc_middle::{bug, span_bug}; -use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::impls::{ MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive, }; use rustc_mir_dataflow::storage::always_storage_live_locals; +use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor}; use rustc_span::Span; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::sym; @@ -817,9 +817,9 @@ impl ops::Deref for CoroutineSavedLocals { /// computation; see `CoroutineLayout` for more. fn compute_storage_conflicts<'mir, 'tcx>( body: &'mir Body<'tcx>, - saved_locals: &CoroutineSavedLocals, + saved_locals: &'mir CoroutineSavedLocals, always_live_locals: BitSet<Local>, - mut requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>, + mut requires_storage: Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>, ) -> BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal> { assert_eq!(body.local_decls.len(), saved_locals.domain_size()); @@ -877,15 +877,13 @@ struct StorageConflictVisitor<'a, 'tcx> { eligible_storage_live: BitSet<Local>, } -impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> +impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>> for StorageConflictVisitor<'a, 'tcx> { - type Domain = BitSet<Local>; - fn visit_statement_before_primary_effect( &mut self, - _results: &mut R, - state: &Self::Domain, + _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>, + state: &BitSet<Local>, _statement: &'a Statement<'tcx>, loc: Location, ) { @@ -894,8 +892,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> fn visit_terminator_before_primary_effect( &mut self, - _results: &mut R, - state: &Self::Domain, + _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>, + state: &BitSet<Local>, _terminator: &'a Terminator<'tcx>, loc: Location, ) { @@ -1071,11 +1069,9 @@ fn elaborate_coroutine_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // Note that `elaborate_drops` only drops the upvars of a coroutine, and // this is ok because `open_drop` can only be reached within that own // coroutine's resume function. + let typing_env = body.typing_env(tcx); - let def_id = body.source.def_id(); - let param_env = tcx.param_env(def_id); - - let mut elaborator = DropShimElaborator { body, patch: MirPatch::new(body), tcx, param_env }; + let mut elaborator = DropShimElaborator { body, patch: MirPatch::new(body), tcx, typing_env }; for (block, block_data) in body.basic_blocks.iter_enumerated() { let (target, unwind, source_info) = match block_data.terminator() { @@ -1206,9 +1202,9 @@ fn insert_panic_block<'tcx>( insert_term_block(body, kind) } -fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { +fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { // Returning from a function with an uninhabited return type is undefined behavior. - if body.return_ty().is_privately_uninhabited(tcx, param_env) { + if body.return_ty().is_privately_uninhabited(tcx, typing_env) { return false; } @@ -1629,7 +1625,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { // `storage_liveness` tells us which locals have live storage at suspension points let (remap, layout, storage_liveness) = compute_layout(liveness_info, body); - let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id())); + let can_return = can_return(tcx, body, body.typing_env(tcx)); // Run the transformation which converts Places from Local to coroutine struct // accesses for locals in `remap`. @@ -1776,6 +1772,7 @@ impl<'tcx> Visitor<'tcx> for EnsureCoroutineFieldAssignmentsNeverAlias<'_> { | StatementKind::Coverage(..) | StatementKind::Intrinsic(..) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs index 59b403538a3..b23d8b9e737 100644 --- a/compiler/rustc_mir_transform/src/cost_checker.rs +++ b/compiler/rustc_mir_transform/src/cost_checker.rs @@ -1,7 +1,7 @@ use rustc_middle::bug; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; const INSTR_COST: usize = 5; const CALL_PENALTY: usize = 25; @@ -14,7 +14,7 @@ const CONST_SWITCH_BONUS: usize = 10; #[derive(Clone)] pub(super) struct CostChecker<'b, 'tcx> { tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, penalty: usize, bonus: usize, callee_body: &'b Body<'tcx>, @@ -24,11 +24,11 @@ pub(super) struct CostChecker<'b, 'tcx> { impl<'b, 'tcx> CostChecker<'b, 'tcx> { pub(super) fn new( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, instance: Option<ty::Instance<'tcx>>, callee_body: &'b Body<'tcx>, ) -> CostChecker<'b, 'tcx> { - CostChecker { tcx, param_env, callee_body, instance, penalty: 0, bonus: 0 } + CostChecker { tcx, typing_env, callee_body, instance, penalty: 0, bonus: 0 } } /// Add function-level costs not well-represented by the block-level costs. @@ -119,7 +119,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { TerminatorKind::Drop { place, unwind, .. } => { // If the place doesn't actually need dropping, treat it like a regular goto. let ty = self.instantiate_ty(place.ty(self.callee_body, self.tcx).ty); - if ty.needs_drop(self.tcx, self.param_env) { + if ty.needs_drop(self.tcx, self.typing_env) { self.penalty += CALL_PENALTY; if let UnwindAction::Cleanup(_) = unwind { self.penalty += LANDINGPAD_PENALTY; diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 875db23ce09..824d657e1fc 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -97,6 +97,7 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> { StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => None, // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead` diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 7d073f1fa57..d017202f48b 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -16,7 +16,7 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::{InterpResult, Scalar}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::lattice::{FlatSet, HasBottom}; @@ -82,7 +82,7 @@ struct ConstAnalysis<'a, 'tcx> { tcx: TyCtxt<'tcx>, local_decls: &'a LocalDecls<'tcx>, ecx: InterpCx<'tcx, DummyMachine>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, } impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> { @@ -144,13 +144,13 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> { impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map<'tcx>) -> Self { - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let typing_env = body.typing_env(tcx); Self { map, tcx, local_decls: &body.local_decls, - ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine), - param_env, + ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine), + typing_env, } } @@ -186,7 +186,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { | StatementKind::FakeRead(..) | StatementKind::PlaceMention(..) | StatementKind::Coverage(..) - | StatementKind::AscribeUserType(..) => (), + | StatementKind::BackwardIncompatibleDropHint { .. } + | StatementKind::AscribeUserType(..) => {} } } @@ -389,7 +390,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { && let Some(operand_ty) = operand_ty.builtin_deref(true) && let ty::Array(_, len) = operand_ty.kind() && let Some(len) = Const::Ty(self.tcx.types.usize, *len) - .try_eval_scalar_int(self.tcx, self.param_env) + .try_eval_scalar_int(self.tcx, self.typing_env) { state.insert_value_idx(target_len, FlatSet::Elem(len.into()), &self.map); } @@ -411,7 +412,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { let place_ty = place.ty(self.local_decls, self.tcx); if let ty::Array(_, len) = place_ty.ty.kind() { Const::Ty(self.tcx.types.usize, *len) - .try_eval_scalar(self.tcx, self.param_env) + .try_eval_scalar(self.tcx, self.typing_env) .map_or(FlatSet::Top, FlatSet::Elem) } else if let [ProjectionElem::Deref] = place.projection[..] { state.get_len(place.local.into(), &self.map) @@ -420,7 +421,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => { - let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else { + let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else { return ValueOrPlace::Value(FlatSet::Top); }; match self.eval_operand(operand, state) { @@ -434,7 +435,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } Rvalue::Cast(CastKind::FloatToInt | CastKind::FloatToFloat, operand, ty) => { - let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else { + let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else { return ValueOrPlace::Value(FlatSet::Top); }; match self.eval_operand(operand, state) { @@ -470,7 +471,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { FlatSet::Top => FlatSet::Top, }, Rvalue::NullaryOp(null_op, ty) => { - let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else { + let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else { return ValueOrPlace::Value(FlatSet::Top); }; let val = match null_op { @@ -479,7 +480,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { NullOp::OffsetOf(fields) => self .ecx .tcx - .offset_of_subfield(self.ecx.param_env(), layout, fields.iter()) + .offset_of_subfield(self.typing_env, layout, fields.iter()) .bytes(), _ => return ValueOrPlace::Value(FlatSet::Top), }; @@ -514,7 +515,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { ) -> FlatSet<Scalar> { constant .const_ - .try_eval_scalar(self.tcx, self.param_env) + .try_eval_scalar(self.tcx, self.typing_env) .map_or(FlatSet::Top, FlatSet::Elem) } @@ -554,7 +555,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } else if rhs.projection.first() == Some(&PlaceElem::Deref) && let FlatSet::Elem(pointer) = state.get(rhs.local.into(), &self.map) && let rhs_ty = self.local_decls[rhs.local].ty - && let Ok(rhs_layout) = self.tcx.layout_of(self.param_env.and(rhs_ty)) + && let Ok(rhs_layout) = + self.tcx.layout_of(self.typing_env.as_query_input(rhs_ty)) { let op = ImmTy::from_scalar(pointer, rhs_layout).into(); self.assign_constant(state, place, op, rhs.projection); @@ -614,8 +616,10 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { TrackElem::DerefLen => { let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_err()?.into(); let len_usize = op.len(&self.ecx).discard_err()?; - let layout = - self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).unwrap(); + let layout = self + .tcx + .layout_of(self.typing_env.as_query_input(self.tcx.types.usize)) + .unwrap(); Some(ImmTy::from_uint(len_usize, layout).into()) } }, @@ -702,9 +706,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { FlatSet::Top => FlatSet::Top, FlatSet::Elem(scalar) => { let ty = op.ty(self.local_decls, self.tcx); - self.tcx.layout_of(self.param_env.and(ty)).map_or(FlatSet::Top, |layout| { - FlatSet::Elem(ImmTy::from_scalar(scalar, layout)) - }) + self.tcx + .layout_of(self.typing_env.as_query_input(ty)) + .map_or(FlatSet::Top, |layout| { + FlatSet::Elem(ImmTy::from_scalar(scalar, layout)) + }) } FlatSet::Bottom => FlatSet::Bottom, } @@ -714,7 +720,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { if !enum_ty.is_enum() { return None; } - let enum_ty_layout = self.tcx.layout_of(self.param_env.and(enum_ty)).ok()?; + let enum_ty_layout = self.tcx.layout_of(self.typing_env.as_query_input(enum_ty)).ok()?; let discr_value = self.ecx.discriminant_for_variant(enum_ty_layout.ty, variant_index).discard_err()?; Some(discr_value.to_scalar()) @@ -941,16 +947,12 @@ fn try_write_constant<'tcx>( interp_ok(()) } -impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx>>> - for Collector<'_, 'tcx> -{ - type Domain = State<FlatSet<Scalar>>; - +impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> { #[instrument(level = "trace", skip(self, results, statement))] fn visit_statement_before_primary_effect( &mut self, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, - state: &Self::Domain, + state: &State<FlatSet<Scalar>>, statement: &'mir Statement<'tcx>, location: Location, ) { @@ -972,7 +974,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx fn visit_statement_after_primary_effect( &mut self, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, - state: &Self::Domain, + state: &State<FlatSet<Scalar>>, statement: &'mir Statement<'tcx>, location: Location, ) { @@ -997,7 +999,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx fn visit_terminator_before_primary_effect( &mut self, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, - state: &Self::Domain, + state: &State<FlatSet<Scalar>>, terminator: &'mir Terminator<'tcx>, location: Location, ) { diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 2898f82e25c..0c75cdadc92 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -99,7 +99,8 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { | StatementKind::Intrinsic(_) | StatementKind::ConstEvalCounter | StatementKind::PlaceMention(_) - | StatementKind::Nop => (), + | StatementKind::BackwardIncompatibleDropHint { .. } + | StatementKind::Nop => {} StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { bug!("{:?} not found in this MIR phase!", statement.kind) diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs index 753bae8e156..67b215c7c9d 100644 --- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -198,7 +198,7 @@ pub(super) fn deduced_param_attrs<'tcx>( // see [1]. // // [1]: https://github.com/rust-lang/rust/pull/103172#discussion_r999139997 - let param_env = tcx.param_env_reveal_all_normalized(def_id); + let typing_env = body.typing_env(tcx); let mut deduced_param_attrs = tcx.arena.alloc_from_iter( body.local_decls.iter().skip(1).take(body.arg_count).enumerate().map( |(arg_index, local_decl)| DeducedParamAttrs { @@ -207,8 +207,8 @@ pub(super) fn deduced_param_attrs<'tcx>( // their generic parameters, otherwise we'll see exponential // blow-up in compile times: #113372 && tcx - .normalize_erasing_regions(param_env, local_decl.ty) - .is_freeze(tcx, param_env), + .normalize_erasing_regions(typing_env, local_decl.ty) + .is_freeze(tcx, typing_env), }, ), ); diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index beeab0d4a66..9c74b2f0839 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -581,7 +581,7 @@ impl WriteInfo { | Rvalue::RawPtr(_, _) | Rvalue::Len(_) | Rvalue::Discriminant(_) - | Rvalue::CopyForDeref(_) => (), + | Rvalue::CopyForDeref(_) => {} } } // Retags are technically also reads, but reporting them as a write suffices @@ -596,7 +596,8 @@ impl WriteInfo { | StatementKind::Coverage(_) | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) - | StatementKind::PlaceMention(_) => (), + | StatementKind::BackwardIncompatibleDropHint { .. } + | StatementKind::PlaceMention(_) => {} StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { bug!("{:?} not found in this MIR phase", statement) } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 74572100db3..b0f041d8722 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -3,6 +3,7 @@ use std::fmt; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; +use rustc_infer::traits::Reveal; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; @@ -53,14 +54,14 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops { #[instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("elaborate_drops({:?} @ {:?})", body.source, body.span); - - let def_id = body.source.def_id(); - let param_env = tcx.param_env_reveal_all_normalized(def_id); + // FIXME(#132279): This is used during the phase transition from analysis + // to runtime, so we have to manually specify the correct typing mode. + let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id()); // For types that do not need dropping, the behaviour is trivial. So we only need to track // init/uninit for types that do need dropping. - let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, param_env)); + let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, typing_env)); let elaborate_patch = { - let env = MoveDataParamEnv { move_data, param_env }; + let env = MoveDataParamEnv { move_data, param_env: typing_env.param_env }; let mut inits = MaybeInitializedPlaces::new(tcx, body, &env.move_data) .skipping_unreachable_unwind() @@ -147,8 +148,8 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for ElaborateDropsCtxt<'a, 'tcx> { self.tcx } - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env() + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + self.typing_env() } #[instrument(level = "debug", skip(self), ret)] @@ -250,6 +251,11 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> { self.env.param_env } + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + debug_assert_eq!(self.param_env().reveal(), Reveal::All); + ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env: self.param_env() } + } + fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) { let patch = &mut self.patch; debug!("create_drop_flag({:?})", self.body.span); @@ -335,7 +341,7 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> { if !place .ty(&self.body.local_decls, self.tcx) .ty - .needs_drop(self.tcx, self.env.param_env) + .needs_drop(self.tcx, self.typing_env()) { self.patch.patch_terminator(bb, TerminatorKind::Goto { target }); continue; diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 274eea9563f..976f4a8e919 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -100,7 +100,7 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::GlobalAlloc; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; +use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use rustc_span::def_id::DefId; @@ -120,12 +120,12 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!(def_id = ?body.source.def_id()); - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - let ssa = SsaLocals::new(tcx, body, param_env); + let typing_env = body.typing_env(tcx); + let ssa = SsaLocals::new(tcx, body, typing_env); // Clone dominators because we need them while mutating the body. let dominators = body.basic_blocks.dominators().clone(); - let mut state = VnState::new(tcx, body, param_env, &ssa, dominators, &body.local_decls); + let mut state = VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls); ssa.for_each_assignment_mut( body.basic_blocks.as_mut_preserves_cfg(), |local, value, location| { @@ -241,7 +241,6 @@ enum Value<'tcx> { struct VnState<'body, 'tcx> { tcx: TyCtxt<'tcx>, ecx: InterpCx<'tcx, DummyMachine>, - param_env: ty::ParamEnv<'tcx>, local_decls: &'body LocalDecls<'tcx>, /// Value stored in each local. locals: IndexVec<Local, Option<VnIndex>>, @@ -266,7 +265,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { fn new( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ssa: &'body SsaLocals, dominators: Dominators<BasicBlock>, local_decls: &'body LocalDecls<'tcx>, @@ -280,8 +279,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { + 4 * body.basic_blocks.len(); VnState { tcx, - ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine), - param_env, + ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine), local_decls, locals: IndexVec::from_elem(None, local_decls), rev_locals: IndexVec::with_capacity(num_values), @@ -295,6 +293,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + self.ecx.typing_env() + } + #[instrument(level = "trace", skip(self), ret)] fn insert(&mut self, value: Value<'tcx>) -> VnIndex { let (index, new) = self.values.insert_full(value); @@ -343,7 +345,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // Only register the value if its type is `Sized`, as we will emit copies of it. let is_sized = !self.feature_unsized_locals - || self.local_decls[local].ty.is_sized(self.tcx, self.param_env); + || self.local_decls[local].ty.is_sized(self.tcx, self.typing_env()); if is_sized { self.rev_locals[value].push(local); } @@ -531,7 +533,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { NullOp::OffsetOf(fields) => self .ecx .tcx - .offset_of_subfield(self.ecx.param_env(), layout, fields.iter()) + .offset_of_subfield(self.typing_env(), layout, fields.iter()) .bytes(), NullOp::UbChecks => return None, }; @@ -638,7 +640,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let ty = place.ty(self.local_decls, self.tcx).ty; if let Some(Mutability::Not) = ty.ref_mutability() && let Some(pointee_ty) = ty.builtin_deref(true) - && pointee_ty.is_freeze(self.tcx, self.param_env) + && pointee_ty.is_freeze(self.tcx, self.typing_env()) { // An immutable borrow `_x` always points to the same value for the // lifetime of the borrow, so we can merge all instances of `*_x`. @@ -1057,7 +1059,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let ty::RawPtr(from_pointee_ty, from_mtbl) = cast_from.kind() && let ty::RawPtr(_, output_mtbl) = output_pointer_ty.kind() && from_mtbl == output_mtbl - && from_pointee_ty.is_sized(self.tcx, self.param_env) + && from_pointee_ty.is_sized(self.tcx, self.typing_env()) { fields[0] = *cast_value; *data_pointer_ty = *cast_from; @@ -1379,7 +1381,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) = self.get(value) && let ty::RawPtr(to_pointee, _) = to.kind() - && to_pointee.is_sized(self.tcx, self.param_env) + && to_pointee.is_sized(self.tcx, self.typing_env()) { from = *data_pointer_ty; value = fields[0]; @@ -1476,8 +1478,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { if left_meta_ty == right_meta_ty { true } else if let Ok(left) = - self.tcx.try_normalize_erasing_regions(self.param_env, left_meta_ty) - && let Ok(right) = self.tcx.try_normalize_erasing_regions(self.param_env, right_meta_ty) + self.tcx.try_normalize_erasing_regions(self.typing_env(), left_meta_ty) + && let Ok(right) = + self.tcx.try_normalize_erasing_regions(self.typing_env(), right_meta_ty) { left == right } else { diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index e95ab4ffe16..00f6c3845d4 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -13,9 +13,7 @@ use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::{ - self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt, TypeFlags, TypeVisitableExt, -}; +use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypeFlags, TypeVisitableExt}; use rustc_session::config::{DebugInfo, OptLevel}; use rustc_span::source_map::Spanned; use rustc_span::sym; @@ -94,12 +92,12 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { return false; } - let param_env = tcx.param_env_reveal_all_normalized(def_id); + let typing_env = body.typing_env(tcx); let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); let mut this = Inliner { tcx, - param_env, + typing_env, codegen_fn_attrs, history: Vec::new(), changed: false, @@ -115,7 +113,7 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { struct Inliner<'tcx> { tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, /// Caller codegen attributes. codegen_fn_attrs: &'tcx CodegenFnAttrs, /// Stack of inlined instances. @@ -201,7 +199,8 @@ impl<'tcx> Inliner<'tcx> { let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty; for arg in args { - if !arg.node.ty(&caller_body.local_decls, self.tcx).is_sized(self.tcx, self.param_env) { + if !arg.node.ty(&caller_body.local_decls, self.tcx).is_sized(self.tcx, self.typing_env) + { // We do not allow inlining functions with unsized params. Inlining these functions // could create unsized locals, which are unsound and being phased out. return Err("Call has unsized argument"); @@ -219,7 +218,7 @@ impl<'tcx> Inliner<'tcx> { let Ok(callee_body) = callsite.callee.try_instantiate_mir_and_normalize_erasing_regions( self.tcx, - self.param_env, + self.typing_env, ty::EarlyBinder::bind(callee_body.clone()), ) else { return Err("failed to normalize callee body"); @@ -230,7 +229,7 @@ impl<'tcx> Inliner<'tcx> { if !validate_types( self.tcx, MirPhase::Runtime(RuntimePhase::Optimized), - self.param_env, + self.typing_env, &callee_body, &caller_body, ) @@ -243,13 +242,7 @@ impl<'tcx> Inliner<'tcx> { // Normally, this shouldn't be required, but trait normalization failure can create a // validation ICE. let output_type = callee_body.return_ty(); - if !util::sub_types( - self.tcx, - caller_body.typing_mode(self.tcx), - self.param_env, - output_type, - destination_ty, - ) { + if !util::sub_types(self.tcx, self.typing_env, output_type, destination_ty) { trace!(?output_type, ?destination_ty); return Err("failed to normalize return type"); } @@ -279,13 +272,7 @@ impl<'tcx> Inliner<'tcx> { self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter()) { let input_type = callee_body.local_decls[input].ty; - if !util::sub_types( - self.tcx, - caller_body.typing_mode(self.tcx), - self.param_env, - input_type, - arg_ty, - ) { + if !util::sub_types(self.tcx, self.typing_env, input_type, arg_ty) { trace!(?arg_ty, ?input_type); return Err("failed to normalize tuple argument type"); } @@ -294,13 +281,7 @@ impl<'tcx> Inliner<'tcx> { for (arg, input) in args.iter().zip(callee_body.args_iter()) { let input_type = callee_body.local_decls[input].ty; let arg_ty = arg.node.ty(&caller_body.local_decls, self.tcx); - if !util::sub_types( - self.tcx, - caller_body.typing_mode(self.tcx), - self.param_env, - input_type, - arg_ty, - ) { + if !util::sub_types(self.tcx, self.typing_env, input_type, arg_ty) { trace!(?arg_ty, ?input_type); return Err("failed to normalize argument type"); } @@ -402,9 +383,10 @@ impl<'tcx> Inliner<'tcx> { let func_ty = func.ty(caller_body, self.tcx); if let ty::FnDef(def_id, args) = *func_ty.kind() { // To resolve an instance its args have to be fully normalized. - let args = self.tcx.try_normalize_erasing_regions(self.param_env, args).ok()?; - let callee = - Instance::try_resolve(self.tcx, self.param_env, def_id, args).ok().flatten()?; + let args = self.tcx.try_normalize_erasing_regions(self.typing_env, args).ok()?; + let callee = Instance::try_resolve(self.tcx, self.typing_env, def_id, args) + .ok() + .flatten()?; if let InstanceKind::Virtual(..) | InstanceKind::Intrinsic(_) = callee.def { return None; @@ -528,7 +510,7 @@ impl<'tcx> Inliner<'tcx> { // FIXME: Give a bonus to functions with only a single caller let mut checker = - CostChecker::new(self.tcx, self.param_env, Some(callsite.callee), callee_body); + CostChecker::new(self.tcx, self.typing_env, Some(callsite.callee), callee_body); checker.add_function_level_costs(); @@ -552,7 +534,7 @@ impl<'tcx> Inliner<'tcx> { self.tcx, ty::EarlyBinder::bind(&place.ty(callee_body, tcx).ty), ); - if ty.needs_drop(tcx, self.param_env) + if ty.needs_drop(tcx, self.typing_env) && let UnwindAction::Cleanup(unwind) = unwind { work_list.push(unwind); diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 9828e90de88..a40768300f5 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -15,7 +15,6 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( (root, target): (ty::Instance<'tcx>, LocalDefId), ) -> bool { trace!(%root, target = %tcx.def_path_str(target)); - let param_env = tcx.param_env_reveal_all_normalized(target); assert_ne!( root.def_id().expect_local(), target, @@ -31,11 +30,11 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( ); #[instrument( level = "debug", - skip(tcx, param_env, target, stack, seen, recursion_limiter, caller, recursion_limit) + skip(tcx, typing_env, target, stack, seen, recursion_limiter, caller, recursion_limit) )] fn process<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, caller: ty::Instance<'tcx>, target: LocalDefId, stack: &mut Vec<ty::Instance<'tcx>>, @@ -47,13 +46,13 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( for &(callee, args) in tcx.mir_inliner_callees(caller.def) { let Ok(args) = caller.try_instantiate_mir_and_normalize_erasing_regions( tcx, - param_env, + typing_env, ty::EarlyBinder::bind(args), ) else { - trace!(?caller, ?param_env, ?args, "cannot normalize, skipping"); + trace!(?caller, ?typing_env, ?args, "cannot normalize, skipping"); continue; }; - let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, param_env, callee, args) else { + let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, typing_env, callee, args) else { trace!(?callee, "cannot resolve, skipping"); continue; }; @@ -115,7 +114,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( let found_recursion = ensure_sufficient_stack(|| { process( tcx, - param_env, + typing_env, callee, target, stack, @@ -146,7 +145,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( let recursion_limit = tcx.recursion_limit() / 2; process( tcx, - param_env, + ty::TypingEnv::post_analysis(tcx, target), root, target, &mut Vec::new(), diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 9471c1b2a9a..3352d583f2c 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -6,7 +6,7 @@ use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::mir::*; use rustc_middle::ty::layout::ValidityRequirement; -use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, layout}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, layout}; use rustc_span::sym; use rustc_span::symbol::Symbol; @@ -34,7 +34,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify { let ctx = InstSimplifyContext { tcx, local_decls: &body.local_decls, - param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()), + typing_env: body.typing_env(tcx), }; let preserve_ub_checks = attr::contains_name(tcx.hir().krate_attrs(), sym::rustc_preserve_ub_checks); @@ -66,7 +66,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify { struct InstSimplifyContext<'a, 'tcx> { tcx: TyCtxt<'tcx>, local_decls: &'a LocalDecls<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, } impl<'tcx> InstSimplifyContext<'_, 'tcx> { @@ -348,7 +348,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { } let known_is_valid = - intrinsic_assert_panics(self.tcx, self.param_env, args[0], intrinsic_name); + intrinsic_assert_panics(self.tcx, self.typing_env, args[0], intrinsic_name); match known_is_valid { // We don't know the layout or it's not validity assertion at all, don't touch it None => {} @@ -366,13 +366,13 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { fn intrinsic_assert_panics<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, arg: ty::GenericArg<'tcx>, intrinsic_name: Symbol, ) -> Option<bool> { let requirement = ValidityRequirement::from_intrinsic(intrinsic_name)?; let ty = arg.expect_ty(); - Some(!tcx.check_validity_requirement((requirement, param_env.and(ty))).ok()?) + Some(!tcx.check_validity_requirement((requirement, typing_env.as_query_input(ty))).ok()?) } fn resolve_rust_intrinsic<'tcx>( diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 3772589ac4e..beed007589b 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -77,13 +77,12 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading { return; } - let param_env = tcx.param_env_reveal_all_normalized(def_id); - + let typing_env = body.typing_env(tcx); let arena = &DroplessArena::default(); let mut finder = TOFinder { tcx, - param_env, - ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine), + typing_env, + ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine), body, arena, map: Map::new(tcx, body, Some(MAX_PLACES)), @@ -119,7 +118,7 @@ struct ThreadingOpportunity { struct TOFinder<'a, 'tcx> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ecx: InterpCx<'tcx, DummyMachine>, body: &'a Body<'tcx>, map: Map<'tcx>, @@ -207,7 +206,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let Some(discr) = self.map.find(discr.as_ref()) else { return }; debug!(?discr); - let cost = CostChecker::new(self.tcx, self.param_env, None, self.body); + let cost = CostChecker::new(self.tcx, self.typing_env, None, self.body); let mut state = State::new_reachable(); let conds = if let Some((value, then, else_)) = targets.as_static_if() { @@ -353,6 +352,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { | StatementKind::FakeRead(..) | StatementKind::ConstEvalCounter | StatementKind::PlaceMention(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => None, } } @@ -528,7 +528,8 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // Avoid handling them, though this could be extended in the future. return; } - let Some(value) = value.const_.try_eval_scalar_int(self.tcx, self.param_env) else { + let Some(value) = value.const_.try_eval_scalar_int(self.tcx, self.typing_env) + else { return; }; let conds = conditions.map(self.arena, |c| Condition { diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 0604665642a..53e282e9b46 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -18,7 +18,7 @@ use rustc_middle::bug; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; -use rustc_middle::ty::{self, ConstInt, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, ConstInt, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; use tracing::{debug, instrument, trace}; @@ -65,7 +65,7 @@ impl<'tcx> crate::MirLint<'tcx> for KnownPanicsLint { struct ConstPropagator<'mir, 'tcx> { ecx: InterpCx<'tcx, DummyMachine>, tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, worklist: Vec<BasicBlock>, visited_blocks: BitSet<BasicBlock>, locals: IndexVec<Local, Value<'tcx>>, @@ -169,25 +169,26 @@ impl<'tcx> ty::layout::HasTyCtxt<'tcx> for ConstPropagator<'_, 'tcx> { } } -impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> { +impl<'tcx> ty::layout::HasTypingEnv<'tcx> for ConstPropagator<'_, 'tcx> { #[inline] - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + self.typing_env } } impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> { let def_id = body.source.def_id(); - let param_env = tcx.param_env_reveal_all_normalized(def_id); - - let can_const_prop = CanConstProp::check(tcx, param_env, body); - let ecx = InterpCx::new(tcx, tcx.def_span(def_id), param_env, DummyMachine); + // FIXME(#132279): This is used during the phase transition from analysis + // to runtime, so we have to manually specify the correct typing mode. + let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id()); + let can_const_prop = CanConstProp::check(tcx, typing_env, body); + let ecx = InterpCx::new(tcx, tcx.def_span(def_id), typing_env, DummyMachine); ConstPropagator { ecx, tcx, - param_env, + typing_env, worklist: vec![START_BLOCK], visited_blocks: BitSet::new_empty(body.basic_blocks.len()), locals: IndexVec::from_elem_n(Value::Uninit, body.local_decls.len()), @@ -260,7 +261,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // that the `RevealAll` pass has happened and that the body's consts // are normalized, so any call to resolve before that needs to be // manually normalized. - let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.const_).ok()?; + let val = self.tcx.try_normalize_erasing_regions(self.typing_env, c.const_).ok()?; self.use_ecx(|this| this.ecx.eval_mir_constant(&val, c.span, None))? .as_mplace_or_imm() @@ -450,7 +451,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if rvalue.has_param() { return None; } - if !rvalue.ty(self.local_decls(), self.tcx).is_sized(self.tcx, self.param_env) { + if !rvalue.ty(self.local_decls(), self.tcx).is_sized(self.tcx, self.typing_env) { // the interpreter doesn't support unsized locals (only unsized arguments), // but rustc does (in a kinda broken way), so we have to skip them here return None; @@ -622,7 +623,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { NullOp::AlignOf => op_layout.align.abi.bytes(), NullOp::OffsetOf(fields) => self .tcx - .offset_of_subfield(self.param_env, op_layout, fields.iter()) + .offset_of_subfield(self.typing_env, op_layout, fields.iter()) .bytes(), NullOp::UbChecks => return None, }; @@ -873,7 +874,7 @@ impl CanConstProp { /// Returns true if `local` can be propagated fn check<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, body: &Body<'tcx>, ) -> IndexVec<Local, ConstPropMode> { let mut cpv = CanConstProp { @@ -888,7 +889,7 @@ impl CanConstProp { // variant of a union *val = ConstPropMode::NoPropagation; } else { - match tcx.layout_of(param_env.and(ty)) { + match tcx.layout_of(typing_env.as_query_input(ty)) { Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {} // Either the layout fails to compute, then we can't use this local anyway // or the local is too large, then we don't want to. diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index fa659a56a27..8be5a63d008 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::*; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, AdtDef, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_session::Session; /// A pass that seeks to optimize unnecessary moves of large enum types, if there is a large @@ -39,8 +39,7 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt { // platform, but it will still be valid. let mut alloc_cache = FxHashMap::default(); - let body_did = body.source.def_id(); - let param_env = tcx.param_env_reveal_all_normalized(body_did); + let typing_env = body.typing_env(tcx); let blocks = body.basic_blocks.as_mut(); let local_decls = &mut body.local_decls; @@ -58,7 +57,7 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt { let ty = lhs.ty(local_decls, tcx).ty; let (adt_def, num_variants, alloc_id) = - self.candidate(tcx, param_env, ty, &mut alloc_cache)?; + self.candidate(tcx, typing_env, ty, &mut alloc_cache)?; let source_info = st.source_info; let span = source_info.span; @@ -207,7 +206,7 @@ impl EnumSizeOpt { fn candidate<'tcx>( &self, tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, alloc_cache: &mut FxHashMap<Ty<'tcx>, AllocId>, ) -> Option<(AdtDef<'tcx>, usize, AllocId)> { @@ -215,7 +214,7 @@ impl EnumSizeOpt { ty::Adt(adt_def, _args) if adt_def.is_enum() => adt_def, _ => return None, }; - let layout = tcx.layout_of(param_env.and(ty)).ok()?; + let layout = tcx.layout_of(typing_env.as_query_input(ty)).ok()?; let variants = match &layout.variants { Variants::Single { .. } => return None, Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => return None, diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index d2d5facbbdc..bfb842e4485 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -50,6 +50,7 @@ mod deduce_param_attrs; mod errors; mod ffi_unwind_calls; mod lint; +mod lint_tail_expr_drop_order; mod shim; mod ssa; @@ -333,10 +334,14 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> { } fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs { - let const_kind = tcx.hir().body_const_context(def); - + // N.B., this `borrow()` is guaranteed to be valid (i.e., the value + // cannot yet be stolen), because `mir_promoted()`, which steals + // from `mir_built()`, forces this query to execute before + // performing the steal. + let body = &tcx.mir_built(def).borrow(); + let ccx = check_consts::ConstCx::new(tcx, body); // No need to const-check a non-const `fn`. - match const_kind { + match ccx.const_kind { Some(ConstContext::Const { .. } | ConstContext::Static(_) | ConstContext::ConstFn) => {} None => span_bug!( tcx.def_span(def), @@ -344,20 +349,12 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs { ), } - // N.B., this `borrow()` is guaranteed to be valid (i.e., the value - // cannot yet be stolen), because `mir_promoted()`, which steals - // from `mir_built()`, forces this query to execute before - // performing the steal. - let body = &tcx.mir_built(def).borrow(); - if body.return_ty().references_error() { // It's possible to reach here without an error being emitted (#121103). tcx.dcx().span_delayed_bug(body.span, "mir_const_qualif: MIR had errors"); return Default::default(); } - let ccx = check_consts::ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def) }; - let mut validator = check_consts::check::Checker::new(&ccx); validator.check_body(); @@ -494,6 +491,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & } let (body, _) = tcx.mir_promoted(def); + lint_tail_expr_drop_order::run_lint(tcx, def, &body.borrow()); let mut body = body.steal(); if let Some(error_reported) = tainted_by_errors { diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs new file mode 100644 index 00000000000..b8502fcbafb --- /dev/null +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -0,0 +1,701 @@ +use std::cell::RefCell; +use std::collections::hash_map; +use std::rc::Rc; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::unord::{UnordMap, UnordSet}; +use rustc_errors::Subdiagnostic; +use rustc_hir::CRATE_HIR_ID; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_index::bit_set::ChunkedBitSet; +use rustc_index::{IndexSlice, IndexVec}; +use rustc_macros::{LintDiagnostic, Subdiagnostic}; +use rustc_middle::bug; +use rustc_middle::mir::{ + self, BasicBlock, Body, ClearCrossCrate, Local, Location, Place, StatementKind, TerminatorKind, + dump_mir, +}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_mir_dataflow::impls::MaybeInitializedPlaces; +use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; +use rustc_mir_dataflow::{Analysis, MaybeReachable, ResultsCursor}; +use rustc_session::lint::builtin::TAIL_EXPR_DROP_ORDER; +use rustc_session::lint::{self}; +use rustc_span::{DUMMY_SP, Span, Symbol}; +use rustc_type_ir::data_structures::IndexMap; +use smallvec::{SmallVec, smallvec}; +use tracing::{debug, instrument}; + +fn place_has_common_prefix<'tcx>(left: &Place<'tcx>, right: &Place<'tcx>) -> bool { + left.local == right.local + && left.projection.iter().zip(right.projection).all(|(left, right)| left == right) +} + +/// Cache entry of `drop` at a `BasicBlock` +#[derive(Debug, Clone, Copy)] +enum MovePathIndexAtBlock { + /// We know nothing yet + Unknown, + /// We know that the `drop` here has no effect + None, + /// We know that the `drop` here will invoke a destructor + Some(MovePathIndex), +} + +struct DropsReachable<'a, 'mir, 'tcx> { + body: &'a Body<'tcx>, + place: &'a Place<'tcx>, + drop_span: &'a mut Option<Span>, + move_data: &'a MoveData<'tcx>, + maybe_init: &'a mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, + block_drop_value_info: &'a mut IndexSlice<BasicBlock, MovePathIndexAtBlock>, + collected_drops: &'a mut ChunkedBitSet<MovePathIndex>, + visited: FxHashMap<BasicBlock, Rc<RefCell<ChunkedBitSet<MovePathIndex>>>>, +} + +impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> { + fn visit(&mut self, block: BasicBlock) { + let move_set_size = self.move_data.move_paths.len(); + let make_new_path_set = || Rc::new(RefCell::new(ChunkedBitSet::new_empty(move_set_size))); + + let data = &self.body.basic_blocks[block]; + let Some(terminator) = &data.terminator else { return }; + // Given that we observe these dropped locals here at `block` so far, + // we will try to update the successor blocks. + // An occupied entry at `block` in `self.visited` signals that we have visited `block` before. + let dropped_local_here = + Rc::clone(self.visited.entry(block).or_insert_with(make_new_path_set)); + // We could have invoked reverse lookup for a `MovePathIndex` every time, but unfortunately it is expensive. + // Let's cache them in `self.block_drop_value_info`. + match self.block_drop_value_info[block] { + MovePathIndexAtBlock::Some(dropped) => { + dropped_local_here.borrow_mut().insert(dropped); + } + MovePathIndexAtBlock::Unknown => { + if let TerminatorKind::Drop { place, .. } = &terminator.kind + && let LookupResult::Exact(idx) | LookupResult::Parent(Some(idx)) = + self.move_data.rev_lookup.find(place.as_ref()) + { + // Since we are working with MIRs at a very early stage, + // observing a `drop` terminator is not indicative enough that + // the drop will definitely happen. + // That is decided in the drop elaboration pass instead. + // Therefore, we need to consult with the maybe-initialization information. + self.maybe_init.seek_before_primary_effect(Location { + block, + statement_index: data.statements.len(), + }); + + // Check if the drop of `place` under inspection is really in effect. + // This is true only when `place` may have been initialized along a control flow path from a BID to the drop program point today. + // In other words, this is where the drop of `place` will happen in the future instead. + if let MaybeReachable::Reachable(maybe_init) = self.maybe_init.get() + && maybe_init.contains(idx) + { + // We also cache the drop information, so that we do not need to check on data-flow cursor again + self.block_drop_value_info[block] = MovePathIndexAtBlock::Some(idx); + dropped_local_here.borrow_mut().insert(idx); + } else { + self.block_drop_value_info[block] = MovePathIndexAtBlock::None; + } + } + } + MovePathIndexAtBlock::None => {} + } + + for succ in terminator.successors() { + let target = &self.body.basic_blocks[succ]; + if target.is_cleanup { + continue; + } + + // As long as we are passing through a new block, or new dropped places to propagate, + // we will proceed with `succ` + let dropped_local_there = match self.visited.entry(succ) { + hash_map::Entry::Occupied(occupied_entry) => { + if succ == block + || !occupied_entry.get().borrow_mut().union(&*dropped_local_here.borrow()) + { + // `succ` has been visited but no new drops observed so far, + // so we can bail on `succ` until new drop information arrives + continue; + } + Rc::clone(occupied_entry.get()) + } + hash_map::Entry::Vacant(vacant_entry) => Rc::clone( + vacant_entry.insert(Rc::new(RefCell::new(dropped_local_here.borrow().clone()))), + ), + }; + if let Some(terminator) = &target.terminator + && let TerminatorKind::Drop { + place: dropped_place, + target: _, + unwind: _, + replace: _, + } = &terminator.kind + && place_has_common_prefix(dropped_place, self.place) + { + // We have now reached the current drop of the `place`. + // Let's check the observed dropped places in. + self.collected_drops.union(&*dropped_local_there.borrow()); + if self.drop_span.is_none() { + // FIXME(@dingxiangfei2009): it turns out that `self.body.source_scopes` are still a bit wonky. + // There is a high chance that this span still points to a block rather than a statement semicolon. + *self.drop_span = Some(terminator.source_info.span); + } + // Now we have discovered a simple control flow path from a future drop point + // to the current drop point. + // We will not continue from there. + } else { + self.visit(succ) + } + } + } +} + +/// An additional filter to exclude well-known types from the ecosystem +/// because their drops are trivial. +/// This returns additional types to check if the drops are delegated to those. +/// A typical example is `hashbrown::HashMap<K, V>`, whose drop is delegated to `K` and `V`. +fn true_significant_drop_ty<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Option<SmallVec<[Ty<'tcx>; 2]>> { + if let ty::Adt(def, args) = ty.kind() { + let mut did = def.did(); + let mut name_rev = vec![]; + loop { + let key = tcx.def_key(did); + + match key.disambiguated_data.data { + rustc_hir::definitions::DefPathData::CrateRoot => { + name_rev.push(tcx.crate_name(did.krate)) + } + rustc_hir::definitions::DefPathData::TypeNs(symbol) => name_rev.push(symbol), + _ => return None, + } + if let Some(parent) = key.parent { + did = DefId { krate: did.krate, index: parent }; + } else { + break; + } + } + let name_str: Vec<_> = name_rev.iter().rev().map(|x| x.as_str()).collect(); + debug!(?name_str); + match name_str[..] { + // These are the types from Rust core ecosystem + ["sym" | "proc_macro2", ..] + | ["core" | "std", "task", "LocalWaker" | "Waker"] + | ["core" | "std", "task", "wake", "LocalWaker" | "Waker"] => Some(smallvec![]), + // These are important types from Rust ecosystem + ["tracing", "instrument", "Instrumented"] | ["bytes", "Bytes"] => Some(smallvec![]), + ["hashbrown", "raw", "RawTable" | "RawIntoIter"] => { + if let [ty, ..] = &***args + && let Some(ty) = ty.as_type() + { + Some(smallvec![ty]) + } else { + None + } + } + ["hashbrown", "raw", "RawDrain"] => { + if let [_, ty, ..] = &***args + && let Some(ty) = ty.as_type() + { + Some(smallvec![ty]) + } else { + None + } + } + _ => None, + } + } else { + None + } +} + +/// Returns the list of types with a "potentially sigificant" that may be dropped +/// by dropping a value of type `ty`. +#[instrument(level = "debug", skip(tcx, param_env))] +fn extract_component_raw<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + ty_seen: &mut UnordSet<Ty<'tcx>>, +) -> SmallVec<[Ty<'tcx>; 4]> { + // Droppiness does not depend on regions, so let us erase them. + let ty = tcx + .try_normalize_erasing_regions( + ty::TypingEnv { param_env, typing_mode: ty::TypingMode::PostAnalysis }, + ty, + ) + .unwrap_or(ty); + + let tys = tcx.list_significant_drop_tys(param_env.and(ty)); + debug!(?ty, "components"); + let mut out_tys = smallvec![]; + for ty in tys { + if let Some(tys) = true_significant_drop_ty(tcx, ty) { + // Some types can be further opened up because the drop is simply delegated + for ty in tys { + if ty_seen.insert(ty) { + out_tys.extend(extract_component_raw(tcx, param_env, ty, ty_seen)); + } + } + } else { + if ty_seen.insert(ty) { + out_tys.push(ty); + } + } + } + out_tys +} + +#[instrument(level = "debug", skip(tcx, param_env))] +fn extract_component_with_significant_dtor<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> SmallVec<[Ty<'tcx>; 4]> { + let mut tys = extract_component_raw(tcx, param_env, ty, &mut Default::default()); + let mut deduplicate = FxHashSet::default(); + tys.retain(|oty| deduplicate.insert(*oty)); + tys.into_iter().collect() +} + +/// Extract the span of the custom destructor of a type +/// especially the span of the `impl Drop` header or its entire block +/// when we are working with current local crate. +#[instrument(level = "debug", skip(tcx))] +fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> { + match ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Error(_) + | ty::Str + | ty::Never + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::FnPtr(_, _) + | ty::Tuple(_) + | ty::Dynamic(_, _, _) + | ty::Alias(_, _) + | ty::Bound(_, _) + | ty::Pat(_, _) + | ty::Placeholder(_) + | ty::Infer(_) + | ty::Slice(_) + | ty::Array(_, _) => None, + ty::Adt(adt_def, _) => { + let did = adt_def.did(); + let try_local_did_span = |did: DefId| { + if let Some(local) = did.as_local() { + tcx.source_span(local) + } else { + tcx.def_span(did) + } + }; + let dtor = if let Some(dtor) = tcx.adt_destructor(did) { + dtor.did + } else if let Some(dtor) = tcx.adt_async_destructor(did) { + dtor.future + } else { + return Some(try_local_did_span(did)); + }; + let def_key = tcx.def_key(dtor); + let Some(parent_index) = def_key.parent else { return Some(try_local_did_span(dtor)) }; + let parent_did = DefId { index: parent_index, krate: dtor.krate }; + Some(try_local_did_span(parent_did)) + } + ty::Coroutine(did, _) + | ty::CoroutineWitness(did, _) + | ty::CoroutineClosure(did, _) + | ty::Closure(did, _) + | ty::FnDef(did, _) + | ty::Foreign(did) => Some(tcx.def_span(did)), + ty::Param(_) => None, + } +} + +/// Check if a moved place at `idx` is a part of a BID. +/// The use of this check is that we will consider drops on these +/// as a drop of the overall BID and, thus, we can exclude it from the diagnosis. +fn place_descendent_of_bids<'tcx>( + mut idx: MovePathIndex, + move_data: &MoveData<'tcx>, + bids: &UnordSet<&Place<'tcx>>, +) -> bool { + loop { + let path = &move_data.move_paths[idx]; + if bids.contains(&path.place) { + return true; + } + if let Some(parent) = path.parent { + idx = parent; + } else { + return false; + } + } +} + +/// The core of the lint `tail-expr-drop-order` +pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<'tcx>) { + if matches!(tcx.def_kind(def_id), rustc_hir::def::DefKind::SyntheticCoroutineBody) { + // A synthetic coroutine has no HIR body and it is enough to just analyse the original body + return; + } + if body.span.edition().at_least_rust_2024() + || tcx.lints_that_dont_need_to_run(()).contains(&lint::LintId::of(TAIL_EXPR_DROP_ORDER)) + { + return; + } + // ## About BIDs in blocks ## + // Track the set of blocks that contain a backwards-incompatible drop (BID) + // and, for each block, the vector of locations. + // + // We group them per-block because they tend to scheduled in the same drop ladder block. + let mut bid_per_block = IndexMap::default(); + let mut bid_places = UnordSet::new(); + let param_env = tcx.param_env(def_id).with_reveal_all_normalized(tcx); + let mut ty_dropped_components = UnordMap::default(); + for (block, data) in body.basic_blocks.iter_enumerated() { + for (statement_index, stmt) in data.statements.iter().enumerate() { + if let StatementKind::BackwardIncompatibleDropHint { place, reason: _ } = &stmt.kind { + let ty = place.ty(body, tcx).ty; + if ty_dropped_components + .entry(ty) + .or_insert_with(|| extract_component_with_significant_dtor(tcx, param_env, ty)) + .is_empty() + { + continue; + } + bid_per_block + .entry(block) + .or_insert(vec![]) + .push((Location { block, statement_index }, &**place)); + bid_places.insert(&**place); + } + } + } + if bid_per_block.is_empty() { + return; + } + + dump_mir(tcx, false, "lint_tail_expr_drop_order", &0 as _, body, |_, _| Ok(())); + let locals_with_user_names = collect_user_names(body); + let is_closure_like = tcx.is_closure_like(def_id.to_def_id()); + + // Compute the "maybe initialized" information for this body. + // When we encounter a DROP of some place P we only care + // about the drop if `P` may be initialized. + let move_data = MoveData::gather_moves(body, tcx, |_| true); + let maybe_init = MaybeInitializedPlaces::new(tcx, body, &move_data); + let mut maybe_init = maybe_init.iterate_to_fixpoint(tcx, body, None).into_results_cursor(body); + let mut block_drop_value_info = + IndexVec::from_elem_n(MovePathIndexAtBlock::Unknown, body.basic_blocks.len()); + for (&block, candidates) in &bid_per_block { + // We will collect drops on locals on paths between BID points to their actual drop locations + // into `all_locals_dropped`. + let mut all_locals_dropped = ChunkedBitSet::new_empty(move_data.move_paths.len()); + let mut drop_span = None; + for &(_, place) in candidates.iter() { + let mut collected_drops = ChunkedBitSet::new_empty(move_data.move_paths.len()); + // ## On detecting change in relative drop order ## + // Iterate through each BID-containing block `block`. + // If the place `P` targeted by the BID is "maybe initialized", + // then search forward to find the actual `DROP(P)` point. + // Everything dropped between the BID and the actual drop point + // is something whose relative drop order will change. + DropsReachable { + body, + place, + drop_span: &mut drop_span, + move_data: &move_data, + maybe_init: &mut maybe_init, + block_drop_value_info: &mut block_drop_value_info, + collected_drops: &mut collected_drops, + visited: Default::default(), + } + .visit(block); + // Compute the set `all_locals_dropped` of local variables that are dropped + // after the BID point but before the current drop point. + // + // These are the variables whose drop impls will be reordered with respect + // to `place`. + all_locals_dropped.union(&collected_drops); + } + + // We shall now exclude some local bindings for the following cases. + { + let mut to_exclude = ChunkedBitSet::new_empty(all_locals_dropped.domain_size()); + // We will now do subtraction from the candidate dropped locals, because of the following reasons. + for path_idx in all_locals_dropped.iter() { + let move_path = &move_data.move_paths[path_idx]; + let dropped_local = move_path.place.local; + // a) A return value _0 will eventually be used + // Example: + // fn f() -> Droppy { + // let _x = Droppy; + // Droppy + // } + // _0 holds the literal `Droppy` and rightfully `_x` has to be dropped first + if dropped_local == Local::ZERO { + debug!(?dropped_local, "skip return value"); + to_exclude.insert(path_idx); + continue; + } + // b) If we are analysing a closure, the captures are still dropped last. + // This is part of the closure capture lifetime contract. + // They are similar to the return value _0 with respect to lifetime rules. + if is_closure_like && matches!(dropped_local, ty::CAPTURE_STRUCT_LOCAL) { + debug!(?dropped_local, "skip closure captures"); + to_exclude.insert(path_idx); + continue; + } + // c) Sometimes we collect places that are projections into the BID locals, + // so they are considered dropped now. + // Example: + // struct NotVeryDroppy(Droppy); + // impl Drop for Droppy {..} + // fn f() -> NotVeryDroppy { + // let x = NotVeryDroppy(droppy()); + // { + // let y: Droppy = x.0; + // NotVeryDroppy(y) + // } + // } + // `y` takes `x.0`, which invalidates `x` as a complete `NotVeryDroppy` + // so there is no point in linting against `x` any more. + if place_descendent_of_bids(path_idx, &move_data, &bid_places) { + debug!(?dropped_local, "skip descendent of bids"); + to_exclude.insert(path_idx); + continue; + } + let observer_ty = move_path.place.ty(body, tcx).ty; + // d) The collected local has no custom destructor that passes our ecosystem filter. + if ty_dropped_components + .entry(observer_ty) + .or_insert_with(|| { + extract_component_with_significant_dtor(tcx, param_env, observer_ty) + }) + .is_empty() + { + debug!(?dropped_local, "skip non-droppy types"); + to_exclude.insert(path_idx); + continue; + } + } + // Suppose that all BIDs point into the same local, + // we can remove the this local from the observed drops, + // so that we can focus our diagnosis more on the others. + if candidates.iter().all(|&(_, place)| candidates[0].1.local == place.local) { + for path_idx in all_locals_dropped.iter() { + if move_data.move_paths[path_idx].place.local == candidates[0].1.local { + to_exclude.insert(path_idx); + } + } + } + all_locals_dropped.subtract(&to_exclude); + } + if all_locals_dropped.is_empty() { + // No drop effect is observable, so let us move on. + continue; + } + + // ## The final work to assemble the diagnosis ## + // First collect or generate fresh names for local variable bindings and temporary values. + let local_names = assign_observables_names( + all_locals_dropped + .iter() + .map(|path_idx| move_data.move_paths[path_idx].place.local) + .chain(candidates.iter().map(|(_, place)| place.local)), + &locals_with_user_names, + ); + + let mut lint_root = None; + let mut local_labels = vec![]; + // We now collect the types with custom destructors. + for &(_, place) in candidates { + let linted_local_decl = &body.local_decls[place.local]; + let Some(&(ref name, is_generated_name)) = local_names.get(&place.local) else { + bug!("a name should have been assigned") + }; + let name = name.as_str(); + + if lint_root.is_none() + && let ClearCrossCrate::Set(data) = + &body.source_scopes[linted_local_decl.source_info.scope].local_data + { + lint_root = Some(data.lint_root); + } + + // Collect spans of the custom destructors. + let mut seen_dyn = false; + let destructors = ty_dropped_components + .get(&linted_local_decl.ty) + .unwrap() + .iter() + .filter_map(|&ty| { + if let Some(span) = ty_dtor_span(tcx, ty) { + Some(DestructorLabel { span, name, dtor_kind: "concrete" }) + } else if matches!(ty.kind(), ty::Dynamic(..)) { + if seen_dyn { + None + } else { + seen_dyn = true; + Some(DestructorLabel { span: DUMMY_SP, name, dtor_kind: "dyn" }) + } + } else { + None + } + }) + .collect(); + local_labels.push(LocalLabel { + span: linted_local_decl.source_info.span, + destructors, + name, + is_generated_name, + is_dropped_first_edition_2024: true, + }); + } + + // Similarly, custom destructors of the observed drops. + for path_idx in all_locals_dropped.iter() { + let place = &move_data.move_paths[path_idx].place; + // We are not using the type of the local because the drop may be partial. + let observer_ty = place.ty(body, tcx).ty; + + let observer_local_decl = &body.local_decls[place.local]; + let Some(&(ref name, is_generated_name)) = local_names.get(&place.local) else { + bug!("a name should have been assigned") + }; + let name = name.as_str(); + + let mut seen_dyn = false; + let destructors = extract_component_with_significant_dtor(tcx, param_env, observer_ty) + .into_iter() + .filter_map(|ty| { + if let Some(span) = ty_dtor_span(tcx, ty) { + Some(DestructorLabel { span, name, dtor_kind: "concrete" }) + } else if matches!(ty.kind(), ty::Dynamic(..)) { + if seen_dyn { + None + } else { + seen_dyn = true; + Some(DestructorLabel { span: DUMMY_SP, name, dtor_kind: "dyn" }) + } + } else { + None + } + }) + .collect(); + local_labels.push(LocalLabel { + span: observer_local_decl.source_info.span, + destructors, + name, + is_generated_name, + is_dropped_first_edition_2024: false, + }); + } + + let span = local_labels[0].span; + tcx.emit_node_span_lint( + lint::builtin::TAIL_EXPR_DROP_ORDER, + lint_root.unwrap_or(CRATE_HIR_ID), + span, + TailExprDropOrderLint { local_labels, drop_span, _epilogue: () }, + ); + } +} + +/// Extract binding names if available for diagnosis +fn collect_user_names(body: &Body<'_>) -> IndexMap<Local, Symbol> { + let mut names = IndexMap::default(); + for var_debug_info in &body.var_debug_info { + if let mir::VarDebugInfoContents::Place(place) = &var_debug_info.value + && let Some(local) = place.local_or_deref_local() + { + names.entry(local).or_insert(var_debug_info.name); + } + } + names +} + +/// Assign names for anonymous or temporary values for diagnosis +fn assign_observables_names( + locals: impl IntoIterator<Item = Local>, + user_names: &IndexMap<Local, Symbol>, +) -> IndexMap<Local, (String, bool)> { + let mut names = IndexMap::default(); + let mut assigned_names = FxHashSet::default(); + let mut idx = 0u64; + let mut fresh_name = || { + idx += 1; + (format!("#{idx}"), true) + }; + for local in locals { + let name = if let Some(name) = user_names.get(&local) { + let name = name.as_str(); + if assigned_names.contains(name) { fresh_name() } else { (name.to_owned(), false) } + } else { + fresh_name() + }; + assigned_names.insert(name.0.clone()); + names.insert(local, name); + } + names +} + +#[derive(LintDiagnostic)] +#[diag(mir_transform_tail_expr_drop_order)] +struct TailExprDropOrderLint<'a> { + #[subdiagnostic] + local_labels: Vec<LocalLabel<'a>>, + #[label(mir_transform_drop_location)] + drop_span: Option<Span>, + #[note(mir_transform_note_epilogue)] + _epilogue: (), +} + +struct LocalLabel<'a> { + span: Span, + name: &'a str, + is_generated_name: bool, + is_dropped_first_edition_2024: bool, + destructors: Vec<DestructorLabel<'a>>, +} + +/// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order +impl Subdiagnostic for LocalLabel<'_> { + fn add_to_diag_with< + G: rustc_errors::EmissionGuarantee, + F: rustc_errors::SubdiagMessageOp<G>, + >( + self, + diag: &mut rustc_errors::Diag<'_, G>, + f: &F, + ) { + diag.arg("name", self.name); + diag.arg("is_generated_name", self.is_generated_name); + diag.arg("is_dropped_first_edition_2024", self.is_dropped_first_edition_2024); + let msg = f(diag, crate::fluent_generated::mir_transform_tail_expr_local.into()); + diag.span_label(self.span, msg); + for dtor in self.destructors { + dtor.add_to_diag_with(diag, f); + } + let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue.into()); + diag.span_label(self.span, msg); + } +} + +#[derive(Subdiagnostic)] +#[note(mir_transform_tail_expr_dtor)] +struct DestructorLabel<'a> { + #[primary_span] + span: Span, + dtor_kind: &'static str, + name: &'a str, +} diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 237227f5294..ff027680c49 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -5,7 +5,7 @@ use rustc_index::IndexSlice; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; -use rustc_middle::ty::{ParamEnv, ScalarInt, Ty, TyCtxt}; +use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_type_ir::TyKind::*; use super::simplify::simplify_cfg; @@ -19,8 +19,7 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let def_id = body.source.def_id(); - let param_env = tcx.param_env_reveal_all_normalized(def_id); - + let typing_env = body.typing_env(tcx); let mut should_cleanup = false; for i in 0..body.basic_blocks.len() { let bbs = &*body.basic_blocks; @@ -40,11 +39,11 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification { _ => continue, }; - if SimplifyToIf.simplify(tcx, body, bb_idx, param_env).is_some() { + if SimplifyToIf.simplify(tcx, body, bb_idx, typing_env).is_some() { should_cleanup = true; continue; } - if SimplifyToExp::default().simplify(tcx, body, bb_idx, param_env).is_some() { + if SimplifyToExp::default().simplify(tcx, body, bb_idx, typing_env).is_some() { should_cleanup = true; continue; } @@ -65,7 +64,7 @@ trait SimplifyMatch<'tcx> { tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, switch_bb_idx: BasicBlock, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> Option<()> { let bbs = &body.basic_blocks; let (discr, targets) = match bbs[switch_bb_idx].terminator().kind { @@ -74,7 +73,7 @@ trait SimplifyMatch<'tcx> { }; let discr_ty = discr.ty(body.local_decls(), tcx); - self.can_simplify(tcx, targets, param_env, bbs, discr_ty)?; + self.can_simplify(tcx, targets, typing_env, bbs, discr_ty)?; let mut patch = MirPatch::new(body); @@ -90,7 +89,16 @@ trait SimplifyMatch<'tcx> { let parent_end = Location { block: switch_bb_idx, statement_index }; patch.add_statement(parent_end, StatementKind::StorageLive(discr_local)); patch.add_assign(parent_end, Place::from(discr_local), Rvalue::Use(discr)); - self.new_stmts(tcx, targets, param_env, &mut patch, parent_end, bbs, discr_local, discr_ty); + self.new_stmts( + tcx, + targets, + typing_env, + &mut patch, + parent_end, + bbs, + discr_local, + discr_ty, + ); patch.add_statement(parent_end, StatementKind::StorageDead(discr_local)); patch.patch_terminator(switch_bb_idx, bbs[first].terminator().kind.clone()); patch.apply(body); @@ -104,7 +112,7 @@ trait SimplifyMatch<'tcx> { &mut self, tcx: TyCtxt<'tcx>, targets: &SwitchTargets, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, discr_ty: Ty<'tcx>, ) -> Option<()>; @@ -113,7 +121,7 @@ trait SimplifyMatch<'tcx> { &self, tcx: TyCtxt<'tcx>, targets: &SwitchTargets, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, patch: &mut MirPatch<'tcx>, parent_end: Location, bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, @@ -160,7 +168,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf { &mut self, tcx: TyCtxt<'tcx>, targets: &SwitchTargets, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, _discr_ty: Ty<'tcx>, ) -> Option<()> { @@ -197,8 +205,8 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf { ) if lhs_f == lhs_s && f_c.const_.ty().is_bool() && s_c.const_.ty().is_bool() - && f_c.const_.try_eval_bool(tcx, param_env).is_some() - && s_c.const_.try_eval_bool(tcx, param_env).is_some() => {} + && f_c.const_.try_eval_bool(tcx, typing_env).is_some() + && s_c.const_.try_eval_bool(tcx, typing_env).is_some() => {} // Otherwise we cannot optimize. Try another block. _ => return None, @@ -211,7 +219,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf { &self, tcx: TyCtxt<'tcx>, targets: &SwitchTargets, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, patch: &mut MirPatch<'tcx>, parent_end: Location, bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, @@ -235,15 +243,15 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf { StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))), ) => { // From earlier loop we know that we are dealing with bool constants only: - let f_b = f_c.const_.try_eval_bool(tcx, param_env).unwrap(); - let s_b = s_c.const_.try_eval_bool(tcx, param_env).unwrap(); + let f_b = f_c.const_.try_eval_bool(tcx, typing_env).unwrap(); + let s_b = s_c.const_.try_eval_bool(tcx, typing_env).unwrap(); if f_b == s_b { // Same value in both blocks. Use statement as is. patch.add_statement(parent_end, f.kind.clone()); } else { // Different value between blocks. Make value conditional on switch // condition. - let size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size; + let size = tcx.layout_of(typing_env.as_query_input(discr_ty)).unwrap().size; let const_cmp = Operand::const_from_scalar( tcx, discr_ty, @@ -363,7 +371,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { &mut self, tcx: TyCtxt<'tcx>, targets: &SwitchTargets, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, discr_ty: Ty<'tcx>, ) -> Option<()> { @@ -388,7 +396,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { return None; } - let discr_layout = tcx.layout_of(param_env.and(discr_ty)).unwrap(); + let discr_layout = tcx.layout_of(typing_env.as_query_input(discr_ty)).unwrap(); let first_stmts = &bbs[first_target].statements; let (second_case_val, second_target) = target_iter.next().unwrap(); let second_stmts = &bbs[second_target].statements; @@ -414,8 +422,8 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { && f_c.const_.ty().is_integral() => { match ( - f_c.const_.try_eval_scalar_int(tcx, param_env), - s_c.const_.try_eval_scalar_int(tcx, param_env), + f_c.const_.try_eval_scalar_int(tcx, typing_env), + s_c.const_.try_eval_scalar_int(tcx, typing_env), ) { (Some(f), Some(s)) if f == s => ExpectedTransformKind::SameByEq { place: lhs_f, @@ -467,11 +475,11 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), ) if lhs_f == lhs_s && s_c.const_.ty() == f_ty - && s_c.const_.try_eval_scalar_int(tcx, param_env) == Some(scalar) => {} + && s_c.const_.try_eval_scalar_int(tcx, typing_env) == Some(scalar) => {} ( ExpectedTransformKind::Cast { place: lhs_f, ty: f_ty }, StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), - ) if let Some(f) = s_c.const_.try_eval_scalar_int(tcx, param_env) + ) if let Some(f) = s_c.const_.try_eval_scalar_int(tcx, typing_env) && lhs_f == lhs_s && s_c.const_.ty() == f_ty && can_cast(tcx, other_val, discr_layout, f_ty, f) => {} @@ -487,7 +495,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { &self, _tcx: TyCtxt<'tcx>, targets: &SwitchTargets, - _param_env: ParamEnv<'tcx>, + _typing_env: ty::TypingEnv<'tcx>, patch: &mut MirPatch<'tcx>, parent_end: Location, bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index fa9a6bfcf7c..6be95b1f0f1 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -325,7 +325,7 @@ impl<'tcx> Validator<'_, 'tcx> { if let TempState::Defined { location: loc, .. } = self.temps[local] && let Left(statement) = self.body.stmt_at(loc) && let Some((_, Rvalue::Use(Operand::Constant(c)))) = statement.kind.as_assign() - && let Some(idx) = c.const_.try_eval_target_usize(self.tcx, self.param_env) + && let Some(idx) = c.const_.try_eval_target_usize(self.tcx, self.typing_env) // Determine the type of the thing we are indexing. && let ty::Array(_, len) = place_base.ty(self.body, self.tcx).ty.kind() // It's an array; determine its length. @@ -490,7 +490,7 @@ impl<'tcx> Validator<'_, 'tcx> { // Integer division: the RHS must be a non-zero const. let rhs_val = match rhs { Operand::Constant(c) => { - c.const_.try_eval_scalar_int(self.tcx, self.param_env) + c.const_.try_eval_scalar_int(self.tcx, self.typing_env) } _ => None, }; @@ -509,7 +509,7 @@ impl<'tcx> Validator<'_, 'tcx> { let lhs_val = match lhs { Operand::Constant(c) => c .const_ - .try_eval_scalar_int(self.tcx, self.param_env), + .try_eval_scalar_int(self.tcx, self.typing_env), _ => None, }; let lhs_min = sz.signed_int_min(); diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index b11b503e8d4..af438ac2177 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -85,8 +85,8 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation { } fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - let ssa = SsaLocals::new(tcx, body, param_env); + let typing_env = body.typing_env(tcx); + let ssa = SsaLocals::new(tcx, body, typing_env); let mut replacer = compute_replacement(tcx, body, &ssa); debug!(?replacer.targets); diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 55394e93a5c..fd49e956f43 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -92,6 +92,7 @@ impl RemoveNoopLandingPads { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => { // These are all noops in a landing pad } diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs index 20c34a7469e..f786c676e9e 100644 --- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs @@ -1,7 +1,7 @@ use rustc_abi::FieldIdx; use rustc_index::bit_set::ChunkedBitSet; use rustc_middle::mir::{Body, TerminatorKind}; -use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, VariantDef}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, VariantDef}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; use rustc_mir_dataflow::{Analysis, MaybeReachable, move_path_children_matching}; @@ -18,8 +18,8 @@ pub(super) struct RemoveUninitDrops; impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let param_env = tcx.param_env(body.source.def_id()); - let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, param_env)); + let typing_env = body.typing_env(tcx); + let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, typing_env)); let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) .iterate_to_fixpoint(tcx, body, Some("remove_uninit_drops")) @@ -40,7 +40,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops { let should_keep = is_needs_drop_and_init( tcx, - param_env, + typing_env, maybe_inits, &move_data, place.ty(body, tcx).ty, @@ -66,24 +66,24 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops { fn is_needs_drop_and_init<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, maybe_inits: &ChunkedBitSet<MovePathIndex>, move_data: &MoveData<'tcx>, ty: Ty<'tcx>, mpi: MovePathIndex, ) -> bool { // No need to look deeper if the root is definitely uninit or if it has no `Drop` impl. - if !maybe_inits.contains(mpi) || !ty.needs_drop(tcx, param_env) { + if !maybe_inits.contains(mpi) || !ty.needs_drop(tcx, typing_env) { return false; } let field_needs_drop_and_init = |(f, f_ty, mpi)| { let child = move_path_children_matching(move_data, mpi, |x| x.is_field_to(f)); let Some(mpi) = child else { - return Ty::needs_drop(f_ty, tcx, param_env); + return Ty::needs_drop(f_ty, tcx, typing_env); }; - is_needs_drop_and_init(tcx, param_env, maybe_inits, move_data, f_ty, mpi) + is_needs_drop_and_init(tcx, typing_env, maybe_inits, move_data, f_ty, mpi) }; // This pass is only needed for const-checking, so it doesn't handle as many cases as @@ -110,7 +110,7 @@ fn is_needs_drop_and_init<'tcx>( let downcast = move_path_children_matching(move_data, mpi, |x| x.is_downcast_to(vid)); let Some(dc_mpi) = downcast else { - return variant_needs_drop(tcx, param_env, args, variant); + return variant_needs_drop(tcx, typing_env, args, variant); }; dc_mpi @@ -139,12 +139,12 @@ fn is_needs_drop_and_init<'tcx>( fn variant_needs_drop<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, args: GenericArgsRef<'tcx>, variant: &VariantDef, ) -> bool { variant.fields.iter().any(|field| { let f_ty = field.ty(tcx, args); - f_ty.needs_drop(tcx, param_env) + f_ty.needs_drop(tcx, typing_env) }) } diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs index 28925ba1beb..ad62b47a66d 100644 --- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs @@ -16,18 +16,18 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("Running RemoveUnneededDrops on {:?}", body.source); - let did = body.source.def_id(); - let param_env = tcx.param_env_reveal_all_normalized(did); + let typing_env = body.typing_env(tcx); let mut should_simplify = false; - for block in body.basic_blocks.as_mut() { let terminator = block.terminator_mut(); if let TerminatorKind::Drop { place, target, .. } = terminator.kind { let ty = place.ty(&body.local_decls, tcx); - if ty.ty.needs_drop(tcx, param_env) { + if ty.ty.needs_drop(tcx, typing_env) { continue; } - if !tcx.consider_optimizing(|| format!("RemoveUnneededDrops {did:?} ")) { + if !tcx.consider_optimizing(|| { + format!("RemoveUnneededDrops {:?}", body.source.def_id()) + }) { continue; } debug!("SUCCESS: replacing `drop` with goto({:?})", target); diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index f13bb1c5993..6fd70fbe9b0 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -21,9 +21,9 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveZsts { return; } - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let typing_env = body.typing_env(tcx); let local_decls = &body.local_decls; - let mut replacer = Replacer { tcx, param_env, local_decls }; + let mut replacer = Replacer { tcx, typing_env, local_decls }; for var_debug_info in &mut body.var_debug_info { replacer.visit_var_debug_info(var_debug_info); } @@ -35,7 +35,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveZsts { struct Replacer<'a, 'tcx> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, local_decls: &'a LocalDecls<'tcx>, } @@ -61,7 +61,7 @@ impl<'tcx> Replacer<'_, 'tcx> { if !maybe_zst(ty) { return false; } - let Ok(layout) = self.tcx.layout_of(self.param_env.and(ty)) else { + let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(ty)) else { return false; }; layout.is_zst() @@ -125,6 +125,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { StatementKind::Coverage(_) | StatementKind::Intrinsic(_) | StatementKind::Nop + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::ConstEvalCounter => None, }; if let Some(place_for_ty) = place_for_ty diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs index f3b2f78b31c..587032ee720 100644 --- a/compiler/rustc_mir_transform/src/reveal_all.rs +++ b/compiler/rustc_mir_transform/src/reveal_all.rs @@ -8,14 +8,16 @@ pub(super) struct RevealAll; impl<'tcx> crate::MirPass<'tcx> for RevealAll { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - RevealAllVisitor { tcx, param_env }.visit_body_preserves_cfg(body); + // FIXME(#132279): This is used during the phase transition from analysis + // to runtime, so we have to manually specify the correct typing mode. + let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id()); + RevealAllVisitor { tcx, typing_env }.visit_body_preserves_cfg(body); } } struct RevealAllVisitor<'tcx> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, } impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> { @@ -53,7 +55,7 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> { // We have to use `try_normalize_erasing_regions` here, since it's // possible that we visit impossible-to-satisfy where clauses here, // see #91745 - if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.const_) { + if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.typing_env, constant.const_) { constant.const_ = c; } self.super_const_operand(constant, location); @@ -64,7 +66,7 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> { // We have to use `try_normalize_erasing_regions` here, since it's // possible that we visit impossible-to-satisfy where clauses here, // see #91745 - if let Ok(t) = self.tcx.try_normalize_erasing_regions(self.param_env, *ty) { + if let Ok(t) = self.tcx.try_normalize_erasing_regions(self.typing_env, *ty) { *ty = t; } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index ffa11f5b213..f16cde7cd4e 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -274,9 +274,9 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) if ty.is_some() { let patch = { - let param_env = tcx.param_env_reveal_all_normalized(def_id); + let typing_env = ty::TypingEnv::post_analysis(tcx, def_id); let mut elaborator = - DropShimElaborator { body: &body, patch: MirPatch::new(&body), tcx, param_env }; + DropShimElaborator { body: &body, patch: MirPatch::new(&body), tcx, typing_env }; let dropee = tcx.mk_place_deref(dropee_ptr); let resume_block = elaborator.patch.resume_block(); elaborate_drops::elaborate_drop( @@ -334,7 +334,7 @@ pub(super) struct DropShimElaborator<'a, 'tcx> { pub body: &'a Body<'tcx>, pub patch: MirPatch<'tcx>, pub tcx: TyCtxt<'tcx>, - pub param_env: ty::ParamEnv<'tcx>, + pub typing_env: ty::TypingEnv<'tcx>, } impl fmt::Debug for DropShimElaborator<'_, '_> { @@ -355,8 +355,8 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + self.typing_env } fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle { @@ -914,7 +914,7 @@ fn build_call_shim<'tcx>( pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { debug_assert!(tcx.is_constructor(ctor_id)); - let param_env = tcx.param_env_reveal_all_normalized(ctor_id); + let typing_env = ty::TypingEnv::post_analysis(tcx, ctor_id); // Normalize the sig. let sig = tcx @@ -922,7 +922,7 @@ pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { .instantiate_identity() .no_bound_vars() .expect("LBR in ADT constructor signature"); - let sig = tcx.normalize_erasing_regions(param_env, sig); + let sig = tcx.normalize_erasing_regions(typing_env, sig); let ty::Adt(adt_def, args) = sig.output().kind() else { bug!("unexpected type for ADT ctor {:?}", sig.output()); diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index f1672272862..139b25be0ab 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -48,7 +48,7 @@ struct AsyncDestructorCtorShimBuilder<'tcx> { self_ty: Option<Ty<'tcx>>, span: Span, source_info: SourceInfo, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, stack: Vec<Operand<'tcx>>, last_bb: BasicBlock, @@ -86,14 +86,14 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> { // Usual case: noop() + unwind resume + return let mut bbs = IndexVec::with_capacity(3); - let param_env = tcx.param_env_reveal_all_normalized(def_id); + let typing_env = ty::TypingEnv::post_analysis(tcx, def_id); AsyncDestructorCtorShimBuilder { tcx, def_id, self_ty, span, source_info, - param_env, + typing_env, stack: Vec::with_capacity(Self::MAX_STACK_LEN), last_bb: bbs.push(BasicBlockData::new(None)), @@ -422,7 +422,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> { statements: Vec::new(), terminator: Some(Terminator { source_info, - kind: if self.locals[local].ty.needs_drop(self.tcx, self.param_env) { + kind: if self.locals[local].ty.needs_drop(self.tcx, self.typing_env) { TerminatorKind::Drop { place: local.into(), target: *top_cleanup_bb, diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 7ed43547e11..4f312ed2aaa 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -523,7 +523,8 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { } StatementKind::SetDiscriminant { ref place, variant_index: _ } - | StatementKind::Deinit(ref place) => { + | StatementKind::Deinit(ref place) + | StatementKind::BackwardIncompatibleDropHint { ref place, reason: _ } => { self.visit_lhs(place, location); } } @@ -560,6 +561,7 @@ fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Bod StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local), StatementKind::SetDiscriminant { ref place, .. } + | StatementKind::BackwardIncompatibleDropHint { ref place, reason: _ } | StatementKind::Deinit(ref place) => used_locals.is_used(place.local), StatementKind::Nop => false, _ => true, @@ -587,6 +589,20 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { self.tcx } + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { + if let StatementKind::BackwardIncompatibleDropHint { place, reason: _ } = + &mut statement.kind + { + self.visit_local( + &mut place.local, + PlaceContext::MutatingUse(MutatingUseContext::Store), + location, + ); + } else { + self.super_statement(statement, location); + } + } + fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { *l = self.map[*l].unwrap(); } diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index e83b4727c48..bea3d0d8557 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -18,14 +18,14 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("Running SimplifyConstCondition on {:?}", body.source); - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let typing_env = body.typing_env(tcx); 'blocks: for block in body.basic_blocks_mut() { for stmt in block.statements.iter_mut() { // Simplify `assume` of a known value: either a NOP or unreachable. if let StatementKind::Intrinsic(box ref intrinsic) = stmt.kind && let NonDivergingIntrinsic::Assume(discr) = intrinsic && let Operand::Constant(ref c) = discr - && let Some(constant) = c.const_.try_eval_bool(tcx, param_env) + && let Some(constant) = c.const_.try_eval_bool(tcx, typing_env) { if constant { stmt.make_nop(); @@ -42,7 +42,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { TerminatorKind::SwitchInt { discr: Operand::Constant(ref c), ref targets, .. } => { - let constant = c.const_.try_eval_bits(tcx, param_env); + let constant = c.const_.try_eval_bits(tcx, typing_env); if let Some(constant) = constant { let target = targets.target_for_value(constant); TerminatorKind::Goto { target } @@ -52,7 +52,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { } TerminatorKind::Assert { target, cond: Operand::Constant(ref c), expected, .. - } => match c.const_.try_eval_bool(tcx, param_env) { + } => match c.const_.try_eval_bool(tcx, typing_env) { Some(v) if v == expected => TerminatorKind::Goto { target }, _ => continue, }, diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index 26496b7f3fe..b6d80173086 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -37,7 +37,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { let opts = helper.find_optimizations(); let mut storage_deads_to_insert = vec![]; let mut storage_deads_to_remove: Vec<(usize, BasicBlock)> = vec![]; - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let typing_env = body.typing_env(tcx); for opt in opts { trace!("SUCCESS: Applying {:?}", opt); // replace terminator with a switchInt that switches on the integer directly @@ -46,7 +46,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { let new_value = match opt.branch_value_scalar { Scalar::Int(int) => { let layout = tcx - .layout_of(param_env.and(opt.branch_value_ty)) + .layout_of(typing_env.as_query_input(opt.branch_value_ty)) .expect("if we have an evaluated constant we must know the layout"); int.to_bits(layout.size) } diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index 53bbb122096..52b9ec1e0a3 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -28,12 +28,12 @@ impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates { } let mut excluded = excluded_locals(body); - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let typing_env = body.typing_env(tcx); loop { debug!(?excluded); - let escaping = escaping_locals(tcx, param_env, &excluded, body); + let escaping = escaping_locals(tcx, typing_env, &excluded, body); debug!(?escaping); - let replacements = compute_flattening(tcx, param_env, body, escaping); + let replacements = compute_flattening(tcx, typing_env, body, escaping); debug!(?replacements); let all_dead_locals = replace_flattened_locals(tcx, body, replacements); if !all_dead_locals.is_empty() { @@ -59,7 +59,7 @@ impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates { /// client code. fn escaping_locals<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, excluded: &BitSet<Local>, body: &Body<'tcx>, ) -> BitSet<Local> { @@ -84,7 +84,7 @@ fn escaping_locals<'tcx>( // niche, so we do not want to automatically exclude it. return false; } - let Ok(layout) = tcx.layout_of(param_env.and(ty)) else { + let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) else { // We can't get the layout return true; }; @@ -196,7 +196,7 @@ impl<'tcx> ReplacementMap<'tcx> { /// The replacement will be done later in `ReplacementVisitor`. fn compute_flattening<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, body: &mut Body<'tcx>, escaping: BitSet<Local>, ) -> ReplacementMap<'tcx> { @@ -208,7 +208,7 @@ fn compute_flattening<'tcx>( } let decl = body.local_decls[local].clone(); let ty = decl.ty; - iter_fields(ty, tcx, param_env, |variant, field, field_ty| { + iter_fields(ty, tcx, typing_env, |variant, field, field_ty| { if variant.is_some() { // Downcasts are currently not supported. return; diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index 84df666e34a..5653aef0aae 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -13,7 +13,7 @@ use rustc_middle::bug; use rustc_middle::middle::resolve_bound_vars::Set1; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::{ParamEnv, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use tracing::{debug, instrument, trace}; pub(super) struct SsaLocals { @@ -42,7 +42,7 @@ impl SsaLocals { pub(super) fn new<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> SsaLocals { let assignment_order = Vec::with_capacity(body.local_decls.len()); @@ -80,7 +80,7 @@ impl SsaLocals { // have already been marked as non-SSA. debug!(?visitor.borrowed_locals); for local in visitor.borrowed_locals.iter() { - if !body.local_decls[local].ty.is_freeze(tcx, param_env) { + if !body.local_decls[local].ty.is_freeze(tcx, typing_env) { visitor.assignments[local] = Set1::Many; } } diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs index 3011af4d9d7..57e255b7c32 100644 --- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs @@ -92,9 +92,7 @@ impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching { let Some(discriminant_ty) = get_switched_on_type(bb_data, tcx, body) else { continue }; - let layout = tcx.layout_of( - tcx.param_env_reveal_all_normalized(body.source.def_id()).and(discriminant_ty), - ); + let layout = tcx.layout_of(body.typing_env(tcx).as_query_input(discriminant_ty)); let mut allowed_variants = if let Ok(layout) = layout { // Find allowed variants based on uninhabited. diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index ae4e6ea6a74..1739fdcc9af 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -12,8 +12,7 @@ use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{ - self, CoroutineArgsExt, InstanceKind, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt, - Variance, + self, CoroutineArgsExt, InstanceKind, ScalarInt, Ty, TyCtxt, TypeVisitableExt, Variance, }; use rustc_middle::{bug, span_bug}; use rustc_trait_selection::traits::ObligationCtxt; @@ -47,9 +46,10 @@ impl<'tcx> crate::MirPass<'tcx> for Validator { if matches!(body.source.instance, InstanceKind::Intrinsic(..) | InstanceKind::Virtual(..)) { return; } + debug_assert_eq!(self.mir_phase, body.phase); let def_id = body.source.def_id(); - let mir_phase = self.mir_phase; - let param_env = mir_phase.param_env(tcx, def_id); + let mir_phase = body.phase; + let typing_env = body.typing_env(tcx); let can_unwind = if mir_phase <= MirPhase::Runtime(RuntimePhase::Initial) { // In this case `AbortUnwindingCalls` haven't yet been executed. true @@ -86,7 +86,7 @@ impl<'tcx> crate::MirPass<'tcx> for Validator { cfg_checker.check_cleanup_control_flow(); // Also run the TypeChecker. - for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body, body) { + for (location, msg) in validate_types(tcx, self.mir_phase, typing_env, body, body) { cfg_checker.fail(location, msg); } @@ -343,6 +343,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { | StatementKind::Intrinsic(_) | StatementKind::ConstEvalCounter | StatementKind::PlaceMention(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} } @@ -532,12 +533,12 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { pub(super) fn validate_types<'tcx>( tcx: TyCtxt<'tcx>, mir_phase: MirPhase, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, body: &Body<'tcx>, caller_body: &Body<'tcx>, ) -> Vec<(Location, String)> { let mut type_checker = - TypeChecker { body, caller_body, tcx, param_env, mir_phase, failures: Vec::new() }; + TypeChecker { body, caller_body, tcx, typing_env, mir_phase, failures: Vec::new() }; type_checker.visit_body(body); type_checker.failures } @@ -546,7 +547,7 @@ struct TypeChecker<'a, 'tcx> { body: &'a Body<'tcx>, caller_body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, mir_phase: MirPhase, failures: Vec<(Location, String)>, } @@ -582,14 +583,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Variance::Covariant }; - crate::util::relate_types( - self.tcx, - self.body.typing_mode(self.tcx), - self.param_env, - variance, - src, - dest, - ) + crate::util::relate_types(self.tcx, self.typing_env, variance, src, dest) } /// Check that the given predicate definitely holds in the param-env of this MIR body. @@ -608,12 +602,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return true; } - let infcx = self.tcx.infer_ctxt().build(self.body.typing_mode(self.tcx)); + let (infcx, param_env) = self.tcx.infer_ctxt().build_with_typing_env(self.typing_env); let ocx = ObligationCtxt::new(&infcx); ocx.register_obligation(Obligation::new( self.tcx, ObligationCause::dummy(), - self.param_env, + param_env, pred, )); ocx.select_all_or_error().is_empty() @@ -630,7 +624,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if let Operand::Copy(place) = operand { let ty = place.ty(&self.body.local_decls, self.tcx).ty; - if !ty.is_copy_modulo_regions(self.tcx, self.param_env) { + if !ty.is_copy_modulo_regions(self.tcx, self.typing_env) { self.fail(location, format!("`Operand::Copy` with non-`Copy` type {ty}")); } } @@ -802,8 +796,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ProjectionElem::Subtype(ty) => { if !util::sub_types( self.tcx, - self.body.typing_mode(self.tcx), - self.param_env, + self.typing_env, ty, place_ref.ty(&self.body.local_decls, self.tcx).ty, ) { @@ -916,7 +909,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { assert!(adt_def.is_union()); assert_eq!(idx, FIRST_VARIANT); let dest_ty = self.tcx.normalize_erasing_regions( - self.param_env, + self.typing_env, adt_def.non_enum_variant().fields[field].ty(self.tcx, args), ); if let [field] = fields.raw.as_slice() { @@ -938,7 +931,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { for (src, dest) in std::iter::zip(fields, &variant.fields) { let dest_ty = self .tcx - .normalize_erasing_regions(self.param_env, dest.ty(self.tcx, args)); + .normalize_erasing_regions(self.typing_env, dest.ty(self.tcx, args)); if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest_ty) { self.fail(location, "adt field has the wrong type"); } @@ -997,7 +990,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } // FIXME: check `Thin` instead of `Sized` - if !in_pointee.is_sized(self.tcx, self.param_env) { + if !in_pointee.is_sized(self.tcx, self.typing_env) { self.fail(location, "input pointer must be thin"); } } else { @@ -1012,7 +1005,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if !self.mir_assign_valid_types(metadata_ty, self.tcx.types.usize) { self.fail(location, "slice metadata must be usize"); } - } else if pointee_ty.is_sized(self.tcx, self.param_env) { + } else if pointee_ty.is_sized(self.tcx, self.typing_env) { if metadata_ty != self.tcx.types.unit { self.fail(location, "metadata for pointer-to-thin must be unit"); } @@ -1301,8 +1294,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if !self .tcx - .normalize_erasing_regions(self.param_env, op_ty) - .is_sized(self.tcx, self.param_env) + .normalize_erasing_regions(self.typing_env, op_ty) + .is_sized(self.tcx, self.typing_env) { self.fail( location, @@ -1311,8 +1304,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } if !self .tcx - .normalize_erasing_regions(self.param_env, *target_type) - .is_sized(self.tcx, self.param_env) + .normalize_erasing_regions(self.typing_env, *target_type) + .is_sized(self.tcx, self.typing_env) { self.fail( location, @@ -1353,7 +1346,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { return; }; - current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty); + current_ty = self.tcx.normalize_erasing_regions(self.typing_env, f_ty); } ty::Adt(adt_def, args) => { let Some(field) = adt_def.variant(variant).fields.get(field) else { @@ -1362,7 +1355,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; let f_ty = field.ty(self.tcx, args); - current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty); + current_ty = self.tcx.normalize_erasing_regions(self.typing_env, f_ty); } _ => { self.fail( @@ -1501,6 +1494,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { | StatementKind::Coverage(_) | StatementKind::ConstEvalCounter | StatementKind::PlaceMention(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 429e31b2c88..8ee9ac3df72 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -207,6 +207,7 @@ use std::path::PathBuf; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{LRef, MTLock, par_for_each_in}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; @@ -215,7 +216,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar}; -use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; +use rustc_middle::mir::mono::{CollectionMode, InstantiationMode, MonoItem}; use rustc_middle::mir::visit::Visitor as MirVisitor; use rustc_middle::mir::{self, Location, MentionedItem, traversal}; use rustc_middle::query::TyCtxtAt; @@ -243,16 +244,6 @@ pub(crate) enum MonoItemCollectionStrategy { Lazy, } -pub(crate) struct UsageMap<'tcx> { - // Maps every mono item to the mono items used by it. - used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, - - // Maps every mono item to the mono items that use it. - user_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, -} - -type MonoItems<'tcx> = Vec<Spanned<MonoItem<'tcx>>>; - /// The state that is shared across the concurrent threads that are doing collection. struct SharedState<'tcx> { /// Items that have been or are currently being recursively collected. @@ -264,22 +255,12 @@ struct SharedState<'tcx> { usage_map: MTLock<UsageMap<'tcx>>, } -/// See module-level docs on some contect for "mentioned" items. -#[derive(Copy, Clone, Debug, PartialEq)] -enum CollectionMode { - /// Collect items that are used, i.e., actually needed for codegen. - /// - /// Which items are used can depend on optimization levels, as MIR optimizations can remove - /// uses. - UsedItems, - /// Collect items that are mentioned. The goal of this mode is that it is independent of - /// optimizations: the set of "mentioned" items is computed before optimizations are run. - /// - /// The exact contents of this set are *not* a stable guarantee. (For instance, it is currently - /// computed after drop-elaboration. If we ever do some optimizations even in debug builds, we - /// might decide to run them before computing mentioned items.) The key property of this set is - /// that it is optimization-independent. - MentionedItems, +pub(crate) struct UsageMap<'tcx> { + // Maps every mono item to the mono items used by it. + used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, + + // Maps every mono item to the mono items that use it. + user_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, } impl<'tcx> UsageMap<'tcx> { @@ -287,19 +268,15 @@ impl<'tcx> UsageMap<'tcx> { UsageMap { used_map: Default::default(), user_map: Default::default() } } - fn record_used<'a>( - &mut self, - user_item: MonoItem<'tcx>, - used_items: &'a [Spanned<MonoItem<'tcx>>], - ) where + fn record_used<'a>(&mut self, user_item: MonoItem<'tcx>, used_items: &'a MonoItems<'tcx>) + where 'tcx: 'a, { - let used_items: Vec<_> = used_items.iter().map(|item| item.node).collect(); - for &used_item in used_items.iter() { + for used_item in used_items.items() { self.user_map.entry(used_item).or_default().push(user_item); } - assert!(self.used_map.insert(user_item, used_items).is_none()); + assert!(self.used_map.insert(user_item, used_items.items().collect()).is_none()); } pub(crate) fn get_user_items(&self, item: MonoItem<'tcx>) -> &[MonoItem<'tcx>] { @@ -325,6 +302,52 @@ impl<'tcx> UsageMap<'tcx> { } } +struct MonoItems<'tcx> { + // We want a set of MonoItem + Span where trying to re-insert a MonoItem with a different Span + // is ignored. Map does that, but it looks odd. + items: FxIndexMap<MonoItem<'tcx>, Span>, +} + +impl<'tcx> MonoItems<'tcx> { + fn new() -> Self { + Self { items: FxIndexMap::default() } + } + + fn is_empty(&self) -> bool { + self.items.is_empty() + } + + fn push(&mut self, item: Spanned<MonoItem<'tcx>>) { + // Insert only if the entry does not exist. A normal insert would stomp the first span that + // got inserted. + self.items.entry(item.node).or_insert(item.span); + } + + fn items(&self) -> impl Iterator<Item = MonoItem<'tcx>> + '_ { + self.items.keys().cloned() + } +} + +impl<'tcx> IntoIterator for MonoItems<'tcx> { + type Item = Spanned<MonoItem<'tcx>>; + type IntoIter = impl Iterator<Item = Spanned<MonoItem<'tcx>>>; + + fn into_iter(self) -> Self::IntoIter { + self.items.into_iter().map(|(item, span)| respan(span, item)) + } +} + +impl<'tcx> Extend<Spanned<MonoItem<'tcx>>> for MonoItems<'tcx> { + fn extend<I>(&mut self, iter: I) + where + I: IntoIterator<Item = Spanned<MonoItem<'tcx>>>, + { + for item in iter { + self.push(item) + } + } +} + /// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a /// post-monomorphization error is encountered during a collection step. /// @@ -404,7 +427,7 @@ fn collect_items_rec<'tcx>( let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() }; // Nested statics have no type. if !nested { - let ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); + let ty = instance.ty(tcx, ty::TypingEnv::fully_monomorphized()); visit_drop_use(tcx, ty, true, starting_item.span, &mut used_items); } @@ -443,13 +466,9 @@ fn collect_items_rec<'tcx>( )); rustc_data_structures::stack::ensure_sufficient_stack(|| { - collect_items_of_instance( - tcx, - instance, - &mut used_items, - &mut mentioned_items, - mode, - ) + let (used, mentioned) = tcx.items_of_instance((instance, mode)); + used_items.extend(used.into_iter().copied()); + mentioned_items.extend(mentioned.into_iter().copied()); }); } MonoItem::GlobalAsm(item_id) => { @@ -617,7 +636,7 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { trace!("monomorphize: self.instance={:?}", self.instance); self.instance.instantiate_mir_and_normalize_erasing_regions( self.tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), ty::EarlyBinder::bind(value), ) } @@ -628,12 +647,11 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { constant: &mir::ConstOperand<'tcx>, ) -> Option<mir::ConstValue<'tcx>> { let const_ = self.monomorphize(constant.const_); - let param_env = ty::ParamEnv::reveal_all(); // Evaluate the constant. This makes const eval failure a collection-time error (rather than // a codegen-time error). rustc stops after collection if there was an error, so this // ensures codegen never has to worry about failing consts. // (codegen relies on this and ICEs will happen if this is violated.) - match const_.eval(self.tcx, param_env, constant.span) { + match const_.eval(self.tcx, ty::TypingEnv::fully_monomorphized(), constant.span) { Ok(v) => Some(v), Err(ErrorHandled::TooGeneric(..)) => span_bug!( constant.span, @@ -844,9 +862,20 @@ fn visit_fn_use<'tcx>( ) { if let ty::FnDef(def_id, args) = *ty.kind() { let instance = if is_direct_call { - ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, source) + ty::Instance::expect_resolve( + tcx, + ty::TypingEnv::fully_monomorphized(), + def_id, + args, + source, + ) } else { - match ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, args) { + match ty::Instance::resolve_for_fn_ptr( + tcx, + ty::TypingEnv::fully_monomorphized(), + def_id, + args, + ) { Some(instance) => instance, _ => bug!("failed to resolve instance for {ty}"), } @@ -1005,12 +1034,12 @@ fn find_vtable_types_for_unsizing<'tcx>( target_ty: Ty<'tcx>, ) -> (Ty<'tcx>, Ty<'tcx>) { let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { - let param_env = ty::ParamEnv::reveal_all(); + let typing_env = ty::TypingEnv::fully_monomorphized(); let type_has_metadata = |ty: Ty<'tcx>| -> bool { - if ty.is_sized(tcx.tcx, param_env) { + if ty.is_sized(tcx.tcx, typing_env) { return false; } - let tail = tcx.struct_tail_for_codegen(ty, param_env); + let tail = tcx.struct_tail_for_codegen(ty, typing_env); match tail.kind() { ty::Foreign(..) => false, ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, @@ -1020,7 +1049,7 @@ fn find_vtable_types_for_unsizing<'tcx>( if type_has_metadata(inner_source) { (inner_source, inner_target) } else { - tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, param_env) + tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, typing_env) } }; @@ -1171,14 +1200,12 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt /// Scans the MIR in order to find function calls, closures, and drop-glue. /// /// Anything that's found is added to `output`. Furthermore the "mentioned items" of the MIR are returned. -#[instrument(skip(tcx, used_items, mentioned_items), level = "debug")] +#[instrument(skip(tcx), level = "debug")] fn collect_items_of_instance<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, - used_items: &mut MonoItems<'tcx>, - mentioned_items: &mut MonoItems<'tcx>, mode: CollectionMode, -) { +) -> (MonoItems<'tcx>, MonoItems<'tcx>) { // This item is getting monomorphized, do mono-time checks. tcx.ensure().check_mono_item(instance); @@ -1193,11 +1220,13 @@ fn collect_items_of_instance<'tcx>( // mentioned item. So instead we collect all pre-monomorphized `MentionedItem` that were already // added to `used_items` in a hash set, which can efficiently query in the // `body.mentioned_items` loop below without even having to monomorphize the item. + let mut used_items = MonoItems::new(); + let mut mentioned_items = MonoItems::new(); let mut used_mentioned_items = Default::default(); let mut collector = MirUsedCollector { tcx, body, - used_items, + used_items: &mut used_items, used_mentioned_items: &mut used_mentioned_items, instance, }; @@ -1212,7 +1241,7 @@ fn collect_items_of_instance<'tcx>( // them errors. for const_op in body.required_consts() { if let Some(val) = collector.eval_constant(const_op) { - collect_const_value(tcx, val, mentioned_items); + collect_const_value(tcx, val, &mut mentioned_items); } } @@ -1221,9 +1250,23 @@ fn collect_items_of_instance<'tcx>( for item in body.mentioned_items() { if !collector.used_mentioned_items.contains(&item.node) { let item_mono = collector.monomorphize(item.node); - visit_mentioned_item(tcx, &item_mono, item.span, mentioned_items); + visit_mentioned_item(tcx, &item_mono, item.span, &mut mentioned_items); } } + + (used_items, mentioned_items) +} + +fn items_of_instance<'tcx>( + tcx: TyCtxt<'tcx>, + (instance, mode): (Instance<'tcx>, CollectionMode), +) -> (&'tcx [Spanned<MonoItem<'tcx>>], &'tcx [Spanned<MonoItem<'tcx>>]) { + let (used_items, mentioned_items) = collect_items_of_instance(tcx, instance, mode); + + let used_items = tcx.arena.alloc_from_iter(used_items); + let mentioned_items = tcx.arena.alloc_from_iter(mentioned_items); + + (used_items, mentioned_items) } /// `item` must be already monomorphized. @@ -1237,8 +1280,13 @@ fn visit_mentioned_item<'tcx>( match *item { MentionedItem::Fn(ty) => { if let ty::FnDef(def_id, args) = *ty.kind() { - let instance = - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, span); + let instance = Instance::expect_resolve( + tcx, + ty::TypingEnv::fully_monomorphized(), + def_id, + args, + span, + ); // `visit_instance_use` was written for "used" item collection but works just as well // for "mentioned" item collection. // We can set `is_direct_call`; that just means we'll skip a bunch of shims that anyway @@ -1304,7 +1352,7 @@ fn collect_const_value<'tcx>( #[instrument(skip(tcx, mode), level = "debug")] fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionStrategy) -> Vec<MonoItem<'_>> { debug!("collecting roots"); - let mut roots = Vec::new(); + let mut roots = MonoItems::new(); { let entry_fn = tcx.entry_fn(()); @@ -1454,13 +1502,13 @@ impl<'v> RootCollector<'_, 'v> { // regions must appear in the argument // listing. let main_ret_ty = self.tcx.normalize_erasing_regions( - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), main_ret_ty.no_bound_vars().unwrap(), ); let start_instance = Instance::expect_resolve( self.tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), start_def_id, self.tcx.mk_args(&[main_ret_ty.into()]), DUMMY_SP, @@ -1518,8 +1566,8 @@ fn create_mono_items_for_default_impls<'tcx>( return; } - let param_env = ty::ParamEnv::reveal_all(); - let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); + let typing_env = ty::TypingEnv::fully_monomorphized(); + let trait_ref = tcx.normalize_erasing_regions(typing_env, trait_ref); let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id); for method in tcx.provided_trait_methods(trait_ref.def_id) { if overridden_methods.contains_key(&method.def_id) { @@ -1534,7 +1582,7 @@ fn create_mono_items_for_default_impls<'tcx>( // only has lifetime generic parameters. This is validated by calling // `own_requires_monomorphization` on both the impl and method. let args = trait_ref.args.extend_to(tcx, method.def_id, only_region_params); - let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args, DUMMY_SP); + let instance = ty::Instance::expect_resolve(tcx, typing_env, method.def_id, args, DUMMY_SP); let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP); if mono_item.node.is_instantiable(tcx) && tcx.should_codegen_locally(instance) { @@ -1596,4 +1644,5 @@ pub(crate) fn collect_crate_mono_items<'tcx>( pub(crate) fn provide(providers: &mut Providers) { providers.hooks.should_codegen_locally = should_codegen_locally; + providers.items_of_instance = items_of_instance; } diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 0cfc4371db5..0f08930fb4c 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -2,6 +2,7 @@ #![feature(array_windows)] #![feature(file_buffered)] #![feature(if_let_guard)] +#![feature(impl_trait_in_assoc_type)] #![feature(let_chains)] #![warn(unreachable_pub)] // tidy-alphabetical-end @@ -34,7 +35,9 @@ fn custom_coerce_unsize_info<'tcx>( [source_ty, target_ty], ); - match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) { + match tcx + .codegen_select_candidate(ty::TypingEnv::fully_monomorphized().as_query_input(trait_ref)) + { Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData { impl_def_id, .. diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index d53595929e7..30e634d8252 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -3,7 +3,7 @@ use rustc_hir::CRATE_HIR_ID; use rustc_middle::mir::{self, traversal}; use rustc_middle::ty::inherent::*; -use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt}; use rustc_session::lint::builtin::ABI_UNSUPPORTED_VECTOR_TYPES; use rustc_span::def_id::DefId; use rustc_span::{DUMMY_SP, Span, Symbol}; @@ -36,9 +36,7 @@ fn do_check_abi<'tcx>( target_feature_def: DefId, mut emit_err: impl FnMut(Option<&'static str>), ) { - let Some(feature_def) = tcx.sess.target.features_for_correct_vector_abi() else { - return; - }; + let feature_def = tcx.sess.target.features_for_correct_vector_abi(); let codegen_attrs = tcx.codegen_fn_attrs(target_feature_def); for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) { let size = arg_abi.layout.size; @@ -64,8 +62,9 @@ fn do_check_abi<'tcx>( /// Checks that the ABI of a given instance of a function does not contain vector-passed arguments /// or return values for which the corresponding target feature is not enabled. fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { - let param_env = ParamEnv::reveal_all(); - let Ok(abi) = tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty()))) else { + let typing_env = ty::TypingEnv::fully_monomorphized(); + let Ok(abi) = tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty()))) + else { // An error will be reported during codegen if we cannot determine the ABI of this // function. return; @@ -102,18 +101,18 @@ fn check_call_site_abi<'tcx>( // "Rust" ABI never passes arguments in vector registers. return; } - let param_env = ParamEnv::reveal_all(); + let typing_env = ty::TypingEnv::fully_monomorphized(); let callee_abi = match *callee.kind() { ty::FnPtr(..) => { - tcx.fn_abi_of_fn_ptr(param_env.and((callee.fn_sig(tcx), ty::List::empty()))) + tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((callee.fn_sig(tcx), ty::List::empty()))) } ty::FnDef(def_id, args) => { // Intrinsics are handled separately by the compiler. if tcx.intrinsic(def_id).is_some() { return; } - let instance = ty::Instance::expect_resolve(tcx, param_env, def_id, args, DUMMY_SP); - tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty()))) + let instance = ty::Instance::expect_resolve(tcx, typing_env, def_id, args, DUMMY_SP); + tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty()))) } _ => { panic!("Invalid function call"); @@ -153,7 +152,7 @@ fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &m let callee_ty = func.ty(body, tcx); let callee_ty = instance.instantiate_mir_and_normalize_erasing_regions( tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), ty::EarlyBinder::bind(callee_ty), ); check_call_site_abi(tcx, callee_ty, *fn_span, body.source.instance); diff --git a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs index 7f04bdf46f1..438d49fd7fb 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs @@ -61,7 +61,7 @@ impl<'tcx> MoveCheckVisitor<'tcx> { trace!("monomorphize: self.instance={:?}", self.instance); self.instance.instantiate_mir_and_normalize_erasing_regions( self.tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), ty::EarlyBinder::bind(value), ) } @@ -128,7 +128,9 @@ impl<'tcx> MoveCheckVisitor<'tcx> { ) -> Option<Size> { let ty = operand.ty(self.body, self.tcx); let ty = self.monomorphize(ty); - let Ok(layout) = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) else { + let Ok(layout) = + self.tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) + else { return None; }; if layout.size.bytes_usize() > limit.0 { diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index e2a6d392ca0..7240cfce0f7 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -666,7 +666,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( // This is a method within an impl, find out what the self-type is: let impl_self_ty = tcx.instantiate_and_normalize_erasing_regions( instance.args, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), tcx.type_of(impl_def_id), ); if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { @@ -1319,5 +1319,20 @@ pub(crate) fn provide(providers: &mut Providers) { .unwrap_or_else(|| panic!("failed to find cgu with name {name:?}")) }; + providers.size_estimate = |tcx, instance| { + match instance.def { + // "Normal" functions size estimate: the number of + // statements, plus one for the terminator. + InstanceKind::Item(..) + | InstanceKind::DropGlue(..) + | InstanceKind::AsyncDropGlueCtorShim(..) => { + let mir = tcx.instance_mir(instance.def); + mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum() + } + // Other compiler-generated shims size estimate: 1 + _ => 1, + } + }; + collector::provide(providers); } diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs index 093a697beeb..deb4ab433bf 100644 --- a/compiler/rustc_monomorphize/src/util.rs +++ b/compiler/rustc_monomorphize/src/util.rs @@ -22,29 +22,29 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In let typeck_results = tcx.typeck(closure_def_id); if typeck_results.closure_size_eval.contains_key(&closure_def_id) { - let param_env = ty::ParamEnv::reveal_all(); + let typing_env = ty::TypingEnv::fully_monomorphized(); let ClosureSizeProfileData { before_feature_tys, after_feature_tys } = typeck_results.closure_size_eval[&closure_def_id]; let before_feature_tys = tcx.instantiate_and_normalize_erasing_regions( closure_instance.args, - param_env, + typing_env, ty::EarlyBinder::bind(before_feature_tys), ); let after_feature_tys = tcx.instantiate_and_normalize_erasing_regions( closure_instance.args, - param_env, + typing_env, ty::EarlyBinder::bind(after_feature_tys), ); let new_size = tcx - .layout_of(param_env.and(after_feature_tys)) + .layout_of(typing_env.as_query_input(after_feature_tys)) .map(|l| format!("{:?}", l.size.bytes())) .unwrap_or_else(|e| format!("Failed {e:?}")); let old_size = tcx - .layout_of(param_env.and(before_feature_tys)) + .layout_of(typing_env.as_query_input(before_feature_tys)) .map(|l| format!("{:?}", l.size.bytes())) .unwrap_or_else(|e| format!("Failed {e:?}")); diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index ebf7372926f..545ab15b945 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -102,7 +102,7 @@ where /// Assemble additional assumptions for an alias that are not included /// in the item bounds of the alias. For now, this is limited to the - /// `implied_const_bounds` for an associated type. + /// `explicit_implied_const_bounds` for an associated type. fn consider_additional_alias_assumptions( ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, @@ -159,13 +159,6 @@ where goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution>; - /// A type is `PointerLike` if we can compute its layout, and that layout - /// matches the layout of `usize`. - fn consider_builtin_pointer_like_candidate( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal<I, Self>, - ) -> Result<Candidate<I>, NoSolution>; - /// A type is a `FnPtr` if it is of `FnPtr` type. fn consider_builtin_fn_ptr_trait_candidate( ecx: &mut EvalCtxt<'_, D>, @@ -449,9 +442,6 @@ where ty::ClosureKind::FnOnce, ) } - Some(TraitSolverLangItem::PointerLike) => { - G::consider_builtin_pointer_like_candidate(self, goal) - } Some(TraitSolverLangItem::FnPtrTrait) => { G::consider_builtin_fn_ptr_trait_candidate(self, goal) } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 5c1a7852dc0..a56febec48c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -633,6 +633,76 @@ fn coroutine_closure_to_ambiguous_coroutine<I: Interner>( ) } +/// This duplicates `extract_tupled_inputs_and_output_from_callable` but needs +/// to return different information (namely, the def id and args) so that we can +/// create const conditions. +/// +/// Doing so on all calls to `extract_tupled_inputs_and_output_from_callable` +/// would be wasteful. +pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>( + cx: I, + self_ty: I::Ty, +) -> Result<(ty::Binder<I, (I::FnInputTys, I::Ty)>, I::DefId, I::GenericArgs), NoSolution> { + match self_ty.kind() { + ty::FnDef(def_id, args) => { + let sig = cx.fn_sig(def_id); + if sig.skip_binder().is_fn_trait_compatible() + && !cx.has_target_features(def_id) + && cx.fn_is_const(def_id) + { + Ok(( + sig.instantiate(cx, args).map_bound(|sig| (sig.inputs(), sig.output())), + def_id, + args, + )) + } else { + return Err(NoSolution); + } + } + // `FnPtr`s are not const for now. + ty::FnPtr(..) => { + return Err(NoSolution); + } + // `Closure`s are not const for now. + ty::Closure(..) => { + return Err(NoSolution); + } + // `CoroutineClosure`s are not const for now. + ty::CoroutineClosure(..) => { + return Err(NoSolution); + } + + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::Dynamic(_, _, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Tuple(_) + | ty::Pat(_, _) + | ty::Alias(_, _) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Error(_) => return Err(NoSolution), + + ty::Bound(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + panic!("unexpected type `{self_ty:?}`") + } + } +} + /// Assemble a list of predicates that would be present on a theoretical /// user impl for an object type. These predicates must be checked any time /// we assemble a built-in object candidate for an object type, since they diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 0912e5effa6..603a68eb890 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -3,15 +3,15 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; +use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::{self as ty, Interner, elaborate}; use tracing::instrument; -use super::assembly::Candidate; +use super::assembly::{Candidate, structural_traits}; use crate::delegate::SolverDelegate; -use crate::solve::assembly::{self}; use crate::solve::{ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution, - QueryResult, + QueryResult, assembly, }; impl<D, I> assembly::GoalKind<D> for ty::HostEffectPredicate<I> @@ -84,12 +84,9 @@ where let cx = ecx.cx(); let mut candidates = vec![]; - // FIXME(const_trait_impl): We elaborate here because the implied const bounds - // aren't necessarily elaborated. We probably should prefix this query - // with `explicit_`... for clause in elaborate::elaborate( cx, - cx.implied_const_bounds(alias_ty.def_id) + cx.explicit_implied_const_bounds(alias_ty.def_id) .iter_instantiated(cx, alias_ty.args) .map(|trait_ref| trait_ref.to_host_effect_clause(cx, goal.predicate.constness)), ) { @@ -142,7 +139,7 @@ where ty::ImplPolarity::Positive => {} }; - if !cx.is_const_impl(impl_def_id) { + if !cx.impl_is_const(impl_def_id) { return Err(NoSolution); } @@ -207,14 +204,7 @@ where _ecx: &mut EvalCtxt<'_, D>, _goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { - todo!("Copy/Clone is not yet const") - } - - fn consider_builtin_pointer_like_candidate( - _ecx: &mut EvalCtxt<'_, D>, - _goal: Goal<I, Self>, - ) -> Result<Candidate<I>, NoSolution> { - unreachable!("PointerLike is not const") + Err(NoSolution) } fn consider_builtin_fn_ptr_trait_candidate( @@ -225,11 +215,48 @@ where } fn consider_builtin_fn_trait_candidates( - _ecx: &mut EvalCtxt<'_, D>, - _goal: Goal<I, Self>, + ecx: &mut EvalCtxt<'_, D>, + goal: Goal<I, Self>, _kind: rustc_type_ir::ClosureKind, ) -> Result<Candidate<I>, NoSolution> { - todo!("Fn* are not yet const") + let cx = ecx.cx(); + + let self_ty = goal.predicate.self_ty(); + let (inputs_and_output, def_id, args) = + structural_traits::extract_fn_def_from_const_callable(cx, self_ty)?; + + // A built-in `Fn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) + let output_is_sized_pred = inputs_and_output.map_bound(|(_, output)| { + ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output]) + }); + let requirements = cx + .const_conditions(def_id) + .iter_instantiated(cx, args) + .map(|trait_ref| { + ( + GoalSource::ImplWhereBound, + goal.with(cx, trait_ref.to_host_effect_clause(cx, goal.predicate.constness)), + ) + }) + .chain([(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))]); + + let pred = inputs_and_output + .map_bound(|(inputs, _)| { + ty::TraitRef::new(cx, goal.predicate.def_id(), [ + goal.predicate.self_ty(), + Ty::new_tup(cx, inputs.as_slice()), + ]) + }) + .to_host_effect_clause(cx, goal.predicate.constness); + + Self::probe_and_consider_implied_clause( + ecx, + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), + goal, + pred, + requirements, + ) } fn consider_builtin_async_fn_trait_candidates( @@ -314,7 +341,7 @@ where _ecx: &mut EvalCtxt<'_, D>, _goal: Goal<I, Self>, ) -> Result<Candidate<I>, NoSolution> { - unreachable!("Destruct is not const") + Err(NoSolution) } fn consider_builtin_transmute_candidate( diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 129744b4db7..6b407640426 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -363,13 +363,6 @@ where panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal); } - fn consider_builtin_pointer_like_candidate( - _ecx: &mut EvalCtxt<'_, D>, - goal: Goal<I, Self>, - ) -> Result<Candidate<I>, NoSolution> { - panic!("`PointerLike` does not have an associated type: {:?}", goal); - } - fn consider_builtin_fn_ptr_trait_candidate( _ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, @@ -394,6 +387,9 @@ where return ecx.forced_ambiguity(MaybeCause::Ambiguity); } }; + + // A built-in `Fn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output]) }); @@ -408,8 +404,6 @@ where }) .upcast(cx); - // A built-in `Fn` impl only holds if the output is sized. - // (FIXME: technically we only need to check this if the type is a fn ptr...) Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), @@ -438,6 +432,9 @@ where goal_kind, env_region, )?; + + // A built-in `AsyncFn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| { ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output_ty]) @@ -494,8 +491,6 @@ where ) .upcast(cx); - // A built-in `AsyncFn` impl only holds if the output is sized. - // (FIXME: technically we only need to check this if the type is a fn ptr...) Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index df4f0ffdd57..ce16258d180 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -248,28 +248,6 @@ where ) } - fn consider_builtin_pointer_like_candidate( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal<I, Self>, - ) -> Result<Candidate<I>, NoSolution> { - if goal.predicate.polarity != ty::PredicatePolarity::Positive { - return Err(NoSolution); - } - - let cx = ecx.cx(); - // But if there are inference variables, we have to wait until it's resolved. - if (goal.param_env, goal.predicate.self_ty()).has_non_region_infer() { - return ecx.forced_ambiguity(MaybeCause::Ambiguity); - } - - if cx.layout_is_pointer_like(goal.param_env, goal.predicate.self_ty()) { - ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) - .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) - } else { - Err(NoSolution) - } - } - fn consider_builtin_fn_ptr_trait_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, @@ -322,6 +300,9 @@ where return ecx.forced_ambiguity(MaybeCause::Ambiguity); } }; + + // A built-in `Fn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output]) }); @@ -331,8 +312,6 @@ where ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) }) .upcast(cx); - // A built-in `Fn` impl only holds if the output is sized. - // (FIXME: technically we only need to check this if the type is a fn ptr...) Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), @@ -360,6 +339,9 @@ where // This region doesn't matter because we're throwing away the coroutine type Region::new_static(cx), )?; + + // A built-in `AsyncFn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| { ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [ @@ -376,8 +358,6 @@ where ]) }) .upcast(cx); - // A built-in `AsyncFn` impl only holds if the output is sized. - // (FIXME: technically we only need to check this if the type is a fn ptr...) Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 7ec4ad6dc35..37eb463cba6 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -650,8 +650,9 @@ pub(crate) struct LeftArrowOperator { #[diag(parse_remove_let)] pub(crate) struct RemoveLet { #[primary_span] - #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")] pub span: Span, + #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")] + pub suggestion: Span, } #[derive(Diagnostic)] 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/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 0ac6133e828..0012db471ef 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2683,6 +2683,13 @@ impl<'a> Parser<'a> { // ^^ // } // + // We account for macro calls that were meant as conditions as well. + // + // if ... { + // } else if macro! { foo bar } { + // ^^ + // } + // // If $cond is "statement-like" such as ExprKind::While then we // want to suggest wrapping in braces. // @@ -2693,7 +2700,9 @@ impl<'a> Parser<'a> { // } // ^ if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) - && classify::expr_requires_semi_to_be_stmt(&cond) => + && (classify::expr_requires_semi_to_be_stmt(&cond) + || matches!(cond.kind, ExprKind::MacCall(..))) + => { self.dcx().emit_err(errors::ExpectedElseBlock { first_tok_span, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 6b4e2d0f4e2..fddbf5896ad 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -77,18 +77,35 @@ impl<'a> Parser<'a> { if !self.eat(term) { let token_str = super::token_descr(&self.token); if !self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) { + let is_let = self.token.is_keyword(kw::Let); + let is_let_mut = is_let && self.look_ahead(1, |t| t.is_keyword(kw::Mut)); + let let_has_ident = is_let && !is_let_mut && self.is_kw_followed_by_ident(kw::Let); + let msg = format!("expected item, found {token_str}"); let mut err = self.dcx().struct_span_err(self.token.span, msg); - let span = self.token.span; - if self.is_kw_followed_by_ident(kw::Let) { - err.span_label( - span, - "consider using `const` or `static` instead of `let` for global variables", - ); + + let label = if is_let { + "`let` cannot be used for global variables" } else { - err.span_label(span, "expected item") - .note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>"); + "expected item" }; + err.span_label(self.token.span, label); + + if is_let { + if is_let_mut { + err.help("consider using `static` and a `Mutex` instead of `let mut`"); + } else if let_has_ident { + err.span_suggestion_short( + self.token.span, + "consider using `static` or `const` instead of `let`", + "static", + Applicability::MaybeIncorrect, + ); + } else { + err.help("consider using `static` or `const` instead of `let`"); + } + } + err.note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>"); return Err(err); } } 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_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 3546e5b0f04..c4326427f67 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -685,7 +685,7 @@ impl<'a> Parser<'a> { self.bump(); // Trim extra space after the `let` let span = lo.with_hi(self.token.span.lo()); - self.dcx().emit_err(RemoveLet { span }); + self.dcx().emit_err(RemoveLet { span: lo, suggestion: span }); lo = self.token.span; } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index b7cdae3e3e1..190cd9ed061 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -475,6 +475,7 @@ impl<'a> Parser<'a> { } fn error_block_no_opening_brace_msg(&mut self, msg: Cow<'static, str>) -> Diag<'a> { + let prev = self.prev_token.span; let sp = self.token.span; let mut e = self.dcx().struct_span_err(sp, msg); let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon; @@ -514,8 +515,97 @@ impl<'a> Parser<'a> { } else { stmt.span }; + self.suggest_fixes_misparsed_for_loop_head( + &mut e, + prev.between(sp), + stmt_span, + &stmt.kind, + ); + } + Err(e) => { + self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); + e.cancel(); + } + _ => {} + } + e.span_label(sp, "expected `{`"); + e + } + + fn suggest_fixes_misparsed_for_loop_head( + &self, + e: &mut Diag<'_>, + between: Span, + stmt_span: Span, + stmt_kind: &StmtKind, + ) { + match (&self.token.kind, &stmt_kind) { + (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) + if let ExprKind::Call(..) = expr.kind => + { + // for _ in x y() {} + e.span_suggestion_verbose( + between, + "you might have meant to write a method call", + ".".to_string(), + Applicability::MaybeIncorrect, + ); + } + (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) + if let ExprKind::Field(..) = expr.kind => + { + // for _ in x y.z {} + e.span_suggestion_verbose( + between, + "you might have meant to write a field access", + ".".to_string(), + Applicability::MaybeIncorrect, + ); + } + (token::CloseDelim(Delimiter::Brace), StmtKind::Expr(expr)) + if let ExprKind::Struct(expr) = &expr.kind + && let None = expr.qself + && expr.path.segments.len() == 1 => + { + // This is specific to "mistyped `if` condition followed by empty body" + // + // for _ in x y {} + e.span_suggestion_verbose( + between, + "you might have meant to write a field access", + ".".to_string(), + Applicability::MaybeIncorrect, + ); + } + (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) + if let ExprKind::Lit(lit) = expr.kind + && let None = lit.suffix + && let token::LitKind::Integer | token::LitKind::Float = lit.kind => + { + // for _ in x 0 {} + // for _ in x 0.0 {} + e.span_suggestion_verbose( + between, + format!("you might have meant to write a field access"), + ".".to_string(), + Applicability::MaybeIncorrect, + ); + } + (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) + if let ExprKind::Loop(..) + | ExprKind::If(..) + | ExprKind::While(..) + | ExprKind::Match(..) + | ExprKind::ForLoop { .. } + | ExprKind::TryBlock(..) + | ExprKind::Ret(..) + | ExprKind::Closure(..) + | ExprKind::Struct(..) + | ExprKind::Try(..) = expr.kind => + { + // These are more likely to have been meant as a block body. e.multipart_suggestion( - "try placing this code inside a block", + "you might have meant to write this as part of a block", vec![ (stmt_span.shrink_to_lo(), "{ ".to_string()), (stmt_span.shrink_to_hi(), " }".to_string()), @@ -524,14 +614,19 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); } - Err(e) => { - self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); - e.cancel(); + (token::OpenDelim(Delimiter::Brace), _) => {} + (_, _) => { + e.multipart_suggestion( + "you might have meant to write this as part of a block", + vec![ + (stmt_span.shrink_to_lo(), "{ ".to_string()), + (stmt_span.shrink_to_hi(), " }".to_string()), + ], + // Speculative; has been misleading in the past (#46836). + Applicability::MaybeIncorrect, + ); } - _ => {} } - e.span_label(sp, "expected `{`"); - e } fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> { diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index b1267562f7b..4db8584b884 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -59,9 +59,9 @@ fn unwrap_fn_abi<'tcx>( } fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { - let param_env = tcx.param_env(item_def_id); + let typing_env = ty::TypingEnv::post_analysis(tcx, item_def_id); let args = GenericArgs::identity_for_item(tcx, item_def_id); - let instance = match Instance::try_resolve(tcx, param_env, item_def_id.into(), args) { + let instance = match Instance::try_resolve(tcx, typing_env, item_def_id.into(), args) { Ok(Some(instance)) => instance, Ok(None) => { // Not sure what to do here, but `LayoutError::Unknown` seems reasonable? @@ -75,7 +75,9 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut Err(_guaranteed) => return, }; let abi = unwrap_fn_abi( - tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))), + tcx.fn_abi_of_instance( + typing_env.as_query_input((instance, /* extra_args */ ty::List::empty())), + ), tcx, item_def_id, ); @@ -117,10 +119,10 @@ fn test_abi_eq<'tcx>(abi1: &'tcx FnAbi<'tcx, Ty<'tcx>>, abi2: &'tcx FnAbi<'tcx, } fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { - let param_env = tcx.param_env(item_def_id); + let typing_env = ty::TypingEnv::post_analysis(tcx, item_def_id); let ty = tcx.type_of(item_def_id).instantiate_identity(); let span = tcx.def_span(item_def_id); - if !ensure_wf(tcx, param_env, ty, item_def_id, span) { + if !ensure_wf(tcx, typing_env, ty, item_def_id, span) { return; } let meta_items = attr.meta_item_list().unwrap_or_default(); @@ -134,10 +136,10 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut ); }; let abi = unwrap_fn_abi( - tcx.fn_abi_of_fn_ptr( - param_env - .and((sig_tys.with(*hdr), /* extra_args */ ty::List::empty())), - ), + tcx.fn_abi_of_fn_ptr(typing_env.as_query_input(( + sig_tys.with(*hdr), + /* extra_args */ ty::List::empty(), + ))), tcx, item_def_id, ); @@ -165,10 +167,10 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut ); }; let abi1 = unwrap_fn_abi( - tcx.fn_abi_of_fn_ptr( - param_env - .and((sig_tys1.with(*hdr1), /* extra_args */ ty::List::empty())), - ), + tcx.fn_abi_of_fn_ptr(typing_env.as_query_input(( + sig_tys1.with(*hdr1), + /* extra_args */ ty::List::empty(), + ))), tcx, item_def_id, ); @@ -179,10 +181,10 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut ); }; let abi2 = unwrap_fn_abi( - tcx.fn_abi_of_fn_ptr( - param_env - .and((sig_tys2.with(*hdr2), /* extra_args */ ty::List::empty())), - ), + tcx.fn_abi_of_fn_ptr(typing_env.as_query_input(( + sig_tys2.with(*hdr2), + /* extra_args */ ty::List::empty(), + ))), tcx, item_def_id, ); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 836511325f4..87069e0b057 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -162,6 +162,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_rustc_std_internal_symbol(attr, span, target) } [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs), + [sym::rustc_as_ptr, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } [sym::rustc_never_returns_null_ptr, ..] => { self.check_applied_to_fn_or_method(hir_id, attr, span, target) } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index b1db66fa52d..ecf8d34ad84 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -273,7 +273,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { data.get(expr.hir_id).expect("no offset_of_data for offset_of"); let body_did = self.typeck_results().hir_owner.to_def_id(); - let param_env = self.tcx.param_env(body_did); + let typing_env = ty::TypingEnv::non_body_analysis(self.tcx, body_did); let mut current_ty = container; @@ -285,13 +285,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { self.insert_def_id(field.did); let field_ty = field.ty(self.tcx, args); - current_ty = self.tcx.normalize_erasing_regions(param_env, field_ty); + current_ty = self.tcx.normalize_erasing_regions(typing_env, field_ty); } // we don't need to mark tuple fields as live, // but we may need to mark subfields ty::Tuple(tys) => { current_ty = - self.tcx.normalize_erasing_regions(param_env, tys[field.as_usize()]); + self.tcx.normalize_erasing_regions(typing_env, tys[field.as_usize()]); } _ => span_bug!(expr.span, "named field access on non-ADT"), } @@ -944,7 +944,10 @@ impl<'tcx> DeadVisitor<'tcx> { if is_positional && self .tcx - .layout_of(self.tcx.param_env(field.did).and(field_type)) + .layout_of( + ty::TypingEnv::non_body_analysis(self.tcx, field.did) + .as_query_input(field_type), + ) .map_or(true, |layout| layout.is_zst()) { return ShouldWarnAboutField::No; 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/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 986dce5b56d..bb90b5a1e31 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -2,10 +2,9 @@ use rustc_abi::{HasDataLayout, TargetDataLayout}; use rustc_ast::Attribute; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; -use rustc_middle::infer::canonical::ir::TypingMode; use rustc_middle::span_bug; -use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers}; -use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; @@ -39,11 +38,13 @@ pub fn test_layout(tcx: TyCtxt<'_>) { pub fn ensure_wf<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, def_id: LocalDefId, span: Span, ) -> bool { + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); let pred = ty::ClauseKind::WellFormed(ty.into()); let obligation = traits::Obligation::new( tcx, @@ -55,8 +56,6 @@ pub fn ensure_wf<'tcx>( param_env, pred, ); - let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); - let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); if !errors.is_empty() { @@ -69,13 +68,13 @@ pub fn ensure_wf<'tcx>( } fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { - let param_env = tcx.param_env(item_def_id); + let typing_env = ty::TypingEnv::post_analysis(tcx, item_def_id); let ty = tcx.type_of(item_def_id).instantiate_identity(); let span = tcx.def_span(item_def_id.to_def_id()); - if !ensure_wf(tcx, param_env, ty, item_def_id, span) { + if !ensure_wf(tcx, typing_env, ty, item_def_id, span) { return; } - match tcx.layout_of(param_env.and(ty)) { + match tcx.layout_of(typing_env.as_query_input(ty)) { Ok(ty_layout) => { // Check out the `#[rustc_layout(..)]` attribute to tell what to dump. // The `..` are the names of fields to dump. @@ -107,19 +106,15 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { span, homogeneous_aggregate: format!( "{:?}", - ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }) + ty_layout + .homogeneous_aggregate(&UnwrapLayoutCx { tcx, typing_env }) ), }); } sym::debug => { - let normalized_ty = format!( - "{}", - tcx.normalize_erasing_regions( - param_env.with_reveal_all_normalized(tcx), - ty, - ) - ); + let normalized_ty = + format!("{}", tcx.normalize_erasing_regions(typing_env, ty)); // FIXME: using the `Debug` impl here isn't ideal. let ty_layout = format!("{:#?}", *ty_layout); tcx.dcx().emit_err(LayoutOf { span, normalized_ty, ty_layout }); @@ -140,7 +135,7 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { struct UnwrapLayoutCx<'tcx> { tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, } impl<'tcx> LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> { @@ -155,9 +150,9 @@ impl<'tcx> HasTyCtxt<'tcx> for UnwrapLayoutCx<'tcx> { } } -impl<'tcx> HasParamEnv<'tcx> for UnwrapLayoutCx<'tcx> { - fn param_env(&self) -> ParamEnv<'tcx> { - self.param_env +impl<'tcx> HasTypingEnv<'tcx> for UnwrapLayoutCx<'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + self.typing_env } } 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_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 366f7dd293c..9cd95a0b02d 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -468,7 +468,7 @@ const ACC_USE: u32 = 4; struct Liveness<'a, 'tcx> { ir: &'a mut IrMaps<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, closure_min_captures: Option<&'tcx RootVariableMinCaptureList<'tcx>>, successors: IndexVec<LiveNode, Option<LiveNode>>, rwu_table: rwu_table::RWUTable, @@ -491,7 +491,8 @@ struct Liveness<'a, 'tcx> { impl<'a, 'tcx> Liveness<'a, 'tcx> { fn new(ir: &'a mut IrMaps<'tcx>, body_owner: LocalDefId) -> Liveness<'a, 'tcx> { let typeck_results = ir.tcx.typeck(body_owner); - let param_env = ir.tcx.param_env(body_owner); + // FIXME(#132279): we're in a body here. + let typing_env = ty::TypingEnv::non_body_analysis(ir.tcx, body_owner); let closure_min_captures = typeck_results.closure_min_captures.get(&body_owner); let closure_ln = ir.add_live_node(ClosureNode); let exit_ln = ir.add_live_node(ExitNode); @@ -502,7 +503,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { Liveness { ir, typeck_results, - param_env, + typing_env, closure_min_captures, successors: IndexVec::from_elem_n(None, num_live_nodes), rwu_table: rwu_table::RWUTable::new(num_live_nodes, num_vars), @@ -1297,7 +1298,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn check_is_ty_uninhabited(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNode { let ty = self.typeck_results.expr_ty(expr); let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id(); - if ty.is_inhabited_from(self.ir.tcx, m, self.param_env) { + if ty.is_inhabited_from(self.ir.tcx, m, self.typing_env) { return succ; } match self.ir.lnks[succ] { diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 9ea5023064c..cc0763ac751 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -9,6 +9,7 @@ use rustc_index::{Idx, IndexVec}; use rustc_middle::middle::stability::EvalResult; use rustc_middle::mir::{self, Const}; use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary}; +use rustc_middle::traits::Reveal; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef, @@ -108,6 +109,17 @@ impl<'p, 'tcx: 'p> fmt::Debug for RustcPatCtxt<'p, 'tcx> { } impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { + pub fn typing_mode(&self) -> ty::TypingMode<'tcx> { + debug_assert_eq!(self.param_env.reveal(), Reveal::UserFacing); + // FIXME(#132279): This is inside of a body. If we need to use the `param_env` + // and `typing_mode` we should reveal opaques defined by that body. + ty::TypingMode::non_body_analysis() + } + + pub fn typing_env(&self) -> ty::TypingEnv<'tcx> { + ty::TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env } + } + /// Type inference occasionally gives us opaque types in places where corresponding patterns /// have more specific types. To avoid inconsistencies as well as detect opaque uninhabited /// types, we use the corresponding concrete type if possible. @@ -139,7 +151,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { !ty.inhabited_predicate(self.tcx).apply_revealing_opaque( self.tcx, - self.param_env, + self.typing_env(), self.module, &|key| self.reveal_opaque_key(key), ) @@ -179,7 +191,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { variant.fields.iter().map(move |field| { let ty = field.ty(self.tcx, args); // `field.ty()` doesn't normalize after instantiating. - let ty = self.tcx.normalize_erasing_regions(self.param_env, ty); + let ty = self.tcx.normalize_erasing_regions(self.typing_env(), ty); let ty = self.reveal_opaque_ty(ty); (field, ty) }) @@ -369,7 +381,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let is_inhabited = v .inhabited_predicate(cx.tcx, *def) .instantiate(cx.tcx, args) - .apply_revealing_opaque(cx.tcx, cx.param_env, cx.module, &|key| { + .apply_revealing_opaque(cx.tcx, cx.typing_env(), cx.module, &|key| { cx.reveal_opaque_key(key) }); // Variants that depend on a disabled unstable feature. @@ -430,7 +442,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { match bdy { PatRangeBoundary::NegInfinity => MaybeInfiniteInt::NegInfinity, PatRangeBoundary::Finite(value) => { - let bits = value.eval_bits(self.tcx, self.param_env); + let bits = value.eval_bits(self.tcx, self.typing_env()); match *ty.kind() { ty::Int(ity) => { let size = Integer::from_int_ty(&self.tcx, ity).size().bits(); @@ -453,7 +465,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let fields: Vec<_>; match &pat.kind { PatKind::AscribeUserType { subpattern, .. } - | PatKind::InlineConstant { subpattern, .. } => return self.lower_pat(subpattern), + | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern), PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat), PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { ctor = Wildcard; @@ -539,7 +551,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { PatKind::Constant { value } => { match ty.kind() { ty::Bool => { - ctor = match value.try_eval_bool(cx.tcx, cx.param_env) { + ctor = match value.try_eval_bool(cx.tcx, cx.typing_env()) { Some(b) => Bool(b), None => Opaque(OpaqueId::new()), }; @@ -547,7 +559,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { arity = 0; } ty::Char | ty::Int(_) | ty::Uint(_) => { - ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { + ctor = match value.try_eval_bits(cx.tcx, cx.typing_env()) { Some(bits) => { let x = match *ty.kind() { ty::Int(ity) => { @@ -564,7 +576,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { arity = 0; } ty::Float(ty::FloatTy::F16) => { - ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { + ctor = match value.try_eval_bits(cx.tcx, cx.typing_env()) { Some(bits) => { use rustc_apfloat::Float; let value = rustc_apfloat::ieee::Half::from_bits(bits); @@ -576,7 +588,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { arity = 0; } ty::Float(ty::FloatTy::F32) => { - ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { + ctor = match value.try_eval_bits(cx.tcx, cx.typing_env()) { Some(bits) => { use rustc_apfloat::Float; let value = rustc_apfloat::ieee::Single::from_bits(bits); @@ -588,7 +600,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { arity = 0; } ty::Float(ty::FloatTy::F64) => { - ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { + ctor = match value.try_eval_bits(cx.tcx, cx.typing_env()) { Some(bits) => { use rustc_apfloat::Float; let value = rustc_apfloat::ieee::Double::from_bits(bits); @@ -600,7 +612,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { arity = 0; } ty::Float(ty::FloatTy::F128) => { - ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { + ctor = match value.try_eval_bits(cx.tcx, cx.typing_env()) { Some(bits) => { use rustc_apfloat::Float; let value = rustc_apfloat::ieee::Quad::from_bits(bits); @@ -649,8 +661,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } ty::Float(fty) => { use rustc_apfloat::Float; - let lo = lo.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env)); - let hi = hi.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env)); + let lo = lo.as_finite().map(|c| c.eval_bits(cx.tcx, cx.typing_env())); + let hi = hi.as_finite().map(|c| c.eval_bits(cx.tcx, cx.typing_env())); match fty { ty::FloatTy::F16 => { use rustc_apfloat::ieee::Half; 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/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index bdf940a04b5..293cee500bb 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1324,7 +1324,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // This way they can use `macro_rules` defined later. self.visit_vis(&item.vis); self.visit_ident(&item.ident); - item.kind.walk(item, AssocCtxt::Trait, self); + item.kind.walk(item.span, item.id, &item.ident, &item.vis, (), self); visit::walk_list!(self, visit_attribute, &item.attrs); } _ => visit::walk_item(self, item), 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..466e190028a 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, - 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, + Shadowing::Unrestricted, 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 @@ -1511,9 +1478,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if segment_idx == 0 { if name == kw::SelfLower { let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0(); - module = Some(ModuleOrUniformRoot::Module( - self.resolve_self(&mut ctxt, parent_scope.module), - )); + let self_mod = self.resolve_self(&mut ctxt, parent_scope.module); + if let Some(res) = self_mod.res() { + record_segment_res(self, res); + } + module = Some(ModuleOrUniformRoot::Module(self_mod)); continue; } if name == kw::PathRoot && ident.span.at_least_rust_2018() { @@ -1530,7 +1499,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } if name == kw::PathRoot || name == kw::Crate || name == kw::DollarCrate { // `::a::b`, `crate::a::b` or `$crate::a::b` - module = Some(ModuleOrUniformRoot::Module(self.resolve_crate_root(ident))); + let crate_root = self.resolve_crate_root(ident); + if let Some(res) = crate_root.res() { + record_segment_res(self, res); + } + module = Some(ModuleOrUniformRoot::Module(crate_root)); continue; } } @@ -1563,6 +1536,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_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 0e6f905e7a1..2f4387e412d 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -133,7 +133,7 @@ fn encode_const<'tcx>( match ct_ty.kind() { ty::Int(ity) => { let bits = c - .try_to_bits(tcx, ty::ParamEnv::reveal_all()) + .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected monomorphic const in cfi"); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; if val < 0 { @@ -143,7 +143,7 @@ fn encode_const<'tcx>( } ty::Uint(_) => { let val = c - .try_to_bits(tcx, ty::ParamEnv::reveal_all()) + .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected monomorphic const in cfi"); let _ = write!(s, "{val}"); } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs index 01568a0f61c..562e288afaa 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs @@ -117,7 +117,9 @@ pub fn typeid_for_instance<'tcx>( .unwrap_or_else(|| bug!("typeid_for_instance: invalid option(s) `{:?}`", options.bits())); let instance = transform_instance(tcx, instance, transform_ty_options); let fn_abi = tcx - .fn_abi_of_instance(ty::ParamEnv::reveal_all().and((instance, ty::List::empty()))) + .fn_abi_of_instance( + ty::TypingEnv::fully_monomorphized().as_query_input((instance, ty::List::empty())), + ) .unwrap_or_else(|error| { bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}") }); diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index cba79a02f8b..9c01bd04353 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -136,18 +136,18 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> { return t; } let variant = adt_def.non_enum_variant(); - let param_env = self.tcx.param_env(variant.def_id); + let typing_env = ty::TypingEnv::post_analysis(self.tcx, variant.def_id); let field = variant.fields.iter().find(|field| { let ty = self.tcx.type_of(field.did).instantiate_identity(); let is_zst = self .tcx - .layout_of(param_env.and(ty)) + .layout_of(typing_env.as_query_input(ty)) .is_ok_and(|layout| layout.is_zst()); !is_zst }); if let Some(field) = field { let ty0 = self.tcx.normalize_erasing_regions( - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), field.ty(self.tcx, args), ); // Generalize any repr(transparent) user-defined type that is either a @@ -209,9 +209,9 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> { } } - ty::Alias(..) => { - self.fold_ty(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), t)) - } + ty::Alias(..) => self.fold_ty( + self.tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), t), + ), ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => { bug!("fold_ty: unexpected `{:?}`", t.kind()); @@ -241,7 +241,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc let alias_ty = ty::AliasTy::new_from_args(tcx, assoc_ty.def_id, super_trait_ref.args); let resolved = tcx.normalize_erasing_regions( - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), alias_ty.to_ty(tcx), ); debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx)); @@ -376,7 +376,7 @@ pub(crate) fn transform_instance<'tcx>( // implementation will not. We need to walk back to the more general trait method let trait_ref = tcx.instantiate_and_normalize_erasing_regions( instance.args, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), trait_ref, ); let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); @@ -397,7 +397,7 @@ pub(crate) fn transform_instance<'tcx>( } else if tcx.is_closure_like(instance.def_id()) { // We're either a closure or a coroutine. Our goal is to find the trait we're defined on, // instantiate it, and take the type of its only method as our own. - let closure_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); + let closure_ty = instance.ty(tcx, ty::TypingEnv::fully_monomorphized()); let (trait_id, inputs) = match closure_ty.kind() { ty::Closure(..) => { let closure_args = instance.args.as_closure(); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 44721bd889a..d60c56fee75 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -30,17 +30,18 @@ use rustc_target::spec::{ }; use tracing::debug; +pub use crate::config::cfg::{Cfg, CheckCfg, ExpectedValues}; +use crate::config::native_libs::parse_native_libs; use crate::errors::FileWriteFail; pub use crate::options::*; use crate::search_paths::SearchPath; -use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; +use crate::utils::CanonicalizedPath; use crate::{EarlyDiagCtxt, HashStableContext, Session, filesearch, lint}; mod cfg; +mod native_libs; pub mod sigpipe; -pub use cfg::{Cfg, CheckCfg, ExpectedValues}; - /// The different settings that the `-C strip` flag can have. #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum Strip { @@ -1068,7 +1069,7 @@ impl OutputFilenames { self.with_directory_and_extension(&self.out_directory, extension) } - fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf { + pub fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf { let mut path = directory.join(&self.filestem); path.set_extension(extension); path @@ -2134,143 +2135,6 @@ fn parse_assert_incr_state( } } -fn parse_native_lib_kind( - early_dcx: &EarlyDiagCtxt, - matches: &getopts::Matches, - kind: &str, -) -> (NativeLibKind, Option<bool>) { - let (kind, modifiers) = match kind.split_once(':') { - None => (kind, None), - Some((kind, modifiers)) => (kind, Some(modifiers)), - }; - - let kind = match kind { - "static" => NativeLibKind::Static { bundle: None, whole_archive: None }, - "dylib" => NativeLibKind::Dylib { as_needed: None }, - "framework" => NativeLibKind::Framework { as_needed: None }, - "link-arg" => { - if !nightly_options::is_unstable_enabled(matches) { - let why = if nightly_options::match_is_nightly_build(matches) { - " and only accepted on the nightly compiler" - } else { - ", the `-Z unstable-options` flag must also be passed to use it" - }; - early_dcx.early_fatal(format!("library kind `link-arg` is unstable{why}")) - } - NativeLibKind::LinkArg - } - _ => early_dcx.early_fatal(format!( - "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg" - )), - }; - match modifiers { - None => (kind, None), - Some(modifiers) => parse_native_lib_modifiers(early_dcx, kind, modifiers, matches), - } -} - -fn parse_native_lib_modifiers( - early_dcx: &EarlyDiagCtxt, - mut kind: NativeLibKind, - modifiers: &str, - matches: &getopts::Matches, -) -> (NativeLibKind, Option<bool>) { - let mut verbatim = None; - for modifier in modifiers.split(',') { - let (modifier, value) = match modifier.strip_prefix(['+', '-']) { - Some(m) => (m, modifier.starts_with('+')), - None => early_dcx.early_fatal( - "invalid linking modifier syntax, expected '+' or '-' prefix \ - before one of: bundle, verbatim, whole-archive, as-needed", - ), - }; - - let report_unstable_modifier = || { - if !nightly_options::is_unstable_enabled(matches) { - let why = if nightly_options::match_is_nightly_build(matches) { - " and only accepted on the nightly compiler" - } else { - ", the `-Z unstable-options` flag must also be passed to use it" - }; - early_dcx.early_fatal(format!("linking modifier `{modifier}` is unstable{why}")) - } - }; - let assign_modifier = |dst: &mut Option<bool>| { - if dst.is_some() { - let msg = format!("multiple `{modifier}` modifiers in a single `-l` option"); - early_dcx.early_fatal(msg) - } else { - *dst = Some(value); - } - }; - match (modifier, &mut kind) { - ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle), - ("bundle", _) => early_dcx.early_fatal( - "linking modifier `bundle` is only compatible with `static` linking kind", - ), - - ("verbatim", _) => assign_modifier(&mut verbatim), - - ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => { - assign_modifier(whole_archive) - } - ("whole-archive", _) => early_dcx.early_fatal( - "linking modifier `whole-archive` is only compatible with `static` linking kind", - ), - - ("as-needed", NativeLibKind::Dylib { as_needed }) - | ("as-needed", NativeLibKind::Framework { as_needed }) => { - report_unstable_modifier(); - assign_modifier(as_needed) - } - ("as-needed", _) => early_dcx.early_fatal( - "linking modifier `as-needed` is only compatible with \ - `dylib` and `framework` linking kinds", - ), - - // Note: this error also excludes the case with empty modifier - // string, like `modifiers = ""`. - _ => early_dcx.early_fatal(format!( - "unknown linking modifier `{modifier}`, expected one \ - of: bundle, verbatim, whole-archive, as-needed" - )), - } - } - - (kind, verbatim) -} - -fn parse_libs(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Vec<NativeLib> { - matches - .opt_strs("l") - .into_iter() - .map(|s| { - // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]", - // where KIND is one of "dylib", "framework", "static", "link-arg" and - // where MODIFIERS are a comma separated list of supported modifiers - // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed - // with either + or - to indicate whether it is enabled or disabled. - // The last value specified for a given modifier wins. - let (name, kind, verbatim) = match s.split_once('=') { - None => (s, NativeLibKind::Unspecified, None), - Some((kind, name)) => { - let (kind, verbatim) = parse_native_lib_kind(early_dcx, matches, kind); - (name.to_string(), kind, verbatim) - } - }; - - let (name, new_name) = match name.split_once(':') { - None => (name, None), - Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())), - }; - if name.is_empty() { - early_dcx.early_fatal("library name must not be empty"); - } - NativeLib { name, new_name, kind, verbatim } - }) - .collect() -} - pub fn parse_externs( early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches, @@ -2644,7 +2508,10 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let debuginfo = select_debuginfo(matches, &cg); let debuginfo_compression = unstable_opts.debuginfo_compression; - let libs = parse_libs(early_dcx, matches); + let crate_name = matches.opt_str("crate-name"); + let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref()); + // Parse any `-l` flags, which link to native libraries. + let libs = parse_native_libs(early_dcx, &unstable_opts, unstable_features, matches); let test = matches.opt_present("test"); @@ -2659,8 +2526,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let externs = parse_externs(early_dcx, matches, &unstable_opts); - let crate_name = matches.opt_str("crate-name"); - let remap_path_prefix = parse_remap_path_prefix(early_dcx, matches, &unstable_opts); let pretty = parse_pretty(early_dcx, &unstable_opts); @@ -2734,7 +2599,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M error_format, diagnostic_width, externs, - unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()), + unstable_features, crate_name, libs, debug_assertions, diff --git a/compiler/rustc_session/src/config/native_libs.rs b/compiler/rustc_session/src/config/native_libs.rs new file mode 100644 index 00000000000..f1f0aeb5e59 --- /dev/null +++ b/compiler/rustc_session/src/config/native_libs.rs @@ -0,0 +1,192 @@ +//! Parser for the `-l` command-line option, which links the generated crate to +//! a native library. +//! +//! (There is also a similar but separate syntax for `#[link]` attributes, +//! which have their own parser in `rustc_metadata`.) + +use rustc_feature::UnstableFeatures; + +use crate::EarlyDiagCtxt; +use crate::config::UnstableOptions; +use crate::utils::{NativeLib, NativeLibKind}; + +#[cfg(test)] +mod tests; + +/// Parses all `-l` options. +pub(crate) fn parse_native_libs( + early_dcx: &EarlyDiagCtxt, + unstable_opts: &UnstableOptions, + unstable_features: UnstableFeatures, + matches: &getopts::Matches, +) -> Vec<NativeLib> { + let cx = ParseNativeLibCx { + early_dcx, + unstable_options_enabled: unstable_opts.unstable_options, + is_nightly: unstable_features.is_nightly_build(), + }; + matches.opt_strs("l").into_iter().map(|value| parse_native_lib(&cx, &value)).collect() +} + +struct ParseNativeLibCx<'a> { + early_dcx: &'a EarlyDiagCtxt, + unstable_options_enabled: bool, + is_nightly: bool, +} + +impl ParseNativeLibCx<'_> { + /// If unstable values are not permitted, exits with a fatal error made by + /// combining the given strings. + fn on_unstable_value(&self, message: &str, if_nightly: &str, if_stable: &str) { + if self.unstable_options_enabled { + return; + } + + let suffix = if self.is_nightly { if_nightly } else { if_stable }; + self.early_dcx.early_fatal(format!("{message}{suffix}")); + } +} + +/// Parses the value of a single `-l` option. +fn parse_native_lib(cx: &ParseNativeLibCx<'_>, value: &str) -> NativeLib { + let NativeLibParts { kind, modifiers, name, new_name } = split_native_lib_value(value); + + let kind = kind.map_or(NativeLibKind::Unspecified, |kind| match kind { + "static" => NativeLibKind::Static { bundle: None, whole_archive: None }, + "dylib" => NativeLibKind::Dylib { as_needed: None }, + "framework" => NativeLibKind::Framework { as_needed: None }, + "link-arg" => { + cx.on_unstable_value( + "library kind `link-arg` is unstable", + ", the `-Z unstable-options` flag must also be passed to use it", + " and only accepted on the nightly compiler", + ); + NativeLibKind::LinkArg + } + _ => cx.early_dcx.early_fatal(format!( + "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg" + )), + }); + + // Provisionally create the result, so that modifiers can modify it. + let mut native_lib = NativeLib { + name: name.to_owned(), + new_name: new_name.map(str::to_owned), + kind, + verbatim: None, + }; + + if let Some(modifiers) = modifiers { + // If multiple modifiers are present, they are separated by commas. + for modifier in modifiers.split(',') { + parse_and_apply_modifier(cx, modifier, &mut native_lib); + } + } + + if native_lib.name.is_empty() { + cx.early_dcx.early_fatal("library name must not be empty"); + } + + native_lib +} + +/// Parses one of the comma-separated modifiers (prefixed by `+` or `-`), and +/// modifies `native_lib` appropriately. +/// +/// Exits with a fatal error if a malformed/unknown/inappropriate modifier is +/// found. +fn parse_and_apply_modifier(cx: &ParseNativeLibCx<'_>, modifier: &str, native_lib: &mut NativeLib) { + let early_dcx = cx.early_dcx; + + // Split off the leading `+` or `-` into a boolean value. + let (modifier, value) = match modifier.split_at_checked(1) { + Some(("+", m)) => (m, true), + Some(("-", m)) => (m, false), + _ => cx.early_dcx.early_fatal( + "invalid linking modifier syntax, expected '+' or '-' prefix \ + before one of: bundle, verbatim, whole-archive, as-needed", + ), + }; + + // Assigns the value (from `+` or `-`) to an empty `Option<bool>`, or emits + // a fatal error if the option has already been set. + let assign_modifier = |opt_bool: &mut Option<bool>| { + if opt_bool.is_some() { + let msg = format!("multiple `{modifier}` modifiers in a single `-l` option"); + early_dcx.early_fatal(msg) + } + *opt_bool = Some(value); + }; + + // Check that the modifier is applicable to the native lib kind, and apply it. + match (modifier, &mut native_lib.kind) { + ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle), + ("bundle", _) => early_dcx + .early_fatal("linking modifier `bundle` is only compatible with `static` linking kind"), + + ("verbatim", _) => assign_modifier(&mut native_lib.verbatim), + + ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => { + assign_modifier(whole_archive) + } + ("whole-archive", _) => early_dcx.early_fatal( + "linking modifier `whole-archive` is only compatible with `static` linking kind", + ), + + ("as-needed", NativeLibKind::Dylib { as_needed }) + | ("as-needed", NativeLibKind::Framework { as_needed }) => { + cx.on_unstable_value( + "linking modifier `as-needed` is unstable", + ", the `-Z unstable-options` flag must also be passed to use it", + " and only accepted on the nightly compiler", + ); + assign_modifier(as_needed) + } + ("as-needed", _) => early_dcx.early_fatal( + "linking modifier `as-needed` is only compatible with \ + `dylib` and `framework` linking kinds", + ), + + _ => early_dcx.early_fatal(format!( + "unknown linking modifier `{modifier}`, expected one \ + of: bundle, verbatim, whole-archive, as-needed" + )), + } +} + +#[derive(Debug, PartialEq, Eq)] +struct NativeLibParts<'a> { + kind: Option<&'a str>, + modifiers: Option<&'a str>, + name: &'a str, + new_name: Option<&'a str>, +} + +/// Splits a string of the form `[KIND[:MODIFIERS]=]NAME[:NEW_NAME]` into those +/// individual parts. This cannot fail, but the resulting strings require +/// further validation. +fn split_native_lib_value(value: &str) -> NativeLibParts<'_> { + // Split the initial value into `[KIND=]NAME`. + let name = value; + let (kind, name) = match name.split_once('=') { + Some((prefix, name)) => (Some(prefix), name), + None => (None, name), + }; + + // Split the kind part, if present, into `KIND[:MODIFIERS]`. + let (kind, modifiers) = match kind { + Some(kind) => match kind.split_once(':') { + Some((kind, modifiers)) => (Some(kind), Some(modifiers)), + None => (Some(kind), None), + }, + None => (None, None), + }; + + // Split the name part into `NAME[:NEW_NAME]`. + let (name, new_name) = match name.split_once(':') { + Some((name, new_name)) => (name, Some(new_name)), + None => (name, None), + }; + + NativeLibParts { kind, modifiers, name, new_name } +} diff --git a/compiler/rustc_session/src/config/native_libs/tests.rs b/compiler/rustc_session/src/config/native_libs/tests.rs new file mode 100644 index 00000000000..3bcab93ef4b --- /dev/null +++ b/compiler/rustc_session/src/config/native_libs/tests.rs @@ -0,0 +1,50 @@ +use crate::config::native_libs::{NativeLibParts, split_native_lib_value}; + +#[test] +fn split() { + // This is a unit test for some implementation details, so consider deleting + // it if it gets in the way. + use NativeLibParts as P; + + let examples = &[ + ("", P { kind: None, modifiers: None, name: "", new_name: None }), + ("foo", P { kind: None, modifiers: None, name: "foo", new_name: None }), + ("foo:", P { kind: None, modifiers: None, name: "foo", new_name: Some("") }), + ("foo:bar", P { kind: None, modifiers: None, name: "foo", new_name: Some("bar") }), + (":bar", P { kind: None, modifiers: None, name: "", new_name: Some("bar") }), + ("kind=foo", P { kind: Some("kind"), modifiers: None, name: "foo", new_name: None }), + (":mods=foo", P { kind: Some(""), modifiers: Some("mods"), name: "foo", new_name: None }), + (":mods=:bar", P { + kind: Some(""), + modifiers: Some("mods"), + name: "", + new_name: Some("bar"), + }), + ("kind=foo:bar", P { + kind: Some("kind"), + modifiers: None, + name: "foo", + new_name: Some("bar"), + }), + ("kind:mods=foo", P { + kind: Some("kind"), + modifiers: Some("mods"), + name: "foo", + new_name: None, + }), + ("kind:mods=foo:bar", P { + kind: Some("kind"), + modifiers: Some("mods"), + name: "foo", + new_name: Some("bar"), + }), + ("::==::", P { kind: Some(""), modifiers: Some(":"), name: "=", new_name: Some(":") }), + ("==::==", P { kind: Some(""), modifiers: None, name: "=", new_name: Some(":==") }), + ]; + + for &(value, ref expected) in examples { + println!("{value:?}"); + let actual = split_native_lib_value(value); + assert_eq!(&actual, expected); + } +} diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f485e8cace5..cbfe5d22f1d 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], @@ -1889,7 +1887,7 @@ options! { meta_stats: bool = (false, parse_bool, [UNTRACKED], "gather metadata statistics (default: no)"), metrics_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED], - "stores metrics about the errors being emitted by rustc to disk"), + "the directory metrics emitted by rustc are dumped into (implicitly enables default set of metrics)"), mir_emit_retag: bool = (false, parse_bool, [TRACKED], "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \ (default: no)"), diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs index 5c09879f60e..4e8db6096d4 100644 --- a/compiler/rustc_smir/src/rustc_smir/alloc.rs +++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs @@ -41,7 +41,7 @@ pub(crate) fn try_new_allocation<'tcx>( let size = scalar.size(); let align = tables .tcx - .layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty)) + .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty)) .map_err(|e| e.stable(tables))? .align; let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi); @@ -53,7 +53,7 @@ pub(crate) fn try_new_allocation<'tcx>( ConstValue::ZeroSized => { let align = tables .tcx - .layout_of(rustc_middle::ty::ParamEnv::empty().and(ty)) + .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty)) .map_err(|e| e.stable(tables))? .align; new_empty_allocation(align.abi) @@ -66,7 +66,7 @@ pub(crate) fn try_new_allocation<'tcx>( rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx); let layout = tables .tcx - .layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty)) + .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty)) .map_err(|e| e.stable(tables))?; let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(layout.size, layout.align.abi); @@ -90,7 +90,7 @@ pub(crate) fn try_new_allocation<'tcx>( let alloc = tables.tcx.global_alloc(alloc_id).unwrap_memory(); let ty_size = tables .tcx - .layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty)) + .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty)) .map_err(|e| e.stable(tables))? .size; allocation_filter(&alloc.0, alloc_range(offset, ty_size), tables) diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs index cd91fc26c10..2eb0cea0e85 100644 --- a/compiler/rustc_smir/src/rustc_smir/builder.rs +++ b/compiler/rustc_smir/src/rustc_smir/builder.rs @@ -40,7 +40,7 @@ impl<'tcx> BodyBuilder<'tcx> { { let mut mono_body = self.instance.instantiate_mir_and_normalize_erasing_regions( tables.tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), ty::EarlyBinder::bind(body), ); self.visit_body(&mut mono_body); @@ -60,7 +60,7 @@ impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> { location: mir::Location, ) { let const_ = constant.const_; - let val = match const_.eval(self.tcx, ty::ParamEnv::reveal_all(), constant.span) { + let val = match const_.eval(self.tcx, ty::TypingEnv::fully_monomorphized(), constant.span) { Ok(v) => v, Err(mir::interpret::ErrorHandled::Reported(..)) => return, Err(mir::interpret::ErrorHandled::TooGeneric(..)) => { diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 3db65692af7..9025b47c422 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -11,11 +11,11 @@ use std::iter; use rustc_abi::HasDataLayout; use rustc_hir::LangItem; use rustc_middle::ty::layout::{ - FnAbiOf, FnAbiOfHelpers, HasParamEnv, HasTyCtxt, LayoutOf, LayoutOfHelpers, + FnAbiOf, FnAbiOfHelpers, HasTyCtxt, HasTypingEnv, LayoutOf, LayoutOfHelpers, }; use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; use rustc_middle::ty::{ - GenericPredicates, Instance, List, ParamEnv, ScalarInt, TyCtxt, TypeVisitableExt, ValTree, + GenericPredicates, Instance, List, ScalarInt, TyCtxt, TypeVisitableExt, ValTree, }; use rustc_middle::{mir, ty}; use rustc_span::def_id::LOCAL_CRATE; @@ -410,7 +410,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let tcx = tables.tcx; let mir_const = cnst.internal(&mut *tables, tcx); mir_const - .try_eval_target_usize(tables.tcx, ParamEnv::empty()) + .try_eval_target_usize(tables.tcx, ty::TypingEnv::fully_monomorphized()) .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64"))) } fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error> { @@ -428,7 +428,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let ty_internal = ty.internal(&mut *tables, tcx); let size = tables .tcx - .layout_of(ParamEnv::empty().and(ty_internal)) + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty_internal)) .map_err(|err| { Error::new(format!( "Cannot create a zero-sized constant for type `{ty_internal}`: {err}" @@ -469,7 +469,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx)); - let size = tables.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap().size; + let size = tables + .tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) + .unwrap() + .size; // We don't use Const::from_bits since it doesn't have any error checking. let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| { @@ -486,7 +490,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx)); - let size = tables.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap().size; + let size = tables + .tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) + .unwrap() + .size; // We don't use Const::from_bits since it doesn't have any error checking. let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| { @@ -523,7 +531,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let def_ty = tables.tcx.type_of(item.internal(&mut *tables, tcx)); tables .tcx - .instantiate_and_normalize_erasing_regions(args, ty::ParamEnv::reveal_all(), def_ty) + .instantiate_and_normalize_erasing_regions( + args, + ty::TypingEnv::fully_monomorphized(), + def_ty, + ) .stable(&mut *tables) } @@ -573,7 +585,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; assert!(!instance.has_non_region_param(), "{instance:?} needs further instantiation"); - instance.ty(tables.tcx, ParamEnv::reveal_all()).stable(&mut *tables) + instance.ty(tables.tcx, ty::TypingEnv::fully_monomorphized()).stable(&mut *tables) } fn instance_args(&self, def: InstanceDef) -> GenericArgs { @@ -642,7 +654,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let tcx = tables.tcx; let def_id = def.0.internal(&mut *tables, tcx); let args_ref = args.internal(&mut *tables, tcx); - match Instance::try_resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) { + match Instance::try_resolve( + tables.tcx, + ty::TypingEnv::fully_monomorphized(), + def_id, + args_ref, + ) { Ok(Some(instance)) => Some(instance.stable(&mut *tables)), Ok(None) | Err(_) => None, } @@ -665,8 +682,13 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let tcx = tables.tcx; let def_id = def.0.internal(&mut *tables, tcx); let args_ref = args.internal(&mut *tables, tcx); - Instance::resolve_for_fn_ptr(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) - .stable(&mut *tables) + Instance::resolve_for_fn_ptr( + tables.tcx, + ty::TypingEnv::fully_monomorphized(), + def_id, + args_ref, + ) + .stable(&mut *tables) } fn resolve_closure( @@ -691,7 +713,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let instance = tables.instances[def]; let tcx = tables.tcx; let result = tcx.const_eval_instance( - ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), instance, tcx.def_span(instance.def_id()), ); @@ -827,9 +849,9 @@ impl<'tcx> LayoutOfHelpers<'tcx> for Tables<'tcx> { } } -impl<'tcx> HasParamEnv<'tcx> for Tables<'tcx> { - fn param_env(&self) -> ty::ParamEnv<'tcx> { - ty::ParamEnv::reveal_all() +impl<'tcx> HasTypingEnv<'tcx> for Tables<'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + ty::TypingEnv::fully_monomorphized() } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 820d8a6be25..fcdf8703b14 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -151,6 +151,10 @@ impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> { mir::StatementKind::ConstEvalCounter => { stable_mir::mir::StatementKind::ConstEvalCounter } + // BackwardIncompatibleDropHint has no semantics, so it is translated to Nop. + mir::StatementKind::BackwardIncompatibleDropHint { .. } => { + stable_mir::mir::StatementKind::Nop + } mir::StatementKind::Nop => stable_mir::mir::StatementKind::Nop, } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 42c6221dc57..a2d9859645f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -316,6 +316,7 @@ symbols! { SubdiagMessage, Subdiagnostic, Sync, + SyncUnsafeCell, T, Target, ToOwned, @@ -409,7 +410,6 @@ symbols! { arm, arm_target_feature, array, - as_mut_ptr, as_ptr, as_ref, as_str, @@ -589,6 +589,7 @@ symbols! { cmse_nonsecure_entry, coerce_unsized, cold, + cold_path, collapse_debuginfo, column, compare_bytes, @@ -1225,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, @@ -1653,6 +1655,7 @@ symbols! { rustc_allow_const_fn_unstable, rustc_allow_incoherent_impl, rustc_allowed_through_unstable_modules, + rustc_as_ptr, rustc_attrs, rustc_autodiff, rustc_box, @@ -1665,7 +1668,6 @@ symbols! { rustc_const_panic_str, rustc_const_stable, rustc_const_stable_indirect, - rustc_const_stable_intrinsic, rustc_const_unstable, rustc_conversion_suggestion, rustc_deallocator, @@ -1695,6 +1697,7 @@ symbols! { rustc_inherit_overflow_checks, rustc_insignificant_dtor, rustc_intrinsic, + rustc_intrinsic_const_stable_indirect, rustc_intrinsic_must_be_overridden, rustc_layout, rustc_layout_scalar_valid_range_end, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 05b4ff327a9..dcbc5f0f76d 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -26,7 +26,7 @@ pub(super) fn mangle<'tcx>( ) -> String { let def_id = instance.def_id(); // FIXME(eddyb) this should ideally not be needed. - let args = tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), instance.args); + let args = tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), instance.args); let prefix = "_R"; let mut cx: SymbolMangler<'_> = SymbolMangler { @@ -233,19 +233,20 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { let key = self.tcx.def_key(impl_def_id); let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id }; - let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id); + let mut typing_env = ty::TypingEnv::post_analysis(self.tcx, impl_def_id); if !args.is_empty() { - param_env = EarlyBinder::bind(param_env).instantiate(self.tcx, args); + typing_env.param_env = + EarlyBinder::bind(typing_env.param_env).instantiate(self.tcx, args); } match &mut impl_trait_ref { Some(impl_trait_ref) => { assert_eq!(impl_trait_ref.self_ty(), self_ty); - *impl_trait_ref = self.tcx.normalize_erasing_regions(param_env, *impl_trait_ref); + *impl_trait_ref = self.tcx.normalize_erasing_regions(typing_env, *impl_trait_ref); self_ty = impl_trait_ref.self_ty(); } None => { - self_ty = self.tcx.normalize_erasing_regions(param_env, self_ty); + self_ty = self.tcx.normalize_erasing_regions(typing_env, self_ty); } } @@ -591,7 +592,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { ct_ty.print(self)?; let mut bits = ct - .try_to_bits(self.tcx, ty::ParamEnv::reveal_all()) + .try_to_bits(self.tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected const to be monomorphic"); // Negative integer values are mangled using `n` as a "sign prefix". diff --git a/compiler/rustc_target/src/callconv/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs index 502e7331267..c99eb9226ef 100644 --- a/compiler/rustc_target/src/callconv/s390x.rs +++ b/compiler/rustc_target/src/callconv/s390x.rs @@ -1,12 +1,16 @@ -// FIXME: The assumes we're using the non-vector ABI, i.e., compiling -// for a pre-z13 machine or using -mno-vx. +// Reference: ELF Application Binary Interface s390x Supplement +// https://github.com/IBM/s390x-abi -use crate::abi::call::{ArgAbi, FnAbi, Reg}; -use crate::abi::{HasDataLayout, TyAbiInterface}; +use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind}; +use crate::abi::{BackendRepr, HasDataLayout, TyAbiInterface}; use crate::spec::HasTargetSpec; fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) { - if !ret.layout.is_aggregate() && ret.layout.size.bits() <= 64 { + let size = ret.layout.size; + if size.bits() <= 128 && matches!(ret.layout.backend_repr, BackendRepr::Vector { .. }) { + return; + } + if !ret.layout.is_aggregate() && size.bits() <= 64 { ret.extend_integer_width_to(64); } else { ret.make_indirect(); @@ -32,19 +36,25 @@ where } return; } - if !arg.layout.is_aggregate() && arg.layout.size.bits() <= 64 { + + let size = arg.layout.size; + if size.bits() <= 128 && arg.layout.is_single_vector_element(cx, size) { + arg.cast_to(Reg { kind: RegKind::Vector, size }); + return; + } + if !arg.layout.is_aggregate() && size.bits() <= 64 { arg.extend_integer_width_to(64); return; } if arg.layout.is_single_fp_element(cx) { - match arg.layout.size.bytes() { + match size.bytes() { 4 => arg.cast_to(Reg::f32()), 8 => arg.cast_to(Reg::f64()), _ => arg.make_indirect(), } } else { - match arg.layout.size.bytes() { + match size.bytes() { 1 => arg.cast_to(Reg::i8()), 2 => arg.cast_to(Reg::i16()), 4 => arg.cast_to(Reg::i32()), diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs index 3efbb464836..a84a18a433f 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs @@ -6,9 +6,6 @@ pub(crate) fn target() -> Target { base.endian = Endian::Big; // z10 is the oldest CPU supported by LLVM base.cpu = "z10".into(); - // FIXME: The ABI implementation in abi/call/s390x.rs is for now hard-coded to assume the no-vector - // ABI. Pass the -vector feature string to LLVM to respect this assumption. - base.features = "-vector".into(); base.max_atomic_width = Some(128); base.min_global_align = Some(16); base.stack_probes = StackProbeType::Inline; diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs index 65b5c1167bd..4bde0fb729c 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs @@ -6,9 +6,6 @@ pub(crate) fn target() -> Target { base.endian = Endian::Big; // z10 is the oldest CPU supported by LLVM base.cpu = "z10".into(); - // FIXME: The ABI implementation in abi/call/s390x.rs is for now hard-coded to assume the no-vector - // ABI. Pass the -vector feature string to LLVM to respect this assumption. - base.features = "-vector".into(); base.max_atomic_width = Some(128); base.min_global_align = Some(16); base.static_position_independent_executables = true; diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs index a213adadbea..a70cebbd9c8 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs @@ -5,7 +5,8 @@ use crate::spec::{ pub(crate) fn target() -> Target { // Reset flags for non-Em flavors back to empty to satisfy sanity checking tests. let pre_link_args = LinkArgs::new(); - let post_link_args = TargetOptions::link_args(LinkerFlavor::EmCc, &["-sABORTING_MALLOC=0"]); + let post_link_args = + TargetOptions::link_args(LinkerFlavor::EmCc, &["-sABORTING_MALLOC=0", "-sWASM_BIGINT"]); let opts = TargetOptions { os: "emscripten".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs index 3a3716db350..f42188ec61a 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs @@ -8,7 +8,7 @@ pub(crate) fn target() -> Target { base.vendor = "win7".into(); Target { - llvm_target: "x86_64-win7-windows-msvc".into(), + llvm_target: "x86_64-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { description: Some("64-bit Windows 7 support".into()), tier: Some(3), diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 88536926b11..112eb862663 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -598,7 +598,12 @@ const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[ const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "zvl64b"), */ (128, "v")]; // Always warn on SPARC, as the necessary target features cannot be enabled in Rust at the moment. -const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(128, "vis")*/]; +const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/]; + +const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = + &[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")]; +const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")]; +const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")]; impl super::spec::Target { pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] { @@ -620,20 +625,24 @@ impl super::spec::Target { } } - // Returns None if we do not support ABI checks on the given target yet. - pub fn features_for_correct_vector_abi(&self) -> Option<&'static [(u64, &'static str)]> { + pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] { match &*self.arch { - "x86" | "x86_64" => Some(X86_FEATURES_FOR_CORRECT_VECTOR_ABI), - "aarch64" | "arm64ec" => Some(AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI), - "arm" => Some(ARM_FEATURES_FOR_CORRECT_VECTOR_ABI), - "powerpc" | "powerpc64" => Some(POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI), - "loongarch64" => Some(&[]), // on-stack ABI, so we complain about all by-val vectors - "riscv32" | "riscv64" => Some(RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI), - "wasm32" | "wasm64" => Some(WASM_FEATURES_FOR_CORRECT_VECTOR_ABI), - "s390x" => Some(S390X_FEATURES_FOR_CORRECT_VECTOR_ABI), - "sparc" | "sparc64" => Some(SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI), - // FIXME: add support for non-tier2 architectures - _ => None, + "x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_VECTOR_ABI, + "aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI, + "arm" => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI, + "powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI, + "loongarch64" => &[], // on-stack ABI, so we complain about all by-val vectors + "riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI, + "wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI, + "s390x" => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI, + "sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI, + "hexagon" => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI, + "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI, + "bpf" => &[], // no vector ABI + "csky" => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI, + // FIXME: for some tier3 targets, we are overly cautious and always give warnings + // when passing args in vector registers. + _ => &[], } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 808e6a50d85..9a7bdaa5b57 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -528,7 +528,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // Find the method being called. let Ok(Some(instance)) = ty::Instance::try_resolve( tcx, - ctxt.param_env, + self.cx.typing_env(ctxt.param_env), ctxt.assoc_item.def_id, self.cx.resolve_vars_if_possible(ctxt.args), ) else { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 1109b11d2a7..4e7d7b79ff4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2079,7 +2079,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { cand.trait_ref = self .tcx .try_normalize_erasing_regions( - self.tcx.param_env(cand.impl_def_id), + ty::TypingEnv::non_body_analysis(self.tcx, cand.impl_def_id), cand.trait_ref, ) .unwrap_or(cand.trait_ref); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index a5e364d49f7..5ad15feadff 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1075,93 +1075,110 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> { // Autoderef is useful here because sometimes we box callables, etc. let Some((def_id_or_name, output, inputs)) = - (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| { - match *found.kind() { - ty::FnPtr(sig_tys, _) => Some(( - DefIdOrName::Name("function pointer"), - sig_tys.output(), - sig_tys.inputs(), - )), - ty::FnDef(def_id, _) => { - let fn_sig = found.fn_sig(self.tcx); - Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs())) - } - ty::Closure(def_id, args) => { - let fn_sig = args.as_closure().sig(); - Some(( - DefIdOrName::DefId(def_id), - fn_sig.output(), - fn_sig.inputs().map_bound(|inputs| &inputs[1..]), - )) - } - ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { - self.tcx - .item_super_predicates(def_id) - .instantiate(self.tcx, args) - .iter() - .find_map(|pred| { - if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() - && self.tcx.is_lang_item(proj.projection_term.def_id,LangItem::FnOnceOutput) - // args tuple will always be args[1] - && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind() - { - Some(( - DefIdOrName::DefId(def_id), - pred.kind().rebind(proj.term.expect_type()), - pred.kind().rebind(args.as_slice()), - )) - } else { - None - } - }) - } - ty::Dynamic(data, _, ty::Dyn) => { - data.iter().find_map(|pred| { - if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() + (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| match *found.kind() { + ty::FnPtr(sig_tys, _) => Some(( + DefIdOrName::Name("function pointer"), + sig_tys.output(), + sig_tys.inputs(), + )), + ty::FnDef(def_id, _) => { + let fn_sig = found.fn_sig(self.tcx); + Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs())) + } + ty::Closure(def_id, args) => { + let fn_sig = args.as_closure().sig(); + Some(( + DefIdOrName::DefId(def_id), + fn_sig.output(), + fn_sig.inputs().map_bound(|inputs| inputs[0].tuple_fields().as_slice()), + )) + } + ty::CoroutineClosure(def_id, args) => { + let sig_parts = args.as_coroutine_closure().coroutine_closure_sig(); + Some(( + DefIdOrName::DefId(def_id), + sig_parts.map_bound(|sig| { + sig.to_coroutine( + self.tcx, + args.as_coroutine_closure().parent_args(), + // Just use infer vars here, since we don't really care + // what these types are, just that we're returning a coroutine. + self.next_ty_var(DUMMY_SP), + self.tcx.coroutine_for_closure(def_id), + self.next_ty_var(DUMMY_SP), + ) + }), + sig_parts.map_bound(|sig| sig.tupled_inputs_ty.tuple_fields().as_slice()), + )) + } + ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self + .tcx + .item_super_predicates(def_id) + .instantiate(self.tcx, args) + .iter() + .find_map(|pred| { + if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() + && self + .tcx + .is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput) + // args tuple will always be args[1] + && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind() + { + Some(( + DefIdOrName::DefId(def_id), + pred.kind().rebind(proj.term.expect_type()), + pred.kind().rebind(args.as_slice()), + )) + } else { + None + } + }), + ty::Dynamic(data, _, ty::Dyn) => data.iter().find_map(|pred| { + if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() && self.tcx.is_lang_item(proj.def_id, LangItem::FnOnceOutput) // for existential projection, args are shifted over by 1 && let ty::Tuple(args) = proj.args.type_at(0).kind() - { - Some(( - DefIdOrName::Name("trait object"), - pred.rebind(proj.term.expect_type()), - pred.rebind(args.as_slice()), - )) - } else { - None - } - }) + { + Some(( + DefIdOrName::Name("trait object"), + pred.rebind(proj.term.expect_type()), + pred.rebind(args.as_slice()), + )) + } else { + None } - ty::Param(param) => { - let generics = self.tcx.generics_of(body_id); - let name = if generics.count() > param.index as usize - && let def = generics.param_at(param.index as usize, self.tcx) - && matches!(def.kind, ty::GenericParamDefKind::Type { .. }) - && def.name == param.name + }), + ty::Param(param) => { + let generics = self.tcx.generics_of(body_id); + let name = if generics.count() > param.index as usize + && let def = generics.param_at(param.index as usize, self.tcx) + && matches!(def.kind, ty::GenericParamDefKind::Type { .. }) + && def.name == param.name + { + DefIdOrName::DefId(def.def_id) + } else { + DefIdOrName::Name("type parameter") + }; + param_env.caller_bounds().iter().find_map(|pred| { + if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() + && self + .tcx + .is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput) + && proj.projection_term.self_ty() == found + // args tuple will always be args[1] + && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind() { - DefIdOrName::DefId(def.def_id) + Some(( + name, + pred.kind().rebind(proj.term.expect_type()), + pred.kind().rebind(args.as_slice()), + )) } else { - DefIdOrName::Name("type parameter") - }; - param_env.caller_bounds().iter().find_map(|pred| { - if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() - && self.tcx.is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput) - && proj.projection_term.self_ty() == found - // args tuple will always be args[1] - && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind() - { - Some(( - name, - pred.kind().rebind(proj.term.expect_type()), - pred.kind().rebind(args.as_slice()), - )) - } else { - None - } - }) - } - _ => None, + None + } + }) } + _ => None, }) else { return None; diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 8f1c8a29663..43244eb5dcb 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -32,8 +32,10 @@ impl<'tcx> InferCtxt<'tcx> { fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); + // FIXME(#132279): This should be removed as it causes us to incorrectly + // handle opaques in their defining scope. if !(param_env, ty).has_infer() { - return ty.is_copy_modulo_regions(self.tcx, param_env); + return ty.is_copy_modulo_regions(self.tcx, self.typing_env(param_env)); } let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None); diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 103f7c76a86..fac0414d714 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -9,7 +9,6 @@ use rustc_data_structures::unord::UnordSet; use rustc_infer::infer::DefineOpaqueTypes; use rustc_middle::ty::{Region, RegionVid}; use tracing::debug; -use ty::TypingMode; use super::*; use crate::errors::UnableToConstructConstantValue; @@ -71,7 +70,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { pub fn find_auto_trait_generics<A>( &self, ty: Ty<'tcx>, - orig_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, trait_did: DefId, mut auto_trait_callback: impl FnMut(AutoTraitInfo<'tcx>) -> A, ) -> AutoTraitResult<A> { @@ -79,7 +78,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { let trait_ref = ty::TraitRef::new(tcx, trait_did, [ty]); - let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); + let (infcx, orig_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); let mut selcx = SelectionContext::new(&infcx); for polarity in [ty::PredicatePolarity::Positive, ty::PredicatePolarity::Negative] { let result = selcx.select(&Obligation::new( @@ -89,17 +88,13 @@ impl<'tcx> AutoTraitFinder<'tcx> { ty::TraitPredicate { trait_ref, polarity }, )); if let Ok(Some(ImplSource::UserDefined(_))) = result { - debug!( - "find_auto_trait_generics({:?}): \ - manual impl found, bailing out", - trait_ref - ); + debug!("find_auto_trait_generics({trait_ref:?}): manual impl found, bailing out"); // If an explicit impl exists, it always takes priority over an auto impl return AutoTraitResult::ExplicitImpl; } } - let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); + let (infcx, orig_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); let mut fresh_preds = FxIndexSet::default(); // Due to the way projections are handled by SelectionContext, we need to run diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index c00246cfd7d..cf63f14fb93 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -513,7 +513,7 @@ fn check_receiver_correct<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, method: let method_def_id = method.def_id; let sig = tcx.fn_sig(method_def_id).instantiate_identity(); - let param_env = tcx.param_env(method_def_id); + let typing_env = ty::TypingEnv::non_body_analysis(tcx, method_def_id); let receiver_ty = tcx.liberate_late_bound_regions(method_def_id, sig.input(0)); if receiver_ty == tcx.types.self_param { @@ -523,7 +523,7 @@ fn check_receiver_correct<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, method: // e.g., `Rc<()>` let unit_receiver_ty = receiver_for_self_ty(tcx, receiver_ty, tcx.types.unit, method_def_id); - match tcx.layout_of(param_env.and(unit_receiver_ty)).map(|l| l.backend_repr) { + match tcx.layout_of(typing_env.as_query_input(unit_receiver_ty)).map(|l| l.backend_repr) { Ok(BackendRepr::Scalar(..)) => (), abi => { tcx.dcx().span_delayed_bug( @@ -538,7 +538,7 @@ fn check_receiver_correct<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, method: // e.g., `Rc<dyn Trait>` let trait_object_receiver = receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method_def_id); - match tcx.layout_of(param_env.and(trait_object_receiver)).map(|l| l.backend_repr) { + match tcx.layout_of(typing_env.as_query_input(trait_object_receiver)).map(|l| l.backend_repr) { Ok(BackendRepr::ScalarPair(..)) => (), abi => { tcx.dcx().span_delayed_bug( diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index fe90066b4e7..80cef690028 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -611,11 +611,12 @@ pub fn try_evaluate_const<'tcx>( // // FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All` // instead of having this logic here - let env = tcx.erase_regions(param_env).with_reveal_all_normalized(tcx); + let typing_env = + tcx.erase_regions(infcx.typing_env(param_env)).with_reveal_all_normalized(tcx); let erased_uv = tcx.erase_regions(uv); use rustc_middle::mir::interpret::ErrorHandled; - match tcx.const_eval_resolve_for_typeck(env, erased_uv, DUMMY_SP) { + match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) { Ok(Ok(val)) => Ok(ty::Const::new_value( tcx, val, @@ -697,8 +698,8 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( /// used during analysis. pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec<ty::Clause<'tcx>>) -> bool { debug!("impossible_predicates(predicates={:?})", predicates); - let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); - let param_env = ty::ParamEnv::reveal_all(); + let (infcx, param_env) = + tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized()); let ocx = ObligationCtxt::new(&infcx); let predicates = ocx.normalize(&ObligationCause::dummy(), param_env, predicates); for predicate in predicates { diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 4ff0910c9b9..1d3e8d43af7 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -144,7 +144,14 @@ pub fn compute_dropck_outlives_inner<'tcx>( result.overflows.len(), ty_stack.len() ); - dtorck_constraint_for_ty_inner(tcx, param_env, DUMMY_SP, depth, ty, &mut constraints)?; + dtorck_constraint_for_ty_inner( + tcx, + ocx.infcx.typing_env(param_env), + DUMMY_SP, + depth, + ty, + &mut constraints, + )?; // "outlives" represent types/regions that may be touched // by a destructor. @@ -196,10 +203,10 @@ pub fn compute_dropck_outlives_inner<'tcx>( /// Returns a set of constraints that needs to be satisfied in /// order for `ty` to be valid for destruction. -#[instrument(level = "debug", skip(tcx, param_env, span, constraints))] +#[instrument(level = "debug", skip(tcx, typing_env, span, constraints))] pub fn dtorck_constraint_for_ty_inner<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, span: Span, depth: usize, ty: Ty<'tcx>, @@ -234,20 +241,20 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( ty::Pat(ety, _) | ty::Array(ety, _) | ty::Slice(ety) => { // single-element containers, behave like their element rustc_data_structures::stack::ensure_sufficient_stack(|| { - dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, *ety, constraints) + dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, *ety, constraints) })?; } ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| { for ty in tys.iter() { - dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, ty, constraints)?; + dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?; } Ok::<_, NoSolution>(()) })?, ty::Closure(_, args) => rustc_data_structures::stack::ensure_sufficient_stack(|| { for ty in args.as_closure().upvar_tys() { - dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, ty, constraints)?; + dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?; } Ok::<_, NoSolution>(()) })?, @@ -257,7 +264,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( for ty in args.as_coroutine_closure().upvar_tys() { dtorck_constraint_for_ty_inner( tcx, - param_env, + typing_env, span, depth + 1, ty, @@ -296,7 +303,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // While we conservatively assume that all coroutines require drop // to avoid query cycles during MIR building, we can check the actual // witness during borrowck to avoid unnecessary liveness constraints. - if args.witness().needs_drop(tcx, tcx.erase_regions(param_env)) { + if args.witness().needs_drop(tcx, tcx.erase_regions(typing_env)) { constraints.outlives.extend(args.upvar_tys().iter().map(ty::GenericArg::from)); constraints.outlives.push(args.resume_ty().into()); } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index bf3f83ec827..345e1cc31f3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -111,8 +111,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidates_for_transmutability(obligation, &mut candidates); } else if tcx.is_lang_item(def_id, LangItem::Tuple) { self.assemble_candidate_for_tuple(obligation, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::PointerLike) { - self.assemble_candidate_for_pointer_like(obligation, &mut candidates); } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) { self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates); } else { @@ -1216,31 +1214,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - fn assemble_candidate_for_pointer_like( - &mut self, - obligation: &PolyTraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) { - // The regions of a type don't affect the size of the type - let tcx = self.tcx(); - let self_ty = tcx.instantiate_bound_regions_with_erased(obligation.predicate.self_ty()); - // We should erase regions from both the param-env and type, since both - // may have infer regions. Specifically, after canonicalizing and instantiating, - // early bound regions turn into region vars in both the new and old solver. - let key = tcx.erase_regions(obligation.param_env.and(self_ty)); - // But if there are inference variables, we have to wait until it's resolved. - if key.has_non_region_infer() { - candidates.ambiguous = true; - return; - } - - if let Ok(layout) = tcx.layout_of(key) - && layout.layout.is_pointer_like(&tcx.data_layout) - { - candidates.vec.push(BuiltinCandidate { has_nested: false }); - } - } - fn assemble_candidates_for_fn_ptr_trait( &mut self, obligation: &PolyTraitObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index bb56d6eaf54..b5bc8364c7b 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -9,8 +9,7 @@ use rustc_infer::traits::util::PredicateSet; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, - VtblEntry, + self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, Upcast, VtblEntry, }; use rustc_span::{DUMMY_SP, Span, sym}; use smallvec::{SmallVec, smallvec}; @@ -276,8 +275,10 @@ fn vtable_entries<'tcx>( // The trait type may have higher-ranked lifetimes in it; // erase them if they appear, so that we get the type // at some particular call site. - let args = - tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), args); + let args = tcx.normalize_erasing_late_bound_regions( + ty::TypingEnv::fully_monomorphized(), + args, + ); // It's possible that the method relies on where-clauses that // do not hold for this particular set of type parameters. @@ -294,7 +295,7 @@ fn vtable_entries<'tcx>( let instance = ty::Instance::expect_resolve_for_vtable( tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), def_id, args, DUMMY_SP, @@ -440,8 +441,8 @@ fn trait_refs_are_compatible<'tcx>( return false; } - let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); - let param_env = ty::ParamEnv::reveal_all(); + let (infcx, param_env) = + tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized()); let ocx = ObligationCtxt::new(&infcx); let hr_source_principal = ocx.normalize(&ObligationCause::dummy(), param_env, hr_vtable_principal); diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index d8c1c50d79a..57225df0819 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -6,7 +6,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::traits::CodegenObligationError; -use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode}; +use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeVisitableExt}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{ ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, @@ -23,14 +23,15 @@ use tracing::debug; /// This also expects that `trait_ref` is fully normalized. pub(crate) fn codegen_select_candidate<'tcx>( tcx: TyCtxt<'tcx>, - (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>), + key: PseudoCanonicalInput<'tcx, ty::TraitRef<'tcx>>, ) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> { + let PseudoCanonicalInput { typing_env, value: trait_ref } = key; // We expect the input to be fully normalized. - debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref)); + debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(typing_env, trait_ref)); // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::from_param_env(param_env)); + let (infcx, param_env) = tcx.infer_ctxt().ignoring_regions().build_with_typing_env(typing_env); let mut selcx = SelectionContext::new(&infcx); let obligation_cause = ObligationCause::dummy(); diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index 4e5309eea28..51e4dbe81b3 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -5,7 +5,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; -use rustc_middle::ty::{GenericArgs, TyCtxt}; +use rustc_middle::ty::{self, GenericArgs, TyCtxt}; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::dropck_outlives::{ compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner, @@ -35,7 +35,7 @@ pub(crate) fn adt_dtorck_constraint( ) -> Result<&DropckConstraint<'_>, NoSolution> { let def = tcx.adt_def(def_id); let span = tcx.def_span(def_id); - let param_env = tcx.param_env(def_id); + let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id); debug!("dtorck_constraint: {:?}", def); if def.is_manually_drop() { @@ -57,7 +57,7 @@ pub(crate) fn adt_dtorck_constraint( let mut result = DropckConstraint::empty(); for field in def.all_fields() { let fty = tcx.type_of(field.did).instantiate_identity(); - dtorck_constraint_for_ty_inner(tcx, param_env, span, 0, fty, &mut result)?; + dtorck_constraint_for_ty_inner(tcx, typing_env, span, 0, fty, &mut result)?; } result.outlives.extend(tcx.destructor_constraints(def)); dedup_dtorck_constraint(&mut result); diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index d79059a39a1..68ff66bbce7 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -1,7 +1,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt, TypingMode}; +use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Normalized, ObligationCause}; use tracing::debug; @@ -19,10 +19,10 @@ pub(crate) fn provide(p: &mut Providers) { fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + PartialEq + Copy>( tcx: TyCtxt<'tcx>, - goal: ParamEnvAnd<'tcx, T>, + goal: PseudoCanonicalInput<'tcx, T>, ) -> Result<T, NoSolution> { - let ParamEnvAnd { param_env, value } = goal; - let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); + let PseudoCanonicalInput { typing_env, value } = goal; + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); let cause = ObligationCause::dummy(); match infcx.at(&cause, param_env).query_normalize(value) { Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => { diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 9dabcea706f..023c8fad781 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -31,7 +31,7 @@ where #[cfg(feature = "rustc")] mod rustc { use rustc_middle::ty::layout::LayoutCx; - use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; + use rustc_middle::ty::{Ty, TyCtxt, TypingEnv}; use super::*; use crate::layout::tree::rustc::Err; @@ -43,7 +43,7 @@ mod rustc { pub(crate) fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> { let Self { src, dst, assume, context } = self; - let layout_cx = LayoutCx::new(context, ParamEnv::reveal_all()); + let layout_cx = LayoutCx::new(context, TypingEnv::fully_monomorphized()); // Convert `src` and `dst` from their rustc representations, to `Tree`-based // representations. diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 0184e93acf1..a5a9125c8b5 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -7,7 +7,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ - FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout, fn_can_unwind, + FnAbiError, HasTyCtxt, HasTypingEnv, LayoutCx, LayoutOf, TyAndLayout, fn_can_unwind, }; use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt}; use rustc_session::config::OptLevel; @@ -26,11 +26,11 @@ pub(crate) fn provide(providers: &mut Providers) { // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead), // or should go through `FnAbi` instead, to avoid losing any // adjustments `fn_abi_of_instance` might be performing. -#[tracing::instrument(level = "debug", skip(tcx, param_env))] +#[tracing::instrument(level = "debug", skip(tcx, typing_env))] fn fn_sig_for_fn_abi<'tcx>( tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> ty::PolyFnSig<'tcx> { if let InstanceKind::ThreadLocalShim(..) = instance.def { return ty::Binder::dummy(tcx.mk_fn_sig( @@ -42,7 +42,7 @@ fn fn_sig_for_fn_abi<'tcx>( )); } - let ty = instance.ty(tcx, param_env); + let ty = instance.ty(tcx, typing_env); match *ty.kind() { ty::FnDef(..) => { // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering @@ -56,7 +56,10 @@ fn fn_sig_for_fn_abi<'tcx>( ty::FnDef(def_id, args) => tcx .fn_sig(def_id) .map_bound(|fn_sig| { - tcx.normalize_erasing_regions(tcx.param_env(def_id), fn_sig) + tcx.normalize_erasing_regions( + ty::TypingEnv::non_body_analysis(tcx, def_id), + fn_sig, + ) }) .instantiate(tcx, args), _ => unreachable!(), @@ -329,27 +332,26 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: ExternAbi, c_variadic: bool) -> Conv fn fn_abi_of_fn_ptr<'tcx>( tcx: TyCtxt<'tcx>, - query: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>, + query: ty::PseudoCanonicalInput<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>, ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> { - let (param_env, (sig, extra_args)) = query.into_parts(); - - let cx = LayoutCx::new(tcx, param_env); + let ty::PseudoCanonicalInput { typing_env, value: (sig, extra_args) } = query; + let cx = LayoutCx::new(tcx, typing_env); fn_abi_new_uncached(&cx, sig, extra_args, None, None, false) } fn fn_abi_of_instance<'tcx>( tcx: TyCtxt<'tcx>, - query: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>, + query: ty::PseudoCanonicalInput<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>, ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> { - let (param_env, (instance, extra_args)) = query.into_parts(); + let ty::PseudoCanonicalInput { typing_env, value: (instance, extra_args) } = query; - let sig = fn_sig_for_fn_abi(tcx, instance, param_env); + let sig = fn_sig_for_fn_abi(tcx, instance, typing_env); let caller_location = instance.def.requires_caller_location(tcx).then(|| tcx.caller_location_ty()); fn_abi_new_uncached( - &LayoutCx::new(tcx, param_env), + &LayoutCx::new(tcx, typing_env), sig, extra_args, caller_location, @@ -395,7 +397,7 @@ fn adjust_for_rust_scalar<'tcx>( Some(kind) } else if let Some(pointee) = drop_target_pointee { // The argument to `drop_in_place` is semantically equivalent to a mutable reference. - Some(PointerKind::MutableRef { unpin: pointee.is_unpin(tcx, cx.param_env()) }) + Some(PointerKind::MutableRef { unpin: pointee.is_unpin(tcx, cx.typing_env) }) } else { None }; @@ -542,7 +544,7 @@ fn fn_abi_sanity_check<'tcx>( // With metadata. Must be unsized and not on the stack. assert!(arg.layout.is_unsized() && !on_stack); // Also, must not be `extern` type. - let tail = tcx.struct_tail_for_codegen(arg.layout.ty, cx.param_env()); + let tail = tcx.struct_tail_for_codegen(arg.layout.ty, cx.typing_env); if matches!(tail.kind(), ty::Foreign(..)) { // These types do not have metadata, so having `meta_attrs` is bogus. // Conceptually, unsized arguments must be copied around, which requires dynamically @@ -573,7 +575,7 @@ fn fn_abi_new_uncached<'tcx>( force_thin_self_ptr: bool, ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> { let tcx = cx.tcx(); - let sig = tcx.normalize_erasing_late_bound_regions(cx.param_env, sig); + let sig = tcx.normalize_erasing_late_bound_regions(cx.typing_env, sig); let conv = conv_from_spec_abi(cx.tcx(), sig.abi, sig.c_variadic); @@ -744,7 +746,7 @@ fn fn_abi_adjust_for_abi<'tcx>( #[tracing::instrument(level = "debug", skip(cx))] fn make_thin_self_ptr<'tcx>( - cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>), + cx: &(impl HasTyCtxt<'tcx> + HasTypingEnv<'tcx>), layout: TyAndLayout<'tcx>, ) -> TyAndLayout<'tcx> { let tcx = cx.tcx(); @@ -784,6 +786,6 @@ fn make_thin_self_ptr<'tcx>( // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing the `Result` // should always work because the type is always `*mut ()`. - ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap() + ..tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(unit_ptr_ty)).unwrap() } } diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index c26b41d8960..2157ab3c402 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -3,34 +3,33 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_trait_selection::traits; -fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { +fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { is_item_raw(tcx, query, LangItem::Copy) } -fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { +fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { is_item_raw(tcx, query, LangItem::Sized) } -fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { +fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { is_item_raw(tcx, query, LangItem::Freeze) } -fn is_unpin_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { +fn is_unpin_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { is_item_raw(tcx, query, LangItem::Unpin) } fn is_item_raw<'tcx>( tcx: TyCtxt<'tcx>, - query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, + query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>, item: LangItem, ) -> bool { - let (param_env, ty) = query.into_parts(); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(query.typing_env); let trait_def_id = tcx.require_lang_item(item, None); - let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); - traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id) + traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, query.value, trait_def_id) } pub(crate) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 1d8a0880760..29fc92e1f2f 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -6,29 +6,31 @@ use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError}; use rustc_middle::ty::util::AsyncDropGlueMorphology; -use rustc_middle::ty::{self, GenericArgsRef, Instance, TyCtxt, TypeVisitableExt, TypingMode}; +use rustc_middle::ty::{ + self, GenericArgsRef, Instance, PseudoCanonicalInput, TyCtxt, TypeVisitableExt, +}; use rustc_span::sym; use rustc_trait_selection::traits; use rustc_type_ir::ClosureKind; use tracing::debug; -use traits::{Reveal, translate_args}; +use traits::translate_args; use crate::errors::UnexpectedFnPtrAssociatedItem; fn resolve_instance_raw<'tcx>( tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)>, + key: ty::PseudoCanonicalInput<'tcx, (DefId, GenericArgsRef<'tcx>)>, ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> { - let (param_env, (def_id, args)) = key.into_parts(); + let PseudoCanonicalInput { typing_env, value: (def_id, args) } = key; let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { - debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env); + debug!(" => associated item, attempting to find impl in typing_env {:#?}", typing_env); resolve_associated_item( tcx, def_id, - param_env, + typing_env, trait_def_id, - tcx.normalize_erasing_regions(param_env, args), + tcx.normalize_erasing_regions(typing_env, args), ) } else { let def = if tcx.intrinsic(def_id).is_some() { @@ -37,7 +39,7 @@ fn resolve_instance_raw<'tcx>( } else if tcx.is_lang_item(def_id, LangItem::DropInPlace) { let ty = args.type_at(0); - if ty.needs_drop(tcx, param_env) { + if ty.needs_drop(tcx, typing_env) { debug!(" => nontrivial drop glue"); match *ty.kind() { ty::Closure(..) @@ -93,15 +95,16 @@ fn resolve_instance_raw<'tcx>( fn resolve_associated_item<'tcx>( tcx: TyCtxt<'tcx>, trait_item_id: DefId, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, trait_id: DefId, rcvr_args: GenericArgsRef<'tcx>, ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> { - debug!(?trait_item_id, ?param_env, ?trait_id, ?rcvr_args, "resolve_associated_item"); + debug!(?trait_item_id, ?typing_env, ?trait_id, ?rcvr_args, "resolve_associated_item"); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_args); - let vtbl = match tcx.codegen_select_candidate((param_env, trait_ref)) { + let input = typing_env.as_query_input(trait_ref); + let vtbl = match tcx.codegen_select_candidate(input) { Ok(vtbl) => vtbl, Err( CodegenObligationError::Ambiguity @@ -116,7 +119,7 @@ fn resolve_associated_item<'tcx>( traits::ImplSource::UserDefined(impl_data) => { debug!( "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}", - param_env, trait_item_id, rcvr_args, impl_data + typing_env, trait_item_id, rcvr_args, impl_data ); assert!(!rcvr_args.has_infer()); assert!(!trait_ref.has_infer()); @@ -129,17 +132,6 @@ fn resolve_associated_item<'tcx>( .unwrap_or_else(|| { bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id); }); - let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); - let param_env = param_env.with_reveal_all_normalized(tcx); - let args = rcvr_args.rebase_onto(tcx, trait_def_id, impl_data.args); - let args = translate_args( - &infcx, - param_env, - impl_data.impl_def_id, - args, - leaf_def.defining_node, - ); - let args = infcx.tcx.erase_regions(args); // Since this is a trait item, we need to see if the item is either a trait default item // or a specialization because we can't resolve those unless we can `Reveal::All`. @@ -153,16 +145,28 @@ fn resolve_associated_item<'tcx>( // and the obligation is monomorphic, otherwise passes such as // transmute checking and polymorphic MIR optimizations could // get a result which isn't correct for all monomorphizations. - if param_env.reveal() == Reveal::All { - !trait_ref.still_further_specializable() - } else { - false + match typing_env.typing_mode { + ty::TypingMode::Coherence + | ty::TypingMode::Analysis { defining_opaque_types: _ } => false, + ty::TypingMode::PostAnalysis => !trait_ref.still_further_specializable(), } }; if !eligible { return Ok(None); } + let typing_env = typing_env.with_reveal_all_normalized(tcx); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + let args = rcvr_args.rebase_onto(tcx, trait_def_id, impl_data.args); + let args = translate_args( + &infcx, + param_env, + impl_data.impl_def_id, + args, + leaf_def.defining_node, + ); + let args = infcx.tcx.erase_regions(args); + // HACK: We may have overlapping `dyn Trait` built-in impls and // user-provided blanket impls. Detect that case here, and return // ambiguity. diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 63421dfdce6..092e140a600 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -19,7 +19,8 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, AdtDef, CoroutineArgsExt, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, + self, AdtDef, CoroutineArgsExt, EarlyBinder, GenericArgsRef, PseudoCanonicalInput, Ty, TyCtxt, + TypeVisitableExt, }; use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use rustc_span::sym; @@ -40,22 +41,22 @@ pub(crate) fn provide(providers: &mut Providers) { #[instrument(skip(tcx, query), level = "debug")] fn layout_of<'tcx>( tcx: TyCtxt<'tcx>, - query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, + query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>, ) -> Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>> { - let (param_env, ty) = query.into_parts(); + let PseudoCanonicalInput { typing_env, value: ty } = query; debug!(?ty); // Optimization: We convert to RevealAll and convert opaque types in the where bounds // to their hidden types. This reduces overall uncached invocations of `layout_of` and // is thus a small performance improvement. - let param_env = param_env.with_reveal_all_normalized(tcx); + let typing_env = typing_env.with_reveal_all_normalized(tcx); let unnormalized_ty = ty; // FIXME: We might want to have two different versions of `layout_of`: // One that can be called after typecheck has completed and can use // `normalize_erasing_regions` here and another one that can be called // before typecheck has completed and uses `try_normalize_erasing_regions`. - let ty = match tcx.try_normalize_erasing_regions(param_env, ty) { + let ty = match tcx.try_normalize_erasing_regions(typing_env, ty) { Ok(t) => t, Err(normalization_error) => { return Err(tcx @@ -66,10 +67,10 @@ fn layout_of<'tcx>( if ty != unnormalized_ty { // Ensure this layout is also cached for the normalized type. - return tcx.layout_of(param_env.and(ty)); + return tcx.layout_of(typing_env.as_query_input(ty)); } - let cx = LayoutCx::new(tcx, param_env); + let cx = LayoutCx::new(tcx, typing_env); let layout = layout_of_uncached(&cx, ty)?; let layout = TyAndLayout { ty, layout }; @@ -104,7 +105,7 @@ fn map_error<'tcx>( // This is sometimes not a compile error if there are trivially false where clauses. // See `tests/ui/layout/trivial-bounds-sized.rs` for an example. assert!(field.layout.is_unsized(), "invalid layout error {err:#?}"); - if !field.ty.is_sized(cx.tcx(), cx.param_env) { + if !field.ty.is_sized(cx.tcx(), cx.typing_env) { cx.tcx().dcx().delayed_bug(format!( "encountered unexpected unsized field in layout of {ty:?}: {field:#?}" )); @@ -152,7 +153,6 @@ fn layout_of_uncached<'tcx>( } let tcx = cx.tcx(); - let param_env = cx.param_env; let dl = cx.data_layout(); let scalar_unit = |value: Primitive| { let size = value.size(dl); @@ -178,12 +178,12 @@ fn layout_of_uncached<'tcx>( { if let Some(start) = start { scalar.valid_range_mut().start = start - .try_to_bits(tcx, param_env) + .try_to_bits(tcx, cx.typing_env) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; } if let Some(end) = end { let mut end = end - .try_to_bits(tcx, param_env) + .try_to_bits(tcx, cx.typing_env) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; if !include_end { end = end.wrapping_sub(1); @@ -235,8 +235,8 @@ fn layout_of_uncached<'tcx>( data_ptr.valid_range_mut().start = 1; } - let pointee = tcx.normalize_erasing_regions(param_env, pointee); - if pointee.is_sized(tcx, param_env) { + let pointee = tcx.normalize_erasing_regions(cx.typing_env, pointee); + if pointee.is_sized(tcx, cx.typing_env) { return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr))); } @@ -247,7 +247,7 @@ fn layout_of_uncached<'tcx>( { let pointee_metadata = Ty::new_projection(tcx, metadata_def_id, [pointee]); let metadata_ty = - match tcx.try_normalize_erasing_regions(param_env, pointee_metadata) { + match tcx.try_normalize_erasing_regions(cx.typing_env, pointee_metadata) { Ok(metadata_ty) => metadata_ty, Err(mut err) => { // Usually `<Ty as Pointee>::Metadata` can't be normalized because @@ -259,7 +259,7 @@ fn layout_of_uncached<'tcx>( // that is an alias, which is likely the cause of the normalization // error. match tcx.try_normalize_erasing_regions( - param_env, + cx.typing_env, tcx.struct_tail_raw(pointee, |ty| ty, || {}), ) { Ok(_) => {} @@ -283,7 +283,7 @@ fn layout_of_uncached<'tcx>( metadata } else { - let unsized_part = tcx.struct_tail_for_codegen(pointee, param_env); + let unsized_part = tcx.struct_tail_for_codegen(pointee, cx.typing_env); match unsized_part.kind() { ty::Foreign(..) => { @@ -316,7 +316,7 @@ fn layout_of_uncached<'tcx>( // Arrays and slices. ty::Array(element, mut count) => { if count.has_aliases() { - count = tcx.normalize_erasing_regions(param_env, count); + count = tcx.normalize_erasing_regions(cx.typing_env, count); if count.has_aliases() { return Err(error(cx, LayoutError::Unknown(ty))); } @@ -331,7 +331,7 @@ fn layout_of_uncached<'tcx>( .checked_mul(count, dl) .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?; - let abi = if count != 0 && ty.is_privately_uninhabited(tcx, param_env) { + let abi = if count != 0 && ty.is_privately_uninhabited(tcx, cx.typing_env) { BackendRepr::Uninhabited } else { BackendRepr::Memory { sized: true } @@ -594,8 +594,8 @@ fn layout_of_uncached<'tcx>( let maybe_unsized = def.is_struct() && def.non_enum_variant().tail_opt().is_some_and(|last_field| { - let param_env = tcx.param_env(def.did()); - !tcx.type_of(last_field.did).instantiate_identity().is_sized(tcx, param_env) + let typing_env = ty::TypingEnv::post_analysis(tcx, def.did()); + !tcx.type_of(last_field.did).instantiate_identity().is_sized(tcx, typing_env) }); let layout = cx @@ -620,7 +620,7 @@ fn layout_of_uncached<'tcx>( // If the struct tail is sized and can be unsized, check that unsizing doesn't move the fields around. if cfg!(debug_assertions) && maybe_unsized - && def.non_enum_variant().tail().ty(tcx, args).is_sized(tcx, cx.param_env) + && def.non_enum_variant().tail().ty(tcx, args).is_sized(tcx, cx.typing_env) { let mut variants = variants; let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap(); @@ -1024,7 +1024,7 @@ fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx>, layout: TyAndLayout<'tc // Ignore layouts that are done with non-empty environments or // non-monomorphic layouts, as the user only wants to see the stuff // resulting from the final codegen session. - if layout.ty.has_non_region_param() || !cx.param_env.caller_bounds().is_empty() { + if layout.ty.has_non_region_param() || !cx.typing_env.param_env.caller_bounds().is_empty() { return; } diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index fc05dd8256b..26ea81daf78 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -9,7 +9,7 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa let tcx = cx.tcx(); // Type-level uninhabitedness should always imply ABI uninhabitedness. - if layout.ty.is_privately_uninhabited(tcx, cx.param_env) { + if layout.ty.is_privately_uninhabited(tcx, cx.typing_env) { assert!(layout.is_uninhabited()); } diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 5fecbd310b7..469a4ac3e41 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -8,20 +8,23 @@ use rustc_middle::ty::util::{AlwaysRequiresDrop, needs_drop_components}; use rustc_middle::ty::{self, EarlyBinder, GenericArgsRef, Ty, TyCtxt}; use rustc_session::Limit; use rustc_span::sym; -use tracing::debug; +use tracing::{debug, instrument}; use crate::errors::NeedsDropOverflow; type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>; -fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { +fn needs_drop_raw<'tcx>( + tcx: TyCtxt<'tcx>, + query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>, +) -> bool { // If we don't know a type doesn't need drop, for example if it's a type // parameter without a `Copy` bound, then we conservatively return that it // needs drop. let adt_has_dtor = |adt_def: ty::AdtDef<'tcx>| adt_def.destructor(tcx).map(|_| DtorType::Significant); - let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor, false) - .filter(filter_array_elements(tcx, query.param_env)) + let res = drop_tys_helper(tcx, query.value, query.typing_env, adt_has_dtor, false, false) + .filter(filter_array_elements(tcx, query.typing_env)) .next() .is_some(); @@ -29,14 +32,17 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx> res } -fn needs_async_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { +fn needs_async_drop_raw<'tcx>( + tcx: TyCtxt<'tcx>, + query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>, +) -> bool { // If we don't know a type doesn't need async drop, for example if it's a // type parameter without a `Copy` bound, then we conservatively return that // it needs async drop. let adt_has_async_dtor = |adt_def: ty::AdtDef<'tcx>| adt_def.async_destructor(tcx).map(|_| DtorType::Significant); - let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_async_dtor, false) - .filter(filter_array_elements(tcx, query.param_env)) + let res = drop_tys_helper(tcx, query.value, query.typing_env, adt_has_async_dtor, false, false) + .filter(filter_array_elements(tcx, query.typing_env)) .next() .is_some(); @@ -50,11 +56,11 @@ fn needs_async_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty /// logic that is easier to follow while not repeating any checks that may thus diverge. fn filter_array_elements<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> impl Fn(&Result<Ty<'tcx>, AlwaysRequiresDrop>) -> bool { move |ty| match ty { Ok(ty) => match *ty.kind() { - ty::Array(elem, _) => tcx.needs_drop_raw(param_env.and(elem)), + ty::Array(elem, _) => tcx.needs_drop_raw(typing_env.as_query_input(elem)), _ => true, }, Err(AlwaysRequiresDrop) => true, @@ -63,16 +69,17 @@ fn filter_array_elements<'tcx>( fn has_significant_drop_raw<'tcx>( tcx: TyCtxt<'tcx>, - query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, + query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>, ) -> bool { let res = drop_tys_helper( tcx, query.value, - query.param_env, + query.typing_env, adt_consider_insignificant_dtor(tcx), true, + false, ) - .filter(filter_array_elements(tcx, query.param_env)) + .filter(filter_array_elements(tcx, query.typing_env)) .next() .is_some(); debug!("has_significant_drop_raw({:?}) = {:?}", query, res); @@ -81,9 +88,9 @@ fn has_significant_drop_raw<'tcx>( struct NeedsDropTypes<'tcx, F> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - // Whether to reveal coroutine witnesses, this is set - // to `false` unless we compute `needs_drop` for a coroutine witness. + typing_env: ty::TypingEnv<'tcx>, + /// Whether to reveal coroutine witnesses, this is set + /// to `false` unless we compute `needs_drop` for a coroutine witness. reveal_coroutine_witnesses: bool, query_ty: Ty<'tcx>, seen_tys: FxHashSet<Ty<'tcx>>, @@ -94,28 +101,40 @@ struct NeedsDropTypes<'tcx, F> { unchecked_tys: Vec<(Ty<'tcx>, usize)>, recursion_limit: Limit, adt_components: F, + /// Set this to true if an exhaustive list of types involved in + /// drop obligation is requested. + exhaustive: bool, } impl<'tcx, F> NeedsDropTypes<'tcx, F> { fn new( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, + exhaustive: bool, adt_components: F, ) -> Self { let mut seen_tys = FxHashSet::default(); seen_tys.insert(ty); Self { tcx, - param_env, - reveal_coroutine_witnesses: false, + typing_env, + reveal_coroutine_witnesses: exhaustive, seen_tys, query_ty: ty, unchecked_tys: vec![(ty, 0)], recursion_limit: tcx.recursion_limit(), adt_components, + exhaustive, } } + + /// Called when `ty` is found to always require drop. + /// If the exhaustive flag is true, then `Ok(ty)` is returned like any other type. + /// Otherwise, `Err(AlwaysRequireDrop)` is returned, which will cause iteration to abort. + fn always_drop_component(&self, ty: Ty<'tcx>) -> NeedsDropResult<Ty<'tcx>> { + if self.exhaustive { Ok(ty) } else { Err(AlwaysRequiresDrop) } + } } impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> @@ -125,19 +144,22 @@ where { type Item = NeedsDropResult<Ty<'tcx>>; + #[instrument(level = "debug", skip(self), ret)] fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> { let tcx = self.tcx; while let Some((ty, level)) = self.unchecked_tys.pop() { + debug!(?ty, "needs_drop_components: inspect"); if !self.recursion_limit.value_within_limit(level) { // Not having a `Span` isn't great. But there's hopefully some other // recursion limit error as well. + debug!("needs_drop_components: recursion limit exceeded"); tcx.dcx().emit_err(NeedsDropOverflow { query_ty: self.query_ty }); - return Some(Err(AlwaysRequiresDrop)); + return Some(self.always_drop_component(ty)); } let components = match needs_drop_components(tcx, ty) { - Err(e) => return Some(Err(e)), + Err(AlwaysRequiresDrop) => return Some(self.always_drop_component(ty)), Ok(components) => components, }; debug!("needs_drop_components({:?}) = {:?}", ty, components); @@ -165,7 +187,7 @@ where if self.reveal_coroutine_witnesses { queue_type(self, args.as_coroutine().witness()); } else { - return Some(Err(AlwaysRequiresDrop)); + return Some(self.always_drop_component(ty)); } } ty::CoroutineWitness(def_id, args) => { @@ -180,7 +202,7 @@ where } } - _ if component.is_copy_modulo_regions(tcx, self.param_env) => (), + _ if component.is_copy_modulo_regions(tcx, self.typing_env) => {} ty::Closure(_, args) => { for upvar in args.as_closure().upvar_tys() { @@ -199,12 +221,14 @@ where // impl then check whether the field types need `Drop`. ty::Adt(adt_def, args) => { let tys = match (self.adt_components)(adt_def, args) { - Err(e) => return Some(Err(e)), + Err(AlwaysRequiresDrop) => { + return Some(self.always_drop_component(ty)); + } Ok(tys) => tys, }; for required_ty in tys { let required = tcx - .try_normalize_erasing_regions(self.param_env, required_ty) + .try_normalize_erasing_regions(self.typing_env, required_ty) .unwrap_or(required_ty); queue_type(self, required); @@ -224,7 +248,8 @@ where } ty::Foreign(_) | ty::Dynamic(..) => { - return Some(Err(AlwaysRequiresDrop)); + debug!("needs_drop_components: foreign or dynamic"); + return Some(self.always_drop_component(ty)); } ty::Bool @@ -271,9 +296,10 @@ enum DtorType { fn drop_tys_helper<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, - param_env: rustc_middle::ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, adt_has_dtor: impl Fn(ty::AdtDef<'tcx>) -> Option<DtorType>, only_significant: bool, + exhaustive: bool, ) -> impl Iterator<Item = NeedsDropResult<Ty<'tcx>>> { fn with_query_cache<'tcx>( tcx: TyCtxt<'tcx>, @@ -337,7 +363,7 @@ fn drop_tys_helper<'tcx>( .map(|v| v.into_iter()) }; - NeedsDropTypes::new(tcx, param_env, ty, adt_components) + NeedsDropTypes::new(tcx, typing_env, ty, exhaustive, adt_components) } fn adt_consider_insignificant_dtor<'tcx>( @@ -375,9 +401,10 @@ fn adt_drop_tys<'tcx>( drop_tys_helper( tcx, tcx.type_of(def_id).instantiate_identity(), - tcx.param_env(def_id), + ty::TypingEnv::non_body_analysis(tcx, def_id), adt_has_dtor, false, + false, ) .collect::<Result<Vec<_>, _>>() .map(|components| tcx.mk_type_list(&components)) @@ -392,14 +419,34 @@ fn adt_significant_drop_tys( drop_tys_helper( tcx, tcx.type_of(def_id).instantiate_identity(), // identical to `tcx.make_adt(def, identity_args)` - tcx.param_env(def_id), + ty::TypingEnv::non_body_analysis(tcx, def_id), adt_consider_insignificant_dtor(tcx), true, + false, ) .collect::<Result<Vec<_>, _>>() .map(|components| tcx.mk_type_list(&components)) } +#[instrument(level = "debug", skip(tcx), ret)] +fn list_significant_drop_tys<'tcx>( + tcx: TyCtxt<'tcx>, + ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, +) -> &'tcx ty::List<Ty<'tcx>> { + tcx.mk_type_list( + &drop_tys_helper( + tcx, + ty.value, + ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env: ty.param_env }, + adt_consider_insignificant_dtor(tcx), + true, + true, + ) + .filter_map(|res| res.ok()) + .collect::<Vec<_>>(), + ) +} + pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { needs_drop_raw, @@ -407,6 +454,7 @@ pub(crate) fn provide(providers: &mut Providers) { has_significant_drop_raw, adt_drop_tys, adt_significant_drop_tys, + list_significant_drop_tys, ..*providers }; } diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 3fbce7886ed..2c1ad9de9aa 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -157,7 +157,7 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> { } // `T: ~const Trait` implies `T: ~const Supertrait`. ty::ClauseKind::HostEffect(data) => self.extend_deduped( - cx.implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| { + cx.explicit_implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| { elaboratable.child( trait_ref .to_host_effect_clause(cx, data.constness) diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index aadb64f45d7..b01d3dc5269 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -1,12 +1,11 @@ use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use crate::fold::TypeFoldable; -use crate::inherent::*; use crate::relate::RelateResult; use crate::relate::combine::PredicateEmittingRelation; -use crate::solve::Reveal; use crate::{self as ty, Interner}; /// The current typing mode of an inference context. We unfortunately have some @@ -20,6 +19,7 @@ use crate::{self as ty, Interner}; /// If neither of these functions are available, feel free to reach out to /// t-types for help. #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum TypingMode<I: Interner> { /// When checking whether impls overlap, we check whether any obligations @@ -56,18 +56,6 @@ impl<I: Interner> TypingMode<I> { pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> { TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) } } - - /// FIXME(#132279): Using this function is questionable as the `param_env` - /// does not track `defining_opaque_types` and whether we're in coherence mode. - /// Many uses of this function should also use a not-yet implemented typing mode - /// which reveals already defined opaque types in the future. This function will - /// get completely removed at some point. - pub fn from_param_env(param_env: I::ParamEnv) -> TypingMode<I> { - match param_env.reveal() { - Reveal::UserFacing => TypingMode::non_body_analysis(), - Reveal::All => TypingMode::PostAnalysis, - } - } } pub trait InferCtxtLike: Sized { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 36ddddccfa2..93b9c2e2892 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -223,12 +223,13 @@ pub trait Interner: def_id: Self::DefId, ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>>; - fn is_const_impl(self, def_id: Self::DefId) -> bool; + fn impl_is_const(self, def_id: Self::DefId) -> bool; + fn fn_is_const(self, def_id: Self::DefId) -> bool; fn const_conditions( self, def_id: Self::DefId, ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>; - fn implied_const_bounds( + fn explicit_implied_const_bounds( self, def_id: Self::DefId, ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>; @@ -277,8 +278,6 @@ pub trait Interner: fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool; fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool; - fn layout_is_pointer_like(self, param_env: Self::ParamEnv, ty: Self::Ty) -> bool; - type UnsizingParams: Deref<Target = BitSet<u32>>; fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams; diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index d6ca22a90a4..df43346065d 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -31,7 +31,6 @@ pub enum TraitSolverLangItem { Metadata, Option, PointeeTrait, - PointerLike, Poll, Sized, TransmuteTrait, diff --git a/config.example.toml b/config.example.toml index 9dc71b10f70..d3233ad17b5 100644 --- a/config.example.toml +++ b/config.example.toml @@ -81,7 +81,7 @@ # Indicates whether the LLVM plugin is enabled or not #plugins = false -# Wheter to build Enzyme as AutoDiff backend. +# Whether to build Enzyme as AutoDiff backend. #enzyme = false # Whether to build LLVM with support for it's gpu offload runtime. diff --git a/library/Cargo.lock b/library/Cargo.lock index 70ecac4e17c..97996d5f0b2 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.161" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" dependencies = [ "rustc-std-workspace-core", ] diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index bb6dd1d2d30..ee60ec0fbac 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -191,6 +191,8 @@ use core::error::{self, Error}; use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; +#[cfg(not(bootstrap))] +use core::marker::PointerLike; use core::marker::{Tuple, Unsize}; use core::mem::{self, SizedTypeProperties}; use core::ops::{ @@ -1500,6 +1502,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { /// [`as_ptr`]: Self::as_ptr #[unstable(feature = "box_as_ptr", issue = "129090")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub fn as_mut_ptr(b: &mut Self) -> *mut T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing @@ -1548,6 +1551,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { /// [`as_ptr`]: Self::as_ptr #[unstable(feature = "box_as_ptr", issue = "129090")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub fn as_ptr(b: &Self) -> *const T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing @@ -2129,3 +2133,7 @@ impl<E: Error> Error for Box<E> { Error::provide(&**self, request); } } + +#[cfg(not(bootstrap))] +#[unstable(feature = "pointer_like_trait", issue = "none")] +impl<T> PointerLike for Box<T> {} 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..041ff37897f 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -136,6 +136,7 @@ #![feature(panic_internals)] #![feature(pattern)] #![feature(pin_coerce_unsized_trait)] +#![feature(pointer_like_trait)] #![feature(ptr_internals)] #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] @@ -143,6 +144,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/alloc/src/string.rs b/library/alloc/src/string.rs index b042720933b..e0576c25515 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -116,7 +116,7 @@ use crate::vec::Vec; /// `String`s are always valid UTF-8. If you need a non-UTF-8 string, consider /// [`OsString`]. It is similar, but without the UTF-8 constraint. Because UTF-8 /// is a variable width encoding, `String`s are typically smaller than an array of -/// the same `chars`: +/// the same `char`s: /// /// ``` /// use std::mem; diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 07a1bd49321..990b7e8f761 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1662,6 +1662,7 @@ impl<T, A: Allocator> Vec<T, A> { #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub const fn as_ptr(&self) -> *const T { // We shadow the slice method of the same name to avoid going through @@ -1724,6 +1725,7 @@ impl<T, A: Allocator> Vec<T, A> { #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub const fn as_mut_ptr(&mut self) -> *mut T { // We shadow the slice method of the same name to avoid going through diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 1a461987c76..bfd2a71f97b 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -587,6 +587,7 @@ impl<T: ?Sized> Cell<T> { #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] #[rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *mut T { self.value.get() @@ -1149,6 +1150,7 @@ impl<T: ?Sized> RefCell<T> { /// ``` #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub fn as_ptr(&self) -> *mut T { self.value.get() @@ -2158,6 +2160,7 @@ impl<T: ?Sized> UnsafeCell<T> { #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn get(&self) -> *mut T { // We can just cast the pointer from `UnsafeCell<T>` to `T` because of @@ -2271,6 +2274,7 @@ impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> /// See [`UnsafeCell`] for details. #[unstable(feature = "sync_unsafe_cell", issue = "95439")] #[repr(transparent)] +#[rustc_diagnostic_item = "SyncUnsafeCell"] #[rustc_pub_transparent] pub struct SyncUnsafeCell<T: ?Sized> { value: UnsafeCell<T>, @@ -2304,6 +2308,7 @@ impl<T: ?Sized> SyncUnsafeCell<T> { /// when casting to `&mut T`, and ensure that there are no mutations /// or mutable aliases going on when casting to `&T` #[inline] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn get(&self) -> *mut T { self.value.get() diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 85571222b5c..9e32f74227c 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -500,6 +500,7 @@ impl CStr { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *const c_char { self.inner.as_ptr() diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 72e34e5faf5..e9859a58696 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -15,7 +15,7 @@ //! and make the intrinsic declaration a `const fn`. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, -//! `#[rustc_const_stable_intrinsic]` needs to be added to the intrinsic. Such a change requires +//! `#[rustc_intrinsic_const_stable_indirect]` needs to be added to the intrinsic. Such a change requires //! T-lang approval, because it may bake a feature into the language that cannot be replicated in //! user code without compiler support. //! @@ -1435,7 +1435,7 @@ pub fn abort() -> ! { bootstrap, rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0") )] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1454,7 +1454,7 @@ pub const unsafe fn unreachable() -> ! { /// /// The stabilized version of this intrinsic is [`core::hint::assert_unchecked`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assume", since = "1.77.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] @@ -1465,6 +1465,22 @@ pub const unsafe fn assume(b: bool) { } } +/// Hints to the compiler that current code path is cold. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// This intrinsic does not have a stable counterpart. +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[cfg(not(bootstrap))] +#[rustc_nounwind] +#[miri::intrinsic_fallback_is_spec] +#[cold] +pub const fn cold_path() {} + /// Hints to the compiler that branch condition is likely to be true. /// Returns the value passed to it. /// @@ -1480,13 +1496,21 @@ pub const unsafe fn assume(b: bool) { bootstrap, rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") )] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_intrinsic] #[rustc_nounwind] -#[miri::intrinsic_fallback_is_spec] +#[inline(always)] pub const fn likely(b: bool) -> bool { - b + #[cfg(bootstrap)] + { + b + } + #[cfg(not(bootstrap))] + if b { + true + } else { + cold_path(); + false + } } /// Hints to the compiler that branch condition is likely to be false. @@ -1504,13 +1528,21 @@ pub const fn likely(b: bool) -> bool { bootstrap, rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") )] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_intrinsic] #[rustc_nounwind] -#[miri::intrinsic_fallback_is_spec] +#[inline(always)] pub const fn unlikely(b: bool) -> bool { - b + #[cfg(bootstrap)] + { + b + } + #[cfg(not(bootstrap))] + if b { + cold_path(); + true + } else { + false + } } /// Returns either `true_val` or `false_val` depending on condition `b` with a @@ -1539,7 +1571,7 @@ pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T { /// /// This intrinsic does not have a stable counterpart. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1552,7 +1584,7 @@ pub const fn assert_inhabited<T>() { /// /// This intrinsic does not have a stable counterpart. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1564,7 +1596,7 @@ pub const fn assert_zero_valid<T>() { /// /// This intrinsic does not have a stable counterpart. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1581,7 +1613,7 @@ pub const fn assert_mem_uninitialized_valid<T>() { /// /// Consider using [`core::panic::Location::caller`] instead. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1599,7 +1631,7 @@ pub const fn caller_location() -> &'static crate::panic::Location<'static> { /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1913,7 +1945,7 @@ pub const unsafe fn transmute<Src, Dst>(_src: Src) -> Dst { /// This is not expected to ever be exposed directly to users, rather it /// may eventually be exposed through some more-constrained API. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1935,7 +1967,7 @@ pub const unsafe fn transmute_unchecked<Src, Dst>(_src: Src) -> Dst { /// /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1961,7 +1993,7 @@ pub const fn needs_drop<T: ?Sized>() -> bool { /// The stabilized version of this intrinsic is [`pointer::offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1984,7 +2016,7 @@ pub const unsafe fn offset<Ptr, Delta>(_dst: Ptr, _offset: Delta) -> Ptr { /// The stabilized version of this intrinsic is [`pointer::wrapping_offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2692,7 +2724,7 @@ pub fn frem_algebraic<T: Copy>(_a: T, _b: T) -> T { /// primitives via the `count_ones` method. For example, /// [`u32::count_ones`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2737,7 +2769,7 @@ pub const fn ctpop<T: Copy>(_x: T) -> u32 { /// assert_eq!(num_leading, 16); /// ``` #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2763,7 +2795,7 @@ pub const fn ctlz<T: Copy>(_x: T) -> u32 { /// assert_eq!(num_leading, 3); /// ``` #[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2808,7 +2840,7 @@ pub const unsafe fn ctlz_nonzero<T: Copy>(_x: T) -> u32 { /// assert_eq!(num_trailing, 16); /// ``` #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2834,7 +2866,7 @@ pub const fn cttz<T: Copy>(_x: T) -> u32 { /// assert_eq!(num_trailing, 3); /// ``` #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2853,7 +2885,7 @@ pub const unsafe fn cttz_nonzero<T: Copy>(_x: T) -> u32 { /// primitives via the `swap_bytes` method. For example, /// [`u32::swap_bytes`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2872,7 +2904,7 @@ pub const fn bswap<T: Copy>(_x: T) -> T { /// primitives via the `reverse_bits` method. For example, /// [`u32::reverse_bits`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2905,7 +2937,7 @@ pub const fn three_way_compare<T: Copy>(_lhs: T, _rhss: T) -> crate::cmp::Orderi /// primitives via the `overflowing_add` method. For example, /// [`u32::overflowing_add`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2924,7 +2956,7 @@ pub const fn add_with_overflow<T: Copy>(_x: T, _y: T) -> (T, bool) { /// primitives via the `overflowing_sub` method. For example, /// [`u32::overflowing_sub`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2943,7 +2975,7 @@ pub const fn sub_with_overflow<T: Copy>(_x: T, _y: T) -> (T, bool) { /// primitives via the `overflowing_mul` method. For example, /// [`u32::overflowing_mul`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2970,7 +3002,7 @@ pub const unsafe fn exact_div<T: Copy>(_x: T, _y: T) -> T { /// primitives via the `checked_div` method. For example, /// [`u32::checked_div`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2984,7 +3016,7 @@ pub const unsafe fn unchecked_div<T: Copy>(_x: T, _y: T) -> T { /// primitives via the `checked_rem` method. For example, /// [`u32::checked_rem`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2999,7 +3031,7 @@ pub const unsafe fn unchecked_rem<T: Copy>(_x: T, _y: T) -> T { /// primitives via the `checked_shl` method. For example, /// [`u32::checked_shl`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3013,7 +3045,7 @@ pub const unsafe fn unchecked_shl<T: Copy, U: Copy>(_x: T, _y: U) -> T { /// primitives via the `checked_shr` method. For example, /// [`u32::checked_shr`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3027,7 +3059,7 @@ pub const unsafe fn unchecked_shr<T: Copy, U: Copy>(_x: T, _y: U) -> T { /// The stable counterpart of this intrinsic is `unchecked_add` on the various /// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3041,7 +3073,7 @@ pub const unsafe fn unchecked_add<T: Copy>(_x: T, _y: T) -> T { /// The stable counterpart of this intrinsic is `unchecked_sub` on the various /// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3055,7 +3087,7 @@ pub const unsafe fn unchecked_sub<T: Copy>(_x: T, _y: T) -> T { /// The stable counterpart of this intrinsic is `unchecked_mul` on the various /// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3074,7 +3106,7 @@ pub const unsafe fn unchecked_mul<T: Copy>(_x: T, _y: T) -> T { /// primitives via the `rotate_left` method. For example, /// [`u32::rotate_left`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3093,7 +3125,7 @@ pub const fn rotate_left<T: Copy>(_x: T, _shift: u32) -> T { /// primitives via the `rotate_right` method. For example, /// [`u32::rotate_right`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3112,7 +3144,7 @@ pub const fn rotate_right<T: Copy>(_x: T, _shift: u32) -> T { /// primitives via the `wrapping_add` method. For example, /// [`u32::wrapping_add`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3130,7 +3162,7 @@ pub const fn wrapping_add<T: Copy>(_a: T, _b: T) -> T { /// primitives via the `wrapping_sub` method. For example, /// [`u32::wrapping_sub`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3148,7 +3180,7 @@ pub const fn wrapping_sub<T: Copy>(_a: T, _b: T) -> T { /// primitives via the `wrapping_mul` method. For example, /// [`u32::wrapping_mul`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3167,7 +3199,7 @@ pub const fn wrapping_mul<T: Copy>(_a: T, _b: T) -> T { /// primitives via the `saturating_add` method. For example, /// [`u32::saturating_add`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3185,7 +3217,7 @@ pub const fn saturating_add<T: Copy>(_a: T, _b: T) -> T { /// primitives via the `saturating_sub` method. For example, /// [`u32::saturating_sub`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3200,7 +3232,7 @@ pub const fn saturating_sub<T: Copy>(_a: T, _b: T) -> T { /// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it /// trivially obeys runtime-MIR rules about derefs in operands. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3215,7 +3247,7 @@ pub const unsafe fn read_via_copy<T>(_ptr: *const T) -> T { /// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so /// that it trivially obeys runtime-MIR rules about derefs in operands. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3233,7 +3265,7 @@ pub const unsafe fn write_via_move<T>(_ptr: *mut T, _value: T) { /// /// The stabilized version of this intrinsic is [`core::mem::discriminant`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3273,7 +3305,7 @@ extern "rust-intrinsic" { /// See documentation of `<*const T>::offset_from` for details. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3292,8 +3324,8 @@ pub const unsafe fn ptr_offset_from_unsigned<T>(_ptr: *const T, _base: *const T) /// See documentation of `<*const T>::guaranteed_eq` for details. /// Returns `2` if the result is unknown. -/// Returns `1` if the pointers are guaranteed equal -/// Returns `0` if the pointers are guaranteed inequal +/// Returns `1` if the pointers are guaranteed equal. +/// Returns `0` if the pointers are guaranteed inequal. #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020"))] #[rustc_intrinsic] #[rustc_nounwind] @@ -3535,7 +3567,6 @@ pub(crate) macro const_eval_select { /// In other words, the following code has *Undefined Behavior*: /// /// ```no_run -/// #![feature(is_val_statically_known)] /// #![feature(core_intrinsics)] /// # #![allow(internal_features)] /// use std::hint::unreachable_unchecked; @@ -3548,7 +3579,6 @@ pub(crate) macro const_eval_select { /// may panic, or it may not: /// /// ```no_run -/// #![feature(is_val_statically_known)] /// #![feature(core_intrinsics)] /// # #![allow(internal_features)] /// use std::intrinsics::is_val_statically_known; @@ -3581,7 +3611,6 @@ pub(crate) macro const_eval_select { /// behave identically: /// /// ``` -/// #![feature(is_val_statically_known)] /// #![feature(core_intrinsics)] /// # #![allow(internal_features)] /// use std::intrinsics::is_val_statically_known; @@ -3598,7 +3627,11 @@ pub(crate) macro const_eval_select { /// # _ = foo(&5_i32); /// # _ = bar(&5_i32); /// ``` -#[rustc_const_unstable(feature = "is_val_statically_known", issue = "none")] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_is_val_statically_known", since = "CURRENT_RUSTC_VERSION") +)] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] @@ -3641,7 +3674,7 @@ pub const unsafe fn typed_swap<T>(x: *mut T, y: *mut T) { /// user has UB checks disabled, the checks will still get optimized out. This intrinsic is /// primarily used by [`ub_checks::assert_unsafe_precondition`]. #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] // just for UB checks +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] // just for UB checks #[inline(always)] #[rustc_intrinsic] pub const fn ub_checks() -> bool { @@ -3725,7 +3758,7 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_size_of", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn size_of<T>() -> usize { @@ -3743,7 +3776,7 @@ pub const fn size_of<T>() -> usize { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_min_align_of", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn min_align_of<T>() -> usize { @@ -3857,7 +3890,7 @@ pub const fn type_id<T: ?Sized + 'static>() -> u128 { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn aggregate_raw_ptr<P: AggregateRawPtr<D, Metadata = M>, D, M>(_data: D, _meta: M) -> P { @@ -3886,7 +3919,7 @@ impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P { bootstrap, cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")) )] -#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *const P) -> M { @@ -3993,7 +4026,7 @@ pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *cons #[rustc_diagnostic_item = "ptr_copy_nonoverlapping"] pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) { #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] + #[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -4013,9 +4046,9 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us count: usize = count, ) => { let zero_size = count == 0 || size == 0; - ub_checks::is_aligned_and_not_null(src, align, zero_size) - && ub_checks::is_aligned_and_not_null(dst, align, zero_size) - && ub_checks::is_nonoverlapping(src, dst, size, count) + ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size) + && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size) + && ub_checks::maybe_is_nonoverlapping(src, dst, size, count) } ); @@ -4100,7 +4133,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us #[rustc_diagnostic_item = "ptr_copy"] pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] + #[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -4119,8 +4152,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { align: usize = align_of::<T>(), zero_size: bool = T::IS_ZST || count == 0, ) => - ub_checks::is_aligned_and_not_null(src, align, zero_size) - && ub_checks::is_aligned_and_not_null(dst, align, zero_size) + ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size) + && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size) ); copy(src, dst, count) } @@ -4184,7 +4217,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { #[rustc_diagnostic_item = "ptr_write_bytes"] pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) { #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] + #[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -4201,7 +4234,7 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) { addr: *const () = dst as *const (), align: usize = align_of::<T>(), zero_size: bool = T::IS_ZST || count == 0, - ) => ub_checks::is_aligned_and_not_null(addr, align, zero_size) + ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, zero_size) ); write_bytes(dst, val, count) } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 6f7ea769420..d30bf96cfd4 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -109,6 +109,7 @@ // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(const_exact_div))] #![cfg_attr(bootstrap, feature(const_fmt_arguments_new))] +#![cfg_attr(bootstrap, feature(const_ub_checks))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(const_align_of_val)] @@ -120,8 +121,6 @@ #![feature(const_float_methods)] #![feature(const_heap)] #![feature(const_nonnull_new)] -#![feature(const_pin_2)] -#![feature(const_ptr_is_null)] #![feature(const_ptr_sub_ptr)] #![feature(const_raw_ptr_comparison)] #![feature(const_size_of_val)] @@ -132,14 +131,12 @@ #![feature(const_type_id)] #![feature(const_type_name)] #![feature(const_typed_swap)] -#![feature(const_ub_checks)] #![feature(core_intrinsics)] #![feature(coverage_attribute)] #![feature(do_not_recommend)] #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] -#![feature(is_val_statically_known)] #![feature(lazy_get)] #![feature(link_cfg)] #![feature(non_null_from_ref)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 1c5c58d64a2..c8ea52a1fb0 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -981,6 +981,18 @@ pub trait Tuple {} )] pub trait PointerLike {} +#[cfg(not(bootstrap))] +marker_impls! { + #[unstable(feature = "pointer_like_trait", issue = "none")] + PointerLike for + usize, + {T} &T, + {T} &mut T, + {T} *const T, + {T} *mut T, + {T: PointerLike} crate::pin::Pin<T>, +} + /// A marker for types which can be used as types of `const` generic parameters. /// /// These types must have a proper equivalence relation (`Eq`) and it must be automatically diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 8c6cdf57c58..58315cb74f0 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -525,6 +525,7 @@ impl<T> MaybeUninit<T> { /// until they are, it is advisable to avoid them.) #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit_as_ptr", since = "1.59.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] pub const fn as_ptr(&self) -> *const T { // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer. @@ -566,6 +567,7 @@ impl<T> MaybeUninit<T> { /// until they are, it is advisable to avoid them.) #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit_as_mut_ptr", since = "1.83.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] pub const fn as_mut_ptr(&mut self) -> *mut T { // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer. diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 4d24b102096..318bb8ee4cd 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2242,7 +2242,6 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn wrapping_pow(self, mut exp: u32) -> Self { if exp == 0 { return 1; @@ -2808,7 +2807,6 @@ macro_rules! int_impl { without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn pow(self, mut exp: u32) -> Self { if exp == 0 { return 1; diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 0a5101884f7..0383c13fa08 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2251,7 +2251,6 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn wrapping_pow(self, mut exp: u32) -> Self { if exp == 0 { return 1; @@ -2791,7 +2790,6 @@ macro_rules! uint_impl { without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn pow(self, mut exp: u32) -> Self { if exp == 0 { return 1; 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/core/src/pin.rs b/library/core/src/pin.rs index 254b306fcaa..c14c49a0d92 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1214,7 +1214,8 @@ impl<Ptr: Deref<Target: Unpin>> Pin<Ptr> { /// assert_eq!(*r, 5); /// ``` #[inline(always)] - #[rustc_const_unstable(feature = "const_pin_2", issue = "76654")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const fn into_inner(pin: Pin<Ptr>) -> Ptr { pin.__pointer @@ -1503,7 +1504,8 @@ impl<Ptr: Deref> Pin<Ptr> { /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used /// instead. #[inline(always)] - #[rustc_const_unstable(feature = "const_pin_2", issue = "76654")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const unsafe fn into_inner_unchecked(pin: Pin<Ptr>) -> Ptr { pin.__pointer diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 2d7507e2d53..0dbe819acb1 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -29,16 +29,18 @@ impl<T: ?Sized> *const T { /// assert!(!ptr.is_null()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "ptr_const_is_null"] #[inline] + #[rustc_allow_const_fn_unstable(const_eval_select)] pub const fn is_null(self) -> bool { // Compare via a cast to a thin pointer, so fat pointers are only // considering their "data" part for null-ness. let ptr = self as *const u8; const_eval_select!( @capture { ptr: *const u8 } -> bool: - if const #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] { + // This use of `const_raw_ptr_comparison` has been explicitly blessed by t-lang. + if const #[rustc_allow_const_fn_unstable(const_raw_ptr_comparison)] { match (ptr).guaranteed_eq(null_mut()) { Some(res) => res, // To remain maximally convervative, we stop execution when we don't @@ -280,7 +282,7 @@ impl<T: ?Sized> *const T { /// } /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> { // SAFETY: the caller must guarantee that `self` is valid diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 603e9044217..805edddfe63 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1103,9 +1103,9 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { count: usize = count, ) => { let zero_size = size == 0 || count == 0; - ub_checks::is_aligned_and_not_null(x, align, zero_size) - && ub_checks::is_aligned_and_not_null(y, align, zero_size) - && ub_checks::is_nonoverlapping(x, y, size, count) + ub_checks::maybe_is_aligned_and_not_null(x, align, zero_size) + && ub_checks::maybe_is_aligned_and_not_null(y, align, zero_size) + && ub_checks::maybe_is_nonoverlapping(x, y, size, count) } ); @@ -1216,7 +1216,7 @@ pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T { addr: *const () = dst as *const (), align: usize = align_of::<T>(), is_zst: bool = T::IS_ZST, - ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) ); mem::replace(&mut *dst, src) } @@ -1369,7 +1369,7 @@ pub const unsafe fn read<T>(src: *const T) -> T { addr: *const () = src as *const (), align: usize = align_of::<T>(), is_zst: bool = T::IS_ZST, - ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) ); crate::intrinsics::read_via_copy(src) } @@ -1573,7 +1573,7 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) { addr: *mut () = dst as *mut (), align: usize = align_of::<T>(), is_zst: bool = T::IS_ZST, - ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) ); intrinsics::write_via_move(dst, src) } @@ -1745,7 +1745,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T { addr: *const () = src as *const (), align: usize = align_of::<T>(), is_zst: bool = T::IS_ZST, - ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) ); intrinsics::volatile_load(src) } @@ -1825,7 +1825,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) { addr: *mut () = dst as *mut (), align: usize = align_of::<T>(), is_zst: bool = T::IS_ZST, - ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst) + ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) ); intrinsics::volatile_store(dst, src); } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 344ba46a50e..f0204bd0f77 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -29,7 +29,7 @@ impl<T: ?Sized> *mut T { /// assert!(!ptr.is_null()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "ptr_is_null"] #[inline] pub const fn is_null(self) -> bool { @@ -271,7 +271,7 @@ impl<T: ?Sized> *mut T { /// } /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> { // SAFETY: the caller must guarantee that `self` is valid for a @@ -619,7 +619,7 @@ impl<T: ?Sized> *mut T { /// println!("{s:?}"); // It'll print: "[4, 2, 3]". /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] + #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const unsafe fn as_mut<'a>(self) -> Option<&'a mut T> { // SAFETY: the caller must guarantee that `self` is be valid for diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index ef52cc44126..c855f963771 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -735,6 +735,7 @@ impl<T> [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] #[must_use] pub const fn as_ptr(&self) -> *const T { @@ -765,6 +766,7 @@ impl<T> [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] #[must_use] pub const fn as_mut_ptr(&mut self) -> *mut T { diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 89840881c4d..319b76899bf 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -132,7 +132,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] align: usize = align_of::<T>(), len: usize = len, ) => - ub_checks::is_aligned_and_not_null(data, align, false) + ub_checks::maybe_is_aligned_and_not_null(data, align, false) && ub_checks::is_valid_allocation_size(size, len) ); &*ptr::slice_from_raw_parts(data, len) @@ -186,7 +186,7 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m align: usize = align_of::<T>(), len: usize = len, ) => - ub_checks::is_aligned_and_not_null(data, align, false) + ub_checks::maybe_is_aligned_and_not_null(data, align, false) && ub_checks::is_valid_allocation_size(size, len) ); &mut *ptr::slice_from_raw_parts_mut(data, len) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 5aecbf303f9..4629b770cb4 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -373,6 +373,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[must_use] #[inline(always)] pub const fn as_ptr(&self) -> *const u8 { @@ -390,6 +391,7 @@ impl str { #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] #[rustc_const_stable(feature = "const_str_as_mut", since = "1.83.0")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[must_use] #[inline(always)] pub const fn as_mut_ptr(&mut self) -> *mut u8 { diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 93b4ad5c1c9..7f2a5424787 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -469,7 +469,7 @@ impl AtomicBool { /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses #[stable(feature = "atomic_from_ptr", since = "1.75.0")] - #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")] + #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool { // SAFETY: guaranteed by the caller unsafe { &*ptr.cast() } @@ -1264,7 +1264,7 @@ impl<T> AtomicPtr<T> { /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses #[stable(feature = "atomic_from_ptr", since = "1.75.0")] - #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")] + #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> { // SAFETY: guaranteed by the caller unsafe { &*ptr.cast() } @@ -2263,7 +2263,7 @@ macro_rules! atomic_int { /// [valid]: crate::ptr#safety /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses #[stable(feature = "atomic_from_ptr", since = "1.75.0")] - #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")] + #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type { // SAFETY: guaranteed by the caller unsafe { &*ptr.cast() } diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index 8fcbda141da..3e6110c9c88 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -64,8 +64,6 @@ macro_rules! assert_unsafe_precondition { #[rustc_no_mir_inline] #[inline] #[rustc_nounwind] - #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] - #[rustc_allow_const_fn_unstable(const_ptr_is_null, const_ub_checks)] // only for UB checks const fn precondition_check($($name:$ty),*) { if !$e { ::core::panicking::panic_nounwind( @@ -116,12 +114,16 @@ pub(crate) const fn check_language_ub() -> bool { /// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the /// check is anyway not executed in `const`. #[inline] -#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] -pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool { +#[rustc_allow_const_fn_unstable(const_eval_select)] +pub(crate) const fn maybe_is_aligned_and_not_null( + ptr: *const (), + align: usize, + is_zst: bool, +) -> bool { // This is just for safety checks so we can const_eval_select. const_eval_select!( @capture { ptr: *const (), align: usize, is_zst: bool } -> bool: - if const #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] { + if const { is_zst || !ptr.is_null() } else { ptr.is_aligned_to(align) && (is_zst || !ptr.is_null()) @@ -141,8 +143,8 @@ pub(crate) const fn is_valid_allocation_size(size: usize, len: usize) -> bool { /// Note that in const-eval this function just returns `true` and therefore must /// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`. #[inline] -#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] -pub(crate) const fn is_nonoverlapping( +#[rustc_allow_const_fn_unstable(const_eval_select)] +pub(crate) const fn maybe_is_nonoverlapping( src: *const (), dst: *const (), size: usize, diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index f515e9e4109..f7825571cd7 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -21,7 +21,6 @@ #![feature(const_eval_select)] #![feature(const_heap)] #![feature(const_nonnull_new)] -#![feature(const_pin_2)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index b732fdf1696..c1ab70b714a 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -34,7 +34,7 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false } addr2line = { version = "0.22.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] -libc = { version = "0.2.161", default-features = false, features = [ +libc = { version = "0.2.162", default-features = false, features = [ 'rustc-dep-of-std', ], public = true } 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/io/cursor.rs b/library/std/src/io/cursor.rs index 9f913eae095..fbfdb4fa023 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -153,7 +153,8 @@ impl<T> Cursor<T> { /// let reference = buff.get_mut(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut T { + #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")] + pub const fn get_mut(&mut self) -> &mut T { &mut self.inner } @@ -200,7 +201,8 @@ impl<T> Cursor<T> { /// assert_eq!(buff.position(), 4); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_position(&mut self, pos: u64) { + #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")] + pub const fn set_position(&mut self, pos: u64) { self.pos = pos; } } diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 30d43c8bbfd..4302e24781e 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1448,6 +1448,9 @@ mod self_upper_keyword {} /// in a multithreaded context. As such, all accesses to mutable `static`s /// require an [`unsafe`] block. /// +/// When possible, it's often better to use a non-mutable `static` with an +/// interior mutable type such as [`Mutex`], [`OnceLock`], or an [atomic]. +/// /// Despite their unsafety, mutable `static`s are necessary in many contexts: /// they can be used to represent global state shared by the whole program or in /// [`extern`] blocks to bind to variables from C libraries. @@ -1468,7 +1471,10 @@ mod self_upper_keyword {} /// [`extern`]: keyword.extern.html /// [`mut`]: keyword.mut.html /// [`unsafe`]: keyword.unsafe.html +/// [`Mutex`]: sync::Mutex +/// [`OnceLock`]: sync::OnceLock /// [`RefCell`]: cell::RefCell +/// [atomic]: sync::atomic /// [Reference]: ../reference/items/static-items.html mod static_keyword {} diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index da2da6f9dfc..d55d1c80dca 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -4,10 +4,10 @@ mod tests; use crate::cell::UnsafeCell; use crate::fmt; use crate::marker::PhantomData; -use crate::mem::ManuallyDrop; +use crate::mem::{ManuallyDrop, forget}; use crate::ops::{Deref, DerefMut}; use crate::ptr::NonNull; -use crate::sync::{LockResult, TryLockError, TryLockResult, poison}; +use crate::sync::{LockResult, PoisonError, TryLockError, TryLockResult, poison}; use crate::sys::sync as sys; /// A reader-writer lock @@ -574,8 +574,12 @@ impl<T> From<T> for RwLock<T> { impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { /// Creates a new instance of `RwLockReadGuard<T>` from a `RwLock<T>`. - // SAFETY: if and only if `lock.inner.read()` (or `lock.inner.try_read()`) has been - // successfully called from the same thread before instantiating this object. + /// + /// # Safety + /// + /// This function is safe if and only if the same thread has successfully and safely called + /// `lock.inner.read()`, `lock.inner.try_read()`, or `lock.inner.downgrade()` before + /// instantiating this object. unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockReadGuard<'rwlock, T>> { poison::map_result(lock.poison.borrow(), |()| RwLockReadGuard { data: unsafe { NonNull::new_unchecked(lock.data.get()) }, @@ -957,6 +961,68 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { None => Err(orig), } } + + /// Downgrades a write-locked `RwLockWriteGuard` into a read-locked [`RwLockReadGuard`]. + /// + /// This method will atomically change the state of the [`RwLock`] from exclusive mode into + /// shared mode. This means that it is impossible for a writing thread to get in between a + /// thread calling `downgrade` and the same thread reading whatever it wrote while it had the + /// [`RwLock`] in write mode. + /// + /// Note that since we have the `RwLockWriteGuard`, we know that the [`RwLock`] is already + /// locked for writing, so this method cannot fail. + /// + /// # Example + /// + /// ``` + /// #![feature(rwlock_downgrade)] + /// use std::sync::{Arc, RwLock, RwLockWriteGuard}; + /// + /// // The inner value starts as 0. + /// let rw = Arc::new(RwLock::new(0)); + /// + /// // Put the lock in write mode. + /// let mut main_write_guard = rw.write().unwrap(); + /// + /// let evil = rw.clone(); + /// let handle = std::thread::spawn(move || { + /// // This will not return until the main thread drops the `main_read_guard`. + /// let mut evil_guard = evil.write().unwrap(); + /// + /// assert_eq!(*evil_guard, 1); + /// *evil_guard = 2; + /// }); + /// + /// // After spawning the writer thread, set the inner value to 1. + /// *main_write_guard = 1; + /// + /// // Atomically downgrade the write guard into a read guard. + /// let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard); + /// + /// // Since `downgrade` is atomic, the writer thread cannot have set the inner value to 2. + /// assert_eq!(*main_read_guard, 1, "`downgrade` was not atomic"); + /// + /// // Clean up everything now + /// drop(main_read_guard); + /// handle.join().unwrap(); + /// + /// let final_check = rw.read().unwrap(); + /// assert_eq!(*final_check, 2); + /// ``` + #[unstable(feature = "rwlock_downgrade", issue = "128203")] + pub fn downgrade(s: Self) -> RwLockReadGuard<'a, T> { + let lock = s.lock; + + // We don't want to call the destructor since that calls `write_unlock`. + forget(s); + + // SAFETY: We take ownership of a write guard, so we must already have the `RwLock` in write + // mode, satisfying the `downgrade` contract. + unsafe { lock.inner.downgrade() }; + + // SAFETY: We have just successfully called `downgrade`, so we fulfill the safety contract. + unsafe { RwLockReadGuard::new(lock).unwrap_or_else(PoisonError::into_inner) } + } } impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs index 37a2e41641a..29cad4400f1 100644 --- a/library/std/src/sync/rwlock/tests.rs +++ b/library/std/src/sync/rwlock/tests.rs @@ -501,3 +501,111 @@ fn panic_while_mapping_write_unlocked_poison() { drop(lock); } + +#[test] +fn test_downgrade_basic() { + let r = RwLock::new(()); + + let write_guard = r.write().unwrap(); + let _read_guard = RwLockWriteGuard::downgrade(write_guard); +} + +#[test] +fn test_downgrade_observe() { + // Taken from the test `test_rwlock_downgrade` from: + // https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs + + const W: usize = 20; + const N: usize = 100; + + // This test spawns `W` writer threads, where each will increment a counter `N` times, ensuring + // that the value they wrote has not changed after downgrading. + + let rw = Arc::new(RwLock::new(0)); + + // Spawn the writers that will do `W * N` operations and checks. + let handles: Vec<_> = (0..W) + .map(|_| { + let rw = rw.clone(); + thread::spawn(move || { + for _ in 0..N { + // Increment the counter. + let mut write_guard = rw.write().unwrap(); + *write_guard += 1; + let cur_val = *write_guard; + + // Downgrade the lock to read mode, where the value protected cannot be modified. + let read_guard = RwLockWriteGuard::downgrade(write_guard); + assert_eq!(cur_val, *read_guard); + } + }) + }) + .collect(); + + for handle in handles { + handle.join().unwrap(); + } + + assert_eq!(*rw.read().unwrap(), W * N); +} + +#[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; + + // This test checks that `downgrade` is atomic, meaning as soon as a write lock has been + // downgraded, the lock must be in read mode and no other threads can take the write lock to + // modify the protected value. + + // `W` is the number of evil writer threads. + const W: usize = 20; + let rwlock = Arc::new(RwLock::new(0)); + + // Spawns many evil writer threads that will try and write to the locked value before the + // initial writer (who has the exclusive lock) can read after it downgrades. + // If the `RwLock` behaves correctly, then the initial writer should read the value it wrote + // itself as no other thread should be able to mutate the protected value. + + // Put the lock in write mode, causing all future threads trying to access this go to sleep. + let mut main_write_guard = rwlock.write().unwrap(); + + // Spawn all of the evil writer threads. They will each increment the protected value by 1. + let handles: Vec<_> = (0..W) + .map(|_| { + let rwlock = rwlock.clone(); + thread::spawn(move || { + // Will go to sleep since the main thread initially has the write lock. + let mut evil_guard = rwlock.write().unwrap(); + *evil_guard += 1; + }) + }) + .collect(); + + // Wait for a good amount of time so that evil threads go to sleep. + // Note: this is not strictly necessary... + let eternity = crate::time::Duration::from_millis(42); + thread::sleep(eternity); + + // Once everyone is asleep, set the value to `NEW_VALUE`. + *main_write_guard = NEW_VALUE; + + // Atomically downgrade the write guard into a read guard. + let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard); + + // If the above is not atomic, then it would be possible for an evil thread to get in front of + // this read and change the value to be non-negative. + assert_eq!(*main_read_guard, NEW_VALUE, "`downgrade` was not atomic"); + + // Drop the main read guard and allow the evil writer threads to start incrementing. + drop(main_read_guard); + + for handle in handles { + handle.join().unwrap(); + } + + let final_check = rwlock.read().unwrap(); + assert_eq!(*final_check, W as i32 + NEW_VALUE); +} diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index 0cc9cecb89d..1b83f4b0aee 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -18,6 +18,7 @@ use crate::{fmt, io}; #[derive(Debug)] pub struct Command { prog: OsString, + args: Vec<OsString>, stdout: Option<Stdio>, stderr: Option<Stdio>, } @@ -39,12 +40,11 @@ pub enum Stdio { impl Command { pub fn new(program: &OsStr) -> Command { - Command { prog: program.to_os_string(), stdout: None, stderr: None } + Command { prog: program.to_os_string(), args: Vec::new(), stdout: None, stderr: None } } - // FIXME: Implement arguments as reverse of parsing algorithm - pub fn arg(&mut self, _arg: &OsStr) { - panic!("unsupported") + pub fn arg(&mut self, arg: &OsStr) { + self.args.push(arg.to_os_string()); } pub fn env_mut(&mut self) -> &mut CommandEnv { @@ -72,7 +72,7 @@ impl Command { } pub fn get_args(&self) -> CommandArgs<'_> { - panic!("unsupported") + CommandArgs { iter: self.args.iter() } } pub fn get_envs(&self) -> CommandEnvs<'_> { @@ -116,6 +116,12 @@ impl Command { pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> { let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?; + // UEFI adds the bin name by default + if !self.args.is_empty() { + let args = uefi_command_internal::create_args(&self.prog, &self.args); + cmd.set_args(args); + } + // Setup Stdout let stdout = self.stdout.unwrap_or(Stdio::MakePipe); let stdout = Self::create_pipe(stdout)?; @@ -315,7 +321,7 @@ mod uefi_command_internal { stdout: Option<helpers::OwnedProtocol<PipeProtocol>>, stderr: Option<helpers::OwnedProtocol<PipeProtocol>>, st: OwnedTable<r_efi::efi::SystemTable>, - args: Option<Vec<u16>>, + args: Option<(*mut u16, usize)>, } impl Image { @@ -449,20 +455,20 @@ mod uefi_command_internal { } } - pub fn set_args(&mut self, args: &OsStr) { + pub fn set_args(&mut self, args: Box<[u16]>) { let loaded_image: NonNull<loaded_image::Protocol> = helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap(); - let mut args = args.encode_wide().collect::<Vec<u16>>(); - let args_size = (crate::mem::size_of::<u16>() * args.len()) as u32; + let len = args.len(); + let args_size: u32 = crate::mem::size_of_val(&args).try_into().unwrap(); + let ptr = Box::into_raw(args).as_mut_ptr(); unsafe { - (*loaded_image.as_ptr()).load_options = - args.as_mut_ptr() as *mut crate::ffi::c_void; + (*loaded_image.as_ptr()).load_options = ptr as *mut crate::ffi::c_void; (*loaded_image.as_ptr()).load_options_size = args_size; } - self.args = Some(args); + self.args = Some((ptr, len)); } fn update_st_crc32(&mut self) -> io::Result<()> { @@ -502,6 +508,10 @@ mod uefi_command_internal { ((*bt.as_ptr()).unload_image)(self.handle.as_ptr()); } } + + if let Some((ptr, len)) = self.args { + let _ = unsafe { Box::from_raw(crate::ptr::slice_from_raw_parts_mut(ptr, len)) }; + } } } @@ -681,4 +691,38 @@ mod uefi_command_internal { } } } + + pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> { + const QUOTE: u16 = 0x0022; + const SPACE: u16 = 0x0020; + const CARET: u16 = 0x005e; + const NULL: u16 = 0; + + // This is the lower bound on the final length under the assumption that + // the arguments only contain ASCII characters. + let mut res = Vec::with_capacity(args.iter().map(|arg| arg.len() + 3).sum()); + + // Wrap program name in quotes to avoid any problems + res.push(QUOTE); + res.extend(prog.encode_wide()); + res.push(QUOTE); + res.push(SPACE); + + for arg in args { + // Wrap the argument in quotes to be treat as single arg + res.push(QUOTE); + for c in arg.encode_wide() { + // CARET in quotes is used to escape CARET or QUOTE + if c == QUOTE || c == CARET { + res.push(CARET); + } + res.push(c); + } + res.push(QUOTE); + + res.push(SPACE); + } + + res.into_boxed_slice() + } } diff --git a/library/std/src/sys/sync/rwlock/futex.rs b/library/std/src/sys/sync/rwlock/futex.rs index 447048edf76..961819cae8d 100644 --- a/library/std/src/sys/sync/rwlock/futex.rs +++ b/library/std/src/sys/sync/rwlock/futex.rs @@ -18,6 +18,7 @@ pub struct RwLock { const READ_LOCKED: Primitive = 1; const MASK: Primitive = (1 << 30) - 1; const WRITE_LOCKED: Primitive = MASK; +const DOWNGRADE: Primitive = READ_LOCKED.wrapping_sub(WRITE_LOCKED); // READ_LOCKED - WRITE_LOCKED const MAX_READERS: Primitive = MASK - 1; const READERS_WAITING: Primitive = 1 << 30; const WRITERS_WAITING: Primitive = 1 << 31; @@ -54,6 +55,24 @@ fn is_read_lockable(state: Primitive) -> bool { } #[inline] +fn is_read_lockable_after_wakeup(state: Primitive) -> bool { + // We make a special case for checking if we can read-lock _after_ a reader thread that went to + // sleep has been woken up by a call to `downgrade`. + // + // `downgrade` will wake up all readers and place the lock in read mode. Thus, there should be + // no readers waiting and the lock should be read-locked (not write-locked or unlocked). + // + // Note that we do not check if any writers are waiting. This is because a call to `downgrade` + // implies that the caller wants other readers to read the value protected by the lock. If we + // did not allow readers to acquire the lock before writers after a `downgrade`, then only the + // original writer would be able to read the value, thus defeating the purpose of `downgrade`. + state & MASK < MAX_READERS + && !has_readers_waiting(state) + && !is_write_locked(state) + && !is_unlocked(state) +} + +#[inline] fn has_reached_max_readers(state: Primitive) -> bool { state & MASK == MAX_READERS } @@ -84,6 +103,9 @@ impl RwLock { } } + /// # Safety + /// + /// The `RwLock` must be read-locked (N readers) in order to call this. #[inline] pub unsafe fn read_unlock(&self) { let state = self.state.fetch_sub(READ_LOCKED, Release) - READ_LOCKED; @@ -100,11 +122,13 @@ impl RwLock { #[cold] fn read_contended(&self) { + let mut has_slept = false; let mut state = self.spin_read(); loop { - // If we can lock it, lock it. - if is_read_lockable(state) { + // If we have just been woken up, first check for a `downgrade` call. + // Otherwise, if we can read-lock it, lock it. + if (has_slept && is_read_lockable_after_wakeup(state)) || is_read_lockable(state) { match self.state.compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed) { Ok(_) => return, // Locked! @@ -116,9 +140,7 @@ impl RwLock { } // Check for overflow. - if has_reached_max_readers(state) { - panic!("too many active read locks on RwLock"); - } + assert!(!has_reached_max_readers(state), "too many active read locks on RwLock"); // Make sure the readers waiting bit is set before we go to sleep. if !has_readers_waiting(state) { @@ -132,6 +154,7 @@ impl RwLock { // Wait for the state to change. futex_wait(&self.state, state | READERS_WAITING, None); + has_slept = true; // Spin again after waking up. state = self.spin_read(); @@ -152,6 +175,9 @@ impl RwLock { } } + /// # Safety + /// + /// The `RwLock` must be write-locked (single writer) in order to call this. #[inline] pub unsafe fn write_unlock(&self) { let state = self.state.fetch_sub(WRITE_LOCKED, Release) - WRITE_LOCKED; @@ -163,6 +189,22 @@ impl RwLock { } } + /// # Safety + /// + /// The `RwLock` must be write-locked (single writer) in order to call this. + #[inline] + pub unsafe fn downgrade(&self) { + // Removes all write bits and adds a single read bit. + let state = self.state.fetch_add(DOWNGRADE, Release); + debug_assert!(is_write_locked(state), "RwLock must be write locked to call `downgrade`"); + + if has_readers_waiting(state) { + // Since we had the exclusive lock, nobody else can unset this bit. + self.state.fetch_sub(READERS_WAITING, Relaxed); + futex_wake_all(&self.state); + } + } + #[cold] fn write_contended(&self) { let mut state = self.spin_write(); diff --git a/library/std/src/sys/sync/rwlock/no_threads.rs b/library/std/src/sys/sync/rwlock/no_threads.rs index 6965e2e2cab..c11e59f719e 100644 --- a/library/std/src/sys/sync/rwlock/no_threads.rs +++ b/library/std/src/sys/sync/rwlock/no_threads.rs @@ -62,4 +62,9 @@ impl RwLock { pub unsafe fn write_unlock(&self) { assert_eq!(self.mode.replace(0), -1); } + + #[inline] + pub unsafe fn downgrade(&self) { + assert_eq!(self.mode.replace(1), -1); + } } diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs index 889961915f4..51330f8fafe 100644 --- a/library/std/src/sys/sync/rwlock/queue.rs +++ b/library/std/src/sys/sync/rwlock/queue.rs @@ -1,37 +1,38 @@ //! Efficient read-write locking without `pthread_rwlock_t`. //! -//! The readers-writer lock provided by the `pthread` library has a number of -//! problems which make it a suboptimal choice for `std`: +//! The readers-writer lock provided by the `pthread` library has a number of problems which make it +//! a suboptimal choice for `std`: //! -//! * It is non-movable, so it needs to be allocated (lazily, to make the -//! constructor `const`). -//! * `pthread` is an external library, meaning the fast path of acquiring an -//! uncontended lock cannot be inlined. -//! * Some platforms (at least glibc before version 2.25) have buggy implementations -//! that can easily lead to undefined behavior in safe Rust code when not properly -//! guarded against. +//! * It is non-movable, so it needs to be allocated (lazily, to make the constructor `const`). +//! * `pthread` is an external library, meaning the fast path of acquiring an uncontended lock +//! cannot be inlined. +//! * Some platforms (at least glibc before version 2.25) have buggy implementations that can easily +//! lead to undefined behaviour in safe Rust code when not properly guarded against. //! * On some platforms (e.g. macOS), the lock is very slow. //! -//! Therefore, we implement our own `RwLock`! Naively, one might reach for a -//! spinlock, but those [can be quite problematic] when the lock is contended. -//! Instead, this readers-writer lock copies its implementation strategy from -//! the Windows [SRWLOCK] and the [usync] library. Spinning is still used for the -//! fast path, but it is bounded: after spinning fails, threads will locklessly -//! add an information structure containing a [`Thread`] handle into a queue of -//! waiters associated with the lock. The lock owner, upon releasing the lock, -//! will scan through the queue and wake up threads as appropriate, which will -//! then again try to acquire the lock. The resulting [`RwLock`] is: +//! Therefore, we implement our own [`RwLock`]! Naively, one might reach for a spinlock, but those +//! can be quite [problematic] when the lock is contended. //! -//! * adaptive, since it spins before doing any heavywheight parking operations -//! * allocation-free, modulo the per-thread [`Thread`] handle, which is -//! allocated regardless when using threads created by `std` +//! Instead, this [`RwLock`] copies its implementation strategy from the Windows [SRWLOCK] and the +//! [usync] library implementations. +//! +//! Spinning is still used for the fast path, but it is bounded: after spinning fails, threads will +//! locklessly add an information structure ([`Node`]) containing a [`Thread`] handle into a queue +//! of waiters associated with the lock. The lock owner, upon releasing the lock, will scan through +//! the queue and wake up threads as appropriate, and the newly-awoken threads will then try to +//! acquire the lock themselves. +//! +//! The resulting [`RwLock`] is: +//! +//! * adaptive, since it spins before doing any heavyweight parking operations +//! * allocation-free, modulo the per-thread [`Thread`] handle, which is allocated anyways when +//! using threads created by `std` //! * writer-preferring, even if some readers may still slip through -//! * unfair, which reduces context-switching and thus drastically improves -//! performance +//! * unfair, which reduces context-switching and thus drastically improves performance //! //! and also quite fast in most cases. //! -//! [can be quite problematic]: https://matklad.github.io/2020/01/02/spinlocks-considered-harmful.html +//! [problematic]: https://matklad.github.io/2020/01/02/spinlocks-considered-harmful.html //! [SRWLOCK]: https://learn.microsoft.com/en-us/windows/win32/sync/slim-reader-writer--srw--locks //! [usync]: https://crates.io/crates/usync //! @@ -39,33 +40,37 @@ //! //! ## State //! -//! A single [`AtomicPtr`] is used as state variable. The lowest three bits are used -//! to indicate the meaning of the remaining bits: +//! A single [`AtomicPtr`] is used as state variable. The lowest four bits are used to indicate the +//! meaning of the remaining bits: +//! +//! | [`LOCKED`] | [`QUEUED`] | [`QUEUE_LOCKED`] | [`DOWNGRADED`] | Remaining | | +//! |------------|:-----------|:-----------------|:---------------|:-------------|:----------------------------------------------------------------------------------------------------------------------------| +//! | 0 | 0 | 0 | 0 | 0 | The lock is unlocked, no threads are waiting | +//! | 1 | 0 | 0 | 0 | 0 | The lock is write-locked, no threads waiting | +//! | 1 | 0 | 0 | 0 | n > 0 | The lock is read-locked with n readers | +//! | 0 | 1 | * | 0 | `*mut Node` | The lock is unlocked, but some threads are waiting. Only writers may lock the lock | +//! | 1 | 1 | * | * | `*mut Node` | The lock is locked, but some threads are waiting. If the lock is read-locked, the last queue node contains the reader count | +//! +//! ## Waiter Queue //! -//! | [`LOCKED`] | [`QUEUED`] | [`QUEUE_LOCKED`] | Remaining | | -//! |:-----------|:-----------|:-----------------|:-------------|:----------------------------------------------------------------------------------------------------------------------------| -//! | 0 | 0 | 0 | 0 | The lock is unlocked, no threads are waiting | -//! | 1 | 0 | 0 | 0 | The lock is write-locked, no threads waiting | -//! | 1 | 0 | 0 | n > 0 | The lock is read-locked with n readers | -//! | 0 | 1 | * | `*mut Node` | The lock is unlocked, but some threads are waiting. Only writers may lock the lock | -//! | 1 | 1 | * | `*mut Node` | The lock is locked, but some threads are waiting. If the lock is read-locked, the last queue node contains the reader count | +//! When threads are waiting on the lock (the `QUEUE` bit is set), the lock state points to a queue +//! of waiters, which is implemented as a linked list of nodes stored on the stack to avoid memory +//! allocation. //! -//! ## Waiter queue +//! To enable lock-free enqueuing of new nodes to the queue, the linked list is singly-linked upon +//! creation. //! -//! When threads are waiting on the lock (`QUEUE` is set), the lock state -//! points to a queue of waiters, which is implemented as a linked list of -//! nodes stored on the stack to avoid memory allocation. To enable lockless -//! enqueuing of new nodes to the queue, the linked list is single-linked upon -//! creation. Since when the lock is read-locked, the lock count is stored in -//! the last link of the queue, threads have to traverse the queue to find the -//! last element upon releasing the lock. To avoid having to traverse the whole -//! list again and again, a pointer to the found tail is cached in the (current) -//! first element of the queue. +//! When the lock is read-locked, the lock count (number of readers) is stored in the last link of +//! the queue. Threads have to traverse the queue to find the last element upon releasing the lock. +//! To avoid having to traverse the entire list every time we want to access the reader count, a +//! pointer to the found tail is cached in the (current) first element of the queue. //! -//! Also, while the lock is unfair for performance reasons, it is still best to -//! wake the tail node first, which requires backlinks to previous nodes to be -//! created. This is done at the same time as finding the tail, and thus a set -//! tail field indicates the remaining portion of the queue is initialized. +//! Also, while the lock is unfair for performance reasons, it is still best to wake the tail node +//! first (FIFO ordering). Since we always pop nodes off the tail of the queue, we must store +//! backlinks to previous nodes so that we can update the `tail` field of the (current) first +//! element of the queue. Adding backlinks is done at the same time as finding the tail (via the +//! function [`find_tail_and_add_backlinks`]), and thus encountering a set tail field on a node +//! indicates that all following nodes in the queue are initialized. //! //! TLDR: Here's a diagram of what the queue looks like: //! @@ -89,21 +94,21 @@ //! 3. All nodes preceding this node must have a correct, non-null `next` field. //! 4. All nodes following this node must have a correct, non-null `prev` field. //! -//! Access to the queue is controlled by the `QUEUE_LOCKED` bit, which threads -//! try to set both after enqueuing themselves to eagerly add backlinks to the -//! queue, which drastically improves performance, and after unlocking the lock -//! to wake the next waiter(s). This is done atomically at the same time as the -//! enqueuing/unlocking operation. The thread releasing the `QUEUE_LOCK` bit -//! will check the state of the lock and wake up waiters as appropriate. This -//! guarantees forward-progress even if the unlocking thread could not acquire -//! the queue lock. +//! Access to the queue is controlled by the `QUEUE_LOCKED` bit. Threads will try to set this bit +//! in two cases: one is when a thread enqueues itself and eagerly adds backlinks to the queue +//! (which drastically improves performance), and the other is after a thread unlocks the lock to +//! wake up the next waiter(s). //! -//! ## Memory orderings +//! `QUEUE_LOCKED` is set atomically at the same time as the enqueuing/unlocking operations. The +//! thread releasing the `QUEUE_LOCKED` bit will check the state of the lock (in particular, whether +//! a downgrade was requested using the [`DOWNGRADED`] bit) and wake up waiters as appropriate. This +//! guarantees forward progress even if the unlocking thread could not acquire the queue lock. //! -//! To properly synchronize changes to the data protected by the lock, the lock -//! is acquired and released with [`Acquire`] and [`Release`] ordering, respectively. -//! To propagate the initialization of nodes, changes to the queue lock are also -//! performed using these orderings. +//! ## Memory Orderings +//! +//! To properly synchronize changes to the data protected by the lock, the lock is acquired and +//! released with [`Acquire`] and [`Release`] ordering, respectively. To propagate the +//! initialization of nodes, changes to the queue lock are also performed using these orderings. #![forbid(unsafe_op_in_unsafe_fn)] @@ -115,26 +120,30 @@ use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release}; use crate::sync::atomic::{AtomicBool, AtomicPtr}; use crate::thread::{self, Thread, ThreadId}; -// Locking uses exponential backoff. `SPIN_COUNT` indicates how many times the -// locking operation will be retried. -// `spin_loop` will be called `2.pow(SPIN_COUNT) - 1` times. -const SPIN_COUNT: usize = 7; - -type State = *mut (); +/// The atomic lock state. type AtomicState = AtomicPtr<()>; +/// The inner lock state. +type State = *mut (); const UNLOCKED: State = without_provenance_mut(0); -const LOCKED: usize = 1; -const QUEUED: usize = 2; -const QUEUE_LOCKED: usize = 4; -const SINGLE: usize = 8; -const MASK: usize = !(QUEUE_LOCKED | QUEUED | LOCKED); +const LOCKED: usize = 1 << 0; +const QUEUED: usize = 1 << 1; +const QUEUE_LOCKED: usize = 1 << 2; +const DOWNGRADED: usize = 1 << 3; +const SINGLE: usize = 1 << 4; +const STATE: usize = DOWNGRADED | QUEUE_LOCKED | QUEUED | LOCKED; +const NODE_MASK: usize = !STATE; + +/// Locking uses exponential backoff. `SPIN_COUNT` indicates how many times the locking operation +/// will be retried. +/// +/// In other words, `spin_loop` will be called `2.pow(SPIN_COUNT) - 1` times. +const SPIN_COUNT: usize = 7; /// Marks the state as write-locked, if possible. #[inline] fn write_lock(state: State) -> Option<State> { - let state = state.wrapping_byte_add(LOCKED); - if state.addr() & LOCKED == LOCKED { Some(state) } else { None } + if state.addr() & LOCKED == 0 { Some(state.map_addr(|addr| addr | LOCKED)) } else { None } } /// Marks the state as read-locked, if possible. @@ -147,13 +156,32 @@ fn read_lock(state: State) -> Option<State> { } } -/// Masks the state, assuming it points to a queue node. +/// Converts a `State` into a `Node` by masking out the bottom bits of the state, assuming that the +/// state points to a queue node. /// /// # Safety +/// /// The state must contain a valid pointer to a queue node. #[inline] unsafe fn to_node(state: State) -> NonNull<Node> { - unsafe { NonNull::new_unchecked(state.mask(MASK)).cast() } + unsafe { NonNull::new_unchecked(state.mask(NODE_MASK)).cast() } +} + +/// The representation of a thread waiting on the lock queue. +/// +/// We initialize these `Node`s on thread execution stacks to avoid allocation. +/// +/// Note that we need an alignment of 16 to ensure that the last 4 bits of any +/// pointers to `Node`s are always zeroed (for the bit flags described in the +/// module-level documentation). +#[repr(align(16))] +struct Node { + next: AtomicLink, + prev: AtomicLink, + tail: AtomicLink, + write: bool, + thread: OnceCell<Thread>, + completed: AtomicBool, } /// An atomic node pointer with relaxed operations. @@ -173,16 +201,6 @@ impl AtomicLink { } } -#[repr(align(8))] -struct Node { - next: AtomicLink, - prev: AtomicLink, - tail: AtomicLink, - write: bool, - thread: OnceCell<Thread>, - completed: AtomicBool, -} - impl Node { /// Creates a new queue node. fn new(write: bool) -> Node { @@ -198,17 +216,17 @@ impl Node { /// Prepare this node for waiting. fn prepare(&mut self) { - // Fall back to creating an unnamed `Thread` handle to allow locking in - // TLS destructors. + // Fall back to creating an unnamed `Thread` handle to allow locking in TLS destructors. self.thread.get_or_init(|| { thread::try_current().unwrap_or_else(|| Thread::new_unnamed(ThreadId::new())) }); self.completed = AtomicBool::new(false); } - /// Wait until this node is marked as completed. + /// Wait until this node is marked as [`complete`](Node::complete)d by another thread. /// /// # Safety + /// /// May only be called from the thread that created the node. unsafe fn wait(&self) { while !self.completed.load(Acquire) { @@ -218,51 +236,48 @@ impl Node { } } - /// Atomically mark this node as completed. The node may not outlive this call. - unsafe fn complete(this: NonNull<Node>) { - // Since the node may be destroyed immediately after the completed flag - // is set, clone the thread handle before that. - let thread = unsafe { this.as_ref().thread.get().unwrap().clone() }; + /// Atomically mark this node as completed. + /// + /// # Safety + /// + /// `node` must point to a valid `Node`, and the node may not outlive this call. + unsafe fn complete(node: NonNull<Node>) { + // Since the node may be destroyed immediately after the completed flag is set, clone the + // thread handle before that. + let thread = unsafe { node.as_ref().thread.get().unwrap().clone() }; unsafe { - this.as_ref().completed.store(true, Release); + node.as_ref().completed.store(true, Release); } thread.unpark(); } } -struct PanicGuard; - -impl Drop for PanicGuard { - fn drop(&mut self) { - rtabort!("tried to drop node in intrusive list."); - } -} - -/// Add backlinks to the queue, returning the tail. +/// Traverse the queue and find the tail, adding backlinks to the queue while traversing. /// -/// May be called from multiple threads at the same time, while the queue is not +/// This may be called from multiple threads at the same time as long as the queue is not being /// modified (this happens when unlocking multiple readers). /// /// # Safety +/// /// * `head` must point to a node in a valid queue. -/// * `head` must be or be in front of the head of the queue at the time of the -/// last removal. -/// * The part of the queue starting with `head` must not be modified during this -/// call. -unsafe fn add_backlinks_and_find_tail(head: NonNull<Node>) -> NonNull<Node> { +/// * `head` must be in front of the previous head node that was used to perform the last removal. +/// * The part of the queue starting with `head` must not be modified during this call. +unsafe fn find_tail_and_add_backlinks(head: NonNull<Node>) -> NonNull<Node> { let mut current = head; + + // Traverse the queue until we find a node that has a set `tail`. let tail = loop { let c = unsafe { current.as_ref() }; - match c.tail.get() { - Some(tail) => break tail, - // SAFETY: - // All `next` fields before the first node with a `set` tail are - // non-null and valid (invariant 3). - None => unsafe { - let next = c.next.get().unwrap_unchecked(); - next.as_ref().prev.set(Some(current)); - current = next; - }, + if let Some(tail) = c.tail.get() { + break tail; + } + + // SAFETY: All `next` fields before the first node with a set `tail` are non-null and valid + // (by Invariant 3). + unsafe { + let next = c.next.get().unwrap_unchecked(); + next.as_ref().prev.set(Some(current)); + current = next; } }; @@ -272,6 +287,38 @@ unsafe fn add_backlinks_and_find_tail(head: NonNull<Node>) -> NonNull<Node> { } } +/// [`complete`](Node::complete)s all threads in the queue ending with `tail`. +/// +/// # Safety +/// +/// * `tail` must be a valid tail of a fully linked queue. +/// * The current thread must have exclusive access to that queue. +unsafe fn complete_all(tail: NonNull<Node>) { + let mut current = tail; + + // Traverse backwards through the queue (FIFO) and `complete` all of the nodes. + loop { + let prev = unsafe { current.as_ref().prev.get() }; + unsafe { + Node::complete(current); + } + match prev { + Some(prev) => current = prev, + None => return, + } + } +} + +/// A type to guard against the unwinds of stacks that nodes are located on due to panics. +struct PanicGuard; + +impl Drop for PanicGuard { + fn drop(&mut self) { + rtabort!("tried to drop node in intrusive list."); + } +} + +/// The public inner `RwLock` type. pub struct RwLock { state: AtomicState, } @@ -296,11 +343,10 @@ impl RwLock { #[inline] pub fn try_write(&self) -> bool { - // Atomically set the `LOCKED` bit. This is lowered to a single atomic - // instruction on most modern processors (e.g. "lock bts" on x86 and - // "ldseta" on modern AArch64), and therefore is more efficient than - // `fetch_update(lock(true))`, which can spuriously fail if a new node - // is appended to the queue. + // Atomically set the `LOCKED` bit. This is lowered to a single atomic instruction on most + // modern processors (e.g. "lock bts" on x86 and "ldseta" on modern AArch64), and therefore + // is more efficient than `fetch_update(lock(true))`, which can spuriously fail if a new + // node is appended to the queue. self.state.fetch_or(LOCKED, Acquire).addr() & LOCKED == 0 } @@ -313,88 +359,97 @@ impl RwLock { #[cold] fn lock_contended(&self, write: bool) { - let update = if write { write_lock } else { read_lock }; let mut node = Node::new(write); let mut state = self.state.load(Relaxed); let mut count = 0; + let update_fn = if write { write_lock } else { read_lock }; + loop { - if let Some(next) = update(state) { + // Optimistically update the state. + if let Some(next) = update_fn(state) { // The lock is available, try locking it. match self.state.compare_exchange_weak(state, next, Acquire, Relaxed) { Ok(_) => return, Err(new) => state = new, } + continue; } else if state.addr() & QUEUED == 0 && count < SPIN_COUNT { - // If the lock is not available and no threads are queued, spin - // for a while, using exponential backoff to decrease cache - // contention. + // If the lock is not available and no threads are queued, optimistically spin for a + // while, using exponential backoff to decrease cache contention. for _ in 0..(1 << count) { spin_loop(); } state = self.state.load(Relaxed); count += 1; + continue; + } + // The optimistic paths did not succeed, so fall back to parking the thread. + + // First, prepare the node. + node.prepare(); + + // If there are threads queued, this will set the `next` field to be a pointer to the + // first node in the queue. + // If the state is read-locked, this will set `next` to the lock count. + // If it is write-locked, it will set `next` to zero. + node.next.0 = AtomicPtr::new(state.mask(NODE_MASK).cast()); + node.prev = AtomicLink::new(None); + + // Set the `QUEUED` bit and preserve the `LOCKED` and `DOWNGRADED` bit. + let mut next = ptr::from_ref(&node) + .map_addr(|addr| addr | QUEUED | (state.addr() & (DOWNGRADED | LOCKED))) + as State; + + let mut is_queue_locked = false; + if state.addr() & QUEUED == 0 { + // If this is the first node in the queue, set the `tail` field to the node itself + // to ensure there is a valid `tail` field in the queue (Invariants 1 & 2). + // This needs to use `set` to avoid invalidating the new pointer. + node.tail.set(Some(NonNull::from(&node))); } else { - // Fall back to parking. First, prepare the node. - node.prepare(); - - // If there are threads queued, set the `next` field to a - // pointer to the next node in the queue. Otherwise set it to - // the lock count if the state is read-locked or to zero if it - // is write-locked. - node.next.0 = AtomicPtr::new(state.mask(MASK).cast()); - node.prev = AtomicLink::new(None); - let mut next = ptr::from_ref(&node) - .map_addr(|addr| addr | QUEUED | (state.addr() & LOCKED)) - as State; - - if state.addr() & QUEUED == 0 { - // If this is the first node in the queue, set the tail field to - // the node itself to ensure there is a current `tail` field in - // the queue (invariants 1 and 2). This needs to use `set` to - // avoid invalidating the new pointer. - node.tail.set(Some(NonNull::from(&node))); - } else { - // Otherwise, the tail of the queue is not known. - node.tail.set(None); - // Try locking the queue to eagerly add backlinks. - next = next.map_addr(|addr| addr | QUEUE_LOCKED); - } + // Otherwise, the tail of the queue is not known. + node.tail.set(None); - // Register the node, using release ordering to propagate our - // changes to the waking thread. - if let Err(new) = self.state.compare_exchange_weak(state, next, AcqRel, Relaxed) { - // The state has changed, just try again. - state = new; - continue; - } + // Try locking the queue to eagerly add backlinks. + next = next.map_addr(|addr| addr | QUEUE_LOCKED); - // The node is registered, so the structure must not be - // mutably accessed or destroyed while other threads may - // be accessing it. Guard against unwinds using a panic - // guard that aborts when dropped. - let guard = PanicGuard; + // Track if we changed the `QUEUE_LOCKED` bit from off to on. + is_queue_locked = state.addr() & QUEUE_LOCKED == 0; + } - // If the current thread locked the queue, unlock it again, - // linking it in the process. - if state.addr() & (QUEUE_LOCKED | QUEUED) == QUEUED { - unsafe { - self.unlock_queue(next); - } - } + // Register the node, using release ordering to propagate our changes to the waking + // thread. + if let Err(new) = self.state.compare_exchange_weak(state, next, AcqRel, Relaxed) { + // The state has changed, just try again. + state = new; + continue; + } + // The node has been registered, so the structure must not be mutably accessed or + // destroyed while other threads may be accessing it. - // Wait until the node is removed from the queue. - // SAFETY: the node was created by the current thread. + // Guard against unwinds using a `PanicGuard` that aborts when dropped. + let guard = PanicGuard; + + // If the current thread locked the queue, unlock it to eagerly adding backlinks. + if is_queue_locked { + // SAFETY: This thread set the `QUEUE_LOCKED` bit above. unsafe { - node.wait(); + self.unlock_queue(next); } + } - // The node was removed from the queue, disarm the guard. - mem::forget(guard); - - // Reload the state and try again. - state = self.state.load(Relaxed); - count = 0; + // Wait until the node is removed from the queue. + // SAFETY: the node was created by the current thread. + unsafe { + node.wait(); } + + // The node was removed from the queue, disarm the guard. + mem::forget(guard); + + // Reload the state and try again. + state = self.state.load(Relaxed); + count = 0; } } @@ -402,39 +457,51 @@ impl RwLock { pub unsafe fn read_unlock(&self) { match self.state.fetch_update(Release, Acquire, |state| { if state.addr() & QUEUED == 0 { + // If there are no threads queued, simply decrement the reader count. let count = state.addr() - (SINGLE | LOCKED); Some(if count > 0 { without_provenance_mut(count | LOCKED) } else { UNLOCKED }) + } else if state.addr() & DOWNGRADED != 0 { + // This thread used to have exclusive access, but requested a downgrade. This has + // not been completed yet, so we still have exclusive access. + // Retract the downgrade request and unlock, but leave waking up new threads to the + // thread that already holds the queue lock. + Some(state.mask(!(DOWNGRADED | LOCKED))) } else { None } }) { Ok(_) => {} - // There are waiters queued and the lock count was moved to the - // tail of the queue. + // There are waiters queued and the lock count was moved to the tail of the queue. Err(state) => unsafe { self.read_unlock_contended(state) }, } } + /// # Safety + /// + /// * There must be threads queued on the lock. + /// * `state` must be a pointer to a node in a valid queue. + /// * There cannot be a `downgrade` in progress. #[cold] unsafe fn read_unlock_contended(&self, state: State) { - // The state was observed with acquire ordering above, so the current - // thread will observe all node initializations. - // SAFETY: - // Because new read-locks cannot be acquired while threads are queued, - // all queue-lock owners will observe the set `LOCKED` bit. Because they - // do not modify the queue while there is a lock owner, the queue will - // not be removed from here. - let tail = unsafe { add_backlinks_and_find_tail(to_node(state)).as_ref() }; + // The state was observed with acquire ordering above, so the current thread will have + // observed all node initializations. + // We also know that no threads can be modifying the queue starting at `state`: because new + // read-locks cannot be acquired while there are any threads queued on the lock, all + // queue-lock owners will observe a set `LOCKED` bit in `self.state` and will not modify + // the queue. The other case that a thread could modify the queue is if a downgrade is in + // progress (removal of the entire queue), but since that is part of this function's safety + // contract, we can guarantee that no other threads can modify the queue. + let tail = unsafe { find_tail_and_add_backlinks(to_node(state)).as_ref() }; + // The lock count is stored in the `next` field of `tail`. - // Decrement it, making sure to observe all changes made to the queue - // by the other lock owners by using acquire-release ordering. + // Decrement it, making sure to observe all changes made to the queue by the other lock + // owners by using acquire-release ordering. let was_last = tail.next.0.fetch_byte_sub(SINGLE, AcqRel).addr() - SINGLE == 0; if was_last { - // SAFETY: - // Other threads cannot read-lock while threads are queued. Also, - // the `LOCKED` bit is still set, so there are no writers. Therefore, - // the current thread exclusively owns the lock. + // SAFETY: Other threads cannot read-lock while threads are queued. Also, the `LOCKED` + // bit is still set, so there are no writers. Thus the current thread exclusively owns + // this lock, even though it is a reader. unsafe { self.unlock_contended(state) } } } @@ -444,49 +511,143 @@ impl RwLock { if let Err(state) = self.state.compare_exchange(without_provenance_mut(LOCKED), UNLOCKED, Release, Relaxed) { - // SAFETY: - // Since other threads cannot acquire the lock, the state can only - // have changed because there are threads queued on the lock. + // SAFETY: Since other threads cannot acquire the lock, the state can only have changed + // because there are threads queued on the lock. unsafe { self.unlock_contended(state) } } } /// # Safety + /// /// * The lock must be exclusively owned by this thread. /// * There must be threads queued on the lock. + /// * `state` must be a pointer to a node in a valid queue. + /// * There cannot be a `downgrade` in progress. #[cold] - unsafe fn unlock_contended(&self, mut state: State) { + unsafe fn unlock_contended(&self, state: State) { + debug_assert_eq!(state.addr() & (DOWNGRADED | QUEUED | LOCKED), QUEUED | LOCKED); + + let mut current = state; + + // We want to atomically release the lock and try to acquire the queue lock. loop { + // First check if the queue lock is already held. + if current.addr() & QUEUE_LOCKED != 0 { + // Another thread holds the queue lock, so let them wake up waiters for us. + let next = current.mask(!LOCKED); + match self.state.compare_exchange_weak(current, next, Release, Relaxed) { + Ok(_) => return, + Err(new) => { + current = new; + continue; + } + } + } + // Atomically release the lock and try to acquire the queue lock. - let next = state.map_addr(|a| (a & !LOCKED) | QUEUE_LOCKED); - match self.state.compare_exchange_weak(state, next, AcqRel, Relaxed) { - // The queue lock was acquired. Release it, waking up the next - // waiter in the process. - Ok(_) if state.addr() & QUEUE_LOCKED == 0 => unsafe { - return self.unlock_queue(next); - }, - // Another thread already holds the queue lock, leave waking up - // waiters to it. - Ok(_) => return, - Err(new) => state = new, + let next = current.map_addr(|addr| (addr & !LOCKED) | QUEUE_LOCKED); + match self.state.compare_exchange_weak(current, next, AcqRel, Relaxed) { + // Now that we have the queue lock, we can wake up the next waiter. + Ok(_) => { + // SAFETY: This thread just acquired the queue lock, and this function's safety + // contract requires that there are threads already queued on the lock. + unsafe { self.unlock_queue(next) }; + return; + } + Err(new) => current = new, } } } - /// Unlocks the queue. If the lock is unlocked, wakes up the next eligible - /// thread(s). + /// # Safety + /// + /// * The lock must be write-locked by this thread. + #[inline] + pub unsafe fn downgrade(&self) { + // Optimistically change the state from write-locked with a single writer and no waiters to + // read-locked with a single reader and no waiters. + if let Err(state) = self.state.compare_exchange( + without_provenance_mut(LOCKED), + without_provenance_mut(SINGLE | LOCKED), + Release, + Relaxed, + ) { + // SAFETY: The only way the state can have changed is if there are threads queued. + // Wake all of them up. + unsafe { self.downgrade_slow(state) } + } + } + + /// Downgrades the lock from write-locked to read-locked in the case that there are threads + /// waiting on the wait queue. + /// + /// This function will either wake up all of the waiters on the wait queue or designate the + /// current holder of the queue lock to wake up all of the waiters instead. Once the waiters + /// wake up, they will continue in the execution loop of `lock_contended`. /// /// # Safety - /// The queue lock must be held by the current thread. + /// + /// * The lock must be write-locked by this thread. + /// * `state` must be a pointer to a node in a valid queue. + /// * There must be threads queued on the lock. + #[cold] + unsafe fn downgrade_slow(&self, mut state: State) { + debug_assert_eq!(state.addr() & (DOWNGRADED | QUEUED | LOCKED), QUEUED | LOCKED); + + // Attempt to wake up all waiters by taking ownership of the entire waiter queue. + loop { + if state.addr() & QUEUE_LOCKED != 0 { + // Another thread already holds the queue lock. Tell it to wake up all waiters. + // If the other thread succeeds in waking up waiters before we release our lock, the + // effect will be just the same as if we had changed the state below. + // Otherwise, the `DOWNGRADED` bit will still be set, meaning that when this thread + // calls `read_unlock` later (because it holds a read lock and must unlock + // eventually), it will realize that the lock is still exclusively locked and act + // accordingly. + let next = state.map_addr(|addr| addr | DOWNGRADED); + match self.state.compare_exchange_weak(state, next, Release, Relaxed) { + Ok(_) => return, + Err(new) => state = new, + } + } else { + // Grab the entire queue by swapping the `state` with a single reader. + let next = ptr::without_provenance_mut(SINGLE | LOCKED); + if let Err(new) = self.state.compare_exchange_weak(state, next, AcqRel, Relaxed) { + state = new; + continue; + } + + // SAFETY: We have full ownership of this queue now, so nobody else can modify it. + let tail = unsafe { find_tail_and_add_backlinks(to_node(state)) }; + + // Wake up all waiters. + // SAFETY: `tail` was just computed, meaning the whole queue is linked, and we have + // full ownership of the queue, so we have exclusive access. + unsafe { complete_all(tail) }; + + return; + } + } + } + + /// Unlocks the queue. Wakes up all threads if a downgrade was requested, otherwise wakes up the + /// next eligible thread(s) if the lock is unlocked. + /// + /// # Safety + /// + /// * The queue lock must be held by the current thread. + /// * `state` must be a pointer to a node in a valid queue. + /// * There must be threads queued on the lock. unsafe fn unlock_queue(&self, mut state: State) { debug_assert_eq!(state.addr() & (QUEUED | QUEUE_LOCKED), QUEUED | QUEUE_LOCKED); loop { - let tail = unsafe { add_backlinks_and_find_tail(to_node(state)) }; + // SAFETY: Since we have the queue lock, nobody else can be modifying the queue. + let tail = unsafe { find_tail_and_add_backlinks(to_node(state)) }; - if state.addr() & LOCKED == LOCKED { - // Another thread has locked the lock. Leave waking up waiters - // to them by releasing the queue lock. + if state.addr() & (DOWNGRADED | LOCKED) == LOCKED { + // Another thread has locked the lock and no downgrade was requested. + // Leave waking up waiters to them by releasing the queue lock. match self.state.compare_exchange_weak( state, state.mask(!QUEUE_LOCKED), @@ -501,53 +662,63 @@ impl RwLock { } } + // Since we hold the queue lock and downgrades cannot be requested if the lock is + // already read-locked, we have exclusive control over the queue here and can make + // modifications. + + let downgrade = state.addr() & DOWNGRADED != 0; let is_writer = unsafe { tail.as_ref().write }; - if is_writer && let Some(prev) = unsafe { tail.as_ref().prev.get() } { - // `tail` is a writer and there is a node before `tail`. - // Split off `tail`. + if !downgrade + && is_writer + && let Some(prev) = unsafe { tail.as_ref().prev.get() } + { + // If we are not downgrading and the next thread is a writer, only wake up that + // writing thread. - // There are no set `tail` links before the node pointed to by - // `state`, so the first non-null tail field will be current - // (invariant 2). Invariant 4 is fullfilled since `find_tail` - // was called on this node, which ensures all backlinks are set. + // Split off `tail`. + // There are no set `tail` links before the node pointed to by `state`, so the first + // non-null tail field will be current (Invariant 2). + // We also fulfill Invariant 4 since `find_tail` was called on this node, which + // ensures all backlinks are set. unsafe { to_node(state).as_ref().tail.set(Some(prev)); } - // Release the queue lock. Doing this by subtraction is more - // efficient on modern processors since it is a single instruction - // instead of an update loop, which will fail if new threads are - // added to the list. - self.state.fetch_byte_sub(QUEUE_LOCKED, Release); + // Try to release the queue lock. We need to check the state again since another + // thread might have acquired the lock and requested a downgrade. + let next = state.mask(!QUEUE_LOCKED); + if let Err(new) = self.state.compare_exchange_weak(state, next, Release, Acquire) { + // Undo the tail modification above, so that we can find the tail again above. + // As mentioned above, we have exclusive control over the queue, so no other + // thread could have noticed the change. + unsafe { + to_node(state).as_ref().tail.set(Some(tail)); + } + state = new; + continue; + } - // The tail was split off and the lock released. Mark the node as - // completed. + // The tail was split off and the lock was released. Mark the node as completed. unsafe { return Node::complete(tail); } } else { - // The next waiter is a reader or the queue only consists of one - // waiter. Just wake all threads. - - // The lock cannot be locked (checked above), so mark it as - // unlocked to reset the queue. - if let Err(new) = - self.state.compare_exchange_weak(state, UNLOCKED, Release, Acquire) - { + // We are either downgrading, the next waiter is a reader, or the queue only + // consists of one waiter. In any case, just wake all threads. + + // Clear the queue. + let next = + if downgrade { ptr::without_provenance_mut(SINGLE | LOCKED) } else { UNLOCKED }; + if let Err(new) = self.state.compare_exchange_weak(state, next, Release, Acquire) { state = new; continue; } - let mut current = tail; - loop { - let prev = unsafe { current.as_ref().prev.get() }; - unsafe { - Node::complete(current); - } - match prev { - Some(prev) => current = prev, - None => return, - } + // SAFETY: we computed `tail` above, and no new nodes can have been added since + // (otherwise the CAS above would have failed). + // Thus we have complete control over the whole queue. + unsafe { + return complete_all(tail); } } } diff --git a/library/std/src/sys/sync/rwlock/solid.rs b/library/std/src/sys/sync/rwlock/solid.rs index 7703082f951..f664fef9074 100644 --- a/library/std/src/sys/sync/rwlock/solid.rs +++ b/library/std/src/sys/sync/rwlock/solid.rs @@ -79,6 +79,12 @@ impl RwLock { let rwl = self.raw(); expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl"); } + + #[inline] + pub unsafe fn downgrade(&self) { + // The SOLID platform does not support the `downgrade` operation for reader writer locks, so + // this function is simply a no-op as only 1 reader can read: the original writer. + } } impl Drop for RwLock { diff --git a/library/std/src/sys/sync/rwlock/teeos.rs b/library/std/src/sys/sync/rwlock/teeos.rs index 76343022383..4a71a3abc27 100644 --- a/library/std/src/sys/sync/rwlock/teeos.rs +++ b/library/std/src/sys/sync/rwlock/teeos.rs @@ -41,4 +41,10 @@ impl RwLock { pub unsafe fn write_unlock(&self) { unsafe { self.inner.unlock() }; } + + #[inline] + pub unsafe fn downgrade(&self) { + // Since there is no difference between read-locked and write-locked on this platform, this + // function is simply a no-op as only 1 reader can read: the original writer. + } } 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/docker/host-aarch64/aarch64-gnu-debug/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile index dcfea77149e..eb39861d8c7 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile @@ -55,4 +55,4 @@ ENV RUST_CONFIGURE_ARGS \ ENV SCRIPT \ python3 ../x.py --stage 2 build && \ - python3 ../x.py --stage 2 test tests/run-make --test-args clang + python3 ../x.py --stage 2 test tests/run-make diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 340dfd67b7d..9a51a3f4268 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: @@ -477,7 +477,7 @@ auto: --enable-profiler SCRIPT: python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-8c + <<: *job-windows - image: dist-i686-mingw 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/doc/unstable-book/src/language-features/asm-goto.md b/src/doc/unstable-book/src/language-features/asm-goto.md index d72eb7c0c6e..823118bcae1 100644 --- a/src/doc/unstable-book/src/language-features/asm-goto.md +++ b/src/doc/unstable-book/src/language-features/asm-goto.md @@ -21,7 +21,9 @@ unsafe { } ``` -The block must have unit type or diverge. +The block must have unit type or diverge. The block starts a new safety context, +so despite outer `unsafe`, you need extra unsafe to perform unsafe operations +within `label <block>`. When `label <block>` is used together with `noreturn` option, it means that the assembly will not fallthrough. It's allowed to jump to a label within the diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 31e4e79c00a..3fe567b1c39 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -21,7 +21,7 @@ pub(crate) fn synthesize_auto_trait_impls<'tcx>( item_def_id: DefId, ) -> Vec<clean::Item> { let tcx = cx.tcx; - let param_env = tcx.param_env(item_def_id); + let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id); let ty = tcx.type_of(item_def_id).instantiate_identity(); let finder = auto_trait::AutoTraitFinder::new(tcx); @@ -34,7 +34,7 @@ pub(crate) fn synthesize_auto_trait_impls<'tcx>( cx, ty, trait_def_id, - param_env, + typing_env, item_def_id, &finder, DiscardPositiveImpls::No, @@ -42,13 +42,13 @@ pub(crate) fn synthesize_auto_trait_impls<'tcx>( }) .collect(); // We are only interested in case the type *doesn't* implement the `Sized` trait. - if !ty.is_sized(tcx, param_env) + if !ty.is_sized(tcx, typing_env) && let Some(sized_trait_def_id) = tcx.lang_items().sized_trait() && let Some(impl_item) = synthesize_auto_trait_impl( cx, ty, sized_trait_def_id, - param_env, + typing_env, item_def_id, &finder, DiscardPositiveImpls::Yes, @@ -64,7 +64,7 @@ fn synthesize_auto_trait_impl<'tcx>( cx: &mut DocContext<'tcx>, ty: Ty<'tcx>, trait_def_id: DefId, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, item_def_id: DefId, finder: &auto_trait::AutoTraitFinder<'tcx>, discard_positive_impls: DiscardPositiveImpls, @@ -76,7 +76,7 @@ fn synthesize_auto_trait_impl<'tcx>( return None; } - let result = finder.find_auto_trait_generics(ty, param_env, trait_def_id, |info| { + let result = finder.find_auto_trait_generics(ty, typing_env, trait_def_id, |info| { clean_param_env(cx, item_def_id, info.full_user_env, info.region_data, info.vid_to_region) }); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9e11360cab4..031696d445d 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,14 +1814,12 @@ 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 { - // Only anon consts can implicitly capture params. - // FIXME: is this correct behavior? - let param_env = cx.tcx.param_env(*def_id); - cx.tcx.normalize_erasing_regions(param_env, ct) + let typing_env = ty::TypingEnv::post_analysis(cx.tcx, *def_id); + cx.tcx.normalize_erasing_regions(typing_env, ct) } else { ct }; @@ -2039,7 +2038,7 @@ pub(crate) fn clean_middle_ty<'tcx>( format!("{pat:?}").into_boxed_str(), ), ty::Array(ty, n) => { - let n = cx.tcx.normalize_erasing_regions(cx.param_env, n); + let n = cx.tcx.normalize_erasing_regions(cx.typing_env(), n); let n = print_const(cx, n); Array(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), n.into()) } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index e3a0dbe1a7f..a10a6a92bf5 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -772,8 +772,10 @@ impl Item { .find(|field| { let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did)); - tcx.layout_of(tcx.param_env(field.did).and(ty)) - .is_ok_and(|layout| !layout.is_1zst()) + tcx.layout_of( + ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty), + ) + .is_ok_and(|layout| !layout.is_1zst()) }) .map_or_else( || adt.all_fields().any(|field| field.vis.is_public()), diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index e551e0170c6..d59b4e4081c 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -419,7 +419,10 @@ fn print_const_with_custom_print_scalar<'tcx>( } (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Int(i)) => { let ty = ct.ty(); - let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size; + let size = tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) + .unwrap() + .size; let sign_extended_data = int.assert_scalar_int().to_int(size); let mut output = if with_underscores { format_integer_with_underscore_sep(&sign_extended_data.to_string()) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index d5f6bfe415d..a562a9eee71 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -19,7 +19,7 @@ use rustc_hir::{HirId, Path}; use rustc_interface::interface; use rustc_lint::{MissingDoc, late_lint_mod}; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; use rustc_session::config::{self, CrateType, ErrorOutputType, Input, ResolveDocLinks}; pub(crate) use rustc_session::config::{Options, UnstableOptions}; use rustc_session::{Session, lint}; @@ -88,6 +88,13 @@ impl<'tcx> DocContext<'tcx> { ret } + pub(crate) fn typing_env(&self) -> ty::TypingEnv<'tcx> { + ty::TypingEnv { + typing_mode: ty::TypingMode::non_body_analysis(), + param_env: self.param_env, + } + } + /// Call the closure with the given parameters set as /// the generic parameters for a type alias' RHS. pub(crate) fn enter_alias<F, R>( 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/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs index d85ba3a2b14..9317844956d 100644 --- a/src/librustdoc/html/render/type_layout.rs +++ b/src/librustdoc/html/render/type_layout.rs @@ -37,9 +37,9 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>( } let tcx = cx.tcx(); - let param_env = tcx.param_env(ty_def_id); + let typing_env = ty::TypingEnv::post_analysis(tcx, ty_def_id); let ty = tcx.type_of(ty_def_id).instantiate_identity(); - let type_layout = tcx.layout_of(param_env.and(ty)); + let type_layout = tcx.layout_of(typing_env.as_query_input(ty)); let variants = if let Ok(type_layout) = type_layout && let Variants::Multiple { variants, tag, tag_encoding, .. } = @@ -71,7 +71,7 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>( Vec::new() }; - let type_layout_size = tcx.layout_of(param_env.and(ty)).map(|layout| { + let type_layout_size = tcx.layout_of(typing_env.as_query_input(ty)).map(|layout| { let is_unsized = layout.is_unsized(); let is_uninhabited = layout.is_uninhabited(); let size = layout.size.bytes(); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 6d118ae5784..9e5cf497211 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -692,8 +692,6 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) { const quadcolon = /::\s*::/.exec(path); if (path.startsWith("::")) { throw ["Paths cannot start with ", "::"]; - } else if (path.endsWith("::")) { - throw ["Paths cannot end with ", "::"]; } else if (quadcolon !== null) { throw ["Unexpected ", quadcolon[0]]; } @@ -990,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) { @@ -1055,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; @@ -1070,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; } } @@ -1087,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; } } @@ -3974,18 +4017,19 @@ class DocSearch { if (parsedQuery.foundElems === 1 && !parsedQuery.hasReturnArrow) { const elem = parsedQuery.elems[0]; - for (const id of this.nameTrie.search(elem.normalizedPathLast, this.tailTable)) { + // use arrow functions to preserve `this`. + const handleNameSearch = id => { const row = this.searchIndex[id]; if (!typePassesFilter(elem.typeFilter, row.ty) || (filterCrates !== null && row.crate !== filterCrates)) { - continue; + return; } let pathDist = 0; if (elem.fullPath.length > 1) { pathDist = checkPath(elem.pathWithoutLast, row); if (pathDist === null) { - continue; + return; } } @@ -4008,9 +4052,20 @@ class DocSearch { maxEditDistance, ); } + }; + if (elem.normalizedPathLast !== "") { + const last = elem.normalizedPathLast; + for (const id of this.nameTrie.search(last, this.tailTable)) { + handleNameSearch(id); + } } const length = this.searchIndex.length; + for (let i = 0, nSearchIndex = length; i < nSearchIndex; ++i) { + // queries that end in :: bypass the trie + if (elem.normalizedPathLast === "") { + handleNameSearch(i); + } const row = this.searchIndex[i]; if (filterCrates !== null && row.crate !== filterCrates) { continue; diff --git a/src/llvm-project b/src/llvm-project -Subproject b35599be758613448201a49f4b8c7ebfba5558a +Subproject 104d0d16c3c7c3fef2435fef6efb2d57b70fff7 diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 4a2d8dc636445b276288543882e076f254b3ae9 +Subproject 66221abdeca2002d318fde6efff516aab091df0 diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index 0b82c0cd04c..00626a37ef8 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { }, _ => return, } - && let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_id, fn_gen_args) + && let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.typing_env(), fn_id, fn_gen_args) // TODO: This check currently bails if the local variable has no initializer. // That is overly conservative - the lint should fire even if there was no initializer, // but the variable has been initialized before `lhs` was evaluated. diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs index 7d89195eeca..adac2f27ea8 100644 --- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs @@ -62,7 +62,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) - }) .is_some_and(|assoc_item| { let proj = Ty::new_projection(cx.tcx, assoc_item.def_id, cx.tcx.mk_args_trait(ty, [])); - let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj); + let nty = cx.tcx.normalize_erasing_regions(cx.typing_env(), proj); nty.is_bool() }) diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs index 86c5f6b9f0b..46d67e615c7 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs @@ -39,7 +39,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut)) // The `U` in `pointer::cast` have to be `Sized` // as explained here: https://github.com/rust-lang/rust/issues/60602. - && to_pointee_ty.is_sized(cx.tcx, cx.param_env) + && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) { let mut app = Applicability::MachineApplicable; let turbofish = match &cast_to_hir_ty.kind { diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index b167d7f2208..fce7f9985ea 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -15,9 +15,10 @@ use rustc_hir::{ self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TyKind, UnOp, }; +use rustc_hir::def_id::DefId; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt, TypeckResults}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults}; use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -753,10 +754,10 @@ impl TyCoercionStability { fn for_defined_ty<'tcx>(cx: &LateContext<'tcx>, ty: DefinedTy<'tcx>, for_return: bool) -> Self { match ty { DefinedTy::Hir(ty) => Self::for_hir_ty(ty), - DefinedTy::Mir(ty) => Self::for_mir_ty( + DefinedTy::Mir { def_site_def_id, ty } => Self::for_mir_ty( cx.tcx, - ty.param_env, - cx.tcx.instantiate_bound_regions_with_erased(ty.value), + def_site_def_id, + cx.tcx.instantiate_bound_regions_with_erased(ty), for_return, ), } @@ -823,12 +824,15 @@ impl TyCoercionStability { } } - fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>, for_return: bool) -> Self { + fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, def_site_def_id: Option<DefId>, ty: Ty<'tcx>, for_return: bool) -> Self { let ty::Ref(_, mut ty, _) = *ty.kind() else { return Self::None; }; - ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty); + if let Some(def_id) = def_site_def_id { + let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id); + ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + } loop { break match *ty.kind() { ty::Ref(_, ref_ty, _) => { @@ -1027,7 +1031,7 @@ fn report<'tcx>( State::ExplicitDeref { mutability } => { if is_block_like(expr) && let ty::Ref(_, ty, _) = data.adjusted_ty.kind() - && ty.is_sized(cx.tcx, cx.param_env) + && ty.is_sized(cx.tcx, cx.typing_env()) { // Rustc bug: auto deref doesn't work on block expression when targeting sized types. return; diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 0db6a822ec0..3b6b3c89858 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -454,13 +454,13 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id) && !has_non_exhaustive_attr(cx.tcx, *adt) && !ty_implements_eq_trait(cx.tcx, ty, eq_trait_def_id) - && let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id) + && let typing_env = typing_env_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id) && let Some(local_def_id) = adt.did().as_local() // If all of our fields implement `Eq`, we can implement `Eq` too && adt .all_fields() .map(|f| f.ty(cx.tcx, args)) - .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, None, &[])) + .all(|ty| implements_trait_with_env(cx.tcx, typing_env, ty, eq_trait_def_id, None, &[])) { span_lint_hir_and_then( cx, @@ -485,7 +485,7 @@ fn ty_implements_eq_trait<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, eq_trait_id: De } /// Creates the `ParamEnv` used for the give type's derived `Eq` impl. -fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ParamEnv<'_> { +fn typing_env_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ty::TypingEnv<'_> { // Initial map from generic index to param def. // Vec<(param_def, needs_eq)> let mut params = tcx @@ -506,7 +506,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> } } - ParamEnv::new( + let param_env = ParamEnv::new( tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain( params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| { ClauseKind::Trait(TraitPredicate { @@ -517,5 +517,9 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> }), )), Reveal::UserFacing, - ) + ); + ty::TypingEnv { + typing_mode: ty::TypingMode::non_body_analysis(), + param_env, + } } diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs index 55afdbf22e1..617982f4da3 100644 --- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs +++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs @@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { sym::mem_forget if is_copy => return, sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => return, sym::mem_drop - if !(arg_ty.needs_drop(cx.tcx, cx.param_env) + if !(arg_ty.needs_drop(cx.tcx, cx.typing_env()) || is_must_use_func_call(cx, arg) || is_must_use_ty(cx, arg_ty) || drop_is_single_call_in_arm) => @@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { (DROP_NON_DROP, DROP_NON_DROP_SUMMARY.into(), Some(arg.span)) }, sym::mem_forget => { - if arg_ty.needs_drop(cx.tcx, cx.param_env) { + if arg_ty.needs_drop(cx.tcx, cx.typing_env()) { ( MEM_FORGET, Cow::Owned(format!( diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index c74ba088b78..175d92d2d79 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -198,7 +198,7 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet) // primitive types are never mutable ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false, ty::Adt(adt, args) => { - tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.param_env) + tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.typing_env()) || matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::Rc | sym::Arc)) && args.types().any(|ty| is_mutable_ty(cx, ty, tys)) }, diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs index 25105817ad9..4bc6ad0798c 100644 --- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs @@ -70,7 +70,7 @@ fn check_sig(cx: &LateContext<'_>, name: Symbol, sig: &FnSig<'_>, fn_id: LocalDe .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(fn_id).instantiate_identity().output()); let ret_ty = cx .tcx - .try_normalize_erasing_regions(cx.param_env, ret_ty) + .try_normalize_erasing_regions(cx.typing_env(), ret_ty) .unwrap_or(ret_ty); if cx .tcx diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs index 314d0dfa26c..906da81b183 100644 --- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -215,7 +215,7 @@ impl {self_ty_without_ref} {{ && implements_trait(cx, ret_ty, iterator_did, &[]) && let Some(iter_ty) = make_normalized_projection( cx.tcx, - cx.param_env, + cx.typing_env(), iterator_did, sym::Item, [ret_ty], diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs index c5a2760234f..644365c9fe5 100644 --- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, ParamEnv}; +use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Pos, Span}; @@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Array(element_type, cst) = ty.kind() && let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx - .try_normalize_erasing_regions(ParamEnv::empty(), *cst).unwrap_or(*cst).try_to_valtree() + .try_normalize_erasing_regions(cx.typing_env(), *cst).unwrap_or(*cst).try_to_valtree() && let element_count = element_count.to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size) diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs index 25f9be8b2d7..593704f206a 100644 --- a/src/tools/clippy/clippy_lints/src/large_futures.rs +++ b/src/tools/clippy/clippy_lints/src/large_futures.rs @@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeFuture { && let ty = cx.typeck_results().expr_ty(arg) && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() && implements_trait(cx, ty, future_trait_def_id, &[]) - && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) + && let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty)) && let size = layout.layout.size() && size >= Size::from_bytes(self.future_size_threshold) { diff --git a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs index d2bdf194ada..5ed948c02bb 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs @@ -150,11 +150,11 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { } let mir = cx.tcx.optimized_mir(def_id); - let param_env = cx.tcx.param_env(def_id); + let typing_env = mir.typing_env(cx.tcx); let sizes_of_locals = || { mir.local_decls.iter().filter_map(|local| { - let layout = cx.tcx.layout_of(param_env.and(local.ty)).ok()?; + let layout = cx.tcx.layout_of(typing_env.as_query_input(local.ty)).ok()?; Some((local, layout.size.bytes())) }) }; diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs index 0e488cee6b7..5db28e9ae9b 100644 --- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs +++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs @@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { let has_interior_mutability = !cx .typeck_results() .node_type(canonical_id) - .is_freeze(cx.tcx, cx.param_env); + .is_freeze(cx.tcx, cx.typing_env()); if has_interior_mutability { return; } diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs index ee561ea85ed..d999e1a0585 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs @@ -115,11 +115,11 @@ fn is_ref_iterable<'tcx>( .tcx .liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder()) && let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output - && let param_env = cx.tcx.param_env(fn_id) - && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, Some(fn_id), &[]) + && let typing_env = ty::TypingEnv::non_body_analysis(cx.tcx, fn_id) + && implements_trait_with_env(cx.tcx, typing_env, req_self_ty, trait_id, Some(fn_id), &[]) && let Some(into_iter_ty) = - make_normalized_projection_with_regions(cx.tcx, param_env, trait_id, sym!(IntoIter), [req_self_ty]) - && let req_res_ty = normalize_with_regions(cx.tcx, param_env, req_res_ty) + make_normalized_projection_with_regions(cx.tcx, typing_env, trait_id, sym!(IntoIter), [req_self_ty]) + && let req_res_ty = normalize_with_regions(cx.tcx, typing_env, req_res_ty) && into_iter_ty == req_res_ty { let adjustments = typeck.expr_adjustments(self_arg); @@ -151,7 +151,7 @@ fn is_ref_iterable<'tcx>( // Using by value won't consume anything if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty]) && ty == res_ty { return Some((AdjustKind::None, self_ty)); @@ -168,7 +168,7 @@ fn is_ref_iterable<'tcx>( }; if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty]) && ty == res_ty { return Some((AdjustKind::reborrow(mutbl), self_ty)); @@ -181,7 +181,7 @@ fn is_ref_iterable<'tcx>( // Attempt to borrow let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, self_ty, mutbl); if implements_trait(cx, self_ty, trait_id, &[]) - && let Some(ty) = make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty]) + && let Some(ty) = make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty]) && ty == res_ty { return Some((AdjustKind::borrow(mutbl), self_ty)); @@ -204,7 +204,7 @@ fn is_ref_iterable<'tcx>( && target != self_ty && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target]) && ty == res_ty { Some((AdjustKind::auto_reborrow(mutbl), target)) @@ -222,7 +222,7 @@ fn is_ref_iterable<'tcx>( if is_copy(cx, target) && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target]) && ty == res_ty { Some((AdjustKind::Deref, target)) @@ -240,7 +240,7 @@ fn is_ref_iterable<'tcx>( if self_ty.is_ref() && implements_trait(cx, target, trait_id, &[]) && let Some(ty) = - make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target]) + make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target]) && ty == res_ty { Some((AdjustKind::auto_borrow(mutbl), target)) diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs index 223b0630bfd..7aa13d8d5b6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs @@ -148,7 +148,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: _ => {}, } } - requires_copy |= !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); + requires_copy |= !ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()); break; } }, @@ -158,9 +158,9 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: } if can_lint - && (!requires_copy || arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env)) + && (!requires_copy || arg_ty.is_copy_modulo_regions(cx.tcx, cx.typing_env())) // This case could be handled, but a fair bit of care would need to be taken. - && (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.param_env)) + && (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.typing_env())) { if requires_deref { edits.push((param.span.shrink_to_lo(), "&".into())); diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 9c41528e647..c00b9b368c4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -203,10 +203,10 @@ fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool { fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: Ty<'tcx>) -> bool { if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) && let Some(into_iter_trait) = cx.tcx.get_diagnostic_item(sym::IntoIterator) - && let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.param_env, iter_trait, sym::Item, [iter_ty]) + && let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.typing_env(), iter_trait, sym::Item, [iter_ty]) && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, sym::Item, [collect_ty]) && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions( - cx.param_env, + cx.typing_env(), Ty::new_projection_from_args(cx.tcx, into_iter_item_proj.def_id, into_iter_item_proj.args), ) { @@ -237,7 +237,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - ) && let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))]) && let proj_ty = Ty::new_projection_from_args(cx.tcx, iter_item.def_id, args) - && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty) + && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), proj_ty) { item_ty == EarlyBinder::bind(search_ty).instantiate(cx.tcx, cx.typeck_results().node_args(call_id)) } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs index 062d1348555..7d01bdc2269 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs @@ -19,7 +19,7 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, ) { let typeck_results = cx.typeck_results(); - let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck_results); + let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), typeck_results); if let Some(id) = typeck_results.type_dependent_def_id(expr.hir_id) && (cx.tcx.is_diagnostic_item(sym::cmp_ord_min, id) || cx.tcx.is_diagnostic_item(sym::cmp_ord_max, id)) { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 82549413fa9..84ea3554a35 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -578,7 +578,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< if output_ty.contains(param_ty) { if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions( new_subst, - cx.param_env, + cx.typing_env(), bound_fn_sig.rebind(output_ty), ) { expr = parent_expr; diff --git a/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs b/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs index d33021c2a7b..102fa7bc895 100644 --- a/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs +++ b/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs @@ -7,7 +7,7 @@ use super::ZST_OFFSET; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { if let ty::RawPtr(ty, _) = cx.typeck_results().expr_ty(recv).kind() - && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(*ty)) + && let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(*ty)) && layout.is_zst() { span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value"); diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs index 6cddd7ea813..e2ab5e98504 100644 --- a/src/tools/clippy/clippy_lints/src/mut_mut.rs +++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs @@ -80,7 +80,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for MutVisitor<'_, 'tcx> { "generally you want to avoid `&mut &mut _` if possible", ); } else if let ty::Ref(_, ty, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() { - if ty.peel_refs().is_sized(self.cx.tcx, self.cx.param_env) { + if ty.peel_refs().is_sized(self.cx.tcx, self.cx.typing_env()) { span_lint_hir( self.cx, MUT_MUT, diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index c1424b9f1dc..9ebef531bc5 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -85,8 +85,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { && use_cx.same_ctxt && !use_cx.is_ty_unified && let use_node = use_cx.use_node(cx) - && let Some(DefinedTy::Mir(ty)) = use_node.defined_ty(cx) - && let ty::Param(ty) = *ty.value.skip_binder().kind() + && let Some(DefinedTy::Mir { def_site_def_id: _, ty }) = use_node.defined_ty(cx) + && let ty::Param(param_ty) = *ty.skip_binder().kind() && let Some((hir_id, fn_id, i)) = match use_node { ExprUseNode::MethodArg(_, _, 0) => None, ExprUseNode::MethodArg(hir_id, None, i) => cx @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { fn_id, cx.typeck_results().node_args(hir_id), i, - ty, + param_ty, expr, &self.msrv, ) @@ -421,7 +421,7 @@ fn replace_types<'tcx>( .expect_ty(cx.tcx) .to_ty(cx.tcx); - if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection) + if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), projection) && args[term_param_ty.index as usize] != GenericArg::from(projected_ty) { deque.push_back((*term_param_ty, projected_ty)); diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 0775d7abdbb..b65ec8c3c48 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -180,11 +180,16 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { if !is_self(arg) && !ty.is_mutable_ptr() && !is_copy(cx, ty) - && ty.is_sized(cx.tcx, cx.param_env) + && ty.is_sized(cx.tcx, cx.typing_env()) && !allowed_traits.iter().any(|&t| { - implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, t, None, [Option::< - ty::GenericArg<'tcx>, - >::None]) + implements_trait_with_env_from_iter( + cx.tcx, + cx.typing_env(), + ty, + t, + None, + [None::<ty::GenericArg<'tcx>>] + ) }) && !implements_borrow_trait && !all_borrowable_trait diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 5e20b406426..5416e00fe0c 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -270,31 +270,31 @@ impl<'tcx> NonCopyConst<'tcx> { instance, promoted: None, }; - let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx); - let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, DUMMY_SP); + let typing_env = ty::TypingEnv::post_analysis(cx.tcx, def_id); + let result = cx.tcx.const_eval_global_id_for_typeck(typing_env, cid, DUMMY_SP); Self::is_value_unfrozen_raw(cx, result, ty) } fn is_value_unfrozen_expr(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { let args = cx.typeck_results().node_args(hir_id); - let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), DUMMY_SP); + let result = Self::const_eval_resolve(cx.tcx, cx.typing_env(), ty::UnevaluatedConst::new(def_id, args), DUMMY_SP); Self::is_value_unfrozen_raw(cx, result, ty) } pub fn const_eval_resolve( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ct: ty::UnevaluatedConst<'tcx>, span: Span, ) -> EvalToValTreeResult<'tcx> { - match ty::Instance::try_resolve(tcx, param_env, ct.def, ct.args) { + match ty::Instance::try_resolve(tcx, typing_env, ct.def, ct.args) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted: None, }; - tcx.const_eval_global_id_for_typeck(param_env, cid, span) + tcx.const_eval_global_id_for_typeck(typing_env, cid, span) }, Ok(None) => Err(ErrorHandled::TooGeneric(span)), Err(err) => Err(ErrorHandled::Reported(err.into(), span)), @@ -321,7 +321,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { // Normalize assoc types because ones originated from generic params // bounded other traits could have their bound. - let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); + let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); if self.interior_mut.is_interior_mut_ty(cx, normalized) // When there's no default value, lint it only according to its type; // in other words, lint consts whose value *could* be unfrozen, not definitely is. @@ -361,12 +361,12 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { .trait_item_def_id && cx .tcx - .layout_of(cx.tcx.param_env(of_trait_def_id).and( + .layout_of(ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id).as_query_input( // Normalize assoc types because ones originated from generic params // bounded other traits could have their bound at the trait defs; // and, in that case, the definition is *not* generic. cx.tcx.normalize_erasing_regions( - cx.tcx.param_env(of_trait_def_id), + ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id), cx.tcx.type_of(of_assoc_item).instantiate_identity(), ), )) @@ -376,7 +376,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { // similar to unknown layouts. // e.g. `layout_of(...).is_err() || has_frozen_variant(...);` && let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity() - && let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty) + && let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty) && self.interior_mut.is_interior_mut_ty(cx, normalized) && Self::is_value_unfrozen_poly(cx, *body_id, normalized) { @@ -386,7 +386,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { ItemKind::Impl(Impl { of_trait: None, .. }) => { let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity(); // Normalize assoc types originated from generic params. - let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); + let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); if self.interior_mut.is_interior_mut_ty(cx, normalized) && Self::is_value_unfrozen_poly(cx, *body_id, normalized) diff --git a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs index 5d94cfab3b0..1a0bfd8b997 100644 --- a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs @@ -26,7 +26,7 @@ fn comparison_to_const<'tcx>( if let ExprKind::Binary(operator, left, right) = expr.kind && let Ok(cmp_op) = CmpOp::try_from(operator.node) { - let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck); + let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), typeck); match (ecx.eval(left), ecx.eval(right)) { (Some(_), Some(_)) => None, (_, Some(con)) => Some((cmp_op, left, right, con, typeck.expr_ty(right))), diff --git a/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs b/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs index 24bfe2b050b..e3fc8d8fea7 100644 --- a/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs +++ b/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs @@ -39,7 +39,7 @@ fn check_op<'tcx>( other: &Expr<'tcx>, parent: &Expr<'tcx>, ) { - if ConstEvalCtxt::with_env(cx.tcx, cx.param_env, tck).eval_simple(op) == Some(Constant::Int(0)) { + if ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), tck).eval_simple(op) == Some(Constant::Int(0)) { if different_types(tck, other, parent) { return; } diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs index ab5f91c1d67..8272d3643d4 100644 --- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs @@ -17,8 +17,7 @@ pub(crate) fn check<'tcx>( right: &'tcx Expr<'_>, ) { if (op == BinOpKind::Eq || op == BinOpKind::Ne) && is_float(cx, left) { - let typeck = cx.typeck_results(); - let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck); + let ecx = ConstEvalCtxt::new(cx); let left_is_local = match ecx.eval_with_source(left) { Some((c, s)) if !is_allowed(&c) => s.is_local(), Some(_) => return, diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index a00fd01a62e..f69cb9be4ca 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -251,7 +251,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex { let mut applicability = Applicability::MachineApplicable; let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability); - let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) + let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()) && !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); let sugg = if let Some(else_inner) = r#else { if eq_expr_value(cx, caller, peel_blocks(else_inner)) { diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs index dc66fb28fa8..0ac818c21d9 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs @@ -136,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { }); } else if let Some(target_id) = cx.tcx.lang_items().deref_target() { if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions( - cx.param_env, + cx.typing_env(), Ty::new_projection_from_args(cx.tcx, target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])), ) { if deref_ty == expr_ty { diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 1e0f6dff1ab..aeff31d02d2 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -391,7 +391,7 @@ fn check_final_expr<'tcx>( if let Some(inner) = inner { if for_each_unconsumed_temporary(cx, inner, |temporary_ty| { - if temporary_ty.has_significant_drop(cx.tcx, cx.param_env) + if temporary_ty.has_significant_drop(cx.tcx, cx.typing_env()) && temporary_ty .walk() .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if !re.is_static())) diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs index abd8363456d..1a5b958e6a6 100644 --- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs +++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs @@ -154,7 +154,7 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { let ty = self .cx .tcx - .try_normalize_erasing_regions(self.cx.param_env, ty) + .try_normalize_erasing_regions(self.cx.typing_env(), ty) .unwrap_or(ty); match self.type_cache.entry(ty) { Entry::Occupied(e) => return *e.get(), diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs index 52bb7c4bd68..50a1577b288 100644 --- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs +++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs @@ -58,7 +58,7 @@ fn is_struct_with_trailing_zero_sized_array<'tcx>(cx: &LateContext<'tcx>, item: && let Some(last_field) = data.fields().last() && let field_ty = cx .tcx - .normalize_erasing_regions(cx.param_env, cx.tcx.type_of(last_field.def_id).instantiate_identity()) + .normalize_erasing_regions(cx.typing_env(), cx.tcx.type_of(last_field.def_id).instantiate_identity()) && let ty::Array(_, array_len) = *field_ty.kind() && let Some(0) = array_len.try_to_target_usize(cx.tcx) { diff --git a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs index ca9daf2d2a0..1209bd5b34f 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs @@ -88,8 +88,8 @@ pub(super) fn check<'tcx>( && is_normalizable(cx, cx.param_env, to_ty) // we only want to lint if the target type has a niche that is larger than the one of the source type // e.g. `u8` to `NonZero<u8>` should lint, but `NonZero<u8>` to `u8` should not - && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from_ty)) - && let Ok(to_layout) = cx.tcx.layout_of(cx.param_env.and(to_ty)) + && let Ok(from_layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(from_ty)) + && let Ok(to_layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(to_ty)) && match (from_layout.largest_niche, to_layout.largest_niche) { (Some(from_niche), Some(to_niche)) => !range_fully_contained(from_niche.valid_range, to_niche.valid_range), (None, Some(_)) => true, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index 0772b284968..bf6700b1b6b 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>( |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { if from_mutbl == to_mutbl - && to_pointee_ty.is_sized(cx.tcx, cx.param_env) + && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) && msrv.meets(msrvs::POINTER_CAST) { diag.span_suggestion_verbose( diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs index 3b32e4396b9..48d65eb15d9 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -206,12 +206,12 @@ fn reduce_refs<'tcx>(cx: &LateContext<'tcx>, mut from_ty: Ty<'tcx>, mut to_ty: T continue; }, (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(unsized_ty, _)), _) - if !unsized_ty.is_sized(cx.tcx, cx.param_env) => + if !unsized_ty.is_sized(cx.tcx, cx.typing_env()) => { (true, false) }, (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(unsized_ty, _))) - if !unsized_ty.is_sized(cx.tcx, cx.param_env) => + if !unsized_ty.is_sized(cx.tcx, cx.typing_env()) => { (false, true) }, @@ -244,7 +244,7 @@ enum ReducedTy<'tcx> { /// Reduce structs containing a single non-zero sized field to it's contained type. fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> { loop { - ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty); + ty = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty).unwrap_or(ty); return match *ty.kind() { ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => { ReducedTy::TypeErasure { raw_ptr_only: false } @@ -297,8 +297,8 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> } fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) - && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) + if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) + && let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty)) { layout.layout.size().bytes() == 0 } else { diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index e8ccd35b4da..5baa67b1f3e 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -4,10 +4,11 @@ use rustc_middle::ty::Ty; // check if the component types of the transmuted collection and the result have different ABI, // size or alignment pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool { - if let Ok(from) = cx.tcx.try_normalize_erasing_regions(cx.param_env, from) - && let Ok(to) = cx.tcx.try_normalize_erasing_regions(cx.param_env, to) - && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from)) - && let Ok(to_layout) = cx.tcx.layout_of(cx.param_env.and(to)) + let typing_env = cx.typing_env(); + if let Ok(from) = cx.tcx.try_normalize_erasing_regions(typing_env, from) + && let Ok(to) = cx.tcx.try_normalize_erasing_regions(typing_env, to) + && let Ok(from_layout) = cx.tcx.layout_of(typing_env.as_query_input(from)) + && let Ok(to_layout) = cx.tcx.layout_of(typing_env.as_query_input(to)) { from_layout.size != to_layout.size || from_layout.align.abi != to_layout.align.abi } else { diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs index 1a656088b17..de3456a8ba5 100644 --- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs +++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs @@ -60,7 +60,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: // here because `mod.rs` guarantees this lint is only run on types outside of bodies and // is not run on locals. let ty = lower_ty(cx.tcx, hir_ty); - if ty.has_escaping_bound_vars() || !ty.is_sized(cx.tcx, cx.param_env) { + if ty.has_escaping_bound_vars() || !ty.is_sized(cx.tcx, cx.typing_env()) { return false; } hir_ty.span diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs index 230239335c6..9b236d3bda5 100644 --- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>( && let boxed_alloc_ty = last.args.get(1) && let ty_ty = lower_ty(cx.tcx, boxed_ty) && !ty_ty.has_escaping_bound_vars() - && ty_ty.is_sized(cx.tcx, cx.param_env) + && ty_ty.is_sized(cx.tcx, cx.typing_env()) && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes()) && ty_ty_size < box_size_threshold // https://github.com/rust-lang/rust-clippy/issues/7114 diff --git a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs index cfa565cf803..ee9ef017253 100644 --- a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs +++ b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs @@ -46,7 +46,7 @@ impl LateLintPass<'_> for UninhabitedReferences { if let ExprKind::Unary(UnOp::Deref, _) = expr.kind { let ty = cx.typeck_results().expr_ty_adjusted(expr); - if ty.is_privately_uninhabited(cx.tcx, cx.param_env) { + if ty.is_privately_uninhabited(cx.tcx, cx.typing_env()) { span_lint( cx, UNINHABITED_REFERENCES, @@ -71,7 +71,7 @@ impl LateLintPass<'_> for UninhabitedReferences { } if let FnRetTy::Return(hir_ty) = fndecl.output && let TyKind::Ref(_, mut_ty) = hir_ty.kind - && lower_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.param_env) + && lower_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.typing_env()) { span_lint( cx, diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs index 14f4aa6676b..34df1d5560a 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs @@ -82,7 +82,7 @@ impl UnnecessaryBoxReturns { // It's sometimes useful to return Box<T> if T is unsized, so don't lint those. // Also, don't lint if we know that T is very large, in which case returning // a Box<T> may be beneficial. - if boxed_ty.is_sized(cx.tcx, cx.param_env) && approx_ty_size(cx, boxed_ty) <= self.maximum_size { + if boxed_ty.is_sized(cx.tcx, cx.typing_env()) && approx_ty_size(cx, boxed_ty) <= self.maximum_size { span_lint_and_then( cx, UNNECESSARY_BOX_RETURNS, diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 24a02c7ef87..52c98646289 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -18,7 +18,7 @@ use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir::ConstValue; use rustc_middle::mir::interpret::{Scalar, alloc_range}; -use rustc_middle::ty::{self, FloatTy, IntTy, ParamEnv, ScalarInt, Ty, TyCtxt, TypeckResults, UintTy}; +use rustc_middle::ty::{self, FloatTy, IntTy, ScalarInt, Ty, TyCtxt, TypeckResults, UintTy}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::def_id::DefId; use rustc_span::symbol::Ident; @@ -387,7 +387,7 @@ impl Ord for FullInt { /// See the module level documentation for some context. pub struct ConstEvalCtxt<'tcx> { tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, typeck: &'tcx TypeckResults<'tcx>, source: Cell<ConstantSource>, } @@ -398,17 +398,17 @@ impl<'tcx> ConstEvalCtxt<'tcx> { pub fn new(cx: &LateContext<'tcx>) -> Self { Self { tcx: cx.tcx, - param_env: cx.param_env, + typing_env: cx.typing_env(), typeck: cx.typeck_results(), source: Cell::new(ConstantSource::Local), } } /// Creates an evaluation context. - pub fn with_env(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, typeck: &'tcx TypeckResults<'tcx>) -> Self { + pub fn with_env(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, typeck: &'tcx TypeckResults<'tcx>) -> Self { Self { tcx, - param_env, + typing_env, typeck, source: Cell::new(ConstantSource::Local), } @@ -643,7 +643,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { let args = self.typeck.node_args(id); let result = self .tcx - .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), qpath.span()) + .const_eval_resolve(self.typing_env, mir::UnevaluatedConst::new(def_id, args), qpath.span()) .ok() .map(|val| mir::Const::from_value(val, ty))?; f(self, result) diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index a2e97919d04..7f0363ac942 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -105,7 +105,7 @@ fn res_has_significant_drop(res: Res, cx: &LateContext<'_>, e: &Expr<'_>) -> boo { cx.typeck_results() .expr_ty(e) - .has_significant_drop(cx.tcx, cx.param_env) + .has_significant_drop(cx.tcx, cx.typing_env()) } else { false } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index c73ab4bfa68..ea866a78d87 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -297,8 +297,8 @@ impl HirEqInterExpr<'_, '_, '_> { if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results && typeck_lhs.expr_ty(left) == typeck_rhs.expr_ty(right) && let (Some(l), Some(r)) = ( - ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.param_env, typeck_lhs).eval_simple(left), - ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.param_env, typeck_rhs).eval_simple(right), + ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.typing_env(), typeck_lhs).eval_simple(left), + ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.typing_env(), typeck_rhs).eval_simple(right), ) && l == r { @@ -813,7 +813,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { #[expect(clippy::too_many_lines)] pub fn hash_expr(&mut self, e: &Expr<'_>) { let simple_const = self.maybe_typeck_results.and_then(|typeck_results| { - ConstEvalCtxt::with_env(self.cx.tcx, self.cx.param_env, typeck_results).eval_simple(e) + ConstEvalCtxt::with_env(self.cx.tcx, self.cx.typing_env(), typeck_results).eval_simple(e) }); // const hashing may result in the same hash as some unrelated node, so add a sort of diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 19316a90683..6408cc938cb 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -116,8 +116,8 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ - self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgsRef, IntTy, ParamEnv, - ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, UintTy, UpvarCapture, + self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgsRef, IntTy, + Ty, TyCtxt, TypeVisitableExt, UintTy, UpvarCapture, }; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; @@ -1631,7 +1631,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool } let enclosing_body = cx.tcx.hir().enclosing_body_owner(e.hir_id); if let Some(Constant::Int(v)) = - ConstEvalCtxt::with_env(cx.tcx, cx.tcx.param_env(enclosing_body), cx.tcx.typeck(enclosing_body)).eval(e) + ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), cx.tcx.typeck(enclosing_body)).eval(e) { return value == v; } @@ -2712,9 +2712,17 @@ pub fn walk_to_expr_usage<'tcx, T>( pub enum DefinedTy<'tcx> { // Used for locals and closures defined within the function. Hir(&'tcx hir::Ty<'tcx>), - /// Used for function signatures, and constant and static values. This includes the `ParamEnv` - /// from the definition site. - Mir(ParamEnvAnd<'tcx, Binder<'tcx, Ty<'tcx>>>), + /// Used for function signatures, and constant and static values. The type is + /// in the context of its definition site. We also track the `def_id` of its + /// definition site. + /// + /// WARNING: As the `ty` in in the scope of the definition, not of the function + /// using it, you must be very careful with how you use it. Using it in the wrong + /// scope easily results in ICEs. + Mir { + def_site_def_id: Option<DefId>, + ty: Binder<'tcx, Ty<'tcx>>, + }, } /// The context an expressions value is used in. @@ -2833,10 +2841,10 @@ impl<'tcx> ExprUseNode<'tcx> { pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option<DefinedTy<'tcx>> { match *self { Self::LetStmt(LetStmt { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)), - Self::ConstStatic(id) => Some(DefinedTy::Mir( - cx.param_env - .and(Binder::dummy(cx.tcx.type_of(id).instantiate_identity())), - )), + Self::ConstStatic(id) => Some(DefinedTy::Mir { + def_site_def_id: Some(id.def_id.to_def_id()), + ty: Binder::dummy(cx.tcx.type_of(id).instantiate_identity()), + }), Self::Return(id) => { if let Node::Expr(Expr { kind: ExprKind::Closure(c), @@ -2848,9 +2856,8 @@ impl<'tcx> ExprUseNode<'tcx> { FnRetTy::Return(ty) => Some(DefinedTy::Hir(ty)), } } else { - Some(DefinedTy::Mir( - cx.param_env.and(cx.tcx.fn_sig(id).instantiate_identity().output()), - )) + let ty = cx.tcx.fn_sig(id).instantiate_identity().output(); + Some(DefinedTy::Mir { def_site_def_id: Some(id.def_id.to_def_id()), ty }) } }, Self::Field(field) => match get_parent_expr_for_hir(cx, field.hir_id) { @@ -2866,12 +2873,9 @@ impl<'tcx> ExprUseNode<'tcx> { .find(|f| f.name == field.ident.name) .map(|f| (adt, f)) }) - .map(|(adt, field_def)| { - DefinedTy::Mir( - cx.tcx - .param_env(adt.did()) - .and(Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity())), - ) + .map(|(adt, field_def)| DefinedTy::Mir { + def_site_def_id: Some(adt.did()), + ty: Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity()), }), _ => None, }, @@ -2880,17 +2884,19 @@ impl<'tcx> ExprUseNode<'tcx> { let (hir_ty, ty) = sig.input_with_hir(i)?; Some(match hir_ty { Some(hir_ty) => DefinedTy::Hir(hir_ty), - None => DefinedTy::Mir( - sig.predicates_id() - .map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id)) - .and(ty), - ), + None => DefinedTy::Mir { + def_site_def_id: sig.predicates_id(), + ty, + } }) }, Self::MethodArg(id, _, i) => { let id = cx.typeck_results().type_dependent_def_id(id)?; let sig = cx.tcx.fn_sig(id).skip_binder(); - Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i)))) + Some(DefinedTy::Mir { + def_site_def_id: Some(id), + ty: sig.input(i), + }) }, Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Other | Self::AddrOf(..) => None, } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 971f8eeb1b3..345c46f944a 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -142,7 +142,7 @@ fn check_rvalue<'tcx>( // We cannot allow this for now. return Err((span, "unsizing casts are only allowed for references right now".into())); }; - let unsized_ty = tcx.struct_tail_for_codegen(pointee_ty, tcx.param_env(def_id)); + let unsized_ty = tcx.struct_tail_for_codegen(pointee_ty, ty::TypingEnv::post_analysis(tcx, def_id)); if let ty::Slice(_) | ty::Str = unsized_ty.kind() { check_operand(tcx, op, span, body, msrv)?; // Casting/coercing things to slices is fine. @@ -233,6 +233,7 @@ fn check_statement<'tcx>( | StatementKind::PlaceMention(..) | StatementKind::Coverage(..) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => Ok(()), } } @@ -408,15 +409,17 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx> return true; } + + let (infcx, param_env) = + tcx.infer_ctxt().build_with_typing_env(body.typing_env(tcx)); // FIXME(const_trait_impl) constness let obligation = Obligation::new( tcx, ObligationCause::dummy_with_span(body.span), - ConstCx::new(tcx, body).param_env, + param_env, TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]), ); - let infcx = tcx.infer_ctxt().build(body.typing_mode(tcx)); let mut selcx = SelectionContext::new(&infcx); let Some(impl_src) = selcx.select(&obligation).ok().flatten() else { return false; @@ -434,5 +437,5 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx> ocx.select_all_or_error().is_empty() } - !ty.needs_drop(tcx, ConstCx::new(tcx, body).param_env) + !ty.needs_drop(tcx, ConstCx::new(tcx, body).typing_env) } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 770cd9c3786..3498606dfd3 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, UintTy, Upcast, VariantDef, VariantDiscr, + TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; @@ -38,7 +38,7 @@ pub use type_certainty::expr_type_is_certain; /// Checks if the given type implements copy. pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - ty.is_copy_modulo_regions(cx.tcx, cx.param_env) + ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()) } /// This checks whether a given type is known to implement Debug. @@ -226,7 +226,7 @@ pub fn implements_trait<'tcx>( trait_id: DefId, args: &[GenericArg<'tcx>], ) -> bool { - implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, trait_id, None, args.iter().map(|&x| Some(x))) + implements_trait_with_env_from_iter(cx.tcx, cx.typing_env(), ty, trait_id, None, args.iter().map(|&x| Some(x))) } /// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context. @@ -235,19 +235,19 @@ pub fn implements_trait<'tcx>( /// environment, used for checking const traits. pub fn implements_trait_with_env<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, trait_id: DefId, callee_id: Option<DefId>, args: &[GenericArg<'tcx>], ) -> bool { - implements_trait_with_env_from_iter(tcx, param_env, ty, trait_id, callee_id, args.iter().map(|&x| Some(x))) + implements_trait_with_env_from_iter(tcx, typing_env, ty, trait_id, callee_id, args.iter().map(|&x| Some(x))) } /// Same as `implements_trait_from_env` but takes the arguments as an iterator. pub fn implements_trait_with_env_from_iter<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, trait_id: DefId, callee_id: Option<DefId>, @@ -268,7 +268,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>( return false; } - let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); let args = args .into_iter() .map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into())) @@ -467,7 +467,7 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { if !seen.insert(ty) { return false; } - if !ty.has_significant_drop(cx.tcx, cx.param_env) { + if !ty.has_significant_drop(cx.tcx, cx.typing_env()) { false } // Check for std types which implement drop, but only for memory allocation. @@ -575,8 +575,9 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { /// Checks if a given type looks safe to be uninitialized. pub fn is_uninit_value_valid_for_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + let typing_env = cx.typing_env().with_reveal_all_normalized(cx.tcx); cx.tcx - .check_validity_requirement((ValidityRequirement::Uninit, cx.param_env.and(ty))) + .check_validity_requirement((ValidityRequirement::Uninit, typing_env.as_query_input(ty))) .unwrap_or_else(|_| is_uninit_value_valid_for_ty_fallback(cx, ty)) } @@ -725,7 +726,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t _ => None, } }, - ty::Alias(ty::Projection, proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) { + ty::Alias(ty::Projection, proj) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) { Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty), _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), }, @@ -1111,12 +1112,12 @@ pub fn make_projection<'tcx>( /// succeeds as well as everything checked by `make_projection`. pub fn make_normalized_projection<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, container_id: DefId, assoc_ty: Symbol, args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>, ) -> Option<Ty<'tcx>> { - fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> { + fn helper<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> { #[cfg(debug_assertions)] if let Some((i, arg)) = ty .args @@ -1132,7 +1133,7 @@ pub fn make_normalized_projection<'tcx>( ); return None; } - match tcx.try_normalize_erasing_regions(param_env, Ty::new_projection_from_args(tcx, ty.def_id, ty.args)) { + match tcx.try_normalize_erasing_regions(typing_env, Ty::new_projection_from_args(tcx, ty.def_id, ty.args)) { Ok(ty) => Some(ty), Err(e) => { debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}"); @@ -1140,7 +1141,7 @@ pub fn make_normalized_projection<'tcx>( }, } } - helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, args)?) + helper(tcx, typing_env, make_projection(tcx, container_id, assoc_ty, args)?) } /// Helper to check if given type has inner mutability such as [`std::cell::Cell`] or @@ -1238,12 +1239,12 @@ impl<'tcx> InteriorMut<'tcx> { pub fn make_normalized_projection_with_regions<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, container_id: DefId, assoc_ty: Symbol, args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>, ) -> Option<Ty<'tcx>> { - fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> { + fn helper<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> { #[cfg(debug_assertions)] if let Some((i, arg)) = ty .args @@ -1260,10 +1261,8 @@ pub fn make_normalized_projection_with_regions<'tcx>( return None; } let cause = ObligationCause::dummy(); - match tcx - .infer_ctxt() - .build(TypingMode::from_param_env(param_env)) - .at(&cause, param_env) + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + match infcx.at(&cause, param_env) .query_normalize(Ty::new_projection_from_args(tcx, ty.def_id, ty.args)) { Ok(ty) => Some(ty.value), @@ -1273,20 +1272,13 @@ pub fn make_normalized_projection_with_regions<'tcx>( }, } } - helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, args)?) + helper(tcx, typing_env, make_projection(tcx, container_id, assoc_ty, args)?) } -pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { +pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { let cause = ObligationCause::dummy(); - match tcx - .infer_ctxt() - .build(TypingMode::from_param_env(param_env)) - .at(&cause, param_env) - .query_normalize(ty) - { - Ok(ty) => ty.value, - Err(_) => ty, - } + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + infcx.at(&cause, param_env).query_normalize(ty).map_or(ty, |ty| ty.value) } /// Checks if the type is `core::mem::ManuallyDrop<_>` @@ -1300,7 +1292,7 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl if let Some(deref_did) = cx.tcx.lang_items().deref_trait() && implements_trait(cx, ty, deref_did, &[]) { - make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty]) + make_normalized_projection(cx.tcx, cx.typing_env(), deref_did, sym::Target, [ty]) } else { None } 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/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 16fcc26be33..a855603eeb3 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -12,7 +12,7 @@ use std::{cmp, mem}; use rustc_abi::{BackendRepr, Size}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::{Mutability, RetagKind}; -use rustc_middle::ty::layout::HasParamEnv; +use rustc_middle::ty::layout::HasTypingEnv; use rustc_middle::ty::{self, Ty}; use self::diagnostics::{RetagCause, RetagInfo}; @@ -71,7 +71,7 @@ impl NewPermission { access: None, protector: None, } - } else if pointee.is_unpin(*cx.tcx, cx.param_env()) { + } else if pointee.is_unpin(*cx.tcx, cx.typing_env()) { // A regular full mutable reference. On `FnEntry` this is `noalias` and `dereferenceable`. NewPermission::Uniform { perm: Permission::Unique, @@ -129,7 +129,7 @@ impl NewPermission { fn from_box_ty<'tcx>(ty: Ty<'tcx>, kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>) -> Self { // `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling). let pointee = ty.builtin_deref(true).unwrap(); - if pointee.is_unpin(*cx.tcx, cx.param_env()) { + if pointee.is_unpin(*cx.tcx, cx.typing_env()) { // A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only // a weak protector). NewPermission::Uniform { @@ -608,7 +608,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { match new_perm { NewPermission::Uniform { perm, .. } => write!(kind_str, "{perm:?} permission").unwrap(), - NewPermission::FreezeSensitive { freeze_perm, .. } if ty.is_freeze(*this.tcx, this.param_env()) => + NewPermission::FreezeSensitive { freeze_perm, .. } if ty.is_freeze(*this.tcx, this.typing_env()) => write!(kind_str, "{freeze_perm:?} permission").unwrap(), NewPermission::FreezeSensitive { freeze_perm, nonfreeze_perm, .. } => write!(kind_str, "{freeze_perm:?}/{nonfreeze_perm:?} permission for frozen/non-frozen parts").unwrap(), diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index f92150758dc..8469744bbc4 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -1,6 +1,6 @@ use rustc_abi::{BackendRepr, Size}; use rustc_middle::mir::{Mutability, RetagKind}; -use rustc_middle::ty::layout::HasParamEnv; +use rustc_middle::ty::layout::HasTypingEnv; use rustc_middle::ty::{self, Ty}; use rustc_span::def_id::DefId; @@ -132,8 +132,8 @@ impl<'tcx> NewPermission { kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>, ) -> Option<Self> { - let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.param_env()); - let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.param_env()); + let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env()); + let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.typing_env()); let is_protected = kind == RetagKind::FnEntry; // As demonstrated by `tests/fail/tree_borrows/reservedim_spurious_write.rs`, // interior mutability and protectors interact poorly. @@ -164,10 +164,10 @@ impl<'tcx> NewPermission { zero_size: bool, ) -> Option<Self> { let pointee = ty.builtin_deref(true).unwrap(); - pointee.is_unpin(*cx.tcx, cx.param_env()).then_some(()).map(|()| { + pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| { // Regular `Unpin` box, give it `noalias` but only a weak protector // because it is valid to deallocate it within the function. - let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.param_env()); + let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.typing_env()); let protected = kind == RetagKind::FnEntry; let initial_state = Permission::new_reserved(ty_is_freeze, protected); Self { @@ -521,7 +521,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Note: if we were to inline `new_reserved` below we would find out that // `ty_is_freeze` is eventually unused because it appears in a `ty_is_freeze || true`. // We are nevertheless including it here for clarity. - let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.param_env()); + let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env()); // Retag it. With protection! That is the entire point. let new_perm = NewPermission { initial_state: Permission::new_reserved(ty_is_freeze, /* protected */ true), diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 1e56e104918..85591a0b370 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -268,10 +268,14 @@ pub fn create_ecx<'tcx>( entry_type: EntryFnType, config: &MiriConfig, ) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> { - let param_env = ty::ParamEnv::reveal_all(); - let layout_cx = LayoutCx::new(tcx, param_env); - let mut ecx = - InterpCx::new(tcx, rustc_span::DUMMY_SP, param_env, MiriMachine::new(config, layout_cx)); + let typing_env = ty::TypingEnv::fully_monomorphized(); + let layout_cx = LayoutCx::new(tcx, typing_env); + let mut ecx = InterpCx::new( + tcx, + rustc_span::DUMMY_SP, + typing_env, + MiriMachine::new(config, layout_cx) + ); // Some parts of initialization require a full `InterpCx`. MiriMachine::late_init(&mut ecx, config, { @@ -376,7 +380,7 @@ pub fn create_ecx<'tcx>( let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); let start_instance = ty::Instance::try_resolve( tcx, - ty::ParamEnv::reveal_all(), + typing_env, start_id, tcx.mk_args(&[ty::GenericArg::from(main_ret_ty)]), ) diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 526030bef2e..4b34f1686a0 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -116,8 +116,8 @@ pub fn resolve_path<'tcx>( /// Gets the layout of a type at a path. #[track_caller] pub fn path_ty_layout<'tcx>(cx: &impl LayoutOf<'tcx>, path: &[&str]) -> TyAndLayout<'tcx> { - let ty = - resolve_path(cx.tcx(), path, Namespace::TypeNS).ty(cx.tcx(), ty::ParamEnv::reveal_all()); + let ty = resolve_path(cx.tcx(), path, Namespace::TypeNS) + .ty(cx.tcx(), cx.typing_env()); cx.layout_of(ty).to_result().ok().unwrap() } diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 9668998aaa3..7b03aed4763 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -17,7 +17,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::static_assert_size; use rustc_middle::mir; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{ + HasTyCtxt, HasTypingEnv, LayoutCx, LayoutError, LayoutOf, TyAndLayout, +}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::config::InliningThreshold; use rustc_span::def_id::{CrateNum, DefId}; @@ -1127,7 +1129,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { }; let info = ecx.get_alloc_info(alloc_id); let def_ty = ecx.tcx.type_of(def_id).instantiate_identity(); - let extern_decl_layout = ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap(); + let extern_decl_layout = + ecx.tcx.layout_of(ecx.typing_env().as_query_input(def_ty)).unwrap(); if extern_decl_layout.size != info.size || extern_decl_layout.align.abi != info.align { throw_unsup_format!( "extern static `{link_name}` has been declared as `{krate}::{name}` \ diff --git a/src/tools/miri/tests/pass/shims/time-with-isolation.stdout b/src/tools/miri/tests/pass/shims/time-with-isolation.stdout index 2d7fb5f4a61..6058735f005 100644 --- a/src/tools/miri/tests/pass/shims/time-with-isolation.stdout +++ b/src/tools/miri/tests/pass/shims/time-with-isolation.stdout @@ -1,2 +1,2 @@ -The loop took around 1250ms +The loop took around 1350ms (It's fine for this number to change when you `--bless` this test.) diff --git a/src/tools/run-make-support/src/external_deps/c_build.rs b/src/tools/run-make-support/src/external_deps/c_build.rs index f8d1666adda..9dd30713f95 100644 --- a/src/tools/run-make-support/src/external_deps/c_build.rs +++ b/src/tools/run-make-support/src/external_deps/c_build.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use crate::artifact_names::{dynamic_lib_name, static_lib_name}; -use crate::external_deps::cc::{cc, cxx}; +use crate::external_deps::c_cxx_compiler::{cc, cxx}; use crate::external_deps::llvm::llvm_ar; use crate::path_helpers::path; use crate::targets::{is_darwin, is_msvc, is_windows}; diff --git a/src/tools/run-make-support/src/external_deps/cc.rs b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/cc.rs index 011ad89e170..becb91ae989 100644 --- a/src/tools/run-make-support/src/external_deps/cc.rs +++ b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/cc.rs @@ -1,7 +1,7 @@ use std::path::Path; use crate::command::Command; -use crate::{env_var, is_msvc, is_windows, uname}; +use crate::{env_var, is_msvc}; /// Construct a new platform-specific C compiler invocation. /// @@ -127,99 +127,3 @@ impl Cc { self } } - -/// `EXTRACFLAGS` -pub fn extra_c_flags() -> Vec<&'static str> { - // Adapted from tools.mk (trimmed): - // - // ```makefile - // ifdef IS_WINDOWS - // ifdef IS_MSVC - // EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib synchronization.lib - // else - // EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll -lsynchronization - // endif - // else - // ifeq ($(UNAME),Darwin) - // EXTRACFLAGS := -lresolv - // else - // ifeq ($(UNAME),FreeBSD) - // EXTRACFLAGS := -lm -lpthread -lgcc_s - // else - // ifeq ($(UNAME),SunOS) - // EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv - // else - // ifeq ($(UNAME),OpenBSD) - // EXTRACFLAGS := -lm -lpthread -lc++abi - // else - // EXTRACFLAGS := -lm -lrt -ldl -lpthread - // endif - // endif - // endif - // endif - // endif - // ``` - - if is_windows() { - if is_msvc() { - vec![ - "ws2_32.lib", - "userenv.lib", - "advapi32.lib", - "bcrypt.lib", - "ntdll.lib", - "synchronization.lib", - ] - } else { - vec!["-lws2_32", "-luserenv", "-lbcrypt", "-lntdll", "-lsynchronization"] - } - } else { - match uname() { - n if n.contains("Darwin") => vec!["-lresolv"], - n if n.contains("FreeBSD") => vec!["-lm", "-lpthread", "-lgcc_s"], - n if n.contains("SunOS") => { - vec!["-lm", "-lpthread", "-lposix4", "-lsocket", "-lresolv"] - } - n if n.contains("OpenBSD") => vec!["-lm", "-lpthread", "-lc++abi"], - _ => vec!["-lm", "-lrt", "-ldl", "-lpthread"], - } - } -} - -/// `EXTRACXXFLAGS` -pub fn extra_cxx_flags() -> Vec<&'static str> { - // Adapted from tools.mk (trimmed): - // - // ```makefile - // ifdef IS_WINDOWS - // ifdef IS_MSVC - // else - // EXTRACXXFLAGS := -lstdc++ - // endif - // else - // ifeq ($(UNAME),Darwin) - // EXTRACXXFLAGS := -lc++ - // else - // ifeq ($(UNAME),FreeBSD) - // else - // ifeq ($(UNAME),SunOS) - // else - // ifeq ($(UNAME),OpenBSD) - // else - // EXTRACXXFLAGS := -lstdc++ - // endif - // endif - // endif - // endif - // endif - // ``` - if is_windows() { - if is_msvc() { vec![] } else { vec!["-lstdc++"] } - } else { - match &uname()[..] { - "Darwin" => vec!["-lc++"], - "FreeBSD" | "SunOS" | "OpenBSD" => vec![], - _ => vec!["-lstdc++"], - } - } -} diff --git a/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs new file mode 100644 index 00000000000..49210d75e06 --- /dev/null +++ b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs @@ -0,0 +1,97 @@ +use crate::{is_msvc, is_windows, uname}; + +/// `EXTRACFLAGS` +pub fn extra_c_flags() -> Vec<&'static str> { + // Adapted from tools.mk (trimmed): + // + // ```makefile + // ifdef IS_WINDOWS + // ifdef IS_MSVC + // EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib synchronization.lib + // else + // EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll -lsynchronization + // endif + // else + // ifeq ($(UNAME),Darwin) + // EXTRACFLAGS := -lresolv + // else + // ifeq ($(UNAME),FreeBSD) + // EXTRACFLAGS := -lm -lpthread -lgcc_s + // else + // ifeq ($(UNAME),SunOS) + // EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv + // else + // ifeq ($(UNAME),OpenBSD) + // EXTRACFLAGS := -lm -lpthread -lc++abi + // else + // EXTRACFLAGS := -lm -lrt -ldl -lpthread + // endif + // endif + // endif + // endif + // endif + // ``` + + if is_windows() { + if is_msvc() { + vec![ + "ws2_32.lib", + "userenv.lib", + "advapi32.lib", + "bcrypt.lib", + "ntdll.lib", + "synchronization.lib", + ] + } else { + vec!["-lws2_32", "-luserenv", "-lbcrypt", "-lntdll", "-lsynchronization"] + } + } else { + match uname() { + n if n.contains("Darwin") => vec!["-lresolv"], + n if n.contains("FreeBSD") => vec!["-lm", "-lpthread", "-lgcc_s"], + n if n.contains("SunOS") => { + vec!["-lm", "-lpthread", "-lposix4", "-lsocket", "-lresolv"] + } + n if n.contains("OpenBSD") => vec!["-lm", "-lpthread", "-lc++abi"], + _ => vec!["-lm", "-lrt", "-ldl", "-lpthread"], + } + } +} + +/// `EXTRACXXFLAGS` +pub fn extra_cxx_flags() -> Vec<&'static str> { + // Adapted from tools.mk (trimmed): + // + // ```makefile + // ifdef IS_WINDOWS + // ifdef IS_MSVC + // else + // EXTRACXXFLAGS := -lstdc++ + // endif + // else + // ifeq ($(UNAME),Darwin) + // EXTRACXXFLAGS := -lc++ + // else + // ifeq ($(UNAME),FreeBSD) + // else + // ifeq ($(UNAME),SunOS) + // else + // ifeq ($(UNAME),OpenBSD) + // else + // EXTRACXXFLAGS := -lstdc++ + // endif + // endif + // endif + // endif + // endif + // ``` + if is_windows() { + if is_msvc() { vec![] } else { vec!["-lstdc++"] } + } else { + match &uname()[..] { + "Darwin" => vec!["-lc++"], + "FreeBSD" | "SunOS" | "OpenBSD" => vec![], + _ => vec!["-lstdc++"], + } + } +} diff --git a/src/tools/run-make-support/src/external_deps/c_cxx_compiler/gcc.rs b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/gcc.rs new file mode 100644 index 00000000000..e02c4f97255 --- /dev/null +++ b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/gcc.rs @@ -0,0 +1,66 @@ +use std::path::Path; + +use crate::command::Command; + +/// Construct a gcc invocation. +/// +/// WARNING: This assumes *a* `gcc` exists in the environment and is suitable for use. +#[track_caller] +pub fn gcc() -> Gcc { + Gcc::new() +} + +/// A specific `gcc`. +#[derive(Debug)] +#[must_use] +pub struct Gcc { + cmd: Command, +} + +crate::macros::impl_common_helpers!(Gcc); + +impl Gcc { + /// Construct a `gcc` invocation. This assumes that *a* suitable `gcc` is available in the + /// environment. + /// + /// Note that this does **not** prepopulate the `gcc` invocation with `CC_DEFAULT_FLAGS`. + #[track_caller] + pub fn new() -> Self { + let cmd = Command::new("gcc"); + Self { cmd } + } + + /// Specify path of the input file. + pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { + self.cmd.arg(path.as_ref()); + self + } + + /// Adds directories to the list that the linker searches for libraries. + /// Equivalent to `-L`. + pub fn library_search_path<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { + self.cmd.arg("-L"); + self.cmd.arg(path.as_ref()); + self + } + + /// Specify `-o`. + pub fn out_exe(&mut self, name: &str) -> &mut Self { + self.cmd.arg("-o"); + self.cmd.arg(name); + self + } + + /// Specify path of the output binary. + pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { + self.cmd.arg("-o"); + self.cmd.arg(path.as_ref()); + self + } + + /// Optimize the output at `-O3`. + pub fn optimize(&mut self) -> &mut Self { + self.cmd.arg("-O3"); + self + } +} diff --git a/src/tools/run-make-support/src/external_deps/c_cxx_compiler/mod.rs b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/mod.rs new file mode 100644 index 00000000000..9aaefd8aa47 --- /dev/null +++ b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/mod.rs @@ -0,0 +1,7 @@ +mod cc; +mod extras; +mod gcc; + +pub use cc::*; +pub use extras::*; +pub use gcc::*; diff --git a/src/tools/run-make-support/src/external_deps/mod.rs b/src/tools/run-make-support/src/external_deps/mod.rs index 80c34a9070f..129b06761ef 100644 --- a/src/tools/run-make-support/src/external_deps/mod.rs +++ b/src/tools/run-make-support/src/external_deps/mod.rs @@ -2,8 +2,8 @@ //! such as `cc` or `python`. pub mod c_build; +pub mod c_cxx_compiler; pub mod cargo; -pub mod cc; pub mod clang; pub mod htmldocck; pub mod llvm; diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 6cf0aedfe9f..819bbc161e6 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -46,10 +46,10 @@ pub use wasmparser; // tidy-alphabetical-end // Re-exports of external dependencies. -pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rustdoc}; +pub use external_deps::{c_build, c_cxx_compiler, clang, htmldocck, llvm, python, rustc, rustdoc}; // These rely on external dependencies. -pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc}; +pub use c_cxx_compiler::{Cc, Gcc, cc, cxx, extra_c_flags, extra_cxx_flags, gcc}; pub use c_build::{ build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_cxx, build_native_static_lib_optimized, diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 55705de9b2c..019609e6a5b 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -2625,18 +2625,18 @@ checksum = "672423d4fea7ffa2f6c25ba60031ea13dc6258070556f125cc4d790007d4a155" [[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" [[package]] name = "xtask" diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs index df7a5112f12..4d3e85ab1b2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs @@ -1,7 +1,7 @@ use either::Either; use ide_db::FxHashMap; use itertools::Itertools; -use syntax::{ast, ted, AstNode, SmolStr, ToSmolStr}; +use syntax::{ast, syntax_editor::SyntaxEditor, AstNode, SmolStr, SyntaxElement, ToSmolStr}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -24,6 +24,11 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti let record = path.syntax().parent().and_then(<Either<ast::RecordExpr, ast::RecordPat>>::cast)?; + let parent_node = match ctx.covering_element() { + SyntaxElement::Node(n) => n, + SyntaxElement::Token(t) => t.parent()?, + }; + let ranks = compute_fields_ranks(&path, ctx)?; let get_rank_of_field = |of: Option<SmolStr>| { *ranks.get(of.unwrap_or_default().trim_start_matches("r#")).unwrap_or(&usize::MAX) @@ -65,23 +70,31 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti AssistId("reorder_fields", AssistKind::RefactorRewrite), "Reorder record fields", target, - |builder| match fields { - Either::Left((sorted, field_list)) => { - replace(builder.make_mut(field_list).fields(), sorted) - } - Either::Right((sorted, field_list)) => { - replace(builder.make_mut(field_list).fields(), sorted) + |builder| { + let mut editor = builder.make_editor(&parent_node); + + match fields { + Either::Left((sorted, field_list)) => { + replace(&mut editor, field_list.fields(), sorted) + } + Either::Right((sorted, field_list)) => { + replace(&mut editor, field_list.fields(), sorted) + } } + + builder.add_file_edits(ctx.file_id(), editor); }, ) } fn replace<T: AstNode + PartialEq>( + editor: &mut SyntaxEditor, fields: impl Iterator<Item = T>, sorted_fields: impl IntoIterator<Item = T>, ) { fields.zip(sorted_fields).for_each(|(field, sorted_field)| { - ted::replace(field.syntax(), sorted_field.syntax().clone_for_update()) + // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us + editor.replace(field.syntax(), sorted_field.syntax().clone_for_update()) }); } 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/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index a5c9d2823e0..4975467ece9 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -511,12 +511,16 @@ pub(crate) fn handle_document_diagnostics( .into_iter() .filter_map(|d| { let file = d.range.file_id; - let diagnostic = convert_diagnostic(&line_index, d); if file == file_id { + let diagnostic = convert_diagnostic(&line_index, d); return Some(diagnostic); } if supports_related { - related_documents.entry(file).or_insert_with(Vec::new).push(diagnostic); + let (diagnostics, line_index) = related_documents + .entry(file) + .or_insert_with(|| (Vec::new(), snap.file_line_index(file).ok())); + let diagnostic = convert_diagnostic(line_index.as_mut()?, d); + diagnostics.push(diagnostic); } None }); @@ -529,7 +533,7 @@ pub(crate) fn handle_document_diagnostics( related_documents: related_documents.is_empty().not().then(|| { related_documents .into_iter() - .map(|(id, items)| { + .map(|(id, (items, _))| { ( to_proto::url(&snap, id), lsp_types::DocumentDiagnosticReportKind::Full( diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 327a547b295..68c481bda6e 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -3449,21 +3449,14 @@ impl Rewrite for ast::ForeignItem { ref generics, ref body, } = **fn_kind; - if let Some(ref body) = body { + if body.is_some() { let mut visitor = FmtVisitor::from_context(context); visitor.block_indent = shape.indent; visitor.last_pos = self.span.lo(); let inner_attrs = inner_attributes(&self.attrs); let fn_ctxt = visit::FnCtxt::Foreign; visitor.visit_fn( - visit::FnKind::Fn( - fn_ctxt, - self.ident, - sig, - &self.vis, - generics, - Some(body), - ), + visit::FnKind::Fn(fn_ctxt, &self.ident, sig, &self.vis, generics, body), &sig.decl, self.span, defaultness, diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 8102fe7ad8f..9b116b620b7 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -390,7 +390,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { block = b; self.rewrite_fn_before_block( indent, - ident, + *ident, &FnSig::from_fn_kind(&fk, fd, defaultness), mk_sp(s.lo(), b.span.lo()), ) @@ -540,21 +540,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ref generics, ref body, } = **fn_kind; - if let Some(ref body) = body { + if body.is_some() { let inner_attrs = inner_attributes(&item.attrs); let fn_ctxt = match sig.header.ext { ast::Extern::None => visit::FnCtxt::Free, _ => visit::FnCtxt::Foreign, }; self.visit_fn( - visit::FnKind::Fn( - fn_ctxt, - item.ident, - sig, - &item.vis, - generics, - Some(body), - ), + visit::FnKind::Fn(fn_ctxt, &item.ident, sig, &item.vis, generics, body), &sig.decl, item.span, defaultness, @@ -648,11 +641,11 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ref generics, ref body, } = **fn_kind; - if let Some(ref body) = body { + if body.is_some() { let inner_attrs = inner_attributes(&ai.attrs); let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt); self.visit_fn( - visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, generics, Some(body)), + visit::FnKind::Fn(fn_ctxt, &ai.ident, sig, &ai.vis, generics, body), &sig.decl, ai.span, defaultness, diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs index 751d678e581..a66ccd37070 100644 --- a/src/tools/tidy/src/target_specific_tests.rs +++ b/src/tools/tidy/src/target_specific_tests.rs @@ -10,26 +10,6 @@ use crate::walk::filter_not_rust; const LLVM_COMPONENTS_HEADER: &str = "needs-llvm-components:"; const COMPILE_FLAGS_HEADER: &str = "compile-flags:"; -const KNOWN_LLVM_COMPONENTS: &[&str] = &[ - "aarch64", - "arm", - "avr", - "bpf", - "csky", - "hexagon", - "loongarch", - "m68k", - "mips", - "msp430", - "nvptx", - "powerpc", - "riscv", - "sparc", - "systemz", - "webassembly", - "x86", -]; - #[derive(Default, Debug)] struct RevisionInfo<'a> { target_arch: Option<&'a str>, @@ -94,20 +74,6 @@ pub fn check(tests_path: &Path, bad: &mut bool) { // gathered. } } - if let Some(llvm_components) = llvm_components { - for component in llvm_components { - // Ensure the given component even exists. - // This is somewhat redundant with COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS, - // but helps detect such problems earlier (PR CI rather than bors CI). - if !KNOWN_LLVM_COMPONENTS.contains(component) { - eprintln!( - "{}: revision {} specifies unknown LLVM component `{}`", - file, rev, component - ); - *bad = true; - } - } - } } }); } diff --git a/tests/assembly/s390x-vector-abi.rs b/tests/assembly/s390x-vector-abi.rs new file mode 100644 index 00000000000..c1935582561 --- /dev/null +++ b/tests/assembly/s390x-vector-abi.rs @@ -0,0 +1,322 @@ +//@ revisions: z10 z10_vector z13 z13_no_vector +// ignore-tidy-linelength +//@ assembly-output: emit-asm +//@ compile-flags: -O -Z merge-functions=disabled +//@[z10] compile-flags: --target s390x-unknown-linux-gnu --cfg no_vector +//@[z10] needs-llvm-components: systemz +//@[z10_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector +//@[z10_vector] needs-llvm-components: systemz +//@[z13] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 +//@[z13] needs-llvm-components: systemz +//@[z13_no_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector --cfg no_vector +//@[z13_no_vector] needs-llvm-components: systemz + +#![feature(no_core, lang_items, repr_simd, s390x_target_feature)] +#![no_core] +#![crate_type = "lib"] +#![allow(non_camel_case_types)] + +// Cases where vector feature is disabled are rejected. +// See tests/ui/simd-abi-checks-s390x.rs for test for them. + +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} +#[lang = "freeze"] +pub trait Freeze {} + +impl<T: Copy, const N: usize> Copy for [T; N] {} + +#[lang = "phantom_data"] +pub struct PhantomData<T: ?Sized>; +impl<T: ?Sized> Copy for PhantomData<T> {} + +#[repr(simd)] +pub struct i8x8([i8; 8]); +#[repr(simd)] +pub struct i8x16([i8; 16]); +#[repr(simd)] +pub struct i8x32([i8; 32]); +#[repr(C)] +pub struct Wrapper<T>(T); +#[repr(C, align(16))] +pub struct WrapperAlign16<T>(T); +#[repr(C)] +pub struct WrapperWithZst<T>(T, PhantomData<()>); +#[repr(transparent)] +pub struct TransparentWrapper<T>(T); + +impl Copy for i8 {} +impl Copy for i64 {} +impl Copy for i8x8 {} +impl Copy for i8x16 {} +impl Copy for i8x32 {} +impl<T: Copy> Copy for Wrapper<T> {} +impl<T: Copy> Copy for WrapperAlign16<T> {} +impl<T: Copy> Copy for WrapperWithZst<T> {} +impl<T: Copy> Copy for TransparentWrapper<T> {} + +// CHECK-LABEL: vector_ret_small: +// CHECK: vlrepg %v24, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 { + *x +} +// CHECK-LABEL: vector_ret: +// CHECK: vl %v24, 0(%r2), 3 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_ret(x: &i8x16) -> i8x16 { + *x +} +// CHECK-LABEL: vector_ret_large: +// z10: vl %v0, 16(%r3), 4 +// z10-NEXT: vl %v1, 0(%r3), 4 +// z10-NEXT: vst %v0, 16(%r2), 4 +// z10-NEXT: vst %v1, 0(%r2), 4 +// z10-NEXT: br %r14 +// z13: vl %v0, 0(%r3), 4 +// z13-NEXT: vl %v1, 16(%r3), 4 +// z13-NEXT: vst %v1, 16(%r2), 4 +// z13-NEXT: vst %v0, 0(%r2), 4 +// z13-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_ret_large(x: &i8x32) -> i8x32 { + *x +} + +// CHECK-LABEL: vector_wrapper_ret_small: +// CHECK: mvc 0(8,%r2), 0(%r3) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_ret_small(x: &Wrapper<i8x8>) -> Wrapper<i8x8> { + *x +} +// CHECK-LABEL: vector_wrapper_ret: +// CHECK: mvc 0(16,%r2), 0(%r3) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_ret(x: &Wrapper<i8x16>) -> Wrapper<i8x16> { + *x +} +// CHECK-LABEL: vector_wrapper_ret_large: +// z10: vl %v0, 16(%r3), 4 +// z10-NEXT: vl %v1, 0(%r3), 4 +// z10-NEXT: vst %v0, 16(%r2), 4 +// z10-NEXT: vst %v1, 0(%r2), 4 +// z10-NEXT: br %r14 +// z13: vl %v0, 16(%r3), 4 +// z13-NEXT: vst %v0, 16(%r2), 4 +// z13-NEXT: vl %v0, 0(%r3), 4 +// z13-NEXT: vst %v0, 0(%r2), 4 +// z13-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_ret_large(x: &Wrapper<i8x32>) -> Wrapper<i8x32> { + *x +} + +// CHECK-LABEL: vector_wrapper_padding_ret: +// CHECK: mvc 0(16,%r2), 0(%r3) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_padding_ret(x: &WrapperAlign16<i8x8>) -> WrapperAlign16<i8x8> { + *x +} + +// CHECK-LABEL: vector_wrapper_with_zst_ret_small: +// CHECK: mvc 0(8,%r2), 0(%r3) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_with_zst_ret_small( + x: &WrapperWithZst<i8x8>, +) -> WrapperWithZst<i8x8> { + *x +} +// CHECK-LABEL: vector_wrapper_with_zst_ret: +// CHECK: mvc 0(16,%r2), 0(%r3) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_with_zst_ret( + x: &WrapperWithZst<i8x16>, +) -> WrapperWithZst<i8x16> { + *x +} +// CHECK-LABEL: vector_wrapper_with_zst_ret_large: +// z10: vl %v0, 16(%r3), 4 +// z10-NEXT: vl %v1, 0(%r3), 4 +// z10-NEXT: vst %v0, 16(%r2), 4 +// z10-NEXT: vst %v1, 0(%r2), 4 +// z10-NEXT: br %r14 +// z13: vl %v0, 16(%r3), 4 +// z13-NEXT: vst %v0, 16(%r2), 4 +// z13-NEXT: vl %v0, 0(%r3), 4 +// z13-NEXT: vst %v0, 0(%r2), 4 +// z13-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_with_zst_ret_large( + x: &WrapperWithZst<i8x32>, +) -> WrapperWithZst<i8x32> { + *x +} + +// CHECK-LABEL: vector_transparent_wrapper_ret_small: +// CHECK: vlrepg %v24, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_transparent_wrapper_ret_small( + x: &TransparentWrapper<i8x8>, +) -> TransparentWrapper<i8x8> { + *x +} +// CHECK-LABEL: vector_transparent_wrapper_ret: +// CHECK: vl %v24, 0(%r2), 3 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_transparent_wrapper_ret( + x: &TransparentWrapper<i8x16>, +) -> TransparentWrapper<i8x16> { + *x +} +// CHECK-LABEL: vector_transparent_wrapper_ret_large: +// z10: vl %v0, 16(%r3), 4 +// z10-NEXT: vl %v1, 0(%r3), 4 +// z10-NEXT: vst %v0, 16(%r2), 4 +// z10-NEXT: vst %v1, 0(%r2), 4 +// z10-NEXT: br %r14 +// z13: vl %v0, 0(%r3), 4 +// z13-NEXT: vl %v1, 16(%r3), 4 +// z13-NEXT: vst %v1, 16(%r2), 4 +// z13-NEXT: vst %v0, 0(%r2), 4 +// z13-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_transparent_wrapper_ret_large( + x: &TransparentWrapper<i8x32>, +) -> TransparentWrapper<i8x32> { + *x +} + +// CHECK-LABEL: vector_arg_small: +// CHECK: vlgvg %r2, %v24, 0 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_arg_small(x: i8x8) -> i64 { + unsafe { *(&x as *const i8x8 as *const i64) } +} +// CHECK-LABEL: vector_arg: +// CHECK: vlgvg %r2, %v24, 0 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_arg(x: i8x16) -> i64 { + unsafe { *(&x as *const i8x16 as *const i64) } +} +// CHECK-LABEL: vector_arg_large: +// CHECK: lg %r2, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_arg_large(x: i8x32) -> i64 { + unsafe { *(&x as *const i8x32 as *const i64) } +} + +// CHECK-LABEL: vector_wrapper_arg_small: +// CHECK: vlgvg %r2, %v24, 0 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 { + unsafe { *(&x as *const Wrapper<i8x8> as *const i64) } +} +// CHECK-LABEL: vector_wrapper_arg: +// CHECK: vlgvg %r2, %v24, 0 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 { + unsafe { *(&x as *const Wrapper<i8x16> as *const i64) } +} +// CHECK-LABEL: vector_wrapper_arg_large: +// CHECK: lg %r2, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_arg_large(x: Wrapper<i8x32>) -> i64 { + unsafe { *(&x as *const Wrapper<i8x32> as *const i64) } +} + +// https://github.com/rust-lang/rust/pull/131586#discussion_r1837071121 +// CHECK-LABEL: vector_wrapper_padding_arg: +// CHECK: lg %r2, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_padding_arg(x: WrapperAlign16<i8x8>) -> i64 { + unsafe { *(&x as *const WrapperAlign16<i8x8> as *const i64) } +} + +// CHECK-LABEL: vector_wrapper_with_zst_arg_small: +// CHECK: .cfi_startproc +// CHECK-NOT: vlgvg +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_with_zst_arg_small(x: WrapperWithZst<i8x8>) -> i64 { + unsafe { *(&x as *const WrapperWithZst<i8x8> as *const i64) } +} +// CHECK-LABEL: vector_wrapper_with_zst_arg: +// CHECK: lg %r2, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_with_zst_arg(x: WrapperWithZst<i8x16>) -> i64 { + unsafe { *(&x as *const WrapperWithZst<i8x16> as *const i64) } +} +// CHECK-LABEL: vector_wrapper_with_zst_arg_large: +// CHECK: lg %r2, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_wrapper_with_zst_arg_large(x: WrapperWithZst<i8x32>) -> i64 { + unsafe { *(&x as *const WrapperWithZst<i8x32> as *const i64) } +} + +// CHECK-LABEL: vector_transparent_wrapper_arg_small: +// CHECK: vlgvg %r2, %v24, 0 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 { + unsafe { *(&x as *const TransparentWrapper<i8x8> as *const i64) } +} +// CHECK-LABEL: vector_transparent_wrapper_arg: +// CHECK: vlgvg %r2, %v24, 0 +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 { + unsafe { *(&x as *const TransparentWrapper<i8x16> as *const i64) } +} +// CHECK-LABEL: vector_transparent_wrapper_arg_large: +// CHECK: lg %r2, 0(%r2) +// CHECK-NEXT: br %r14 +#[cfg_attr(no_vector, target_feature(enable = "vector"))] +#[no_mangle] +unsafe extern "C" fn vector_transparent_wrapper_arg_large(x: TransparentWrapper<i8x32>) -> i64 { + unsafe { *(&x as *const TransparentWrapper<i8x32> as *const i64) } +} diff --git a/tests/codegen/checked_math.rs b/tests/codegen/checked_math.rs index 63f5c3d34f7..c612ddccdaa 100644 --- a/tests/codegen/checked_math.rs +++ b/tests/codegen/checked_math.rs @@ -90,7 +90,7 @@ pub fn checked_shr_signed(a: i32, b: u32) -> Option<i32> { #[no_mangle] pub fn checked_add_one_unwrap_unsigned(x: u32) -> u32 { // CHECK: %[[IS_MAX:.+]] = icmp eq i32 %x, -1 - // CHECK: br i1 %[[IS_MAX]], label %[[NONE_BB:.+]], label %[[SOME_BB:.+]] + // CHECK: br i1 %[[IS_MAX]], label %[[NONE_BB:.+]], label %[[SOME_BB:.+]], // CHECK: [[SOME_BB]]: // CHECK: %[[R:.+]] = add nuw i32 %x, 1 // CHECK: ret i32 %[[R]] diff --git a/tests/codegen/intrinsics/cold_path.rs b/tests/codegen/intrinsics/cold_path.rs new file mode 100644 index 00000000000..24ee84e07bf --- /dev/null +++ b/tests/codegen/intrinsics/cold_path.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -O +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::cold_path; + +#[no_mangle] +pub fn test_cold_path(x: bool) { + cold_path(); +} + +// CHECK-LABEL: @test_cold_path( +// CHECK-NOT: cold_path diff --git a/tests/codegen/intrinsics/likely.rs b/tests/codegen/intrinsics/likely.rs index 9dc31d21045..e318390db20 100644 --- a/tests/codegen/intrinsics/likely.rs +++ b/tests/codegen/intrinsics/likely.rs @@ -1,22 +1,35 @@ -//@ compile-flags: -C no-prepopulate-passes -Copt-level=1 - +//@ compile-flags: -O #![crate_type = "lib"] #![feature(core_intrinsics)] -use std::intrinsics::{likely, unlikely}; +use std::intrinsics::likely; +#[inline(never)] #[no_mangle] -pub fn check_likely(x: i32, y: i32) -> Option<i32> { - unsafe { - // CHECK: call i1 @llvm.expect.i1(i1 %{{.*}}, i1 true) - if likely(x == y) { None } else { Some(x + y) } - } +pub fn path_a() { + println!("path a"); +} + +#[inline(never)] +#[no_mangle] +pub fn path_b() { + println!("path b"); } #[no_mangle] -pub fn check_unlikely(x: i32, y: i32) -> Option<i32> { - unsafe { - // CHECK: call i1 @llvm.expect.i1(i1 %{{.*}}, i1 false) - if unlikely(x == y) { None } else { Some(x + y) } +pub fn test_likely(x: bool) { + if likely(x) { + path_a(); + } else { + path_b(); } } + +// CHECK-LABEL: @test_likely( +// CHECK: br i1 %x, label %bb2, label %bb3, !prof ![[NUM:[0-9]+]] +// CHECK: bb3: +// CHECK-NOT: cold_path +// CHECK: path_b +// CHECK: bb2: +// CHECK: path_a +// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1} diff --git a/tests/codegen/intrinsics/likely_assert.rs b/tests/codegen/intrinsics/likely_assert.rs new file mode 100644 index 00000000000..0ddbd6206ae --- /dev/null +++ b/tests/codegen/intrinsics/likely_assert.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -O +#![crate_type = "lib"] + +#[no_mangle] +pub fn test_assert(x: bool) { + assert!(x); +} + +// check that assert! emits branch weights + +// CHECK-LABEL: @test_assert( +// CHECK: br i1 %x, label %bb2, label %bb1, !prof ![[NUM:[0-9]+]] +// CHECK: bb1: +// CHECK: panic +// CHECK: bb2: +// CHECK: ret void +// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1} diff --git a/tests/codegen/intrinsics/unlikely.rs b/tests/codegen/intrinsics/unlikely.rs new file mode 100644 index 00000000000..2d776031a52 --- /dev/null +++ b/tests/codegen/intrinsics/unlikely.rs @@ -0,0 +1,35 @@ +//@ compile-flags: -O +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::unlikely; + +#[inline(never)] +#[no_mangle] +pub fn path_a() { + println!("path a"); +} + +#[inline(never)] +#[no_mangle] +pub fn path_b() { + println!("path b"); +} + +#[no_mangle] +pub fn test_unlikely(x: bool) { + if unlikely(x) { + path_a(); + } else { + path_b(); + } +} + +// CHECK-LABEL: @test_unlikely( +// CHECK: br i1 %x, label %bb2, label %bb4, !prof ![[NUM:[0-9]+]] +// CHECK: bb4: +// CHECK: path_b +// CHECK: bb2: +// CHECK-NOT: cold_path +// CHECK: path_a +// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000} diff --git a/tests/crashes/113280.rs b/tests/crashes/113280.rs deleted file mode 100644 index 86677f416fe..00000000000 --- a/tests/crashes/113280.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #113280 -//@ only-x86_64 - -#![feature(dyn_star, pointer_like_trait)] -#![allow(incomplete_features)] - -use std::fmt::Debug; -use std::marker::PointerLike; - -fn make_dyn_star<'a>(t: impl PointerLike + Debug + 'a) -> dyn* Debug + 'a { - f32::from_bits(0x1) as f64 -} - -fn main() { - println!("{:?}", make_dyn_star(Box::new(1i32))); -} diff --git a/tests/crashes/123077-2.rs b/tests/crashes/123077-2.rs deleted file mode 100644 index e086e330337..00000000000 --- a/tests/crashes/123077-2.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #123077 -//@ only-x86_64 -use std::arch::x86_64::{__m128, _mm_blend_ps}; - -pub fn sse41_blend_noinline( ) -> __m128 { - let f = { |x, y| unsafe { - _mm_blend_ps(x, y, { |x, y| unsafe }) - }}; - f(x, y) -} - -pub fn main() {} diff --git a/tests/crashes/127676.rs b/tests/crashes/127676.rs deleted file mode 100644 index 81149c2ef84..00000000000 --- a/tests/crashes/127676.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #127676 -//@ edition:2018 - -#![feature(dyn_star,const_async_blocks)] - -static S: dyn* Send + Sync = async { 42 }; - -pub fn main() {} diff --git a/tests/crashes/129150.rs b/tests/crashes/129150.rs deleted file mode 100644 index 9f8c2ba1739..00000000000 --- a/tests/crashes/129150.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: rust-lang/rust#129150 -//@ only-x86_64 -use std::arch::x86_64::_mm_blend_ps; - -pub fn main() { - _mm_blend_ps(1, 2, &const {} ); -} 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/131535.rs b/tests/crashes/131535.rs deleted file mode 100644 index 47ccdf87f2d..00000000000 --- a/tests/crashes/131535.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #131535 -#![feature(non_lifetime_binders)] -trait v0<> {} -fn kind :(v0<'_, > impl for<v4> v0<'_, v2 = impl v0<v4> + '_>) {} diff --git a/tests/crashes/131637.rs b/tests/crashes/131637.rs deleted file mode 100644 index 7d328384a74..00000000000 --- a/tests/crashes/131637.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: #121637 -#![feature(non_lifetime_binders)] -trait Trait<Type> { - type Type; - - fn method(&self) -> impl for<T> Trait<impl Trait<T>>; -} diff --git a/tests/crashes/132530.rs b/tests/crashes/132530.rs deleted file mode 100644 index b43da62bfc1..00000000000 --- a/tests/crashes/132530.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #132530 - -#![feature(non_lifetime_binders)] - -trait Trait<'a, A> { - type Assoc<'a> = i32; -} - -fn a() -> impl for<T> Trait<Assoc = impl Trait<T>> {} 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/debuginfo/numeric-types.rs b/tests/debuginfo/numeric-types.rs index 9d232578979..9a0fd01d7e2 100644 --- a/tests/debuginfo/numeric-types.rs +++ b/tests/debuginfo/numeric-types.rs @@ -2,6 +2,14 @@ //@ ignore-windows-gnu: #128981 +// Note: u128 visualization was not supported in 10.0.22621.3233 but was fixed in 10.0.26100.2161. + +// FIXME(#133107): this is temporarily marked as `only-64bit` because of course 32-bit msvc has +// a different integer width and thus underlying integer type display. Only marked as such to +// unblock the tree. +//@ only-64bit +//@ min-cdb-version: 10.0.26100.2161 + // Tests the visualizations for `NonZero<T>`, `Wrapping<T>` and // `Atomic{Bool,I8,I16,I32,I64,Isize,U8,U16,U32,U64,Usize}` located in `libcore.natvis`. @@ -48,8 +56,8 @@ // cdb-check:nz_u64 : 0x64 [Type: core::num::nonzero::NonZero<u64>] // cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<u64>] -// 128-bit integers don't seem to work in CDB // cdb-command: dx nz_u128 +// cdb-check:nz_u128 : 111 [Type: core::num::nonzero::NonZero<u128>] // cdb-check: [<Raw View>] [Type: core::num::nonzero::NonZero<u128>] // cdb-command: dx nz_usize @@ -58,101 +66,99 @@ // cdb-command: dx w_i8 // cdb-check:w_i8 : 10 [Type: core::num::wrapping::Wrapping<i8>] -// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<i8>] +// cdb-check: [+0x000] __0 : 10 [Type: char] // cdb-command: dx w_i16 // cdb-check:w_i16 : 20 [Type: core::num::wrapping::Wrapping<i16>] -// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<i16>] +// cdb-check: [+0x000] __0 : 20 [Type: short] // cdb-command: dx w_i32 // cdb-check:w_i32 : 30 [Type: core::num::wrapping::Wrapping<i32>] -// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<i32>] +// cdb-check: [+0x000] __0 : 30 [Type: int] // cdb-command: dx w_i64 // cdb-check:w_i64 : 40 [Type: core::num::wrapping::Wrapping<i64>] -// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<i64>] +// cdb-check: [+0x000] __0 : 40 [Type: __int64] -// 128-bit integers don't seem to work in CDB // cdb-command: dx w_i128 -// cdb-check:w_i128 [Type: core::num::wrapping::Wrapping<i128>] -// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<i128>] +// cdb-check:w_i128 : 50 [Type: core::num::wrapping::Wrapping<i128>] +// cdb-check: [+0x000] __0 : 50 [Type: i128] // cdb-command: dx w_isize // cdb-check:w_isize : 60 [Type: core::num::wrapping::Wrapping<isize>] -// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<isize>] +// cdb-check: [+0x000] __0 : 60 [Type: __int64] // cdb-command: dx w_u8 // cdb-check:w_u8 : 0x46 [Type: core::num::wrapping::Wrapping<u8>] -// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<u8>] +// cdb-check: [+0x000] __0 : 0x46 [Type: unsigned char] // cdb-command: dx w_u16 // cdb-check:w_u16 : 0x50 [Type: core::num::wrapping::Wrapping<u16>] -// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<u16>] +// cdb-check: [+0x000] __0 : 0x50 [Type: unsigned short] // cdb-command: dx w_u32 // cdb-check:w_u32 : 0x5a [Type: core::num::wrapping::Wrapping<u32>] -// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<u32>] +// cdb-check: [+0x000] __0 : 0x5a [Type: unsigned int] // cdb-command: dx w_u64 // cdb-check:w_u64 : 0x64 [Type: core::num::wrapping::Wrapping<u64>] -// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<u64>] +// cdb-check: [+0x000] __0 : 0x64 [Type: unsigned __int64] -// 128-bit integers don't seem to work in CDB // cdb-command: dx w_u128 -// cdb-check:w_u128 [Type: core::num::wrapping::Wrapping<u128>] -// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<u128>] +// cdb-check:w_u128 : 110 [Type: core::num::wrapping::Wrapping<u128>] +// cdb-check: [+0x000] __0 : 110 [Type: u128] // cdb-command: dx w_usize // cdb-check:w_usize : 0x78 [Type: core::num::wrapping::Wrapping<usize>] -// cdb-check: [<Raw View>] [Type: core::num::wrapping::Wrapping<usize>] +// cdb-check: [+0x000] __0 : 0x78 [Type: unsigned __int64] // cdb-command: dx a_bool_t // cdb-check:a_bool_t : true [Type: core::sync::atomic::AtomicBool] -// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicBool] +// cdb-check: [+0x000] v : 0x1 [Type: core::cell::UnsafeCell<u8>] // cdb-command: dx a_bool_f // cdb-check:a_bool_f : false [Type: core::sync::atomic::AtomicBool] -// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicBool] +// cdb-check: [+0x000] v : 0x0 [Type: core::cell::UnsafeCell<u8>] // cdb-command: dx a_i8 // cdb-check:a_i8 : 2 [Type: core::sync::atomic::AtomicI8] -// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicI8] +// cdb-check: [+0x000] v : 2 [Type: core::cell::UnsafeCell<i8>] // cdb-command: dx a_i16 // cdb-check:a_i16 : 4 [Type: core::sync::atomic::AtomicI16] -// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicI16] +// cdb-check: [+0x000] v : 4 [Type: core::cell::UnsafeCell<i16>] // cdb-command: dx a_i32 // cdb-check:a_i32 : 8 [Type: core::sync::atomic::AtomicI32] -// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicI32] +// cdb-check: [+0x000] v : 8 [Type: core::cell::UnsafeCell<i32>] // cdb-command: dx a_i64 // cdb-check:a_i64 : 16 [Type: core::sync::atomic::AtomicI64] -// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicI64] +// cdb-check: [+0x000] v : 16 [Type: core::cell::UnsafeCell<i64>] // cdb-command: dx a_isize // cdb-check:a_isize : 32 [Type: core::sync::atomic::AtomicIsize] -// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicIsize] +// cdb-check: [+0x000] v : 32 [Type: core::cell::UnsafeCell<isize>] // cdb-command: dx a_u8 // cdb-check:a_u8 : 0x40 [Type: core::sync::atomic::AtomicU8] -// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicU8] +// cdb-check: [+0x000] v : 0x40 [Type: core::cell::UnsafeCell<u8>] // cdb-command: dx a_u16 // cdb-check:a_u16 : 0x80 [Type: core::sync::atomic::AtomicU16] -// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicU16] +// cdb-check: [+0x000] v : 0x80 [Type: core::cell::UnsafeCell<u16>] // cdb-command: dx a_u32 // cdb-check:a_u32 : 0x100 [Type: core::sync::atomic::AtomicU32] -// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicU32] +// cdb-check: [+0x000] v : 0x100 [Type: core::cell::UnsafeCell<u32>] // cdb-command: dx a_u64 // cdb-check:a_u64 : 0x200 [Type: core::sync::atomic::AtomicU64] -// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicU64] +// cdb-check: [+0x000] v : 0x200 [Type: core::cell::UnsafeCell<u64>] // cdb-command: dx a_usize // cdb-check:a_usize : 0x400 [Type: core::sync::atomic::AtomicUsize] -// cdb-check: [<Raw View>] [Type: core::sync::atomic::AtomicUsize] +// cdb-check: [+0x000] v : 0x400 [Type: core::cell::UnsafeCell<usize>] // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/range-types.rs b/tests/debuginfo/range-types.rs index 8c18fd9addd..068a55a5767 100644 --- a/tests/debuginfo/range-types.rs +++ b/tests/debuginfo/range-types.rs @@ -1,7 +1,10 @@ // Testing the display of range types in cdb. -// cdb-only -//@ min-cdb-version: 10.0.18317.1001 +//@ only-cdb + +// FIXME(jieyouxu): triple check in CI if the directive actually works +//@ min-cdb-version: 10.0.26100.2161 + //@ compile-flags:-g // === CDB TESTS ================================================================================== @@ -10,23 +13,26 @@ // cdb-command: dx r1,d // cdb-check:r1,d : (3..5) [Type: core::ops::range::Range<i32>] -// cdb-check: [<Raw View>] [Type: core::ops::range::Range<i32>] +// cdb-check: [+0x000] start : 3 [Type: int] +// cdb-check: [+0x004] end : 5 [Type: int] // cdb-command: dx r2,d // cdb-check:r2,d : (2..) [Type: core::ops::range::RangeFrom<i32>] -// cdb-check: [<Raw View>] [Type: core::ops::range::RangeFrom<i32>] +// cdb-check: [+0x000] start : 2 [Type: int] // cdb-command: dx r3,d // cdb-check:r3,d : (1..=4) [Type: core::ops::range::RangeInclusive<i32>] -// cdb-check: [<Raw View>] [Type: core::ops::range::RangeInclusive<i32>] +// cdb-check: [+0x000] start : 1 [Type: int] +// cdb-check: [+0x004] end : 4 [Type: int] +// cdb-check: [+0x008] exhausted : false [Type: bool] // cdb-command: dx r4,d // cdb-check:r4,d : (..10) [Type: core::ops::range::RangeTo<i32>] -// cdb-check: [<Raw View>] [Type: core::ops::range::RangeTo<i32>] +// cdb-check: [+0x000] end : 10 [Type: int] // cdb-command: dx r5,d // cdb-check:r5,d : (..=3) [Type: core::ops::range::RangeToInclusive<i32>] -// cdb-check: [<Raw View>] [Type: core::ops::range::RangeToInclusive<i32>] +// cdb-check: [+0x000] end : 3 [Type: int] // cdb-command: dx r6,d // cdb-check:r6,d [Type: core::ops::range::RangeFull] diff --git a/tests/debuginfo/unit-type.rs b/tests/debuginfo/unit-type.rs index 42c0ff11f71..0ffa2fe490a 100644 --- a/tests/debuginfo/unit-type.rs +++ b/tests/debuginfo/unit-type.rs @@ -1,5 +1,8 @@ //@ compile-flags:-g +// FIXME(jieyouxu): triple check if this works in CI +//@ min-cdb-version: 10.0.26100.2161 + // === GDB TESTS =================================================================================== // gdb-command: run @@ -26,18 +29,18 @@ // cdb-check: Breakpoint 0 hit // cdb-command: dx _ref -// cdb-check: _ref : 0x[...] : () [Type: tuple$<> *] +// cdb-check: _ref : 0x[...] [Type: tuple$<> *] // cdb-command: dx _ptr -// cdb-check: _ptr : 0x[...] : () [Type: tuple$<> *] +// cdb-check: _ptr : 0x[...] [Type: tuple$<> *] // cdb-command: dx _local -// cdb-check: _local : () [Type: tuple$<>] +// cdb-check: _local [Type: tuple$<>] // cdb-command: dx _field,d // cdb-check: _field,d [Type: unit_type::_TypeContainingUnitField] // cdb-check: [+0x[...]] _a : 123 [Type: unsigned int] -// cdb-check: [+0x[...]] _unit : () [Type: tuple$<>] +// cdb-check: [+0x[...]] _unit [Type: tuple$<>] // cdb-check: [+0x[...]] _b : 456 [Type: unsigned __int64] // Check that we can cast "void pointers" to their actual type in the debugger diff --git a/tests/incremental/hygiene/load_cached_hygiene.rs b/tests/incremental/hygiene/load_cached_hygiene.rs index 4ad9c7d49fd..101d280cd49 100644 --- a/tests/incremental/hygiene/load_cached_hygiene.rs +++ b/tests/incremental/hygiene/load_cached_hygiene.rs @@ -7,7 +7,7 @@ // This causes hygiene information to be saved to the incr cache. // 2. One function is the foreign crate is modified. This causes the // optimized mir for an unmodified function to be loaded from the -//@ incremental cache and written out to the crate metadata. +// incremental cache and written out to the crate metadata. // 3. In the process of loading and writing out this function's MIR, // we load hygiene information from the incremental cache and // write it to our metadata. diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir index 935e67fc3c0..cff5b4c7243 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir @@ -13,7 +13,9 @@ fn step_forward(_1: u16, _2: usize) -> u16 { scope 6 (inlined core::num::<impl u16>::checked_add) { let mut _5: (u16, bool); let mut _6: bool; - let mut _7: bool; + scope 7 (inlined unlikely) { + let _7: (); + } } } scope 5 (inlined convert::num::ptr_try_from_impls::<impl TryFrom<usize> for u16>::try_from) { @@ -21,11 +23,11 @@ fn step_forward(_1: u16, _2: usize) -> u16 { let mut _4: u16; } } - scope 7 (inlined Option::<u16>::is_none) { - scope 8 (inlined Option::<u16>::is_some) { + scope 8 (inlined Option::<u16>::is_none) { + scope 9 (inlined Option::<u16>::is_some) { } } - scope 9 (inlined core::num::<impl u16>::wrapping_add) { + scope 10 (inlined core::num::<impl u16>::wrapping_add) { } } @@ -39,29 +41,26 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb1: { _4 = copy _2 as u16 (IntToInt); StorageDead(_3); - StorageLive(_7); StorageLive(_6); StorageLive(_5); _5 = AddWithOverflow(copy _1, copy _4); _6 = copy (_5.1: bool); - _7 = unlikely(move _6) -> [return: bb2, unwind unreachable]; + switchInt(copy _6) -> [0: bb2, otherwise: bb3]; } bb2: { - switchInt(move _7) -> [0: bb3, otherwise: bb4]; - } - - bb3: { StorageDead(_5); StorageDead(_6); - StorageDead(_7); goto -> bb7; } + bb3: { + _7 = cold_path() -> [return: bb4, unwind unreachable]; + } + bb4: { StorageDead(_5); StorageDead(_6); - StorageDead(_7); goto -> bb6; } diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir index bf1ffd1ef32..6e0242a220d 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir @@ -13,7 +13,9 @@ fn step_forward(_1: u16, _2: usize) -> u16 { scope 6 (inlined core::num::<impl u16>::checked_add) { let mut _5: (u16, bool); let mut _6: bool; - let mut _7: bool; + scope 7 (inlined unlikely) { + let _7: (); + } } } scope 5 (inlined convert::num::ptr_try_from_impls::<impl TryFrom<usize> for u16>::try_from) { @@ -21,11 +23,11 @@ fn step_forward(_1: u16, _2: usize) -> u16 { let mut _4: u16; } } - scope 7 (inlined Option::<u16>::is_none) { - scope 8 (inlined Option::<u16>::is_some) { + scope 8 (inlined Option::<u16>::is_none) { + scope 9 (inlined Option::<u16>::is_some) { } } - scope 9 (inlined core::num::<impl u16>::wrapping_add) { + scope 10 (inlined core::num::<impl u16>::wrapping_add) { } } @@ -39,29 +41,26 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb1: { _4 = copy _2 as u16 (IntToInt); StorageDead(_3); - StorageLive(_7); StorageLive(_6); StorageLive(_5); _5 = AddWithOverflow(copy _1, copy _4); _6 = copy (_5.1: bool); - _7 = unlikely(move _6) -> [return: bb2, unwind unreachable]; + switchInt(copy _6) -> [0: bb2, otherwise: bb3]; } bb2: { - switchInt(move _7) -> [0: bb3, otherwise: bb4]; - } - - bb3: { StorageDead(_5); StorageDead(_6); - StorageDead(_7); goto -> bb7; } + bb3: { + _7 = cold_path() -> [return: bb4, unwind unreachable]; + } + bb4: { StorageDead(_5); StorageDead(_6); - StorageDead(_7); goto -> bb6; } diff --git a/tests/run-make/mte-ffi/rmake.rs b/tests/run-make/mte-ffi/rmake.rs index f4fafb796e3..50f5f14191b 100644 --- a/tests/run-make/mte-ffi/rmake.rs +++ b/tests/run-make/mte-ffi/rmake.rs @@ -1,14 +1,12 @@ -// Tests that MTE tags and values stored in the top byte of a pointer (TBI) are -// preserved across FFI boundaries (C <-> Rust). -// This test does not require MTE: whilst the test will use MTE if available, if it is not, -// arbitrary tag bits are set using TBI. +//! Tests that MTE tags and values stored in the top byte of a pointer (TBI) are preserved across +//! FFI boundaries (C <-> Rust). This test does not require MTE: whilst the test will use MTE if +//! available, if it is not, arbitrary tag bits are set using TBI. -// This test is only valid for AArch64. -// The linker must be explicitly specified when cross-compiling, so it is limited to -// `aarch64-unknown-linux-gnu`. //@ only-aarch64-unknown-linux-gnu +// Reason: this test is only valid for AArch64 with `gcc`. The linker must be explicitly specified +// when cross-compiling, so it is limited to `aarch64-unknown-linux-gnu`. -use run_make_support::{cc, dynamic_lib_name, extra_c_flags, run, rustc, target}; +use run_make_support::{dynamic_lib_name, extra_c_flags, gcc, run, rustc, target}; fn main() { run_test("int"); @@ -29,7 +27,8 @@ fn run_test(variant: &str) { .target(target()) .linker("aarch64-linux-gnu-gcc") .run(); - cc().input(format!("bar_{variant}.c")) + gcc() + .input(format!("bar_{variant}.c")) .input(dynamic_lib_name("foo")) .out_exe("test") .args(&flags) diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs index cf6e3d86377..0a2186b0953 100644 --- a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs +++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs @@ -10,14 +10,16 @@ //@ ignore-cross-compile // Reason: the compiled binary is executed -use run_make_support::{clang, env_var, llvm_ar, run, rustc, static_lib_name}; +use run_make_support::{clang, env_var, llvm_ar, llvm_objdump, run, rustc, static_lib_name}; + +static PAUTH_A_KEY_PATTERN: &'static str = "paciasp"; +static PAUTH_B_KEY_PATTERN: &'static str = "pacibsp"; fn main() { clang() .arg("-v") .lto("thin") - .arg("-mbranch-protection=bti+pac-ret+leaf") - .arg("-O2") + .arg("-mbranch-protection=bti+pac-ret+b-key+leaf") .arg("-c") .out_exe("test.o") .input("test.c") @@ -32,5 +34,15 @@ fn main() { .input("test.rs") .output("test.bin") .run(); + + // Check that both a-key and b-key pac-ret survived LTO + llvm_objdump() + .disassemble() + .input("test.bin") + .run() + .assert_stdout_contains_regex(PAUTH_A_KEY_PATTERN) + .assert_stdout_contains_regex(PAUTH_B_KEY_PATTERN); + + // Check that the binary actually runs run("test.bin"); } diff --git a/tests/run-make/unstable-feature-usage-metrics/lib.rs b/tests/run-make/unstable-feature-usage-metrics/lib.rs new file mode 100644 index 00000000000..2202d722c49 --- /dev/null +++ b/tests/run-make/unstable-feature-usage-metrics/lib.rs @@ -0,0 +1,9 @@ +#![feature(ascii_char)] // random lib feature +#![feature(box_patterns)] // random lang feature + +// picked arbitrary unstable features, just need a random lib and lang feature, ideally ones that +// won't be stabilized any time soon so we don't have to update this test + +fn main() { + println!("foobar"); +} diff --git a/tests/run-make/unstable-feature-usage-metrics/rmake.rs b/tests/run-make/unstable-feature-usage-metrics/rmake.rs new file mode 100644 index 00000000000..1397548a6fc --- /dev/null +++ b/tests/run-make/unstable-feature-usage-metrics/rmake.rs @@ -0,0 +1,87 @@ +//! This test checks if unstable feature usage metric dump files `unstable-feature-usage*.json` work +//! as expected. +//! +//! - Basic sanity checks on a default ICE dump. +//! +//! See <https://github.com/rust-lang/rust/issues/129485>. +//! +//! # Test history +//! +//! - forked from dump-ice-to-disk test, which has flakeyness issues on i686-mingw, I'm assuming +//! those will be present in this test as well on the same platform + +//@ ignore-windows +//FIXME(#128911): still flakey on i686-mingw. + +use std::path::{Path, PathBuf}; + +use run_make_support::rfs::create_dir_all; +use run_make_support::{ + cwd, filename_contains, has_extension, rfs, run_in_tmpdir, rustc, serde_json, + shallow_find_files, +}; + +fn find_feature_usage_metrics<P: AsRef<Path>>(dir: P) -> Vec<PathBuf> { + shallow_find_files(dir, |path| { + if filename_contains(path, "unstable_feature_usage") && has_extension(path, "json") { + true + } else { + dbg!(path); + false + } + }) +} + +fn main() { + test_metrics_dump(); + test_metrics_errors(); +} + +#[track_caller] +fn test_metrics_dump() { + run_in_tmpdir(|| { + let metrics_dir = cwd().join("metrics"); + create_dir_all(&metrics_dir); + rustc() + .input("lib.rs") + .env("RUST_BACKTRACE", "short") + .arg(format!("-Zmetrics-dir={}", metrics_dir.display())) + .run(); + let mut metrics = find_feature_usage_metrics(&metrics_dir); + let json_path = + metrics.pop().expect("there should be one metrics file in the output directory"); + + // After the `pop` above, there should be no files left. + assert!( + metrics.is_empty(), + "there should be no more than one metrics file in the output directory" + ); + + let message = rfs::read_to_string(json_path); + let parsed: serde_json::Value = + serde_json::from_str(&message).expect("metrics should be dumped as json"); + let expected = serde_json::json!( + { + "lib_features":[{"symbol":"ascii_char"}], + "lang_features":[{"symbol":"box_patterns","since":null}] + } + ); + + assert_eq!(expected, parsed); + }); +} + +#[track_caller] +fn test_metrics_errors() { + run_in_tmpdir(|| { + rustc() + .input("lib.rs") + .env("RUST_BACKTRACE", "short") + .arg("-Zmetrics-dir=invaliddirectorythatdefinitelydoesntexist") + .run_fail() + .assert_stderr_contains( + "error: cannot dump feature usage metrics: No such file or directory", + ) + .assert_stdout_not_contains("internal compiler error"); + }); +} diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js index 068298e7236..8bffef61c8f 100644 --- a/tests/rustdoc-js-std/parser-errors.js +++ b/tests/rustdoc-js-std/parser-errors.js @@ -144,14 +144,6 @@ const PARSED = [ error: "Unexpected `:: ::`", }, { - query: "a::b::", - elems: [], - foundElems: 0, - userQuery: "a::b::", - returned: [], - error: "Paths cannot end with `::`", - }, - { query: ":a", elems: [], foundElems: 0, diff --git a/tests/rustdoc-js-std/path-end-empty.js b/tests/rustdoc-js-std/path-end-empty.js new file mode 100644 index 00000000000..6e853c61b4d --- /dev/null +++ b/tests/rustdoc-js-std/path-end-empty.js @@ -0,0 +1,6 @@ +const EXPECTED = { + 'query': 'Option::', + 'others': [ + { 'path': 'std::option::Option', 'name': 'get_or_insert_default' }, + ], +} diff --git a/tests/rustdoc-js/trailing.js b/tests/rustdoc-js/trailing.js new file mode 100644 index 00000000000..df5dd22ca4e --- /dev/null +++ b/tests/rustdoc-js/trailing.js @@ -0,0 +1,7 @@ +// exact-check +const EXPECTED = { + 'query': 'inner::', + 'others': [ + { 'path': 'trailing::inner', 'name': 'function' }, + ], +} diff --git a/tests/rustdoc-js/trailing.rs b/tests/rustdoc-js/trailing.rs new file mode 100644 index 00000000000..5c7c9362ffb --- /dev/null +++ b/tests/rustdoc-js/trailing.rs @@ -0,0 +1,3 @@ +pub mod inner { + pub fn function() {} +} 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-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs index d7f37f36681..3534228f73e 100644 --- a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs +++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs @@ -64,7 +64,7 @@ fn check_instance(instance: &Instance) { if instance.has_body() { let Some(body) = instance.body() else { unreachable!("Expected a body") }; assert!(!body.blocks.is_empty()); - assert_eq!(&name, "likely"); + assert_eq!(&name, "select_unpredictable"); } else { assert!(instance.body().is_none()); assert_matches!(name.as_str(), "size_of_val" | "vtable_size"); @@ -78,7 +78,7 @@ fn check_def(fn_def: FnDef) { let name = intrinsic.fn_name(); match name.as_str() { - "likely" => { + "select_unpredictable" => { assert!(!intrinsic.must_be_overridden()); assert!(fn_def.has_body()); } @@ -132,7 +132,7 @@ fn generate_input(path: &str) -> std::io::Result<()> { pub fn use_intrinsics(init: bool) -> bool {{ let vtable_sz = unsafe {{ vtable_size(0 as *const ()) }}; let sz = unsafe {{ size_of_val("hi") }}; - likely(init && sz == 2) + select_unpredictable(init && sz == 2, false, true) }} "# )?; diff --git a/tests/ui/asm/x86_64/goto-block-safe.rs b/tests/ui/asm/x86_64/goto-block-safe.rs new file mode 100644 index 00000000000..ee833a48a4b --- /dev/null +++ b/tests/ui/asm/x86_64/goto-block-safe.rs @@ -0,0 +1,23 @@ +//@ only-x86_64 +//@ needs-asm-support + +#![deny(unreachable_code)] +#![feature(asm_goto)] + +use std::arch::asm; + +fn goto_fallthough() { + unsafe { + asm!( + "/* {} */", + label { + core::hint::unreachable_unchecked(); + //~^ ERROR [E0133] + } + ) + } +} + +fn main() { + goto_fallthough(); +} diff --git a/tests/ui/asm/x86_64/goto-block-safe.stderr b/tests/ui/asm/x86_64/goto-block-safe.stderr new file mode 100644 index 00000000000..49818db7484 --- /dev/null +++ b/tests/ui/asm/x86_64/goto-block-safe.stderr @@ -0,0 +1,14 @@ +error[E0133]: call to unsafe function `unreachable_unchecked` is unsafe and requires unsafe function or block + --> $DIR/goto-block-safe.rs:14:17 + | +LL | unsafe { + | ------ items do not inherit unsafety from separate enclosing items +... +LL | core::hint::unreachable_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/auxiliary/pub-and-stability.rs b/tests/ui/auxiliary/pub-and-stability.rs index ee05a07dbb2..d2d07f99398 100644 --- a/tests/ui/auxiliary/pub-and-stability.rs +++ b/tests/ui/auxiliary/pub-and-stability.rs @@ -5,8 +5,8 @@ // The basic stability pattern in this file has four cases: // 1. no stability attribute at all // 2. a stable attribute (feature "unit_test") -// 3. an unstable attribute that unit test declares (feature "unstable_declared") -// 4. an unstable attribute that unit test fails to declare (feature "unstable_undeclared") +// 3. an unstable attribute that unit test enables (feature "unstable_declared") +// 4. an unstable attribute that unit test fails to enable (feature "unstable_undeclared") // // This file also covers four kinds of visibility: private, // pub(module), pub(crate), and pub. diff --git a/tests/ui/bootstrap/rustc_bootstap.force_stable.stderr b/tests/ui/bootstrap/rustc_bootstap.force_stable.stderr new file mode 100644 index 00000000000..f378f3c70dd --- /dev/null +++ b/tests/ui/bootstrap/rustc_bootstap.force_stable.stderr @@ -0,0 +1,10 @@ +error: the option `Z` is only accepted on the nightly compiler + +help: consider switching to a nightly toolchain: `rustup default nightly` + +note: selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html> + +note: for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features> + +error: 1 nightly option were parsed + diff --git a/tests/ui/bootstrap/rustc_bootstap.rs b/tests/ui/bootstrap/rustc_bootstap.rs new file mode 100644 index 00000000000..3d792ef4be4 --- /dev/null +++ b/tests/ui/bootstrap/rustc_bootstap.rs @@ -0,0 +1,47 @@ +//! Check `RUSTC_BOOTSTRAP`'s behavior in relation to feature stability and what rustc considers +//! itself to be (stable vs non-stable ). +//! +//! `RUSTC_BOOTSTRAP` accepts: +//! +//! - `1`: cheat, allow usage of unstable features even if rustc thinks it is a stable compiler. +//! - `x,y,z`: comma-delimited list of crates. +//! - `-1`: force rustc to think it is a stable compiler. + +// ignore-tidy-linelength + +//@ revisions: default_nightly cheat cheat_single_crate cheat_multi_crate force_stable invalid_zero invalid_junk +//@ only-nightly + +//@[default_nightly] unset-rustc-env:RUSTC_BOOTSTRAP +//@[default_nightly] check-pass + +// For a nightly compiler, this is same as `default_nightly` as if `RUSTC_BOOTSTRAP` was unset. +//@[invalid_zero] rustc-env:RUSTC_BOOTSTRAP=0 +//@[invalid_zero] check-pass + +// Invalid values are silently discarded, same as `default_nightly`, i.e. as if `RUSTC_BOOTSTRAP` +// was unset. +//@[invalid_junk] rustc-env:RUSTC_BOOTSTRAP=* +//@[invalid_junk] check-pass + +//@[cheat] rustc-env:RUSTC_BOOTSTRAP=1 +//@[cheat] check-pass + +//@[cheat_single_crate] rustc-env:RUSTC_BOOTSTRAP=x +//@[cheat_single_crate] check-pass + +//@[cheat_multi_crate] rustc-env:RUSTC_BOOTSTRAP=x,y,z +//@[cheat_multi_crate] check-pass + +// Note: compiletest passes some `-Z` flags to the compiler for ui testing purposes, so here we +// instead abuse the fact that `-Z unstable-options` is also part of rustc's stability story and is +// also affected by `RUSTC_BOOTSTRAP`. +//@[force_stable] rustc-env:RUSTC_BOOTSTRAP=-1 +//@[force_stable] compile-flags: -Z unstable-options +//@[force_stable] regex-error-pattern: error: the option `Z` is only accepted on the nightly compiler + +#![crate_type = "lib"] + +// Note: `rustc_attrs` is a perma-unstable internal feature that is unlikely to change, which is +// used as a proxy to check `RUSTC_BOOTSTRAP` versus stability checking logic. +#![feature(rustc_attrs)] 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/closures/2229_closure_analysis/bad-pattern.stderr b/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr index ca8c2a16d32..5f980c46a1f 100644 --- a/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr +++ b/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr @@ -97,16 +97,19 @@ LL | if let Refutable::A = v3 { todo!() }; error[E0005]: refutable pattern in local binding --> $DIR/bad-pattern.rs:19:13 | +LL | const PAT: u32 = 0; + | -------------- missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable +... LL | let PAT = v1; - | ^^^ - | | - | pattern `1_u32..=u32::MAX` not covered - | missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable - | help: introduce a variable instead: `PAT_var` + | ^^^ pattern `1_u32..=u32::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u32` +help: introduce a variable instead + | +LL | let PAT_var = v1; + | ~~~~~~~ error: aborting due to 7 previous errors diff --git a/tests/ui/closures/correct-args-on-call-suggestion.rs b/tests/ui/closures/correct-args-on-call-suggestion.rs new file mode 100644 index 00000000000..fa7915a7c03 --- /dev/null +++ b/tests/ui/closures/correct-args-on-call-suggestion.rs @@ -0,0 +1,7 @@ +// Ensure we give the right args when we suggest calling a closure. + +fn main() { + let x = |a: i32, b: i32| a + b; + let y: i32 = x; + //~^ ERROR mismatched types +} diff --git a/tests/ui/closures/correct-args-on-call-suggestion.stderr b/tests/ui/closures/correct-args-on-call-suggestion.stderr new file mode 100644 index 00000000000..2613c7776b2 --- /dev/null +++ b/tests/ui/closures/correct-args-on-call-suggestion.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/correct-args-on-call-suggestion.rs:5:18 + | +LL | let x = |a: i32, b: i32| a + b; + | ---------------- the found closure +LL | let y: i32 = x; + | --- ^ expected `i32`, found closure + | | + | expected due to this + | + = note: expected type `i32` + found closure `{closure@$DIR/correct-args-on-call-suggestion.rs:4:13: 4:29}` +help: use parentheses to call this closure + | +LL | let y: i32 = x(/* i32 */, /* i32 */); + | ++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/coercion/unboxing-needing-parenthases-issue-132924.rs b/tests/ui/coercion/unboxing-needing-parenthases-issue-132924.rs new file mode 100644 index 00000000000..fc4258fc0af --- /dev/null +++ b/tests/ui/coercion/unboxing-needing-parenthases-issue-132924.rs @@ -0,0 +1,18 @@ +//@ check-fail +fn main() { + let x = Box::new(Some(1)); + + let test: Option<i32> = x; + //~^ ERROR mismatched types + let x = Box::new(Some(1)); + let test: Option<i32> = { x as Box<Option<i32>> }; + //~^ ERROR mismatched types + + let x = Box::new(Some(1)); + let test: Option<i32> = if true { x as Box<Option<i32>> } else { None }; + //~^ ERROR mismatched types + + let x = std::rc::Rc::new(Some(1)); + let test: Option<i32> = x as std::rc::Rc<Option<i32>>; + //~^ ERROR mismatched types +} diff --git a/tests/ui/coercion/unboxing-needing-parenthases-issue-132924.stderr b/tests/ui/coercion/unboxing-needing-parenthases-issue-132924.stderr new file mode 100644 index 00000000000..429b1b87357 --- /dev/null +++ b/tests/ui/coercion/unboxing-needing-parenthases-issue-132924.stderr @@ -0,0 +1,59 @@ +error[E0308]: mismatched types + --> $DIR/unboxing-needing-parenthases-issue-132924.rs:5:29 + | +LL | let test: Option<i32> = x; + | ----------- ^ expected `Option<i32>`, found `Box<Option<{integer}>>` + | | + | expected due to this + | + = note: expected enum `Option<i32>` + found struct `Box<Option<{integer}>>` +help: consider unboxing the value + | +LL | let test: Option<i32> = *x; + | + + +error[E0308]: mismatched types + --> $DIR/unboxing-needing-parenthases-issue-132924.rs:8:31 + | +LL | let test: Option<i32> = { x as Box<Option<i32>> }; + | ^^^^^^^^^^^^^^^^^^^^^ expected `Option<i32>`, found `Box<Option<i32>>` + | + = note: expected enum `Option<_>` + found struct `Box<Option<_>>` +help: consider unboxing the value + | +LL | let test: Option<i32> = { *(x as Box<Option<i32>>) }; + | ++ + + +error[E0308]: mismatched types + --> $DIR/unboxing-needing-parenthases-issue-132924.rs:12:39 + | +LL | let test: Option<i32> = if true { x as Box<Option<i32>> } else { None }; + | ^^^^^^^^^^^^^^^^^^^^^ expected `Option<i32>`, found `Box<Option<i32>>` + | + = note: expected enum `Option<_>` + found struct `Box<Option<_>>` +help: consider unboxing the value + | +LL | let test: Option<i32> = if true { *(x as Box<Option<i32>>) } else { None }; + | ++ + + +error[E0308]: mismatched types + --> $DIR/unboxing-needing-parenthases-issue-132924.rs:16:29 + | +LL | let test: Option<i32> = x as std::rc::Rc<Option<i32>>; + | ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Option<i32>`, found `Rc<Option<i32>>` + | | + | expected due to this + | + = note: expected enum `Option<_>` + found struct `Rc<Option<_>>` +help: consider dereferencing the type + | +LL | let test: Option<i32> = *(x as std::rc::Rc<Option<i32>>); + | ++ + + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/confuse-field-and-method/issue-18343.stderr b/tests/ui/confuse-field-and-method/issue-18343.stderr index a51fd4f02aa..e50c971d837 100644 --- a/tests/ui/confuse-field-and-method/issue-18343.stderr +++ b/tests/ui/confuse-field-and-method/issue-18343.stderr @@ -7,7 +7,7 @@ LL | struct Obj<F> where F: FnMut() -> u32 { LL | o.closure(); | ^^^^^^^ field, not a method | -help: to call the function stored in `closure`, surround the field access with parentheses +help: to call the closure stored in `closure`, surround the field access with parentheses | LL | (o.closure)(); | + + diff --git a/tests/ui/confuse-field-and-method/issue-2392.stderr b/tests/ui/confuse-field-and-method/issue-2392.stderr index 440fbb27c00..77930de44a7 100644 --- a/tests/ui/confuse-field-and-method/issue-2392.stderr +++ b/tests/ui/confuse-field-and-method/issue-2392.stderr @@ -7,7 +7,7 @@ LL | struct Obj<F> where F: FnOnce() -> u32 { LL | o_closure.closure(); | ^^^^^^^ field, not a method | -help: to call the function stored in `closure`, surround the field access with parentheses +help: to call the closure stored in `closure`, surround the field access with parentheses | LL | (o_closure.closure)(); | + + @@ -46,7 +46,7 @@ LL | struct BoxedObj { LL | boxed_fn.boxed_closure(); | ^^^^^^^^^^^^^ field, not a method | -help: to call the function stored in `boxed_closure`, surround the field access with parentheses +help: to call the trait object stored in `boxed_closure`, surround the field access with parentheses | LL | (boxed_fn.boxed_closure)(); | + + @@ -60,7 +60,7 @@ LL | struct BoxedObj { LL | boxed_closure.boxed_closure(); | ^^^^^^^^^^^^^ field, not a method | -help: to call the function stored in `boxed_closure`, surround the field access with parentheses +help: to call the trait object stored in `boxed_closure`, surround the field access with parentheses | LL | (boxed_closure.boxed_closure)(); | + + @@ -99,7 +99,7 @@ LL | struct Obj<F> where F: FnOnce() -> u32 { LL | check_expression().closure(); | ^^^^^^^ field, not a method | -help: to call the function stored in `closure`, surround the field access with parentheses +help: to call the trait object stored in `closure`, surround the field access with parentheses | LL | (check_expression().closure)(); | + + @@ -113,7 +113,7 @@ LL | struct FuncContainer { LL | (*self.container).f1(1); | ^^ field, not a method | -help: to call the function stored in `f1`, surround the field access with parentheses +help: to call the function pointer stored in `f1`, surround the field access with parentheses | LL | ((*self.container).f1)(1); | + + @@ -127,7 +127,7 @@ LL | struct FuncContainer { LL | (*self.container).f2(1); | ^^ field, not a method | -help: to call the function stored in `f2`, surround the field access with parentheses +help: to call the function pointer stored in `f2`, surround the field access with parentheses | LL | ((*self.container).f2)(1); | + + @@ -141,7 +141,7 @@ LL | struct FuncContainer { LL | (*self.container).f3(1); | ^^ field, not a method | -help: to call the function stored in `f3`, surround the field access with parentheses +help: to call the function pointer stored in `f3`, surround the field access with parentheses | LL | ((*self.container).f3)(1); | + + diff --git a/tests/ui/confuse-field-and-method/issue-32128.stderr b/tests/ui/confuse-field-and-method/issue-32128.stderr index 3d860d8c85a..aaec15a41dc 100644 --- a/tests/ui/confuse-field-and-method/issue-32128.stderr +++ b/tests/ui/confuse-field-and-method/issue-32128.stderr @@ -7,7 +7,7 @@ LL | struct Example { LL | demo.example(1); | ^^^^^^^ field, not a method | -help: to call the function stored in `example`, surround the field access with parentheses +help: to call the trait object stored in `example`, surround the field access with parentheses | LL | (demo.example)(1); | + + diff --git a/tests/ui/confuse-field-and-method/issue-33784.stderr b/tests/ui/confuse-field-and-method/issue-33784.stderr index 8acd1f8ff1e..59a6f4fccd8 100644 --- a/tests/ui/confuse-field-and-method/issue-33784.stderr +++ b/tests/ui/confuse-field-and-method/issue-33784.stderr @@ -4,7 +4,7 @@ error[E0599]: no method named `closure` found for reference `&Obj<{closure@$DIR/ LL | p.closure(); | ^^^^^^^ field, not a method | -help: to call the function stored in `closure`, surround the field access with parentheses +help: to call the closure stored in `closure`, surround the field access with parentheses | LL | (p.closure)(); | + + @@ -19,7 +19,7 @@ error[E0599]: no method named `fn_ptr` found for reference `&&Obj<{closure@$DIR/ LL | q.fn_ptr(); | ^^^^^^ field, not a method | -help: to call the function stored in `fn_ptr`, surround the field access with parentheses +help: to call the function pointer stored in `fn_ptr`, surround the field access with parentheses | LL | (q.fn_ptr)(); | + + @@ -30,7 +30,7 @@ error[E0599]: no method named `c_fn_ptr` found for reference `&D` in the current LL | s.c_fn_ptr(); | ^^^^^^^^ field, not a method | -help: to call the function stored in `c_fn_ptr`, surround the field access with parentheses +help: to call the function pointer stored in `c_fn_ptr`, surround the field access with parentheses | LL | (s.c_fn_ptr)(); | + + 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/const-pattern-irrefutable.rs b/tests/ui/consts/const-pattern-irrefutable.rs index 61bdf57ffdb..759d2e8b2ed 100644 --- a/tests/ui/consts/const-pattern-irrefutable.rs +++ b/tests/ui/consts/const-pattern-irrefutable.rs @@ -1,28 +1,43 @@ mod foo { pub const b: u8 = 2; - pub const d: u8 = 2; + //~^ missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable + pub const d: (u8, u8) = (2, 1); + //~^ missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable } use foo::b as c; use foo::d; const a: u8 = 2; +//~^ missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable + +#[derive(PartialEq)] +struct S { + foo: u8, +} + +const e: S = S { + foo: 0, +}; fn main() { let a = 4; //~^ ERROR refutable pattern in local binding //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - //~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable //~| HELP introduce a variable instead let c = 4; //~^ ERROR refutable pattern in local binding //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - //~| missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable //~| HELP introduce a variable instead - let d = 4; + let d = (4, 4); //~^ ERROR refutable pattern in local binding - //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - //~| missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable + //~| patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered + //~| HELP introduce a variable instead + let e = S { + //~^ ERROR refutable pattern in local binding + //~| pattern `S { foo: 1_u8..=u8::MAX }` not covered //~| HELP introduce a variable instead + foo: 1, + }; fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115). } diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr index 2aed68bdd64..afb67a3a118 100644 --- a/tests/ui/consts/const-pattern-irrefutable.stderr +++ b/tests/ui/consts/const-pattern-irrefutable.stderr @@ -1,45 +1,76 @@ error[E0005]: refutable pattern in local binding - --> $DIR/const-pattern-irrefutable.rs:12:9 + --> $DIR/const-pattern-irrefutable.rs:24:9 | +LL | const a: u8 = 2; + | ----------- missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable +... LL | let a = 4; - | ^ - | | - | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - | missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable - | help: introduce a variable instead: `a_var` + | ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u8` +help: introduce a variable instead + | +LL | let a_var = 4; + | ~~~~~ error[E0005]: refutable pattern in local binding - --> $DIR/const-pattern-irrefutable.rs:17:9 + --> $DIR/const-pattern-irrefutable.rs:28:9 | +LL | pub const b: u8 = 2; + | --------------- missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable +... LL | let c = 4; - | ^ - | | - | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - | missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable - | help: introduce a variable instead: `c_var` + | ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u8` +help: introduce a variable instead + | +LL | let b_var = 4; + | ~~~~~ error[E0005]: refutable pattern in local binding - --> $DIR/const-pattern-irrefutable.rs:22:9 + --> $DIR/const-pattern-irrefutable.rs:32:9 | -LL | let d = 4; - | ^ - | | - | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - | missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable - | help: introduce a variable instead: `d_var` +LL | pub const d: (u8, u8) = (2, 1); + | --------------------- missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable +... +LL | let d = (4, 4); + | ^ patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html - = note: the matched value is of type `u8` + = note: the matched value is of type `(u8, u8)` +help: introduce a variable instead + | +LL | let d_var = (4, 4); + | ~~~~~ + +error[E0005]: refutable pattern in local binding + --> $DIR/const-pattern-irrefutable.rs:36:9 + | +LL | const e: S = S { + | ---------- missing patterns are not covered because `e` is interpreted as a constant pattern, not a new variable +... +LL | let e = S { + | ^ pattern `S { foo: 1_u8..=u8::MAX }` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +note: `S` defined here + --> $DIR/const-pattern-irrefutable.rs:15:8 + | +LL | struct S { + | ^ + = note: the matched value is of type `S` +help: introduce a variable instead + | +LL | let e_var = S { + | ~~~~~ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/consts/const-ptr-is-null.rs b/tests/ui/consts/const-ptr-is-null.rs index 82c293c0ad6..92cf87a9782 100644 --- a/tests/ui/consts/const-ptr-is-null.rs +++ b/tests/ui/consts/const-ptr-is-null.rs @@ -1,4 +1,3 @@ -#![feature(const_ptr_is_null)] use std::ptr; const IS_NULL: () = { diff --git a/tests/ui/consts/const-ptr-is-null.stderr b/tests/ui/consts/const-ptr-is-null.stderr index 5fd35142818..f71b3752772 100644 --- a/tests/ui/consts/const-ptr-is-null.stderr +++ b/tests/ui/consts/const-ptr-is-null.stderr @@ -8,7 +8,7 @@ note: inside `std::ptr::const_ptr::<impl *const T>::is_null::compiletime` note: inside `std::ptr::const_ptr::<impl *const i32>::is_null` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `MAYBE_NULL` - --> $DIR/const-ptr-is-null.rs:17:14 + --> $DIR/const-ptr-is-null.rs:16:14 | LL | assert!(!ptr.wrapping_sub(512).is_null()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index 8b61b0904a9..dfca04bef07 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -74,7 +74,7 @@ error: intrinsic `copy::copy` cannot be (indirectly) exposed to stable LL | unsafe { copy(src, dst, count) } | ^^^^^^^^^^^^^^^^^^^^^ | - = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_intrinsic_const_stable_indirect]` (but this requires team approval) error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` --> $DIR/const-unstable-intrinsic.rs:61:9 diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr index bd61f43727b..c73d1f05900 100644 --- a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr +++ b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr @@ -3,8 +3,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered | LL | match &[][..] { | ^^^^^^^ patterns `&[]` and `&[_, _, ..]` not covered +LL | +LL | E_SL => {} + | ---- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `E_SL` | = note: the matched value is of type `&[E]` +note: constant `E_SL` defined here + --> $DIR/incomplete-slice.rs:6:1 + | +LL | const E_SL: &[E] = &[E::A]; + | ^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | E_SL_var => {} + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ E_SL => {}, diff --git a/tests/ui/consts/is_val_statically_known.rs b/tests/ui/consts/is_val_statically_known.rs index a9059817bcc..d55910d32d3 100644 --- a/tests/ui/consts/is_val_statically_known.rs +++ b/tests/ui/consts/is_val_statically_known.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(core_intrinsics, is_val_statically_known)] +#![feature(core_intrinsics)] use std::intrinsics::is_val_statically_known; diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs index 51811b14203..429fa060521 100644 --- a/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs +++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Zforce-unstable-if-unmarked //@ edition: 2021 -#![feature(const_async_blocks, rustc_attrs, rustc_private)] +#![feature(const_async_blocks, rustc_attrs)] pub const fn not_stably_const() { // We need to do something const-unstable here. 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/consts/ptr_is_null.rs b/tests/ui/consts/ptr_is_null.rs index bbf13802312..8b41f5718e8 100644 --- a/tests/ui/consts/ptr_is_null.rs +++ b/tests/ui/consts/ptr_is_null.rs @@ -1,7 +1,6 @@ //@ compile-flags: --crate-type=lib //@ check-pass -#![feature(const_ptr_is_null)] #![allow(useless_ptr_null_checks)] const FOO: &usize = &42; diff --git a/tests/ui/debuginfo/debuginfo-inline-callsite-location-macro-1.rs b/tests/ui/debuginfo/debuginfo-inline-callsite-location-macro-1.rs new file mode 100644 index 00000000000..32ef849f47e --- /dev/null +++ b/tests/ui/debuginfo/debuginfo-inline-callsite-location-macro-1.rs @@ -0,0 +1,4124 @@ +//@ check-pass +//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Zmir-enable-passes=+Inline +//@ ignore-msvc +// ignore-tidy-filelength + +#[derive(Default)] +struct Something {} + +#[collapse_debuginfo(yes)] +macro_rules! collapsed_macro { + ($code:expr) => { + // Important to use a function here, so it can be inlined + // at the MIR stage. + Something::default() + } +} + +fn collapsed_debuginfo() { + // LLVM allows 12 bits for encoding discriminators, so 4096+1 calls to a + // MIR-inlined function will exhaust it. But because we're using + // collapse_debuginfo(yes) for this macro, we shouldn't need discriminators + // at all. + collapsed_macro!(1); + collapsed_macro!(2); + collapsed_macro!(3); + collapsed_macro!(4); + collapsed_macro!(5); + collapsed_macro!(6); + collapsed_macro!(7); + collapsed_macro!(8); + collapsed_macro!(9); + collapsed_macro!(10); + collapsed_macro!(11); + collapsed_macro!(12); + collapsed_macro!(13); + collapsed_macro!(14); + collapsed_macro!(15); + collapsed_macro!(16); + collapsed_macro!(17); + collapsed_macro!(18); + collapsed_macro!(19); + collapsed_macro!(20); + collapsed_macro!(21); + collapsed_macro!(22); + collapsed_macro!(23); + collapsed_macro!(24); + collapsed_macro!(25); + collapsed_macro!(26); + collapsed_macro!(27); + collapsed_macro!(28); + collapsed_macro!(29); + collapsed_macro!(30); + collapsed_macro!(31); + collapsed_macro!(32); + collapsed_macro!(33); + collapsed_macro!(34); + collapsed_macro!(35); + collapsed_macro!(36); + collapsed_macro!(37); + collapsed_macro!(38); + collapsed_macro!(39); + collapsed_macro!(40); + collapsed_macro!(41); + collapsed_macro!(42); + collapsed_macro!(43); + collapsed_macro!(44); + collapsed_macro!(45); + collapsed_macro!(46); + collapsed_macro!(47); + collapsed_macro!(48); + collapsed_macro!(49); + collapsed_macro!(50); + collapsed_macro!(51); + collapsed_macro!(52); + collapsed_macro!(53); + collapsed_macro!(54); + collapsed_macro!(55); + collapsed_macro!(56); + collapsed_macro!(57); + collapsed_macro!(58); + collapsed_macro!(59); + collapsed_macro!(60); + collapsed_macro!(61); + collapsed_macro!(62); + collapsed_macro!(63); + collapsed_macro!(64); + collapsed_macro!(65); + collapsed_macro!(66); + collapsed_macro!(67); + collapsed_macro!(68); + collapsed_macro!(69); + collapsed_macro!(70); + collapsed_macro!(71); + collapsed_macro!(72); + collapsed_macro!(73); + collapsed_macro!(74); + collapsed_macro!(75); + collapsed_macro!(76); + collapsed_macro!(77); + collapsed_macro!(78); + collapsed_macro!(79); + collapsed_macro!(80); + collapsed_macro!(81); + collapsed_macro!(82); + collapsed_macro!(83); + collapsed_macro!(84); + collapsed_macro!(85); + collapsed_macro!(86); + collapsed_macro!(87); + collapsed_macro!(88); + collapsed_macro!(89); + collapsed_macro!(90); + collapsed_macro!(91); + collapsed_macro!(92); + collapsed_macro!(93); + collapsed_macro!(94); + collapsed_macro!(95); + collapsed_macro!(96); + collapsed_macro!(97); + collapsed_macro!(98); + collapsed_macro!(99); + collapsed_macro!(100); + collapsed_macro!(101); + collapsed_macro!(102); + collapsed_macro!(103); + collapsed_macro!(104); + collapsed_macro!(105); + collapsed_macro!(106); + collapsed_macro!(107); + collapsed_macro!(108); + collapsed_macro!(109); + collapsed_macro!(110); + collapsed_macro!(111); + collapsed_macro!(112); + collapsed_macro!(113); + collapsed_macro!(114); + collapsed_macro!(115); + collapsed_macro!(116); + collapsed_macro!(117); + collapsed_macro!(118); + collapsed_macro!(119); + collapsed_macro!(120); + collapsed_macro!(121); + collapsed_macro!(122); + collapsed_macro!(123); + collapsed_macro!(124); + collapsed_macro!(125); + collapsed_macro!(126); + collapsed_macro!(127); + collapsed_macro!(128); + collapsed_macro!(129); + collapsed_macro!(130); + collapsed_macro!(131); + collapsed_macro!(132); + collapsed_macro!(133); + collapsed_macro!(134); + collapsed_macro!(135); + collapsed_macro!(136); + collapsed_macro!(137); + collapsed_macro!(138); + collapsed_macro!(139); + collapsed_macro!(140); + collapsed_macro!(141); + collapsed_macro!(142); + collapsed_macro!(143); + collapsed_macro!(144); + collapsed_macro!(145); + collapsed_macro!(146); + collapsed_macro!(147); + collapsed_macro!(148); + collapsed_macro!(149); + collapsed_macro!(150); + collapsed_macro!(151); + collapsed_macro!(152); + collapsed_macro!(153); + collapsed_macro!(154); + collapsed_macro!(155); + collapsed_macro!(156); + collapsed_macro!(157); + collapsed_macro!(158); + collapsed_macro!(159); + collapsed_macro!(160); + collapsed_macro!(161); + collapsed_macro!(162); + collapsed_macro!(163); + collapsed_macro!(164); + collapsed_macro!(165); + collapsed_macro!(166); + collapsed_macro!(167); + collapsed_macro!(168); + collapsed_macro!(169); + collapsed_macro!(170); + collapsed_macro!(171); + collapsed_macro!(172); + collapsed_macro!(173); + collapsed_macro!(174); + collapsed_macro!(175); + collapsed_macro!(176); + collapsed_macro!(177); + collapsed_macro!(178); + collapsed_macro!(179); + collapsed_macro!(180); + collapsed_macro!(181); + collapsed_macro!(182); + collapsed_macro!(183); + collapsed_macro!(184); + collapsed_macro!(185); + collapsed_macro!(186); + collapsed_macro!(187); + collapsed_macro!(188); + collapsed_macro!(189); + collapsed_macro!(190); + collapsed_macro!(191); + collapsed_macro!(192); + collapsed_macro!(193); + collapsed_macro!(194); + collapsed_macro!(195); + collapsed_macro!(196); + collapsed_macro!(197); + collapsed_macro!(198); + collapsed_macro!(199); + collapsed_macro!(200); + collapsed_macro!(201); + collapsed_macro!(202); + collapsed_macro!(203); + collapsed_macro!(204); + collapsed_macro!(205); + collapsed_macro!(206); + collapsed_macro!(207); + collapsed_macro!(208); + collapsed_macro!(209); + collapsed_macro!(210); + collapsed_macro!(211); + collapsed_macro!(212); + collapsed_macro!(213); + collapsed_macro!(214); + collapsed_macro!(215); + collapsed_macro!(216); + collapsed_macro!(217); + collapsed_macro!(218); + collapsed_macro!(219); + collapsed_macro!(220); + collapsed_macro!(221); + collapsed_macro!(222); + collapsed_macro!(223); + collapsed_macro!(224); + collapsed_macro!(225); + collapsed_macro!(226); + collapsed_macro!(227); + collapsed_macro!(228); + collapsed_macro!(229); + collapsed_macro!(230); + collapsed_macro!(231); + collapsed_macro!(232); + collapsed_macro!(233); + collapsed_macro!(234); + collapsed_macro!(235); + collapsed_macro!(236); + collapsed_macro!(237); + collapsed_macro!(238); + collapsed_macro!(239); + collapsed_macro!(240); + collapsed_macro!(241); + collapsed_macro!(242); + collapsed_macro!(243); + collapsed_macro!(244); + collapsed_macro!(245); + collapsed_macro!(246); + collapsed_macro!(247); + collapsed_macro!(248); + collapsed_macro!(249); + collapsed_macro!(250); + collapsed_macro!(251); + collapsed_macro!(252); + collapsed_macro!(253); + collapsed_macro!(254); + collapsed_macro!(255); + collapsed_macro!(256); + collapsed_macro!(257); + collapsed_macro!(258); + collapsed_macro!(259); + collapsed_macro!(260); + collapsed_macro!(261); + collapsed_macro!(262); + collapsed_macro!(263); + collapsed_macro!(264); + collapsed_macro!(265); + collapsed_macro!(266); + collapsed_macro!(267); + collapsed_macro!(268); + collapsed_macro!(269); + collapsed_macro!(270); + collapsed_macro!(271); + collapsed_macro!(272); + collapsed_macro!(273); + collapsed_macro!(274); + collapsed_macro!(275); + collapsed_macro!(276); + collapsed_macro!(277); + collapsed_macro!(278); + collapsed_macro!(279); + collapsed_macro!(280); + collapsed_macro!(281); + collapsed_macro!(282); + collapsed_macro!(283); + collapsed_macro!(284); + collapsed_macro!(285); + collapsed_macro!(286); + collapsed_macro!(287); + collapsed_macro!(288); + collapsed_macro!(289); + collapsed_macro!(290); + collapsed_macro!(291); + collapsed_macro!(292); + collapsed_macro!(293); + collapsed_macro!(294); + collapsed_macro!(295); + collapsed_macro!(296); + collapsed_macro!(297); + collapsed_macro!(298); + collapsed_macro!(299); + collapsed_macro!(300); + collapsed_macro!(301); + collapsed_macro!(302); + collapsed_macro!(303); + collapsed_macro!(304); + collapsed_macro!(305); + collapsed_macro!(306); + collapsed_macro!(307); + collapsed_macro!(308); + collapsed_macro!(309); + collapsed_macro!(310); + collapsed_macro!(311); + collapsed_macro!(312); + collapsed_macro!(313); + collapsed_macro!(314); + collapsed_macro!(315); + collapsed_macro!(316); + collapsed_macro!(317); + collapsed_macro!(318); + collapsed_macro!(319); + collapsed_macro!(320); + collapsed_macro!(321); + collapsed_macro!(322); + collapsed_macro!(323); + collapsed_macro!(324); + collapsed_macro!(325); + collapsed_macro!(326); + collapsed_macro!(327); + collapsed_macro!(328); + collapsed_macro!(329); + collapsed_macro!(330); + collapsed_macro!(331); + collapsed_macro!(332); + collapsed_macro!(333); + collapsed_macro!(334); + collapsed_macro!(335); + collapsed_macro!(336); + collapsed_macro!(337); + collapsed_macro!(338); + collapsed_macro!(339); + collapsed_macro!(340); + collapsed_macro!(341); + collapsed_macro!(342); + collapsed_macro!(343); + collapsed_macro!(344); + collapsed_macro!(345); + collapsed_macro!(346); + collapsed_macro!(347); + collapsed_macro!(348); + collapsed_macro!(349); + collapsed_macro!(350); + collapsed_macro!(351); + collapsed_macro!(352); + collapsed_macro!(353); + collapsed_macro!(354); + collapsed_macro!(355); + collapsed_macro!(356); + collapsed_macro!(357); + collapsed_macro!(358); + collapsed_macro!(359); + collapsed_macro!(360); + collapsed_macro!(361); + collapsed_macro!(362); + collapsed_macro!(363); + collapsed_macro!(364); + collapsed_macro!(365); + collapsed_macro!(366); + collapsed_macro!(367); + collapsed_macro!(368); + collapsed_macro!(369); + collapsed_macro!(370); + collapsed_macro!(371); + collapsed_macro!(372); + collapsed_macro!(373); + collapsed_macro!(374); + collapsed_macro!(375); + collapsed_macro!(376); + collapsed_macro!(377); + collapsed_macro!(378); + collapsed_macro!(379); + collapsed_macro!(380); + collapsed_macro!(381); + collapsed_macro!(382); + collapsed_macro!(383); + collapsed_macro!(384); + collapsed_macro!(385); + collapsed_macro!(386); + collapsed_macro!(387); + collapsed_macro!(388); + collapsed_macro!(389); + collapsed_macro!(390); + collapsed_macro!(391); + collapsed_macro!(392); + collapsed_macro!(393); + collapsed_macro!(394); + collapsed_macro!(395); + collapsed_macro!(396); + collapsed_macro!(397); + collapsed_macro!(398); + collapsed_macro!(399); + collapsed_macro!(400); + collapsed_macro!(401); + collapsed_macro!(402); + collapsed_macro!(403); + collapsed_macro!(404); + collapsed_macro!(405); + collapsed_macro!(406); + collapsed_macro!(407); + collapsed_macro!(408); + collapsed_macro!(409); + collapsed_macro!(410); + collapsed_macro!(411); + collapsed_macro!(412); + collapsed_macro!(413); + collapsed_macro!(414); + collapsed_macro!(415); + collapsed_macro!(416); + collapsed_macro!(417); + collapsed_macro!(418); + collapsed_macro!(419); + collapsed_macro!(420); + collapsed_macro!(421); + collapsed_macro!(422); + collapsed_macro!(423); + collapsed_macro!(424); + collapsed_macro!(425); + collapsed_macro!(426); + collapsed_macro!(427); + collapsed_macro!(428); + collapsed_macro!(429); + collapsed_macro!(430); + collapsed_macro!(431); + collapsed_macro!(432); + collapsed_macro!(433); + collapsed_macro!(434); + collapsed_macro!(435); + collapsed_macro!(436); + collapsed_macro!(437); + collapsed_macro!(438); + collapsed_macro!(439); + collapsed_macro!(440); + collapsed_macro!(441); + collapsed_macro!(442); + collapsed_macro!(443); + collapsed_macro!(444); + collapsed_macro!(445); + collapsed_macro!(446); + collapsed_macro!(447); + collapsed_macro!(448); + collapsed_macro!(449); + collapsed_macro!(450); + collapsed_macro!(451); + collapsed_macro!(452); + collapsed_macro!(453); + collapsed_macro!(454); + collapsed_macro!(455); + collapsed_macro!(456); + collapsed_macro!(457); + collapsed_macro!(458); + collapsed_macro!(459); + collapsed_macro!(460); + collapsed_macro!(461); + collapsed_macro!(462); + collapsed_macro!(463); + collapsed_macro!(464); + collapsed_macro!(465); + collapsed_macro!(466); + collapsed_macro!(467); + collapsed_macro!(468); + collapsed_macro!(469); + collapsed_macro!(470); + collapsed_macro!(471); + collapsed_macro!(472); + collapsed_macro!(473); + collapsed_macro!(474); + collapsed_macro!(475); + collapsed_macro!(476); + collapsed_macro!(477); + collapsed_macro!(478); + collapsed_macro!(479); + collapsed_macro!(480); + collapsed_macro!(481); + collapsed_macro!(482); + collapsed_macro!(483); + collapsed_macro!(484); + collapsed_macro!(485); + collapsed_macro!(486); + collapsed_macro!(487); + collapsed_macro!(488); + collapsed_macro!(489); + collapsed_macro!(490); + collapsed_macro!(491); + collapsed_macro!(492); + collapsed_macro!(493); + collapsed_macro!(494); + collapsed_macro!(495); + collapsed_macro!(496); + collapsed_macro!(497); + collapsed_macro!(498); + collapsed_macro!(499); + collapsed_macro!(500); + collapsed_macro!(501); + collapsed_macro!(502); + collapsed_macro!(503); + collapsed_macro!(504); + collapsed_macro!(505); + collapsed_macro!(506); + collapsed_macro!(507); + collapsed_macro!(508); + collapsed_macro!(509); + collapsed_macro!(510); + collapsed_macro!(511); + collapsed_macro!(512); + collapsed_macro!(513); + collapsed_macro!(514); + collapsed_macro!(515); + collapsed_macro!(516); + collapsed_macro!(517); + collapsed_macro!(518); + collapsed_macro!(519); + collapsed_macro!(520); + collapsed_macro!(521); + collapsed_macro!(522); + collapsed_macro!(523); + collapsed_macro!(524); + collapsed_macro!(525); + collapsed_macro!(526); + collapsed_macro!(527); + collapsed_macro!(528); + collapsed_macro!(529); + collapsed_macro!(530); + collapsed_macro!(531); + collapsed_macro!(532); + collapsed_macro!(533); + collapsed_macro!(534); + collapsed_macro!(535); + collapsed_macro!(536); + collapsed_macro!(537); + collapsed_macro!(538); + collapsed_macro!(539); + collapsed_macro!(540); + collapsed_macro!(541); + collapsed_macro!(542); + collapsed_macro!(543); + collapsed_macro!(544); + collapsed_macro!(545); + collapsed_macro!(546); + collapsed_macro!(547); + collapsed_macro!(548); + collapsed_macro!(549); + collapsed_macro!(550); + collapsed_macro!(551); + collapsed_macro!(552); + collapsed_macro!(553); + collapsed_macro!(554); + collapsed_macro!(555); + collapsed_macro!(556); + collapsed_macro!(557); + collapsed_macro!(558); + collapsed_macro!(559); + collapsed_macro!(560); + collapsed_macro!(561); + collapsed_macro!(562); + collapsed_macro!(563); + collapsed_macro!(564); + collapsed_macro!(565); + collapsed_macro!(566); + collapsed_macro!(567); + collapsed_macro!(568); + collapsed_macro!(569); + collapsed_macro!(570); + collapsed_macro!(571); + collapsed_macro!(572); + collapsed_macro!(573); + collapsed_macro!(574); + collapsed_macro!(575); + collapsed_macro!(576); + collapsed_macro!(577); + collapsed_macro!(578); + collapsed_macro!(579); + collapsed_macro!(580); + collapsed_macro!(581); + collapsed_macro!(582); + collapsed_macro!(583); + collapsed_macro!(584); + collapsed_macro!(585); + collapsed_macro!(586); + collapsed_macro!(587); + collapsed_macro!(588); + collapsed_macro!(589); + collapsed_macro!(590); + collapsed_macro!(591); + collapsed_macro!(592); + collapsed_macro!(593); + collapsed_macro!(594); + collapsed_macro!(595); + collapsed_macro!(596); + collapsed_macro!(597); + collapsed_macro!(598); + collapsed_macro!(599); + collapsed_macro!(600); + collapsed_macro!(601); + collapsed_macro!(602); + collapsed_macro!(603); + collapsed_macro!(604); + collapsed_macro!(605); + collapsed_macro!(606); + collapsed_macro!(607); + collapsed_macro!(608); + collapsed_macro!(609); + collapsed_macro!(610); + collapsed_macro!(611); + collapsed_macro!(612); + collapsed_macro!(613); + collapsed_macro!(614); + collapsed_macro!(615); + collapsed_macro!(616); + collapsed_macro!(617); + collapsed_macro!(618); + collapsed_macro!(619); + collapsed_macro!(620); + collapsed_macro!(621); + collapsed_macro!(622); + collapsed_macro!(623); + collapsed_macro!(624); + collapsed_macro!(625); + collapsed_macro!(626); + collapsed_macro!(627); + collapsed_macro!(628); + collapsed_macro!(629); + collapsed_macro!(630); + collapsed_macro!(631); + collapsed_macro!(632); + collapsed_macro!(633); + collapsed_macro!(634); + collapsed_macro!(635); + collapsed_macro!(636); + collapsed_macro!(637); + collapsed_macro!(638); + collapsed_macro!(639); + collapsed_macro!(640); + collapsed_macro!(641); + collapsed_macro!(642); + collapsed_macro!(643); + collapsed_macro!(644); + collapsed_macro!(645); + collapsed_macro!(646); + collapsed_macro!(647); + collapsed_macro!(648); + collapsed_macro!(649); + collapsed_macro!(650); + collapsed_macro!(651); + collapsed_macro!(652); + collapsed_macro!(653); + collapsed_macro!(654); + collapsed_macro!(655); + collapsed_macro!(656); + collapsed_macro!(657); + collapsed_macro!(658); + collapsed_macro!(659); + collapsed_macro!(660); + collapsed_macro!(661); + collapsed_macro!(662); + collapsed_macro!(663); + collapsed_macro!(664); + collapsed_macro!(665); + collapsed_macro!(666); + collapsed_macro!(667); + collapsed_macro!(668); + collapsed_macro!(669); + collapsed_macro!(670); + collapsed_macro!(671); + collapsed_macro!(672); + collapsed_macro!(673); + collapsed_macro!(674); + collapsed_macro!(675); + collapsed_macro!(676); + collapsed_macro!(677); + collapsed_macro!(678); + collapsed_macro!(679); + collapsed_macro!(680); + collapsed_macro!(681); + collapsed_macro!(682); + collapsed_macro!(683); + collapsed_macro!(684); + collapsed_macro!(685); + collapsed_macro!(686); + collapsed_macro!(687); + collapsed_macro!(688); + collapsed_macro!(689); + collapsed_macro!(690); + collapsed_macro!(691); + collapsed_macro!(692); + collapsed_macro!(693); + collapsed_macro!(694); + collapsed_macro!(695); + collapsed_macro!(696); + collapsed_macro!(697); + collapsed_macro!(698); + collapsed_macro!(699); + collapsed_macro!(700); + collapsed_macro!(701); + collapsed_macro!(702); + collapsed_macro!(703); + collapsed_macro!(704); + collapsed_macro!(705); + collapsed_macro!(706); + collapsed_macro!(707); + collapsed_macro!(708); + collapsed_macro!(709); + collapsed_macro!(710); + collapsed_macro!(711); + collapsed_macro!(712); + collapsed_macro!(713); + collapsed_macro!(714); + collapsed_macro!(715); + collapsed_macro!(716); + collapsed_macro!(717); + collapsed_macro!(718); + collapsed_macro!(719); + collapsed_macro!(720); + collapsed_macro!(721); + collapsed_macro!(722); + collapsed_macro!(723); + collapsed_macro!(724); + collapsed_macro!(725); + collapsed_macro!(726); + collapsed_macro!(727); + collapsed_macro!(728); + collapsed_macro!(729); + collapsed_macro!(730); + collapsed_macro!(731); + collapsed_macro!(732); + collapsed_macro!(733); + collapsed_macro!(734); + collapsed_macro!(735); + collapsed_macro!(736); + collapsed_macro!(737); + collapsed_macro!(738); + collapsed_macro!(739); + collapsed_macro!(740); + collapsed_macro!(741); + collapsed_macro!(742); + collapsed_macro!(743); + collapsed_macro!(744); + collapsed_macro!(745); + collapsed_macro!(746); + collapsed_macro!(747); + collapsed_macro!(748); + collapsed_macro!(749); + collapsed_macro!(750); + collapsed_macro!(751); + collapsed_macro!(752); + collapsed_macro!(753); + collapsed_macro!(754); + collapsed_macro!(755); + collapsed_macro!(756); + collapsed_macro!(757); + collapsed_macro!(758); + collapsed_macro!(759); + collapsed_macro!(760); + collapsed_macro!(761); + collapsed_macro!(762); + collapsed_macro!(763); + collapsed_macro!(764); + collapsed_macro!(765); + collapsed_macro!(766); + collapsed_macro!(767); + collapsed_macro!(768); + collapsed_macro!(769); + collapsed_macro!(770); + collapsed_macro!(771); + collapsed_macro!(772); + collapsed_macro!(773); + collapsed_macro!(774); + collapsed_macro!(775); + collapsed_macro!(776); + collapsed_macro!(777); + collapsed_macro!(778); + collapsed_macro!(779); + collapsed_macro!(780); + collapsed_macro!(781); + collapsed_macro!(782); + collapsed_macro!(783); + collapsed_macro!(784); + collapsed_macro!(785); + collapsed_macro!(786); + collapsed_macro!(787); + collapsed_macro!(788); + collapsed_macro!(789); + collapsed_macro!(790); + collapsed_macro!(791); + collapsed_macro!(792); + collapsed_macro!(793); + collapsed_macro!(794); + collapsed_macro!(795); + collapsed_macro!(796); + collapsed_macro!(797); + collapsed_macro!(798); + collapsed_macro!(799); + collapsed_macro!(800); + collapsed_macro!(801); + collapsed_macro!(802); + collapsed_macro!(803); + collapsed_macro!(804); + collapsed_macro!(805); + collapsed_macro!(806); + collapsed_macro!(807); + collapsed_macro!(808); + collapsed_macro!(809); + collapsed_macro!(810); + collapsed_macro!(811); + collapsed_macro!(812); + collapsed_macro!(813); + collapsed_macro!(814); + collapsed_macro!(815); + collapsed_macro!(816); + collapsed_macro!(817); + collapsed_macro!(818); + collapsed_macro!(819); + collapsed_macro!(820); + collapsed_macro!(821); + collapsed_macro!(822); + collapsed_macro!(823); + collapsed_macro!(824); + collapsed_macro!(825); + collapsed_macro!(826); + collapsed_macro!(827); + collapsed_macro!(828); + collapsed_macro!(829); + collapsed_macro!(830); + collapsed_macro!(831); + collapsed_macro!(832); + collapsed_macro!(833); + collapsed_macro!(834); + collapsed_macro!(835); + collapsed_macro!(836); + collapsed_macro!(837); + collapsed_macro!(838); + collapsed_macro!(839); + collapsed_macro!(840); + collapsed_macro!(841); + collapsed_macro!(842); + collapsed_macro!(843); + collapsed_macro!(844); + collapsed_macro!(845); + collapsed_macro!(846); + collapsed_macro!(847); + collapsed_macro!(848); + collapsed_macro!(849); + collapsed_macro!(850); + collapsed_macro!(851); + collapsed_macro!(852); + collapsed_macro!(853); + collapsed_macro!(854); + collapsed_macro!(855); + collapsed_macro!(856); + collapsed_macro!(857); + collapsed_macro!(858); + collapsed_macro!(859); + collapsed_macro!(860); + collapsed_macro!(861); + collapsed_macro!(862); + collapsed_macro!(863); + collapsed_macro!(864); + collapsed_macro!(865); + collapsed_macro!(866); + collapsed_macro!(867); + collapsed_macro!(868); + collapsed_macro!(869); + collapsed_macro!(870); + collapsed_macro!(871); + collapsed_macro!(872); + collapsed_macro!(873); + collapsed_macro!(874); + collapsed_macro!(875); + collapsed_macro!(876); + collapsed_macro!(877); + collapsed_macro!(878); + collapsed_macro!(879); + collapsed_macro!(880); + collapsed_macro!(881); + collapsed_macro!(882); + collapsed_macro!(883); + collapsed_macro!(884); + collapsed_macro!(885); + collapsed_macro!(886); + collapsed_macro!(887); + collapsed_macro!(888); + collapsed_macro!(889); + collapsed_macro!(890); + collapsed_macro!(891); + collapsed_macro!(892); + collapsed_macro!(893); + collapsed_macro!(894); + collapsed_macro!(895); + collapsed_macro!(896); + collapsed_macro!(897); + collapsed_macro!(898); + collapsed_macro!(899); + collapsed_macro!(900); + collapsed_macro!(901); + collapsed_macro!(902); + collapsed_macro!(903); + collapsed_macro!(904); + collapsed_macro!(905); + collapsed_macro!(906); + collapsed_macro!(907); + collapsed_macro!(908); + collapsed_macro!(909); + collapsed_macro!(910); + collapsed_macro!(911); + collapsed_macro!(912); + collapsed_macro!(913); + collapsed_macro!(914); + collapsed_macro!(915); + collapsed_macro!(916); + collapsed_macro!(917); + collapsed_macro!(918); + collapsed_macro!(919); + collapsed_macro!(920); + collapsed_macro!(921); + collapsed_macro!(922); + collapsed_macro!(923); + collapsed_macro!(924); + collapsed_macro!(925); + collapsed_macro!(926); + collapsed_macro!(927); + collapsed_macro!(928); + collapsed_macro!(929); + collapsed_macro!(930); + collapsed_macro!(931); + collapsed_macro!(932); + collapsed_macro!(933); + collapsed_macro!(934); + collapsed_macro!(935); + collapsed_macro!(936); + collapsed_macro!(937); + collapsed_macro!(938); + collapsed_macro!(939); + collapsed_macro!(940); + collapsed_macro!(941); + collapsed_macro!(942); + collapsed_macro!(943); + collapsed_macro!(944); + collapsed_macro!(945); + collapsed_macro!(946); + collapsed_macro!(947); + collapsed_macro!(948); + collapsed_macro!(949); + collapsed_macro!(950); + collapsed_macro!(951); + collapsed_macro!(952); + collapsed_macro!(953); + collapsed_macro!(954); + collapsed_macro!(955); + collapsed_macro!(956); + collapsed_macro!(957); + collapsed_macro!(958); + collapsed_macro!(959); + collapsed_macro!(960); + collapsed_macro!(961); + collapsed_macro!(962); + collapsed_macro!(963); + collapsed_macro!(964); + collapsed_macro!(965); + collapsed_macro!(966); + collapsed_macro!(967); + collapsed_macro!(968); + collapsed_macro!(969); + collapsed_macro!(970); + collapsed_macro!(971); + collapsed_macro!(972); + collapsed_macro!(973); + collapsed_macro!(974); + collapsed_macro!(975); + collapsed_macro!(976); + collapsed_macro!(977); + collapsed_macro!(978); + collapsed_macro!(979); + collapsed_macro!(980); + collapsed_macro!(981); + collapsed_macro!(982); + collapsed_macro!(983); + collapsed_macro!(984); + collapsed_macro!(985); + collapsed_macro!(986); + collapsed_macro!(987); + collapsed_macro!(988); + collapsed_macro!(989); + collapsed_macro!(990); + collapsed_macro!(991); + collapsed_macro!(992); + collapsed_macro!(993); + collapsed_macro!(994); + collapsed_macro!(995); + collapsed_macro!(996); + collapsed_macro!(997); + collapsed_macro!(998); + collapsed_macro!(999); + collapsed_macro!(1000); + collapsed_macro!(1001); + collapsed_macro!(1002); + collapsed_macro!(1003); + collapsed_macro!(1004); + collapsed_macro!(1005); + collapsed_macro!(1006); + collapsed_macro!(1007); + collapsed_macro!(1008); + collapsed_macro!(1009); + collapsed_macro!(1010); + collapsed_macro!(1011); + collapsed_macro!(1012); + collapsed_macro!(1013); + collapsed_macro!(1014); + collapsed_macro!(1015); + collapsed_macro!(1016); + collapsed_macro!(1017); + collapsed_macro!(1018); + collapsed_macro!(1019); + collapsed_macro!(1020); + collapsed_macro!(1021); + collapsed_macro!(1022); + collapsed_macro!(1023); + collapsed_macro!(1024); + collapsed_macro!(1025); + collapsed_macro!(1026); + collapsed_macro!(1027); + collapsed_macro!(1028); + collapsed_macro!(1029); + collapsed_macro!(1030); + collapsed_macro!(1031); + collapsed_macro!(1032); + collapsed_macro!(1033); + collapsed_macro!(1034); + collapsed_macro!(1035); + collapsed_macro!(1036); + collapsed_macro!(1037); + collapsed_macro!(1038); + collapsed_macro!(1039); + collapsed_macro!(1040); + collapsed_macro!(1041); + collapsed_macro!(1042); + collapsed_macro!(1043); + collapsed_macro!(1044); + collapsed_macro!(1045); + collapsed_macro!(1046); + collapsed_macro!(1047); + collapsed_macro!(1048); + collapsed_macro!(1049); + collapsed_macro!(1050); + collapsed_macro!(1051); + collapsed_macro!(1052); + collapsed_macro!(1053); + collapsed_macro!(1054); + collapsed_macro!(1055); + collapsed_macro!(1056); + collapsed_macro!(1057); + collapsed_macro!(1058); + collapsed_macro!(1059); + collapsed_macro!(1060); + collapsed_macro!(1061); + collapsed_macro!(1062); + collapsed_macro!(1063); + collapsed_macro!(1064); + collapsed_macro!(1065); + collapsed_macro!(1066); + collapsed_macro!(1067); + collapsed_macro!(1068); + collapsed_macro!(1069); + collapsed_macro!(1070); + collapsed_macro!(1071); + collapsed_macro!(1072); + collapsed_macro!(1073); + collapsed_macro!(1074); + collapsed_macro!(1075); + collapsed_macro!(1076); + collapsed_macro!(1077); + collapsed_macro!(1078); + collapsed_macro!(1079); + collapsed_macro!(1080); + collapsed_macro!(1081); + collapsed_macro!(1082); + collapsed_macro!(1083); + collapsed_macro!(1084); + collapsed_macro!(1085); + collapsed_macro!(1086); + collapsed_macro!(1087); + collapsed_macro!(1088); + collapsed_macro!(1089); + collapsed_macro!(1090); + collapsed_macro!(1091); + collapsed_macro!(1092); + collapsed_macro!(1093); + collapsed_macro!(1094); + collapsed_macro!(1095); + collapsed_macro!(1096); + collapsed_macro!(1097); + collapsed_macro!(1098); + collapsed_macro!(1099); + collapsed_macro!(1100); + collapsed_macro!(1101); + collapsed_macro!(1102); + collapsed_macro!(1103); + collapsed_macro!(1104); + collapsed_macro!(1105); + collapsed_macro!(1106); + collapsed_macro!(1107); + collapsed_macro!(1108); + collapsed_macro!(1109); + collapsed_macro!(1110); + collapsed_macro!(1111); + collapsed_macro!(1112); + collapsed_macro!(1113); + collapsed_macro!(1114); + collapsed_macro!(1115); + collapsed_macro!(1116); + collapsed_macro!(1117); + collapsed_macro!(1118); + collapsed_macro!(1119); + collapsed_macro!(1120); + collapsed_macro!(1121); + collapsed_macro!(1122); + collapsed_macro!(1123); + collapsed_macro!(1124); + collapsed_macro!(1125); + collapsed_macro!(1126); + collapsed_macro!(1127); + collapsed_macro!(1128); + collapsed_macro!(1129); + collapsed_macro!(1130); + collapsed_macro!(1131); + collapsed_macro!(1132); + collapsed_macro!(1133); + collapsed_macro!(1134); + collapsed_macro!(1135); + collapsed_macro!(1136); + collapsed_macro!(1137); + collapsed_macro!(1138); + collapsed_macro!(1139); + collapsed_macro!(1140); + collapsed_macro!(1141); + collapsed_macro!(1142); + collapsed_macro!(1143); + collapsed_macro!(1144); + collapsed_macro!(1145); + collapsed_macro!(1146); + collapsed_macro!(1147); + collapsed_macro!(1148); + collapsed_macro!(1149); + collapsed_macro!(1150); + collapsed_macro!(1151); + collapsed_macro!(1152); + collapsed_macro!(1153); + collapsed_macro!(1154); + collapsed_macro!(1155); + collapsed_macro!(1156); + collapsed_macro!(1157); + collapsed_macro!(1158); + collapsed_macro!(1159); + collapsed_macro!(1160); + collapsed_macro!(1161); + collapsed_macro!(1162); + collapsed_macro!(1163); + collapsed_macro!(1164); + collapsed_macro!(1165); + collapsed_macro!(1166); + collapsed_macro!(1167); + collapsed_macro!(1168); + collapsed_macro!(1169); + collapsed_macro!(1170); + collapsed_macro!(1171); + collapsed_macro!(1172); + collapsed_macro!(1173); + collapsed_macro!(1174); + collapsed_macro!(1175); + collapsed_macro!(1176); + collapsed_macro!(1177); + collapsed_macro!(1178); + collapsed_macro!(1179); + collapsed_macro!(1180); + collapsed_macro!(1181); + collapsed_macro!(1182); + collapsed_macro!(1183); + collapsed_macro!(1184); + collapsed_macro!(1185); + collapsed_macro!(1186); + collapsed_macro!(1187); + collapsed_macro!(1188); + collapsed_macro!(1189); + collapsed_macro!(1190); + collapsed_macro!(1191); + collapsed_macro!(1192); + collapsed_macro!(1193); + collapsed_macro!(1194); + collapsed_macro!(1195); + collapsed_macro!(1196); + collapsed_macro!(1197); + collapsed_macro!(1198); + collapsed_macro!(1199); + collapsed_macro!(1200); + collapsed_macro!(1201); + collapsed_macro!(1202); + collapsed_macro!(1203); + collapsed_macro!(1204); + collapsed_macro!(1205); + collapsed_macro!(1206); + collapsed_macro!(1207); + collapsed_macro!(1208); + collapsed_macro!(1209); + collapsed_macro!(1210); + collapsed_macro!(1211); + collapsed_macro!(1212); + collapsed_macro!(1213); + collapsed_macro!(1214); + collapsed_macro!(1215); + collapsed_macro!(1216); + collapsed_macro!(1217); + collapsed_macro!(1218); + collapsed_macro!(1219); + collapsed_macro!(1220); + collapsed_macro!(1221); + collapsed_macro!(1222); + collapsed_macro!(1223); + collapsed_macro!(1224); + collapsed_macro!(1225); + collapsed_macro!(1226); + collapsed_macro!(1227); + collapsed_macro!(1228); + collapsed_macro!(1229); + collapsed_macro!(1230); + collapsed_macro!(1231); + collapsed_macro!(1232); + collapsed_macro!(1233); + collapsed_macro!(1234); + collapsed_macro!(1235); + collapsed_macro!(1236); + collapsed_macro!(1237); + collapsed_macro!(1238); + collapsed_macro!(1239); + collapsed_macro!(1240); + collapsed_macro!(1241); + collapsed_macro!(1242); + collapsed_macro!(1243); + collapsed_macro!(1244); + collapsed_macro!(1245); + collapsed_macro!(1246); + collapsed_macro!(1247); + collapsed_macro!(1248); + collapsed_macro!(1249); + collapsed_macro!(1250); + collapsed_macro!(1251); + collapsed_macro!(1252); + collapsed_macro!(1253); + collapsed_macro!(1254); + collapsed_macro!(1255); + collapsed_macro!(1256); + collapsed_macro!(1257); + collapsed_macro!(1258); + collapsed_macro!(1259); + collapsed_macro!(1260); + collapsed_macro!(1261); + collapsed_macro!(1262); + collapsed_macro!(1263); + collapsed_macro!(1264); + collapsed_macro!(1265); + collapsed_macro!(1266); + collapsed_macro!(1267); + collapsed_macro!(1268); + collapsed_macro!(1269); + collapsed_macro!(1270); + collapsed_macro!(1271); + collapsed_macro!(1272); + collapsed_macro!(1273); + collapsed_macro!(1274); + collapsed_macro!(1275); + collapsed_macro!(1276); + collapsed_macro!(1277); + collapsed_macro!(1278); + collapsed_macro!(1279); + collapsed_macro!(1280); + collapsed_macro!(1281); + collapsed_macro!(1282); + collapsed_macro!(1283); + collapsed_macro!(1284); + collapsed_macro!(1285); + collapsed_macro!(1286); + collapsed_macro!(1287); + collapsed_macro!(1288); + collapsed_macro!(1289); + collapsed_macro!(1290); + collapsed_macro!(1291); + collapsed_macro!(1292); + collapsed_macro!(1293); + collapsed_macro!(1294); + collapsed_macro!(1295); + collapsed_macro!(1296); + collapsed_macro!(1297); + collapsed_macro!(1298); + collapsed_macro!(1299); + collapsed_macro!(1300); + collapsed_macro!(1301); + collapsed_macro!(1302); + collapsed_macro!(1303); + collapsed_macro!(1304); + collapsed_macro!(1305); + collapsed_macro!(1306); + collapsed_macro!(1307); + collapsed_macro!(1308); + collapsed_macro!(1309); + collapsed_macro!(1310); + collapsed_macro!(1311); + collapsed_macro!(1312); + collapsed_macro!(1313); + collapsed_macro!(1314); + collapsed_macro!(1315); + collapsed_macro!(1316); + collapsed_macro!(1317); + collapsed_macro!(1318); + collapsed_macro!(1319); + collapsed_macro!(1320); + collapsed_macro!(1321); + collapsed_macro!(1322); + collapsed_macro!(1323); + collapsed_macro!(1324); + collapsed_macro!(1325); + collapsed_macro!(1326); + collapsed_macro!(1327); + collapsed_macro!(1328); + collapsed_macro!(1329); + collapsed_macro!(1330); + collapsed_macro!(1331); + collapsed_macro!(1332); + collapsed_macro!(1333); + collapsed_macro!(1334); + collapsed_macro!(1335); + collapsed_macro!(1336); + collapsed_macro!(1337); + collapsed_macro!(1338); + collapsed_macro!(1339); + collapsed_macro!(1340); + collapsed_macro!(1341); + collapsed_macro!(1342); + collapsed_macro!(1343); + collapsed_macro!(1344); + collapsed_macro!(1345); + collapsed_macro!(1346); + collapsed_macro!(1347); + collapsed_macro!(1348); + collapsed_macro!(1349); + collapsed_macro!(1350); + collapsed_macro!(1351); + collapsed_macro!(1352); + collapsed_macro!(1353); + collapsed_macro!(1354); + collapsed_macro!(1355); + collapsed_macro!(1356); + collapsed_macro!(1357); + collapsed_macro!(1358); + collapsed_macro!(1359); + collapsed_macro!(1360); + collapsed_macro!(1361); + collapsed_macro!(1362); + collapsed_macro!(1363); + collapsed_macro!(1364); + collapsed_macro!(1365); + collapsed_macro!(1366); + collapsed_macro!(1367); + collapsed_macro!(1368); + collapsed_macro!(1369); + collapsed_macro!(1370); + collapsed_macro!(1371); + collapsed_macro!(1372); + collapsed_macro!(1373); + collapsed_macro!(1374); + collapsed_macro!(1375); + collapsed_macro!(1376); + collapsed_macro!(1377); + collapsed_macro!(1378); + collapsed_macro!(1379); + collapsed_macro!(1380); + collapsed_macro!(1381); + collapsed_macro!(1382); + collapsed_macro!(1383); + collapsed_macro!(1384); + collapsed_macro!(1385); + collapsed_macro!(1386); + collapsed_macro!(1387); + collapsed_macro!(1388); + collapsed_macro!(1389); + collapsed_macro!(1390); + collapsed_macro!(1391); + collapsed_macro!(1392); + collapsed_macro!(1393); + collapsed_macro!(1394); + collapsed_macro!(1395); + collapsed_macro!(1396); + collapsed_macro!(1397); + collapsed_macro!(1398); + collapsed_macro!(1399); + collapsed_macro!(1400); + collapsed_macro!(1401); + collapsed_macro!(1402); + collapsed_macro!(1403); + collapsed_macro!(1404); + collapsed_macro!(1405); + collapsed_macro!(1406); + collapsed_macro!(1407); + collapsed_macro!(1408); + collapsed_macro!(1409); + collapsed_macro!(1410); + collapsed_macro!(1411); + collapsed_macro!(1412); + collapsed_macro!(1413); + collapsed_macro!(1414); + collapsed_macro!(1415); + collapsed_macro!(1416); + collapsed_macro!(1417); + collapsed_macro!(1418); + collapsed_macro!(1419); + collapsed_macro!(1420); + collapsed_macro!(1421); + collapsed_macro!(1422); + collapsed_macro!(1423); + collapsed_macro!(1424); + collapsed_macro!(1425); + collapsed_macro!(1426); + collapsed_macro!(1427); + collapsed_macro!(1428); + collapsed_macro!(1429); + collapsed_macro!(1430); + collapsed_macro!(1431); + collapsed_macro!(1432); + collapsed_macro!(1433); + collapsed_macro!(1434); + collapsed_macro!(1435); + collapsed_macro!(1436); + collapsed_macro!(1437); + collapsed_macro!(1438); + collapsed_macro!(1439); + collapsed_macro!(1440); + collapsed_macro!(1441); + collapsed_macro!(1442); + collapsed_macro!(1443); + collapsed_macro!(1444); + collapsed_macro!(1445); + collapsed_macro!(1446); + collapsed_macro!(1447); + collapsed_macro!(1448); + collapsed_macro!(1449); + collapsed_macro!(1450); + collapsed_macro!(1451); + collapsed_macro!(1452); + collapsed_macro!(1453); + collapsed_macro!(1454); + collapsed_macro!(1455); + collapsed_macro!(1456); + collapsed_macro!(1457); + collapsed_macro!(1458); + collapsed_macro!(1459); + collapsed_macro!(1460); + collapsed_macro!(1461); + collapsed_macro!(1462); + collapsed_macro!(1463); + collapsed_macro!(1464); + collapsed_macro!(1465); + collapsed_macro!(1466); + collapsed_macro!(1467); + collapsed_macro!(1468); + collapsed_macro!(1469); + collapsed_macro!(1470); + collapsed_macro!(1471); + collapsed_macro!(1472); + collapsed_macro!(1473); + collapsed_macro!(1474); + collapsed_macro!(1475); + collapsed_macro!(1476); + collapsed_macro!(1477); + collapsed_macro!(1478); + collapsed_macro!(1479); + collapsed_macro!(1480); + collapsed_macro!(1481); + collapsed_macro!(1482); + collapsed_macro!(1483); + collapsed_macro!(1484); + collapsed_macro!(1485); + collapsed_macro!(1486); + collapsed_macro!(1487); + collapsed_macro!(1488); + collapsed_macro!(1489); + collapsed_macro!(1490); + collapsed_macro!(1491); + collapsed_macro!(1492); + collapsed_macro!(1493); + collapsed_macro!(1494); + collapsed_macro!(1495); + collapsed_macro!(1496); + collapsed_macro!(1497); + collapsed_macro!(1498); + collapsed_macro!(1499); + collapsed_macro!(1500); + collapsed_macro!(1501); + collapsed_macro!(1502); + collapsed_macro!(1503); + collapsed_macro!(1504); + collapsed_macro!(1505); + collapsed_macro!(1506); + collapsed_macro!(1507); + collapsed_macro!(1508); + collapsed_macro!(1509); + collapsed_macro!(1510); + collapsed_macro!(1511); + collapsed_macro!(1512); + collapsed_macro!(1513); + collapsed_macro!(1514); + collapsed_macro!(1515); + collapsed_macro!(1516); + collapsed_macro!(1517); + collapsed_macro!(1518); + collapsed_macro!(1519); + collapsed_macro!(1520); + collapsed_macro!(1521); + collapsed_macro!(1522); + collapsed_macro!(1523); + collapsed_macro!(1524); + collapsed_macro!(1525); + collapsed_macro!(1526); + collapsed_macro!(1527); + collapsed_macro!(1528); + collapsed_macro!(1529); + collapsed_macro!(1530); + collapsed_macro!(1531); + collapsed_macro!(1532); + collapsed_macro!(1533); + collapsed_macro!(1534); + collapsed_macro!(1535); + collapsed_macro!(1536); + collapsed_macro!(1537); + collapsed_macro!(1538); + collapsed_macro!(1539); + collapsed_macro!(1540); + collapsed_macro!(1541); + collapsed_macro!(1542); + collapsed_macro!(1543); + collapsed_macro!(1544); + collapsed_macro!(1545); + collapsed_macro!(1546); + collapsed_macro!(1547); + collapsed_macro!(1548); + collapsed_macro!(1549); + collapsed_macro!(1550); + collapsed_macro!(1551); + collapsed_macro!(1552); + collapsed_macro!(1553); + collapsed_macro!(1554); + collapsed_macro!(1555); + collapsed_macro!(1556); + collapsed_macro!(1557); + collapsed_macro!(1558); + collapsed_macro!(1559); + collapsed_macro!(1560); + collapsed_macro!(1561); + collapsed_macro!(1562); + collapsed_macro!(1563); + collapsed_macro!(1564); + collapsed_macro!(1565); + collapsed_macro!(1566); + collapsed_macro!(1567); + collapsed_macro!(1568); + collapsed_macro!(1569); + collapsed_macro!(1570); + collapsed_macro!(1571); + collapsed_macro!(1572); + collapsed_macro!(1573); + collapsed_macro!(1574); + collapsed_macro!(1575); + collapsed_macro!(1576); + collapsed_macro!(1577); + collapsed_macro!(1578); + collapsed_macro!(1579); + collapsed_macro!(1580); + collapsed_macro!(1581); + collapsed_macro!(1582); + collapsed_macro!(1583); + collapsed_macro!(1584); + collapsed_macro!(1585); + collapsed_macro!(1586); + collapsed_macro!(1587); + collapsed_macro!(1588); + collapsed_macro!(1589); + collapsed_macro!(1590); + collapsed_macro!(1591); + collapsed_macro!(1592); + collapsed_macro!(1593); + collapsed_macro!(1594); + collapsed_macro!(1595); + collapsed_macro!(1596); + collapsed_macro!(1597); + collapsed_macro!(1598); + collapsed_macro!(1599); + collapsed_macro!(1600); + collapsed_macro!(1601); + collapsed_macro!(1602); + collapsed_macro!(1603); + collapsed_macro!(1604); + collapsed_macro!(1605); + collapsed_macro!(1606); + collapsed_macro!(1607); + collapsed_macro!(1608); + collapsed_macro!(1609); + collapsed_macro!(1610); + collapsed_macro!(1611); + collapsed_macro!(1612); + collapsed_macro!(1613); + collapsed_macro!(1614); + collapsed_macro!(1615); + collapsed_macro!(1616); + collapsed_macro!(1617); + collapsed_macro!(1618); + collapsed_macro!(1619); + collapsed_macro!(1620); + collapsed_macro!(1621); + collapsed_macro!(1622); + collapsed_macro!(1623); + collapsed_macro!(1624); + collapsed_macro!(1625); + collapsed_macro!(1626); + collapsed_macro!(1627); + collapsed_macro!(1628); + collapsed_macro!(1629); + collapsed_macro!(1630); + collapsed_macro!(1631); + collapsed_macro!(1632); + collapsed_macro!(1633); + collapsed_macro!(1634); + collapsed_macro!(1635); + collapsed_macro!(1636); + collapsed_macro!(1637); + collapsed_macro!(1638); + collapsed_macro!(1639); + collapsed_macro!(1640); + collapsed_macro!(1641); + collapsed_macro!(1642); + collapsed_macro!(1643); + collapsed_macro!(1644); + collapsed_macro!(1645); + collapsed_macro!(1646); + collapsed_macro!(1647); + collapsed_macro!(1648); + collapsed_macro!(1649); + collapsed_macro!(1650); + collapsed_macro!(1651); + collapsed_macro!(1652); + collapsed_macro!(1653); + collapsed_macro!(1654); + collapsed_macro!(1655); + collapsed_macro!(1656); + collapsed_macro!(1657); + collapsed_macro!(1658); + collapsed_macro!(1659); + collapsed_macro!(1660); + collapsed_macro!(1661); + collapsed_macro!(1662); + collapsed_macro!(1663); + collapsed_macro!(1664); + collapsed_macro!(1665); + collapsed_macro!(1666); + collapsed_macro!(1667); + collapsed_macro!(1668); + collapsed_macro!(1669); + collapsed_macro!(1670); + collapsed_macro!(1671); + collapsed_macro!(1672); + collapsed_macro!(1673); + collapsed_macro!(1674); + collapsed_macro!(1675); + collapsed_macro!(1676); + collapsed_macro!(1677); + collapsed_macro!(1678); + collapsed_macro!(1679); + collapsed_macro!(1680); + collapsed_macro!(1681); + collapsed_macro!(1682); + collapsed_macro!(1683); + collapsed_macro!(1684); + collapsed_macro!(1685); + collapsed_macro!(1686); + collapsed_macro!(1687); + collapsed_macro!(1688); + collapsed_macro!(1689); + collapsed_macro!(1690); + collapsed_macro!(1691); + collapsed_macro!(1692); + collapsed_macro!(1693); + collapsed_macro!(1694); + collapsed_macro!(1695); + collapsed_macro!(1696); + collapsed_macro!(1697); + collapsed_macro!(1698); + collapsed_macro!(1699); + collapsed_macro!(1700); + collapsed_macro!(1701); + collapsed_macro!(1702); + collapsed_macro!(1703); + collapsed_macro!(1704); + collapsed_macro!(1705); + collapsed_macro!(1706); + collapsed_macro!(1707); + collapsed_macro!(1708); + collapsed_macro!(1709); + collapsed_macro!(1710); + collapsed_macro!(1711); + collapsed_macro!(1712); + collapsed_macro!(1713); + collapsed_macro!(1714); + collapsed_macro!(1715); + collapsed_macro!(1716); + collapsed_macro!(1717); + collapsed_macro!(1718); + collapsed_macro!(1719); + collapsed_macro!(1720); + collapsed_macro!(1721); + collapsed_macro!(1722); + collapsed_macro!(1723); + collapsed_macro!(1724); + collapsed_macro!(1725); + collapsed_macro!(1726); + collapsed_macro!(1727); + collapsed_macro!(1728); + collapsed_macro!(1729); + collapsed_macro!(1730); + collapsed_macro!(1731); + collapsed_macro!(1732); + collapsed_macro!(1733); + collapsed_macro!(1734); + collapsed_macro!(1735); + collapsed_macro!(1736); + collapsed_macro!(1737); + collapsed_macro!(1738); + collapsed_macro!(1739); + collapsed_macro!(1740); + collapsed_macro!(1741); + collapsed_macro!(1742); + collapsed_macro!(1743); + collapsed_macro!(1744); + collapsed_macro!(1745); + collapsed_macro!(1746); + collapsed_macro!(1747); + collapsed_macro!(1748); + collapsed_macro!(1749); + collapsed_macro!(1750); + collapsed_macro!(1751); + collapsed_macro!(1752); + collapsed_macro!(1753); + collapsed_macro!(1754); + collapsed_macro!(1755); + collapsed_macro!(1756); + collapsed_macro!(1757); + collapsed_macro!(1758); + collapsed_macro!(1759); + collapsed_macro!(1760); + collapsed_macro!(1761); + collapsed_macro!(1762); + collapsed_macro!(1763); + collapsed_macro!(1764); + collapsed_macro!(1765); + collapsed_macro!(1766); + collapsed_macro!(1767); + collapsed_macro!(1768); + collapsed_macro!(1769); + collapsed_macro!(1770); + collapsed_macro!(1771); + collapsed_macro!(1772); + collapsed_macro!(1773); + collapsed_macro!(1774); + collapsed_macro!(1775); + collapsed_macro!(1776); + collapsed_macro!(1777); + collapsed_macro!(1778); + collapsed_macro!(1779); + collapsed_macro!(1780); + collapsed_macro!(1781); + collapsed_macro!(1782); + collapsed_macro!(1783); + collapsed_macro!(1784); + collapsed_macro!(1785); + collapsed_macro!(1786); + collapsed_macro!(1787); + collapsed_macro!(1788); + collapsed_macro!(1789); + collapsed_macro!(1790); + collapsed_macro!(1791); + collapsed_macro!(1792); + collapsed_macro!(1793); + collapsed_macro!(1794); + collapsed_macro!(1795); + collapsed_macro!(1796); + collapsed_macro!(1797); + collapsed_macro!(1798); + collapsed_macro!(1799); + collapsed_macro!(1800); + collapsed_macro!(1801); + collapsed_macro!(1802); + collapsed_macro!(1803); + collapsed_macro!(1804); + collapsed_macro!(1805); + collapsed_macro!(1806); + collapsed_macro!(1807); + collapsed_macro!(1808); + collapsed_macro!(1809); + collapsed_macro!(1810); + collapsed_macro!(1811); + collapsed_macro!(1812); + collapsed_macro!(1813); + collapsed_macro!(1814); + collapsed_macro!(1815); + collapsed_macro!(1816); + collapsed_macro!(1817); + collapsed_macro!(1818); + collapsed_macro!(1819); + collapsed_macro!(1820); + collapsed_macro!(1821); + collapsed_macro!(1822); + collapsed_macro!(1823); + collapsed_macro!(1824); + collapsed_macro!(1825); + collapsed_macro!(1826); + collapsed_macro!(1827); + collapsed_macro!(1828); + collapsed_macro!(1829); + collapsed_macro!(1830); + collapsed_macro!(1831); + collapsed_macro!(1832); + collapsed_macro!(1833); + collapsed_macro!(1834); + collapsed_macro!(1835); + collapsed_macro!(1836); + collapsed_macro!(1837); + collapsed_macro!(1838); + collapsed_macro!(1839); + collapsed_macro!(1840); + collapsed_macro!(1841); + collapsed_macro!(1842); + collapsed_macro!(1843); + collapsed_macro!(1844); + collapsed_macro!(1845); + collapsed_macro!(1846); + collapsed_macro!(1847); + collapsed_macro!(1848); + collapsed_macro!(1849); + collapsed_macro!(1850); + collapsed_macro!(1851); + collapsed_macro!(1852); + collapsed_macro!(1853); + collapsed_macro!(1854); + collapsed_macro!(1855); + collapsed_macro!(1856); + collapsed_macro!(1857); + collapsed_macro!(1858); + collapsed_macro!(1859); + collapsed_macro!(1860); + collapsed_macro!(1861); + collapsed_macro!(1862); + collapsed_macro!(1863); + collapsed_macro!(1864); + collapsed_macro!(1865); + collapsed_macro!(1866); + collapsed_macro!(1867); + collapsed_macro!(1868); + collapsed_macro!(1869); + collapsed_macro!(1870); + collapsed_macro!(1871); + collapsed_macro!(1872); + collapsed_macro!(1873); + collapsed_macro!(1874); + collapsed_macro!(1875); + collapsed_macro!(1876); + collapsed_macro!(1877); + collapsed_macro!(1878); + collapsed_macro!(1879); + collapsed_macro!(1880); + collapsed_macro!(1881); + collapsed_macro!(1882); + collapsed_macro!(1883); + collapsed_macro!(1884); + collapsed_macro!(1885); + collapsed_macro!(1886); + collapsed_macro!(1887); + collapsed_macro!(1888); + collapsed_macro!(1889); + collapsed_macro!(1890); + collapsed_macro!(1891); + collapsed_macro!(1892); + collapsed_macro!(1893); + collapsed_macro!(1894); + collapsed_macro!(1895); + collapsed_macro!(1896); + collapsed_macro!(1897); + collapsed_macro!(1898); + collapsed_macro!(1899); + collapsed_macro!(1900); + collapsed_macro!(1901); + collapsed_macro!(1902); + collapsed_macro!(1903); + collapsed_macro!(1904); + collapsed_macro!(1905); + collapsed_macro!(1906); + collapsed_macro!(1907); + collapsed_macro!(1908); + collapsed_macro!(1909); + collapsed_macro!(1910); + collapsed_macro!(1911); + collapsed_macro!(1912); + collapsed_macro!(1913); + collapsed_macro!(1914); + collapsed_macro!(1915); + collapsed_macro!(1916); + collapsed_macro!(1917); + collapsed_macro!(1918); + collapsed_macro!(1919); + collapsed_macro!(1920); + collapsed_macro!(1921); + collapsed_macro!(1922); + collapsed_macro!(1923); + collapsed_macro!(1924); + collapsed_macro!(1925); + collapsed_macro!(1926); + collapsed_macro!(1927); + collapsed_macro!(1928); + collapsed_macro!(1929); + collapsed_macro!(1930); + collapsed_macro!(1931); + collapsed_macro!(1932); + collapsed_macro!(1933); + collapsed_macro!(1934); + collapsed_macro!(1935); + collapsed_macro!(1936); + collapsed_macro!(1937); + collapsed_macro!(1938); + collapsed_macro!(1939); + collapsed_macro!(1940); + collapsed_macro!(1941); + collapsed_macro!(1942); + collapsed_macro!(1943); + collapsed_macro!(1944); + collapsed_macro!(1945); + collapsed_macro!(1946); + collapsed_macro!(1947); + collapsed_macro!(1948); + collapsed_macro!(1949); + collapsed_macro!(1950); + collapsed_macro!(1951); + collapsed_macro!(1952); + collapsed_macro!(1953); + collapsed_macro!(1954); + collapsed_macro!(1955); + collapsed_macro!(1956); + collapsed_macro!(1957); + collapsed_macro!(1958); + collapsed_macro!(1959); + collapsed_macro!(1960); + collapsed_macro!(1961); + collapsed_macro!(1962); + collapsed_macro!(1963); + collapsed_macro!(1964); + collapsed_macro!(1965); + collapsed_macro!(1966); + collapsed_macro!(1967); + collapsed_macro!(1968); + collapsed_macro!(1969); + collapsed_macro!(1970); + collapsed_macro!(1971); + collapsed_macro!(1972); + collapsed_macro!(1973); + collapsed_macro!(1974); + collapsed_macro!(1975); + collapsed_macro!(1976); + collapsed_macro!(1977); + collapsed_macro!(1978); + collapsed_macro!(1979); + collapsed_macro!(1980); + collapsed_macro!(1981); + collapsed_macro!(1982); + collapsed_macro!(1983); + collapsed_macro!(1984); + collapsed_macro!(1985); + collapsed_macro!(1986); + collapsed_macro!(1987); + collapsed_macro!(1988); + collapsed_macro!(1989); + collapsed_macro!(1990); + collapsed_macro!(1991); + collapsed_macro!(1992); + collapsed_macro!(1993); + collapsed_macro!(1994); + collapsed_macro!(1995); + collapsed_macro!(1996); + collapsed_macro!(1997); + collapsed_macro!(1998); + collapsed_macro!(1999); + collapsed_macro!(2000); + collapsed_macro!(2001); + collapsed_macro!(2002); + collapsed_macro!(2003); + collapsed_macro!(2004); + collapsed_macro!(2005); + collapsed_macro!(2006); + collapsed_macro!(2007); + collapsed_macro!(2008); + collapsed_macro!(2009); + collapsed_macro!(2010); + collapsed_macro!(2011); + collapsed_macro!(2012); + collapsed_macro!(2013); + collapsed_macro!(2014); + collapsed_macro!(2015); + collapsed_macro!(2016); + collapsed_macro!(2017); + collapsed_macro!(2018); + collapsed_macro!(2019); + collapsed_macro!(2020); + collapsed_macro!(2021); + collapsed_macro!(2022); + collapsed_macro!(2023); + collapsed_macro!(2024); + collapsed_macro!(2025); + collapsed_macro!(2026); + collapsed_macro!(2027); + collapsed_macro!(2028); + collapsed_macro!(2029); + collapsed_macro!(2030); + collapsed_macro!(2031); + collapsed_macro!(2032); + collapsed_macro!(2033); + collapsed_macro!(2034); + collapsed_macro!(2035); + collapsed_macro!(2036); + collapsed_macro!(2037); + collapsed_macro!(2038); + collapsed_macro!(2039); + collapsed_macro!(2040); + collapsed_macro!(2041); + collapsed_macro!(2042); + collapsed_macro!(2043); + collapsed_macro!(2044); + collapsed_macro!(2045); + collapsed_macro!(2046); + collapsed_macro!(2047); + collapsed_macro!(2048); + collapsed_macro!(2049); + collapsed_macro!(2050); + collapsed_macro!(2051); + collapsed_macro!(2052); + collapsed_macro!(2053); + collapsed_macro!(2054); + collapsed_macro!(2055); + collapsed_macro!(2056); + collapsed_macro!(2057); + collapsed_macro!(2058); + collapsed_macro!(2059); + collapsed_macro!(2060); + collapsed_macro!(2061); + collapsed_macro!(2062); + collapsed_macro!(2063); + collapsed_macro!(2064); + collapsed_macro!(2065); + collapsed_macro!(2066); + collapsed_macro!(2067); + collapsed_macro!(2068); + collapsed_macro!(2069); + collapsed_macro!(2070); + collapsed_macro!(2071); + collapsed_macro!(2072); + collapsed_macro!(2073); + collapsed_macro!(2074); + collapsed_macro!(2075); + collapsed_macro!(2076); + collapsed_macro!(2077); + collapsed_macro!(2078); + collapsed_macro!(2079); + collapsed_macro!(2080); + collapsed_macro!(2081); + collapsed_macro!(2082); + collapsed_macro!(2083); + collapsed_macro!(2084); + collapsed_macro!(2085); + collapsed_macro!(2086); + collapsed_macro!(2087); + collapsed_macro!(2088); + collapsed_macro!(2089); + collapsed_macro!(2090); + collapsed_macro!(2091); + collapsed_macro!(2092); + collapsed_macro!(2093); + collapsed_macro!(2094); + collapsed_macro!(2095); + collapsed_macro!(2096); + collapsed_macro!(2097); + collapsed_macro!(2098); + collapsed_macro!(2099); + collapsed_macro!(2100); + collapsed_macro!(2101); + collapsed_macro!(2102); + collapsed_macro!(2103); + collapsed_macro!(2104); + collapsed_macro!(2105); + collapsed_macro!(2106); + collapsed_macro!(2107); + collapsed_macro!(2108); + collapsed_macro!(2109); + collapsed_macro!(2110); + collapsed_macro!(2111); + collapsed_macro!(2112); + collapsed_macro!(2113); + collapsed_macro!(2114); + collapsed_macro!(2115); + collapsed_macro!(2116); + collapsed_macro!(2117); + collapsed_macro!(2118); + collapsed_macro!(2119); + collapsed_macro!(2120); + collapsed_macro!(2121); + collapsed_macro!(2122); + collapsed_macro!(2123); + collapsed_macro!(2124); + collapsed_macro!(2125); + collapsed_macro!(2126); + collapsed_macro!(2127); + collapsed_macro!(2128); + collapsed_macro!(2129); + collapsed_macro!(2130); + collapsed_macro!(2131); + collapsed_macro!(2132); + collapsed_macro!(2133); + collapsed_macro!(2134); + collapsed_macro!(2135); + collapsed_macro!(2136); + collapsed_macro!(2137); + collapsed_macro!(2138); + collapsed_macro!(2139); + collapsed_macro!(2140); + collapsed_macro!(2141); + collapsed_macro!(2142); + collapsed_macro!(2143); + collapsed_macro!(2144); + collapsed_macro!(2145); + collapsed_macro!(2146); + collapsed_macro!(2147); + collapsed_macro!(2148); + collapsed_macro!(2149); + collapsed_macro!(2150); + collapsed_macro!(2151); + collapsed_macro!(2152); + collapsed_macro!(2153); + collapsed_macro!(2154); + collapsed_macro!(2155); + collapsed_macro!(2156); + collapsed_macro!(2157); + collapsed_macro!(2158); + collapsed_macro!(2159); + collapsed_macro!(2160); + collapsed_macro!(2161); + collapsed_macro!(2162); + collapsed_macro!(2163); + collapsed_macro!(2164); + collapsed_macro!(2165); + collapsed_macro!(2166); + collapsed_macro!(2167); + collapsed_macro!(2168); + collapsed_macro!(2169); + collapsed_macro!(2170); + collapsed_macro!(2171); + collapsed_macro!(2172); + collapsed_macro!(2173); + collapsed_macro!(2174); + collapsed_macro!(2175); + collapsed_macro!(2176); + collapsed_macro!(2177); + collapsed_macro!(2178); + collapsed_macro!(2179); + collapsed_macro!(2180); + collapsed_macro!(2181); + collapsed_macro!(2182); + collapsed_macro!(2183); + collapsed_macro!(2184); + collapsed_macro!(2185); + collapsed_macro!(2186); + collapsed_macro!(2187); + collapsed_macro!(2188); + collapsed_macro!(2189); + collapsed_macro!(2190); + collapsed_macro!(2191); + collapsed_macro!(2192); + collapsed_macro!(2193); + collapsed_macro!(2194); + collapsed_macro!(2195); + collapsed_macro!(2196); + collapsed_macro!(2197); + collapsed_macro!(2198); + collapsed_macro!(2199); + collapsed_macro!(2200); + collapsed_macro!(2201); + collapsed_macro!(2202); + collapsed_macro!(2203); + collapsed_macro!(2204); + collapsed_macro!(2205); + collapsed_macro!(2206); + collapsed_macro!(2207); + collapsed_macro!(2208); + collapsed_macro!(2209); + collapsed_macro!(2210); + collapsed_macro!(2211); + collapsed_macro!(2212); + collapsed_macro!(2213); + collapsed_macro!(2214); + collapsed_macro!(2215); + collapsed_macro!(2216); + collapsed_macro!(2217); + collapsed_macro!(2218); + collapsed_macro!(2219); + collapsed_macro!(2220); + collapsed_macro!(2221); + collapsed_macro!(2222); + collapsed_macro!(2223); + collapsed_macro!(2224); + collapsed_macro!(2225); + collapsed_macro!(2226); + collapsed_macro!(2227); + collapsed_macro!(2228); + collapsed_macro!(2229); + collapsed_macro!(2230); + collapsed_macro!(2231); + collapsed_macro!(2232); + collapsed_macro!(2233); + collapsed_macro!(2234); + collapsed_macro!(2235); + collapsed_macro!(2236); + collapsed_macro!(2237); + collapsed_macro!(2238); + collapsed_macro!(2239); + collapsed_macro!(2240); + collapsed_macro!(2241); + collapsed_macro!(2242); + collapsed_macro!(2243); + collapsed_macro!(2244); + collapsed_macro!(2245); + collapsed_macro!(2246); + collapsed_macro!(2247); + collapsed_macro!(2248); + collapsed_macro!(2249); + collapsed_macro!(2250); + collapsed_macro!(2251); + collapsed_macro!(2252); + collapsed_macro!(2253); + collapsed_macro!(2254); + collapsed_macro!(2255); + collapsed_macro!(2256); + collapsed_macro!(2257); + collapsed_macro!(2258); + collapsed_macro!(2259); + collapsed_macro!(2260); + collapsed_macro!(2261); + collapsed_macro!(2262); + collapsed_macro!(2263); + collapsed_macro!(2264); + collapsed_macro!(2265); + collapsed_macro!(2266); + collapsed_macro!(2267); + collapsed_macro!(2268); + collapsed_macro!(2269); + collapsed_macro!(2270); + collapsed_macro!(2271); + collapsed_macro!(2272); + collapsed_macro!(2273); + collapsed_macro!(2274); + collapsed_macro!(2275); + collapsed_macro!(2276); + collapsed_macro!(2277); + collapsed_macro!(2278); + collapsed_macro!(2279); + collapsed_macro!(2280); + collapsed_macro!(2281); + collapsed_macro!(2282); + collapsed_macro!(2283); + collapsed_macro!(2284); + collapsed_macro!(2285); + collapsed_macro!(2286); + collapsed_macro!(2287); + collapsed_macro!(2288); + collapsed_macro!(2289); + collapsed_macro!(2290); + collapsed_macro!(2291); + collapsed_macro!(2292); + collapsed_macro!(2293); + collapsed_macro!(2294); + collapsed_macro!(2295); + collapsed_macro!(2296); + collapsed_macro!(2297); + collapsed_macro!(2298); + collapsed_macro!(2299); + collapsed_macro!(2300); + collapsed_macro!(2301); + collapsed_macro!(2302); + collapsed_macro!(2303); + collapsed_macro!(2304); + collapsed_macro!(2305); + collapsed_macro!(2306); + collapsed_macro!(2307); + collapsed_macro!(2308); + collapsed_macro!(2309); + collapsed_macro!(2310); + collapsed_macro!(2311); + collapsed_macro!(2312); + collapsed_macro!(2313); + collapsed_macro!(2314); + collapsed_macro!(2315); + collapsed_macro!(2316); + collapsed_macro!(2317); + collapsed_macro!(2318); + collapsed_macro!(2319); + collapsed_macro!(2320); + collapsed_macro!(2321); + collapsed_macro!(2322); + collapsed_macro!(2323); + collapsed_macro!(2324); + collapsed_macro!(2325); + collapsed_macro!(2326); + collapsed_macro!(2327); + collapsed_macro!(2328); + collapsed_macro!(2329); + collapsed_macro!(2330); + collapsed_macro!(2331); + collapsed_macro!(2332); + collapsed_macro!(2333); + collapsed_macro!(2334); + collapsed_macro!(2335); + collapsed_macro!(2336); + collapsed_macro!(2337); + collapsed_macro!(2338); + collapsed_macro!(2339); + collapsed_macro!(2340); + collapsed_macro!(2341); + collapsed_macro!(2342); + collapsed_macro!(2343); + collapsed_macro!(2344); + collapsed_macro!(2345); + collapsed_macro!(2346); + collapsed_macro!(2347); + collapsed_macro!(2348); + collapsed_macro!(2349); + collapsed_macro!(2350); + collapsed_macro!(2351); + collapsed_macro!(2352); + collapsed_macro!(2353); + collapsed_macro!(2354); + collapsed_macro!(2355); + collapsed_macro!(2356); + collapsed_macro!(2357); + collapsed_macro!(2358); + collapsed_macro!(2359); + collapsed_macro!(2360); + collapsed_macro!(2361); + collapsed_macro!(2362); + collapsed_macro!(2363); + collapsed_macro!(2364); + collapsed_macro!(2365); + collapsed_macro!(2366); + collapsed_macro!(2367); + collapsed_macro!(2368); + collapsed_macro!(2369); + collapsed_macro!(2370); + collapsed_macro!(2371); + collapsed_macro!(2372); + collapsed_macro!(2373); + collapsed_macro!(2374); + collapsed_macro!(2375); + collapsed_macro!(2376); + collapsed_macro!(2377); + collapsed_macro!(2378); + collapsed_macro!(2379); + collapsed_macro!(2380); + collapsed_macro!(2381); + collapsed_macro!(2382); + collapsed_macro!(2383); + collapsed_macro!(2384); + collapsed_macro!(2385); + collapsed_macro!(2386); + collapsed_macro!(2387); + collapsed_macro!(2388); + collapsed_macro!(2389); + collapsed_macro!(2390); + collapsed_macro!(2391); + collapsed_macro!(2392); + collapsed_macro!(2393); + collapsed_macro!(2394); + collapsed_macro!(2395); + collapsed_macro!(2396); + collapsed_macro!(2397); + collapsed_macro!(2398); + collapsed_macro!(2399); + collapsed_macro!(2400); + collapsed_macro!(2401); + collapsed_macro!(2402); + collapsed_macro!(2403); + collapsed_macro!(2404); + collapsed_macro!(2405); + collapsed_macro!(2406); + collapsed_macro!(2407); + collapsed_macro!(2408); + collapsed_macro!(2409); + collapsed_macro!(2410); + collapsed_macro!(2411); + collapsed_macro!(2412); + collapsed_macro!(2413); + collapsed_macro!(2414); + collapsed_macro!(2415); + collapsed_macro!(2416); + collapsed_macro!(2417); + collapsed_macro!(2418); + collapsed_macro!(2419); + collapsed_macro!(2420); + collapsed_macro!(2421); + collapsed_macro!(2422); + collapsed_macro!(2423); + collapsed_macro!(2424); + collapsed_macro!(2425); + collapsed_macro!(2426); + collapsed_macro!(2427); + collapsed_macro!(2428); + collapsed_macro!(2429); + collapsed_macro!(2430); + collapsed_macro!(2431); + collapsed_macro!(2432); + collapsed_macro!(2433); + collapsed_macro!(2434); + collapsed_macro!(2435); + collapsed_macro!(2436); + collapsed_macro!(2437); + collapsed_macro!(2438); + collapsed_macro!(2439); + collapsed_macro!(2440); + collapsed_macro!(2441); + collapsed_macro!(2442); + collapsed_macro!(2443); + collapsed_macro!(2444); + collapsed_macro!(2445); + collapsed_macro!(2446); + collapsed_macro!(2447); + collapsed_macro!(2448); + collapsed_macro!(2449); + collapsed_macro!(2450); + collapsed_macro!(2451); + collapsed_macro!(2452); + collapsed_macro!(2453); + collapsed_macro!(2454); + collapsed_macro!(2455); + collapsed_macro!(2456); + collapsed_macro!(2457); + collapsed_macro!(2458); + collapsed_macro!(2459); + collapsed_macro!(2460); + collapsed_macro!(2461); + collapsed_macro!(2462); + collapsed_macro!(2463); + collapsed_macro!(2464); + collapsed_macro!(2465); + collapsed_macro!(2466); + collapsed_macro!(2467); + collapsed_macro!(2468); + collapsed_macro!(2469); + collapsed_macro!(2470); + collapsed_macro!(2471); + collapsed_macro!(2472); + collapsed_macro!(2473); + collapsed_macro!(2474); + collapsed_macro!(2475); + collapsed_macro!(2476); + collapsed_macro!(2477); + collapsed_macro!(2478); + collapsed_macro!(2479); + collapsed_macro!(2480); + collapsed_macro!(2481); + collapsed_macro!(2482); + collapsed_macro!(2483); + collapsed_macro!(2484); + collapsed_macro!(2485); + collapsed_macro!(2486); + collapsed_macro!(2487); + collapsed_macro!(2488); + collapsed_macro!(2489); + collapsed_macro!(2490); + collapsed_macro!(2491); + collapsed_macro!(2492); + collapsed_macro!(2493); + collapsed_macro!(2494); + collapsed_macro!(2495); + collapsed_macro!(2496); + collapsed_macro!(2497); + collapsed_macro!(2498); + collapsed_macro!(2499); + collapsed_macro!(2500); + collapsed_macro!(2501); + collapsed_macro!(2502); + collapsed_macro!(2503); + collapsed_macro!(2504); + collapsed_macro!(2505); + collapsed_macro!(2506); + collapsed_macro!(2507); + collapsed_macro!(2508); + collapsed_macro!(2509); + collapsed_macro!(2510); + collapsed_macro!(2511); + collapsed_macro!(2512); + collapsed_macro!(2513); + collapsed_macro!(2514); + collapsed_macro!(2515); + collapsed_macro!(2516); + collapsed_macro!(2517); + collapsed_macro!(2518); + collapsed_macro!(2519); + collapsed_macro!(2520); + collapsed_macro!(2521); + collapsed_macro!(2522); + collapsed_macro!(2523); + collapsed_macro!(2524); + collapsed_macro!(2525); + collapsed_macro!(2526); + collapsed_macro!(2527); + collapsed_macro!(2528); + collapsed_macro!(2529); + collapsed_macro!(2530); + collapsed_macro!(2531); + collapsed_macro!(2532); + collapsed_macro!(2533); + collapsed_macro!(2534); + collapsed_macro!(2535); + collapsed_macro!(2536); + collapsed_macro!(2537); + collapsed_macro!(2538); + collapsed_macro!(2539); + collapsed_macro!(2540); + collapsed_macro!(2541); + collapsed_macro!(2542); + collapsed_macro!(2543); + collapsed_macro!(2544); + collapsed_macro!(2545); + collapsed_macro!(2546); + collapsed_macro!(2547); + collapsed_macro!(2548); + collapsed_macro!(2549); + collapsed_macro!(2550); + collapsed_macro!(2551); + collapsed_macro!(2552); + collapsed_macro!(2553); + collapsed_macro!(2554); + collapsed_macro!(2555); + collapsed_macro!(2556); + collapsed_macro!(2557); + collapsed_macro!(2558); + collapsed_macro!(2559); + collapsed_macro!(2560); + collapsed_macro!(2561); + collapsed_macro!(2562); + collapsed_macro!(2563); + collapsed_macro!(2564); + collapsed_macro!(2565); + collapsed_macro!(2566); + collapsed_macro!(2567); + collapsed_macro!(2568); + collapsed_macro!(2569); + collapsed_macro!(2570); + collapsed_macro!(2571); + collapsed_macro!(2572); + collapsed_macro!(2573); + collapsed_macro!(2574); + collapsed_macro!(2575); + collapsed_macro!(2576); + collapsed_macro!(2577); + collapsed_macro!(2578); + collapsed_macro!(2579); + collapsed_macro!(2580); + collapsed_macro!(2581); + collapsed_macro!(2582); + collapsed_macro!(2583); + collapsed_macro!(2584); + collapsed_macro!(2585); + collapsed_macro!(2586); + collapsed_macro!(2587); + collapsed_macro!(2588); + collapsed_macro!(2589); + collapsed_macro!(2590); + collapsed_macro!(2591); + collapsed_macro!(2592); + collapsed_macro!(2593); + collapsed_macro!(2594); + collapsed_macro!(2595); + collapsed_macro!(2596); + collapsed_macro!(2597); + collapsed_macro!(2598); + collapsed_macro!(2599); + collapsed_macro!(2600); + collapsed_macro!(2601); + collapsed_macro!(2602); + collapsed_macro!(2603); + collapsed_macro!(2604); + collapsed_macro!(2605); + collapsed_macro!(2606); + collapsed_macro!(2607); + collapsed_macro!(2608); + collapsed_macro!(2609); + collapsed_macro!(2610); + collapsed_macro!(2611); + collapsed_macro!(2612); + collapsed_macro!(2613); + collapsed_macro!(2614); + collapsed_macro!(2615); + collapsed_macro!(2616); + collapsed_macro!(2617); + collapsed_macro!(2618); + collapsed_macro!(2619); + collapsed_macro!(2620); + collapsed_macro!(2621); + collapsed_macro!(2622); + collapsed_macro!(2623); + collapsed_macro!(2624); + collapsed_macro!(2625); + collapsed_macro!(2626); + collapsed_macro!(2627); + collapsed_macro!(2628); + collapsed_macro!(2629); + collapsed_macro!(2630); + collapsed_macro!(2631); + collapsed_macro!(2632); + collapsed_macro!(2633); + collapsed_macro!(2634); + collapsed_macro!(2635); + collapsed_macro!(2636); + collapsed_macro!(2637); + collapsed_macro!(2638); + collapsed_macro!(2639); + collapsed_macro!(2640); + collapsed_macro!(2641); + collapsed_macro!(2642); + collapsed_macro!(2643); + collapsed_macro!(2644); + collapsed_macro!(2645); + collapsed_macro!(2646); + collapsed_macro!(2647); + collapsed_macro!(2648); + collapsed_macro!(2649); + collapsed_macro!(2650); + collapsed_macro!(2651); + collapsed_macro!(2652); + collapsed_macro!(2653); + collapsed_macro!(2654); + collapsed_macro!(2655); + collapsed_macro!(2656); + collapsed_macro!(2657); + collapsed_macro!(2658); + collapsed_macro!(2659); + collapsed_macro!(2660); + collapsed_macro!(2661); + collapsed_macro!(2662); + collapsed_macro!(2663); + collapsed_macro!(2664); + collapsed_macro!(2665); + collapsed_macro!(2666); + collapsed_macro!(2667); + collapsed_macro!(2668); + collapsed_macro!(2669); + collapsed_macro!(2670); + collapsed_macro!(2671); + collapsed_macro!(2672); + collapsed_macro!(2673); + collapsed_macro!(2674); + collapsed_macro!(2675); + collapsed_macro!(2676); + collapsed_macro!(2677); + collapsed_macro!(2678); + collapsed_macro!(2679); + collapsed_macro!(2680); + collapsed_macro!(2681); + collapsed_macro!(2682); + collapsed_macro!(2683); + collapsed_macro!(2684); + collapsed_macro!(2685); + collapsed_macro!(2686); + collapsed_macro!(2687); + collapsed_macro!(2688); + collapsed_macro!(2689); + collapsed_macro!(2690); + collapsed_macro!(2691); + collapsed_macro!(2692); + collapsed_macro!(2693); + collapsed_macro!(2694); + collapsed_macro!(2695); + collapsed_macro!(2696); + collapsed_macro!(2697); + collapsed_macro!(2698); + collapsed_macro!(2699); + collapsed_macro!(2700); + collapsed_macro!(2701); + collapsed_macro!(2702); + collapsed_macro!(2703); + collapsed_macro!(2704); + collapsed_macro!(2705); + collapsed_macro!(2706); + collapsed_macro!(2707); + collapsed_macro!(2708); + collapsed_macro!(2709); + collapsed_macro!(2710); + collapsed_macro!(2711); + collapsed_macro!(2712); + collapsed_macro!(2713); + collapsed_macro!(2714); + collapsed_macro!(2715); + collapsed_macro!(2716); + collapsed_macro!(2717); + collapsed_macro!(2718); + collapsed_macro!(2719); + collapsed_macro!(2720); + collapsed_macro!(2721); + collapsed_macro!(2722); + collapsed_macro!(2723); + collapsed_macro!(2724); + collapsed_macro!(2725); + collapsed_macro!(2726); + collapsed_macro!(2727); + collapsed_macro!(2728); + collapsed_macro!(2729); + collapsed_macro!(2730); + collapsed_macro!(2731); + collapsed_macro!(2732); + collapsed_macro!(2733); + collapsed_macro!(2734); + collapsed_macro!(2735); + collapsed_macro!(2736); + collapsed_macro!(2737); + collapsed_macro!(2738); + collapsed_macro!(2739); + collapsed_macro!(2740); + collapsed_macro!(2741); + collapsed_macro!(2742); + collapsed_macro!(2743); + collapsed_macro!(2744); + collapsed_macro!(2745); + collapsed_macro!(2746); + collapsed_macro!(2747); + collapsed_macro!(2748); + collapsed_macro!(2749); + collapsed_macro!(2750); + collapsed_macro!(2751); + collapsed_macro!(2752); + collapsed_macro!(2753); + collapsed_macro!(2754); + collapsed_macro!(2755); + collapsed_macro!(2756); + collapsed_macro!(2757); + collapsed_macro!(2758); + collapsed_macro!(2759); + collapsed_macro!(2760); + collapsed_macro!(2761); + collapsed_macro!(2762); + collapsed_macro!(2763); + collapsed_macro!(2764); + collapsed_macro!(2765); + collapsed_macro!(2766); + collapsed_macro!(2767); + collapsed_macro!(2768); + collapsed_macro!(2769); + collapsed_macro!(2770); + collapsed_macro!(2771); + collapsed_macro!(2772); + collapsed_macro!(2773); + collapsed_macro!(2774); + collapsed_macro!(2775); + collapsed_macro!(2776); + collapsed_macro!(2777); + collapsed_macro!(2778); + collapsed_macro!(2779); + collapsed_macro!(2780); + collapsed_macro!(2781); + collapsed_macro!(2782); + collapsed_macro!(2783); + collapsed_macro!(2784); + collapsed_macro!(2785); + collapsed_macro!(2786); + collapsed_macro!(2787); + collapsed_macro!(2788); + collapsed_macro!(2789); + collapsed_macro!(2790); + collapsed_macro!(2791); + collapsed_macro!(2792); + collapsed_macro!(2793); + collapsed_macro!(2794); + collapsed_macro!(2795); + collapsed_macro!(2796); + collapsed_macro!(2797); + collapsed_macro!(2798); + collapsed_macro!(2799); + collapsed_macro!(2800); + collapsed_macro!(2801); + collapsed_macro!(2802); + collapsed_macro!(2803); + collapsed_macro!(2804); + collapsed_macro!(2805); + collapsed_macro!(2806); + collapsed_macro!(2807); + collapsed_macro!(2808); + collapsed_macro!(2809); + collapsed_macro!(2810); + collapsed_macro!(2811); + collapsed_macro!(2812); + collapsed_macro!(2813); + collapsed_macro!(2814); + collapsed_macro!(2815); + collapsed_macro!(2816); + collapsed_macro!(2817); + collapsed_macro!(2818); + collapsed_macro!(2819); + collapsed_macro!(2820); + collapsed_macro!(2821); + collapsed_macro!(2822); + collapsed_macro!(2823); + collapsed_macro!(2824); + collapsed_macro!(2825); + collapsed_macro!(2826); + collapsed_macro!(2827); + collapsed_macro!(2828); + collapsed_macro!(2829); + collapsed_macro!(2830); + collapsed_macro!(2831); + collapsed_macro!(2832); + collapsed_macro!(2833); + collapsed_macro!(2834); + collapsed_macro!(2835); + collapsed_macro!(2836); + collapsed_macro!(2837); + collapsed_macro!(2838); + collapsed_macro!(2839); + collapsed_macro!(2840); + collapsed_macro!(2841); + collapsed_macro!(2842); + collapsed_macro!(2843); + collapsed_macro!(2844); + collapsed_macro!(2845); + collapsed_macro!(2846); + collapsed_macro!(2847); + collapsed_macro!(2848); + collapsed_macro!(2849); + collapsed_macro!(2850); + collapsed_macro!(2851); + collapsed_macro!(2852); + collapsed_macro!(2853); + collapsed_macro!(2854); + collapsed_macro!(2855); + collapsed_macro!(2856); + collapsed_macro!(2857); + collapsed_macro!(2858); + collapsed_macro!(2859); + collapsed_macro!(2860); + collapsed_macro!(2861); + collapsed_macro!(2862); + collapsed_macro!(2863); + collapsed_macro!(2864); + collapsed_macro!(2865); + collapsed_macro!(2866); + collapsed_macro!(2867); + collapsed_macro!(2868); + collapsed_macro!(2869); + collapsed_macro!(2870); + collapsed_macro!(2871); + collapsed_macro!(2872); + collapsed_macro!(2873); + collapsed_macro!(2874); + collapsed_macro!(2875); + collapsed_macro!(2876); + collapsed_macro!(2877); + collapsed_macro!(2878); + collapsed_macro!(2879); + collapsed_macro!(2880); + collapsed_macro!(2881); + collapsed_macro!(2882); + collapsed_macro!(2883); + collapsed_macro!(2884); + collapsed_macro!(2885); + collapsed_macro!(2886); + collapsed_macro!(2887); + collapsed_macro!(2888); + collapsed_macro!(2889); + collapsed_macro!(2890); + collapsed_macro!(2891); + collapsed_macro!(2892); + collapsed_macro!(2893); + collapsed_macro!(2894); + collapsed_macro!(2895); + collapsed_macro!(2896); + collapsed_macro!(2897); + collapsed_macro!(2898); + collapsed_macro!(2899); + collapsed_macro!(2900); + collapsed_macro!(2901); + collapsed_macro!(2902); + collapsed_macro!(2903); + collapsed_macro!(2904); + collapsed_macro!(2905); + collapsed_macro!(2906); + collapsed_macro!(2907); + collapsed_macro!(2908); + collapsed_macro!(2909); + collapsed_macro!(2910); + collapsed_macro!(2911); + collapsed_macro!(2912); + collapsed_macro!(2913); + collapsed_macro!(2914); + collapsed_macro!(2915); + collapsed_macro!(2916); + collapsed_macro!(2917); + collapsed_macro!(2918); + collapsed_macro!(2919); + collapsed_macro!(2920); + collapsed_macro!(2921); + collapsed_macro!(2922); + collapsed_macro!(2923); + collapsed_macro!(2924); + collapsed_macro!(2925); + collapsed_macro!(2926); + collapsed_macro!(2927); + collapsed_macro!(2928); + collapsed_macro!(2929); + collapsed_macro!(2930); + collapsed_macro!(2931); + collapsed_macro!(2932); + collapsed_macro!(2933); + collapsed_macro!(2934); + collapsed_macro!(2935); + collapsed_macro!(2936); + collapsed_macro!(2937); + collapsed_macro!(2938); + collapsed_macro!(2939); + collapsed_macro!(2940); + collapsed_macro!(2941); + collapsed_macro!(2942); + collapsed_macro!(2943); + collapsed_macro!(2944); + collapsed_macro!(2945); + collapsed_macro!(2946); + collapsed_macro!(2947); + collapsed_macro!(2948); + collapsed_macro!(2949); + collapsed_macro!(2950); + collapsed_macro!(2951); + collapsed_macro!(2952); + collapsed_macro!(2953); + collapsed_macro!(2954); + collapsed_macro!(2955); + collapsed_macro!(2956); + collapsed_macro!(2957); + collapsed_macro!(2958); + collapsed_macro!(2959); + collapsed_macro!(2960); + collapsed_macro!(2961); + collapsed_macro!(2962); + collapsed_macro!(2963); + collapsed_macro!(2964); + collapsed_macro!(2965); + collapsed_macro!(2966); + collapsed_macro!(2967); + collapsed_macro!(2968); + collapsed_macro!(2969); + collapsed_macro!(2970); + collapsed_macro!(2971); + collapsed_macro!(2972); + collapsed_macro!(2973); + collapsed_macro!(2974); + collapsed_macro!(2975); + collapsed_macro!(2976); + collapsed_macro!(2977); + collapsed_macro!(2978); + collapsed_macro!(2979); + collapsed_macro!(2980); + collapsed_macro!(2981); + collapsed_macro!(2982); + collapsed_macro!(2983); + collapsed_macro!(2984); + collapsed_macro!(2985); + collapsed_macro!(2986); + collapsed_macro!(2987); + collapsed_macro!(2988); + collapsed_macro!(2989); + collapsed_macro!(2990); + collapsed_macro!(2991); + collapsed_macro!(2992); + collapsed_macro!(2993); + collapsed_macro!(2994); + collapsed_macro!(2995); + collapsed_macro!(2996); + collapsed_macro!(2997); + collapsed_macro!(2998); + collapsed_macro!(2999); + collapsed_macro!(3000); + collapsed_macro!(3001); + collapsed_macro!(3002); + collapsed_macro!(3003); + collapsed_macro!(3004); + collapsed_macro!(3005); + collapsed_macro!(3006); + collapsed_macro!(3007); + collapsed_macro!(3008); + collapsed_macro!(3009); + collapsed_macro!(3010); + collapsed_macro!(3011); + collapsed_macro!(3012); + collapsed_macro!(3013); + collapsed_macro!(3014); + collapsed_macro!(3015); + collapsed_macro!(3016); + collapsed_macro!(3017); + collapsed_macro!(3018); + collapsed_macro!(3019); + collapsed_macro!(3020); + collapsed_macro!(3021); + collapsed_macro!(3022); + collapsed_macro!(3023); + collapsed_macro!(3024); + collapsed_macro!(3025); + collapsed_macro!(3026); + collapsed_macro!(3027); + collapsed_macro!(3028); + collapsed_macro!(3029); + collapsed_macro!(3030); + collapsed_macro!(3031); + collapsed_macro!(3032); + collapsed_macro!(3033); + collapsed_macro!(3034); + collapsed_macro!(3035); + collapsed_macro!(3036); + collapsed_macro!(3037); + collapsed_macro!(3038); + collapsed_macro!(3039); + collapsed_macro!(3040); + collapsed_macro!(3041); + collapsed_macro!(3042); + collapsed_macro!(3043); + collapsed_macro!(3044); + collapsed_macro!(3045); + collapsed_macro!(3046); + collapsed_macro!(3047); + collapsed_macro!(3048); + collapsed_macro!(3049); + collapsed_macro!(3050); + collapsed_macro!(3051); + collapsed_macro!(3052); + collapsed_macro!(3053); + collapsed_macro!(3054); + collapsed_macro!(3055); + collapsed_macro!(3056); + collapsed_macro!(3057); + collapsed_macro!(3058); + collapsed_macro!(3059); + collapsed_macro!(3060); + collapsed_macro!(3061); + collapsed_macro!(3062); + collapsed_macro!(3063); + collapsed_macro!(3064); + collapsed_macro!(3065); + collapsed_macro!(3066); + collapsed_macro!(3067); + collapsed_macro!(3068); + collapsed_macro!(3069); + collapsed_macro!(3070); + collapsed_macro!(3071); + collapsed_macro!(3072); + collapsed_macro!(3073); + collapsed_macro!(3074); + collapsed_macro!(3075); + collapsed_macro!(3076); + collapsed_macro!(3077); + collapsed_macro!(3078); + collapsed_macro!(3079); + collapsed_macro!(3080); + collapsed_macro!(3081); + collapsed_macro!(3082); + collapsed_macro!(3083); + collapsed_macro!(3084); + collapsed_macro!(3085); + collapsed_macro!(3086); + collapsed_macro!(3087); + collapsed_macro!(3088); + collapsed_macro!(3089); + collapsed_macro!(3090); + collapsed_macro!(3091); + collapsed_macro!(3092); + collapsed_macro!(3093); + collapsed_macro!(3094); + collapsed_macro!(3095); + collapsed_macro!(3096); + collapsed_macro!(3097); + collapsed_macro!(3098); + collapsed_macro!(3099); + collapsed_macro!(3100); + collapsed_macro!(3101); + collapsed_macro!(3102); + collapsed_macro!(3103); + collapsed_macro!(3104); + collapsed_macro!(3105); + collapsed_macro!(3106); + collapsed_macro!(3107); + collapsed_macro!(3108); + collapsed_macro!(3109); + collapsed_macro!(3110); + collapsed_macro!(3111); + collapsed_macro!(3112); + collapsed_macro!(3113); + collapsed_macro!(3114); + collapsed_macro!(3115); + collapsed_macro!(3116); + collapsed_macro!(3117); + collapsed_macro!(3118); + collapsed_macro!(3119); + collapsed_macro!(3120); + collapsed_macro!(3121); + collapsed_macro!(3122); + collapsed_macro!(3123); + collapsed_macro!(3124); + collapsed_macro!(3125); + collapsed_macro!(3126); + collapsed_macro!(3127); + collapsed_macro!(3128); + collapsed_macro!(3129); + collapsed_macro!(3130); + collapsed_macro!(3131); + collapsed_macro!(3132); + collapsed_macro!(3133); + collapsed_macro!(3134); + collapsed_macro!(3135); + collapsed_macro!(3136); + collapsed_macro!(3137); + collapsed_macro!(3138); + collapsed_macro!(3139); + collapsed_macro!(3140); + collapsed_macro!(3141); + collapsed_macro!(3142); + collapsed_macro!(3143); + collapsed_macro!(3144); + collapsed_macro!(3145); + collapsed_macro!(3146); + collapsed_macro!(3147); + collapsed_macro!(3148); + collapsed_macro!(3149); + collapsed_macro!(3150); + collapsed_macro!(3151); + collapsed_macro!(3152); + collapsed_macro!(3153); + collapsed_macro!(3154); + collapsed_macro!(3155); + collapsed_macro!(3156); + collapsed_macro!(3157); + collapsed_macro!(3158); + collapsed_macro!(3159); + collapsed_macro!(3160); + collapsed_macro!(3161); + collapsed_macro!(3162); + collapsed_macro!(3163); + collapsed_macro!(3164); + collapsed_macro!(3165); + collapsed_macro!(3166); + collapsed_macro!(3167); + collapsed_macro!(3168); + collapsed_macro!(3169); + collapsed_macro!(3170); + collapsed_macro!(3171); + collapsed_macro!(3172); + collapsed_macro!(3173); + collapsed_macro!(3174); + collapsed_macro!(3175); + collapsed_macro!(3176); + collapsed_macro!(3177); + collapsed_macro!(3178); + collapsed_macro!(3179); + collapsed_macro!(3180); + collapsed_macro!(3181); + collapsed_macro!(3182); + collapsed_macro!(3183); + collapsed_macro!(3184); + collapsed_macro!(3185); + collapsed_macro!(3186); + collapsed_macro!(3187); + collapsed_macro!(3188); + collapsed_macro!(3189); + collapsed_macro!(3190); + collapsed_macro!(3191); + collapsed_macro!(3192); + collapsed_macro!(3193); + collapsed_macro!(3194); + collapsed_macro!(3195); + collapsed_macro!(3196); + collapsed_macro!(3197); + collapsed_macro!(3198); + collapsed_macro!(3199); + collapsed_macro!(3200); + collapsed_macro!(3201); + collapsed_macro!(3202); + collapsed_macro!(3203); + collapsed_macro!(3204); + collapsed_macro!(3205); + collapsed_macro!(3206); + collapsed_macro!(3207); + collapsed_macro!(3208); + collapsed_macro!(3209); + collapsed_macro!(3210); + collapsed_macro!(3211); + collapsed_macro!(3212); + collapsed_macro!(3213); + collapsed_macro!(3214); + collapsed_macro!(3215); + collapsed_macro!(3216); + collapsed_macro!(3217); + collapsed_macro!(3218); + collapsed_macro!(3219); + collapsed_macro!(3220); + collapsed_macro!(3221); + collapsed_macro!(3222); + collapsed_macro!(3223); + collapsed_macro!(3224); + collapsed_macro!(3225); + collapsed_macro!(3226); + collapsed_macro!(3227); + collapsed_macro!(3228); + collapsed_macro!(3229); + collapsed_macro!(3230); + collapsed_macro!(3231); + collapsed_macro!(3232); + collapsed_macro!(3233); + collapsed_macro!(3234); + collapsed_macro!(3235); + collapsed_macro!(3236); + collapsed_macro!(3237); + collapsed_macro!(3238); + collapsed_macro!(3239); + collapsed_macro!(3240); + collapsed_macro!(3241); + collapsed_macro!(3242); + collapsed_macro!(3243); + collapsed_macro!(3244); + collapsed_macro!(3245); + collapsed_macro!(3246); + collapsed_macro!(3247); + collapsed_macro!(3248); + collapsed_macro!(3249); + collapsed_macro!(3250); + collapsed_macro!(3251); + collapsed_macro!(3252); + collapsed_macro!(3253); + collapsed_macro!(3254); + collapsed_macro!(3255); + collapsed_macro!(3256); + collapsed_macro!(3257); + collapsed_macro!(3258); + collapsed_macro!(3259); + collapsed_macro!(3260); + collapsed_macro!(3261); + collapsed_macro!(3262); + collapsed_macro!(3263); + collapsed_macro!(3264); + collapsed_macro!(3265); + collapsed_macro!(3266); + collapsed_macro!(3267); + collapsed_macro!(3268); + collapsed_macro!(3269); + collapsed_macro!(3270); + collapsed_macro!(3271); + collapsed_macro!(3272); + collapsed_macro!(3273); + collapsed_macro!(3274); + collapsed_macro!(3275); + collapsed_macro!(3276); + collapsed_macro!(3277); + collapsed_macro!(3278); + collapsed_macro!(3279); + collapsed_macro!(3280); + collapsed_macro!(3281); + collapsed_macro!(3282); + collapsed_macro!(3283); + collapsed_macro!(3284); + collapsed_macro!(3285); + collapsed_macro!(3286); + collapsed_macro!(3287); + collapsed_macro!(3288); + collapsed_macro!(3289); + collapsed_macro!(3290); + collapsed_macro!(3291); + collapsed_macro!(3292); + collapsed_macro!(3293); + collapsed_macro!(3294); + collapsed_macro!(3295); + collapsed_macro!(3296); + collapsed_macro!(3297); + collapsed_macro!(3298); + collapsed_macro!(3299); + collapsed_macro!(3300); + collapsed_macro!(3301); + collapsed_macro!(3302); + collapsed_macro!(3303); + collapsed_macro!(3304); + collapsed_macro!(3305); + collapsed_macro!(3306); + collapsed_macro!(3307); + collapsed_macro!(3308); + collapsed_macro!(3309); + collapsed_macro!(3310); + collapsed_macro!(3311); + collapsed_macro!(3312); + collapsed_macro!(3313); + collapsed_macro!(3314); + collapsed_macro!(3315); + collapsed_macro!(3316); + collapsed_macro!(3317); + collapsed_macro!(3318); + collapsed_macro!(3319); + collapsed_macro!(3320); + collapsed_macro!(3321); + collapsed_macro!(3322); + collapsed_macro!(3323); + collapsed_macro!(3324); + collapsed_macro!(3325); + collapsed_macro!(3326); + collapsed_macro!(3327); + collapsed_macro!(3328); + collapsed_macro!(3329); + collapsed_macro!(3330); + collapsed_macro!(3331); + collapsed_macro!(3332); + collapsed_macro!(3333); + collapsed_macro!(3334); + collapsed_macro!(3335); + collapsed_macro!(3336); + collapsed_macro!(3337); + collapsed_macro!(3338); + collapsed_macro!(3339); + collapsed_macro!(3340); + collapsed_macro!(3341); + collapsed_macro!(3342); + collapsed_macro!(3343); + collapsed_macro!(3344); + collapsed_macro!(3345); + collapsed_macro!(3346); + collapsed_macro!(3347); + collapsed_macro!(3348); + collapsed_macro!(3349); + collapsed_macro!(3350); + collapsed_macro!(3351); + collapsed_macro!(3352); + collapsed_macro!(3353); + collapsed_macro!(3354); + collapsed_macro!(3355); + collapsed_macro!(3356); + collapsed_macro!(3357); + collapsed_macro!(3358); + collapsed_macro!(3359); + collapsed_macro!(3360); + collapsed_macro!(3361); + collapsed_macro!(3362); + collapsed_macro!(3363); + collapsed_macro!(3364); + collapsed_macro!(3365); + collapsed_macro!(3366); + collapsed_macro!(3367); + collapsed_macro!(3368); + collapsed_macro!(3369); + collapsed_macro!(3370); + collapsed_macro!(3371); + collapsed_macro!(3372); + collapsed_macro!(3373); + collapsed_macro!(3374); + collapsed_macro!(3375); + collapsed_macro!(3376); + collapsed_macro!(3377); + collapsed_macro!(3378); + collapsed_macro!(3379); + collapsed_macro!(3380); + collapsed_macro!(3381); + collapsed_macro!(3382); + collapsed_macro!(3383); + collapsed_macro!(3384); + collapsed_macro!(3385); + collapsed_macro!(3386); + collapsed_macro!(3387); + collapsed_macro!(3388); + collapsed_macro!(3389); + collapsed_macro!(3390); + collapsed_macro!(3391); + collapsed_macro!(3392); + collapsed_macro!(3393); + collapsed_macro!(3394); + collapsed_macro!(3395); + collapsed_macro!(3396); + collapsed_macro!(3397); + collapsed_macro!(3398); + collapsed_macro!(3399); + collapsed_macro!(3400); + collapsed_macro!(3401); + collapsed_macro!(3402); + collapsed_macro!(3403); + collapsed_macro!(3404); + collapsed_macro!(3405); + collapsed_macro!(3406); + collapsed_macro!(3407); + collapsed_macro!(3408); + collapsed_macro!(3409); + collapsed_macro!(3410); + collapsed_macro!(3411); + collapsed_macro!(3412); + collapsed_macro!(3413); + collapsed_macro!(3414); + collapsed_macro!(3415); + collapsed_macro!(3416); + collapsed_macro!(3417); + collapsed_macro!(3418); + collapsed_macro!(3419); + collapsed_macro!(3420); + collapsed_macro!(3421); + collapsed_macro!(3422); + collapsed_macro!(3423); + collapsed_macro!(3424); + collapsed_macro!(3425); + collapsed_macro!(3426); + collapsed_macro!(3427); + collapsed_macro!(3428); + collapsed_macro!(3429); + collapsed_macro!(3430); + collapsed_macro!(3431); + collapsed_macro!(3432); + collapsed_macro!(3433); + collapsed_macro!(3434); + collapsed_macro!(3435); + collapsed_macro!(3436); + collapsed_macro!(3437); + collapsed_macro!(3438); + collapsed_macro!(3439); + collapsed_macro!(3440); + collapsed_macro!(3441); + collapsed_macro!(3442); + collapsed_macro!(3443); + collapsed_macro!(3444); + collapsed_macro!(3445); + collapsed_macro!(3446); + collapsed_macro!(3447); + collapsed_macro!(3448); + collapsed_macro!(3449); + collapsed_macro!(3450); + collapsed_macro!(3451); + collapsed_macro!(3452); + collapsed_macro!(3453); + collapsed_macro!(3454); + collapsed_macro!(3455); + collapsed_macro!(3456); + collapsed_macro!(3457); + collapsed_macro!(3458); + collapsed_macro!(3459); + collapsed_macro!(3460); + collapsed_macro!(3461); + collapsed_macro!(3462); + collapsed_macro!(3463); + collapsed_macro!(3464); + collapsed_macro!(3465); + collapsed_macro!(3466); + collapsed_macro!(3467); + collapsed_macro!(3468); + collapsed_macro!(3469); + collapsed_macro!(3470); + collapsed_macro!(3471); + collapsed_macro!(3472); + collapsed_macro!(3473); + collapsed_macro!(3474); + collapsed_macro!(3475); + collapsed_macro!(3476); + collapsed_macro!(3477); + collapsed_macro!(3478); + collapsed_macro!(3479); + collapsed_macro!(3480); + collapsed_macro!(3481); + collapsed_macro!(3482); + collapsed_macro!(3483); + collapsed_macro!(3484); + collapsed_macro!(3485); + collapsed_macro!(3486); + collapsed_macro!(3487); + collapsed_macro!(3488); + collapsed_macro!(3489); + collapsed_macro!(3490); + collapsed_macro!(3491); + collapsed_macro!(3492); + collapsed_macro!(3493); + collapsed_macro!(3494); + collapsed_macro!(3495); + collapsed_macro!(3496); + collapsed_macro!(3497); + collapsed_macro!(3498); + collapsed_macro!(3499); + collapsed_macro!(3500); + collapsed_macro!(3501); + collapsed_macro!(3502); + collapsed_macro!(3503); + collapsed_macro!(3504); + collapsed_macro!(3505); + collapsed_macro!(3506); + collapsed_macro!(3507); + collapsed_macro!(3508); + collapsed_macro!(3509); + collapsed_macro!(3510); + collapsed_macro!(3511); + collapsed_macro!(3512); + collapsed_macro!(3513); + collapsed_macro!(3514); + collapsed_macro!(3515); + collapsed_macro!(3516); + collapsed_macro!(3517); + collapsed_macro!(3518); + collapsed_macro!(3519); + collapsed_macro!(3520); + collapsed_macro!(3521); + collapsed_macro!(3522); + collapsed_macro!(3523); + collapsed_macro!(3524); + collapsed_macro!(3525); + collapsed_macro!(3526); + collapsed_macro!(3527); + collapsed_macro!(3528); + collapsed_macro!(3529); + collapsed_macro!(3530); + collapsed_macro!(3531); + collapsed_macro!(3532); + collapsed_macro!(3533); + collapsed_macro!(3534); + collapsed_macro!(3535); + collapsed_macro!(3536); + collapsed_macro!(3537); + collapsed_macro!(3538); + collapsed_macro!(3539); + collapsed_macro!(3540); + collapsed_macro!(3541); + collapsed_macro!(3542); + collapsed_macro!(3543); + collapsed_macro!(3544); + collapsed_macro!(3545); + collapsed_macro!(3546); + collapsed_macro!(3547); + collapsed_macro!(3548); + collapsed_macro!(3549); + collapsed_macro!(3550); + collapsed_macro!(3551); + collapsed_macro!(3552); + collapsed_macro!(3553); + collapsed_macro!(3554); + collapsed_macro!(3555); + collapsed_macro!(3556); + collapsed_macro!(3557); + collapsed_macro!(3558); + collapsed_macro!(3559); + collapsed_macro!(3560); + collapsed_macro!(3561); + collapsed_macro!(3562); + collapsed_macro!(3563); + collapsed_macro!(3564); + collapsed_macro!(3565); + collapsed_macro!(3566); + collapsed_macro!(3567); + collapsed_macro!(3568); + collapsed_macro!(3569); + collapsed_macro!(3570); + collapsed_macro!(3571); + collapsed_macro!(3572); + collapsed_macro!(3573); + collapsed_macro!(3574); + collapsed_macro!(3575); + collapsed_macro!(3576); + collapsed_macro!(3577); + collapsed_macro!(3578); + collapsed_macro!(3579); + collapsed_macro!(3580); + collapsed_macro!(3581); + collapsed_macro!(3582); + collapsed_macro!(3583); + collapsed_macro!(3584); + collapsed_macro!(3585); + collapsed_macro!(3586); + collapsed_macro!(3587); + collapsed_macro!(3588); + collapsed_macro!(3589); + collapsed_macro!(3590); + collapsed_macro!(3591); + collapsed_macro!(3592); + collapsed_macro!(3593); + collapsed_macro!(3594); + collapsed_macro!(3595); + collapsed_macro!(3596); + collapsed_macro!(3597); + collapsed_macro!(3598); + collapsed_macro!(3599); + collapsed_macro!(3600); + collapsed_macro!(3601); + collapsed_macro!(3602); + collapsed_macro!(3603); + collapsed_macro!(3604); + collapsed_macro!(3605); + collapsed_macro!(3606); + collapsed_macro!(3607); + collapsed_macro!(3608); + collapsed_macro!(3609); + collapsed_macro!(3610); + collapsed_macro!(3611); + collapsed_macro!(3612); + collapsed_macro!(3613); + collapsed_macro!(3614); + collapsed_macro!(3615); + collapsed_macro!(3616); + collapsed_macro!(3617); + collapsed_macro!(3618); + collapsed_macro!(3619); + collapsed_macro!(3620); + collapsed_macro!(3621); + collapsed_macro!(3622); + collapsed_macro!(3623); + collapsed_macro!(3624); + collapsed_macro!(3625); + collapsed_macro!(3626); + collapsed_macro!(3627); + collapsed_macro!(3628); + collapsed_macro!(3629); + collapsed_macro!(3630); + collapsed_macro!(3631); + collapsed_macro!(3632); + collapsed_macro!(3633); + collapsed_macro!(3634); + collapsed_macro!(3635); + collapsed_macro!(3636); + collapsed_macro!(3637); + collapsed_macro!(3638); + collapsed_macro!(3639); + collapsed_macro!(3640); + collapsed_macro!(3641); + collapsed_macro!(3642); + collapsed_macro!(3643); + collapsed_macro!(3644); + collapsed_macro!(3645); + collapsed_macro!(3646); + collapsed_macro!(3647); + collapsed_macro!(3648); + collapsed_macro!(3649); + collapsed_macro!(3650); + collapsed_macro!(3651); + collapsed_macro!(3652); + collapsed_macro!(3653); + collapsed_macro!(3654); + collapsed_macro!(3655); + collapsed_macro!(3656); + collapsed_macro!(3657); + collapsed_macro!(3658); + collapsed_macro!(3659); + collapsed_macro!(3660); + collapsed_macro!(3661); + collapsed_macro!(3662); + collapsed_macro!(3663); + collapsed_macro!(3664); + collapsed_macro!(3665); + collapsed_macro!(3666); + collapsed_macro!(3667); + collapsed_macro!(3668); + collapsed_macro!(3669); + collapsed_macro!(3670); + collapsed_macro!(3671); + collapsed_macro!(3672); + collapsed_macro!(3673); + collapsed_macro!(3674); + collapsed_macro!(3675); + collapsed_macro!(3676); + collapsed_macro!(3677); + collapsed_macro!(3678); + collapsed_macro!(3679); + collapsed_macro!(3680); + collapsed_macro!(3681); + collapsed_macro!(3682); + collapsed_macro!(3683); + collapsed_macro!(3684); + collapsed_macro!(3685); + collapsed_macro!(3686); + collapsed_macro!(3687); + collapsed_macro!(3688); + collapsed_macro!(3689); + collapsed_macro!(3690); + collapsed_macro!(3691); + collapsed_macro!(3692); + collapsed_macro!(3693); + collapsed_macro!(3694); + collapsed_macro!(3695); + collapsed_macro!(3696); + collapsed_macro!(3697); + collapsed_macro!(3698); + collapsed_macro!(3699); + collapsed_macro!(3700); + collapsed_macro!(3701); + collapsed_macro!(3702); + collapsed_macro!(3703); + collapsed_macro!(3704); + collapsed_macro!(3705); + collapsed_macro!(3706); + collapsed_macro!(3707); + collapsed_macro!(3708); + collapsed_macro!(3709); + collapsed_macro!(3710); + collapsed_macro!(3711); + collapsed_macro!(3712); + collapsed_macro!(3713); + collapsed_macro!(3714); + collapsed_macro!(3715); + collapsed_macro!(3716); + collapsed_macro!(3717); + collapsed_macro!(3718); + collapsed_macro!(3719); + collapsed_macro!(3720); + collapsed_macro!(3721); + collapsed_macro!(3722); + collapsed_macro!(3723); + collapsed_macro!(3724); + collapsed_macro!(3725); + collapsed_macro!(3726); + collapsed_macro!(3727); + collapsed_macro!(3728); + collapsed_macro!(3729); + collapsed_macro!(3730); + collapsed_macro!(3731); + collapsed_macro!(3732); + collapsed_macro!(3733); + collapsed_macro!(3734); + collapsed_macro!(3735); + collapsed_macro!(3736); + collapsed_macro!(3737); + collapsed_macro!(3738); + collapsed_macro!(3739); + collapsed_macro!(3740); + collapsed_macro!(3741); + collapsed_macro!(3742); + collapsed_macro!(3743); + collapsed_macro!(3744); + collapsed_macro!(3745); + collapsed_macro!(3746); + collapsed_macro!(3747); + collapsed_macro!(3748); + collapsed_macro!(3749); + collapsed_macro!(3750); + collapsed_macro!(3751); + collapsed_macro!(3752); + collapsed_macro!(3753); + collapsed_macro!(3754); + collapsed_macro!(3755); + collapsed_macro!(3756); + collapsed_macro!(3757); + collapsed_macro!(3758); + collapsed_macro!(3759); + collapsed_macro!(3760); + collapsed_macro!(3761); + collapsed_macro!(3762); + collapsed_macro!(3763); + collapsed_macro!(3764); + collapsed_macro!(3765); + collapsed_macro!(3766); + collapsed_macro!(3767); + collapsed_macro!(3768); + collapsed_macro!(3769); + collapsed_macro!(3770); + collapsed_macro!(3771); + collapsed_macro!(3772); + collapsed_macro!(3773); + collapsed_macro!(3774); + collapsed_macro!(3775); + collapsed_macro!(3776); + collapsed_macro!(3777); + collapsed_macro!(3778); + collapsed_macro!(3779); + collapsed_macro!(3780); + collapsed_macro!(3781); + collapsed_macro!(3782); + collapsed_macro!(3783); + collapsed_macro!(3784); + collapsed_macro!(3785); + collapsed_macro!(3786); + collapsed_macro!(3787); + collapsed_macro!(3788); + collapsed_macro!(3789); + collapsed_macro!(3790); + collapsed_macro!(3791); + collapsed_macro!(3792); + collapsed_macro!(3793); + collapsed_macro!(3794); + collapsed_macro!(3795); + collapsed_macro!(3796); + collapsed_macro!(3797); + collapsed_macro!(3798); + collapsed_macro!(3799); + collapsed_macro!(3800); + collapsed_macro!(3801); + collapsed_macro!(3802); + collapsed_macro!(3803); + collapsed_macro!(3804); + collapsed_macro!(3805); + collapsed_macro!(3806); + collapsed_macro!(3807); + collapsed_macro!(3808); + collapsed_macro!(3809); + collapsed_macro!(3810); + collapsed_macro!(3811); + collapsed_macro!(3812); + collapsed_macro!(3813); + collapsed_macro!(3814); + collapsed_macro!(3815); + collapsed_macro!(3816); + collapsed_macro!(3817); + collapsed_macro!(3818); + collapsed_macro!(3819); + collapsed_macro!(3820); + collapsed_macro!(3821); + collapsed_macro!(3822); + collapsed_macro!(3823); + collapsed_macro!(3824); + collapsed_macro!(3825); + collapsed_macro!(3826); + collapsed_macro!(3827); + collapsed_macro!(3828); + collapsed_macro!(3829); + collapsed_macro!(3830); + collapsed_macro!(3831); + collapsed_macro!(3832); + collapsed_macro!(3833); + collapsed_macro!(3834); + collapsed_macro!(3835); + collapsed_macro!(3836); + collapsed_macro!(3837); + collapsed_macro!(3838); + collapsed_macro!(3839); + collapsed_macro!(3840); + collapsed_macro!(3841); + collapsed_macro!(3842); + collapsed_macro!(3843); + collapsed_macro!(3844); + collapsed_macro!(3845); + collapsed_macro!(3846); + collapsed_macro!(3847); + collapsed_macro!(3848); + collapsed_macro!(3849); + collapsed_macro!(3850); + collapsed_macro!(3851); + collapsed_macro!(3852); + collapsed_macro!(3853); + collapsed_macro!(3854); + collapsed_macro!(3855); + collapsed_macro!(3856); + collapsed_macro!(3857); + collapsed_macro!(3858); + collapsed_macro!(3859); + collapsed_macro!(3860); + collapsed_macro!(3861); + collapsed_macro!(3862); + collapsed_macro!(3863); + collapsed_macro!(3864); + collapsed_macro!(3865); + collapsed_macro!(3866); + collapsed_macro!(3867); + collapsed_macro!(3868); + collapsed_macro!(3869); + collapsed_macro!(3870); + collapsed_macro!(3871); + collapsed_macro!(3872); + collapsed_macro!(3873); + collapsed_macro!(3874); + collapsed_macro!(3875); + collapsed_macro!(3876); + collapsed_macro!(3877); + collapsed_macro!(3878); + collapsed_macro!(3879); + collapsed_macro!(3880); + collapsed_macro!(3881); + collapsed_macro!(3882); + collapsed_macro!(3883); + collapsed_macro!(3884); + collapsed_macro!(3885); + collapsed_macro!(3886); + collapsed_macro!(3887); + collapsed_macro!(3888); + collapsed_macro!(3889); + collapsed_macro!(3890); + collapsed_macro!(3891); + collapsed_macro!(3892); + collapsed_macro!(3893); + collapsed_macro!(3894); + collapsed_macro!(3895); + collapsed_macro!(3896); + collapsed_macro!(3897); + collapsed_macro!(3898); + collapsed_macro!(3899); + collapsed_macro!(3900); + collapsed_macro!(3901); + collapsed_macro!(3902); + collapsed_macro!(3903); + collapsed_macro!(3904); + collapsed_macro!(3905); + collapsed_macro!(3906); + collapsed_macro!(3907); + collapsed_macro!(3908); + collapsed_macro!(3909); + collapsed_macro!(3910); + collapsed_macro!(3911); + collapsed_macro!(3912); + collapsed_macro!(3913); + collapsed_macro!(3914); + collapsed_macro!(3915); + collapsed_macro!(3916); + collapsed_macro!(3917); + collapsed_macro!(3918); + collapsed_macro!(3919); + collapsed_macro!(3920); + collapsed_macro!(3921); + collapsed_macro!(3922); + collapsed_macro!(3923); + collapsed_macro!(3924); + collapsed_macro!(3925); + collapsed_macro!(3926); + collapsed_macro!(3927); + collapsed_macro!(3928); + collapsed_macro!(3929); + collapsed_macro!(3930); + collapsed_macro!(3931); + collapsed_macro!(3932); + collapsed_macro!(3933); + collapsed_macro!(3934); + collapsed_macro!(3935); + collapsed_macro!(3936); + collapsed_macro!(3937); + collapsed_macro!(3938); + collapsed_macro!(3939); + collapsed_macro!(3940); + collapsed_macro!(3941); + collapsed_macro!(3942); + collapsed_macro!(3943); + collapsed_macro!(3944); + collapsed_macro!(3945); + collapsed_macro!(3946); + collapsed_macro!(3947); + collapsed_macro!(3948); + collapsed_macro!(3949); + collapsed_macro!(3950); + collapsed_macro!(3951); + collapsed_macro!(3952); + collapsed_macro!(3953); + collapsed_macro!(3954); + collapsed_macro!(3955); + collapsed_macro!(3956); + collapsed_macro!(3957); + collapsed_macro!(3958); + collapsed_macro!(3959); + collapsed_macro!(3960); + collapsed_macro!(3961); + collapsed_macro!(3962); + collapsed_macro!(3963); + collapsed_macro!(3964); + collapsed_macro!(3965); + collapsed_macro!(3966); + collapsed_macro!(3967); + collapsed_macro!(3968); + collapsed_macro!(3969); + collapsed_macro!(3970); + collapsed_macro!(3971); + collapsed_macro!(3972); + collapsed_macro!(3973); + collapsed_macro!(3974); + collapsed_macro!(3975); + collapsed_macro!(3976); + collapsed_macro!(3977); + collapsed_macro!(3978); + collapsed_macro!(3979); + collapsed_macro!(3980); + collapsed_macro!(3981); + collapsed_macro!(3982); + collapsed_macro!(3983); + collapsed_macro!(3984); + collapsed_macro!(3985); + collapsed_macro!(3986); + collapsed_macro!(3987); + collapsed_macro!(3988); + collapsed_macro!(3989); + collapsed_macro!(3990); + collapsed_macro!(3991); + collapsed_macro!(3992); + collapsed_macro!(3993); + collapsed_macro!(3994); + collapsed_macro!(3995); + collapsed_macro!(3996); + collapsed_macro!(3997); + collapsed_macro!(3998); + collapsed_macro!(3999); + collapsed_macro!(4000); + collapsed_macro!(4001); + collapsed_macro!(4002); + collapsed_macro!(4003); + collapsed_macro!(4004); + collapsed_macro!(4005); + collapsed_macro!(4006); + collapsed_macro!(4007); + collapsed_macro!(4008); + collapsed_macro!(4009); + collapsed_macro!(4010); + collapsed_macro!(4011); + collapsed_macro!(4012); + collapsed_macro!(4013); + collapsed_macro!(4014); + collapsed_macro!(4015); + collapsed_macro!(4016); + collapsed_macro!(4017); + collapsed_macro!(4018); + collapsed_macro!(4019); + collapsed_macro!(4020); + collapsed_macro!(4021); + collapsed_macro!(4022); + collapsed_macro!(4023); + collapsed_macro!(4024); + collapsed_macro!(4025); + collapsed_macro!(4026); + collapsed_macro!(4027); + collapsed_macro!(4028); + collapsed_macro!(4029); + collapsed_macro!(4030); + collapsed_macro!(4031); + collapsed_macro!(4032); + collapsed_macro!(4033); + collapsed_macro!(4034); + collapsed_macro!(4035); + collapsed_macro!(4036); + collapsed_macro!(4037); + collapsed_macro!(4038); + collapsed_macro!(4039); + collapsed_macro!(4040); + collapsed_macro!(4041); + collapsed_macro!(4042); + collapsed_macro!(4043); + collapsed_macro!(4044); + collapsed_macro!(4045); + collapsed_macro!(4046); + collapsed_macro!(4047); + collapsed_macro!(4048); + collapsed_macro!(4049); + collapsed_macro!(4050); + collapsed_macro!(4051); + collapsed_macro!(4052); + collapsed_macro!(4053); + collapsed_macro!(4054); + collapsed_macro!(4055); + collapsed_macro!(4056); + collapsed_macro!(4057); + collapsed_macro!(4058); + collapsed_macro!(4059); + collapsed_macro!(4060); + collapsed_macro!(4061); + collapsed_macro!(4062); + collapsed_macro!(4063); + collapsed_macro!(4064); + collapsed_macro!(4065); + collapsed_macro!(4066); + collapsed_macro!(4067); + collapsed_macro!(4068); + collapsed_macro!(4069); + collapsed_macro!(4070); + collapsed_macro!(4071); + collapsed_macro!(4072); + collapsed_macro!(4073); + collapsed_macro!(4074); + collapsed_macro!(4075); + collapsed_macro!(4076); + collapsed_macro!(4077); + collapsed_macro!(4078); + collapsed_macro!(4079); + collapsed_macro!(4080); + collapsed_macro!(4081); + collapsed_macro!(4082); + collapsed_macro!(4083); + collapsed_macro!(4084); + collapsed_macro!(4085); + collapsed_macro!(4086); + collapsed_macro!(4087); + collapsed_macro!(4088); + collapsed_macro!(4089); + collapsed_macro!(4090); + collapsed_macro!(4091); + collapsed_macro!(4092); + collapsed_macro!(4093); + collapsed_macro!(4094); + collapsed_macro!(4095); + collapsed_macro!(4096); + collapsed_macro!(4097); +} + +fn main() { + collapsed_debuginfo(); +} diff --git a/tests/ui/debuginfo/debuginfo-inline-callsite-location-macro-2.rs b/tests/ui/debuginfo/debuginfo-inline-callsite-location-macro-2.rs new file mode 100644 index 00000000000..3696ed37a20 --- /dev/null +++ b/tests/ui/debuginfo/debuginfo-inline-callsite-location-macro-2.rs @@ -0,0 +1,4122 @@ +//@ check-pass +//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Zmir-enable-passes=+Inline +//@ ignore-msvc +// ignore-tidy-filelength + +#[derive(Default)] +struct Something {} + +macro_rules! simple_macro { + ($code:expr) => { + // Important to use a function here, so it can be inlined + // at the MIR stage. + Something::default() + } +} + +fn uncollapsed_debuginfo() { + // LLVM allows 12 bits for encoding discriminators, so 4096+1 calls to a + // MIR-inlined function will exhaust it. At that point we will start + // dropping debug info (and tracing::warn!). + simple_macro!(1); + simple_macro!(2); + simple_macro!(3); + simple_macro!(4); + simple_macro!(5); + simple_macro!(6); + simple_macro!(7); + simple_macro!(8); + simple_macro!(9); + simple_macro!(10); + simple_macro!(11); + simple_macro!(12); + simple_macro!(13); + simple_macro!(14); + simple_macro!(15); + simple_macro!(16); + simple_macro!(17); + simple_macro!(18); + simple_macro!(19); + simple_macro!(20); + simple_macro!(21); + simple_macro!(22); + simple_macro!(23); + simple_macro!(24); + simple_macro!(25); + simple_macro!(26); + simple_macro!(27); + simple_macro!(28); + simple_macro!(29); + simple_macro!(30); + simple_macro!(31); + simple_macro!(32); + simple_macro!(33); + simple_macro!(34); + simple_macro!(35); + simple_macro!(36); + simple_macro!(37); + simple_macro!(38); + simple_macro!(39); + simple_macro!(40); + simple_macro!(41); + simple_macro!(42); + simple_macro!(43); + simple_macro!(44); + simple_macro!(45); + simple_macro!(46); + simple_macro!(47); + simple_macro!(48); + simple_macro!(49); + simple_macro!(50); + simple_macro!(51); + simple_macro!(52); + simple_macro!(53); + simple_macro!(54); + simple_macro!(55); + simple_macro!(56); + simple_macro!(57); + simple_macro!(58); + simple_macro!(59); + simple_macro!(60); + simple_macro!(61); + simple_macro!(62); + simple_macro!(63); + simple_macro!(64); + simple_macro!(65); + simple_macro!(66); + simple_macro!(67); + simple_macro!(68); + simple_macro!(69); + simple_macro!(70); + simple_macro!(71); + simple_macro!(72); + simple_macro!(73); + simple_macro!(74); + simple_macro!(75); + simple_macro!(76); + simple_macro!(77); + simple_macro!(78); + simple_macro!(79); + simple_macro!(80); + simple_macro!(81); + simple_macro!(82); + simple_macro!(83); + simple_macro!(84); + simple_macro!(85); + simple_macro!(86); + simple_macro!(87); + simple_macro!(88); + simple_macro!(89); + simple_macro!(90); + simple_macro!(91); + simple_macro!(92); + simple_macro!(93); + simple_macro!(94); + simple_macro!(95); + simple_macro!(96); + simple_macro!(97); + simple_macro!(98); + simple_macro!(99); + simple_macro!(100); + simple_macro!(101); + simple_macro!(102); + simple_macro!(103); + simple_macro!(104); + simple_macro!(105); + simple_macro!(106); + simple_macro!(107); + simple_macro!(108); + simple_macro!(109); + simple_macro!(110); + simple_macro!(111); + simple_macro!(112); + simple_macro!(113); + simple_macro!(114); + simple_macro!(115); + simple_macro!(116); + simple_macro!(117); + simple_macro!(118); + simple_macro!(119); + simple_macro!(120); + simple_macro!(121); + simple_macro!(122); + simple_macro!(123); + simple_macro!(124); + simple_macro!(125); + simple_macro!(126); + simple_macro!(127); + simple_macro!(128); + simple_macro!(129); + simple_macro!(130); + simple_macro!(131); + simple_macro!(132); + simple_macro!(133); + simple_macro!(134); + simple_macro!(135); + simple_macro!(136); + simple_macro!(137); + simple_macro!(138); + simple_macro!(139); + simple_macro!(140); + simple_macro!(141); + simple_macro!(142); + simple_macro!(143); + simple_macro!(144); + simple_macro!(145); + simple_macro!(146); + simple_macro!(147); + simple_macro!(148); + simple_macro!(149); + simple_macro!(150); + simple_macro!(151); + simple_macro!(152); + simple_macro!(153); + simple_macro!(154); + simple_macro!(155); + simple_macro!(156); + simple_macro!(157); + simple_macro!(158); + simple_macro!(159); + simple_macro!(160); + simple_macro!(161); + simple_macro!(162); + simple_macro!(163); + simple_macro!(164); + simple_macro!(165); + simple_macro!(166); + simple_macro!(167); + simple_macro!(168); + simple_macro!(169); + simple_macro!(170); + simple_macro!(171); + simple_macro!(172); + simple_macro!(173); + simple_macro!(174); + simple_macro!(175); + simple_macro!(176); + simple_macro!(177); + simple_macro!(178); + simple_macro!(179); + simple_macro!(180); + simple_macro!(181); + simple_macro!(182); + simple_macro!(183); + simple_macro!(184); + simple_macro!(185); + simple_macro!(186); + simple_macro!(187); + simple_macro!(188); + simple_macro!(189); + simple_macro!(190); + simple_macro!(191); + simple_macro!(192); + simple_macro!(193); + simple_macro!(194); + simple_macro!(195); + simple_macro!(196); + simple_macro!(197); + simple_macro!(198); + simple_macro!(199); + simple_macro!(200); + simple_macro!(201); + simple_macro!(202); + simple_macro!(203); + simple_macro!(204); + simple_macro!(205); + simple_macro!(206); + simple_macro!(207); + simple_macro!(208); + simple_macro!(209); + simple_macro!(210); + simple_macro!(211); + simple_macro!(212); + simple_macro!(213); + simple_macro!(214); + simple_macro!(215); + simple_macro!(216); + simple_macro!(217); + simple_macro!(218); + simple_macro!(219); + simple_macro!(220); + simple_macro!(221); + simple_macro!(222); + simple_macro!(223); + simple_macro!(224); + simple_macro!(225); + simple_macro!(226); + simple_macro!(227); + simple_macro!(228); + simple_macro!(229); + simple_macro!(230); + simple_macro!(231); + simple_macro!(232); + simple_macro!(233); + simple_macro!(234); + simple_macro!(235); + simple_macro!(236); + simple_macro!(237); + simple_macro!(238); + simple_macro!(239); + simple_macro!(240); + simple_macro!(241); + simple_macro!(242); + simple_macro!(243); + simple_macro!(244); + simple_macro!(245); + simple_macro!(246); + simple_macro!(247); + simple_macro!(248); + simple_macro!(249); + simple_macro!(250); + simple_macro!(251); + simple_macro!(252); + simple_macro!(253); + simple_macro!(254); + simple_macro!(255); + simple_macro!(256); + simple_macro!(257); + simple_macro!(258); + simple_macro!(259); + simple_macro!(260); + simple_macro!(261); + simple_macro!(262); + simple_macro!(263); + simple_macro!(264); + simple_macro!(265); + simple_macro!(266); + simple_macro!(267); + simple_macro!(268); + simple_macro!(269); + simple_macro!(270); + simple_macro!(271); + simple_macro!(272); + simple_macro!(273); + simple_macro!(274); + simple_macro!(275); + simple_macro!(276); + simple_macro!(277); + simple_macro!(278); + simple_macro!(279); + simple_macro!(280); + simple_macro!(281); + simple_macro!(282); + simple_macro!(283); + simple_macro!(284); + simple_macro!(285); + simple_macro!(286); + simple_macro!(287); + simple_macro!(288); + simple_macro!(289); + simple_macro!(290); + simple_macro!(291); + simple_macro!(292); + simple_macro!(293); + simple_macro!(294); + simple_macro!(295); + simple_macro!(296); + simple_macro!(297); + simple_macro!(298); + simple_macro!(299); + simple_macro!(300); + simple_macro!(301); + simple_macro!(302); + simple_macro!(303); + simple_macro!(304); + simple_macro!(305); + simple_macro!(306); + simple_macro!(307); + simple_macro!(308); + simple_macro!(309); + simple_macro!(310); + simple_macro!(311); + simple_macro!(312); + simple_macro!(313); + simple_macro!(314); + simple_macro!(315); + simple_macro!(316); + simple_macro!(317); + simple_macro!(318); + simple_macro!(319); + simple_macro!(320); + simple_macro!(321); + simple_macro!(322); + simple_macro!(323); + simple_macro!(324); + simple_macro!(325); + simple_macro!(326); + simple_macro!(327); + simple_macro!(328); + simple_macro!(329); + simple_macro!(330); + simple_macro!(331); + simple_macro!(332); + simple_macro!(333); + simple_macro!(334); + simple_macro!(335); + simple_macro!(336); + simple_macro!(337); + simple_macro!(338); + simple_macro!(339); + simple_macro!(340); + simple_macro!(341); + simple_macro!(342); + simple_macro!(343); + simple_macro!(344); + simple_macro!(345); + simple_macro!(346); + simple_macro!(347); + simple_macro!(348); + simple_macro!(349); + simple_macro!(350); + simple_macro!(351); + simple_macro!(352); + simple_macro!(353); + simple_macro!(354); + simple_macro!(355); + simple_macro!(356); + simple_macro!(357); + simple_macro!(358); + simple_macro!(359); + simple_macro!(360); + simple_macro!(361); + simple_macro!(362); + simple_macro!(363); + simple_macro!(364); + simple_macro!(365); + simple_macro!(366); + simple_macro!(367); + simple_macro!(368); + simple_macro!(369); + simple_macro!(370); + simple_macro!(371); + simple_macro!(372); + simple_macro!(373); + simple_macro!(374); + simple_macro!(375); + simple_macro!(376); + simple_macro!(377); + simple_macro!(378); + simple_macro!(379); + simple_macro!(380); + simple_macro!(381); + simple_macro!(382); + simple_macro!(383); + simple_macro!(384); + simple_macro!(385); + simple_macro!(386); + simple_macro!(387); + simple_macro!(388); + simple_macro!(389); + simple_macro!(390); + simple_macro!(391); + simple_macro!(392); + simple_macro!(393); + simple_macro!(394); + simple_macro!(395); + simple_macro!(396); + simple_macro!(397); + simple_macro!(398); + simple_macro!(399); + simple_macro!(400); + simple_macro!(401); + simple_macro!(402); + simple_macro!(403); + simple_macro!(404); + simple_macro!(405); + simple_macro!(406); + simple_macro!(407); + simple_macro!(408); + simple_macro!(409); + simple_macro!(410); + simple_macro!(411); + simple_macro!(412); + simple_macro!(413); + simple_macro!(414); + simple_macro!(415); + simple_macro!(416); + simple_macro!(417); + simple_macro!(418); + simple_macro!(419); + simple_macro!(420); + simple_macro!(421); + simple_macro!(422); + simple_macro!(423); + simple_macro!(424); + simple_macro!(425); + simple_macro!(426); + simple_macro!(427); + simple_macro!(428); + simple_macro!(429); + simple_macro!(430); + simple_macro!(431); + simple_macro!(432); + simple_macro!(433); + simple_macro!(434); + simple_macro!(435); + simple_macro!(436); + simple_macro!(437); + simple_macro!(438); + simple_macro!(439); + simple_macro!(440); + simple_macro!(441); + simple_macro!(442); + simple_macro!(443); + simple_macro!(444); + simple_macro!(445); + simple_macro!(446); + simple_macro!(447); + simple_macro!(448); + simple_macro!(449); + simple_macro!(450); + simple_macro!(451); + simple_macro!(452); + simple_macro!(453); + simple_macro!(454); + simple_macro!(455); + simple_macro!(456); + simple_macro!(457); + simple_macro!(458); + simple_macro!(459); + simple_macro!(460); + simple_macro!(461); + simple_macro!(462); + simple_macro!(463); + simple_macro!(464); + simple_macro!(465); + simple_macro!(466); + simple_macro!(467); + simple_macro!(468); + simple_macro!(469); + simple_macro!(470); + simple_macro!(471); + simple_macro!(472); + simple_macro!(473); + simple_macro!(474); + simple_macro!(475); + simple_macro!(476); + simple_macro!(477); + simple_macro!(478); + simple_macro!(479); + simple_macro!(480); + simple_macro!(481); + simple_macro!(482); + simple_macro!(483); + simple_macro!(484); + simple_macro!(485); + simple_macro!(486); + simple_macro!(487); + simple_macro!(488); + simple_macro!(489); + simple_macro!(490); + simple_macro!(491); + simple_macro!(492); + simple_macro!(493); + simple_macro!(494); + simple_macro!(495); + simple_macro!(496); + simple_macro!(497); + simple_macro!(498); + simple_macro!(499); + simple_macro!(500); + simple_macro!(501); + simple_macro!(502); + simple_macro!(503); + simple_macro!(504); + simple_macro!(505); + simple_macro!(506); + simple_macro!(507); + simple_macro!(508); + simple_macro!(509); + simple_macro!(510); + simple_macro!(511); + simple_macro!(512); + simple_macro!(513); + simple_macro!(514); + simple_macro!(515); + simple_macro!(516); + simple_macro!(517); + simple_macro!(518); + simple_macro!(519); + simple_macro!(520); + simple_macro!(521); + simple_macro!(522); + simple_macro!(523); + simple_macro!(524); + simple_macro!(525); + simple_macro!(526); + simple_macro!(527); + simple_macro!(528); + simple_macro!(529); + simple_macro!(530); + simple_macro!(531); + simple_macro!(532); + simple_macro!(533); + simple_macro!(534); + simple_macro!(535); + simple_macro!(536); + simple_macro!(537); + simple_macro!(538); + simple_macro!(539); + simple_macro!(540); + simple_macro!(541); + simple_macro!(542); + simple_macro!(543); + simple_macro!(544); + simple_macro!(545); + simple_macro!(546); + simple_macro!(547); + simple_macro!(548); + simple_macro!(549); + simple_macro!(550); + simple_macro!(551); + simple_macro!(552); + simple_macro!(553); + simple_macro!(554); + simple_macro!(555); + simple_macro!(556); + simple_macro!(557); + simple_macro!(558); + simple_macro!(559); + simple_macro!(560); + simple_macro!(561); + simple_macro!(562); + simple_macro!(563); + simple_macro!(564); + simple_macro!(565); + simple_macro!(566); + simple_macro!(567); + simple_macro!(568); + simple_macro!(569); + simple_macro!(570); + simple_macro!(571); + simple_macro!(572); + simple_macro!(573); + simple_macro!(574); + simple_macro!(575); + simple_macro!(576); + simple_macro!(577); + simple_macro!(578); + simple_macro!(579); + simple_macro!(580); + simple_macro!(581); + simple_macro!(582); + simple_macro!(583); + simple_macro!(584); + simple_macro!(585); + simple_macro!(586); + simple_macro!(587); + simple_macro!(588); + simple_macro!(589); + simple_macro!(590); + simple_macro!(591); + simple_macro!(592); + simple_macro!(593); + simple_macro!(594); + simple_macro!(595); + simple_macro!(596); + simple_macro!(597); + simple_macro!(598); + simple_macro!(599); + simple_macro!(600); + simple_macro!(601); + simple_macro!(602); + simple_macro!(603); + simple_macro!(604); + simple_macro!(605); + simple_macro!(606); + simple_macro!(607); + simple_macro!(608); + simple_macro!(609); + simple_macro!(610); + simple_macro!(611); + simple_macro!(612); + simple_macro!(613); + simple_macro!(614); + simple_macro!(615); + simple_macro!(616); + simple_macro!(617); + simple_macro!(618); + simple_macro!(619); + simple_macro!(620); + simple_macro!(621); + simple_macro!(622); + simple_macro!(623); + simple_macro!(624); + simple_macro!(625); + simple_macro!(626); + simple_macro!(627); + simple_macro!(628); + simple_macro!(629); + simple_macro!(630); + simple_macro!(631); + simple_macro!(632); + simple_macro!(633); + simple_macro!(634); + simple_macro!(635); + simple_macro!(636); + simple_macro!(637); + simple_macro!(638); + simple_macro!(639); + simple_macro!(640); + simple_macro!(641); + simple_macro!(642); + simple_macro!(643); + simple_macro!(644); + simple_macro!(645); + simple_macro!(646); + simple_macro!(647); + simple_macro!(648); + simple_macro!(649); + simple_macro!(650); + simple_macro!(651); + simple_macro!(652); + simple_macro!(653); + simple_macro!(654); + simple_macro!(655); + simple_macro!(656); + simple_macro!(657); + simple_macro!(658); + simple_macro!(659); + simple_macro!(660); + simple_macro!(661); + simple_macro!(662); + simple_macro!(663); + simple_macro!(664); + simple_macro!(665); + simple_macro!(666); + simple_macro!(667); + simple_macro!(668); + simple_macro!(669); + simple_macro!(670); + simple_macro!(671); + simple_macro!(672); + simple_macro!(673); + simple_macro!(674); + simple_macro!(675); + simple_macro!(676); + simple_macro!(677); + simple_macro!(678); + simple_macro!(679); + simple_macro!(680); + simple_macro!(681); + simple_macro!(682); + simple_macro!(683); + simple_macro!(684); + simple_macro!(685); + simple_macro!(686); + simple_macro!(687); + simple_macro!(688); + simple_macro!(689); + simple_macro!(690); + simple_macro!(691); + simple_macro!(692); + simple_macro!(693); + simple_macro!(694); + simple_macro!(695); + simple_macro!(696); + simple_macro!(697); + simple_macro!(698); + simple_macro!(699); + simple_macro!(700); + simple_macro!(701); + simple_macro!(702); + simple_macro!(703); + simple_macro!(704); + simple_macro!(705); + simple_macro!(706); + simple_macro!(707); + simple_macro!(708); + simple_macro!(709); + simple_macro!(710); + simple_macro!(711); + simple_macro!(712); + simple_macro!(713); + simple_macro!(714); + simple_macro!(715); + simple_macro!(716); + simple_macro!(717); + simple_macro!(718); + simple_macro!(719); + simple_macro!(720); + simple_macro!(721); + simple_macro!(722); + simple_macro!(723); + simple_macro!(724); + simple_macro!(725); + simple_macro!(726); + simple_macro!(727); + simple_macro!(728); + simple_macro!(729); + simple_macro!(730); + simple_macro!(731); + simple_macro!(732); + simple_macro!(733); + simple_macro!(734); + simple_macro!(735); + simple_macro!(736); + simple_macro!(737); + simple_macro!(738); + simple_macro!(739); + simple_macro!(740); + simple_macro!(741); + simple_macro!(742); + simple_macro!(743); + simple_macro!(744); + simple_macro!(745); + simple_macro!(746); + simple_macro!(747); + simple_macro!(748); + simple_macro!(749); + simple_macro!(750); + simple_macro!(751); + simple_macro!(752); + simple_macro!(753); + simple_macro!(754); + simple_macro!(755); + simple_macro!(756); + simple_macro!(757); + simple_macro!(758); + simple_macro!(759); + simple_macro!(760); + simple_macro!(761); + simple_macro!(762); + simple_macro!(763); + simple_macro!(764); + simple_macro!(765); + simple_macro!(766); + simple_macro!(767); + simple_macro!(768); + simple_macro!(769); + simple_macro!(770); + simple_macro!(771); + simple_macro!(772); + simple_macro!(773); + simple_macro!(774); + simple_macro!(775); + simple_macro!(776); + simple_macro!(777); + simple_macro!(778); + simple_macro!(779); + simple_macro!(780); + simple_macro!(781); + simple_macro!(782); + simple_macro!(783); + simple_macro!(784); + simple_macro!(785); + simple_macro!(786); + simple_macro!(787); + simple_macro!(788); + simple_macro!(789); + simple_macro!(790); + simple_macro!(791); + simple_macro!(792); + simple_macro!(793); + simple_macro!(794); + simple_macro!(795); + simple_macro!(796); + simple_macro!(797); + simple_macro!(798); + simple_macro!(799); + simple_macro!(800); + simple_macro!(801); + simple_macro!(802); + simple_macro!(803); + simple_macro!(804); + simple_macro!(805); + simple_macro!(806); + simple_macro!(807); + simple_macro!(808); + simple_macro!(809); + simple_macro!(810); + simple_macro!(811); + simple_macro!(812); + simple_macro!(813); + simple_macro!(814); + simple_macro!(815); + simple_macro!(816); + simple_macro!(817); + simple_macro!(818); + simple_macro!(819); + simple_macro!(820); + simple_macro!(821); + simple_macro!(822); + simple_macro!(823); + simple_macro!(824); + simple_macro!(825); + simple_macro!(826); + simple_macro!(827); + simple_macro!(828); + simple_macro!(829); + simple_macro!(830); + simple_macro!(831); + simple_macro!(832); + simple_macro!(833); + simple_macro!(834); + simple_macro!(835); + simple_macro!(836); + simple_macro!(837); + simple_macro!(838); + simple_macro!(839); + simple_macro!(840); + simple_macro!(841); + simple_macro!(842); + simple_macro!(843); + simple_macro!(844); + simple_macro!(845); + simple_macro!(846); + simple_macro!(847); + simple_macro!(848); + simple_macro!(849); + simple_macro!(850); + simple_macro!(851); + simple_macro!(852); + simple_macro!(853); + simple_macro!(854); + simple_macro!(855); + simple_macro!(856); + simple_macro!(857); + simple_macro!(858); + simple_macro!(859); + simple_macro!(860); + simple_macro!(861); + simple_macro!(862); + simple_macro!(863); + simple_macro!(864); + simple_macro!(865); + simple_macro!(866); + simple_macro!(867); + simple_macro!(868); + simple_macro!(869); + simple_macro!(870); + simple_macro!(871); + simple_macro!(872); + simple_macro!(873); + simple_macro!(874); + simple_macro!(875); + simple_macro!(876); + simple_macro!(877); + simple_macro!(878); + simple_macro!(879); + simple_macro!(880); + simple_macro!(881); + simple_macro!(882); + simple_macro!(883); + simple_macro!(884); + simple_macro!(885); + simple_macro!(886); + simple_macro!(887); + simple_macro!(888); + simple_macro!(889); + simple_macro!(890); + simple_macro!(891); + simple_macro!(892); + simple_macro!(893); + simple_macro!(894); + simple_macro!(895); + simple_macro!(896); + simple_macro!(897); + simple_macro!(898); + simple_macro!(899); + simple_macro!(900); + simple_macro!(901); + simple_macro!(902); + simple_macro!(903); + simple_macro!(904); + simple_macro!(905); + simple_macro!(906); + simple_macro!(907); + simple_macro!(908); + simple_macro!(909); + simple_macro!(910); + simple_macro!(911); + simple_macro!(912); + simple_macro!(913); + simple_macro!(914); + simple_macro!(915); + simple_macro!(916); + simple_macro!(917); + simple_macro!(918); + simple_macro!(919); + simple_macro!(920); + simple_macro!(921); + simple_macro!(922); + simple_macro!(923); + simple_macro!(924); + simple_macro!(925); + simple_macro!(926); + simple_macro!(927); + simple_macro!(928); + simple_macro!(929); + simple_macro!(930); + simple_macro!(931); + simple_macro!(932); + simple_macro!(933); + simple_macro!(934); + simple_macro!(935); + simple_macro!(936); + simple_macro!(937); + simple_macro!(938); + simple_macro!(939); + simple_macro!(940); + simple_macro!(941); + simple_macro!(942); + simple_macro!(943); + simple_macro!(944); + simple_macro!(945); + simple_macro!(946); + simple_macro!(947); + simple_macro!(948); + simple_macro!(949); + simple_macro!(950); + simple_macro!(951); + simple_macro!(952); + simple_macro!(953); + simple_macro!(954); + simple_macro!(955); + simple_macro!(956); + simple_macro!(957); + simple_macro!(958); + simple_macro!(959); + simple_macro!(960); + simple_macro!(961); + simple_macro!(962); + simple_macro!(963); + simple_macro!(964); + simple_macro!(965); + simple_macro!(966); + simple_macro!(967); + simple_macro!(968); + simple_macro!(969); + simple_macro!(970); + simple_macro!(971); + simple_macro!(972); + simple_macro!(973); + simple_macro!(974); + simple_macro!(975); + simple_macro!(976); + simple_macro!(977); + simple_macro!(978); + simple_macro!(979); + simple_macro!(980); + simple_macro!(981); + simple_macro!(982); + simple_macro!(983); + simple_macro!(984); + simple_macro!(985); + simple_macro!(986); + simple_macro!(987); + simple_macro!(988); + simple_macro!(989); + simple_macro!(990); + simple_macro!(991); + simple_macro!(992); + simple_macro!(993); + simple_macro!(994); + simple_macro!(995); + simple_macro!(996); + simple_macro!(997); + simple_macro!(998); + simple_macro!(999); + simple_macro!(1000); + simple_macro!(1001); + simple_macro!(1002); + simple_macro!(1003); + simple_macro!(1004); + simple_macro!(1005); + simple_macro!(1006); + simple_macro!(1007); + simple_macro!(1008); + simple_macro!(1009); + simple_macro!(1010); + simple_macro!(1011); + simple_macro!(1012); + simple_macro!(1013); + simple_macro!(1014); + simple_macro!(1015); + simple_macro!(1016); + simple_macro!(1017); + simple_macro!(1018); + simple_macro!(1019); + simple_macro!(1020); + simple_macro!(1021); + simple_macro!(1022); + simple_macro!(1023); + simple_macro!(1024); + simple_macro!(1025); + simple_macro!(1026); + simple_macro!(1027); + simple_macro!(1028); + simple_macro!(1029); + simple_macro!(1030); + simple_macro!(1031); + simple_macro!(1032); + simple_macro!(1033); + simple_macro!(1034); + simple_macro!(1035); + simple_macro!(1036); + simple_macro!(1037); + simple_macro!(1038); + simple_macro!(1039); + simple_macro!(1040); + simple_macro!(1041); + simple_macro!(1042); + simple_macro!(1043); + simple_macro!(1044); + simple_macro!(1045); + simple_macro!(1046); + simple_macro!(1047); + simple_macro!(1048); + simple_macro!(1049); + simple_macro!(1050); + simple_macro!(1051); + simple_macro!(1052); + simple_macro!(1053); + simple_macro!(1054); + simple_macro!(1055); + simple_macro!(1056); + simple_macro!(1057); + simple_macro!(1058); + simple_macro!(1059); + simple_macro!(1060); + simple_macro!(1061); + simple_macro!(1062); + simple_macro!(1063); + simple_macro!(1064); + simple_macro!(1065); + simple_macro!(1066); + simple_macro!(1067); + simple_macro!(1068); + simple_macro!(1069); + simple_macro!(1070); + simple_macro!(1071); + simple_macro!(1072); + simple_macro!(1073); + simple_macro!(1074); + simple_macro!(1075); + simple_macro!(1076); + simple_macro!(1077); + simple_macro!(1078); + simple_macro!(1079); + simple_macro!(1080); + simple_macro!(1081); + simple_macro!(1082); + simple_macro!(1083); + simple_macro!(1084); + simple_macro!(1085); + simple_macro!(1086); + simple_macro!(1087); + simple_macro!(1088); + simple_macro!(1089); + simple_macro!(1090); + simple_macro!(1091); + simple_macro!(1092); + simple_macro!(1093); + simple_macro!(1094); + simple_macro!(1095); + simple_macro!(1096); + simple_macro!(1097); + simple_macro!(1098); + simple_macro!(1099); + simple_macro!(1100); + simple_macro!(1101); + simple_macro!(1102); + simple_macro!(1103); + simple_macro!(1104); + simple_macro!(1105); + simple_macro!(1106); + simple_macro!(1107); + simple_macro!(1108); + simple_macro!(1109); + simple_macro!(1110); + simple_macro!(1111); + simple_macro!(1112); + simple_macro!(1113); + simple_macro!(1114); + simple_macro!(1115); + simple_macro!(1116); + simple_macro!(1117); + simple_macro!(1118); + simple_macro!(1119); + simple_macro!(1120); + simple_macro!(1121); + simple_macro!(1122); + simple_macro!(1123); + simple_macro!(1124); + simple_macro!(1125); + simple_macro!(1126); + simple_macro!(1127); + simple_macro!(1128); + simple_macro!(1129); + simple_macro!(1130); + simple_macro!(1131); + simple_macro!(1132); + simple_macro!(1133); + simple_macro!(1134); + simple_macro!(1135); + simple_macro!(1136); + simple_macro!(1137); + simple_macro!(1138); + simple_macro!(1139); + simple_macro!(1140); + simple_macro!(1141); + simple_macro!(1142); + simple_macro!(1143); + simple_macro!(1144); + simple_macro!(1145); + simple_macro!(1146); + simple_macro!(1147); + simple_macro!(1148); + simple_macro!(1149); + simple_macro!(1150); + simple_macro!(1151); + simple_macro!(1152); + simple_macro!(1153); + simple_macro!(1154); + simple_macro!(1155); + simple_macro!(1156); + simple_macro!(1157); + simple_macro!(1158); + simple_macro!(1159); + simple_macro!(1160); + simple_macro!(1161); + simple_macro!(1162); + simple_macro!(1163); + simple_macro!(1164); + simple_macro!(1165); + simple_macro!(1166); + simple_macro!(1167); + simple_macro!(1168); + simple_macro!(1169); + simple_macro!(1170); + simple_macro!(1171); + simple_macro!(1172); + simple_macro!(1173); + simple_macro!(1174); + simple_macro!(1175); + simple_macro!(1176); + simple_macro!(1177); + simple_macro!(1178); + simple_macro!(1179); + simple_macro!(1180); + simple_macro!(1181); + simple_macro!(1182); + simple_macro!(1183); + simple_macro!(1184); + simple_macro!(1185); + simple_macro!(1186); + simple_macro!(1187); + simple_macro!(1188); + simple_macro!(1189); + simple_macro!(1190); + simple_macro!(1191); + simple_macro!(1192); + simple_macro!(1193); + simple_macro!(1194); + simple_macro!(1195); + simple_macro!(1196); + simple_macro!(1197); + simple_macro!(1198); + simple_macro!(1199); + simple_macro!(1200); + simple_macro!(1201); + simple_macro!(1202); + simple_macro!(1203); + simple_macro!(1204); + simple_macro!(1205); + simple_macro!(1206); + simple_macro!(1207); + simple_macro!(1208); + simple_macro!(1209); + simple_macro!(1210); + simple_macro!(1211); + simple_macro!(1212); + simple_macro!(1213); + simple_macro!(1214); + simple_macro!(1215); + simple_macro!(1216); + simple_macro!(1217); + simple_macro!(1218); + simple_macro!(1219); + simple_macro!(1220); + simple_macro!(1221); + simple_macro!(1222); + simple_macro!(1223); + simple_macro!(1224); + simple_macro!(1225); + simple_macro!(1226); + simple_macro!(1227); + simple_macro!(1228); + simple_macro!(1229); + simple_macro!(1230); + simple_macro!(1231); + simple_macro!(1232); + simple_macro!(1233); + simple_macro!(1234); + simple_macro!(1235); + simple_macro!(1236); + simple_macro!(1237); + simple_macro!(1238); + simple_macro!(1239); + simple_macro!(1240); + simple_macro!(1241); + simple_macro!(1242); + simple_macro!(1243); + simple_macro!(1244); + simple_macro!(1245); + simple_macro!(1246); + simple_macro!(1247); + simple_macro!(1248); + simple_macro!(1249); + simple_macro!(1250); + simple_macro!(1251); + simple_macro!(1252); + simple_macro!(1253); + simple_macro!(1254); + simple_macro!(1255); + simple_macro!(1256); + simple_macro!(1257); + simple_macro!(1258); + simple_macro!(1259); + simple_macro!(1260); + simple_macro!(1261); + simple_macro!(1262); + simple_macro!(1263); + simple_macro!(1264); + simple_macro!(1265); + simple_macro!(1266); + simple_macro!(1267); + simple_macro!(1268); + simple_macro!(1269); + simple_macro!(1270); + simple_macro!(1271); + simple_macro!(1272); + simple_macro!(1273); + simple_macro!(1274); + simple_macro!(1275); + simple_macro!(1276); + simple_macro!(1277); + simple_macro!(1278); + simple_macro!(1279); + simple_macro!(1280); + simple_macro!(1281); + simple_macro!(1282); + simple_macro!(1283); + simple_macro!(1284); + simple_macro!(1285); + simple_macro!(1286); + simple_macro!(1287); + simple_macro!(1288); + simple_macro!(1289); + simple_macro!(1290); + simple_macro!(1291); + simple_macro!(1292); + simple_macro!(1293); + simple_macro!(1294); + simple_macro!(1295); + simple_macro!(1296); + simple_macro!(1297); + simple_macro!(1298); + simple_macro!(1299); + simple_macro!(1300); + simple_macro!(1301); + simple_macro!(1302); + simple_macro!(1303); + simple_macro!(1304); + simple_macro!(1305); + simple_macro!(1306); + simple_macro!(1307); + simple_macro!(1308); + simple_macro!(1309); + simple_macro!(1310); + simple_macro!(1311); + simple_macro!(1312); + simple_macro!(1313); + simple_macro!(1314); + simple_macro!(1315); + simple_macro!(1316); + simple_macro!(1317); + simple_macro!(1318); + simple_macro!(1319); + simple_macro!(1320); + simple_macro!(1321); + simple_macro!(1322); + simple_macro!(1323); + simple_macro!(1324); + simple_macro!(1325); + simple_macro!(1326); + simple_macro!(1327); + simple_macro!(1328); + simple_macro!(1329); + simple_macro!(1330); + simple_macro!(1331); + simple_macro!(1332); + simple_macro!(1333); + simple_macro!(1334); + simple_macro!(1335); + simple_macro!(1336); + simple_macro!(1337); + simple_macro!(1338); + simple_macro!(1339); + simple_macro!(1340); + simple_macro!(1341); + simple_macro!(1342); + simple_macro!(1343); + simple_macro!(1344); + simple_macro!(1345); + simple_macro!(1346); + simple_macro!(1347); + simple_macro!(1348); + simple_macro!(1349); + simple_macro!(1350); + simple_macro!(1351); + simple_macro!(1352); + simple_macro!(1353); + simple_macro!(1354); + simple_macro!(1355); + simple_macro!(1356); + simple_macro!(1357); + simple_macro!(1358); + simple_macro!(1359); + simple_macro!(1360); + simple_macro!(1361); + simple_macro!(1362); + simple_macro!(1363); + simple_macro!(1364); + simple_macro!(1365); + simple_macro!(1366); + simple_macro!(1367); + simple_macro!(1368); + simple_macro!(1369); + simple_macro!(1370); + simple_macro!(1371); + simple_macro!(1372); + simple_macro!(1373); + simple_macro!(1374); + simple_macro!(1375); + simple_macro!(1376); + simple_macro!(1377); + simple_macro!(1378); + simple_macro!(1379); + simple_macro!(1380); + simple_macro!(1381); + simple_macro!(1382); + simple_macro!(1383); + simple_macro!(1384); + simple_macro!(1385); + simple_macro!(1386); + simple_macro!(1387); + simple_macro!(1388); + simple_macro!(1389); + simple_macro!(1390); + simple_macro!(1391); + simple_macro!(1392); + simple_macro!(1393); + simple_macro!(1394); + simple_macro!(1395); + simple_macro!(1396); + simple_macro!(1397); + simple_macro!(1398); + simple_macro!(1399); + simple_macro!(1400); + simple_macro!(1401); + simple_macro!(1402); + simple_macro!(1403); + simple_macro!(1404); + simple_macro!(1405); + simple_macro!(1406); + simple_macro!(1407); + simple_macro!(1408); + simple_macro!(1409); + simple_macro!(1410); + simple_macro!(1411); + simple_macro!(1412); + simple_macro!(1413); + simple_macro!(1414); + simple_macro!(1415); + simple_macro!(1416); + simple_macro!(1417); + simple_macro!(1418); + simple_macro!(1419); + simple_macro!(1420); + simple_macro!(1421); + simple_macro!(1422); + simple_macro!(1423); + simple_macro!(1424); + simple_macro!(1425); + simple_macro!(1426); + simple_macro!(1427); + simple_macro!(1428); + simple_macro!(1429); + simple_macro!(1430); + simple_macro!(1431); + simple_macro!(1432); + simple_macro!(1433); + simple_macro!(1434); + simple_macro!(1435); + simple_macro!(1436); + simple_macro!(1437); + simple_macro!(1438); + simple_macro!(1439); + simple_macro!(1440); + simple_macro!(1441); + simple_macro!(1442); + simple_macro!(1443); + simple_macro!(1444); + simple_macro!(1445); + simple_macro!(1446); + simple_macro!(1447); + simple_macro!(1448); + simple_macro!(1449); + simple_macro!(1450); + simple_macro!(1451); + simple_macro!(1452); + simple_macro!(1453); + simple_macro!(1454); + simple_macro!(1455); + simple_macro!(1456); + simple_macro!(1457); + simple_macro!(1458); + simple_macro!(1459); + simple_macro!(1460); + simple_macro!(1461); + simple_macro!(1462); + simple_macro!(1463); + simple_macro!(1464); + simple_macro!(1465); + simple_macro!(1466); + simple_macro!(1467); + simple_macro!(1468); + simple_macro!(1469); + simple_macro!(1470); + simple_macro!(1471); + simple_macro!(1472); + simple_macro!(1473); + simple_macro!(1474); + simple_macro!(1475); + simple_macro!(1476); + simple_macro!(1477); + simple_macro!(1478); + simple_macro!(1479); + simple_macro!(1480); + simple_macro!(1481); + simple_macro!(1482); + simple_macro!(1483); + simple_macro!(1484); + simple_macro!(1485); + simple_macro!(1486); + simple_macro!(1487); + simple_macro!(1488); + simple_macro!(1489); + simple_macro!(1490); + simple_macro!(1491); + simple_macro!(1492); + simple_macro!(1493); + simple_macro!(1494); + simple_macro!(1495); + simple_macro!(1496); + simple_macro!(1497); + simple_macro!(1498); + simple_macro!(1499); + simple_macro!(1500); + simple_macro!(1501); + simple_macro!(1502); + simple_macro!(1503); + simple_macro!(1504); + simple_macro!(1505); + simple_macro!(1506); + simple_macro!(1507); + simple_macro!(1508); + simple_macro!(1509); + simple_macro!(1510); + simple_macro!(1511); + simple_macro!(1512); + simple_macro!(1513); + simple_macro!(1514); + simple_macro!(1515); + simple_macro!(1516); + simple_macro!(1517); + simple_macro!(1518); + simple_macro!(1519); + simple_macro!(1520); + simple_macro!(1521); + simple_macro!(1522); + simple_macro!(1523); + simple_macro!(1524); + simple_macro!(1525); + simple_macro!(1526); + simple_macro!(1527); + simple_macro!(1528); + simple_macro!(1529); + simple_macro!(1530); + simple_macro!(1531); + simple_macro!(1532); + simple_macro!(1533); + simple_macro!(1534); + simple_macro!(1535); + simple_macro!(1536); + simple_macro!(1537); + simple_macro!(1538); + simple_macro!(1539); + simple_macro!(1540); + simple_macro!(1541); + simple_macro!(1542); + simple_macro!(1543); + simple_macro!(1544); + simple_macro!(1545); + simple_macro!(1546); + simple_macro!(1547); + simple_macro!(1548); + simple_macro!(1549); + simple_macro!(1550); + simple_macro!(1551); + simple_macro!(1552); + simple_macro!(1553); + simple_macro!(1554); + simple_macro!(1555); + simple_macro!(1556); + simple_macro!(1557); + simple_macro!(1558); + simple_macro!(1559); + simple_macro!(1560); + simple_macro!(1561); + simple_macro!(1562); + simple_macro!(1563); + simple_macro!(1564); + simple_macro!(1565); + simple_macro!(1566); + simple_macro!(1567); + simple_macro!(1568); + simple_macro!(1569); + simple_macro!(1570); + simple_macro!(1571); + simple_macro!(1572); + simple_macro!(1573); + simple_macro!(1574); + simple_macro!(1575); + simple_macro!(1576); + simple_macro!(1577); + simple_macro!(1578); + simple_macro!(1579); + simple_macro!(1580); + simple_macro!(1581); + simple_macro!(1582); + simple_macro!(1583); + simple_macro!(1584); + simple_macro!(1585); + simple_macro!(1586); + simple_macro!(1587); + simple_macro!(1588); + simple_macro!(1589); + simple_macro!(1590); + simple_macro!(1591); + simple_macro!(1592); + simple_macro!(1593); + simple_macro!(1594); + simple_macro!(1595); + simple_macro!(1596); + simple_macro!(1597); + simple_macro!(1598); + simple_macro!(1599); + simple_macro!(1600); + simple_macro!(1601); + simple_macro!(1602); + simple_macro!(1603); + simple_macro!(1604); + simple_macro!(1605); + simple_macro!(1606); + simple_macro!(1607); + simple_macro!(1608); + simple_macro!(1609); + simple_macro!(1610); + simple_macro!(1611); + simple_macro!(1612); + simple_macro!(1613); + simple_macro!(1614); + simple_macro!(1615); + simple_macro!(1616); + simple_macro!(1617); + simple_macro!(1618); + simple_macro!(1619); + simple_macro!(1620); + simple_macro!(1621); + simple_macro!(1622); + simple_macro!(1623); + simple_macro!(1624); + simple_macro!(1625); + simple_macro!(1626); + simple_macro!(1627); + simple_macro!(1628); + simple_macro!(1629); + simple_macro!(1630); + simple_macro!(1631); + simple_macro!(1632); + simple_macro!(1633); + simple_macro!(1634); + simple_macro!(1635); + simple_macro!(1636); + simple_macro!(1637); + simple_macro!(1638); + simple_macro!(1639); + simple_macro!(1640); + simple_macro!(1641); + simple_macro!(1642); + simple_macro!(1643); + simple_macro!(1644); + simple_macro!(1645); + simple_macro!(1646); + simple_macro!(1647); + simple_macro!(1648); + simple_macro!(1649); + simple_macro!(1650); + simple_macro!(1651); + simple_macro!(1652); + simple_macro!(1653); + simple_macro!(1654); + simple_macro!(1655); + simple_macro!(1656); + simple_macro!(1657); + simple_macro!(1658); + simple_macro!(1659); + simple_macro!(1660); + simple_macro!(1661); + simple_macro!(1662); + simple_macro!(1663); + simple_macro!(1664); + simple_macro!(1665); + simple_macro!(1666); + simple_macro!(1667); + simple_macro!(1668); + simple_macro!(1669); + simple_macro!(1670); + simple_macro!(1671); + simple_macro!(1672); + simple_macro!(1673); + simple_macro!(1674); + simple_macro!(1675); + simple_macro!(1676); + simple_macro!(1677); + simple_macro!(1678); + simple_macro!(1679); + simple_macro!(1680); + simple_macro!(1681); + simple_macro!(1682); + simple_macro!(1683); + simple_macro!(1684); + simple_macro!(1685); + simple_macro!(1686); + simple_macro!(1687); + simple_macro!(1688); + simple_macro!(1689); + simple_macro!(1690); + simple_macro!(1691); + simple_macro!(1692); + simple_macro!(1693); + simple_macro!(1694); + simple_macro!(1695); + simple_macro!(1696); + simple_macro!(1697); + simple_macro!(1698); + simple_macro!(1699); + simple_macro!(1700); + simple_macro!(1701); + simple_macro!(1702); + simple_macro!(1703); + simple_macro!(1704); + simple_macro!(1705); + simple_macro!(1706); + simple_macro!(1707); + simple_macro!(1708); + simple_macro!(1709); + simple_macro!(1710); + simple_macro!(1711); + simple_macro!(1712); + simple_macro!(1713); + simple_macro!(1714); + simple_macro!(1715); + simple_macro!(1716); + simple_macro!(1717); + simple_macro!(1718); + simple_macro!(1719); + simple_macro!(1720); + simple_macro!(1721); + simple_macro!(1722); + simple_macro!(1723); + simple_macro!(1724); + simple_macro!(1725); + simple_macro!(1726); + simple_macro!(1727); + simple_macro!(1728); + simple_macro!(1729); + simple_macro!(1730); + simple_macro!(1731); + simple_macro!(1732); + simple_macro!(1733); + simple_macro!(1734); + simple_macro!(1735); + simple_macro!(1736); + simple_macro!(1737); + simple_macro!(1738); + simple_macro!(1739); + simple_macro!(1740); + simple_macro!(1741); + simple_macro!(1742); + simple_macro!(1743); + simple_macro!(1744); + simple_macro!(1745); + simple_macro!(1746); + simple_macro!(1747); + simple_macro!(1748); + simple_macro!(1749); + simple_macro!(1750); + simple_macro!(1751); + simple_macro!(1752); + simple_macro!(1753); + simple_macro!(1754); + simple_macro!(1755); + simple_macro!(1756); + simple_macro!(1757); + simple_macro!(1758); + simple_macro!(1759); + simple_macro!(1760); + simple_macro!(1761); + simple_macro!(1762); + simple_macro!(1763); + simple_macro!(1764); + simple_macro!(1765); + simple_macro!(1766); + simple_macro!(1767); + simple_macro!(1768); + simple_macro!(1769); + simple_macro!(1770); + simple_macro!(1771); + simple_macro!(1772); + simple_macro!(1773); + simple_macro!(1774); + simple_macro!(1775); + simple_macro!(1776); + simple_macro!(1777); + simple_macro!(1778); + simple_macro!(1779); + simple_macro!(1780); + simple_macro!(1781); + simple_macro!(1782); + simple_macro!(1783); + simple_macro!(1784); + simple_macro!(1785); + simple_macro!(1786); + simple_macro!(1787); + simple_macro!(1788); + simple_macro!(1789); + simple_macro!(1790); + simple_macro!(1791); + simple_macro!(1792); + simple_macro!(1793); + simple_macro!(1794); + simple_macro!(1795); + simple_macro!(1796); + simple_macro!(1797); + simple_macro!(1798); + simple_macro!(1799); + simple_macro!(1800); + simple_macro!(1801); + simple_macro!(1802); + simple_macro!(1803); + simple_macro!(1804); + simple_macro!(1805); + simple_macro!(1806); + simple_macro!(1807); + simple_macro!(1808); + simple_macro!(1809); + simple_macro!(1810); + simple_macro!(1811); + simple_macro!(1812); + simple_macro!(1813); + simple_macro!(1814); + simple_macro!(1815); + simple_macro!(1816); + simple_macro!(1817); + simple_macro!(1818); + simple_macro!(1819); + simple_macro!(1820); + simple_macro!(1821); + simple_macro!(1822); + simple_macro!(1823); + simple_macro!(1824); + simple_macro!(1825); + simple_macro!(1826); + simple_macro!(1827); + simple_macro!(1828); + simple_macro!(1829); + simple_macro!(1830); + simple_macro!(1831); + simple_macro!(1832); + simple_macro!(1833); + simple_macro!(1834); + simple_macro!(1835); + simple_macro!(1836); + simple_macro!(1837); + simple_macro!(1838); + simple_macro!(1839); + simple_macro!(1840); + simple_macro!(1841); + simple_macro!(1842); + simple_macro!(1843); + simple_macro!(1844); + simple_macro!(1845); + simple_macro!(1846); + simple_macro!(1847); + simple_macro!(1848); + simple_macro!(1849); + simple_macro!(1850); + simple_macro!(1851); + simple_macro!(1852); + simple_macro!(1853); + simple_macro!(1854); + simple_macro!(1855); + simple_macro!(1856); + simple_macro!(1857); + simple_macro!(1858); + simple_macro!(1859); + simple_macro!(1860); + simple_macro!(1861); + simple_macro!(1862); + simple_macro!(1863); + simple_macro!(1864); + simple_macro!(1865); + simple_macro!(1866); + simple_macro!(1867); + simple_macro!(1868); + simple_macro!(1869); + simple_macro!(1870); + simple_macro!(1871); + simple_macro!(1872); + simple_macro!(1873); + simple_macro!(1874); + simple_macro!(1875); + simple_macro!(1876); + simple_macro!(1877); + simple_macro!(1878); + simple_macro!(1879); + simple_macro!(1880); + simple_macro!(1881); + simple_macro!(1882); + simple_macro!(1883); + simple_macro!(1884); + simple_macro!(1885); + simple_macro!(1886); + simple_macro!(1887); + simple_macro!(1888); + simple_macro!(1889); + simple_macro!(1890); + simple_macro!(1891); + simple_macro!(1892); + simple_macro!(1893); + simple_macro!(1894); + simple_macro!(1895); + simple_macro!(1896); + simple_macro!(1897); + simple_macro!(1898); + simple_macro!(1899); + simple_macro!(1900); + simple_macro!(1901); + simple_macro!(1902); + simple_macro!(1903); + simple_macro!(1904); + simple_macro!(1905); + simple_macro!(1906); + simple_macro!(1907); + simple_macro!(1908); + simple_macro!(1909); + simple_macro!(1910); + simple_macro!(1911); + simple_macro!(1912); + simple_macro!(1913); + simple_macro!(1914); + simple_macro!(1915); + simple_macro!(1916); + simple_macro!(1917); + simple_macro!(1918); + simple_macro!(1919); + simple_macro!(1920); + simple_macro!(1921); + simple_macro!(1922); + simple_macro!(1923); + simple_macro!(1924); + simple_macro!(1925); + simple_macro!(1926); + simple_macro!(1927); + simple_macro!(1928); + simple_macro!(1929); + simple_macro!(1930); + simple_macro!(1931); + simple_macro!(1932); + simple_macro!(1933); + simple_macro!(1934); + simple_macro!(1935); + simple_macro!(1936); + simple_macro!(1937); + simple_macro!(1938); + simple_macro!(1939); + simple_macro!(1940); + simple_macro!(1941); + simple_macro!(1942); + simple_macro!(1943); + simple_macro!(1944); + simple_macro!(1945); + simple_macro!(1946); + simple_macro!(1947); + simple_macro!(1948); + simple_macro!(1949); + simple_macro!(1950); + simple_macro!(1951); + simple_macro!(1952); + simple_macro!(1953); + simple_macro!(1954); + simple_macro!(1955); + simple_macro!(1956); + simple_macro!(1957); + simple_macro!(1958); + simple_macro!(1959); + simple_macro!(1960); + simple_macro!(1961); + simple_macro!(1962); + simple_macro!(1963); + simple_macro!(1964); + simple_macro!(1965); + simple_macro!(1966); + simple_macro!(1967); + simple_macro!(1968); + simple_macro!(1969); + simple_macro!(1970); + simple_macro!(1971); + simple_macro!(1972); + simple_macro!(1973); + simple_macro!(1974); + simple_macro!(1975); + simple_macro!(1976); + simple_macro!(1977); + simple_macro!(1978); + simple_macro!(1979); + simple_macro!(1980); + simple_macro!(1981); + simple_macro!(1982); + simple_macro!(1983); + simple_macro!(1984); + simple_macro!(1985); + simple_macro!(1986); + simple_macro!(1987); + simple_macro!(1988); + simple_macro!(1989); + simple_macro!(1990); + simple_macro!(1991); + simple_macro!(1992); + simple_macro!(1993); + simple_macro!(1994); + simple_macro!(1995); + simple_macro!(1996); + simple_macro!(1997); + simple_macro!(1998); + simple_macro!(1999); + simple_macro!(2000); + simple_macro!(2001); + simple_macro!(2002); + simple_macro!(2003); + simple_macro!(2004); + simple_macro!(2005); + simple_macro!(2006); + simple_macro!(2007); + simple_macro!(2008); + simple_macro!(2009); + simple_macro!(2010); + simple_macro!(2011); + simple_macro!(2012); + simple_macro!(2013); + simple_macro!(2014); + simple_macro!(2015); + simple_macro!(2016); + simple_macro!(2017); + simple_macro!(2018); + simple_macro!(2019); + simple_macro!(2020); + simple_macro!(2021); + simple_macro!(2022); + simple_macro!(2023); + simple_macro!(2024); + simple_macro!(2025); + simple_macro!(2026); + simple_macro!(2027); + simple_macro!(2028); + simple_macro!(2029); + simple_macro!(2030); + simple_macro!(2031); + simple_macro!(2032); + simple_macro!(2033); + simple_macro!(2034); + simple_macro!(2035); + simple_macro!(2036); + simple_macro!(2037); + simple_macro!(2038); + simple_macro!(2039); + simple_macro!(2040); + simple_macro!(2041); + simple_macro!(2042); + simple_macro!(2043); + simple_macro!(2044); + simple_macro!(2045); + simple_macro!(2046); + simple_macro!(2047); + simple_macro!(2048); + simple_macro!(2049); + simple_macro!(2050); + simple_macro!(2051); + simple_macro!(2052); + simple_macro!(2053); + simple_macro!(2054); + simple_macro!(2055); + simple_macro!(2056); + simple_macro!(2057); + simple_macro!(2058); + simple_macro!(2059); + simple_macro!(2060); + simple_macro!(2061); + simple_macro!(2062); + simple_macro!(2063); + simple_macro!(2064); + simple_macro!(2065); + simple_macro!(2066); + simple_macro!(2067); + simple_macro!(2068); + simple_macro!(2069); + simple_macro!(2070); + simple_macro!(2071); + simple_macro!(2072); + simple_macro!(2073); + simple_macro!(2074); + simple_macro!(2075); + simple_macro!(2076); + simple_macro!(2077); + simple_macro!(2078); + simple_macro!(2079); + simple_macro!(2080); + simple_macro!(2081); + simple_macro!(2082); + simple_macro!(2083); + simple_macro!(2084); + simple_macro!(2085); + simple_macro!(2086); + simple_macro!(2087); + simple_macro!(2088); + simple_macro!(2089); + simple_macro!(2090); + simple_macro!(2091); + simple_macro!(2092); + simple_macro!(2093); + simple_macro!(2094); + simple_macro!(2095); + simple_macro!(2096); + simple_macro!(2097); + simple_macro!(2098); + simple_macro!(2099); + simple_macro!(2100); + simple_macro!(2101); + simple_macro!(2102); + simple_macro!(2103); + simple_macro!(2104); + simple_macro!(2105); + simple_macro!(2106); + simple_macro!(2107); + simple_macro!(2108); + simple_macro!(2109); + simple_macro!(2110); + simple_macro!(2111); + simple_macro!(2112); + simple_macro!(2113); + simple_macro!(2114); + simple_macro!(2115); + simple_macro!(2116); + simple_macro!(2117); + simple_macro!(2118); + simple_macro!(2119); + simple_macro!(2120); + simple_macro!(2121); + simple_macro!(2122); + simple_macro!(2123); + simple_macro!(2124); + simple_macro!(2125); + simple_macro!(2126); + simple_macro!(2127); + simple_macro!(2128); + simple_macro!(2129); + simple_macro!(2130); + simple_macro!(2131); + simple_macro!(2132); + simple_macro!(2133); + simple_macro!(2134); + simple_macro!(2135); + simple_macro!(2136); + simple_macro!(2137); + simple_macro!(2138); + simple_macro!(2139); + simple_macro!(2140); + simple_macro!(2141); + simple_macro!(2142); + simple_macro!(2143); + simple_macro!(2144); + simple_macro!(2145); + simple_macro!(2146); + simple_macro!(2147); + simple_macro!(2148); + simple_macro!(2149); + simple_macro!(2150); + simple_macro!(2151); + simple_macro!(2152); + simple_macro!(2153); + simple_macro!(2154); + simple_macro!(2155); + simple_macro!(2156); + simple_macro!(2157); + simple_macro!(2158); + simple_macro!(2159); + simple_macro!(2160); + simple_macro!(2161); + simple_macro!(2162); + simple_macro!(2163); + simple_macro!(2164); + simple_macro!(2165); + simple_macro!(2166); + simple_macro!(2167); + simple_macro!(2168); + simple_macro!(2169); + simple_macro!(2170); + simple_macro!(2171); + simple_macro!(2172); + simple_macro!(2173); + simple_macro!(2174); + simple_macro!(2175); + simple_macro!(2176); + simple_macro!(2177); + simple_macro!(2178); + simple_macro!(2179); + simple_macro!(2180); + simple_macro!(2181); + simple_macro!(2182); + simple_macro!(2183); + simple_macro!(2184); + simple_macro!(2185); + simple_macro!(2186); + simple_macro!(2187); + simple_macro!(2188); + simple_macro!(2189); + simple_macro!(2190); + simple_macro!(2191); + simple_macro!(2192); + simple_macro!(2193); + simple_macro!(2194); + simple_macro!(2195); + simple_macro!(2196); + simple_macro!(2197); + simple_macro!(2198); + simple_macro!(2199); + simple_macro!(2200); + simple_macro!(2201); + simple_macro!(2202); + simple_macro!(2203); + simple_macro!(2204); + simple_macro!(2205); + simple_macro!(2206); + simple_macro!(2207); + simple_macro!(2208); + simple_macro!(2209); + simple_macro!(2210); + simple_macro!(2211); + simple_macro!(2212); + simple_macro!(2213); + simple_macro!(2214); + simple_macro!(2215); + simple_macro!(2216); + simple_macro!(2217); + simple_macro!(2218); + simple_macro!(2219); + simple_macro!(2220); + simple_macro!(2221); + simple_macro!(2222); + simple_macro!(2223); + simple_macro!(2224); + simple_macro!(2225); + simple_macro!(2226); + simple_macro!(2227); + simple_macro!(2228); + simple_macro!(2229); + simple_macro!(2230); + simple_macro!(2231); + simple_macro!(2232); + simple_macro!(2233); + simple_macro!(2234); + simple_macro!(2235); + simple_macro!(2236); + simple_macro!(2237); + simple_macro!(2238); + simple_macro!(2239); + simple_macro!(2240); + simple_macro!(2241); + simple_macro!(2242); + simple_macro!(2243); + simple_macro!(2244); + simple_macro!(2245); + simple_macro!(2246); + simple_macro!(2247); + simple_macro!(2248); + simple_macro!(2249); + simple_macro!(2250); + simple_macro!(2251); + simple_macro!(2252); + simple_macro!(2253); + simple_macro!(2254); + simple_macro!(2255); + simple_macro!(2256); + simple_macro!(2257); + simple_macro!(2258); + simple_macro!(2259); + simple_macro!(2260); + simple_macro!(2261); + simple_macro!(2262); + simple_macro!(2263); + simple_macro!(2264); + simple_macro!(2265); + simple_macro!(2266); + simple_macro!(2267); + simple_macro!(2268); + simple_macro!(2269); + simple_macro!(2270); + simple_macro!(2271); + simple_macro!(2272); + simple_macro!(2273); + simple_macro!(2274); + simple_macro!(2275); + simple_macro!(2276); + simple_macro!(2277); + simple_macro!(2278); + simple_macro!(2279); + simple_macro!(2280); + simple_macro!(2281); + simple_macro!(2282); + simple_macro!(2283); + simple_macro!(2284); + simple_macro!(2285); + simple_macro!(2286); + simple_macro!(2287); + simple_macro!(2288); + simple_macro!(2289); + simple_macro!(2290); + simple_macro!(2291); + simple_macro!(2292); + simple_macro!(2293); + simple_macro!(2294); + simple_macro!(2295); + simple_macro!(2296); + simple_macro!(2297); + simple_macro!(2298); + simple_macro!(2299); + simple_macro!(2300); + simple_macro!(2301); + simple_macro!(2302); + simple_macro!(2303); + simple_macro!(2304); + simple_macro!(2305); + simple_macro!(2306); + simple_macro!(2307); + simple_macro!(2308); + simple_macro!(2309); + simple_macro!(2310); + simple_macro!(2311); + simple_macro!(2312); + simple_macro!(2313); + simple_macro!(2314); + simple_macro!(2315); + simple_macro!(2316); + simple_macro!(2317); + simple_macro!(2318); + simple_macro!(2319); + simple_macro!(2320); + simple_macro!(2321); + simple_macro!(2322); + simple_macro!(2323); + simple_macro!(2324); + simple_macro!(2325); + simple_macro!(2326); + simple_macro!(2327); + simple_macro!(2328); + simple_macro!(2329); + simple_macro!(2330); + simple_macro!(2331); + simple_macro!(2332); + simple_macro!(2333); + simple_macro!(2334); + simple_macro!(2335); + simple_macro!(2336); + simple_macro!(2337); + simple_macro!(2338); + simple_macro!(2339); + simple_macro!(2340); + simple_macro!(2341); + simple_macro!(2342); + simple_macro!(2343); + simple_macro!(2344); + simple_macro!(2345); + simple_macro!(2346); + simple_macro!(2347); + simple_macro!(2348); + simple_macro!(2349); + simple_macro!(2350); + simple_macro!(2351); + simple_macro!(2352); + simple_macro!(2353); + simple_macro!(2354); + simple_macro!(2355); + simple_macro!(2356); + simple_macro!(2357); + simple_macro!(2358); + simple_macro!(2359); + simple_macro!(2360); + simple_macro!(2361); + simple_macro!(2362); + simple_macro!(2363); + simple_macro!(2364); + simple_macro!(2365); + simple_macro!(2366); + simple_macro!(2367); + simple_macro!(2368); + simple_macro!(2369); + simple_macro!(2370); + simple_macro!(2371); + simple_macro!(2372); + simple_macro!(2373); + simple_macro!(2374); + simple_macro!(2375); + simple_macro!(2376); + simple_macro!(2377); + simple_macro!(2378); + simple_macro!(2379); + simple_macro!(2380); + simple_macro!(2381); + simple_macro!(2382); + simple_macro!(2383); + simple_macro!(2384); + simple_macro!(2385); + simple_macro!(2386); + simple_macro!(2387); + simple_macro!(2388); + simple_macro!(2389); + simple_macro!(2390); + simple_macro!(2391); + simple_macro!(2392); + simple_macro!(2393); + simple_macro!(2394); + simple_macro!(2395); + simple_macro!(2396); + simple_macro!(2397); + simple_macro!(2398); + simple_macro!(2399); + simple_macro!(2400); + simple_macro!(2401); + simple_macro!(2402); + simple_macro!(2403); + simple_macro!(2404); + simple_macro!(2405); + simple_macro!(2406); + simple_macro!(2407); + simple_macro!(2408); + simple_macro!(2409); + simple_macro!(2410); + simple_macro!(2411); + simple_macro!(2412); + simple_macro!(2413); + simple_macro!(2414); + simple_macro!(2415); + simple_macro!(2416); + simple_macro!(2417); + simple_macro!(2418); + simple_macro!(2419); + simple_macro!(2420); + simple_macro!(2421); + simple_macro!(2422); + simple_macro!(2423); + simple_macro!(2424); + simple_macro!(2425); + simple_macro!(2426); + simple_macro!(2427); + simple_macro!(2428); + simple_macro!(2429); + simple_macro!(2430); + simple_macro!(2431); + simple_macro!(2432); + simple_macro!(2433); + simple_macro!(2434); + simple_macro!(2435); + simple_macro!(2436); + simple_macro!(2437); + simple_macro!(2438); + simple_macro!(2439); + simple_macro!(2440); + simple_macro!(2441); + simple_macro!(2442); + simple_macro!(2443); + simple_macro!(2444); + simple_macro!(2445); + simple_macro!(2446); + simple_macro!(2447); + simple_macro!(2448); + simple_macro!(2449); + simple_macro!(2450); + simple_macro!(2451); + simple_macro!(2452); + simple_macro!(2453); + simple_macro!(2454); + simple_macro!(2455); + simple_macro!(2456); + simple_macro!(2457); + simple_macro!(2458); + simple_macro!(2459); + simple_macro!(2460); + simple_macro!(2461); + simple_macro!(2462); + simple_macro!(2463); + simple_macro!(2464); + simple_macro!(2465); + simple_macro!(2466); + simple_macro!(2467); + simple_macro!(2468); + simple_macro!(2469); + simple_macro!(2470); + simple_macro!(2471); + simple_macro!(2472); + simple_macro!(2473); + simple_macro!(2474); + simple_macro!(2475); + simple_macro!(2476); + simple_macro!(2477); + simple_macro!(2478); + simple_macro!(2479); + simple_macro!(2480); + simple_macro!(2481); + simple_macro!(2482); + simple_macro!(2483); + simple_macro!(2484); + simple_macro!(2485); + simple_macro!(2486); + simple_macro!(2487); + simple_macro!(2488); + simple_macro!(2489); + simple_macro!(2490); + simple_macro!(2491); + simple_macro!(2492); + simple_macro!(2493); + simple_macro!(2494); + simple_macro!(2495); + simple_macro!(2496); + simple_macro!(2497); + simple_macro!(2498); + simple_macro!(2499); + simple_macro!(2500); + simple_macro!(2501); + simple_macro!(2502); + simple_macro!(2503); + simple_macro!(2504); + simple_macro!(2505); + simple_macro!(2506); + simple_macro!(2507); + simple_macro!(2508); + simple_macro!(2509); + simple_macro!(2510); + simple_macro!(2511); + simple_macro!(2512); + simple_macro!(2513); + simple_macro!(2514); + simple_macro!(2515); + simple_macro!(2516); + simple_macro!(2517); + simple_macro!(2518); + simple_macro!(2519); + simple_macro!(2520); + simple_macro!(2521); + simple_macro!(2522); + simple_macro!(2523); + simple_macro!(2524); + simple_macro!(2525); + simple_macro!(2526); + simple_macro!(2527); + simple_macro!(2528); + simple_macro!(2529); + simple_macro!(2530); + simple_macro!(2531); + simple_macro!(2532); + simple_macro!(2533); + simple_macro!(2534); + simple_macro!(2535); + simple_macro!(2536); + simple_macro!(2537); + simple_macro!(2538); + simple_macro!(2539); + simple_macro!(2540); + simple_macro!(2541); + simple_macro!(2542); + simple_macro!(2543); + simple_macro!(2544); + simple_macro!(2545); + simple_macro!(2546); + simple_macro!(2547); + simple_macro!(2548); + simple_macro!(2549); + simple_macro!(2550); + simple_macro!(2551); + simple_macro!(2552); + simple_macro!(2553); + simple_macro!(2554); + simple_macro!(2555); + simple_macro!(2556); + simple_macro!(2557); + simple_macro!(2558); + simple_macro!(2559); + simple_macro!(2560); + simple_macro!(2561); + simple_macro!(2562); + simple_macro!(2563); + simple_macro!(2564); + simple_macro!(2565); + simple_macro!(2566); + simple_macro!(2567); + simple_macro!(2568); + simple_macro!(2569); + simple_macro!(2570); + simple_macro!(2571); + simple_macro!(2572); + simple_macro!(2573); + simple_macro!(2574); + simple_macro!(2575); + simple_macro!(2576); + simple_macro!(2577); + simple_macro!(2578); + simple_macro!(2579); + simple_macro!(2580); + simple_macro!(2581); + simple_macro!(2582); + simple_macro!(2583); + simple_macro!(2584); + simple_macro!(2585); + simple_macro!(2586); + simple_macro!(2587); + simple_macro!(2588); + simple_macro!(2589); + simple_macro!(2590); + simple_macro!(2591); + simple_macro!(2592); + simple_macro!(2593); + simple_macro!(2594); + simple_macro!(2595); + simple_macro!(2596); + simple_macro!(2597); + simple_macro!(2598); + simple_macro!(2599); + simple_macro!(2600); + simple_macro!(2601); + simple_macro!(2602); + simple_macro!(2603); + simple_macro!(2604); + simple_macro!(2605); + simple_macro!(2606); + simple_macro!(2607); + simple_macro!(2608); + simple_macro!(2609); + simple_macro!(2610); + simple_macro!(2611); + simple_macro!(2612); + simple_macro!(2613); + simple_macro!(2614); + simple_macro!(2615); + simple_macro!(2616); + simple_macro!(2617); + simple_macro!(2618); + simple_macro!(2619); + simple_macro!(2620); + simple_macro!(2621); + simple_macro!(2622); + simple_macro!(2623); + simple_macro!(2624); + simple_macro!(2625); + simple_macro!(2626); + simple_macro!(2627); + simple_macro!(2628); + simple_macro!(2629); + simple_macro!(2630); + simple_macro!(2631); + simple_macro!(2632); + simple_macro!(2633); + simple_macro!(2634); + simple_macro!(2635); + simple_macro!(2636); + simple_macro!(2637); + simple_macro!(2638); + simple_macro!(2639); + simple_macro!(2640); + simple_macro!(2641); + simple_macro!(2642); + simple_macro!(2643); + simple_macro!(2644); + simple_macro!(2645); + simple_macro!(2646); + simple_macro!(2647); + simple_macro!(2648); + simple_macro!(2649); + simple_macro!(2650); + simple_macro!(2651); + simple_macro!(2652); + simple_macro!(2653); + simple_macro!(2654); + simple_macro!(2655); + simple_macro!(2656); + simple_macro!(2657); + simple_macro!(2658); + simple_macro!(2659); + simple_macro!(2660); + simple_macro!(2661); + simple_macro!(2662); + simple_macro!(2663); + simple_macro!(2664); + simple_macro!(2665); + simple_macro!(2666); + simple_macro!(2667); + simple_macro!(2668); + simple_macro!(2669); + simple_macro!(2670); + simple_macro!(2671); + simple_macro!(2672); + simple_macro!(2673); + simple_macro!(2674); + simple_macro!(2675); + simple_macro!(2676); + simple_macro!(2677); + simple_macro!(2678); + simple_macro!(2679); + simple_macro!(2680); + simple_macro!(2681); + simple_macro!(2682); + simple_macro!(2683); + simple_macro!(2684); + simple_macro!(2685); + simple_macro!(2686); + simple_macro!(2687); + simple_macro!(2688); + simple_macro!(2689); + simple_macro!(2690); + simple_macro!(2691); + simple_macro!(2692); + simple_macro!(2693); + simple_macro!(2694); + simple_macro!(2695); + simple_macro!(2696); + simple_macro!(2697); + simple_macro!(2698); + simple_macro!(2699); + simple_macro!(2700); + simple_macro!(2701); + simple_macro!(2702); + simple_macro!(2703); + simple_macro!(2704); + simple_macro!(2705); + simple_macro!(2706); + simple_macro!(2707); + simple_macro!(2708); + simple_macro!(2709); + simple_macro!(2710); + simple_macro!(2711); + simple_macro!(2712); + simple_macro!(2713); + simple_macro!(2714); + simple_macro!(2715); + simple_macro!(2716); + simple_macro!(2717); + simple_macro!(2718); + simple_macro!(2719); + simple_macro!(2720); + simple_macro!(2721); + simple_macro!(2722); + simple_macro!(2723); + simple_macro!(2724); + simple_macro!(2725); + simple_macro!(2726); + simple_macro!(2727); + simple_macro!(2728); + simple_macro!(2729); + simple_macro!(2730); + simple_macro!(2731); + simple_macro!(2732); + simple_macro!(2733); + simple_macro!(2734); + simple_macro!(2735); + simple_macro!(2736); + simple_macro!(2737); + simple_macro!(2738); + simple_macro!(2739); + simple_macro!(2740); + simple_macro!(2741); + simple_macro!(2742); + simple_macro!(2743); + simple_macro!(2744); + simple_macro!(2745); + simple_macro!(2746); + simple_macro!(2747); + simple_macro!(2748); + simple_macro!(2749); + simple_macro!(2750); + simple_macro!(2751); + simple_macro!(2752); + simple_macro!(2753); + simple_macro!(2754); + simple_macro!(2755); + simple_macro!(2756); + simple_macro!(2757); + simple_macro!(2758); + simple_macro!(2759); + simple_macro!(2760); + simple_macro!(2761); + simple_macro!(2762); + simple_macro!(2763); + simple_macro!(2764); + simple_macro!(2765); + simple_macro!(2766); + simple_macro!(2767); + simple_macro!(2768); + simple_macro!(2769); + simple_macro!(2770); + simple_macro!(2771); + simple_macro!(2772); + simple_macro!(2773); + simple_macro!(2774); + simple_macro!(2775); + simple_macro!(2776); + simple_macro!(2777); + simple_macro!(2778); + simple_macro!(2779); + simple_macro!(2780); + simple_macro!(2781); + simple_macro!(2782); + simple_macro!(2783); + simple_macro!(2784); + simple_macro!(2785); + simple_macro!(2786); + simple_macro!(2787); + simple_macro!(2788); + simple_macro!(2789); + simple_macro!(2790); + simple_macro!(2791); + simple_macro!(2792); + simple_macro!(2793); + simple_macro!(2794); + simple_macro!(2795); + simple_macro!(2796); + simple_macro!(2797); + simple_macro!(2798); + simple_macro!(2799); + simple_macro!(2800); + simple_macro!(2801); + simple_macro!(2802); + simple_macro!(2803); + simple_macro!(2804); + simple_macro!(2805); + simple_macro!(2806); + simple_macro!(2807); + simple_macro!(2808); + simple_macro!(2809); + simple_macro!(2810); + simple_macro!(2811); + simple_macro!(2812); + simple_macro!(2813); + simple_macro!(2814); + simple_macro!(2815); + simple_macro!(2816); + simple_macro!(2817); + simple_macro!(2818); + simple_macro!(2819); + simple_macro!(2820); + simple_macro!(2821); + simple_macro!(2822); + simple_macro!(2823); + simple_macro!(2824); + simple_macro!(2825); + simple_macro!(2826); + simple_macro!(2827); + simple_macro!(2828); + simple_macro!(2829); + simple_macro!(2830); + simple_macro!(2831); + simple_macro!(2832); + simple_macro!(2833); + simple_macro!(2834); + simple_macro!(2835); + simple_macro!(2836); + simple_macro!(2837); + simple_macro!(2838); + simple_macro!(2839); + simple_macro!(2840); + simple_macro!(2841); + simple_macro!(2842); + simple_macro!(2843); + simple_macro!(2844); + simple_macro!(2845); + simple_macro!(2846); + simple_macro!(2847); + simple_macro!(2848); + simple_macro!(2849); + simple_macro!(2850); + simple_macro!(2851); + simple_macro!(2852); + simple_macro!(2853); + simple_macro!(2854); + simple_macro!(2855); + simple_macro!(2856); + simple_macro!(2857); + simple_macro!(2858); + simple_macro!(2859); + simple_macro!(2860); + simple_macro!(2861); + simple_macro!(2862); + simple_macro!(2863); + simple_macro!(2864); + simple_macro!(2865); + simple_macro!(2866); + simple_macro!(2867); + simple_macro!(2868); + simple_macro!(2869); + simple_macro!(2870); + simple_macro!(2871); + simple_macro!(2872); + simple_macro!(2873); + simple_macro!(2874); + simple_macro!(2875); + simple_macro!(2876); + simple_macro!(2877); + simple_macro!(2878); + simple_macro!(2879); + simple_macro!(2880); + simple_macro!(2881); + simple_macro!(2882); + simple_macro!(2883); + simple_macro!(2884); + simple_macro!(2885); + simple_macro!(2886); + simple_macro!(2887); + simple_macro!(2888); + simple_macro!(2889); + simple_macro!(2890); + simple_macro!(2891); + simple_macro!(2892); + simple_macro!(2893); + simple_macro!(2894); + simple_macro!(2895); + simple_macro!(2896); + simple_macro!(2897); + simple_macro!(2898); + simple_macro!(2899); + simple_macro!(2900); + simple_macro!(2901); + simple_macro!(2902); + simple_macro!(2903); + simple_macro!(2904); + simple_macro!(2905); + simple_macro!(2906); + simple_macro!(2907); + simple_macro!(2908); + simple_macro!(2909); + simple_macro!(2910); + simple_macro!(2911); + simple_macro!(2912); + simple_macro!(2913); + simple_macro!(2914); + simple_macro!(2915); + simple_macro!(2916); + simple_macro!(2917); + simple_macro!(2918); + simple_macro!(2919); + simple_macro!(2920); + simple_macro!(2921); + simple_macro!(2922); + simple_macro!(2923); + simple_macro!(2924); + simple_macro!(2925); + simple_macro!(2926); + simple_macro!(2927); + simple_macro!(2928); + simple_macro!(2929); + simple_macro!(2930); + simple_macro!(2931); + simple_macro!(2932); + simple_macro!(2933); + simple_macro!(2934); + simple_macro!(2935); + simple_macro!(2936); + simple_macro!(2937); + simple_macro!(2938); + simple_macro!(2939); + simple_macro!(2940); + simple_macro!(2941); + simple_macro!(2942); + simple_macro!(2943); + simple_macro!(2944); + simple_macro!(2945); + simple_macro!(2946); + simple_macro!(2947); + simple_macro!(2948); + simple_macro!(2949); + simple_macro!(2950); + simple_macro!(2951); + simple_macro!(2952); + simple_macro!(2953); + simple_macro!(2954); + simple_macro!(2955); + simple_macro!(2956); + simple_macro!(2957); + simple_macro!(2958); + simple_macro!(2959); + simple_macro!(2960); + simple_macro!(2961); + simple_macro!(2962); + simple_macro!(2963); + simple_macro!(2964); + simple_macro!(2965); + simple_macro!(2966); + simple_macro!(2967); + simple_macro!(2968); + simple_macro!(2969); + simple_macro!(2970); + simple_macro!(2971); + simple_macro!(2972); + simple_macro!(2973); + simple_macro!(2974); + simple_macro!(2975); + simple_macro!(2976); + simple_macro!(2977); + simple_macro!(2978); + simple_macro!(2979); + simple_macro!(2980); + simple_macro!(2981); + simple_macro!(2982); + simple_macro!(2983); + simple_macro!(2984); + simple_macro!(2985); + simple_macro!(2986); + simple_macro!(2987); + simple_macro!(2988); + simple_macro!(2989); + simple_macro!(2990); + simple_macro!(2991); + simple_macro!(2992); + simple_macro!(2993); + simple_macro!(2994); + simple_macro!(2995); + simple_macro!(2996); + simple_macro!(2997); + simple_macro!(2998); + simple_macro!(2999); + simple_macro!(3000); + simple_macro!(3001); + simple_macro!(3002); + simple_macro!(3003); + simple_macro!(3004); + simple_macro!(3005); + simple_macro!(3006); + simple_macro!(3007); + simple_macro!(3008); + simple_macro!(3009); + simple_macro!(3010); + simple_macro!(3011); + simple_macro!(3012); + simple_macro!(3013); + simple_macro!(3014); + simple_macro!(3015); + simple_macro!(3016); + simple_macro!(3017); + simple_macro!(3018); + simple_macro!(3019); + simple_macro!(3020); + simple_macro!(3021); + simple_macro!(3022); + simple_macro!(3023); + simple_macro!(3024); + simple_macro!(3025); + simple_macro!(3026); + simple_macro!(3027); + simple_macro!(3028); + simple_macro!(3029); + simple_macro!(3030); + simple_macro!(3031); + simple_macro!(3032); + simple_macro!(3033); + simple_macro!(3034); + simple_macro!(3035); + simple_macro!(3036); + simple_macro!(3037); + simple_macro!(3038); + simple_macro!(3039); + simple_macro!(3040); + simple_macro!(3041); + simple_macro!(3042); + simple_macro!(3043); + simple_macro!(3044); + simple_macro!(3045); + simple_macro!(3046); + simple_macro!(3047); + simple_macro!(3048); + simple_macro!(3049); + simple_macro!(3050); + simple_macro!(3051); + simple_macro!(3052); + simple_macro!(3053); + simple_macro!(3054); + simple_macro!(3055); + simple_macro!(3056); + simple_macro!(3057); + simple_macro!(3058); + simple_macro!(3059); + simple_macro!(3060); + simple_macro!(3061); + simple_macro!(3062); + simple_macro!(3063); + simple_macro!(3064); + simple_macro!(3065); + simple_macro!(3066); + simple_macro!(3067); + simple_macro!(3068); + simple_macro!(3069); + simple_macro!(3070); + simple_macro!(3071); + simple_macro!(3072); + simple_macro!(3073); + simple_macro!(3074); + simple_macro!(3075); + simple_macro!(3076); + simple_macro!(3077); + simple_macro!(3078); + simple_macro!(3079); + simple_macro!(3080); + simple_macro!(3081); + simple_macro!(3082); + simple_macro!(3083); + simple_macro!(3084); + simple_macro!(3085); + simple_macro!(3086); + simple_macro!(3087); + simple_macro!(3088); + simple_macro!(3089); + simple_macro!(3090); + simple_macro!(3091); + simple_macro!(3092); + simple_macro!(3093); + simple_macro!(3094); + simple_macro!(3095); + simple_macro!(3096); + simple_macro!(3097); + simple_macro!(3098); + simple_macro!(3099); + simple_macro!(3100); + simple_macro!(3101); + simple_macro!(3102); + simple_macro!(3103); + simple_macro!(3104); + simple_macro!(3105); + simple_macro!(3106); + simple_macro!(3107); + simple_macro!(3108); + simple_macro!(3109); + simple_macro!(3110); + simple_macro!(3111); + simple_macro!(3112); + simple_macro!(3113); + simple_macro!(3114); + simple_macro!(3115); + simple_macro!(3116); + simple_macro!(3117); + simple_macro!(3118); + simple_macro!(3119); + simple_macro!(3120); + simple_macro!(3121); + simple_macro!(3122); + simple_macro!(3123); + simple_macro!(3124); + simple_macro!(3125); + simple_macro!(3126); + simple_macro!(3127); + simple_macro!(3128); + simple_macro!(3129); + simple_macro!(3130); + simple_macro!(3131); + simple_macro!(3132); + simple_macro!(3133); + simple_macro!(3134); + simple_macro!(3135); + simple_macro!(3136); + simple_macro!(3137); + simple_macro!(3138); + simple_macro!(3139); + simple_macro!(3140); + simple_macro!(3141); + simple_macro!(3142); + simple_macro!(3143); + simple_macro!(3144); + simple_macro!(3145); + simple_macro!(3146); + simple_macro!(3147); + simple_macro!(3148); + simple_macro!(3149); + simple_macro!(3150); + simple_macro!(3151); + simple_macro!(3152); + simple_macro!(3153); + simple_macro!(3154); + simple_macro!(3155); + simple_macro!(3156); + simple_macro!(3157); + simple_macro!(3158); + simple_macro!(3159); + simple_macro!(3160); + simple_macro!(3161); + simple_macro!(3162); + simple_macro!(3163); + simple_macro!(3164); + simple_macro!(3165); + simple_macro!(3166); + simple_macro!(3167); + simple_macro!(3168); + simple_macro!(3169); + simple_macro!(3170); + simple_macro!(3171); + simple_macro!(3172); + simple_macro!(3173); + simple_macro!(3174); + simple_macro!(3175); + simple_macro!(3176); + simple_macro!(3177); + simple_macro!(3178); + simple_macro!(3179); + simple_macro!(3180); + simple_macro!(3181); + simple_macro!(3182); + simple_macro!(3183); + simple_macro!(3184); + simple_macro!(3185); + simple_macro!(3186); + simple_macro!(3187); + simple_macro!(3188); + simple_macro!(3189); + simple_macro!(3190); + simple_macro!(3191); + simple_macro!(3192); + simple_macro!(3193); + simple_macro!(3194); + simple_macro!(3195); + simple_macro!(3196); + simple_macro!(3197); + simple_macro!(3198); + simple_macro!(3199); + simple_macro!(3200); + simple_macro!(3201); + simple_macro!(3202); + simple_macro!(3203); + simple_macro!(3204); + simple_macro!(3205); + simple_macro!(3206); + simple_macro!(3207); + simple_macro!(3208); + simple_macro!(3209); + simple_macro!(3210); + simple_macro!(3211); + simple_macro!(3212); + simple_macro!(3213); + simple_macro!(3214); + simple_macro!(3215); + simple_macro!(3216); + simple_macro!(3217); + simple_macro!(3218); + simple_macro!(3219); + simple_macro!(3220); + simple_macro!(3221); + simple_macro!(3222); + simple_macro!(3223); + simple_macro!(3224); + simple_macro!(3225); + simple_macro!(3226); + simple_macro!(3227); + simple_macro!(3228); + simple_macro!(3229); + simple_macro!(3230); + simple_macro!(3231); + simple_macro!(3232); + simple_macro!(3233); + simple_macro!(3234); + simple_macro!(3235); + simple_macro!(3236); + simple_macro!(3237); + simple_macro!(3238); + simple_macro!(3239); + simple_macro!(3240); + simple_macro!(3241); + simple_macro!(3242); + simple_macro!(3243); + simple_macro!(3244); + simple_macro!(3245); + simple_macro!(3246); + simple_macro!(3247); + simple_macro!(3248); + simple_macro!(3249); + simple_macro!(3250); + simple_macro!(3251); + simple_macro!(3252); + simple_macro!(3253); + simple_macro!(3254); + simple_macro!(3255); + simple_macro!(3256); + simple_macro!(3257); + simple_macro!(3258); + simple_macro!(3259); + simple_macro!(3260); + simple_macro!(3261); + simple_macro!(3262); + simple_macro!(3263); + simple_macro!(3264); + simple_macro!(3265); + simple_macro!(3266); + simple_macro!(3267); + simple_macro!(3268); + simple_macro!(3269); + simple_macro!(3270); + simple_macro!(3271); + simple_macro!(3272); + simple_macro!(3273); + simple_macro!(3274); + simple_macro!(3275); + simple_macro!(3276); + simple_macro!(3277); + simple_macro!(3278); + simple_macro!(3279); + simple_macro!(3280); + simple_macro!(3281); + simple_macro!(3282); + simple_macro!(3283); + simple_macro!(3284); + simple_macro!(3285); + simple_macro!(3286); + simple_macro!(3287); + simple_macro!(3288); + simple_macro!(3289); + simple_macro!(3290); + simple_macro!(3291); + simple_macro!(3292); + simple_macro!(3293); + simple_macro!(3294); + simple_macro!(3295); + simple_macro!(3296); + simple_macro!(3297); + simple_macro!(3298); + simple_macro!(3299); + simple_macro!(3300); + simple_macro!(3301); + simple_macro!(3302); + simple_macro!(3303); + simple_macro!(3304); + simple_macro!(3305); + simple_macro!(3306); + simple_macro!(3307); + simple_macro!(3308); + simple_macro!(3309); + simple_macro!(3310); + simple_macro!(3311); + simple_macro!(3312); + simple_macro!(3313); + simple_macro!(3314); + simple_macro!(3315); + simple_macro!(3316); + simple_macro!(3317); + simple_macro!(3318); + simple_macro!(3319); + simple_macro!(3320); + simple_macro!(3321); + simple_macro!(3322); + simple_macro!(3323); + simple_macro!(3324); + simple_macro!(3325); + simple_macro!(3326); + simple_macro!(3327); + simple_macro!(3328); + simple_macro!(3329); + simple_macro!(3330); + simple_macro!(3331); + simple_macro!(3332); + simple_macro!(3333); + simple_macro!(3334); + simple_macro!(3335); + simple_macro!(3336); + simple_macro!(3337); + simple_macro!(3338); + simple_macro!(3339); + simple_macro!(3340); + simple_macro!(3341); + simple_macro!(3342); + simple_macro!(3343); + simple_macro!(3344); + simple_macro!(3345); + simple_macro!(3346); + simple_macro!(3347); + simple_macro!(3348); + simple_macro!(3349); + simple_macro!(3350); + simple_macro!(3351); + simple_macro!(3352); + simple_macro!(3353); + simple_macro!(3354); + simple_macro!(3355); + simple_macro!(3356); + simple_macro!(3357); + simple_macro!(3358); + simple_macro!(3359); + simple_macro!(3360); + simple_macro!(3361); + simple_macro!(3362); + simple_macro!(3363); + simple_macro!(3364); + simple_macro!(3365); + simple_macro!(3366); + simple_macro!(3367); + simple_macro!(3368); + simple_macro!(3369); + simple_macro!(3370); + simple_macro!(3371); + simple_macro!(3372); + simple_macro!(3373); + simple_macro!(3374); + simple_macro!(3375); + simple_macro!(3376); + simple_macro!(3377); + simple_macro!(3378); + simple_macro!(3379); + simple_macro!(3380); + simple_macro!(3381); + simple_macro!(3382); + simple_macro!(3383); + simple_macro!(3384); + simple_macro!(3385); + simple_macro!(3386); + simple_macro!(3387); + simple_macro!(3388); + simple_macro!(3389); + simple_macro!(3390); + simple_macro!(3391); + simple_macro!(3392); + simple_macro!(3393); + simple_macro!(3394); + simple_macro!(3395); + simple_macro!(3396); + simple_macro!(3397); + simple_macro!(3398); + simple_macro!(3399); + simple_macro!(3400); + simple_macro!(3401); + simple_macro!(3402); + simple_macro!(3403); + simple_macro!(3404); + simple_macro!(3405); + simple_macro!(3406); + simple_macro!(3407); + simple_macro!(3408); + simple_macro!(3409); + simple_macro!(3410); + simple_macro!(3411); + simple_macro!(3412); + simple_macro!(3413); + simple_macro!(3414); + simple_macro!(3415); + simple_macro!(3416); + simple_macro!(3417); + simple_macro!(3418); + simple_macro!(3419); + simple_macro!(3420); + simple_macro!(3421); + simple_macro!(3422); + simple_macro!(3423); + simple_macro!(3424); + simple_macro!(3425); + simple_macro!(3426); + simple_macro!(3427); + simple_macro!(3428); + simple_macro!(3429); + simple_macro!(3430); + simple_macro!(3431); + simple_macro!(3432); + simple_macro!(3433); + simple_macro!(3434); + simple_macro!(3435); + simple_macro!(3436); + simple_macro!(3437); + simple_macro!(3438); + simple_macro!(3439); + simple_macro!(3440); + simple_macro!(3441); + simple_macro!(3442); + simple_macro!(3443); + simple_macro!(3444); + simple_macro!(3445); + simple_macro!(3446); + simple_macro!(3447); + simple_macro!(3448); + simple_macro!(3449); + simple_macro!(3450); + simple_macro!(3451); + simple_macro!(3452); + simple_macro!(3453); + simple_macro!(3454); + simple_macro!(3455); + simple_macro!(3456); + simple_macro!(3457); + simple_macro!(3458); + simple_macro!(3459); + simple_macro!(3460); + simple_macro!(3461); + simple_macro!(3462); + simple_macro!(3463); + simple_macro!(3464); + simple_macro!(3465); + simple_macro!(3466); + simple_macro!(3467); + simple_macro!(3468); + simple_macro!(3469); + simple_macro!(3470); + simple_macro!(3471); + simple_macro!(3472); + simple_macro!(3473); + simple_macro!(3474); + simple_macro!(3475); + simple_macro!(3476); + simple_macro!(3477); + simple_macro!(3478); + simple_macro!(3479); + simple_macro!(3480); + simple_macro!(3481); + simple_macro!(3482); + simple_macro!(3483); + simple_macro!(3484); + simple_macro!(3485); + simple_macro!(3486); + simple_macro!(3487); + simple_macro!(3488); + simple_macro!(3489); + simple_macro!(3490); + simple_macro!(3491); + simple_macro!(3492); + simple_macro!(3493); + simple_macro!(3494); + simple_macro!(3495); + simple_macro!(3496); + simple_macro!(3497); + simple_macro!(3498); + simple_macro!(3499); + simple_macro!(3500); + simple_macro!(3501); + simple_macro!(3502); + simple_macro!(3503); + simple_macro!(3504); + simple_macro!(3505); + simple_macro!(3506); + simple_macro!(3507); + simple_macro!(3508); + simple_macro!(3509); + simple_macro!(3510); + simple_macro!(3511); + simple_macro!(3512); + simple_macro!(3513); + simple_macro!(3514); + simple_macro!(3515); + simple_macro!(3516); + simple_macro!(3517); + simple_macro!(3518); + simple_macro!(3519); + simple_macro!(3520); + simple_macro!(3521); + simple_macro!(3522); + simple_macro!(3523); + simple_macro!(3524); + simple_macro!(3525); + simple_macro!(3526); + simple_macro!(3527); + simple_macro!(3528); + simple_macro!(3529); + simple_macro!(3530); + simple_macro!(3531); + simple_macro!(3532); + simple_macro!(3533); + simple_macro!(3534); + simple_macro!(3535); + simple_macro!(3536); + simple_macro!(3537); + simple_macro!(3538); + simple_macro!(3539); + simple_macro!(3540); + simple_macro!(3541); + simple_macro!(3542); + simple_macro!(3543); + simple_macro!(3544); + simple_macro!(3545); + simple_macro!(3546); + simple_macro!(3547); + simple_macro!(3548); + simple_macro!(3549); + simple_macro!(3550); + simple_macro!(3551); + simple_macro!(3552); + simple_macro!(3553); + simple_macro!(3554); + simple_macro!(3555); + simple_macro!(3556); + simple_macro!(3557); + simple_macro!(3558); + simple_macro!(3559); + simple_macro!(3560); + simple_macro!(3561); + simple_macro!(3562); + simple_macro!(3563); + simple_macro!(3564); + simple_macro!(3565); + simple_macro!(3566); + simple_macro!(3567); + simple_macro!(3568); + simple_macro!(3569); + simple_macro!(3570); + simple_macro!(3571); + simple_macro!(3572); + simple_macro!(3573); + simple_macro!(3574); + simple_macro!(3575); + simple_macro!(3576); + simple_macro!(3577); + simple_macro!(3578); + simple_macro!(3579); + simple_macro!(3580); + simple_macro!(3581); + simple_macro!(3582); + simple_macro!(3583); + simple_macro!(3584); + simple_macro!(3585); + simple_macro!(3586); + simple_macro!(3587); + simple_macro!(3588); + simple_macro!(3589); + simple_macro!(3590); + simple_macro!(3591); + simple_macro!(3592); + simple_macro!(3593); + simple_macro!(3594); + simple_macro!(3595); + simple_macro!(3596); + simple_macro!(3597); + simple_macro!(3598); + simple_macro!(3599); + simple_macro!(3600); + simple_macro!(3601); + simple_macro!(3602); + simple_macro!(3603); + simple_macro!(3604); + simple_macro!(3605); + simple_macro!(3606); + simple_macro!(3607); + simple_macro!(3608); + simple_macro!(3609); + simple_macro!(3610); + simple_macro!(3611); + simple_macro!(3612); + simple_macro!(3613); + simple_macro!(3614); + simple_macro!(3615); + simple_macro!(3616); + simple_macro!(3617); + simple_macro!(3618); + simple_macro!(3619); + simple_macro!(3620); + simple_macro!(3621); + simple_macro!(3622); + simple_macro!(3623); + simple_macro!(3624); + simple_macro!(3625); + simple_macro!(3626); + simple_macro!(3627); + simple_macro!(3628); + simple_macro!(3629); + simple_macro!(3630); + simple_macro!(3631); + simple_macro!(3632); + simple_macro!(3633); + simple_macro!(3634); + simple_macro!(3635); + simple_macro!(3636); + simple_macro!(3637); + simple_macro!(3638); + simple_macro!(3639); + simple_macro!(3640); + simple_macro!(3641); + simple_macro!(3642); + simple_macro!(3643); + simple_macro!(3644); + simple_macro!(3645); + simple_macro!(3646); + simple_macro!(3647); + simple_macro!(3648); + simple_macro!(3649); + simple_macro!(3650); + simple_macro!(3651); + simple_macro!(3652); + simple_macro!(3653); + simple_macro!(3654); + simple_macro!(3655); + simple_macro!(3656); + simple_macro!(3657); + simple_macro!(3658); + simple_macro!(3659); + simple_macro!(3660); + simple_macro!(3661); + simple_macro!(3662); + simple_macro!(3663); + simple_macro!(3664); + simple_macro!(3665); + simple_macro!(3666); + simple_macro!(3667); + simple_macro!(3668); + simple_macro!(3669); + simple_macro!(3670); + simple_macro!(3671); + simple_macro!(3672); + simple_macro!(3673); + simple_macro!(3674); + simple_macro!(3675); + simple_macro!(3676); + simple_macro!(3677); + simple_macro!(3678); + simple_macro!(3679); + simple_macro!(3680); + simple_macro!(3681); + simple_macro!(3682); + simple_macro!(3683); + simple_macro!(3684); + simple_macro!(3685); + simple_macro!(3686); + simple_macro!(3687); + simple_macro!(3688); + simple_macro!(3689); + simple_macro!(3690); + simple_macro!(3691); + simple_macro!(3692); + simple_macro!(3693); + simple_macro!(3694); + simple_macro!(3695); + simple_macro!(3696); + simple_macro!(3697); + simple_macro!(3698); + simple_macro!(3699); + simple_macro!(3700); + simple_macro!(3701); + simple_macro!(3702); + simple_macro!(3703); + simple_macro!(3704); + simple_macro!(3705); + simple_macro!(3706); + simple_macro!(3707); + simple_macro!(3708); + simple_macro!(3709); + simple_macro!(3710); + simple_macro!(3711); + simple_macro!(3712); + simple_macro!(3713); + simple_macro!(3714); + simple_macro!(3715); + simple_macro!(3716); + simple_macro!(3717); + simple_macro!(3718); + simple_macro!(3719); + simple_macro!(3720); + simple_macro!(3721); + simple_macro!(3722); + simple_macro!(3723); + simple_macro!(3724); + simple_macro!(3725); + simple_macro!(3726); + simple_macro!(3727); + simple_macro!(3728); + simple_macro!(3729); + simple_macro!(3730); + simple_macro!(3731); + simple_macro!(3732); + simple_macro!(3733); + simple_macro!(3734); + simple_macro!(3735); + simple_macro!(3736); + simple_macro!(3737); + simple_macro!(3738); + simple_macro!(3739); + simple_macro!(3740); + simple_macro!(3741); + simple_macro!(3742); + simple_macro!(3743); + simple_macro!(3744); + simple_macro!(3745); + simple_macro!(3746); + simple_macro!(3747); + simple_macro!(3748); + simple_macro!(3749); + simple_macro!(3750); + simple_macro!(3751); + simple_macro!(3752); + simple_macro!(3753); + simple_macro!(3754); + simple_macro!(3755); + simple_macro!(3756); + simple_macro!(3757); + simple_macro!(3758); + simple_macro!(3759); + simple_macro!(3760); + simple_macro!(3761); + simple_macro!(3762); + simple_macro!(3763); + simple_macro!(3764); + simple_macro!(3765); + simple_macro!(3766); + simple_macro!(3767); + simple_macro!(3768); + simple_macro!(3769); + simple_macro!(3770); + simple_macro!(3771); + simple_macro!(3772); + simple_macro!(3773); + simple_macro!(3774); + simple_macro!(3775); + simple_macro!(3776); + simple_macro!(3777); + simple_macro!(3778); + simple_macro!(3779); + simple_macro!(3780); + simple_macro!(3781); + simple_macro!(3782); + simple_macro!(3783); + simple_macro!(3784); + simple_macro!(3785); + simple_macro!(3786); + simple_macro!(3787); + simple_macro!(3788); + simple_macro!(3789); + simple_macro!(3790); + simple_macro!(3791); + simple_macro!(3792); + simple_macro!(3793); + simple_macro!(3794); + simple_macro!(3795); + simple_macro!(3796); + simple_macro!(3797); + simple_macro!(3798); + simple_macro!(3799); + simple_macro!(3800); + simple_macro!(3801); + simple_macro!(3802); + simple_macro!(3803); + simple_macro!(3804); + simple_macro!(3805); + simple_macro!(3806); + simple_macro!(3807); + simple_macro!(3808); + simple_macro!(3809); + simple_macro!(3810); + simple_macro!(3811); + simple_macro!(3812); + simple_macro!(3813); + simple_macro!(3814); + simple_macro!(3815); + simple_macro!(3816); + simple_macro!(3817); + simple_macro!(3818); + simple_macro!(3819); + simple_macro!(3820); + simple_macro!(3821); + simple_macro!(3822); + simple_macro!(3823); + simple_macro!(3824); + simple_macro!(3825); + simple_macro!(3826); + simple_macro!(3827); + simple_macro!(3828); + simple_macro!(3829); + simple_macro!(3830); + simple_macro!(3831); + simple_macro!(3832); + simple_macro!(3833); + simple_macro!(3834); + simple_macro!(3835); + simple_macro!(3836); + simple_macro!(3837); + simple_macro!(3838); + simple_macro!(3839); + simple_macro!(3840); + simple_macro!(3841); + simple_macro!(3842); + simple_macro!(3843); + simple_macro!(3844); + simple_macro!(3845); + simple_macro!(3846); + simple_macro!(3847); + simple_macro!(3848); + simple_macro!(3849); + simple_macro!(3850); + simple_macro!(3851); + simple_macro!(3852); + simple_macro!(3853); + simple_macro!(3854); + simple_macro!(3855); + simple_macro!(3856); + simple_macro!(3857); + simple_macro!(3858); + simple_macro!(3859); + simple_macro!(3860); + simple_macro!(3861); + simple_macro!(3862); + simple_macro!(3863); + simple_macro!(3864); + simple_macro!(3865); + simple_macro!(3866); + simple_macro!(3867); + simple_macro!(3868); + simple_macro!(3869); + simple_macro!(3870); + simple_macro!(3871); + simple_macro!(3872); + simple_macro!(3873); + simple_macro!(3874); + simple_macro!(3875); + simple_macro!(3876); + simple_macro!(3877); + simple_macro!(3878); + simple_macro!(3879); + simple_macro!(3880); + simple_macro!(3881); + simple_macro!(3882); + simple_macro!(3883); + simple_macro!(3884); + simple_macro!(3885); + simple_macro!(3886); + simple_macro!(3887); + simple_macro!(3888); + simple_macro!(3889); + simple_macro!(3890); + simple_macro!(3891); + simple_macro!(3892); + simple_macro!(3893); + simple_macro!(3894); + simple_macro!(3895); + simple_macro!(3896); + simple_macro!(3897); + simple_macro!(3898); + simple_macro!(3899); + simple_macro!(3900); + simple_macro!(3901); + simple_macro!(3902); + simple_macro!(3903); + simple_macro!(3904); + simple_macro!(3905); + simple_macro!(3906); + simple_macro!(3907); + simple_macro!(3908); + simple_macro!(3909); + simple_macro!(3910); + simple_macro!(3911); + simple_macro!(3912); + simple_macro!(3913); + simple_macro!(3914); + simple_macro!(3915); + simple_macro!(3916); + simple_macro!(3917); + simple_macro!(3918); + simple_macro!(3919); + simple_macro!(3920); + simple_macro!(3921); + simple_macro!(3922); + simple_macro!(3923); + simple_macro!(3924); + simple_macro!(3925); + simple_macro!(3926); + simple_macro!(3927); + simple_macro!(3928); + simple_macro!(3929); + simple_macro!(3930); + simple_macro!(3931); + simple_macro!(3932); + simple_macro!(3933); + simple_macro!(3934); + simple_macro!(3935); + simple_macro!(3936); + simple_macro!(3937); + simple_macro!(3938); + simple_macro!(3939); + simple_macro!(3940); + simple_macro!(3941); + simple_macro!(3942); + simple_macro!(3943); + simple_macro!(3944); + simple_macro!(3945); + simple_macro!(3946); + simple_macro!(3947); + simple_macro!(3948); + simple_macro!(3949); + simple_macro!(3950); + simple_macro!(3951); + simple_macro!(3952); + simple_macro!(3953); + simple_macro!(3954); + simple_macro!(3955); + simple_macro!(3956); + simple_macro!(3957); + simple_macro!(3958); + simple_macro!(3959); + simple_macro!(3960); + simple_macro!(3961); + simple_macro!(3962); + simple_macro!(3963); + simple_macro!(3964); + simple_macro!(3965); + simple_macro!(3966); + simple_macro!(3967); + simple_macro!(3968); + simple_macro!(3969); + simple_macro!(3970); + simple_macro!(3971); + simple_macro!(3972); + simple_macro!(3973); + simple_macro!(3974); + simple_macro!(3975); + simple_macro!(3976); + simple_macro!(3977); + simple_macro!(3978); + simple_macro!(3979); + simple_macro!(3980); + simple_macro!(3981); + simple_macro!(3982); + simple_macro!(3983); + simple_macro!(3984); + simple_macro!(3985); + simple_macro!(3986); + simple_macro!(3987); + simple_macro!(3988); + simple_macro!(3989); + simple_macro!(3990); + simple_macro!(3991); + simple_macro!(3992); + simple_macro!(3993); + simple_macro!(3994); + simple_macro!(3995); + simple_macro!(3996); + simple_macro!(3997); + simple_macro!(3998); + simple_macro!(3999); + simple_macro!(4000); + simple_macro!(4001); + simple_macro!(4002); + simple_macro!(4003); + simple_macro!(4004); + simple_macro!(4005); + simple_macro!(4006); + simple_macro!(4007); + simple_macro!(4008); + simple_macro!(4009); + simple_macro!(4010); + simple_macro!(4011); + simple_macro!(4012); + simple_macro!(4013); + simple_macro!(4014); + simple_macro!(4015); + simple_macro!(4016); + simple_macro!(4017); + simple_macro!(4018); + simple_macro!(4019); + simple_macro!(4020); + simple_macro!(4021); + simple_macro!(4022); + simple_macro!(4023); + simple_macro!(4024); + simple_macro!(4025); + simple_macro!(4026); + simple_macro!(4027); + simple_macro!(4028); + simple_macro!(4029); + simple_macro!(4030); + simple_macro!(4031); + simple_macro!(4032); + simple_macro!(4033); + simple_macro!(4034); + simple_macro!(4035); + simple_macro!(4036); + simple_macro!(4037); + simple_macro!(4038); + simple_macro!(4039); + simple_macro!(4040); + simple_macro!(4041); + simple_macro!(4042); + simple_macro!(4043); + simple_macro!(4044); + simple_macro!(4045); + simple_macro!(4046); + simple_macro!(4047); + simple_macro!(4048); + simple_macro!(4049); + simple_macro!(4050); + simple_macro!(4051); + simple_macro!(4052); + simple_macro!(4053); + simple_macro!(4054); + simple_macro!(4055); + simple_macro!(4056); + simple_macro!(4057); + simple_macro!(4058); + simple_macro!(4059); + simple_macro!(4060); + simple_macro!(4061); + simple_macro!(4062); + simple_macro!(4063); + simple_macro!(4064); + simple_macro!(4065); + simple_macro!(4066); + simple_macro!(4067); + simple_macro!(4068); + simple_macro!(4069); + simple_macro!(4070); + simple_macro!(4071); + simple_macro!(4072); + simple_macro!(4073); + simple_macro!(4074); + simple_macro!(4075); + simple_macro!(4076); + simple_macro!(4077); + simple_macro!(4078); + simple_macro!(4079); + simple_macro!(4080); + simple_macro!(4081); + simple_macro!(4082); + simple_macro!(4083); + simple_macro!(4084); + simple_macro!(4085); + simple_macro!(4086); + simple_macro!(4087); + simple_macro!(4088); + simple_macro!(4089); + simple_macro!(4090); + simple_macro!(4091); + simple_macro!(4092); + simple_macro!(4093); + simple_macro!(4094); + simple_macro!(4095); + simple_macro!(4096); + simple_macro!(4097); +} + +fn main() { + uncollapsed_debuginfo(); +} diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs index b35af76da3e..af1c20976d7 100644 --- a/tests/ui/delegation/unsupported.rs +++ b/tests/ui/delegation/unsupported.rs @@ -10,15 +10,11 @@ mod opaque { mod to_reuse { use super::Trait; - pub fn opaque_ret() -> impl Trait { unimplemented!() } - //~^ warn: this function depends on never type fallback being `()` - //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + pub fn opaque_ret() -> impl Trait { () } } trait ToReuse { - fn opaque_ret() -> impl Trait { unimplemented!() } - //~^ warn: this function depends on never type fallback being `()` - //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + fn opaque_ret() -> impl Trait { () } } // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls. diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr index 9391763dca2..2b0bcf9d84e 100644 --- a/tests/ui/delegation/unsupported.stderr +++ b/tests/ui/delegation/unsupported.stderr @@ -1,74 +1,43 @@ -error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:25:5: 25:24>::{synthetic#0}` - --> $DIR/unsupported.rs:26:25 +error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:21:5: 21:24>::{synthetic#0}` + --> $DIR/unsupported.rs:22:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/unsupported.rs:26:25 + --> $DIR/unsupported.rs:22:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:25:5: 25:24>::{synthetic#0}`, completing the cycle -note: cycle used when checking that `opaque::<impl at $DIR/unsupported.rs:25:5: 25:24>` is well-formed - --> $DIR/unsupported.rs:25:5 + = note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:21:5: 21:24>::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::<impl at $DIR/unsupported.rs:21:5: 21:24>` is well-formed + --> $DIR/unsupported.rs:21:5 | LL | impl ToReuse for u8 { | ^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -warning: this function depends on never type fallback being `()` - --> $DIR/unsupported.rs:13:9 - | -LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> - = help: specify the types explicitly -note: in edition 2024, the requirement `!: opaque::Trait` will fail - --> $DIR/unsupported.rs:13:32 - | -LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^ - = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default - -warning: this function depends on never type fallback being `()` - --> $DIR/unsupported.rs:19:9 - | -LL | fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> - = help: specify the types explicitly -note: in edition 2024, the requirement `!: opaque::Trait` will fail - --> $DIR/unsupported.rs:19:28 - | -LL | fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^ - -error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:28:5: 28:25>::{synthetic#0}` - --> $DIR/unsupported.rs:29:24 +error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:24:5: 24:25>::{synthetic#0}` + --> $DIR/unsupported.rs:25:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/unsupported.rs:29:24 + --> $DIR/unsupported.rs:25:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:28:5: 28:25>::{synthetic#0}`, completing the cycle -note: cycle used when checking that `opaque::<impl at $DIR/unsupported.rs:28:5: 28:25>` is well-formed - --> $DIR/unsupported.rs:28:5 + = note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:24:5: 24:25>::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::<impl at $DIR/unsupported.rs:24:5: 24:25>` is well-formed + --> $DIR/unsupported.rs:24:5 | LL | impl ToReuse for u16 { | ^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: recursive delegation is not supported yet - --> $DIR/unsupported.rs:42:22 + --> $DIR/unsupported.rs:38:22 | LL | pub reuse to_reuse2::foo; | --- callee defined here @@ -77,14 +46,14 @@ LL | reuse to_reuse1::foo; | ^^^ error[E0283]: type annotations needed - --> $DIR/unsupported.rs:52:18 + --> $DIR/unsupported.rs:48:18 | LL | reuse Trait::foo; | ^^^ cannot infer type | = note: cannot satisfy `_: effects::Trait` -error: aborting due to 4 previous errors; 2 warnings emitted +error: aborting due to 4 previous errors Some errors have detailed explanations: E0283, E0391. For more information about an error, try `rustc --explain E0283`. 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/drop/lint-tail-expr-drop-order-gated.rs b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs index fde542c756f..508e7bdbf99 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order-gated.rs +++ b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs @@ -1,9 +1,10 @@ -// This test is to demonstrate that the lint is gated behind Edition and -// is triggered only for Edition 2021 and before. +// This test ensures that `tail_expr_drop_order` does not activate in case Edition 2024 is used +// because this is a migration lint. +// Only `cargo fix --edition 2024` shall activate this lint. //@ check-pass -//@ edition: 2024 //@ compile-flags: -Z unstable-options +//@ edition: 2024 #![deny(tail_expr_drop_order)] diff --git a/tests/ui/drop/lint-tail-expr-drop-order.rs b/tests/ui/drop/lint-tail-expr-drop-order.rs index d61abae5187..0fabc1f085c 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order.rs +++ b/tests/ui/drop/lint-tail-expr-drop-order.rs @@ -1,13 +1,26 @@ -//@ edition: 2021 - // Edition 2024 lint for change in drop order at tail expression // This lint is to capture potential change in program semantics // due to implementation of RFC 3606 <https://github.com/rust-lang/rfcs/pull/3606> +//@ edition: 2021 +//@ build-fail -#![deny(tail_expr_drop_order)] +#![deny(tail_expr_drop_order)] //~ NOTE: the lint level is defined here +#![allow(dropping_copy_types)] struct LoudDropper; impl Drop for LoudDropper { + //~^ NOTE: `#1` invokes this custom destructor + //~| NOTE: `x` invokes this custom destructor + //~| NOTE: `#1` invokes this custom destructor + //~| NOTE: `x` invokes this custom destructor + //~| NOTE: `#1` invokes this custom destructor + //~| NOTE: `x` invokes this custom destructor + //~| NOTE: `#1` invokes this custom destructor + //~| NOTE: `x` invokes this custom destructor + //~| NOTE: `#1` invokes this custom destructor + //~| NOTE: `future` invokes this custom destructor + //~| NOTE: `_x` invokes this custom destructor + //~| NOTE: `#1` invokes this custom destructor fn drop(&mut self) { // This destructor should be considered significant because it is a custom destructor // and we will assume that the destructor can generate side effects arbitrarily so that @@ -23,30 +36,70 @@ impl LoudDropper { fn should_lint() -> i32 { let x = LoudDropper; + //~^ NOTE: `x` calls a custom destructor + //~| NOTE: `x` will be dropped later as of Edition 2024 // Should lint x.get() + LoudDropper.get() - //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 + //~^ ERROR: relative drop order changing in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 } +//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement -fn should_lint_closure() -> impl FnOnce() -> i32 { +fn should_not_lint_closure() -> impl FnOnce() -> i32 { let x = LoudDropper; - move || x.get() + LoudDropper.get() - //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 - //~| WARN: this changes meaning in Rust 2024 + move || { + // Should not lint because ... + x.get() + LoudDropper.get() + } + // ^ closure captures like `x` are always dropped last by contract +} + +fn should_lint_in_nested_items() { + fn should_lint_me() -> i32 { + let x = LoudDropper; + //~^ NOTE: `x` calls a custom destructor + //~| NOTE: `x` will be dropped later as of Edition 2024 + // Should lint + x.get() + LoudDropper.get() + //~^ ERROR: relative drop order changing in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 + } + //~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement } +fn should_not_lint_params(x: LoudDropper) -> i32 { + // Should not lint because ... + x.get() + LoudDropper.get() +} +// ^ function parameters like `x` are always dropped last + fn should_not_lint() -> i32 { let x = LoudDropper; // Should not lint x.get() } -fn should_not_lint_in_nested_block() -> i32 { +fn should_lint_in_nested_block() -> i32 { let x = LoudDropper; - // Should not lint because Edition 2021 drops temporaries in blocks earlier already + //~^ NOTE: `x` calls a custom destructor + //~| NOTE: `x` will be dropped later as of Edition 2024 { LoudDropper.get() } + //~^ ERROR: relative drop order changing in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 } +//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement fn should_not_lint_in_match_arm() -> i32 { let x = LoudDropper; @@ -56,14 +109,144 @@ fn should_not_lint_in_match_arm() -> i32 { } } -fn should_lint_in_nested_items() { - fn should_lint_me() -> i32 { +fn should_not_lint_when_consumed() -> (LoudDropper, i32) { + let x = LoudDropper; + // Should not lint because `LoudDropper` is consumed by the return value + (LoudDropper, x.get()) +} + +struct MyAdt { + a: LoudDropper, + b: LoudDropper, +} + +fn should_not_lint_when_consumed_in_ctor() -> MyAdt { + let a = LoudDropper; + // Should not lint + MyAdt { a, b: LoudDropper } +} + +fn should_not_lint_when_moved() -> i32 { + let x = LoudDropper; + drop(x); + // Should not lint because `x` is not live + LoudDropper.get() +} + +fn should_lint_into_async_body() -> i32 { + async fn f() { + async fn f() {} let x = LoudDropper; - // Should lint - x.get() + LoudDropper.get() - //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 - //~| WARN: this changes meaning in Rust 2024 + f().await; + drop(x); + } + + let future = f(); + //~^ NOTE: `future` calls a custom destructor + //~| NOTE: `future` will be dropped later as of Edition 2024 + LoudDropper.get() + //~^ ERROR: relative drop order changing in Rust 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 +} +//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement + +fn should_lint_generics<T: Default>() -> &'static str { + fn extract<T>(_: &T) -> &'static str { + todo!() + } + let x = T::default(); + //~^ NOTE: `x` calls a custom destructor + //~| NOTE: `x` will be dropped later as of Edition 2024 + extract(&T::default()) + //~^ ERROR: relative drop order changing in Rust 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 +} +//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement + +fn should_lint_adt() -> i32 { + let x: Result<LoudDropper, ()> = Ok(LoudDropper); + //~^ NOTE: `x` calls a custom destructor + //~| NOTE: `x` will be dropped later as of Edition 2024 + LoudDropper.get() + //~^ ERROR: relative drop order changing in Rust 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 +} +//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement + +fn should_not_lint_insign_dtor() -> i32 { + let x = String::new(); + LoudDropper.get() +} + +fn should_lint_with_dtor_span() -> i32 { + struct LoudDropper3; + impl Drop for LoudDropper3 { + //~^ NOTE: `#1` invokes this custom destructor + fn drop(&mut self) { + println!("loud drop"); + } } + impl LoudDropper3 { + fn get(&self) -> i32 { + 0 + } + } + struct LoudDropper2; + impl Drop for LoudDropper2 { + //~^ NOTE: `x` invokes this custom destructor + fn drop(&mut self) { + println!("loud drop"); + } + } + impl LoudDropper2 { + fn get(&self) -> i32 { + 0 + } + } + + let x = LoudDropper2; + //~^ NOTE: `x` calls a custom destructor + //~| NOTE: `x` will be dropped later as of Edition 2024 + LoudDropper3.get() + //~^ ERROR: relative drop order changing in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 +} +//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement + +fn should_lint_with_transient_drops() { + drop(( + { + LoudDropper.get() + //~^ ERROR: relative drop order changing in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 + }, + { + let _x = LoudDropper; + //~^ NOTE: `_x` calls a custom destructor + //~| NOTE: `_x` will be dropped later as of Edition 2024 + }, + )); + //~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement } fn main() {} diff --git a/tests/ui/drop/lint-tail-expr-drop-order.stderr b/tests/ui/drop/lint-tail-expr-drop-order.stderr index 6775c4ce6d1..f0da24605e6 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order.stderr +++ b/tests/ui/drop/lint-tail-expr-drop-order.stderr @@ -1,42 +1,335 @@ -error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 - --> $DIR/lint-tail-expr-drop-order.rs:27:15 +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:42:15 | LL | let x = LoudDropper; - | - these values have significant drop implementation and will observe changes in drop order under Edition 2024 -LL | // Should lint + | - + | | + | `x` calls a custom destructor + | `x` will be dropped later as of Edition 2024 +... LL | x.get() + LoudDropper.get() | ^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | } + | - now the temporary value is dropped here, before the local variables in the block or statement | = warning: this changes meaning in Rust 2024 = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739> +note: `#1` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ +note: `x` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages note: the lint level is defined here --> $DIR/lint-tail-expr-drop-order.rs:7:9 | LL | #![deny(tail_expr_drop_order)] | ^^^^^^^^^^^^^^^^^^^^ -error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 - --> $DIR/lint-tail-expr-drop-order.rs:34:23 +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:67:19 + | +LL | let x = LoudDropper; + | - + | | + | `x` calls a custom destructor + | `x` will be dropped later as of Edition 2024 +... +LL | x.get() + LoudDropper.get() + | ^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | } + | - now the temporary value is dropped here, before the local variables in the block or statement + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739> +note: `#1` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ +note: `x` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:94:7 | LL | let x = LoudDropper; - | - these values have significant drop implementation and will observe changes in drop order under Edition 2024 -LL | move || x.get() + LoudDropper.get() - | ^^^^^^^^^^^ + | - + | | + | `x` calls a custom destructor + | `x` will be dropped later as of Edition 2024 +... +LL | { LoudDropper.get() } + | ^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | } + | - now the temporary value is dropped here, before the local variables in the block or statement | = warning: this changes meaning in Rust 2024 = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739> +note: `#1` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ +note: `x` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages -error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 - --> $DIR/lint-tail-expr-drop-order.rs:63:19 +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:147:5 | -LL | let x = LoudDropper; - | - these values have significant drop implementation and will observe changes in drop order under Edition 2024 -LL | // Should lint -LL | x.get() + LoudDropper.get() - | ^^^^^^^^^^^ +LL | let future = f(); + | ------ + | | + | `future` calls a custom destructor + | `future` will be dropped later as of Edition 2024 +... +LL | LoudDropper.get() + | ^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | } + | - now the temporary value is dropped here, before the local variables in the block or statement | = warning: this changes meaning in Rust 2024 = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739> +note: `#1` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ +note: `future` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:164:14 + | +LL | let x = T::default(); + | - + | | + | `x` calls a custom destructor + | `x` will be dropped later as of Edition 2024 +... +LL | extract(&T::default()) + | ^^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | } + | - now the temporary value is dropped here, before the local variables in the block or statement + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739> + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:178:5 + | +LL | let x: Result<LoudDropper, ()> = Ok(LoudDropper); + | - + | | + | `x` calls a custom destructor + | `x` will be dropped later as of Edition 2024 +... +LL | LoudDropper.get() + | ^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | } + | - now the temporary value is dropped here, before the local variables in the block or statement + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739> +note: `#1` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ +note: `x` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:222:5 + | +LL | let x = LoudDropper2; + | - + | | + | `x` calls a custom destructor + | `x` will be dropped later as of Edition 2024 +... +LL | LoudDropper3.get() + | ^^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | } + | - now the temporary value is dropped here, before the local variables in the block or statement + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739> +note: `#1` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:195:5 + | +LL | / impl Drop for LoudDropper3 { +LL | | +LL | | fn drop(&mut self) { +LL | | println!("loud drop"); +LL | | } +LL | | } + | |_____^ +note: `x` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:207:5 + | +LL | / impl Drop for LoudDropper2 { +LL | | +LL | | fn drop(&mut self) { +LL | | println!("loud drop"); +LL | | } +LL | | } + | |_____^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:235:13 + | +LL | LoudDropper.get() + | ^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | let _x = LoudDropper; + | -- + | | + | `_x` calls a custom destructor + | `_x` will be dropped later as of Edition 2024 +... +LL | )); + | - now the temporary value is dropped here, before the local variables in the block or statement + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739> +note: `#1` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ +note: `_x` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages -error: aborting due to 3 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/dyn-star/async-block-dyn-star.rs b/tests/ui/dyn-star/async-block-dyn-star.rs new file mode 100644 index 00000000000..9bffd6c6725 --- /dev/null +++ b/tests/ui/dyn-star/async-block-dyn-star.rs @@ -0,0 +1,9 @@ +//@ edition:2018 + +#![feature(dyn_star, const_async_blocks)] +//~^ WARN the feature `dyn_star` is incomplete + +static S: dyn* Send + Sync = async { 42 }; +//~^ needs to have the same ABI as a pointer + +pub fn main() {} diff --git a/tests/ui/dyn-star/async-block-dyn-star.stderr b/tests/ui/dyn-star/async-block-dyn-star.stderr new file mode 100644 index 00000000000..f62c85c0ad2 --- /dev/null +++ b/tests/ui/dyn-star/async-block-dyn-star.stderr @@ -0,0 +1,20 @@ +warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/async-block-dyn-star.rs:3:12 + | +LL | #![feature(dyn_star, const_async_blocks)] + | ^^^^^^^^ + | + = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to have the same ABI as a pointer + --> $DIR/async-block-dyn-star.rs:6:30 + | +LL | static S: dyn* Send + Sync = async { 42 }; + | ^^^^^^^^^^^^ `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to be a pointer-like type + | + = help: the trait `PointerLike` is not implemented for `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr index 7b5ea7bb707..a0aff69f396 100644 --- a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr +++ b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr @@ -1,14 +1,17 @@ error[E0277]: `&T` needs to have the same ABI as a pointer --> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15 | +LL | fn polymorphic<T: Debug + ?Sized>(t: &T) { + | - this type parameter needs to be `Sized` LL | dyn_debug(t); | ^ `&T` needs to be a pointer-like type | - = help: the trait `PointerLike` is not implemented for `&T` -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + = note: required for `&T` to implement `PointerLike` +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn polymorphic<T: Debug + ?Sized>(t: &T) { +LL + fn polymorphic<T: Debug>(t: &T) { | -LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike { - | +++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr index 7b5ea7bb707..a0aff69f396 100644 --- a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr +++ b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr @@ -1,14 +1,17 @@ error[E0277]: `&T` needs to have the same ABI as a pointer --> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15 | +LL | fn polymorphic<T: Debug + ?Sized>(t: &T) { + | - this type parameter needs to be `Sized` LL | dyn_debug(t); | ^ `&T` needs to be a pointer-like type | - = help: the trait `PointerLike` is not implemented for `&T` -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + = note: required for `&T` to implement `PointerLike` +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn polymorphic<T: Debug + ?Sized>(t: &T) { +LL + fn polymorphic<T: Debug>(t: &T) { | -LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike { - | +++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/dyn-star/drop.rs b/tests/ui/dyn-star/drop.rs index ca86f1b5b01..bc746331527 100644 --- a/tests/ui/dyn-star/drop.rs +++ b/tests/ui/dyn-star/drop.rs @@ -1,13 +1,18 @@ //@ run-pass //@ check-run-results -#![feature(dyn_star)] +#![feature(dyn_star, pointer_like_trait)] #![allow(incomplete_features)] use std::fmt::Debug; +use std::marker::PointerLike; #[derive(Debug)] +#[repr(transparent)] struct Foo(#[allow(dead_code)] usize); +// FIXME(dyn_star): Make this into a derive. +impl PointerLike for Foo {} + impl Drop for Foo { fn drop(&mut self) { println!("destructor called"); diff --git a/tests/ui/dyn-star/enum-cast.rs b/tests/ui/dyn-star/enum-cast.rs index 6e895e9527a..3cc7390eb12 100644 --- a/tests/ui/dyn-star/enum-cast.rs +++ b/tests/ui/dyn-star/enum-cast.rs @@ -3,13 +3,18 @@ // This used to ICE, because the compiler confused a pointer-like to dyn* coercion // with a c-like enum to integer cast. -#![feature(dyn_star)] +#![feature(dyn_star, pointer_like_trait)] #![expect(incomplete_features)] +use std::marker::PointerLike; + +#[repr(transparent)] enum E { Num(usize), } +impl PointerLike for E {} + trait Trait {} impl Trait for E {} diff --git a/tests/ui/dyn-star/error.rs b/tests/ui/dyn-star/error.rs index d8261387efa..7288596f3fa 100644 --- a/tests/ui/dyn-star/error.rs +++ b/tests/ui/dyn-star/error.rs @@ -7,7 +7,7 @@ trait Foo {} fn make_dyn_star() { let i = 42; - let dyn_i: dyn* Foo = i; //~ ERROR trait bound `{integer}: Foo` is not satisfied + let dyn_i: dyn* Foo = i; //~ ERROR trait bound `usize: Foo` is not satisfied } fn main() {} diff --git a/tests/ui/dyn-star/error.stderr b/tests/ui/dyn-star/error.stderr index a9f4a054519..55981c03bac 100644 --- a/tests/ui/dyn-star/error.stderr +++ b/tests/ui/dyn-star/error.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `{integer}: Foo` is not satisfied +error[E0277]: the trait bound `usize: Foo` is not satisfied --> $DIR/error.rs:10:27 | LL | let dyn_i: dyn* Foo = i; - | ^ the trait `Foo` is not implemented for `{integer}` + | ^ the trait `Foo` is not implemented for `usize` | help: this trait has no implementations, consider adding one --> $DIR/error.rs:6:1 diff --git a/tests/ui/dyn-star/float-as-dyn-star.rs b/tests/ui/dyn-star/float-as-dyn-star.rs new file mode 100644 index 00000000000..1b629c64c25 --- /dev/null +++ b/tests/ui/dyn-star/float-as-dyn-star.rs @@ -0,0 +1,16 @@ +//@ only-x86_64 + +#![feature(dyn_star, pointer_like_trait)] +//~^ WARN the feature `dyn_star` is incomplete + +use std::fmt::Debug; +use std::marker::PointerLike; + +fn make_dyn_star() -> dyn* Debug + 'static { + f32::from_bits(0x1) as f64 + //~^ ERROR `f64` needs to have the same ABI as a pointer +} + +fn main() { + println!("{:?}", make_dyn_star()); +} diff --git a/tests/ui/dyn-star/float-as-dyn-star.stderr b/tests/ui/dyn-star/float-as-dyn-star.stderr new file mode 100644 index 00000000000..9caba512e5f --- /dev/null +++ b/tests/ui/dyn-star/float-as-dyn-star.stderr @@ -0,0 +1,21 @@ +warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/float-as-dyn-star.rs:3:12 + | +LL | #![feature(dyn_star, pointer_like_trait)] + | ^^^^^^^^ + | + = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: `f64` needs to have the same ABI as a pointer + --> $DIR/float-as-dyn-star.rs:10:5 + | +LL | f32::from_bits(0x1) as f64 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `f64` needs to be a pointer-like type + | + = help: the trait `PointerLike` is not implemented for `f64` + = help: the trait `PointerLike` is implemented for `usize` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dyn-star/upcast.stderr b/tests/ui/dyn-star/upcast.stderr index adef9525bf1..801e1c233c1 100644 --- a/tests/ui/dyn-star/upcast.stderr +++ b/tests/ui/dyn-star/upcast.stderr @@ -7,6 +7,14 @@ LL | #![feature(dyn_star, trait_upcasting)] = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information = note: `#[warn(incomplete_features)]` on by default +error[E0277]: `W` needs to have the same ABI as a pointer + --> $DIR/upcast.rs:28:23 + | +LL | let w: dyn* Foo = W(0); + | ^^^^ `W` needs to be a pointer-like type + | + = help: the trait `PointerLike` is not implemented for `W` + error[E0277]: `dyn* Foo` needs to have the same ABI as a pointer --> $DIR/upcast.rs:30:23 | @@ -15,6 +23,6 @@ LL | let w: dyn* Bar = w; | = help: the trait `PointerLike` is not implemented for `dyn* Foo` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/editions/never-type-fallback-breaking.e2021.fixed b/tests/ui/editions/never-type-fallback-breaking.e2021.fixed index 3fed16f0ee7..75bc598d17b 100644 --- a/tests/ui/editions/never-type-fallback-breaking.e2021.fixed +++ b/tests/ui/editions/never-type-fallback-breaking.e2021.fixed @@ -16,7 +16,7 @@ fn main() { fn m() { //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! let x: () = match true { true => Default::default(), //[e2024]~^ error: the trait bound `!: Default` is not satisfied @@ -28,7 +28,7 @@ fn m() { fn q() -> Option<()> { //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! fn deserialize<T: Default>() -> Option<T> { Some(T::default()) } @@ -45,7 +45,7 @@ fn help<'a: 'a, T: Into<()>, U>(_: U) -> Result<T, ()> { } fn meow() -> Result<(), ()> { //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! help::<(), _>(1)?; //[e2024]~^ error: the trait bound `(): From<!>` is not satisfied Ok(()) diff --git a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr index fdc97e54d4e..454e88d4569 100644 --- a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr +++ b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr @@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()` LL | fn m() { | ^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail @@ -24,7 +24,7 @@ warning: this function depends on never type fallback being `()` LL | fn q() -> Option<()> { | ^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail @@ -43,7 +43,7 @@ warning: this function depends on never type fallback being `()` LL | fn meow() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the types explicitly note: in edition 2024, the requirement `(): From<!>` will fail diff --git a/tests/ui/editions/never-type-fallback-breaking.rs b/tests/ui/editions/never-type-fallback-breaking.rs index 71d36f3a2d9..32e83e74139 100644 --- a/tests/ui/editions/never-type-fallback-breaking.rs +++ b/tests/ui/editions/never-type-fallback-breaking.rs @@ -16,7 +16,7 @@ fn main() { fn m() { //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! let x = match true { true => Default::default(), //[e2024]~^ error: the trait bound `!: Default` is not satisfied @@ -28,7 +28,7 @@ fn m() { fn q() -> Option<()> { //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! fn deserialize<T: Default>() -> Option<T> { Some(T::default()) } @@ -45,7 +45,7 @@ fn help<'a: 'a, T: Into<()>, U>(_: U) -> Result<T, ()> { } fn meow() -> Result<(), ()> { //[e2021]~^ this function depends on never type fallback being `()` - //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! help(1)?; //[e2024]~^ error: the trait bound `(): From<!>` is not satisfied Ok(()) diff --git a/tests/ui/explore-issue-38412.rs b/tests/ui/explore-issue-38412.rs index e1295a96ba5..2008b120faa 100644 --- a/tests/ui/explore-issue-38412.rs +++ b/tests/ui/explore-issue-38412.rs @@ -1,9 +1,9 @@ //@ aux-build:pub-and-stability.rs -// A big point of this test is that we *declare* `unstable_declared`, -// but do *not* declare `unstable_undeclared`. This way we can check -// that the compiler is letting in uses of declared feature-gated -// stuff but still rejecting uses of undeclared feature-gated stuff. +// A big point of this test is that we *enable* `unstable_declared`, +// but do *not* enable `unstable_undeclared`. This way we can check +// that the compiler is letting in uses of enabled feature-gated +// stuff but still rejecting uses of disabled feature-gated stuff. #![feature(unstable_declared)] extern crate pub_and_stability; diff --git a/tests/ui/feature-gates/feature-gate-large-assignments.rs b/tests/ui/feature-gates/feature-gate-large-assignments.rs index 7e9e574bfa0..c4125c55722 100644 --- a/tests/ui/feature-gates/feature-gate-large-assignments.rs +++ b/tests/ui/feature-gates/feature-gate-large-assignments.rs @@ -1,4 +1,4 @@ -// check that `move_size_limit is feature-gated +// check that `move_size_limit` is feature-gated #![move_size_limit = "42"] //~ ERROR the `#[move_size_limit]` attribute is an experimental feature diff --git a/tests/ui/feature-gates/feature-gate-link-arg-attribute.stderr b/tests/ui/feature-gates/feature-gate-link-arg-attribute.in_attr.stderr index 8cbad78478e..3ea8c89bf3a 100644 --- a/tests/ui/feature-gates/feature-gate-link-arg-attribute.stderr +++ b/tests/ui/feature-gates/feature-gate-link-arg-attribute.in_attr.stderr @@ -1,5 +1,5 @@ error[E0658]: link kind `link-arg` is unstable - --> $DIR/feature-gate-link-arg-attribute.rs:1:15 + --> $DIR/feature-gate-link-arg-attribute.rs:5:15 | LL | #[link(kind = "link-arg", name = "foo")] | ^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-link-arg-attribute.in_flag.stderr b/tests/ui/feature-gates/feature-gate-link-arg-attribute.in_flag.stderr new file mode 100644 index 00000000000..4d65db3c66d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-link-arg-attribute.in_flag.stderr @@ -0,0 +1,2 @@ +error: unknown linking modifier `link-arg`, expected one of: bundle, verbatim, whole-archive, as-needed + diff --git a/tests/ui/feature-gates/feature-gate-link-arg-attribute.rs b/tests/ui/feature-gates/feature-gate-link-arg-attribute.rs index 9036095fbc4..c12ff5b04dc 100644 --- a/tests/ui/feature-gates/feature-gate-link-arg-attribute.rs +++ b/tests/ui/feature-gates/feature-gate-link-arg-attribute.rs @@ -1,5 +1,9 @@ +//@ revisions: in_attr in_flag +//@[in_flag] compile-flags: -l dylib:+link-arg=foo + +#[cfg(in_attr)] #[link(kind = "link-arg", name = "foo")] -//~^ ERROR link kind `link-arg` is unstable +//[in_attr]~^ ERROR link kind `link-arg` is unstable extern "C" {} fn main() {} 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/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr b/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.in_attr.stderr index 216477828e7..11b7abc883e 100644 --- a/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr +++ b/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.in_attr.stderr @@ -1,5 +1,5 @@ error[E0658]: linking modifier `as-needed` is unstable - --> $DIR/feature-gate-native_link_modifiers_as_needed.rs:1:50 + --> $DIR/feature-gate-native_link_modifiers_as_needed.rs:5:50 | LL | #[link(name = "foo", kind = "dylib", modifiers = "+as-needed")] | ^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.in_flag.stderr b/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.in_flag.stderr new file mode 100644 index 00000000000..8f74e9d6f16 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.in_flag.stderr @@ -0,0 +1,2 @@ +error: linking modifier `as-needed` is unstable, the `-Z unstable-options` flag must also be passed to use it + diff --git a/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs b/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs index 132bc6ab04a..c2965e42f27 100644 --- a/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs +++ b/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs @@ -1,5 +1,9 @@ +//@ revisions: in_attr in_flag +//@[in_flag] compile-flags: -l dylib:+as-needed=foo + +#[cfg(in_attr)] #[link(name = "foo", kind = "dylib", modifiers = "+as-needed")] -//~^ ERROR: linking modifier `as-needed` is unstable +//[in_attr]~^ ERROR: linking modifier `as-needed` is unstable extern "C" {} fn main() {} diff --git a/tests/ui/generics/generics-on-self-mod-segment.rs b/tests/ui/generics/generics-on-self-mod-segment.rs new file mode 100644 index 00000000000..ef229eeba53 --- /dev/null +++ b/tests/ui/generics/generics-on-self-mod-segment.rs @@ -0,0 +1,18 @@ +struct Ty; + +fn self_(_: self::<i32>::Ty) {} +//~^ ERROR type arguments are not allowed on module `generics_on_self_mod_segment` + +fn crate_(_: crate::<i32>::Ty) {} +//~^ ERROR type arguments are not allowed on module `generics_on_self_mod_segment` + +macro_rules! dollar_crate { + () => { + fn dollar_crate_(_: $crate::<i32>::Ty) {} + //~^ ERROR type arguments are not allowed on module `generics_on_self_mod_segment` + } +} + +dollar_crate!(); + +fn main() {} diff --git a/tests/ui/generics/generics-on-self-mod-segment.stderr b/tests/ui/generics/generics-on-self-mod-segment.stderr new file mode 100644 index 00000000000..4a2d5939a3e --- /dev/null +++ b/tests/ui/generics/generics-on-self-mod-segment.stderr @@ -0,0 +1,32 @@ +error[E0109]: type arguments are not allowed on module `generics_on_self_mod_segment` + --> $DIR/generics-on-self-mod-segment.rs:3:20 + | +LL | fn self_(_: self::<i32>::Ty) {} + | ---- ^^^ type argument not allowed + | | + | not allowed on module `generics_on_self_mod_segment` + +error[E0109]: type arguments are not allowed on module `generics_on_self_mod_segment` + --> $DIR/generics-on-self-mod-segment.rs:6:22 + | +LL | fn crate_(_: crate::<i32>::Ty) {} + | ----- ^^^ type argument not allowed + | | + | not allowed on module `generics_on_self_mod_segment` + +error[E0109]: type arguments are not allowed on module `generics_on_self_mod_segment` + --> $DIR/generics-on-self-mod-segment.rs:11:38 + | +LL | fn dollar_crate_(_: $crate::<i32>::Ty) {} + | ------ ^^^ type argument not allowed + | | + | not allowed on module `generics_on_self_mod_segment` +... +LL | dollar_crate!(); + | --------------- in this macro invocation + | + = note: this error originates in the macro `dollar_crate` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0109`. diff --git a/tests/ui/impl-trait/in-trait/refine-captures.rs b/tests/ui/impl-trait/in-trait/refine-captures.rs new file mode 100644 index 00000000000..e7dffcb52aa --- /dev/null +++ b/tests/ui/impl-trait/in-trait/refine-captures.rs @@ -0,0 +1,36 @@ +#![feature(precise_capturing_in_traits)] + +trait LifetimeParam<'a> { + fn test() -> impl Sized; +} +// Refining via capturing fewer lifetimes than the trait definition. +impl<'a> LifetimeParam<'a> for i32 { + fn test() -> impl Sized + use<> {} + //~^ WARN impl trait in impl method captures fewer lifetimes than in trait +} +// If the lifetime is substituted, then we don't refine anything. +impl LifetimeParam<'static> for u32 { + fn test() -> impl Sized + use<> {} + // Ok +} + +trait TypeParam<T> { + fn test() -> impl Sized; +} +// Indirectly capturing a lifetime param through a type param substitution. +impl<'a> TypeParam<&'a ()> for i32 { + fn test() -> impl Sized + use<> {} + //~^ WARN impl trait in impl method captures fewer lifetimes than in trait +} +// Two of them, but only one is captured... +impl<'a, 'b> TypeParam<(&'a (), &'b ())> for u32 { + fn test() -> impl Sized + use<'b> {} + //~^ WARN impl trait in impl method captures fewer lifetimes than in trait +} +// What if we don't capture a type param? That should be an error otherwise. +impl<T> TypeParam<T> for u64 { + fn test() -> impl Sized + use<> {} + //~^ ERROR `impl Trait` must mention all type parameters in scope in `use<...>` +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/refine-captures.stderr b/tests/ui/impl-trait/in-trait/refine-captures.stderr new file mode 100644 index 00000000000..ad2c2a11601 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/refine-captures.stderr @@ -0,0 +1,52 @@ +warning: impl trait in impl method captures fewer lifetimes than in trait + --> $DIR/refine-captures.rs:8:31 + | +LL | fn test() -> impl Sized + use<> {} + | ^^^^^ + | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate + = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information + = note: `#[warn(refining_impl_trait_internal)]` on by default +help: modify the `use<..>` bound to capture the same lifetimes that the trait does + | +LL | fn test() -> impl Sized + use<'a> {} + | ~~~~~~~ + +warning: impl trait in impl method captures fewer lifetimes than in trait + --> $DIR/refine-captures.rs:22:31 + | +LL | fn test() -> impl Sized + use<> {} + | ^^^^^ + | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate + = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information +help: modify the `use<..>` bound to capture the same lifetimes that the trait does + | +LL | fn test() -> impl Sized + use<'a> {} + | ~~~~~~~ + +warning: impl trait in impl method captures fewer lifetimes than in trait + --> $DIR/refine-captures.rs:27:31 + | +LL | fn test() -> impl Sized + use<'b> {} + | ^^^^^^^ + | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate + = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information +help: modify the `use<..>` bound to capture the same lifetimes that the trait does + | +LL | fn test() -> impl Sized + use<'a, 'b> {} + | ~~~~~~~~~~~ + +error: `impl Trait` must mention all type parameters in scope in `use<...>` + --> $DIR/refine-captures.rs:32:18 + | +LL | impl<T> TypeParam<T> for u64 { + | - type parameter is implicitly captured by this `impl Trait` +LL | fn test() -> impl Sized + use<> {} + | ^^^^^^^^^^^^^^^^^^ + | + = note: currently, all type parameters are required to be mentioned in the precise captures list + +error: aborting due to 1 previous error; 3 warnings emitted + diff --git a/tests/ui/impl-trait/precise-capturing/auxiliary/no-use-macro.rs b/tests/ui/impl-trait/precise-capturing/auxiliary/no-use-macro.rs new file mode 100644 index 00000000000..2efdc2342c1 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/auxiliary/no-use-macro.rs @@ -0,0 +1,20 @@ +// A macro_rules macro in 2015 that has an RPIT without `use<>` that would +// cause a problem with 2024 capturing rules. + +#[macro_export] +macro_rules! macro_rpit { + () => { + fn test_mbe(x: &Vec<i32>) -> impl std::fmt::Display { + x[0] + } + + pub fn from_mbe() { + let mut x = vec![]; + x.push(1); + + let element = test_mbe(&x); + x.push(2); + println!("{element}"); + } + }; +} diff --git a/tests/ui/impl-trait/precise-capturing/auxiliary/no-use-pm.rs b/tests/ui/impl-trait/precise-capturing/auxiliary/no-use-pm.rs new file mode 100644 index 00000000000..e197dcfef80 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/auxiliary/no-use-pm.rs @@ -0,0 +1,29 @@ +// A proc-macro in 2015 that has an RPIT without `use<>` that would cause a +// problem with 2024 capturing rules. + +//@ force-host +//@ no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro] +pub fn pm_rpit(input: TokenStream) -> TokenStream { + "fn test_pm(x: &Vec<i32>) -> impl std::fmt::Display { + x[0] +} + +pub fn from_pm() { + let mut x = vec![]; + x.push(1); + + let element = test_pm(&x); + x.push(2); + println!(\"{element}\"); +} +" + .parse() + .unwrap() +} diff --git a/tests/ui/impl-trait/precise-capturing/external-macro.rs b/tests/ui/impl-trait/precise-capturing/external-macro.rs new file mode 100644 index 00000000000..492e8036461 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/external-macro.rs @@ -0,0 +1,26 @@ +// Tests that code generated from an external macro (MBE and proc-macro) that +// has an RPIT will not fail when the call-site is 2024. +// https://github.com/rust-lang/rust/issues/132917 + +//@ aux-crate: no_use_pm=no-use-pm.rs +//@ aux-crate: no_use_macro=no-use-macro.rs +//@ edition: 2024 +//@ compile-flags:-Z unstable-options +//@ check-pass + +no_use_pm::pm_rpit!{} + +no_use_macro::macro_rpit!{} + +fn main() { + let mut x = vec![]; + x.push(1); + + let element = test_pm(&x); + x.push(2); + println!("{element}"); + + let element = test_mbe(&x); + x.push(2); + println!("{element}"); +} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed index 6a9d72d028c..1eb88c71d54 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed @@ -1,4 +1,5 @@ //@ run-rustfix +//@ edition: 2018 #![allow(unused)] #![deny(impl_trait_overcaptures)] @@ -37,4 +38,8 @@ fn apit2<U, T: Sized>(_: &T, _: U) -> impl Sized + use<U, T> {} //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 //~| WARN this changes meaning in Rust 2024 +async fn async_fn<'a>(x: &'a ()) -> impl Sized + use<> {} +//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 +//~| WARN this changes meaning in Rust 2024 + fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs index 3a4f5ebb7fb..6f1ef6a472f 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs @@ -1,4 +1,5 @@ //@ run-rustfix +//@ edition: 2018 #![allow(unused)] #![deny(impl_trait_overcaptures)] @@ -37,4 +38,8 @@ fn apit2<U>(_: &impl Sized, _: U) -> impl Sized {} //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 //~| WARN this changes meaning in Rust 2024 +async fn async_fn<'a>(x: &'a ()) -> impl Sized {} +//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 +//~| WARN this changes meaning in Rust 2024 + fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr index c101b980c71..63c87cd46c8 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr @@ -1,5 +1,5 @@ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:6:29 + --> $DIR/overcaptures-2024.rs:7:29 | LL | fn named<'a>(x: &'a i32) -> impl Sized { *x } | ^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | fn named<'a>(x: &'a i32) -> impl Sized { *x } = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html> note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:6:10 + --> $DIR/overcaptures-2024.rs:7:10 | LL | fn named<'a>(x: &'a i32) -> impl Sized { *x } | ^^ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 note: the lint level is defined here - --> $DIR/overcaptures-2024.rs:4:9 + --> $DIR/overcaptures-2024.rs:5:9 | LL | #![deny(impl_trait_overcaptures)] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x } | +++++++ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:10:25 + --> $DIR/overcaptures-2024.rs:11:25 | LL | fn implicit(x: &i32) -> impl Sized { *x } | ^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | fn implicit(x: &i32) -> impl Sized { *x } = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html> note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:10:16 + --> $DIR/overcaptures-2024.rs:11:16 | LL | fn implicit(x: &i32) -> impl Sized { *x } | ^ @@ -42,7 +42,7 @@ LL | fn implicit(x: &i32) -> impl Sized + use<> { *x } | +++++++ error: `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:16:33 + --> $DIR/overcaptures-2024.rs:17:33 | LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self } | ^^^^^^^^^^^^^^^ @@ -50,7 +50,7 @@ LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self } = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html> note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:16:24 + --> $DIR/overcaptures-2024.rs:17:24 | LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self } | ^ @@ -61,7 +61,7 @@ LL | fn hello(&self, x: &i32) -> impl Sized + '_ + use<'_> { self } | +++++++++ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:28:47 + --> $DIR/overcaptures-2024.rs:29:47 | LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {} | ^^^^^^^^^^ @@ -69,7 +69,7 @@ LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {} = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html> note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:28:23 + --> $DIR/overcaptures-2024.rs:29:23 | LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {} | ^^ @@ -80,7 +80,7 @@ LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {} | +++++++ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:32:28 + --> $DIR/overcaptures-2024.rs:33:28 | LL | fn apit(_: &impl Sized) -> impl Sized {} | ^^^^^^^^^^ @@ -88,13 +88,13 @@ LL | fn apit(_: &impl Sized) -> impl Sized {} = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html> note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:32:12 + --> $DIR/overcaptures-2024.rs:33:12 | LL | fn apit(_: &impl Sized) -> impl Sized {} | ^ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 note: you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable - --> $DIR/overcaptures-2024.rs:32:13 + --> $DIR/overcaptures-2024.rs:33:13 | LL | fn apit(_: &impl Sized) -> impl Sized {} | ^^^^^^^^^^ @@ -104,7 +104,7 @@ LL | fn apit<T: Sized>(_: &T) -> impl Sized + use<T> {} | ++++++++++ ~ ++++++++ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:36:38 + --> $DIR/overcaptures-2024.rs:37:38 | LL | fn apit2<U>(_: &impl Sized, _: U) -> impl Sized {} | ^^^^^^^^^^ @@ -112,13 +112,13 @@ LL | fn apit2<U>(_: &impl Sized, _: U) -> impl Sized {} = warning: this changes meaning in Rust 2024 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html> note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:36:16 + --> $DIR/overcaptures-2024.rs:37:16 | LL | fn apit2<U>(_: &impl Sized, _: U) -> impl Sized {} | ^ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 note: you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable - --> $DIR/overcaptures-2024.rs:36:17 + --> $DIR/overcaptures-2024.rs:37:17 | LL | fn apit2<U>(_: &impl Sized, _: U) -> impl Sized {} | ^^^^^^^^^^ @@ -127,5 +127,24 @@ help: use the precise capturing `use<...>` syntax to make the captures explicit LL | fn apit2<U, T: Sized>(_: &T, _: U) -> impl Sized + use<U, T> {} | ++++++++++ ~ +++++++++++ -error: aborting due to 6 previous errors +error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 + --> $DIR/overcaptures-2024.rs:41:37 + | +LL | async fn async_fn<'a>(x: &'a ()) -> impl Sized {} + | ^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html> +note: specifically, this lifetime is in scope but not mentioned in the type's bounds + --> $DIR/overcaptures-2024.rs:41:19 + | +LL | async fn async_fn<'a>(x: &'a ()) -> impl Sized {} + | ^^ + = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 +help: use the precise capturing `use<...>` syntax to make the captures explicit + | +LL | async fn async_fn<'a>(x: &'a ()) -> impl Sized + use<> {} + | +++++++ + +error: aborting due to 7 previous errors diff --git a/tests/ui/intrinsics/reify-intrinsic.rs b/tests/ui/intrinsics/reify-intrinsic.rs index 6c52651f060..0d047ccf4a3 100644 --- a/tests/ui/intrinsics/reify-intrinsic.rs +++ b/tests/ui/intrinsics/reify-intrinsic.rs @@ -13,9 +13,9 @@ fn b() { } fn c() { - let _: [unsafe extern "rust-intrinsic" fn(bool) -> bool; 2] = [ - std::intrinsics::likely, //~ ERROR cannot coerce - std::intrinsics::unlikely, + let _: [unsafe extern "rust-intrinsic" fn(f32) -> f32; 2] = [ + std::intrinsics::floorf32, //~ ERROR cannot coerce + std::intrinsics::log2f32, ]; } diff --git a/tests/ui/intrinsics/reify-intrinsic.stderr b/tests/ui/intrinsics/reify-intrinsic.stderr index 7af17147f28..a456e81e762 100644 --- a/tests/ui/intrinsics/reify-intrinsic.stderr +++ b/tests/ui/intrinsics/reify-intrinsic.stderr @@ -18,11 +18,11 @@ LL | let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) error[E0308]: cannot coerce intrinsics to function pointers --> $DIR/reify-intrinsic.rs:17:9 | -LL | std::intrinsics::likely, - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers +LL | std::intrinsics::floorf32, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers | = note: expected fn pointer `unsafe extern "rust-intrinsic" fn(_) -> _` - found fn item `fn(_) -> _ {likely}` + found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {floorf32}` error: aborting due to 3 previous errors diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs new file mode 100644 index 00000000000..8d854c6c237 --- /dev/null +++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs @@ -0,0 +1,31 @@ +//@ only-x86_64 + +const fn foo<const U: i32>() -> i32 { + U +} + +fn main() { + std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, || ()); + //~^ invalid argument to a legacy const generic + + std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, 5 + || ()); + //~^ invalid argument to a legacy const generic + + std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, foo::<{ 1 + 2 }>()); + //~^ invalid argument to a legacy const generic + + std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, foo::<3>()); + //~^ invalid argument to a legacy const generic + + std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, &const {}); + //~^ invalid argument to a legacy const generic + + std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, { + struct F(); + //~^ invalid argument to a legacy const generic + 1 + }); + + std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ()); + //~^ invalid argument to a legacy const generic +} diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr new file mode 100644 index 00000000000..7e05ae4f20c --- /dev/null +++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr @@ -0,0 +1,82 @@ +error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:8:55 + | +LL | std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, || ()); + | ^^^^^ + | +help: try using a const generic argument instead + | +LL | std::arch::x86_64::_mm_blend_ps::<{ || () }>(loop {}, loop {}); + | +++++++++++++ ~~~~~~~~~~~~~~~~ + +error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:11:59 + | +LL | std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, 5 + || ()); + | ^^^^^ + | +help: try using a const generic argument instead + | +LL | std::arch::x86_64::_mm_blend_ps::<{ 5 + (|| ()) }>(loop {}, loop {}); + | +++++++++++++++++++ ~~~~~~~~~~~~~~~~ + +error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:14:61 + | +LL | std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, foo::<{ 1 + 2 }>()); + | ^^^^^^^^^ + | +help: try using a const generic argument instead + | +LL | std::arch::x86_64::_mm_blend_ps::<{ foo::<{ 1 + 2 }>() }>(loop {}, loop {}); + | ++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~ + +error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:17:61 + | +LL | std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, foo::<3>()); + | ^ + | +help: try using a const generic argument instead + | +LL | std::arch::x86_64::_mm_blend_ps::<{ foo::<3>() }>(loop {}, loop {}); + | ++++++++++++++++++ ~~~~~~~~~~~~~~~~ + +error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:20:56 + | +LL | std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, &const {}); + | ^^^^^^^^ + | +help: try using a const generic argument instead + | +LL | std::arch::x86_64::_mm_blend_ps::<{ &const {} }>(loop {}, loop {}); + | +++++++++++++++++ ~~~~~~~~~~~~~~~~ + +error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:24:9 + | +LL | struct F(); + | ^^^^^^^^^^^ + | +help: try using a const generic argument instead + | +LL ~ std::arch::x86_64::_mm_blend_ps::<{ { +LL + struct F(); +LL + 1 +LL ~ } }>(loop {}, loop {}); + | + +error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:29:59 + | +LL | std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ()); + | ^^^^^ + | +help: try using a const generic argument instead + | +LL | std::arch::x86_64::_mm_inserti_si64::<{ || () }, { 1 + (|| ()) }>(loop {}, loop {}); + | ++++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~ + +error: aborting due to 7 previous errors + diff --git a/tests/ui/issues/issue-39848.stderr b/tests/ui/issues/issue-39848.stderr index a6c6c61f170..1ffed2d4a1d 100644 --- a/tests/ui/issues/issue-39848.stderr +++ b/tests/ui/issues/issue-39848.stderr @@ -16,10 +16,10 @@ LL | if $tgt.has_$field() {} LL | get_opt!(bar, foo); | ------------------ in this macro invocation = note: this error originates in the macro `get_opt` (in Nightly builds, run with -Z macro-backtrace for more info) -help: try placing this code inside a block +help: you might have meant to write a method call | -LL | if $tgt.has_{ $field() } {} - | + + +LL | if $tgt.has_.$field() {} + | + error: aborting due to 1 previous error diff --git a/tests/ui/let-else/let-else-if.stderr b/tests/ui/let-else/let-else-if.stderr index 7e2215c8c05..ad36b423150 100644 --- a/tests/ui/let-else/let-else-if.stderr +++ b/tests/ui/let-else/let-else-if.stderr @@ -4,7 +4,7 @@ error: conditional `else if` is not supported for `let...else` LL | let Some(_) = Some(()) else if true { | ^^ expected `{` | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL ~ let Some(_) = Some(()) else { if true { LL | diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs index 2b515d3e6d5..17c3eca89e2 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs @@ -1,6 +1,7 @@ #![deny(dangling_pointers_from_temporaries)] +#![feature(sync_unsafe_cell)] -use std::cell::Cell; +use std::cell::{Cell, SyncUnsafeCell, UnsafeCell}; use std::ffi::{CStr, CString}; use std::mem::MaybeUninit; @@ -47,6 +48,10 @@ fn main() { //~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped declval::<Vec<AsPtrFake>>().as_ptr(); //~^ ERROR a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped + declval::<UnsafeCell<u8>>().get(); + //~^ ERROR a dangling pointer will be produced because the temporary `UnsafeCell<u8>` will be dropped + declval::<SyncUnsafeCell<u8>>().get(); + //~^ ERROR a dangling pointer will be produced because the temporary `SyncUnsafeCell<u8>` will be dropped declval::<Box<AsPtrFake>>().as_ptr(); declval::<AsPtrFake>().as_ptr(); } diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr index c582a4c6540..250ed6dc9e3 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr @@ -1,5 +1,5 @@ error: a dangling pointer will be produced because the temporary `CString` will be dropped - --> $DIR/types.rs:20:26 + --> $DIR/types.rs:21:26 | LL | declval::<CString>().as_ptr(); | -------------------- ^^^^^^ this pointer will immediately be invalid @@ -15,7 +15,7 @@ LL | #![deny(dangling_pointers_from_temporaries)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a dangling pointer will be produced because the temporary `String` will be dropped - --> $DIR/types.rs:22:25 + --> $DIR/types.rs:23:25 | LL | declval::<String>().as_ptr(); | ------------------- ^^^^^^ this pointer will immediately be invalid @@ -26,7 +26,7 @@ LL | declval::<String>().as_ptr(); = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped - --> $DIR/types.rs:24:26 + --> $DIR/types.rs:25:26 | LL | declval::<Vec<u8>>().as_ptr(); | -------------------- ^^^^^^ this pointer will immediately be invalid @@ -37,7 +37,7 @@ LL | declval::<Vec<u8>>().as_ptr(); = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<CString>` will be dropped - --> $DIR/types.rs:26:31 + --> $DIR/types.rs:27:31 | LL | declval::<Box<CString>>().as_ptr(); | ------------------------- ^^^^^^ this pointer will immediately be invalid @@ -48,7 +48,7 @@ LL | declval::<Box<CString>>().as_ptr(); = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped - --> $DIR/types.rs:28:28 + --> $DIR/types.rs:29:28 | LL | declval::<Box<[u8]>>().as_ptr(); | ---------------------- ^^^^^^ this pointer will immediately be invalid @@ -59,7 +59,7 @@ LL | declval::<Box<[u8]>>().as_ptr(); = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<str>` will be dropped - --> $DIR/types.rs:30:27 + --> $DIR/types.rs:31:27 | LL | declval::<Box<str>>().as_ptr(); | --------------------- ^^^^^^ this pointer will immediately be invalid @@ -70,7 +70,7 @@ LL | declval::<Box<str>>().as_ptr(); = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped - --> $DIR/types.rs:32:28 + --> $DIR/types.rs:33:28 | LL | declval::<Box<CStr>>().as_ptr(); | ---------------------- ^^^^^^ this pointer will immediately be invalid @@ -81,7 +81,7 @@ LL | declval::<Box<CStr>>().as_ptr(); = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped - --> $DIR/types.rs:34:27 + --> $DIR/types.rs:35:27 | LL | declval::<[u8; 10]>().as_ptr(); | --------------------- ^^^^^^ this pointer will immediately be invalid @@ -92,7 +92,7 @@ LL | declval::<[u8; 10]>().as_ptr(); = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped - --> $DIR/types.rs:36:32 + --> $DIR/types.rs:37:32 | LL | declval::<Box<[u8; 10]>>().as_ptr(); | -------------------------- ^^^^^^ this pointer will immediately be invalid @@ -103,7 +103,7 @@ LL | declval::<Box<[u8; 10]>>().as_ptr(); = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped - --> $DIR/types.rs:38:31 + --> $DIR/types.rs:39:31 | LL | declval::<Box<Vec<u8>>>().as_ptr(); | ------------------------- ^^^^^^ this pointer will immediately be invalid @@ -114,7 +114,7 @@ LL | declval::<Box<Vec<u8>>>().as_ptr(); = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<String>` will be dropped - --> $DIR/types.rs:40:30 + --> $DIR/types.rs:41:30 | LL | declval::<Box<String>>().as_ptr(); | ------------------------ ^^^^^^ this pointer will immediately be invalid @@ -125,7 +125,7 @@ LL | declval::<Box<String>>().as_ptr(); = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped - --> $DIR/types.rs:42:43 + --> $DIR/types.rs:43:43 | LL | declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr(); | ------------------------------------- ^^^^^^ this pointer will immediately be invalid @@ -136,7 +136,7 @@ LL | declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr(); = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped - --> $DIR/types.rs:44:27 + --> $DIR/types.rs:45:27 | LL | declval::<Cell<u8>>().as_ptr(); | --------------------- ^^^^^^ this pointer will immediately be invalid @@ -147,7 +147,7 @@ LL | declval::<Cell<u8>>().as_ptr(); = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped - --> $DIR/types.rs:46:34 + --> $DIR/types.rs:47:34 | LL | declval::<MaybeUninit<u8>>().as_ptr(); | ---------------------------- ^^^^^^ this pointer will immediately be invalid @@ -158,7 +158,7 @@ LL | declval::<MaybeUninit<u8>>().as_ptr(); = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped - --> $DIR/types.rs:48:33 + --> $DIR/types.rs:49:33 | LL | declval::<Vec<AsPtrFake>>().as_ptr(); | --------------------------- ^^^^^^ this pointer will immediately be invalid @@ -168,5 +168,27 @@ LL | declval::<Vec<AsPtrFake>>().as_ptr(); = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<AsPtrFake>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> -error: aborting due to 15 previous errors +error: a dangling pointer will be produced because the temporary `UnsafeCell<u8>` will be dropped + --> $DIR/types.rs:51:33 + | +LL | declval::<UnsafeCell<u8>>().get(); + | --------------------------- ^^^ this pointer will immediately be invalid + | | + | this `UnsafeCell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `get` the `UnsafeCell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: a dangling pointer will be produced because the temporary `SyncUnsafeCell<u8>` will be dropped + --> $DIR/types.rs:53:37 + | +LL | declval::<SyncUnsafeCell<u8>>().get(); + | ------------------------------- ^^^ this pointer will immediately be invalid + | | + | this `SyncUnsafeCell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `get` the `SyncUnsafeCell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> + +error: aborting due to 17 previous errors diff --git a/tests/ui/lint/issue-104392.stderr b/tests/ui/lint/issue-104392.stderr index 8e466439ae6..4d8d8c56d41 100644 --- a/tests/ui/lint/issue-104392.stderr +++ b/tests/ui/lint/issue-104392.stderr @@ -6,7 +6,7 @@ LL | { unsafe 92 } | | | while parsing this `unsafe` expression | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | { unsafe { 92 } } | + + diff --git a/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed b/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed index 7cf4aa6cdd4..ada37ccd640 100644 --- a/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed +++ b/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed @@ -10,7 +10,7 @@ unused_mut, unused_variables )] -#![deny(unused_parens)] +#![deny(unused_parens, unused_braces)] fn lint_on_top_level() { let a = 0; //~ ERROR unnecessary parentheses around pattern @@ -43,8 +43,10 @@ fn no_lint_ops() { fn lint_break_if_not_followed_by_block() { #![allow(unreachable_code)] loop { if break {} } //~ ERROR unnecessary parentheses - loop { if break ({ println!("hello") }) {} } //~ ERROR unnecessary parentheses - loop { if (break { println!("hello") }) {} } + loop { if break { println!("hello") } {} } + //~^ ERROR unnecessary parentheses around `if` condition + //~| ERROR unnecessary parentheses around `break` value + loop { if (break println!("hello")) {} } //~ ERROR unnecessary braces around `break` value } // Don't lint in these cases (#64106). diff --git a/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs b/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs index 013255dc213..67066c3bee3 100644 --- a/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs +++ b/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs @@ -10,7 +10,7 @@ unused_mut, unused_variables )] -#![deny(unused_parens)] +#![deny(unused_parens, unused_braces)] fn lint_on_top_level() { let (a) = 0; //~ ERROR unnecessary parentheses around pattern @@ -43,8 +43,10 @@ fn no_lint_ops() { fn lint_break_if_not_followed_by_block() { #![allow(unreachable_code)] loop { if (break) {} } //~ ERROR unnecessary parentheses - loop { if (break ({ println!("hello") })) {} } //~ ERROR unnecessary parentheses - loop { if (break { println!("hello") }) {} } + loop { if (break ({ println!("hello") })) {} } + //~^ ERROR unnecessary parentheses around `if` condition + //~| ERROR unnecessary parentheses around `break` value + loop { if (break { println!("hello") }) {} } //~ ERROR unnecessary braces around `break` value } // Don't lint in these cases (#64106). diff --git a/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr b/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr index f916bba8194..d5fdaef42d8 100644 --- a/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr +++ b/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr @@ -7,7 +7,7 @@ LL | let (a) = 0; note: the lint level is defined here --> $DIR/issue-54538-unused-parens-lint.rs:13:9 | -LL | #![deny(unused_parens)] +LL | #![deny(unused_parens, unused_braces)] | ^^^^^^^^^^^^^ help: remove these parentheses | @@ -99,8 +99,37 @@ LL - loop { if (break ({ println!("hello") })) {} } LL + loop { if break ({ println!("hello") }) {} } | +error: unnecessary parentheses around `break` value + --> $DIR/issue-54538-unused-parens-lint.rs:46:22 + | +LL | loop { if (break ({ println!("hello") })) {} } + | ^ ^ + | +help: remove these parentheses + | +LL - loop { if (break ({ println!("hello") })) {} } +LL + loop { if (break { println!("hello") }) {} } + | + +error: unnecessary braces around `break` value + --> $DIR/issue-54538-unused-parens-lint.rs:49:22 + | +LL | loop { if (break { println!("hello") }) {} } + | ^^ ^^ + | +note: the lint level is defined here + --> $DIR/issue-54538-unused-parens-lint.rs:13:24 + | +LL | #![deny(unused_parens, unused_braces)] + | ^^^^^^^^^^^^^ +help: remove these braces + | +LL - loop { if (break { println!("hello") }) {} } +LL + loop { if (break println!("hello")) {} } + | + error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:71:12 + --> $DIR/issue-54538-unused-parens-lint.rs:73:12 | LL | if let (0 | 1) = 0 {} | ^ ^ @@ -112,7 +141,7 @@ LL + if let 0 | 1 = 0 {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:72:13 + --> $DIR/issue-54538-unused-parens-lint.rs:74:13 | LL | if let ((0 | 1),) = (0,) {} | ^ ^ @@ -124,7 +153,7 @@ LL + if let (0 | 1,) = (0,) {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:73:13 + --> $DIR/issue-54538-unused-parens-lint.rs:75:13 | LL | if let [(0 | 1)] = [0] {} | ^ ^ @@ -136,7 +165,7 @@ LL + if let [0 | 1] = [0] {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:74:16 + --> $DIR/issue-54538-unused-parens-lint.rs:76:16 | LL | if let 0 | (1 | 2) = 0 {} | ^ ^ @@ -148,7 +177,7 @@ LL + if let 0 | 1 | 2 = 0 {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:76:15 + --> $DIR/issue-54538-unused-parens-lint.rs:78:15 | LL | if let TS((0 | 1)) = TS(0) {} | ^ ^ @@ -160,7 +189,7 @@ LL + if let TS(0 | 1) = TS(0) {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:78:20 + --> $DIR/issue-54538-unused-parens-lint.rs:80:20 | LL | if let NS { f: (0 | 1) } = (NS { f: 0 }) {} | ^ ^ @@ -172,7 +201,7 @@ LL + if let NS { f: 0 | 1 } = (NS { f: 0 }) {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:88:9 + --> $DIR/issue-54538-unused-parens-lint.rs:90:9 | LL | (_) => {} | ^ ^ @@ -184,7 +213,7 @@ LL + _ => {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:89:9 + --> $DIR/issue-54538-unused-parens-lint.rs:91:9 | LL | (y) => {} | ^ ^ @@ -196,7 +225,7 @@ LL + y => {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:90:9 + --> $DIR/issue-54538-unused-parens-lint.rs:92:9 | LL | (ref r) => {} | ^ ^ @@ -208,7 +237,7 @@ LL + ref r => {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:91:9 + --> $DIR/issue-54538-unused-parens-lint.rs:93:9 | LL | (e @ 1...2) => {} | ^ ^ @@ -220,7 +249,7 @@ LL + e @ 1...2 => {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:97:9 + --> $DIR/issue-54538-unused-parens-lint.rs:99:9 | LL | (e @ &(1...2)) => {} | ^ ^ @@ -232,7 +261,7 @@ LL + e @ &(1...2) => {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:98:10 + --> $DIR/issue-54538-unused-parens-lint.rs:100:10 | LL | &(_) => {} | ^ ^ @@ -244,7 +273,7 @@ LL + &_ => {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:109:9 + --> $DIR/issue-54538-unused-parens-lint.rs:111:9 | LL | (_) => {} | ^ ^ @@ -256,7 +285,7 @@ LL + _ => {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:110:9 + --> $DIR/issue-54538-unused-parens-lint.rs:112:9 | LL | (y) => {} | ^ ^ @@ -268,7 +297,7 @@ LL + y => {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:111:9 + --> $DIR/issue-54538-unused-parens-lint.rs:113:9 | LL | (ref r) => {} | ^ ^ @@ -280,7 +309,7 @@ LL + ref r => {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:112:9 + --> $DIR/issue-54538-unused-parens-lint.rs:114:9 | LL | (e @ 1..=2) => {} | ^ ^ @@ -292,7 +321,7 @@ LL + e @ 1..=2 => {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:118:9 + --> $DIR/issue-54538-unused-parens-lint.rs:120:9 | LL | (e @ &(1..=2)) => {} | ^ ^ @@ -304,7 +333,7 @@ LL + e @ &(1..=2) => {} | error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:119:10 + --> $DIR/issue-54538-unused-parens-lint.rs:121:10 | LL | &(_) => {} | ^ ^ @@ -315,5 +344,5 @@ LL - &(_) => {} LL + &_ => {} | -error: aborting due to 26 previous errors +error: aborting due to 28 previous errors diff --git a/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.fixed b/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.fixed new file mode 100644 index 00000000000..9343d906cdc --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.fixed @@ -0,0 +1,32 @@ +//@ run-rustfix +#![deny(unused_parens)] +#![allow(unreachable_code)] + +fn foo() { + loop { + break (_ = 42); + // lint unused_parens should not be triggered here. + } + + let _ = loop { + let a = 1; + let b = 2; + break a + b; //~ERROR unnecessary parentheses + }; + + loop { + if break return () { + //~^ ERROR unnecessary parentheses + } + if break return () { + //~^ ERROR unnecessary parentheses + } + } + + return (_ = 42); + // lint unused_parens should not be triggered here. +} + +fn main() { + let _ = foo(); +} diff --git a/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.rs b/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.rs new file mode 100644 index 00000000000..fe9cba3e168 --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.rs @@ -0,0 +1,32 @@ +//@ run-rustfix +#![deny(unused_parens)] +#![allow(unreachable_code)] + +fn foo() { + loop { + break (_ = 42); + // lint unused_parens should not be triggered here. + } + + let _ = loop { + let a = 1; + let b = 2; + break (a + b); //~ERROR unnecessary parentheses + }; + + loop { + if (break return ()) { + //~^ ERROR unnecessary parentheses + } + if break (return ()) { + //~^ ERROR unnecessary parentheses + } + } + + return (_ = 42); + // lint unused_parens should not be triggered here. +} + +fn main() { + let _ = foo(); +} diff --git a/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.stderr b/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.stderr new file mode 100644 index 00000000000..c41cf32bade --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.stderr @@ -0,0 +1,43 @@ +error: unnecessary parentheses around `break` value + --> $DIR/unused-parens-assign-expr-in-ret-issue-131989.rs:14:15 + | +LL | break (a + b); + | ^ ^ + | +note: the lint level is defined here + --> $DIR/unused-parens-assign-expr-in-ret-issue-131989.rs:2:9 + | +LL | #![deny(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - break (a + b); +LL + break a + b; + | + +error: unnecessary parentheses around `if` condition + --> $DIR/unused-parens-assign-expr-in-ret-issue-131989.rs:18:12 + | +LL | if (break return ()) { + | ^ ^ + | +help: remove these parentheses + | +LL - if (break return ()) { +LL + if break return () { + | + +error: unnecessary parentheses around `break` value + --> $DIR/unused-parens-assign-expr-in-ret-issue-131989.rs:21:18 + | +LL | if break (return ()) { + | ^ ^ + | +help: remove these parentheses + | +LL - if break (return ()) { +LL + if break return () { + | + +error: aborting due to 3 previous errors + diff --git a/tests/ui/lint/unused_parens_json_suggestion.fixed b/tests/ui/lint/unused_parens_json_suggestion.fixed index 89fd0d86614..f26bedc3fd5 100644 --- a/tests/ui/lint/unused_parens_json_suggestion.fixed +++ b/tests/ui/lint/unused_parens_json_suggestion.fixed @@ -9,7 +9,7 @@ // test of the JSON error format. #![deny(unused_parens)] -#![allow(unreachable_code)] +#![allow(unreachable_code, unused_braces)] fn main() { // We want to suggest the properly-balanced expression `1 / (2 + 3)`, not diff --git a/tests/ui/lint/unused_parens_json_suggestion.rs b/tests/ui/lint/unused_parens_json_suggestion.rs index 4526084196c..af3d88f71bb 100644 --- a/tests/ui/lint/unused_parens_json_suggestion.rs +++ b/tests/ui/lint/unused_parens_json_suggestion.rs @@ -9,7 +9,7 @@ // test of the JSON error format. #![deny(unused_parens)] -#![allow(unreachable_code)] +#![allow(unreachable_code, unused_braces)] fn main() { // We want to suggest the properly-balanced expression `1 / (2 + 3)`, not diff --git a/tests/ui/lint/unused_parens_json_suggestion.stderr b/tests/ui/lint/unused_parens_json_suggestion.stderr index 1f4928cd464..2ce31817d29 100644 --- a/tests/ui/lint/unused_parens_json_suggestion.stderr +++ b/tests/ui/lint/unused_parens_json_suggestion.stderr @@ -1,4 +1,4 @@ -{"$message_type":"diagnostic","message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":633,"byte_end":634,"line_start":17,"line_end":17,"column_start":26,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":26,"highlight_end":27}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":439,"byte_end":452,"line_start":11,"line_end":11,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![deny(unused_parens)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":633,"byte_end":634,"line_start":17,"line_end":17,"column_start":26,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":26,"highlight_end":27}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around assigned value +{"$message_type":"diagnostic","message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":636,"byte_end":637,"line_start":17,"line_end":17,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":648,"byte_end":649,"line_start":17,"line_end":17,"column_start":26,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":26,"highlight_end":27}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":439,"byte_end":452,"line_start":11,"line_end":11,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![deny(unused_parens)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":636,"byte_end":637,"line_start":17,"line_end":17,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":648,"byte_end":649,"line_start":17,"line_end":17,"column_start":26,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":26,"highlight_end":27}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around assigned value --> $DIR/unused_parens_json_suggestion.rs:17:14 | LL | let _a = (1 / (2 + 3)); diff --git a/tests/ui/lint/unused_parens_remove_json_suggestion.fixed b/tests/ui/lint/unused_parens_remove_json_suggestion.fixed index e2774d5d7e5..899c24f83ed 100644 --- a/tests/ui/lint/unused_parens_remove_json_suggestion.fixed +++ b/tests/ui/lint/unused_parens_remove_json_suggestion.fixed @@ -9,7 +9,7 @@ // test of the JSON error format. #![deny(unused_parens)] -#![allow(unreachable_code)] +#![allow(unreachable_code, unused_braces)] fn main() { diff --git a/tests/ui/lint/unused_parens_remove_json_suggestion.rs b/tests/ui/lint/unused_parens_remove_json_suggestion.rs index b3ac87178db..7f5d935c4ac 100644 --- a/tests/ui/lint/unused_parens_remove_json_suggestion.rs +++ b/tests/ui/lint/unused_parens_remove_json_suggestion.rs @@ -9,7 +9,7 @@ // test of the JSON error format. #![deny(unused_parens)] -#![allow(unreachable_code)] +#![allow(unreachable_code, unused_braces)] fn main() { diff --git a/tests/ui/lint/unused_parens_remove_json_suggestion.stderr b/tests/ui/lint/unused_parens_remove_json_suggestion.stderr index 9268fc1abc4..975de4edfdf 100644 --- a/tests/ui/lint/unused_parens_remove_json_suggestion.stderr +++ b/tests/ui/lint/unused_parens_remove_json_suggestion.stderr @@ -1,4 +1,4 @@ -{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":525,"byte_end":526,"line_start":18,"line_end":18,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (_b) {","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":528,"byte_end":529,"line_start":18,"line_end":18,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" if (_b) {","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":439,"byte_end":452,"line_start":11,"line_end":11,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![deny(unused_parens)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":525,"byte_end":526,"line_start":18,"line_end":18,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (_b) {","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":528,"byte_end":529,"line_start":18,"line_end":18,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" if (_b) {","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition +{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":540,"byte_end":541,"line_start":18,"line_end":18,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (_b) {","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":543,"byte_end":544,"line_start":18,"line_end":18,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" if (_b) {","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":439,"byte_end":452,"line_start":11,"line_end":11,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![deny(unused_parens)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":540,"byte_end":541,"line_start":18,"line_end":18,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (_b) {","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":543,"byte_end":544,"line_start":18,"line_end":18,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" if (_b) {","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition --> $DIR/unused_parens_remove_json_suggestion.rs:18:8 | LL | if (_b) { @@ -16,7 +16,7 @@ LL + if _b { | "} -{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":622,"byte_end":623,"line_start":29,"line_end":29,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" if(c) {","highlight_start":7,"highlight_end":8}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":624,"byte_end":625,"line_start":29,"line_end":29,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":" if(c) {","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":622,"byte_end":623,"line_start":29,"line_end":29,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" if(c) {","highlight_start":7,"highlight_end":8}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":624,"byte_end":625,"line_start":29,"line_end":29,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":" if(c) {","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition +{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":637,"byte_end":638,"line_start":29,"line_end":29,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" if(c) {","highlight_start":7,"highlight_end":8}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":639,"byte_end":640,"line_start":29,"line_end":29,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":" if(c) {","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":637,"byte_end":638,"line_start":29,"line_end":29,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" if(c) {","highlight_start":7,"highlight_end":8}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":639,"byte_end":640,"line_start":29,"line_end":29,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":" if(c) {","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition --> $DIR/unused_parens_remove_json_suggestion.rs:29:7 | LL | if(c) { @@ -29,7 +29,7 @@ LL + if c { | "} -{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":668,"byte_end":669,"line_start":33,"line_end":33,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (c){","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":670,"byte_end":671,"line_start":33,"line_end":33,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" if (c){","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":668,"byte_end":669,"line_start":33,"line_end":33,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (c){","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":670,"byte_end":671,"line_start":33,"line_end":33,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" if (c){","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition +{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":683,"byte_end":684,"line_start":33,"line_end":33,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (c){","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":685,"byte_end":686,"line_start":33,"line_end":33,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" if (c){","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":683,"byte_end":684,"line_start":33,"line_end":33,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (c){","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":685,"byte_end":686,"line_start":33,"line_end":33,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" if (c){","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition --> $DIR/unused_parens_remove_json_suggestion.rs:33:8 | LL | if (c){ @@ -42,7 +42,7 @@ LL + if c { | "} -{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":716,"byte_end":717,"line_start":37,"line_end":37,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":730,"byte_end":731,"line_start":37,"line_end":37,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":716,"byte_end":717,"line_start":37,"line_end":37,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":730,"byte_end":731,"line_start":37,"line_end":37,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition +{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":731,"byte_end":732,"line_start":37,"line_end":37,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":745,"byte_end":746,"line_start":37,"line_end":37,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":731,"byte_end":732,"line_start":37,"line_end":37,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":745,"byte_end":746,"line_start":37,"line_end":37,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition --> $DIR/unused_parens_remove_json_suggestion.rs:37:11 | LL | while (false && true){ @@ -55,7 +55,7 @@ LL + while false && true { | "} -{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":744,"byte_end":745,"line_start":38,"line_end":38,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":" if (c) {","highlight_start":12,"highlight_end":13}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":746,"byte_end":747,"line_start":38,"line_end":38,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" if (c) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":744,"byte_end":745,"line_start":38,"line_end":38,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":" if (c) {","highlight_start":12,"highlight_end":13}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":746,"byte_end":747,"line_start":38,"line_end":38,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" if (c) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition +{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":759,"byte_end":760,"line_start":38,"line_end":38,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":" if (c) {","highlight_start":12,"highlight_end":13}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":761,"byte_end":762,"line_start":38,"line_end":38,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" if (c) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":759,"byte_end":760,"line_start":38,"line_end":38,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":" if (c) {","highlight_start":12,"highlight_end":13}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":761,"byte_end":762,"line_start":38,"line_end":38,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" if (c) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition --> $DIR/unused_parens_remove_json_suggestion.rs:38:12 | LL | if (c) { @@ -68,7 +68,7 @@ LL + if c { | "} -{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":807,"byte_end":808,"line_start":44,"line_end":44,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" while(true && false) {","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":821,"byte_end":822,"line_start":44,"line_end":44,"column_start":24,"column_end":25,"is_primary":true,"text":[{"text":" while(true && false) {","highlight_start":24,"highlight_end":25}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":807,"byte_end":808,"line_start":44,"line_end":44,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" while(true && false) {","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":821,"byte_end":822,"line_start":44,"line_end":44,"column_start":24,"column_end":25,"is_primary":true,"text":[{"text":" while(true && false) {","highlight_start":24,"highlight_end":25}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition +{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":822,"byte_end":823,"line_start":44,"line_end":44,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" while(true && false) {","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":836,"byte_end":837,"line_start":44,"line_end":44,"column_start":24,"column_end":25,"is_primary":true,"text":[{"text":" while(true && false) {","highlight_start":24,"highlight_end":25}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":822,"byte_end":823,"line_start":44,"line_end":44,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" while(true && false) {","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":836,"byte_end":837,"line_start":44,"line_end":44,"column_start":24,"column_end":25,"is_primary":true,"text":[{"text":" while(true && false) {","highlight_start":24,"highlight_end":25}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition --> $DIR/unused_parens_remove_json_suggestion.rs:44:10 | LL | while(true && false) { @@ -81,7 +81,7 @@ LL + while true && false { | "} -{"$message_type":"diagnostic","message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":842,"byte_end":843,"line_start":45,"line_end":45,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){","highlight_start":18,"highlight_end":19}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":849,"byte_end":850,"line_start":45,"line_end":45,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":842,"byte_end":843,"line_start":45,"line_end":45,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){","highlight_start":18,"highlight_end":19}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":849,"byte_end":850,"line_start":45,"line_end":45,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `for` iterator expression +{"$message_type":"diagnostic","message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":857,"byte_end":858,"line_start":45,"line_end":45,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){","highlight_start":18,"highlight_end":19}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":864,"byte_end":865,"line_start":45,"line_end":45,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":857,"byte_end":858,"line_start":45,"line_end":45,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){","highlight_start":18,"highlight_end":19}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":864,"byte_end":865,"line_start":45,"line_end":45,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `for` iterator expression --> $DIR/unused_parens_remove_json_suggestion.rs:45:18 | LL | for _ in (0 .. 3){ @@ -94,7 +94,7 @@ LL + for _ in 0 .. 3 { | "} -{"$message_type":"diagnostic","message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":909,"byte_end":910,"line_start":50,"line_end":50,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":916,"byte_end":917,"line_start":50,"line_end":50,"column_start":21,"column_end":22,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {","highlight_start":21,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":909,"byte_end":910,"line_start":50,"line_end":50,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":916,"byte_end":917,"line_start":50,"line_end":50,"column_start":21,"column_end":22,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {","highlight_start":21,"highlight_end":22}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `for` iterator expression +{"$message_type":"diagnostic","message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":924,"byte_end":925,"line_start":50,"line_end":50,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":931,"byte_end":932,"line_start":50,"line_end":50,"column_start":21,"column_end":22,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {","highlight_start":21,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":924,"byte_end":925,"line_start":50,"line_end":50,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":931,"byte_end":932,"line_start":50,"line_end":50,"column_start":21,"column_end":22,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {","highlight_start":21,"highlight_end":22}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `for` iterator expression --> $DIR/unused_parens_remove_json_suggestion.rs:50:14 | LL | for _ in (0 .. 3) { @@ -107,7 +107,7 @@ LL + for _ in 0 .. 3 { | "} -{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":934,"byte_end":935,"line_start":51,"line_end":51,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":" while (true && false) {","highlight_start":15,"highlight_end":16}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":948,"byte_end":949,"line_start":51,"line_end":51,"column_start":29,"column_end":30,"is_primary":true,"text":[{"text":" while (true && false) {","highlight_start":29,"highlight_end":30}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":934,"byte_end":935,"line_start":51,"line_end":51,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":" while (true && false) {","highlight_start":15,"highlight_end":16}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":948,"byte_end":949,"line_start":51,"line_end":51,"column_start":29,"column_end":30,"is_primary":true,"text":[{"text":" while (true && false) {","highlight_start":29,"highlight_end":30}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition +{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":949,"byte_end":950,"line_start":51,"line_end":51,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":" while (true && false) {","highlight_start":15,"highlight_end":16}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":963,"byte_end":964,"line_start":51,"line_end":51,"column_start":29,"column_end":30,"is_primary":true,"text":[{"text":" while (true && false) {","highlight_start":29,"highlight_end":30}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":949,"byte_end":950,"line_start":51,"line_end":51,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":" while (true && false) {","highlight_start":15,"highlight_end":16}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":963,"byte_end":964,"line_start":51,"line_end":51,"column_start":29,"column_end":30,"is_primary":true,"text":[{"text":" while (true && false) {","highlight_start":29,"highlight_end":30}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition --> $DIR/unused_parens_remove_json_suggestion.rs:51:15 | LL | while (true && false) { diff --git a/tests/ui/match/intended-binding-pattern-is-const.rs b/tests/ui/match/intended-binding-pattern-is-const.rs new file mode 100644 index 00000000000..95c8119cdb9 --- /dev/null +++ b/tests/ui/match/intended-binding-pattern-is-const.rs @@ -0,0 +1,10 @@ +fn main() { + match 1 { //~ ERROR non-exhaustive patterns + //~^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered + //~| the matched value is of type `i32` + x => {} //~ this pattern doesn't introduce a new catch-all binding + //~^ HELP ensure that all possible cases are being handled + //~| HELP if you meant to introduce a binding, use a different name + } + const x: i32 = 4; //~ NOTE constant `x` defined here +} diff --git a/tests/ui/match/intended-binding-pattern-is-const.stderr b/tests/ui/match/intended-binding-pattern-is-const.stderr new file mode 100644 index 00000000000..99af1c7a16e --- /dev/null +++ b/tests/ui/match/intended-binding-pattern-is-const.stderr @@ -0,0 +1,27 @@ +error[E0004]: non-exhaustive patterns: `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered + --> $DIR/intended-binding-pattern-is-const.rs:2:11 + | +LL | match 1 { + | ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered +... +LL | x => {} + | - this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `x` + | + = note: the matched value is of type `i32` +note: constant `x` defined here + --> $DIR/intended-binding-pattern-is-const.rs:9:5 + | +LL | const x: i32 = 4; + | ^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | x_var => {} + | ++++ +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL | x => {}, i32::MIN..=3_i32 | 5_i32..=i32::MAX => todo!() + | ++++++++++++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/mir/issue-112269.stderr b/tests/ui/mir/issue-112269.stderr index f5b79602797..adb662c98a7 100644 --- a/tests/ui/mir/issue-112269.stderr +++ b/tests/ui/mir/issue-112269.stderr @@ -1,30 +1,34 @@ error[E0005]: refutable pattern in local binding --> $DIR/issue-112269.rs:3:9 | +LL | const x: i32 = 4; + | ------------ missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable LL | let x: i32 = 3; - | ^ - | | - | patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered - | missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable - | help: introduce a variable instead: `x_var` + | ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` +help: introduce a variable instead + | +LL | let x_var: i32 = 3; + | ~~~~~ error[E0005]: refutable pattern in local binding --> $DIR/issue-112269.rs:7:9 | +LL | const y: i32 = 3; + | ------------ missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable LL | let y = 4; - | ^ - | | - | patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered - | missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable - | help: introduce a variable instead: `y_var` + | ^ patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` +help: introduce a variable instead + | +LL | let y_var = 4; + | ~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/missing/missing-block-hint.stderr b/tests/ui/missing/missing-block-hint.stderr index 18719289abd..7a08d70d0ce 100644 --- a/tests/ui/missing/missing-block-hint.stderr +++ b/tests/ui/missing/missing-block-hint.stderr @@ -25,7 +25,7 @@ note: the `if` expression is missing a block after this condition | LL | if (foo) | ^^^^^ -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | { bar; } | + + diff --git a/tests/ui/moves/moved-value-on-as-ref-arg.fixed b/tests/ui/moves/moved-value-on-as-ref-arg.fixed index 292fa98a3f7..97bfe094ce5 100644 --- a/tests/ui/moves/moved-value-on-as-ref-arg.fixed +++ b/tests/ui/moves/moved-value-on-as-ref-arg.fixed @@ -18,8 +18,8 @@ impl AsMut<Bar> for Bar { fn foo<T: AsRef<Bar>>(_: T) {} fn qux<T: AsMut<Bar>>(_: T) {} -fn bat<T: Borrow<T>>(_: T) {} -fn baz<T: BorrowMut<T>>(_: T) {} +fn bat<T: Borrow<Bar>>(_: T) {} +fn baz<T: BorrowMut<Bar>>(_: T) {} pub fn main() { let bar = Bar; diff --git a/tests/ui/moves/moved-value-on-as-ref-arg.rs b/tests/ui/moves/moved-value-on-as-ref-arg.rs index 632af9efcda..fed41cf710d 100644 --- a/tests/ui/moves/moved-value-on-as-ref-arg.rs +++ b/tests/ui/moves/moved-value-on-as-ref-arg.rs @@ -18,8 +18,8 @@ impl AsMut<Bar> for Bar { fn foo<T: AsRef<Bar>>(_: T) {} fn qux<T: AsMut<Bar>>(_: T) {} -fn bat<T: Borrow<T>>(_: T) {} -fn baz<T: BorrowMut<T>>(_: T) {} +fn bat<T: Borrow<Bar>>(_: T) {} +fn baz<T: BorrowMut<Bar>>(_: T) {} pub fn main() { let bar = Bar; diff --git a/tests/ui/moves/region-var-in-moved-ty-issue-133118.rs b/tests/ui/moves/region-var-in-moved-ty-issue-133118.rs new file mode 100644 index 00000000000..a49370e315d --- /dev/null +++ b/tests/ui/moves/region-var-in-moved-ty-issue-133118.rs @@ -0,0 +1,25 @@ +//! regression test for #133118 + +pub trait Alpha { + fn y(self) -> usize; +} + +pub trait Beta { + type Gamma; + fn gamma(&self) -> Self::Gamma; +} + +pub fn a<T: Alpha>(_x: T) -> usize { + todo!(); +} + +pub fn x<B>(beta: &B) -> usize +where + for<'a> &'a B: Beta, + for<'a> <&'a B as Beta>::Gamma: Alpha, +{ + let g1 = beta.gamma(); + a(g1) + a(g1) //~ ERROR use of moved value: `g1` [E0382] +} + +pub fn main() {} diff --git a/tests/ui/moves/region-var-in-moved-ty-issue-133118.stderr b/tests/ui/moves/region-var-in-moved-ty-issue-133118.stderr new file mode 100644 index 00000000000..691625d042d --- /dev/null +++ b/tests/ui/moves/region-var-in-moved-ty-issue-133118.stderr @@ -0,0 +1,21 @@ +error[E0382]: use of moved value: `g1` + --> $DIR/region-var-in-moved-ty-issue-133118.rs:22:15 + | +LL | let g1 = beta.gamma(); + | -- move occurs because `g1` has type `<&B as Beta>::Gamma`, which does not implement the `Copy` trait +LL | a(g1) + a(g1) + | -- ^^ value used here after move + | | + | value moved here + | +note: consider changing this parameter type in function `a` to borrow instead if owning the value isn't necessary + --> $DIR/region-var-in-moved-ty-issue-133118.rs:12:24 + | +LL | pub fn a<T: Alpha>(_x: T) -> usize { + | - ^ this parameter takes ownership of the value + | | + | in this function + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/native-library-link-flags/modifiers-bad.blank.stderr b/tests/ui/native-library-link-flags/modifiers-bad.blank.stderr new file mode 100644 index 00000000000..ea36af0b4cf --- /dev/null +++ b/tests/ui/native-library-link-flags/modifiers-bad.blank.stderr @@ -0,0 +1,2 @@ +error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed + diff --git a/tests/ui/native-library-link-flags/modifiers-bad.no-prefix.stderr b/tests/ui/native-library-link-flags/modifiers-bad.no-prefix.stderr new file mode 100644 index 00000000000..ea36af0b4cf --- /dev/null +++ b/tests/ui/native-library-link-flags/modifiers-bad.no-prefix.stderr @@ -0,0 +1,2 @@ +error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed + diff --git a/tests/ui/native-library-link-flags/modifiers-bad.prefix-only.stderr b/tests/ui/native-library-link-flags/modifiers-bad.prefix-only.stderr new file mode 100644 index 00000000000..1e701374688 --- /dev/null +++ b/tests/ui/native-library-link-flags/modifiers-bad.prefix-only.stderr @@ -0,0 +1,2 @@ +error: unknown linking modifier ``, expected one of: bundle, verbatim, whole-archive, as-needed + diff --git a/tests/ui/native-library-link-flags/modifiers-bad.rs b/tests/ui/native-library-link-flags/modifiers-bad.rs new file mode 100644 index 00000000000..185201e0d84 --- /dev/null +++ b/tests/ui/native-library-link-flags/modifiers-bad.rs @@ -0,0 +1,11 @@ +//@ edition: 2021 +//@ revisions: blank no-prefix prefix-only unknown + +//@[blank] compile-flags: -l static:=foo +//@[no-prefix] compile-flags: -l static:bundle=foo +//@[prefix-only] compile-flags: -l static:+=foo +//@[unknown] compile-flags: -l static:+ferris=foo + +// Tests various illegal values for the "modifier" part of an `-l` flag. + +fn main() {} diff --git a/tests/ui/native-library-link-flags/modifiers-bad.unknown.stderr b/tests/ui/native-library-link-flags/modifiers-bad.unknown.stderr new file mode 100644 index 00000000000..75950ad9c64 --- /dev/null +++ b/tests/ui/native-library-link-flags/modifiers-bad.unknown.stderr @@ -0,0 +1,2 @@ +error: unknown linking modifier `ferris`, expected one of: bundle, verbatim, whole-archive, as-needed + diff --git a/tests/ui/never_type/defaulted-never-note.nofallback.stderr b/tests/ui/never_type/defaulted-never-note.nofallback.stderr index 6bc4501b6a3..e8d0be10d4d 100644 --- a/tests/ui/never_type/defaulted-never-note.nofallback.stderr +++ b/tests/ui/never_type/defaulted-never-note.nofallback.stderr @@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()` LL | fn smeg() { | ^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the types explicitly note: in edition 2024, the requirement `!: ImplementedForUnitButNotNever` will fail diff --git a/tests/ui/never_type/defaulted-never-note.rs b/tests/ui/never_type/defaulted-never-note.rs index 40861e73b39..badb5d4c51d 100644 --- a/tests/ui/never_type/defaulted-never-note.rs +++ b/tests/ui/never_type/defaulted-never-note.rs @@ -27,7 +27,7 @@ fn foo<T: ImplementedForUnitButNotNever>(_t: T) {} //[fallback]~| NOTE required by a bound in `foo` fn smeg() { //[nofallback]~^ warn: this function depends on never type fallback being `()` - //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! let _x = return; foo(_x); //[fallback]~^ ERROR the trait bound diff --git a/tests/ui/never_type/dependency-on-fallback-to-unit.rs b/tests/ui/never_type/dependency-on-fallback-to-unit.rs index 5448d0be2c6..fad4c7c7df7 100644 --- a/tests/ui/never_type/dependency-on-fallback-to-unit.rs +++ b/tests/ui/never_type/dependency-on-fallback-to-unit.rs @@ -7,7 +7,7 @@ fn main() { fn def() { //~^ warn: this function depends on never type fallback being `()` - //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! match true { false => <_>::default(), true => return, @@ -18,7 +18,7 @@ fn def() { // <https://github.com/rust-lang/rust/issues/39216> fn question_mark() -> Result<(), ()> { //~^ warn: this function depends on never type fallback being `()` - //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! deserialize()?; Ok(()) } diff --git a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr index 79f47bb5fbc..2f10428ee93 100644 --- a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr +++ b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr @@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()` LL | fn def() { | ^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail @@ -24,7 +24,7 @@ warning: this function depends on never type fallback being `()` LL | fn question_mark() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the types explicitly note: in edition 2024, the requirement `!: Default` will fail diff --git a/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr index d40d1da76f9..35b245bd743 100644 --- a/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr +++ b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr @@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()` LL | fn assignment() { | ^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the types explicitly note: in edition 2024, the requirement `!: UnitDefault` will fail @@ -24,7 +24,7 @@ warning: this function depends on never type fallback being `()` LL | fn assignment_rev() { | ^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the types explicitly note: in edition 2024, the requirement `!: UnitDefault` will fail diff --git a/tests/ui/never_type/diverging-fallback-control-flow.rs b/tests/ui/never_type/diverging-fallback-control-flow.rs index 575e2e9273c..647667126d4 100644 --- a/tests/ui/never_type/diverging-fallback-control-flow.rs +++ b/tests/ui/never_type/diverging-fallback-control-flow.rs @@ -29,7 +29,7 @@ impl UnitDefault for () { fn assignment() { //[nofallback]~^ warn: this function depends on never type fallback being `()` - //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! let x; if true { @@ -41,7 +41,7 @@ fn assignment() { fn assignment_rev() { //[nofallback]~^ warn: this function depends on never type fallback being `()` - //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! let x; if true { diff --git a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr index d11c21d9573..689791fc460 100644 --- a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr +++ b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr @@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()` LL | fn main() { | ^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the types explicitly note: in edition 2024, the requirement `!: Test` will fail diff --git a/tests/ui/never_type/diverging-fallback-no-leak.rs b/tests/ui/never_type/diverging-fallback-no-leak.rs index c6d59c7f273..75ca491bf46 100644 --- a/tests/ui/never_type/diverging-fallback-no-leak.rs +++ b/tests/ui/never_type/diverging-fallback-no-leak.rs @@ -13,7 +13,7 @@ fn unconstrained_arg<T: Test>(_: T) {} fn main() { //[nofallback]~^ warn: this function depends on never type fallback being `()` - //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! // Here the type variable falls back to `!`, // and hence we get a type error. diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr index 30a5e60a758..42018c54609 100644 --- a/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr +++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr @@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()` LL | fn main() { | ^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the types explicitly note: in edition 2024, the requirement `!: UnitReturn` will fail diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.rs b/tests/ui/never_type/diverging-fallback-unconstrained-return.rs index 927991db513..fdea3a94d28 100644 --- a/tests/ui/never_type/diverging-fallback-unconstrained-return.rs +++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.rs @@ -27,7 +27,7 @@ fn unconstrained_return<T: UnitReturn>() -> T { fn main() { //[nofallback]~^ warn: this function depends on never type fallback being `()` - //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! // In Ye Olde Days, the `T` parameter of `unconstrained_return` // winds up "entangled" with the `!` type that results from diff --git a/tests/ui/never_type/fallback-closure-ret.nofallback.stderr b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr index fb0166dd9e0..b5b5d87e7dd 100644 --- a/tests/ui/never_type/fallback-closure-ret.nofallback.stderr +++ b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr @@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()` LL | fn main() { | ^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the types explicitly note: in edition 2024, the requirement `!: Bar` will fail diff --git a/tests/ui/never_type/fallback-closure-ret.rs b/tests/ui/never_type/fallback-closure-ret.rs index 30f9ac54d0b..f1423354f13 100644 --- a/tests/ui/never_type/fallback-closure-ret.rs +++ b/tests/ui/never_type/fallback-closure-ret.rs @@ -20,6 +20,6 @@ fn foo<R: Bar>(_: impl Fn() -> R) {} fn main() { //[nofallback]~^ warn: this function depends on never type fallback being `()` - //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! foo(|| panic!()); } diff --git a/tests/ui/never_type/impl_trait_fallback.rs b/tests/ui/never_type/impl_trait_fallback.rs index fbe13dbe2ac..bd4caeb2b72 100644 --- a/tests/ui/never_type/impl_trait_fallback.rs +++ b/tests/ui/never_type/impl_trait_fallback.rs @@ -7,6 +7,6 @@ impl T for () {} fn should_ret_unit() -> impl T { //~^ warn: this function depends on never type fallback being `()` - //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! panic!() } diff --git a/tests/ui/never_type/impl_trait_fallback.stderr b/tests/ui/never_type/impl_trait_fallback.stderr index 4496746e018..768c226e989 100644 --- a/tests/ui/never_type/impl_trait_fallback.stderr +++ b/tests/ui/never_type/impl_trait_fallback.stderr @@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()` LL | fn should_ret_unit() -> impl T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the types explicitly note: in edition 2024, the requirement `!: T` will fail diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr index 6a48a7b9b47..03bb0ca5f3a 100644 --- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr +++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr @@ -4,7 +4,7 @@ warning: never type fallback affects this call to an `unsafe` function LL | unsafe { mem::zeroed() } | ^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default @@ -19,7 +19,7 @@ warning: never type fallback affects this call to an `unsafe` function LL | core::mem::transmute(Zst) | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly help: use `()` annotations to avoid fallback changes @@ -33,7 +33,7 @@ warning: never type fallback affects this union access LL | unsafe { Union { a: () }.b } | ^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly @@ -43,7 +43,7 @@ warning: never type fallback affects this raw pointer dereference LL | unsafe { *ptr::from_ref(&()).cast() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly help: use `()` annotations to avoid fallback changes @@ -57,7 +57,7 @@ warning: never type fallback affects this call to an `unsafe` function LL | unsafe { internally_create(x) } | ^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly help: use `()` annotations to avoid fallback changes @@ -71,7 +71,7 @@ warning: never type fallback affects this call to an `unsafe` function LL | unsafe { zeroed() } | ^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly help: use `()` annotations to avoid fallback changes @@ -85,7 +85,7 @@ warning: never type fallback affects this `unsafe` function LL | let zeroed = mem::zeroed; | ^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly help: use `()` annotations to avoid fallback changes @@ -99,7 +99,7 @@ warning: never type fallback affects this `unsafe` function LL | let f = internally_create; | ^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly help: use `()` annotations to avoid fallback changes @@ -113,7 +113,7 @@ warning: never type fallback affects this call to an `unsafe` method LL | S(marker::PhantomData).create_out_of_thin_air() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly @@ -126,7 +126,7 @@ LL | match send_message::<_ /* ?0 */>() { LL | msg_send!(); | ----------- in this macro invocation | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly = note: this warning originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr index 844cd62c267..cf12d699f2e 100644 --- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr +++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr @@ -4,7 +4,7 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { mem::zeroed() } | ^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default @@ -19,7 +19,7 @@ error: never type fallback affects this call to an `unsafe` function LL | core::mem::transmute(Zst) | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly help: use `()` annotations to avoid fallback changes @@ -33,7 +33,7 @@ error: never type fallback affects this union access LL | unsafe { Union { a: () }.b } | ^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly @@ -43,7 +43,7 @@ error: never type fallback affects this raw pointer dereference LL | unsafe { *ptr::from_ref(&()).cast() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly help: use `()` annotations to avoid fallback changes @@ -57,7 +57,7 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { internally_create(x) } | ^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly help: use `()` annotations to avoid fallback changes @@ -71,7 +71,7 @@ error: never type fallback affects this call to an `unsafe` function LL | unsafe { zeroed() } | ^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly help: use `()` annotations to avoid fallback changes @@ -85,7 +85,7 @@ error: never type fallback affects this `unsafe` function LL | let zeroed = mem::zeroed; | ^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly help: use `()` annotations to avoid fallback changes @@ -99,7 +99,7 @@ error: never type fallback affects this `unsafe` function LL | let f = internally_create; | ^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly help: use `()` annotations to avoid fallback changes @@ -113,7 +113,7 @@ error: never type fallback affects this call to an `unsafe` method LL | S(marker::PhantomData).create_out_of_thin_air() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly @@ -126,7 +126,7 @@ LL | match send_message::<_ /* ?0 */>() { LL | msg_send!(); | ----------- in this macro invocation | - = warning: this will change its meaning in a future release! + = warning: this changes meaning in Rust 2024 and in a future release in all editions! = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> = help: specify the type explicitly = note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs index c96f4dda3f8..19b51eea2f5 100644 --- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs +++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs @@ -13,7 +13,7 @@ fn _zero() { unsafe { mem::zeroed() } //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function - //~| warn: this will change its meaning in a future release! + //~| warn: this changes meaning in Rust 2024 and in a future release in all editions! //[e2024]~| warning: the type `!` does not permit zero-initialization } else { return; @@ -30,7 +30,7 @@ fn _trans() { core::mem::transmute(Zst) //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function - //~| warn: this will change its meaning in a future release! + //~| warn: this changes meaning in Rust 2024 and in a future release in all editions! } } else { return; @@ -47,7 +47,7 @@ fn _union() { unsafe { Union { a: () }.b } //[e2015]~^ warn: never type fallback affects this union access //[e2024]~^^ error: never type fallback affects this union access - //~| warn: this will change its meaning in a future release! + //~| warn: this changes meaning in Rust 2024 and in a future release in all editions! } else { return; }; @@ -58,7 +58,7 @@ fn _deref() { unsafe { *ptr::from_ref(&()).cast() } //[e2015]~^ warn: never type fallback affects this raw pointer dereference //[e2024]~^^ error: never type fallback affects this raw pointer dereference - //~| warn: this will change its meaning in a future release! + //~| warn: this changes meaning in Rust 2024 and in a future release in all editions! } else { return; }; @@ -79,7 +79,7 @@ fn _only_generics() { unsafe { internally_create(x) } //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function - //~| warn: this will change its meaning in a future release! + //~| warn: this changes meaning in Rust 2024 and in a future release in all editions! x.unwrap() } else { @@ -92,12 +92,12 @@ fn _stored_function() { let zeroed = mem::zeroed; //[e2015]~^ warn: never type fallback affects this `unsafe` function //[e2024]~^^ error: never type fallback affects this `unsafe` function - //~| warn: this will change its meaning in a future release! + //~| warn: this changes meaning in Rust 2024 and in a future release in all editions! unsafe { zeroed() } //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function - //~| warn: this will change its meaning in a future release! + //~| warn: this changes meaning in Rust 2024 and in a future release in all editions! } else { return; }; @@ -115,7 +115,7 @@ fn _only_generics_stored_function() { let f = internally_create; //[e2015]~^ warn: never type fallback affects this `unsafe` function //[e2024]~^^ error: never type fallback affects this `unsafe` function - //~| warn: this will change its meaning in a future release! + //~| warn: this changes meaning in Rust 2024 and in a future release in all editions! unsafe { f(x) } @@ -140,7 +140,7 @@ fn _method() { S(marker::PhantomData).create_out_of_thin_air() //[e2015]~^ warn: never type fallback affects this call to an `unsafe` method //[e2024]~^^ error: never type fallback affects this call to an `unsafe` method - //~| warn: this will change its meaning in a future release! + //~| warn: this changes meaning in Rust 2024 and in a future release in all editions! } } else { return; @@ -158,7 +158,7 @@ fn _objc() { match send_message::<_ /* ?0 */>() { //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function - //~| warn: this will change its meaning in a future release! + //~| warn: this changes meaning in Rust 2024 and in a future release in all editions! Ok(x) => x, Err(_) => loop {}, } diff --git a/tests/ui/parser/bad-if-statements.stderr b/tests/ui/parser/bad-if-statements.stderr index ee839db6455..320b1176993 100644 --- a/tests/ui/parser/bad-if-statements.stderr +++ b/tests/ui/parser/bad-if-statements.stderr @@ -29,7 +29,7 @@ note: the `if` expression is missing a block after this condition | LL | if true x | ^^^^ -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | if true { x } | + + @@ -65,7 +65,7 @@ note: the `if` expression is missing a block after this condition | LL | if true x else {} | ^^^^ -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | if true { x } else {} | + + diff --git a/tests/ui/parser/block-no-opening-brace.stderr b/tests/ui/parser/block-no-opening-brace.stderr index 83360944ed5..b65de4eac3f 100644 --- a/tests/ui/parser/block-no-opening-brace.stderr +++ b/tests/ui/parser/block-no-opening-brace.stderr @@ -6,7 +6,7 @@ LL | loop LL | let x = 0; | ^^^ expected `{` | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | { let x = 0; } | + + @@ -21,7 +21,7 @@ LL | while true LL | let x = 0; | ^^^ expected `{` | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | { let x = 0; } | + + @@ -32,7 +32,7 @@ error: expected `{`, found keyword `let` LL | let x = 0; | ^^^ expected `{` | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | { let x = 0; } | + + diff --git a/tests/ui/parser/closure-return-syntax.stderr b/tests/ui/parser/closure-return-syntax.stderr index eb8428854af..aacc31ed871 100644 --- a/tests/ui/parser/closure-return-syntax.stderr +++ b/tests/ui/parser/closure-return-syntax.stderr @@ -4,7 +4,7 @@ error: expected `{`, found `22` LL | let x = || -> i32 22; | ^^ expected `{` | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | let x = || -> i32 { 22 }; | + + diff --git a/tests/ui/parser/else-no-if.stderr b/tests/ui/parser/else-no-if.stderr index 2e3e8f6b50e..eec64b0f4bc 100644 --- a/tests/ui/parser/else-no-if.stderr +++ b/tests/ui/parser/else-no-if.stderr @@ -30,7 +30,7 @@ error: expected `{`, found `falsy` LL | } else falsy(); | ^^^^^ expected `{` | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | } else { falsy() }; | + + @@ -41,7 +41,7 @@ error: expected `{`, found keyword `loop` LL | } else loop{} | ^^^^ expected `{` | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | } else { loop{} } | + + @@ -65,7 +65,7 @@ error: expected `{`, found `falsy` LL | } else falsy!(); | ^^^^^ expected `{` | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | } else { falsy!() }; | + + @@ -74,12 +74,14 @@ error: expected `{`, found `falsy` --> $DIR/else-no-if.rs:47:12 | LL | } else falsy! {} { - | ^^^^^ expected `{` + | ---- ^^^^^ + | | + | expected an `if` or a block after this `else` | -help: try placing this code inside a block +help: add an `if` if this is the condition of a chained `else if` statement | -LL | } else { falsy! {} } { - | + + +LL | } else if falsy! {} { + | ++ error: expected `{`, found `falsy` --> $DIR/else-no-if.rs:54:12 @@ -87,7 +89,7 @@ error: expected `{`, found `falsy` LL | } else falsy! {}; | ^^^^^ expected `{` | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | } else { falsy! {} }; | + + diff --git a/tests/ui/parser/label-after-block-like.stderr b/tests/ui/parser/label-after-block-like.stderr index be8c679d8ce..4dea225e3f3 100644 --- a/tests/ui/parser/label-after-block-like.stderr +++ b/tests/ui/parser/label-after-block-like.stderr @@ -23,7 +23,7 @@ note: the `if` expression is missing a block after this condition | LL | if let () = () 'a {} | ^^^^^^^^^^^ -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | if let () = () { 'a {} } | + + @@ -53,7 +53,7 @@ note: the `if` expression is missing a block after this condition | LL | if true 'a {} | ^^^^ -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | if true { 'a {} } | + + @@ -80,7 +80,7 @@ LL | loop 'a {} | | | while parsing this `loop` expression | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | loop { 'a {} } | + + @@ -108,7 +108,7 @@ LL | while true 'a {} | | this `while` condition successfully parsed | while parsing the body of this `while` expression | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | while true { 'a {} } | + + @@ -136,7 +136,7 @@ LL | while let () = () 'a {} | | this `while` condition successfully parsed | while parsing the body of this `while` expression | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | while let () = () { 'a {} } | + + @@ -161,7 +161,7 @@ error: expected `{`, found `'a` LL | for _ in 0..0 'a {} | ^^ expected `{` | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | for _ in 0..0 { 'a {} } | + + @@ -188,7 +188,7 @@ LL | unsafe 'a {} | | | while parsing this `unsafe` expression | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | unsafe { 'a {} } | + + diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.fixed b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.fixed new file mode 100644 index 00000000000..ea9dc4cf6cc --- /dev/null +++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.fixed @@ -0,0 +1,39 @@ +//@ run-rustfix +#![allow(dead_code)] +fn main() { + for _ in [1, 2, 3].iter().map(|x| x) {} + //~^ ERROR expected `{`, found `map` + //~| HELP you might have meant to write a method call +} +fn foo5() { + let x = (vec![1, 2, 3],); + for _ in x.0 {} + //~^ ERROR expected `{`, found `0` + //~| HELP you might have meant to write a field access +} +fn foo6() { + let x = ((vec![1, 2, 3],),); + for _ in x.0.0 {} + //~^ ERROR expected `{`, found `0.0` + //~| HELP you might have meant to write a field access +} +fn foo7() { + let x = Some(vec![1, 2, 3]); + for _ in x.unwrap() {} + //~^ ERROR expected `{`, found `unwrap` + //~| HELP you might have meant to write a method call +} +fn foo8() { + let x = S { a: A { b: vec![1, 2, 3] } }; + for _ in x.a.b {} + //~^ ERROR expected `{`, found `a` + //~| HELP you might have meant to write a field access +} + +struct S { + a: A, +} + +struct A { + b: Vec<i32>, +} diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.rs b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.rs new file mode 100644 index 00000000000..1833f458a8a --- /dev/null +++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.rs @@ -0,0 +1,39 @@ +//@ run-rustfix +#![allow(dead_code)] +fn main() { + for _ in [1, 2, 3].iter()map(|x| x) {} + //~^ ERROR expected `{`, found `map` + //~| HELP you might have meant to write a method call +} +fn foo5() { + let x = (vec![1, 2, 3],); + for _ in x 0 {} + //~^ ERROR expected `{`, found `0` + //~| HELP you might have meant to write a field access +} +fn foo6() { + let x = ((vec![1, 2, 3],),); + for _ in x 0.0 {} + //~^ ERROR expected `{`, found `0.0` + //~| HELP you might have meant to write a field access +} +fn foo7() { + let x = Some(vec![1, 2, 3]); + for _ in x unwrap() {} + //~^ ERROR expected `{`, found `unwrap` + //~| HELP you might have meant to write a method call +} +fn foo8() { + let x = S { a: A { b: vec![1, 2, 3] } }; + for _ in x a.b {} + //~^ ERROR expected `{`, found `a` + //~| HELP you might have meant to write a field access +} + +struct S { + a: A, +} + +struct A { + b: Vec<i32>, +} diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.stderr b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.stderr new file mode 100644 index 00000000000..87f76efffa6 --- /dev/null +++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.stderr @@ -0,0 +1,57 @@ +error: expected `{`, found `map` + --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:4:30 + | +LL | for _ in [1, 2, 3].iter()map(|x| x) {} + | ^^^ expected `{` + | +help: you might have meant to write a method call + | +LL | for _ in [1, 2, 3].iter().map(|x| x) {} + | + + +error: expected `{`, found `0` + --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:10:16 + | +LL | for _ in x 0 {} + | ^ expected `{` + | +help: you might have meant to write a field access + | +LL | for _ in x.0 {} + | + + +error: expected `{`, found `0.0` + --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:16:16 + | +LL | for _ in x 0.0 {} + | ^^^ expected `{` + | +help: you might have meant to write a field access + | +LL | for _ in x.0.0 {} + | + + +error: expected `{`, found `unwrap` + --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:22:16 + | +LL | for _ in x unwrap() {} + | ^^^^^^ expected `{` + | +help: you might have meant to write a method call + | +LL | for _ in x.unwrap() {} + | + + +error: expected `{`, found `a` + --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:28:16 + | +LL | for _ in x a.b {} + | ^ expected `{` + | +help: you might have meant to write a field access + | +LL | for _ in x.a.b {} + | + + +error: aborting due to 5 previous errors + diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs new file mode 100644 index 00000000000..c4a9ed66a83 --- /dev/null +++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs @@ -0,0 +1,57 @@ +fn main() { + for _ in [1, 2, 3].iter()map(|x| x) {} + //~^ ERROR expected `{`, found `map` + //~| HELP you might have meant to write a method call +} +fn foo1() { + for _ in 1.3f64 cos() {} + //~^ ERROR expected `{`, found `cos` + //~| HELP you might have meant to write a method call +} +fn foo2() { + for _ in 1.3 cos {} + //~^ ERROR expected `{`, found `cos` + //~| HELP you might have meant to write a field access +} +fn foo3() { + for _ in 1 cos() {} + //~^ ERROR expected `{`, found `cos` + //~| HELP you might have meant to write a method call +} +fn foo4() { + for _ in 1 cos {} + //~^ ERROR expected `{`, found `cos` + //~| HELP you might have meant to write a field access +} +fn foo5() { + let x = (vec![1, 2, 3],); + for _ in x 0 {} + //~^ ERROR expected `{`, found `0` + //~| HELP you might have meant to write a field access +} +fn foo6() { + let x = ((vec![1, 2, 3],),); + for _ in x 0.0 {} + //~^ ERROR expected `{`, found `0.0` + //~| HELP you might have meant to write a field access +} +fn foo7() { + let x = Some(vec![1, 2, 3]); + for _ in x unwrap() {} + //~^ ERROR expected `{`, found `unwrap` + //~| HELP you might have meant to write a method call +} +fn foo8() { + let x = S { a: A { b: vec![1, 2, 3] } }; + for _ in x a.b {} + //~^ ERROR expected `{`, found `a` + //~| HELP you might have meant to write a field access +} + +struct S { + a: A, +} + +struct A { + b: Vec<i32>, +} diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr new file mode 100644 index 00000000000..bfb72b95682 --- /dev/null +++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr @@ -0,0 +1,101 @@ +error: expected `{`, found `map` + --> $DIR/missing-dot-on-if-condition-expression.rs:2:30 + | +LL | for _ in [1, 2, 3].iter()map(|x| x) {} + | ^^^ expected `{` + | +help: you might have meant to write a method call + | +LL | for _ in [1, 2, 3].iter().map(|x| x) {} + | + + +error: expected `{`, found `cos` + --> $DIR/missing-dot-on-if-condition-expression.rs:7:21 + | +LL | for _ in 1.3f64 cos() {} + | ^^^ expected `{` + | +help: you might have meant to write a method call + | +LL | for _ in 1.3f64.cos() {} + | + + +error: expected `{`, found `cos` + --> $DIR/missing-dot-on-if-condition-expression.rs:12:18 + | +LL | for _ in 1.3 cos {} + | ^^^ expected `{` + | +help: you might have meant to write a field access + | +LL | for _ in 1.3.cos {} + | + + +error: expected `{`, found `cos` + --> $DIR/missing-dot-on-if-condition-expression.rs:17:16 + | +LL | for _ in 1 cos() {} + | ^^^ expected `{` + | +help: you might have meant to write a method call + | +LL | for _ in 1.cos() {} + | + + +error: expected `{`, found `cos` + --> $DIR/missing-dot-on-if-condition-expression.rs:22:16 + | +LL | for _ in 1 cos {} + | ^^^ expected `{` + | +help: you might have meant to write a field access + | +LL | for _ in 1.cos {} + | + + +error: expected `{`, found `0` + --> $DIR/missing-dot-on-if-condition-expression.rs:28:16 + | +LL | for _ in x 0 {} + | ^ expected `{` + | +help: you might have meant to write a field access + | +LL | for _ in x.0 {} + | + + +error: expected `{`, found `0.0` + --> $DIR/missing-dot-on-if-condition-expression.rs:34:16 + | +LL | for _ in x 0.0 {} + | ^^^ expected `{` + | +help: you might have meant to write a field access + | +LL | for _ in x.0.0 {} + | + + +error: expected `{`, found `unwrap` + --> $DIR/missing-dot-on-if-condition-expression.rs:40:16 + | +LL | for _ in x unwrap() {} + | ^^^^^^ expected `{` + | +help: you might have meant to write a method call + | +LL | for _ in x.unwrap() {} + | + + +error: expected `{`, found `a` + --> $DIR/missing-dot-on-if-condition-expression.rs:46:16 + | +LL | for _ in x a.b {} + | ^ expected `{` + | +help: you might have meant to write a field access + | +LL | for _ in x.a.b {} + | + + +error: aborting due to 9 previous errors + diff --git a/tests/ui/parser/suggest-const-for-global-var.stderr b/tests/ui/parser/suggest-const-for-global-var.stderr index 235e621d882..6ac7fe8f092 100644 --- a/tests/ui/parser/suggest-const-for-global-var.stderr +++ b/tests/ui/parser/suggest-const-for-global-var.stderr @@ -2,7 +2,12 @@ error: expected item, found keyword `let` --> $DIR/suggest-const-for-global-var.rs:1:1 | LL | let X: i32 = 12; - | ^^^ consider using `const` or `static` instead of `let` for global variables + | ^^^ + | | + | `let` cannot be used for global variables + | help: consider using `static` or `const` instead of `let` + | + = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> error: aborting due to 1 previous error diff --git a/tests/ui/parser/suggest-static-for-global-var-mut.rs b/tests/ui/parser/suggest-static-for-global-var-mut.rs new file mode 100644 index 00000000000..c63b09bb7a7 --- /dev/null +++ b/tests/ui/parser/suggest-static-for-global-var-mut.rs @@ -0,0 +1,5 @@ +let mut _data = vec![1,2,3]; +//~^ ERROR expected item, found keyword `let` + +fn main() { +} diff --git a/tests/ui/parser/suggest-static-for-global-var-mut.stderr b/tests/ui/parser/suggest-static-for-global-var-mut.stderr new file mode 100644 index 00000000000..4b00d1a24f3 --- /dev/null +++ b/tests/ui/parser/suggest-static-for-global-var-mut.stderr @@ -0,0 +1,11 @@ +error: expected item, found keyword `let` + --> $DIR/suggest-static-for-global-var-mut.rs:1:1 + | +LL | let mut _data = vec![1,2,3]; + | ^^^ `let` cannot be used for global variables + | + = help: consider using `static` and a `Mutex` instead of `let mut` + = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/unnecessary-let.fixed b/tests/ui/parser/unnecessary-let.fixed new file mode 100644 index 00000000000..bdee07e76aa --- /dev/null +++ b/tests/ui/parser/unnecessary-let.fixed @@ -0,0 +1,13 @@ +//@ run-rustfix + +fn main() { + for _x in [1, 2, 3] {} + //~^ ERROR expected pattern, found `let` + //~| ERROR missing `in` in `for` loop + + match 1 { + 1 => {} + //~^ ERROR expected pattern, found `let` + _ => {} + } +} diff --git a/tests/ui/parser/unnecessary-let.rs b/tests/ui/parser/unnecessary-let.rs index 6279109621d..a889d9f7789 100644 --- a/tests/ui/parser/unnecessary-let.rs +++ b/tests/ui/parser/unnecessary-let.rs @@ -1,5 +1,7 @@ +//@ run-rustfix + fn main() { - for let x of [1, 2, 3] {} + for let _x of [1, 2, 3] {} //~^ ERROR expected pattern, found `let` //~| ERROR missing `in` in `for` loop diff --git a/tests/ui/parser/unnecessary-let.stderr b/tests/ui/parser/unnecessary-let.stderr index 05ac1faafd4..0b28123747a 100644 --- a/tests/ui/parser/unnecessary-let.stderr +++ b/tests/ui/parser/unnecessary-let.stderr @@ -1,31 +1,31 @@ error: expected pattern, found `let` - --> $DIR/unnecessary-let.rs:2:9 + --> $DIR/unnecessary-let.rs:4:9 | -LL | for let x of [1, 2, 3] {} - | ^^^^ +LL | for let _x of [1, 2, 3] {} + | ^^^ | help: remove the unnecessary `let` keyword | -LL - for let x of [1, 2, 3] {} -LL + for x of [1, 2, 3] {} +LL - for let _x of [1, 2, 3] {} +LL + for _x of [1, 2, 3] {} | error: missing `in` in `for` loop - --> $DIR/unnecessary-let.rs:2:15 + --> $DIR/unnecessary-let.rs:4:16 | -LL | for let x of [1, 2, 3] {} - | ^^ +LL | for let _x of [1, 2, 3] {} + | ^^ | help: try using `in` here instead | -LL | for let x in [1, 2, 3] {} - | ~~ +LL | for let _x in [1, 2, 3] {} + | ~~ error: expected pattern, found `let` - --> $DIR/unnecessary-let.rs:7:9 + --> $DIR/unnecessary-let.rs:9:9 | LL | let 1 => {} - | ^^^^ + | ^^^ | help: remove the unnecessary `let` keyword | diff --git a/tests/ui/pattern/usefulness/conflicting_bindings.rs b/tests/ui/pattern/usefulness/conflicting_bindings.rs index 0b3e7ce9e9a..16737e0a894 100644 --- a/tests/ui/pattern/usefulness/conflicting_bindings.rs +++ b/tests/ui/pattern/usefulness/conflicting_bindings.rs @@ -10,6 +10,8 @@ fn main() { //~^ ERROR: mutable more than once if let Some(ref mut y @ ref mut z) = x && true {} //~^ ERROR: mutable more than once + if let Some(_) = Some(()) && let Some(ref mut y @ ref mut z) = x && true {} + //~^ ERROR: mutable more than once while let Some(ref mut y @ ref mut z) = x {} //~^ ERROR: mutable more than once while let Some(ref mut y @ ref mut z) = x && true {} diff --git a/tests/ui/pattern/usefulness/conflicting_bindings.stderr b/tests/ui/pattern/usefulness/conflicting_bindings.stderr index 679fc83e7f5..6f6504e6f64 100644 --- a/tests/ui/pattern/usefulness/conflicting_bindings.stderr +++ b/tests/ui/pattern/usefulness/conflicting_bindings.stderr @@ -31,7 +31,15 @@ LL | if let Some(ref mut y @ ref mut z) = x && true {} | value is mutably borrowed by `y` here error: cannot borrow value as mutable more than once at a time - --> $DIR/conflicting_bindings.rs:13:20 + --> $DIR/conflicting_bindings.rs:13:43 + | +LL | if let Some(_) = Some(()) && let Some(ref mut y @ ref mut z) = x && true {} + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:15:20 | LL | while let Some(ref mut y @ ref mut z) = x {} | ^^^^^^^^^ --------- value is mutably borrowed by `z` here @@ -39,7 +47,7 @@ LL | while let Some(ref mut y @ ref mut z) = x {} | value is mutably borrowed by `y` here error: cannot borrow value as mutable more than once at a time - --> $DIR/conflicting_bindings.rs:15:20 + --> $DIR/conflicting_bindings.rs:17:20 | LL | while let Some(ref mut y @ ref mut z) = x && true {} | ^^^^^^^^^ --------- value is mutably borrowed by `z` here @@ -47,7 +55,7 @@ LL | while let Some(ref mut y @ ref mut z) = x && true {} | value is mutably borrowed by `y` here error: cannot borrow value as mutable more than once at a time - --> $DIR/conflicting_bindings.rs:18:9 + --> $DIR/conflicting_bindings.rs:20:9 | LL | ref mut y @ ref mut z => {} | ^^^^^^^^^ --------- value is mutably borrowed by `z` here @@ -55,12 +63,12 @@ LL | ref mut y @ ref mut z => {} | value is mutably borrowed by `y` here error: cannot borrow value as mutable more than once at a time - --> $DIR/conflicting_bindings.rs:21:24 + --> $DIR/conflicting_bindings.rs:23:24 | LL | () if let Some(ref mut y @ ref mut z) = x => {} | ^^^^^^^^^ --------- value is mutably borrowed by `z` here | | | value is mutably borrowed by `y` here -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/pattern/usefulness/match-arm-statics-2.stderr b/tests/ui/pattern/usefulness/match-arm-statics-2.stderr index e4dd35a5995..60b4fcca286 100644 --- a/tests/ui/pattern/usefulness/match-arm-statics-2.stderr +++ b/tests/ui/pattern/usefulness/match-arm-statics-2.stderr @@ -3,8 +3,20 @@ error[E0004]: non-exhaustive patterns: `(true, false)` not covered | LL | match (true, false) { | ^^^^^^^^^^^^^ pattern `(true, false)` not covered +LL | +LL | TRUE_TRUE => (), + | --------- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `TRUE_TRUE` | = note: the matched value is of type `(bool, bool)` +note: constant `TRUE_TRUE` defined here + --> $DIR/match-arm-statics-2.rs:14:1 + | +LL | const TRUE_TRUE: (bool, bool) = (true, true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | TRUE_TRUE_var => (), + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ (false, true) => (), diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr index a8786d02414..0a3991fe3d1 100644 --- a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr +++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr @@ -199,8 +199,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered | LL | match s { | ^ patterns `&[]` and `&[_, _, ..]` not covered +LL | +LL | CONST => {} + | ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST` | = note: the matched value is of type `&[bool]` +note: constant `CONST` defined here + --> $DIR/slice-patterns-exhaustiveness.rs:88:5 + | +LL | const CONST: &[bool] = &[true]; + | ^^^^^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | CONST_var => {} + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ CONST => {}, @@ -212,8 +224,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered | LL | match s { | ^ patterns `&[]` and `&[_, _, ..]` not covered +LL | +LL | CONST => {} + | ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST` | = note: the matched value is of type `&[bool]` +note: constant `CONST` defined here + --> $DIR/slice-patterns-exhaustiveness.rs:88:5 + | +LL | const CONST: &[bool] = &[true]; + | ^^^^^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | CONST_var => {} + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ &[false] => {}, @@ -225,8 +249,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered | LL | match s { | ^ patterns `&[]` and `&[_, _, ..]` not covered +... +LL | CONST => {} + | ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST` | = note: the matched value is of type `&[bool]` +note: constant `CONST` defined here + --> $DIR/slice-patterns-exhaustiveness.rs:88:5 + | +LL | const CONST: &[bool] = &[true]; + | ^^^^^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | CONST_var => {} + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ CONST => {}, @@ -238,8 +274,20 @@ error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered | LL | match s { | ^ pattern `&[_, _, ..]` not covered +... +LL | CONST => {} + | ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST` | = note: the matched value is of type `&[bool]` +note: constant `CONST` defined here + --> $DIR/slice-patterns-exhaustiveness.rs:88:5 + | +LL | const CONST: &[bool] = &[true]; + | ^^^^^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | CONST_var => {} + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ CONST => {}, @@ -251,8 +299,20 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered | LL | match s { | ^ pattern `&[false]` not covered +... +LL | CONST => {} + | ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST` | = note: the matched value is of type `&[bool]` +note: constant `CONST` defined here + --> $DIR/slice-patterns-exhaustiveness.rs:88:5 + | +LL | const CONST: &[bool] = &[true]; + | ^^^^^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | CONST_var => {} + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ &[_, _, ..] => {}, @@ -264,8 +324,20 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered | LL | match s1 { | ^^ pattern `&[false]` not covered +LL | +LL | CONST1 => {} + | ------ this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST1` | = note: the matched value is of type `&[bool; 1]` +note: constant `CONST1` defined here + --> $DIR/slice-patterns-exhaustiveness.rs:124:5 + | +LL | const CONST1: &[bool; 1] = &[true]; + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | CONST1_var => {} + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ CONST1 => {}, diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs index 5c333cd7795..47653efffb7 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs @@ -94,4 +94,15 @@ fn use_in_arm_ok(c: bool) { }; } +fn use_in_same_chain(c: bool) { + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, 2) if let y = x && c && let z = x => false, //~ ERROR use of moved value: `x` + _ => true, + }; +} + fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr index 087e54244b3..123c5f19430 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr @@ -60,6 +60,22 @@ help: borrow this binding in the pattern to avoid moving the value LL | (1, 2) if let ref y = x && c => false, | +++ -error: aborting due to 4 previous errors +error[E0382]: use of moved value: `x` + --> $DIR/move-guard-if-let-chain.rs:103:41 + | +LL | let x: Box<_> = Box::new(1); + | - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait +... +LL | (1, 2) if let y = x && c && let z = x => false, + | - ^ value used here after move + | | + | value moved here + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | (1, 2) if let ref y = x && c && let z = x => false, + | +++ + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs new file mode 100644 index 00000000000..389c76337f0 --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs @@ -0,0 +1,25 @@ +// issue-103476 +//@ compile-flags: -Zlint-mir -Zunstable-options +//@ edition: 2024 +//@ check-pass + +#![feature(let_chains)] +#![allow(irrefutable_let_patterns)] + +struct Pd; + +impl Pd { + fn it(&self) -> It { + todo!() + } +} + +pub struct It<'a>(Box<dyn Tr<'a>>); + +trait Tr<'a> {} + +fn f(m: Option<Pd>) { + if let Some(n) = m && let it = n.it() {}; +} + +fn main() {} diff --git a/tests/ui/simd-abi-checks-s390x.rs b/tests/ui/simd-abi-checks-s390x.rs new file mode 100644 index 00000000000..15df66a2ced --- /dev/null +++ b/tests/ui/simd-abi-checks-s390x.rs @@ -0,0 +1,174 @@ +//@ revisions: z10 z13_no_vector z13_soft_float +//@ build-fail +//@[z10] compile-flags: --target s390x-unknown-linux-gnu +//@[z10] needs-llvm-components: systemz +//@[z13_no_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector +//@[z13_no_vector] needs-llvm-components: systemz +// FIXME: +soft-float itself doesn't set -vector +//@[z13_soft_float] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector,+soft-float +//@[z13_soft_float] needs-llvm-components: systemz + +#![feature(no_core, lang_items, repr_simd, s390x_target_feature)] +#![no_core] +#![crate_type = "lib"] +#![allow(non_camel_case_types, improper_ctypes_definitions)] +#![deny(abi_unsupported_vector_types)] + +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} +#[lang = "freeze"] +pub trait Freeze {} + +impl<T: Copy, const N: usize> Copy for [T; N] {} + +#[repr(simd)] +pub struct i8x8([i8; 8]); +#[repr(simd)] +pub struct i8x16([i8; 16]); +#[repr(simd)] +pub struct i8x32([i8; 32]); +#[repr(C)] +pub struct Wrapper<T>(T); +#[repr(transparent)] +pub struct TransparentWrapper<T>(T); + +impl Copy for i8 {} +impl Copy for i64 {} +impl Copy for i8x8 {} +impl Copy for i8x16 {} +impl Copy for i8x32 {} +impl<T: Copy> Copy for Wrapper<T> {} +impl<T: Copy> Copy for TransparentWrapper<T> {} + +#[no_mangle] +extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 { + //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + //~^^ WARN this was previously accepted + *x +} +#[no_mangle] +extern "C" fn vector_ret(x: &i8x16) -> i8x16 { + //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + //~^^ WARN this was previously accepted + *x +} +#[no_mangle] +extern "C" fn vector_ret_large(x: &i8x32) -> i8x32 { + // Ok + *x +} + +#[no_mangle] +#[target_feature(enable = "vector")] +unsafe extern "C" fn vector_ret_target_feature_small(x: &i8x8) -> i8x8 { + // Ok + *x +} +#[no_mangle] +#[target_feature(enable = "vector")] +unsafe extern "C" fn vector_target_feature_ret(x: &i8x16) -> i8x16 { + // Ok + *x +} +#[no_mangle] +#[target_feature(enable = "vector")] +unsafe extern "C" fn vector_ret_target_feature_large(x: &i8x32) -> i8x32 { + // Ok + *x +} + +#[no_mangle] +extern "C" fn vector_wrapper_ret_small(x: &Wrapper<i8x8>) -> Wrapper<i8x8> { + // Ok + *x +} +#[no_mangle] +extern "C" fn vector_wrapper_ret(x: &Wrapper<i8x16>) -> Wrapper<i8x16> { + // Ok + *x +} +#[no_mangle] +extern "C" fn vector_wrapper_ret_large(x: &Wrapper<i8x32>) -> Wrapper<i8x32> { + // Ok + *x +} + +#[no_mangle] +extern "C" fn vector_transparent_wrapper_ret_small( + x: &TransparentWrapper<i8x8>, +) -> TransparentWrapper<i8x8> { + //~^^^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + //~^^^^ WARN this was previously accepted + *x +} +#[no_mangle] +extern "C" fn vector_transparent_wrapper_ret( + x: &TransparentWrapper<i8x16>, +) -> TransparentWrapper<i8x16> { + //~^^^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + //~^^^^ WARN this was previously accepted + *x +} +#[no_mangle] +extern "C" fn vector_transparent_wrapper_ret_large( + x: &TransparentWrapper<i8x32>, +) -> TransparentWrapper<i8x32> { + // Ok + *x +} + +#[no_mangle] +extern "C" fn vector_arg_small(x: i8x8) -> i64 { + //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + //~^^ WARN this was previously accepted + unsafe { *(&x as *const i8x8 as *const i64) } +} +#[no_mangle] +extern "C" fn vector_arg(x: i8x16) -> i64 { + //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + //~^^ WARN this was previously accepted + unsafe { *(&x as *const i8x16 as *const i64) } +} +#[no_mangle] +extern "C" fn vector_arg_large(x: i8x32) -> i64 { + // Ok + unsafe { *(&x as *const i8x32 as *const i64) } +} + +#[no_mangle] +extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 { + //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + //~^^ WARN this was previously accepted + unsafe { *(&x as *const Wrapper<i8x8> as *const i64) } +} +#[no_mangle] +extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 { + //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + //~^^ WARN this was previously accepted + unsafe { *(&x as *const Wrapper<i8x16> as *const i64) } +} +#[no_mangle] +extern "C" fn vector_wrapper_arg_large(x: Wrapper<i8x32>) -> i64 { + // Ok + unsafe { *(&x as *const Wrapper<i8x32> as *const i64) } +} + +#[no_mangle] +extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 { + //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + //~^^ WARN this was previously accepted + unsafe { *(&x as *const TransparentWrapper<i8x8> as *const i64) } +} +#[no_mangle] +extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 { + //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + //~^^ WARN this was previously accepted + unsafe { *(&x as *const TransparentWrapper<i8x16> as *const i64) } +} +#[no_mangle] +extern "C" fn vector_transparent_wrapper_arg_large(x: TransparentWrapper<i8x32>) -> i64 { + // Ok + unsafe { *(&x as *const TransparentWrapper<i8x32> as *const i64) } +} diff --git a/tests/ui/simd-abi-checks-s390x.z10.stderr b/tests/ui/simd-abi-checks-s390x.z10.stderr new file mode 100644 index 00000000000..a91322ec058 --- /dev/null +++ b/tests/ui/simd-abi-checks-s390x.z10.stderr @@ -0,0 +1,111 @@ +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:46:1 + | +LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) +note: the lint level is defined here + --> $DIR/simd-abi-checks-s390x.rs:15:9 + | +LL | #![deny(abi_unsupported_vector_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:52:1 + | +LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:99:1 + | +LL | / extern "C" fn vector_transparent_wrapper_ret_small( +LL | | x: &TransparentWrapper<i8x8>, +LL | | ) -> TransparentWrapper<i8x8> { + | |_____________________________^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:107:1 + | +LL | / extern "C" fn vector_transparent_wrapper_ret( +LL | | x: &TransparentWrapper<i8x16>, +LL | | ) -> TransparentWrapper<i8x16> { + | |______________________________^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:123:1 + | +LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:129:1 + | +LL | extern "C" fn vector_arg(x: i8x16) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:141:1 + | +LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:147:1 + | +LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:159:1 + | +LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:165:1 + | +LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: aborting due to 10 previous errors + diff --git a/tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr b/tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr new file mode 100644 index 00000000000..a91322ec058 --- /dev/null +++ b/tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr @@ -0,0 +1,111 @@ +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:46:1 + | +LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) +note: the lint level is defined here + --> $DIR/simd-abi-checks-s390x.rs:15:9 + | +LL | #![deny(abi_unsupported_vector_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:52:1 + | +LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:99:1 + | +LL | / extern "C" fn vector_transparent_wrapper_ret_small( +LL | | x: &TransparentWrapper<i8x8>, +LL | | ) -> TransparentWrapper<i8x8> { + | |_____________________________^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:107:1 + | +LL | / extern "C" fn vector_transparent_wrapper_ret( +LL | | x: &TransparentWrapper<i8x16>, +LL | | ) -> TransparentWrapper<i8x16> { + | |______________________________^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:123:1 + | +LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:129:1 + | +LL | extern "C" fn vector_arg(x: i8x16) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:141:1 + | +LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:147:1 + | +LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:159:1 + | +LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:165:1 + | +LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: aborting due to 10 previous errors + diff --git a/tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr b/tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr new file mode 100644 index 00000000000..a91322ec058 --- /dev/null +++ b/tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr @@ -0,0 +1,111 @@ +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:46:1 + | +LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) +note: the lint level is defined here + --> $DIR/simd-abi-checks-s390x.rs:15:9 + | +LL | #![deny(abi_unsupported_vector_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:52:1 + | +LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:99:1 + | +LL | / extern "C" fn vector_transparent_wrapper_ret_small( +LL | | x: &TransparentWrapper<i8x8>, +LL | | ) -> TransparentWrapper<i8x8> { + | |_____________________________^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:107:1 + | +LL | / extern "C" fn vector_transparent_wrapper_ret( +LL | | x: &TransparentWrapper<i8x16>, +LL | | ) -> TransparentWrapper<i8x16> { + | |______________________________^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:123:1 + | +LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:129:1 + | +LL | extern "C" fn vector_arg(x: i8x16) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:141:1 + | +LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:147:1 + | +LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:159:1 + | +LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled + --> $DIR/simd-abi-checks-s390x.rs:165:1 + | +LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558> + = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) + +error: aborting due to 10 previous errors + 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/structs-enums/enum-rec/issue-17431-6.rs b/tests/ui/structs-enums/enum-rec/issue-17431-6.rs index 0183bdba111..a3b510848dc 100644 --- a/tests/ui/structs-enums/enum-rec/issue-17431-6.rs +++ b/tests/ui/structs-enums/enum-rec/issue-17431-6.rs @@ -1,8 +1,6 @@ -//@ ignore-apple: cycle error does not appear on apple +use std::cell::UnsafeCell; -use std::sync::Mutex; - -enum Foo { X(Mutex<Option<Foo>>) } +enum Foo { X(UnsafeCell<Option<Foo>>) } //~^ ERROR recursive type `Foo` has infinite size //~| ERROR cycle detected diff --git a/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr b/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr index 22f8519d0ef..b192593d266 100644 --- a/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr +++ b/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr @@ -1,18 +1,18 @@ error[E0072]: recursive type `Foo` has infinite size - --> $DIR/issue-17431-6.rs:5:1 + --> $DIR/issue-17431-6.rs:3:1 | -LL | enum Foo { X(Mutex<Option<Foo>>) } - | ^^^^^^^^ --- recursive without indirection +LL | enum Foo { X(UnsafeCell<Option<Foo>>) } + | ^^^^^^^^ --- recursive without indirection | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | -LL | enum Foo { X(Mutex<Option<Box<Foo>>>) } - | ++++ + +LL | enum Foo { X(UnsafeCell<Option<Box<Foo>>>) } + | ++++ + error[E0391]: cycle detected when computing when `Foo` needs drop - --> $DIR/issue-17431-6.rs:5:1 + --> $DIR/issue-17431-6.rs:3:1 | -LL | enum Foo { X(Mutex<Option<Foo>>) } +LL | enum Foo { X(UnsafeCell<Option<Foo>>) } | ^^^^^^^^ | = note: ...which immediately requires computing when `Foo` needs drop again diff --git a/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index 05e087fd9f9..a040e71cf3b 100644 --- a/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -31,6 +31,10 @@ note: required by a bound in `bar` | LL | fn bar(f: impl Future<Output=()>) {} | ^^^^^^^^^^^^^^^^^ required by this bound in `bar` +help: use parentheses to call this closure + | +LL | bar(async_closure()); + | ++ error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs index af47ba8baa3..1a440a90cd7 100644 --- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs +++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs @@ -2,9 +2,9 @@ fn main() { let A = 3; //~^ ERROR refutable pattern in local binding //~| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered - //~| missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable //~| HELP introduce a variable instead //~| SUGGESTION A_var const A: i32 = 2; + //~^ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable } diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr index b6c28612802..a275d8e4e83 100644 --- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr +++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr @@ -2,15 +2,18 @@ error[E0005]: refutable pattern in local binding --> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9 | LL | let A = 3; - | ^ - | | - | patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered - | missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable - | help: introduce a variable instead: `A_var` + | ^ patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered +... +LL | const A: i32 = 2; + | ------------ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` +help: introduce a variable instead + | +LL | let A_var = 3; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/symbol-names/basic.rs b/tests/ui/symbol-names/basic.rs index dfcac21ccd6..839dda2b3a3 100644 --- a/tests/ui/symbol-names/basic.rs +++ b/tests/ui/symbol-names/basic.rs @@ -1,7 +1,7 @@ //@ build-fail //@ revisions: legacy v0 //@[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy - //@[v0]compile-flags: -C symbol-mangling-version=v0 +//@[v0]compile-flags: -C symbol-mangling-version=v0 #![feature(rustc_attrs)] diff --git a/tests/ui/symbol-names/impl1.rs b/tests/ui/symbol-names/impl1.rs index fa4be88f68f..9aefca47447 100644 --- a/tests/ui/symbol-names/impl1.rs +++ b/tests/ui/symbol-names/impl1.rs @@ -1,7 +1,7 @@ //@ build-fail //@ revisions: legacy v0 //@[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy - //@[v0]compile-flags: -C symbol-mangling-version=v0 +//@[v0]compile-flags: -C symbol-mangling-version=v0 //@[legacy]normalize-stderr-test: "h[\w]{16}E?\)" -> "<SYMBOL_HASH>)" #![feature(auto_traits, rustc_attrs)] diff --git a/tests/ui/symbol-names/issue-60925.rs b/tests/ui/symbol-names/issue-60925.rs index 9f1f007a0fa..ca0f21b7a78 100644 --- a/tests/ui/symbol-names/issue-60925.rs +++ b/tests/ui/symbol-names/issue-60925.rs @@ -1,7 +1,7 @@ //@ build-fail //@ revisions: legacy v0 //@[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy - //@[v0]compile-flags: -C symbol-mangling-version=v0 +//@[v0]compile-flags: -C symbol-mangling-version=v0 #![feature(rustc_attrs)] diff --git a/tests/ui/thir-print/thir-flat-const-variant.stdout b/tests/ui/thir-print/thir-flat-const-variant.stdout index 1840be7885b..5588cfdfa5c 100644 --- a/tests/ui/thir-print/thir-flat-const-variant.stdout +++ b/tests/ui/thir-print/thir-flat-const-variant.stdout @@ -11,9 +11,12 @@ Thir { fields: [], }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:12:32: 12:34 (#0), }, Expr { @@ -25,9 +28,12 @@ Thir { value: e0, }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:12:32: 12:34 (#0), }, Expr { @@ -47,9 +53,12 @@ Thir { }, ), ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:12:23: 12:35 (#0), }, Expr { @@ -61,9 +70,12 @@ Thir { value: e2, }, ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:12:23: 12:35 (#0), }, ], @@ -84,9 +96,12 @@ Thir { fields: [], }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:13:33: 13:35 (#0), }, Expr { @@ -98,9 +113,12 @@ Thir { value: e0, }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:13:33: 13:35 (#0), }, Expr { @@ -120,9 +138,12 @@ Thir { }, ), ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:13:23: 13:36 (#0), }, Expr { @@ -134,9 +155,12 @@ Thir { value: e2, }, ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:13:23: 13:36 (#0), }, ], @@ -157,9 +181,12 @@ Thir { fields: [], }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:14:33: 14:35 (#0), }, Expr { @@ -171,9 +198,12 @@ Thir { value: e0, }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:14:33: 14:35 (#0), }, Expr { @@ -193,9 +223,12 @@ Thir { }, ), ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:14:24: 14:36 (#0), }, Expr { @@ -207,9 +240,12 @@ Thir { value: e2, }, ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:14:24: 14:36 (#0), }, ], @@ -230,9 +266,12 @@ Thir { fields: [], }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:15:34: 15:36 (#0), }, Expr { @@ -244,9 +283,12 @@ Thir { value: e0, }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:15:34: 15:36 (#0), }, Expr { @@ -266,9 +308,12 @@ Thir { }, ), ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:15:24: 15:37 (#0), }, Expr { @@ -280,9 +325,12 @@ Thir { value: e2, }, ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:15:24: 15:37 (#0), }, ], @@ -312,9 +360,12 @@ Thir { block: b0, }, ty: (), - temp_lifetime: Some( - Node(2), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(2), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:18:11: 18:13 (#0), }, Expr { @@ -326,9 +377,12 @@ Thir { value: e0, }, ty: (), - temp_lifetime: Some( - Node(2), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(2), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:18:11: 18:13 (#0), }, ], diff --git a/tests/ui/thir-print/thir-flat.stdout b/tests/ui/thir-print/thir-flat.stdout index a31d08adab6..59cecfe511c 100644 --- a/tests/ui/thir-print/thir-flat.stdout +++ b/tests/ui/thir-print/thir-flat.stdout @@ -20,9 +20,12 @@ Thir { block: b0, }, ty: (), - temp_lifetime: Some( - Node(2), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(2), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat.rs:4:15: 4:17 (#0), }, Expr { @@ -34,9 +37,12 @@ Thir { value: e0, }, ty: (), - temp_lifetime: Some( - Node(2), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(2), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat.rs:4:15: 4:17 (#0), }, ], diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 8cff7887661..a9d6985928a 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -26,7 +26,7 @@ params: [ body: Expr { ty: bool - temp_lifetime: Some(Node(26)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) kind: Scope { @@ -35,7 +35,7 @@ body: value: Expr { ty: bool - temp_lifetime: Some(Node(26)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) kind: Block { @@ -47,7 +47,7 @@ body: expr: Expr { ty: bool - temp_lifetime: Some(Node(26)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0) kind: Scope { @@ -56,14 +56,14 @@ body: value: Expr { ty: bool - temp_lifetime: Some(Node(26)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0) kind: Match { scrutinee: Expr { ty: Foo - temp_lifetime: Some(Node(26)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0) kind: Scope { @@ -72,7 +72,7 @@ body: value: Expr { ty: Foo - temp_lifetime: Some(Node(26)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0) kind: VarRef { @@ -123,7 +123,7 @@ body: body: Expr { ty: bool - temp_lifetime: Some(Node(13)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(13)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) kind: Scope { @@ -132,7 +132,7 @@ body: value: Expr { ty: bool - temp_lifetime: Some(Node(13)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(13)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) kind: Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false) @@ -175,7 +175,7 @@ body: body: Expr { ty: bool - temp_lifetime: Some(Node(19)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(19)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) kind: Scope { @@ -184,7 +184,7 @@ body: value: Expr { ty: bool - temp_lifetime: Some(Node(19)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(19)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) kind: Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false) @@ -219,7 +219,7 @@ body: body: Expr { ty: bool - temp_lifetime: Some(Node(24)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) kind: Scope { @@ -228,7 +228,7 @@ body: value: Expr { ty: bool - temp_lifetime: Some(Node(24)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) kind: Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false) @@ -257,7 +257,7 @@ params: [ body: Expr { ty: () - temp_lifetime: Some(Node(2)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) kind: Scope { @@ -266,7 +266,7 @@ body: value: Expr { ty: () - temp_lifetime: Some(Node(2)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) kind: Block { diff --git a/tests/ui/thir-print/thir-tree.stdout b/tests/ui/thir-print/thir-tree.stdout index ef6db368dbe..b39581ad841 100644 --- a/tests/ui/thir-print/thir-tree.stdout +++ b/tests/ui/thir-print/thir-tree.stdout @@ -4,7 +4,7 @@ params: [ body: Expr { ty: () - temp_lifetime: Some(Node(2)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None } span: $DIR/thir-tree.rs:4:15: 4:17 (#0) kind: Scope { @@ -13,7 +13,7 @@ body: value: Expr { ty: () - temp_lifetime: Some(Node(2)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None } span: $DIR/thir-tree.rs:4:15: 4:17 (#0) kind: Block { diff --git a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs index 2cb63f25d06..fd0e9691700 100644 --- a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs +++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs @@ -1,7 +1,7 @@ trait Trait {} fn test<T: ?self::<i32>::Trait>() {} -//~^ ERROR type arguments are not allowed on this type +//~^ ERROR type arguments are not allowed on module `maybe_bound_has_path_args` //~| WARN relaxing a default bound only does something for `?Sized` fn main() {} diff --git a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr index 701e493f5a5..0c167fff940 100644 --- a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr +++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr @@ -4,13 +4,13 @@ warning: relaxing a default bound only does something for `?Sized`; all other tr LL | fn test<T: ?self::<i32>::Trait>() {} | ^^^^^^^^^^^^^^^^^^^ -error[E0109]: type arguments are not allowed on this type +error[E0109]: type arguments are not allowed on module `maybe_bound_has_path_args` --> $DIR/maybe-bound-has-path-args.rs:3:20 | LL | fn test<T: ?self::<i32>::Trait>() {} | ---- ^^^ type argument not allowed | | - | not allowed on this type + | not allowed on module `maybe_bound_has_path_args` error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr index 25c81ff900f..0970cd5225f 100644 --- a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr +++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr @@ -12,5 +12,13 @@ LL | const fn test() -> impl ~const Fn() { | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 2 previous errors +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-closure-parse-not-item.rs:7:25 + | +LL | const fn test() -> impl ~const Fn() { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors diff --git a/tests/ui/traits/const-traits/const-fns-are-early-bound.rs b/tests/ui/traits/const-traits/const-fns-are-early-bound.rs deleted file mode 100644 index c26eaf67454..00000000000 --- a/tests/ui/traits/const-traits/const-fns-are-early-bound.rs +++ /dev/null @@ -1,90 +0,0 @@ -//@ known-bug: #110395 -//@ failure-status: 101 -//@ dont-check-compiler-stderr -// FIXME(const_trait_impl) check-pass -//@ compile-flags: -Znext-solver - -#![crate_type = "lib"] -#![allow(internal_features, incomplete_features)] -#![no_std] -#![no_core] -#![feature( - auto_traits, - const_trait_impl, - effects, - lang_items, - no_core, - staged_api, - unboxed_closures, - rustc_attrs, - marker_trait_attr, -)] -#![stable(feature = "minicore", since = "1.0.0")] - -fn test() { - fn is_const_fn<F>(_: F) - where - F: const FnOnce<()>, - { - } - - const fn foo() {} - - is_const_fn(foo); -} - -/// ---------------------------------------------------------------------- /// -/// Const fn trait definitions - -#[const_trait] -#[lang = "fn"] -#[rustc_paren_sugar] -trait Fn<Args: Tuple>: ~const FnMut<Args> { - extern "rust-call" fn call(&self, args: Args) -> Self::Output; -} - -#[const_trait] -#[lang = "fn_mut"] -#[rustc_paren_sugar] -trait FnMut<Args: Tuple>: ~const FnOnce<Args> { - extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; -} - -#[const_trait] -#[lang = "fn_once"] -#[rustc_paren_sugar] -trait FnOnce<Args: Tuple> { - #[lang = "fn_once_output"] - type Output; - - extern "rust-call" fn call_once(self, args: Args) -> Self::Output; -} - -/// ---------------------------------------------------------------------- /// -/// All this other stuff needed for core. Unrelated to test. - -#[lang = "destruct"] -#[const_trait] -trait Destruct {} - -#[lang = "freeze"] -unsafe auto trait Freeze {} - -#[lang = "drop"] -#[const_trait] -trait Drop { - fn drop(&mut self); -} - -#[lang = "sized"] -trait Sized {} -#[lang = "copy"] -trait Copy {} - -#[lang = "tuple_trait"] -trait Tuple {} - -#[lang = "legacy_receiver"] -trait LegacyReceiver {} - -impl<T: ?Sized> LegacyReceiver for &T {} diff --git a/tests/ui/traits/const-traits/const-opaque.no.stderr b/tests/ui/traits/const-traits/const-opaque.no.stderr new file mode 100644 index 00000000000..e43a6b603fd --- /dev/null +++ b/tests/ui/traits/const-traits/const-opaque.no.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `(): const Foo` is not satisfied + --> $DIR/const-opaque.rs:31:18 + | +LL | let opaque = bar(()); + | ^^^^^^^ + +error[E0277]: the trait bound `(): const Foo` is not satisfied + --> $DIR/const-opaque.rs:33:5 + | +LL | opaque.method(); + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-opaque.rs b/tests/ui/traits/const-traits/const-opaque.rs new file mode 100644 index 00000000000..96cdd7d9f26 --- /dev/null +++ b/tests/ui/traits/const-traits/const-opaque.rs @@ -0,0 +1,38 @@ +//@ revisions: yes no +//@ compile-flags: -Znext-solver +//@[yes] check-pass + +#![feature(const_trait_impl)] + +#[const_trait] +trait Foo { + fn method(&self); +} + +impl<T: ~const Foo> const Foo for (T,) { + fn method(&self) {} +} + +#[cfg(yes)] +impl const Foo for () { + fn method(&self) {} +} + +#[cfg(no)] +impl Foo for () { + fn method(&self) {} +} + +const fn bar<T: ~const Foo>(t: T) -> impl ~const Foo { + (t,) +} + +const _: () = { + let opaque = bar(()); + //[no]~^ ERROR the trait bound `(): const Foo` is not satisfied + opaque.method(); + //[no]~^ ERROR the trait bound `(): const Foo` is not satisfied + std::mem::forget(opaque); +}; + +fn main() {} diff --git a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs index c467088ab3d..8ff15dd09cc 100644 --- a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs +++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs @@ -3,6 +3,7 @@ const fn test() -> impl ~const Fn() { //~^ ERROR `~const` can only be applied to `#[const_trait]` traits //~| ERROR `~const` can only be applied to `#[const_trait]` traits + //~| ERROR `~const` can only be applied to `#[const_trait]` traits const move || { //~ ERROR const closures are experimental let sl: &[u8] = b"foo"; diff --git a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr index 6d7edaf19f2..879d966b1f9 100644 --- a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr +++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr @@ -1,5 +1,5 @@ error[E0658]: const closures are experimental - --> $DIR/ice-112822-expected-type-for-param.rs:6:5 + --> $DIR/ice-112822-expected-type-for-param.rs:7:5 | LL | const move || { | ^^^^^ @@ -22,8 +22,16 @@ LL | const fn test() -> impl ~const Fn() { | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/ice-112822-expected-type-for-param.rs:3:25 + | +LL | const fn test() -> impl ~const Fn() { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0015]: cannot call non-const operator in constant functions - --> $DIR/ice-112822-expected-type-for-param.rs:11:17 + --> $DIR/ice-112822-expected-type-for-param.rs:12:17 | LL | assert_eq!(first, &b'f'); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +40,7 @@ LL | assert_eq!(first, &b'f'); = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const fn `core::panicking::assert_failed::<&u8, &u8>` in constant functions - --> $DIR/ice-112822-expected-type-for-param.rs:11:17 + --> $DIR/ice-112822-expected-type-for-param.rs:12:17 | LL | assert_eq!(first, &b'f'); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +48,7 @@ LL | assert_eq!(first, &b'f'); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0015, E0658. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs b/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs new file mode 100644 index 00000000000..ee47f92a0bc --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs @@ -0,0 +1,22 @@ +//@ aux-build:minicore.rs +//@ compile-flags: --crate-type=lib -Znext-solver -Cpanic=abort +//@ check-pass + +#![feature(no_core, const_trait_impl)] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +fn is_const_fn<F>(_: F) +where + F: const FnOnce(), +{ +} + +const fn foo() {} + +fn test() { + is_const_fn(foo); +} diff --git a/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs b/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs new file mode 100644 index 00000000000..ae1cbc6ca58 --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs @@ -0,0 +1,21 @@ +//@ aux-build:minicore.rs +//@ compile-flags: --crate-type=lib -Znext-solver + +#![feature(no_core, const_trait_impl)] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +const fn call_indirect<T: ~const Fn()>(t: &T) { t() } + +#[const_trait] +trait Foo {} +impl Foo for () {} +const fn foo<T: ~const Foo>() {} + +const fn test() { + call_indirect(&foo::<()>); + //~^ ERROR the trait bound `(): ~const Foo` is not satisfied +} diff --git a/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr b/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr new file mode 100644 index 00000000000..cf158643b34 --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `(): ~const Foo` is not satisfied + --> $DIR/minicore-fn-fail.rs:19:5 + | +LL | call_indirect(&foo::<()>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/effects/minicore-works.rs b/tests/ui/traits/const-traits/effects/minicore-works.rs index bfbfa8b2d05..c79b4fc07df 100644 --- a/tests/ui/traits/const-traits/effects/minicore-works.rs +++ b/tests/ui/traits/const-traits/effects/minicore-works.rs @@ -20,3 +20,9 @@ const fn test_op() { let _x = Add::add(1, 2); let _y = Custom + Custom; } + +const fn call_indirect<T: ~const Fn()>(t: &T) { t() } + +const fn call() { + call_indirect(&call); +} 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/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs index dda42580e0f..2a301788525 100644 --- a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs +++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs @@ -7,6 +7,7 @@ fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> { //~^ ERROR associated type `Assoc` not found for `Trait` //~| ERROR associated type `Assoc` not found for `Trait` //~| the trait bound `{integer}: Trait<()>` is not satisfied + //~| ERROR cannot capture late-bound type parameter in nested `impl Trait` 16 } diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr index 6e5bd34ce38..38dcdbd0af2 100644 --- a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr +++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr @@ -1,3 +1,9 @@ +error: cannot capture late-bound type parameter in nested `impl Trait` + --> $DIR/non-lifetime-binder-in-constraint.rs:6:58 + | +LL | fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> { + | - parameter defined here ^ + error[E0220]: associated type `Assoc` not found for `Trait` --> $DIR/non-lifetime-binder-in-constraint.rs:6:39 | @@ -27,7 +33,7 @@ help: this trait has no implementations, consider adding one LL | trait Trait<T: ?Sized> {} | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0220, E0277. For more information about an error, try `rustc --explain E0220`. diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs b/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs index 23951c34270..23f3666618b 100644 --- a/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs +++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs @@ -5,6 +5,7 @@ trait Trait<T> {} fn f() -> impl for<T> Trait<impl Trait<T>> {} //~^ ERROR nested `impl Trait` is not allowed -//~| ERROR the trait bound `(): Trait<impl Trait<T>>` is not satisfied +//~| ERROR the trait bound `(): Trait<impl Trait<{type error}>>` is not satisfied +//~| ERROR cannot capture late-bound type parameter in nested `impl Trait` fn main() {} diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr b/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr index 5859d952b75..3c352c9889c 100644 --- a/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr +++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr @@ -7,11 +7,19 @@ LL | fn f() -> impl for<T> Trait<impl Trait<T>> {} | | nested `impl Trait` here | outer `impl Trait` -error[E0277]: the trait bound `(): Trait<impl Trait<T>>` is not satisfied +error: cannot capture late-bound type parameter in nested `impl Trait` + --> $DIR/non-lifetime-binder.rs:6:40 + | +LL | fn f() -> impl for<T> Trait<impl Trait<T>> {} + | - ^ + | | + | parameter defined here + +error[E0277]: the trait bound `(): Trait<impl Trait<{type error}>>` is not satisfied --> $DIR/non-lifetime-binder.rs:6:11 | LL | fn f() -> impl for<T> Trait<impl Trait<T>> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<impl Trait<T>>` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<impl Trait<{type error}>>` is not implemented for `()` | help: this trait has no implementations, consider adding one --> $DIR/non-lifetime-binder.rs:4:1 @@ -19,7 +27,7 @@ help: this trait has no implementations, consider adding one LL | trait Trait<T> {} | ^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0666. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/unsafe/unsafe-block-without-braces.stderr b/tests/ui/unsafe/unsafe-block-without-braces.stderr index d29e49d73a6..3d8234c15e7 100644 --- a/tests/ui/unsafe/unsafe-block-without-braces.stderr +++ b/tests/ui/unsafe/unsafe-block-without-braces.stderr @@ -6,7 +6,7 @@ LL | unsafe //{ LL | std::mem::transmute::<f32, u32>(1.0); | ^^^ expected `{` | -help: try placing this code inside a block +help: you might have meant to write this as part of a block | LL | { std::mem::transmute::<f32, u32>(1.0); } | + + diff --git a/triagebot.toml b/triagebot.toml index d5bc549ca9f..2483bfc4a41 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -236,7 +236,21 @@ trigger_files = [ "compiler", # Tests + "tests/assembly", + "tests/auxiliary", + "tests/codegen", + "tests/codegen-units", + "tests/COMPILER_TESTS.md", + "tests/coverage", + "tests/coverage-run-rustdoc", + "tests/crashes", + "tests/debuginfo", + "tests/incremental", + "tests/mir-opt", + "tests/pretty", + "tests/run-make", "tests/ui", + "tests/ui-fulldeps", ] exclude_labels = [ "T-*", @@ -353,21 +367,22 @@ trigger_files = [ [autolabel."T-bootstrap"] trigger_files = [ - "x.py", - "x", - "x.ps1", + "Cargo.toml", + "configure", + "config.example.toml", "src/bootstrap", + "src/build_helper", "src/tools/rust-installer", "src/tools/x", - "configure", - "Cargo.toml", - "config.example.toml", "src/stage0", "src/tools/compiletest", "src/tools/tidy", "src/tools/rustdoc-gui-test", "src/tools/libcxx-version", "src/tools/rustc-perf-wrapper", + "x.py", + "x", + "x.ps1" ] [autolabel."T-infra"] @@ -886,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"] @@ -997,7 +1012,6 @@ compiler = [ "@oli-obk", "@petrochenkov", "@pnkfelix", - "@TaKO8Ki", "@wesleywiser", ] libs = [ @@ -1048,7 +1062,6 @@ diagnostics = [ "@davidtwco", "@estebank", "@oli-obk", - "@TaKO8Ki", "@chenyukang", ] parser = [ |
