diff --git a/Cargo.lock b/Cargo.lock index 4d54b5aeb4e..f0e035c025e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4029,6 +4029,7 @@ dependencies = [ "rustc_hir", "rustc_hir_pretty", "rustc_index", + "rustc_lint_defs", "rustc_macros", "rustc_query_system", "rustc_serialize", @@ -4495,6 +4496,7 @@ name = "rustc_transmute" version = "0.0.0" dependencies = [ "itertools", + "rustc_abi", "rustc_ast_ir", "rustc_data_structures", "rustc_hir", @@ -4502,7 +4504,6 @@ dependencies = [ "rustc_macros", "rustc_middle", "rustc_span", - "rustc_target", "tracing", ] diff --git a/RELEASES.md b/RELEASES.md index ac72a1d885c..40ddba6dbc5 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -68,15 +68,15 @@ Stabilized APIs - [`impl Default for std::collections::vec_deque::Iter`](https://doc.rust-lang.org/nightly/std/collections/vec_deque/struct.Iter.html#impl-Default-for-Iter%3C'_,+T%3E) - [`impl Default for std::collections::vec_deque::IterMut`](https://doc.rust-lang.org/nightly/std/collections/vec_deque/struct.IterMut.html#impl-Default-for-IterMut%3C'_,+T%3E) - [`Rc::new_uninit`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new_uninit) -- [`Rc::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init) +- [`Rc>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init) - [`Rc<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new_uninit_slice) - [`Rc<[MaybeUninit]>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init-1) - [`Arc::new_uninit`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.new_uninit) -- [`Arc::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init) +- [`Arc>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init) - [`Arc<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.new_uninit_slice) - [`Arc<[MaybeUninit]>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init-1) - [`Box::new_uninit`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.new_uninit) -- [`Box::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init) +- [`Box>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init) - [`Box<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.new_uninit_slice) - [`Box<[MaybeUninit]>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init-1) - [`core::arch::x86_64::_bextri_u64`](https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bextri_u64.html) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 0340d1bd6bc..141a15b99a3 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -7,7 +7,7 @@ use tracing::debug; use crate::{ Abi, AbiAndPrefAlign, Align, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer, - LayoutS, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, + LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange, }; @@ -26,7 +26,7 @@ fn absent<'a, FieldIdx, VariantIdx, F>(fields: &IndexSlice) -> bool where FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug, + F: Deref> + fmt::Debug, { let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited()); // We cannot ignore alignment; that might lead us to entirely discard a variant and @@ -89,7 +89,7 @@ impl LayoutCalculatorError { } type LayoutCalculatorResult = - Result, LayoutCalculatorError>; + Result, LayoutCalculatorError>; #[derive(Clone, Copy, Debug)] pub struct LayoutCalculator { @@ -105,7 +105,7 @@ impl LayoutCalculator { &self, a: Scalar, b: Scalar, - ) -> LayoutS { + ) -> LayoutData { let dl = self.cx.data_layout(); let b_align = b.align(dl); let align = a.align(dl).max(b_align).max(dl.aggregate_align); @@ -119,7 +119,7 @@ impl LayoutCalculator { .chain(Niche::from_scalar(dl, Size::ZERO, a)) .max_by_key(|niche| niche.available(dl)); - LayoutS { + LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { offsets: [Size::ZERO, b_offset].into(), @@ -138,7 +138,7 @@ impl LayoutCalculator { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug + Copy, + F: Deref> + fmt::Debug + Copy, >( &self, fields: &IndexSlice, @@ -211,9 +211,9 @@ impl LayoutCalculator { pub fn layout_of_never_type( &self, - ) -> LayoutS { + ) -> LayoutData { let dl = self.cx.data_layout(); - LayoutS { + LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, abi: Abi::Uninhabited, @@ -229,7 +229,7 @@ impl LayoutCalculator { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug + Copy, + F: Deref> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, @@ -292,7 +292,7 @@ impl LayoutCalculator { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug + Copy, + F: Deref> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, @@ -384,7 +384,7 @@ impl LayoutCalculator { return Err(LayoutCalculatorError::EmptyUnion); }; - Ok(LayoutS { + Ok(LayoutData { variants: Variants::Single { index: only_variant_idx }, fields: FieldsShape::Union(union_field_count), abi, @@ -401,7 +401,7 @@ impl LayoutCalculator { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug + Copy, + F: Deref> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, @@ -501,7 +501,7 @@ impl LayoutCalculator { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug + Copy, + F: Deref> + fmt::Debug + Copy, >( &self, repr: &ReprOptions, @@ -516,8 +516,8 @@ impl LayoutCalculator { // overall LayoutS. Store the overall LayoutS // and the variant LayoutSs here until then. struct TmpLayout { - layout: LayoutS, - variants: IndexVec>, + layout: LayoutData, + variants: IndexVec>, } let dl = self.cx.data_layout(); @@ -649,7 +649,7 @@ impl LayoutCalculator { Abi::Aggregate { sized: true } }; - let layout = LayoutS { + let layout = LayoutData { variants: Variants::Multiple { tag: niche_scalar, tag_encoding: TagEncoding::Niche { @@ -958,7 +958,7 @@ impl LayoutCalculator { let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag); - let tagged_layout = LayoutS { + let tagged_layout = LayoutData { variants: Variants::Multiple { tag, tag_encoding: TagEncoding::Direct, @@ -1013,7 +1013,7 @@ impl LayoutCalculator { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug + Copy, + F: Deref> + fmt::Debug + Copy, >( &self, fields: &IndexSlice, @@ -1341,7 +1341,7 @@ impl LayoutCalculator { unadjusted_abi_align }; - Ok(LayoutS { + Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { offsets, memory_index }, abi, @@ -1357,10 +1357,10 @@ impl LayoutCalculator { 'a, FieldIdx: Idx, VariantIdx: Idx, - F: Deref> + fmt::Debug, + F: Deref> + fmt::Debug, >( &self, - layout: &LayoutS, + layout: &LayoutData, fields: &IndexSlice, ) -> String { let dl = self.cx.data_layout(); diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index c6812c4d4c0..e029e1426b2 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -58,7 +58,7 @@ rustc_index::newtype_index! { } #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)] #[rustc_pass_by_value] -pub struct Layout<'a>(pub Interned<'a, LayoutS>); +pub struct Layout<'a>(pub Interned<'a, LayoutData>); impl<'a> fmt::Debug for Layout<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -68,8 +68,8 @@ impl<'a> fmt::Debug for Layout<'a> { } impl<'a> Deref for Layout<'a> { - type Target = &'a LayoutS; - fn deref(&self) -> &&'a LayoutS { + type Target = &'a LayoutData; + fn deref(&self) -> &&'a LayoutData { &self.0.0 } } @@ -142,8 +142,8 @@ impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> { } impl<'a, Ty> Deref for TyAndLayout<'a, Ty> { - type Target = &'a LayoutS; - fn deref(&self) -> &&'a LayoutS { + type Target = &'a LayoutData; + fn deref(&self) -> &&'a LayoutData { &self.layout.0.0 } } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 8e90130da4c..b54efa4bb48 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1485,7 +1485,7 @@ pub enum Variants { tag: Scalar, tag_encoding: TagEncoding, tag_field: usize, - variants: IndexVec>, + variants: IndexVec>, }, } @@ -1603,7 +1603,7 @@ impl Niche { // NOTE: This struct is generic over the FieldIdx and VariantIdx for rust-analyzer usage. #[derive(PartialEq, Eq, Hash, Clone)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] -pub struct LayoutS { +pub struct LayoutData { /// Says where the fields are located within the layout. pub fields: FieldsShape, @@ -1643,7 +1643,7 @@ pub struct LayoutS { pub unadjusted_abi_align: Align, } -impl LayoutS { +impl LayoutData { /// Returns `true` if this is an aggregate type (including a ScalarPair!) pub fn is_aggregate(&self) -> bool { match self.abi { @@ -1656,7 +1656,7 @@ impl LayoutS { let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); let size = scalar.size(cx); let align = scalar.align(cx); - LayoutS { + LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, abi: Abi::Scalar(scalar), @@ -1669,7 +1669,7 @@ impl LayoutS { } } -impl fmt::Debug for LayoutS +impl fmt::Debug for LayoutData where FieldsShape: fmt::Debug, Variants: fmt::Debug, @@ -1678,7 +1678,7 @@ where // This is how `Layout` used to print before it become // `Interned`. We print it like this to avoid having to update // expected output in a lot of tests. - let LayoutS { + let LayoutData { size, align, abi, @@ -1723,7 +1723,7 @@ pub struct PointeeInfo { pub safe: Option, } -impl LayoutS { +impl LayoutData { /// Returns `true` if the layout corresponds to an unsized type. #[inline] pub fn is_unsized(&self) -> bool { diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 02cb6f188a7..8e4f4c8e71a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2697,7 +2697,7 @@ impl fmt::Debug for ImplPolarity { } /// The polarity of a trait bound. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)] #[derive(HashStable_Generic)] pub enum BoundPolarity { /// `Type: Trait` @@ -2719,7 +2719,7 @@ impl BoundPolarity { } /// The constness of a trait bound. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)] #[derive(HashStable_Generic)] pub enum BoundConstness { /// `Type: Trait` diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index b73412a4b1d..9311af28f54 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -223,7 +223,7 @@ impl AttrItem { self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span)) } - fn meta_item_list(&self) -> Option> { + pub fn meta_item_list(&self) -> Option> { match &self.args { AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { MetaItemKind::list_from_tokens(args.tokens.clone()) diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 207ec710650..eb71ec5f4ec 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -135,7 +135,7 @@ pub trait Visitor<'ast>: Sized { /// or `ControlFlow`. type Result: VisitorResult = (); - fn visit_ident(&mut self, _ident: Ident) -> Self::Result { + fn visit_ident(&mut self, _ident: &'ast Ident) -> Self::Result { Self::Result::output() } fn visit_foreign_item(&mut self, i: &'ast ForeignItem) -> Self::Result { @@ -173,9 +173,6 @@ pub trait Visitor<'ast>: Sized { fn visit_method_receiver_expr(&mut self, ex: &'ast Expr) -> Self::Result { self.visit_expr(ex) } - fn visit_expr_post(&mut self, _ex: &'ast Expr) -> Self::Result { - Self::Result::output() - } fn visit_ty(&mut self, t: &'ast Ty) -> Self::Result { walk_ty(self, t) } @@ -317,12 +314,12 @@ pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::R } pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, Label { ident }: &'a Label) -> V::Result { - visitor.visit_ident(*ident) + visitor.visit_ident(ident) } pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) -> V::Result { let Lifetime { id: _, ident } = lifetime; - visitor.visit_ident(*ident) + visitor.visit_ident(ident) } pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) -> V::Result @@ -429,7 +426,7 @@ impl WalkItemKind for ItemKind { }) => { try_visit!(walk_qself(visitor, qself)); try_visit!(visitor.visit_path(path, *id)); - visit_opt!(visitor, visit_ident, *rename); + visit_opt!(visitor, visit_ident, rename); visit_opt!(visitor, visit_block, body); } ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { @@ -437,9 +434,9 @@ impl WalkItemKind for ItemKind { try_visit!(visitor.visit_path(prefix, *id)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { - visitor.visit_ident(*ident); + visitor.visit_ident(ident); if let Some(rename) = rename { - visitor.visit_ident(*rename); + visitor.visit_ident(rename); } } } @@ -472,7 +469,7 @@ where let Variant { attrs, id: _, span: _, vis, ident, data, disr_expr, is_placeholder: _ } = variant; walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_vis(vis)); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_variant_data(data)); visit_opt!(visitor, visit_variant_discr, disr_expr); V::Result::output() @@ -481,7 +478,7 @@ where pub fn walk_expr_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a ExprField) -> V::Result { let ExprField { attrs, id: _, span: _, ident, expr, is_shorthand: _, is_placeholder: _ } = f; walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_expr(expr)); V::Result::output() } @@ -489,7 +486,7 @@ pub fn walk_expr_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a ExprField) -> pub fn walk_pat_field<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a PatField) -> V::Result { let PatField { ident, pat, is_shorthand: _, attrs, id: _, span: _, is_placeholder: _ } = fp; walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_pat(pat)); V::Result::output() } @@ -564,7 +561,7 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>( match kind { UseTreeKind::Simple(rename) => { // The extra IDs are handled during AST lowering. - visit_opt!(visitor, visit_ident, *rename); + visit_opt!(visitor, visit_ident, rename); } UseTreeKind::Glob => {} UseTreeKind::Nested { ref items, span: _ } => { @@ -581,7 +578,7 @@ pub fn walk_path_segment<'a, V: Visitor<'a>>( segment: &'a PathSegment, ) -> V::Result { let PathSegment { ident, id: _, args } = segment; - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); visit_opt!(visitor, visit_generic_args, args); V::Result::output() } @@ -627,7 +624,7 @@ pub fn walk_assoc_item_constraint<'a, V: Visitor<'a>>( constraint: &'a AssocItemConstraint, ) -> V::Result { let AssocItemConstraint { id: _, ident, gen_args, kind, span: _ } = constraint; - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); visit_opt!(visitor, visit_generic_args, gen_args); match kind { AssocItemConstraintKind::Equality { term } => match term { @@ -665,7 +662,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res try_visit!(visitor.visit_pat(subpattern)); } PatKind::Ident(_bmode, ident, optional_subpattern) => { - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); visit_opt!(visitor, visit_pat, optional_subpattern); } PatKind::Lit(expression) => try_visit!(visitor.visit_expr(expression)), @@ -751,7 +748,7 @@ pub fn walk_generic_param<'a, V: Visitor<'a>>( let GenericParam { id: _, ident, attrs, bounds, is_placeholder: _, kind, colon_span: _ } = param; walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); match kind { GenericParamKind::Lifetime => (), @@ -889,7 +886,7 @@ impl WalkItemKind for AssocItemKind { }) => { try_visit!(walk_qself(visitor, qself)); try_visit!(visitor.visit_path(path, *id)); - visit_opt!(visitor, visit_ident, *rename); + visit_opt!(visitor, visit_ident, rename); visit_opt!(visitor, visit_block, body); } AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { @@ -897,9 +894,9 @@ impl WalkItemKind for AssocItemKind { try_visit!(visitor.visit_path(prefix, id)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { - visitor.visit_ident(*ident); + visitor.visit_ident(ident); if let Some(rename) = rename { - visitor.visit_ident(*rename); + visitor.visit_ident(rename); } } } @@ -915,7 +912,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>( item: &'a Item, ctxt: AssocCtxt, ) -> V::Result { - let &Item { id: _, span: _, ident, ref vis, ref attrs, ref kind, tokens: _ } = item; + 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)); @@ -935,7 +932,7 @@ pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _ } = field; walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_vis(vis)); - visit_opt!(visitor, visit_ident, *ident); + visit_opt!(visitor, visit_ident, ident); try_visit!(visitor.visit_ty(ty)); V::Result::output() } @@ -1017,7 +1014,7 @@ pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs for FormatArgument { kind, expr } in arguments.all_args() { match kind { FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => { - try_visit!(visitor.visit_ident(*ident)) + try_visit!(visitor.visit_ident(ident)) } FormatArgumentKind::Normal => {} } @@ -1137,7 +1134,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Field(subexpression, ident) => { try_visit!(visitor.visit_expr(subexpression)); - try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_ident(ident)); } ExprKind::Index(main_expression, index_expression, _span) => { try_visit!(visitor.visit_expr(main_expression)); @@ -1172,7 +1169,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V ExprKind::FormatArgs(f) => try_visit!(visitor.visit_format_args(f)), ExprKind::OffsetOf(container, fields) => { try_visit!(visitor.visit_ty(container)); - walk_list!(visitor, visit_ident, fields.iter().copied()); + walk_list!(visitor, visit_ident, fields.iter()); } ExprKind::Yield(optional_expression) => { visit_opt!(visitor, visit_expr, optional_expression); @@ -1185,7 +1182,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V ExprKind::Dummy => {} } - visitor.visit_expr_post(expression) + V::Result::output() } pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) -> V::Result { diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 88cdb2ec363..6585a7de245 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -49,7 +49,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | asm::InlineAsmArch::RiscV64 | asm::InlineAsmArch::LoongArch64 ); - if !is_stable && !self.tcx.features().asm_experimental_arch { + if !is_stable && !self.tcx.features().asm_experimental_arch() { feature_err( &self.tcx.sess, sym::asm_experimental_arch, @@ -65,7 +65,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { { self.dcx().emit_err(AttSyntaxOnlyX86 { span: sp }); } - if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind { + if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind() { feature_err( &self.tcx.sess, sym::asm_unwind, @@ -237,7 +237,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } InlineAsmOperand::Label { block } => { - if !self.tcx.features().asm_goto { + if !self.tcx.features().asm_goto() { feature_err( sess, sym::asm_goto, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index ae1e1b3f8a2..a1a16d0ca26 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -575,7 +575,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } else { // Either `body.is_none()` or `is_never_pattern` here. if !is_never_pattern { - if self.tcx.features().never_patterns { + if self.tcx.features().never_patterns() { // If the feature is off we already emitted the error after parsing. let suggestion = span.shrink_to_hi(); self.dcx().emit_err(MatchArmWithNoBody { span, suggestion }); @@ -717,7 +717,7 @@ impl<'hir> LoweringContext<'_, 'hir> { outer_hir_id: HirId, inner_hir_id: HirId, ) { - if self.tcx.features().async_fn_track_caller + if self.tcx.features().async_fn_track_caller() && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)) { @@ -1572,7 +1572,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); } Some(hir::CoroutineKind::Coroutine(_)) => { - if !self.tcx.features().coroutines { + if !self.tcx.features().coroutines() { rustc_session::parse::feature_err( &self.tcx.sess, sym::coroutines, @@ -1584,7 +1584,7 @@ impl<'hir> LoweringContext<'_, 'hir> { false } None => { - if !self.tcx.features().coroutines { + if !self.tcx.features().coroutines() { rustc_session::parse::feature_err( &self.tcx.sess, sym::coroutines, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 7416a1e39eb..97fa90d340e 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -57,7 +57,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { owner: NodeId, f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>, ) { - let mut lctx = LoweringContext::new(self.tcx, self.resolver, self.ast_index); + let mut lctx = LoweringContext::new(self.tcx, self.resolver); lctx.with_hir_id_owner(owner, |lctx| f(lctx)); for (def_id, info) in lctx.children { @@ -193,8 +193,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { let (generics, (ty, body_id)) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -225,16 +223,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let itctx = ImplTraitContext::Universal; - let (generics, decl) = - this.lower_generics(generics, header.constness, false, id, itctx, |this| { - this.lower_fn_decl( - decl, - id, - *fn_sig_span, - FnDeclKind::Fn, - coroutine_kind, - ) - }); + let (generics, decl) = this.lower_generics(generics, id, itctx, |this| { + this.lower_fn_decl(decl, id, *fn_sig_span, FnDeclKind::Fn, coroutine_kind) + }); let sig = hir::FnSig { decl, header: this.lower_fn_header(*header, hir::Safety::Safe), @@ -269,8 +260,6 @@ impl<'hir> LoweringContext<'_, 'hir> { add_ty_alias_where_clause(&mut generics, *where_clauses, true); let (generics, ty) = self.lower_generics( &generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { @@ -294,8 +283,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Enum(enum_definition, generics) => { let (generics, variants) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -309,8 +296,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Struct(struct_def, generics) => { let (generics, struct_def) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, struct_def), @@ -320,8 +305,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Union(vdata, generics) => { let (generics, vdata) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, vdata), @@ -353,7 +336,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // parent lifetime. let itctx = ImplTraitContext::Universal; let (generics, (trait_ref, lowered_ty)) = - self.lower_generics(ast_generics, Const::No, false, id, itctx, |this| { + self.lower_generics(ast_generics, id, itctx, |this| { let modifiers = TraitBoundModifiers { constness: BoundConstness::Never, asyncness: BoundAsyncness::Normal, @@ -405,8 +388,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Trait(box Trait { is_auto, safety, generics, bounds, items }) => { let (generics, (safety, items, bounds)) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -426,8 +407,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::TraitAlias(generics, bounds) => { let (generics, bounds) = self.lower_generics( generics, - Const::No, - false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -604,50 +583,23 @@ impl<'hir> LoweringContext<'_, 'hir> { ctxt: AssocCtxt, parent_hir: &'hir hir::OwnerInfo<'hir>, ) -> hir::OwnerNode<'hir> { - // Evaluate with the lifetimes in `params` in-scope. - // This is used to track which lifetimes have already been defined, - // and which need to be replicated when lowering an async fn. - let parent_item = parent_hir.node().expect_item(); - let constness = match parent_item.kind { + match parent_item.kind { hir::ItemKind::Impl(impl_) => { self.is_in_trait_impl = impl_.of_trait.is_some(); - // N.B. the impl should always lower to methods that have `const host: bool` params if the trait - // is const. It doesn't matter whether the `impl` itself is const. Disallowing const fn from - // calling non-const impls are done through associated types. - if let Some(def_id) = impl_.of_trait.and_then(|tr| tr.trait_def_id()) { - if let Some(local_def) = def_id.as_local() { - match &self.ast_index[local_def] { - AstOwner::Item(ast::Item { attrs, .. }) => attrs - .iter() - .find(|attr| attr.has_name(sym::const_trait)) - .map_or(Const::No, |attr| Const::Yes(attr.span)), - _ => Const::No, - } - } else if self.tcx.is_const_trait(def_id) { - // FIXME(effects) span - Const::Yes(self.tcx.def_ident_span(def_id).unwrap()) - } else { - Const::No - } - } else { - Const::No - } } - hir::ItemKind::Trait(_, _, _, _, _) => parent_hir - .attrs - .get(parent_item.hir_id().local_id) - .iter() - .find(|attr| attr.has_name(sym::const_trait)) - .map_or(Const::No, |attr| Const::Yes(attr.span)), + hir::ItemKind::Trait(_, _, _, _, _) => {} kind => { span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr()) } - }; + } + // Evaluate with the lifetimes in `params` in-scope. + // This is used to track which lifetimes have already been defined, + // and which need to be replicated when lowering an async fn. match ctxt { - AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item, constness)), - AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item, constness)), + AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item)), + AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item)), } } @@ -663,7 +615,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let fdec = &sig.decl; let itctx = ImplTraitContext::Universal; let (generics, (decl, fn_args)) = - self.lower_generics(generics, Const::No, false, i.id, itctx, |this| { + self.lower_generics(generics, i.id, itctx, |this| { ( // Disallow `impl Trait` in foreign items. this.lower_fn_decl( @@ -775,11 +727,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_trait_item( - &mut self, - i: &AssocItem, - trait_constness: Const, - ) -> &'hir hir::TraitItem<'hir> { + fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { let hir_id = self.lower_node_id(i.id); self.lower_attrs(hir_id, &i.attrs); let trait_item_def_id = hir_id.expect_owner(); @@ -788,8 +736,6 @@ impl<'hir> LoweringContext<'_, 'hir> { AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => { let (generics, kind) = self.lower_generics( generics, - Const::No, - false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -810,7 +756,6 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, FnDeclKind::Trait, sig.header.coroutine_kind, - trait_constness, ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false) } @@ -829,7 +774,6 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, FnDeclKind::Trait, sig.header.coroutine_kind, - trait_constness, ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true) } @@ -838,8 +782,6 @@ impl<'hir> LoweringContext<'_, 'hir> { add_ty_alias_where_clause(&mut generics, *where_clauses, false); let (generics, kind) = self.lower_generics( &generics, - Const::No, - false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -912,11 +854,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(span, hir::ExprKind::Err(guar)) } - fn lower_impl_item( - &mut self, - i: &AssocItem, - constness_of_trait: Const, - ) -> &'hir hir::ImplItem<'hir> { + fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> { // Since `default impl` is not yet implemented, this is always true in impls. let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); @@ -926,8 +864,6 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = match &i.kind { AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( generics, - Const::No, - false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -953,7 +889,6 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent }, sig.header.coroutine_kind, - constness_of_trait, ); (generics, hir::ImplItemKind::Fn(sig, body_id)) @@ -963,8 +898,6 @@ impl<'hir> LoweringContext<'_, 'hir> { add_ty_alias_where_clause(&mut generics, *where_clauses, false); self.lower_generics( &generics, - Const::No, - false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { @@ -1370,18 +1303,12 @@ impl<'hir> LoweringContext<'_, 'hir> { id: NodeId, kind: FnDeclKind, coroutine_kind: Option, - parent_constness: Const, ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header, hir::Safety::Safe); - // Don't pass along the user-provided constness of trait associated functions; we don't want to - // synthesize a host effect param for them. We reject `const` on them during AST validation. - let constness = - if kind == FnDeclKind::Inherent { sig.header.constness } else { parent_constness }; let itctx = ImplTraitContext::Universal; - let (generics, decl) = - self.lower_generics(generics, constness, kind == FnDeclKind::Impl, id, itctx, |this| { - this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) - }); + let (generics, decl) = self.lower_generics(generics, id, itctx, |this| { + this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) + }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } @@ -1460,8 +1387,6 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_generics( &mut self, generics: &Generics, - constness: Const, - force_append_constness: bool, parent_node_id: NodeId, itctx: ImplTraitContext, f: impl FnOnce(&mut Self) -> T, @@ -1512,7 +1437,7 @@ impl<'hir> LoweringContext<'_, 'hir> { continue; } let is_param = *is_param.get_or_insert_with(compute_is_param); - if !is_param && !self.tcx.features().more_maybe_bounds { + if !is_param && !self.tcx.features().more_maybe_bounds() { self.tcx .sess .create_feature_err( @@ -1524,30 +1449,6 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - // Desugar `~const` bound in generics into an additional `const host: bool` param - // if the effects feature is enabled. This needs to be done before we lower where - // clauses since where clauses need to bind to the DefId of the host param - let host_param_parts = if let Const::Yes(span) = constness - // if this comes from implementing a `const` trait, we must force constness to be appended - // to the impl item, no matter whether effects is enabled. - && (self.tcx.features().effects || force_append_constness) - { - let span = self.lower_span(span); - let param_node_id = self.next_node_id(); - let hir_id = self.next_id(); - let def_id = self.create_def( - self.local_def_id(parent_node_id), - param_node_id, - sym::host, - DefKind::ConstParam, - span, - ); - self.host_param_id = Some(def_id); - Some((span, hir_id, def_id)) - } else { - None - }; - let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new(); predicates.extend(generics.params.iter().filter_map(|param| { self.lower_generic_bound_predicate( @@ -1595,74 +1496,6 @@ impl<'hir> LoweringContext<'_, 'hir> { let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds); predicates.extend(impl_trait_bounds.into_iter()); - if let Some((span, hir_id, def_id)) = host_param_parts { - let const_node_id = self.next_node_id(); - let anon_const_did = - self.create_def(def_id, const_node_id, kw::Empty, DefKind::AnonConst, span); - - let const_id = self.next_id(); - let const_expr_id = self.next_id(); - let bool_id = self.next_id(); - - self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); - self.children.push((anon_const_did, hir::MaybeOwner::NonOwner(const_id))); - - let const_body = self.lower_body(|this| { - (&[], hir::Expr { - hir_id: const_expr_id, - kind: hir::ExprKind::Lit( - this.arena.alloc(hir::Lit { node: LitKind::Bool(true), span }), - ), - span, - }) - }); - - let default_ac = self.arena.alloc(hir::AnonConst { - def_id: anon_const_did, - hir_id: const_id, - body: const_body, - span, - }); - let default_ct = self.arena.alloc(hir::ConstArg { - hir_id: self.next_id(), - kind: hir::ConstArgKind::Anon(default_ac), - is_desugared_from_effects: false, - }); - let param = hir::GenericParam { - def_id, - hir_id, - name: hir::ParamName::Plain(Ident { name: sym::host, span }), - span, - kind: hir::GenericParamKind::Const { - ty: self.arena.alloc(self.ty( - span, - hir::TyKind::Path(hir::QPath::Resolved( - None, - self.arena.alloc(hir::Path { - res: Res::PrimTy(hir::PrimTy::Bool), - span, - segments: self.arena.alloc_from_iter([hir::PathSegment { - ident: Ident { name: sym::bool, span }, - hir_id: bool_id, - res: Res::PrimTy(hir::PrimTy::Bool), - args: None, - infer_args: false, - }]), - }), - )), - )), - default: Some(default_ct), - is_host_effect: true, - synthetic: true, - }, - colon_span: None, - pure_wrt_drop: false, - source: hir::GenericParamSource::Generics, - }; - - params.push(param); - } - let lowered_generics = self.arena.alloc(hir::Generics { params: self.arena.alloc_from_iter(params), predicates: self.arena.alloc_from_iter(predicates), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 4d8d22e09d9..34b8137aea8 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -154,17 +154,10 @@ struct LoweringContext<'a, 'hir> { /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this /// field from the original parameter 'a to the new parameter 'a1. generics_def_id_map: Vec>, - - host_param_id: Option, - ast_index: &'a IndexSlice>, } impl<'a, 'hir> LoweringContext<'a, 'hir> { - fn new( - tcx: TyCtxt<'hir>, - resolver: &'a mut ResolverAstLowering, - ast_index: &'a IndexSlice>, - ) -> Self { + fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self { Self { // Pseudo-globals. tcx, @@ -193,7 +186,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { impl_trait_defs: Vec::new(), impl_trait_bounds: Vec::new(), allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(), - allow_gen_future: if tcx.features().async_fn_track_caller { + allow_gen_future: if tcx.features().async_fn_track_caller() { [sym::gen_future, sym::closure_track_caller].into() } else { [sym::gen_future].into() @@ -204,8 +197,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // interact with `gen`/`async gen` blocks allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), generics_def_id_map: Default::default(), - host_param_id: None, - ast_index, } } @@ -1035,7 +1026,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: data.inputs_span, }) }; - if !self.tcx.features().return_type_notation + if !self.tcx.features().return_type_notation() && self.tcx.sess.is_nightly_build() { add_feature_diagnostics( @@ -1160,7 +1151,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)), ast::GenericArg::Type(ty) => { match &ty.kind { - TyKind::Infer if self.tcx.features().generic_arg_infer => { + TyKind::Infer if self.tcx.features().generic_arg_infer() => { return GenericArg::Infer(hir::InferArg { hir_id: self.lower_node_id(ty.id), span: self.lower_span(ty.span), @@ -1500,7 +1491,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // is enabled. We don't check the span of the edition, since this is done // on a per-opaque basis to account for nested opaques. let always_capture_in_scope = match origin { - _ if self.tcx.features().lifetime_capture_rules_2024 => true, + _ if self.tcx.features().lifetime_capture_rules_2024() => true, hir::OpaqueTyOrigin::TyAlias { .. } => true, hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(), hir::OpaqueTyOrigin::AsyncFn { .. } => { @@ -1519,7 +1510,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Feature gate for RPITIT + use<..> match origin { rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => { - if !self.tcx.features().precise_capturing_in_traits + if !self.tcx.features().precise_capturing_in_traits() && let Some(span) = bounds.iter().find_map(|bound| match *bound { ast::GenericBound::Use(_, span) => Some(span), _ => None, @@ -1956,7 +1947,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::GenericBound::Trait(hir::PolyTraitRef { bound_generic_params: &[], - modifiers: hir::TraitBoundModifier::None, + modifiers: hir::TraitBoundModifiers::NONE, trait_ref: hir::TraitRef { path: self.make_lang_item_path(trait_lang_item, opaque_ty_span, Some(bound_args)), hir_ref_id: self.next_id(), @@ -2054,11 +2045,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param: &GenericParam, source: hir::GenericParamSource, ) -> hir::GenericParam<'hir> { - let (name, kind) = self.lower_generic_param_kind( - param, - source, - attr::contains_name(¶m.attrs, sym::rustc_runtime), - ); + let (name, kind) = self.lower_generic_param_kind(param, source); let hir_id = self.lower_node_id(param.id); self.lower_attrs(hir_id, ¶m.attrs); @@ -2078,7 +2065,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, param: &GenericParam, source: hir::GenericParamSource, - is_host_effect: bool, ) -> (hir::ParamName, hir::GenericParamKind<'hir>) { match ¶m.kind { GenericParamKind::Lifetime => { @@ -2144,7 +2130,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ( hir::ParamName::Plain(self.lower_ident(param.ident)), - hir::GenericParamKind::Const { ty, default, is_host_effect, synthetic: false }, + hir::GenericParamKind::Const { ty, default, synthetic: false }, ) } } @@ -2270,7 +2256,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen<'hir> { match c.value.kind { ExprKind::Underscore => { - if self.tcx.features().generic_arg_infer { + if self.tcx.features().generic_arg_infer() { hir::ArrayLen::Infer(hir::InferArg { hir_id: self.lower_node_id(c.id), span: self.lower_span(c.value.span), @@ -2445,22 +2431,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_trait_bound_modifiers( &mut self, modifiers: TraitBoundModifiers, - ) -> hir::TraitBoundModifier { - // Invalid modifier combinations will cause an error during AST validation. - // Arbitrarily pick a placeholder for them to make compilation proceed. - match (modifiers.constness, modifiers.polarity) { - (BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None, - (_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe, - (BoundConstness::Never, BoundPolarity::Negative(_)) => { - if self.tcx.features().negative_bounds { - hir::TraitBoundModifier::Negative - } else { - hir::TraitBoundModifier::None - } - } - (BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const, - (BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst, - } + ) -> hir::TraitBoundModifiers { + hir::TraitBoundModifiers { constness: modifiers.constness, polarity: modifiers.polarity } } // Helper methods for building HIR. @@ -2626,7 +2598,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => { let principal = hir::PolyTraitRef { bound_generic_params: &[], - modifiers: hir::TraitBoundModifier::None, + modifiers: hir::TraitBoundModifiers::NONE, trait_ref: hir::TraitRef { path, hir_ref_id: hir_id }, span: self.lower_span(span), }; diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index e60488fdc8c..6a0f03c8b31 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -34,7 +34,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { modifiers: Option, ) -> hir::QPath<'hir> { let qself_position = qself.as_ref().map(|q| q.position); - let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx)); + let qself = qself + .as_ref() + // Reject cases like `::Assoc` and `::Assoc`. + .map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path))); let partial_res = self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err)); @@ -75,6 +78,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { None }; + // Only permit `impl Trait` in the final segment. E.g., we permit `Option`, + // `option::Option::Xyz` and reject `option::Option::Xyz`. + let itctx = |i| { + if i + 1 == p.segments.len() { + itctx + } else { + ImplTraitContext::Disallowed(ImplTraitPosition::Path) + } + }; + let path_span_lo = p.span.shrink_to_lo(); let proj_start = p.segments.len() - unresolved_segments; let path = self.arena.alloc(hir::Path { @@ -121,7 +134,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment, param_mode, generic_args_mode, - itctx, + itctx(i), bound_modifier_allowed_features.clone(), ) }, @@ -185,7 +198,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment, param_mode, generic_args_mode, - itctx, + itctx(i), None, )); let qpath = hir::QPath::TypeRelative(ty, hir_segment); @@ -268,7 +281,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: data.inputs_span, }) }; - if !self.tcx.features().return_type_notation + if !self.tcx.features().return_type_notation() && self.tcx.sess.is_nightly_build() { add_feature_diagnostics( @@ -496,7 +509,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^ // ``` FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => { - if self.tcx.features().impl_trait_in_fn_trait_return { + if self.tcx.features().impl_trait_in_fn_trait_return() { self.lower_ty(ty, itctx) } else { self.lower_ty( diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 92acaaa5f36..d81fd53938b 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -146,8 +146,6 @@ ast_passes_generic_before_constraints = generic arguments must come before the f ast_passes_generic_default_trailing = generic parameters with a default must be trailing -ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters - ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed .help = remove one of these features diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 20a4f2120dc..0a4f86d4822 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -80,10 +80,6 @@ struct AstValidator<'a> { disallow_tilde_const: Option, - /// Used to ban `impl Trait` in path projections like `::Item` - /// or `Foo::Bar` - is_impl_trait_banned: bool, - /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe. extern_mod_safety: Option, @@ -123,12 +119,6 @@ impl<'a> AstValidator<'a> { self.extern_mod_safety = old; } - fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.is_impl_trait_banned, true); - f(self); - self.is_impl_trait_banned = old; - } - fn with_tilde_const( &mut self, disallowed: Option, @@ -213,43 +203,12 @@ impl<'a> AstValidator<'a> { .with_tilde_const(Some(TildeConstReason::TraitObject), |this| { visit::walk_ty(this, t) }), - TyKind::Path(qself, path) => { - // We allow these: - // - `Option` - // - `option::Option` - // - `option::Option::Foo` - // - // But not these: - // - `::Foo` - // - `option::Option::Foo`. - // - // To implement this, we disallow `impl Trait` from `qself` - // (for cases like `::Foo>`) - // but we allow `impl Trait` in `GenericArgs` - // iff there are no more PathSegments. - if let Some(qself) = qself { - // `impl Trait` in `qself` is always illegal - self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty)); - } - - // Note that there should be a call to visit_path here, - // so if any logic is added to process `Path`s a call to it should be - // added both in visit_path and here. This code mirrors visit::walk_path. - for (i, segment) in path.segments.iter().enumerate() { - // Allow `impl Trait` iff we're on the final path segment - if i == path.segments.len() - 1 { - self.visit_path_segment(segment); - } else { - self.with_banned_impl_trait(|this| this.visit_path_segment(segment)); - } - } - } _ => visit::walk_ty(self, t), } } fn visit_struct_field_def(&mut self, field: &'a FieldDef) { - if let Some(ident) = field.ident + if let Some(ref ident) = field.ident && ident.name == kw::Underscore { self.visit_vis(&field.vis); @@ -295,7 +254,8 @@ impl<'a> AstValidator<'a> { return; }; - let make_impl_const_sugg = if self.features.const_trait_impl + let const_trait_impl = self.features.const_trait_impl(); + let make_impl_const_sugg = if const_trait_impl && let TraitOrTraitImpl::TraitImpl { constness: Const::No, polarity: ImplPolarity::Positive, @@ -308,13 +268,12 @@ impl<'a> AstValidator<'a> { None }; - let make_trait_const_sugg = if self.features.const_trait_impl - && let TraitOrTraitImpl::Trait { span, constness: None } = parent - { - Some(span.shrink_to_lo()) - } else { - None - }; + let make_trait_const_sugg = + if const_trait_impl && let TraitOrTraitImpl::Trait { span, constness: None } = parent { + Some(span.shrink_to_lo()) + } else { + None + }; let parent_constness = parent.constness(); self.dcx().emit_err(errors::TraitFnConst { @@ -737,10 +696,6 @@ impl<'a> AstValidator<'a> { } } TyKind::ImplTrait(_, bounds) => { - if self.is_impl_trait_banned { - self.dcx().emit_err(errors::ImplTraitPath { span: ty.span }); - } - if let Some(outer_impl_trait_sp) = self.outer_impl_trait { self.dcx().emit_err(errors::NestedImplTrait { span: ty.span, @@ -899,7 +854,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } this.visit_vis(&item.vis); - this.visit_ident(item.ident); + this.visit_ident(&item.ident); let disallowed = matches!(constness, Const::No) .then(|| TildeConstReason::TraitImpl { span: item.span }); this.with_tilde_const(disallowed, |this| this.visit_generics(generics)); @@ -953,7 +908,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } this.visit_vis(&item.vis); - this.visit_ident(item.ident); + this.visit_ident(&item.ident); this.with_tilde_const( Some(TildeConstReason::Impl { span: item.span }), |this| this.visit_generics(generics), @@ -991,7 +946,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } self.visit_vis(&item.vis); - self.visit_ident(item.ident); + self.visit_ident(&item.ident); let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref()); self.visit_fn(kind, item.span, item.id); @@ -1058,7 +1013,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound // context for the supertraits. this.visit_vis(&item.vis); - this.visit_ident(item.ident); + this.visit_ident(&item.ident); let disallowed = is_const_trait .is_none() .then(|| TildeConstReason::Trait { span: item.span }); @@ -1085,7 +1040,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ItemKind::Struct(vdata, generics) => match vdata { VariantData::Struct { fields, .. } => { self.visit_vis(&item.vis); - self.visit_ident(item.ident); + self.visit_ident(&item.ident); self.visit_generics(generics); // Permit `Anon{Struct,Union}` as field type. walk_list!(self, visit_struct_field_def, fields); @@ -1101,7 +1056,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match vdata { VariantData::Struct { fields, .. } => { self.visit_vis(&item.vis); - self.visit_ident(item.ident); + self.visit_ident(&item.ident); self.visit_generics(generics); // Permit `Anon{Struct,Union}` as field type. walk_list!(self, visit_struct_field_def, fields); @@ -1145,7 +1100,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } self.check_type_no_bounds(bounds, "this context"); - if self.features.lazy_type_alias { + if self.features.lazy_type_alias() { if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) { self.dcx().emit_err(err); } @@ -1286,7 +1241,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { GenericBound::Trait(trait_ref) => { match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) { (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) - if !self.features.more_maybe_bounds => + if !self.features.more_maybe_bounds() => { self.sess .create_feature_err( @@ -1299,7 +1254,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .emit(); } (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) - if !self.features.more_maybe_bounds => + if !self.features.more_maybe_bounds() => { self.sess .create_feature_err( @@ -1521,7 +1476,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { || matches!(sig.header.constness, Const::Yes(_)) => { self.visit_vis(&item.vis); - self.visit_ident(item.ident); + self.visit_ident(&item.ident); let kind = FnKind::Fn( FnCtxt::Assoc(ctxt), item.ident, @@ -1729,7 +1684,6 @@ pub fn check_crate( has_proc_macro_decls: false, outer_impl_trait: None, disallow_tilde_const: Some(TildeConstReason::Item), - is_impl_trait_banned: false, extern_mod_safety: None, lint_buffer: lints, }; diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 4ca1acde1e2..8c3ac9864ed 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -418,13 +418,6 @@ pub(crate) struct TraitObjectBound { pub span: Span, } -#[derive(Diagnostic)] -#[diag(ast_passes_impl_trait_path, code = E0667)] -pub(crate) struct ImplTraitPath { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_passes_nested_impl_trait, code = E0666)] pub(crate) struct NestedImplTrait { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index f2773dcdc60..d646150a620 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -15,13 +15,13 @@ use crate::errors; /// The common case. macro_rules! gate { ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ - if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { + if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) { #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit(); } }}; ($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{ - if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { + if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) { // FIXME: make this translatable #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] @@ -43,7 +43,7 @@ macro_rules! gate_alt { /// The case involving a multispan. macro_rules! gate_multi { ($visitor:expr, $feature:ident, $spans:expr, $explain:expr) => {{ - if !$visitor.features.$feature { + if !$visitor.features.$feature() { let spans: Vec<_> = $spans.filter(|span| !span.allows_unstable(sym::$feature)).collect(); if !spans.is_empty() { @@ -56,7 +56,7 @@ macro_rules! gate_multi { /// The legacy case. macro_rules! gate_legacy { ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ - if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { + if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) { feature_warn(&$visitor.sess, sym::$feature, $span, $explain); } }}; @@ -150,7 +150,7 @@ impl<'a> PostExpansionVisitor<'a> { // FIXME(non_lifetime_binders): Const bound params are pretty broken. // Let's keep users from using this feature accidentally. - if self.features.non_lifetime_binders { + if self.features.non_lifetime_binders() { let const_param_spans: Vec<_> = params .iter() .filter_map(|param| match param.kind { @@ -210,7 +210,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } // Emit errors for non-staged-api crates. - if !self.features.staged_api { + if !self.features.staged_api() { if attr.has_name(sym::unstable) || attr.has_name(sym::stable) || attr.has_name(sym::rustc_const_unstable) @@ -470,7 +470,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { // Limit `min_specialization` to only specializing functions. gate_alt!( &self, - self.features.specialization || (is_fn && self.features.min_specialization), + self.features.specialization() || (is_fn && self.features.min_specialization()), sym::specialization, i.span, "specialization is unstable" @@ -548,7 +548,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(return_type_notation, "return type notation is experimental"); gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); - if !visitor.features.never_patterns { + if !visitor.features.never_patterns() { if let Some(spans) = spans.get(&sym::never_patterns) { for &span in spans { if span.allows_unstable(sym::never_patterns) { @@ -572,7 +572,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { } } - if !visitor.features.negative_bounds { + if !visitor.features.negative_bounds() { for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { sess.dcx().emit_err(errors::NegativeBoundUnsupported { span }); } @@ -600,59 +600,61 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { } fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) { - // checks if `#![feature]` has been used to enable any lang feature - // does not check the same for lib features unless there's at least one - // declared lang feature - if !sess.opts.unstable_features.is_nightly_build() { - if features.declared_features.is_empty() { - return; - } - for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { - let mut err = errors::FeatureOnNonNightly { - span: attr.span, - channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"), - stable_features: vec![], - sugg: None, - }; - - let mut all_stable = true; - for ident in - attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) - { - let name = ident.name; - let stable_since = features - .declared_lang_features - .iter() - .flat_map(|&(feature, _, since)| if feature == name { since } else { None }) - .next(); - if let Some(since) = stable_since { - err.stable_features.push(errors::StableFeature { name, since }); - } else { - all_stable = false; - } - } - if all_stable { - err.sugg = Some(attr.span); - } - sess.dcx().emit_err(err); - } + // checks if `#![feature]` has been used to enable any feature. + if sess.opts.unstable_features.is_nightly_build() { + return; } + if features.enabled_features().is_empty() { + return; + } + let mut errored = false; + for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { + // `feature(...)` used on non-nightly. This is definitely an error. + let mut err = errors::FeatureOnNonNightly { + span: attr.span, + channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"), + stable_features: vec![], + sugg: None, + }; + + let mut all_stable = true; + for ident in attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) { + let name = ident.name; + let stable_since = features + .enabled_lang_features() + .iter() + .find(|feat| feat.gate_name == name) + .map(|feat| feat.stable_since) + .flatten(); + if let Some(since) = stable_since { + err.stable_features.push(errors::StableFeature { name, since }); + } else { + all_stable = false; + } + } + if all_stable { + err.sugg = Some(attr.span); + } + sess.dcx().emit_err(err); + errored = true; + } + // Just make sure we actually error if anything is listed in `enabled_features`. + assert!(errored); } fn check_incompatible_features(sess: &Session, features: &Features) { - let declared_features = features - .declared_lang_features - .iter() - .copied() - .map(|(name, span, _)| (name, span)) - .chain(features.declared_lib_features.iter().copied()); + let enabled_lang_features = + features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); + let enabled_lib_features = + features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); + let enabled_features = enabled_lang_features.chain(enabled_lib_features); for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES .iter() - .filter(|&&(f1, f2)| features.active(f1) && features.active(f2)) + .filter(|(f1, f2)| features.enabled(*f1) && features.enabled(*f2)) { - if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) { - if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2) + if let Some((f1_name, f1_span)) = enabled_features.clone().find(|(name, _)| name == f1) { + if let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2) { let spans = vec![f1_span, f2_span]; sess.dcx().emit_err(errors::IncompatibleFeatures { @@ -671,10 +673,11 @@ fn check_new_solver_banned_features(sess: &Session, features: &Features) { } // Ban GCE with the new solver, because it does not implement GCE correctly. - if let Some(&(_, gce_span, _)) = features - .declared_lang_features + if let Some(gce_span) = features + .enabled_lang_features() .iter() - .find(|&&(feat, _, _)| feat == sym::generic_const_exprs) + .find(|feat| feat.gate_name == sym::generic_const_exprs) + .map(|feat| feat.attr_sp) { sess.dcx().emit_err(errors::IncompatibleFeatures { spans: vec![gce_span], diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs index e22e99f6e4d..9e7204df8ad 100644 --- a/compiler/rustc_ast_passes/src/node_count.rs +++ b/compiler/rustc_ast_passes/src/node_count.rs @@ -16,7 +16,7 @@ impl NodeCounter { } impl<'ast> Visitor<'ast> for NodeCounter { - fn visit_ident(&mut self, _ident: Ident) { + fn visit_ident(&mut self, _ident: &Ident) { self.count += 1; } fn visit_foreign_item(&mut self, i: &ForeignItem) { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 2cdec2138ad..1e18f0779f0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -627,6 +627,13 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) { self.ibox(0); + match item.unsafety { + ast::Safety::Unsafe(_) => { + self.word("unsafe"); + self.popen(); + } + ast::Safety::Default | ast::Safety::Safe(_) => {} + } match &item.args { AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common( Some(MacHeader::Path(&item.path)), @@ -655,6 +662,10 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.word(token_str); } } + match item.unsafety { + ast::Safety::Unsafe(_) => self.pclose(), + ast::Safety::Default | ast::Safety::Safe(_) => {} + } self.end(); } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 8217b6df5b4..8279c66836c 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -38,7 +38,6 @@ impl<'a> State<'a> { self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); } ast::ForeignItemKind::Static(box ast::StaticItem { ty, mutability, expr, safety }) => { - self.print_safety(*safety); self.print_item_const( ident, Some(*mutability), @@ -46,6 +45,7 @@ impl<'a> State<'a> { ty, expr.as_deref(), vis, + *safety, ast::Defaultness::Final, ) } @@ -84,10 +84,12 @@ impl<'a> State<'a> { ty: &ast::Ty, body: Option<&ast::Expr>, vis: &ast::Visibility, + safety: ast::Safety, defaultness: ast::Defaultness, ) { self.head(""); self.print_visibility(vis); + self.print_safety(safety); self.print_defaultness(defaultness); let leading = match mutbl { None => "const", @@ -181,6 +183,7 @@ impl<'a> State<'a> { ty, body.as_deref(), &item.vis, + ast::Safety::Default, ast::Defaultness::Final, ); } @@ -192,6 +195,7 @@ impl<'a> State<'a> { ty, expr.as_deref(), &item.vis, + ast::Safety::Default, *defaultness, ); } @@ -549,6 +553,7 @@ impl<'a> State<'a> { ty, expr.as_deref(), vis, + ast::Safety::Default, *defaultness, ); } diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl index adabf18ca85..235ab7572c4 100644 --- a/compiler/rustc_attr/messages.ftl +++ b/compiler/rustc_attr/messages.ftl @@ -91,6 +91,9 @@ attr_non_ident_feature = attr_rustc_allowed_unstable_pairing = `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute +attr_rustc_const_stable_indirect_pairing = + `const_stable_indirect` attribute does not make sense on `rustc_const_stable` function, its behavior is already implied + attr_rustc_promotable_pairing = `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index bbb17497684..6af75bc94bb 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -16,9 +16,9 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::parse::feature_err; use rustc_session::{RustcVersion, Session}; -use rustc_span::Span; use rustc_span::hygiene::Transparency; use rustc_span::symbol::{Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Span}; use crate::fluent_generated; use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; @@ -92,7 +92,11 @@ impl Stability { #[derive(HashStable_Generic)] pub struct ConstStability { pub level: StabilityLevel, - pub feature: Symbol, + /// This can be `None` for functions that do not have an explicit const feature. + /// We still track them for recursive const stability checks. + pub feature: Option, + /// This is true iff the `const_stable_indirect` attribute is present. + pub const_stable_indirect: bool, /// whether the function has a `#[rustc_promotable]` attribute pub promotable: bool, } @@ -268,17 +272,23 @@ pub fn find_stability( /// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable` /// attributes in `attrs`. Returns `None` if no stability attributes are found. +/// +/// `is_const_fn` indicates whether this is a function marked as `const`. It will always +/// be false for intrinsics in an `extern` block! pub fn find_const_stability( sess: &Session, attrs: &[Attribute], item_sp: Span, + is_const_fn: bool, ) -> Option<(ConstStability, Span)> { let mut const_stab: Option<(ConstStability, Span)> = None; let mut promotable = false; + let mut const_stable_indirect = None; for attr in attrs { match attr.name_or_empty() { sym::rustc_promotable => promotable = true, + sym::rustc_const_stable_indirect => const_stable_indirect = Some(attr.span), sym::rustc_const_unstable => { if const_stab.is_some() { sess.dcx() @@ -287,8 +297,15 @@ pub fn find_const_stability( } if let Some((feature, level)) = parse_unstability(sess, attr) { - const_stab = - Some((ConstStability { level, feature, promotable: false }, attr.span)); + const_stab = Some(( + ConstStability { + level, + feature: Some(feature), + const_stable_indirect: false, + promotable: false, + }, + attr.span, + )); } } sym::rustc_const_stable => { @@ -298,15 +315,22 @@ pub fn find_const_stability( break; } if let Some((feature, level)) = parse_stability(sess, attr) { - const_stab = - Some((ConstStability { level, feature, promotable: false }, attr.span)); + const_stab = Some(( + ConstStability { + level, + feature: Some(feature), + const_stable_indirect: false, + promotable: false, + }, + attr.span, + )); } } _ => {} } } - // Merge the const-unstable info into the stability info + // Merge promotable and not_exposed_on_stable into stability info if promotable { match &mut const_stab { Some((stab, _)) => stab.promotable = promotable, @@ -317,6 +341,46 @@ pub fn find_const_stability( } } } + if const_stable_indirect.is_some() { + match &mut const_stab { + Some((stab, _)) => { + if stab.is_const_unstable() { + stab.const_stable_indirect = true; + } else { + _ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing { + span: item_sp, + }) + } + } + _ => { + // We ignore the `#[rustc_const_stable_indirect]` here, it should be picked up by + // the `default_const_unstable` logic. + } + } + } + // Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const + // fn` get *some* marker, since we are a staged_api crate and therefore will do recursive const + // stability checks for them. We need to do this because the default for whether an unmarked + // function enforces recursive stability differs between staged-api crates and force-unmarked + // crates: in force-unmarked crates, only functions *explicitly* marked `const_stable_indirect` + // enforce recursive stability. Therefore when `lookup_const_stability` is `None`, we have to + // assume the function does not have recursive stability. All functions that *do* have recursive + // stability must explicitly record this, and so that's what we do for all `const fn` in a + // staged_api crate. + if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() { + let c = ConstStability { + feature: None, + const_stable_indirect: const_stable_indirect.is_some(), + promotable: false, + level: StabilityLevel::Unstable { + reason: UnstableReason::Default, + issue: None, + is_soft: false, + implied_by: None, + }, + }; + const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP))); + } const_stab } @@ -619,11 +683,11 @@ pub fn eval_condition( // we can't use `try_gate_cfg` as symbols don't differentiate between `r#true` // and `true`, and we want to keep the former working without feature gate gate_cfg( - &(( + &( if *b { kw::True } else { kw::False }, sym::cfg_boolean_literals, - |features: &Features| features.cfg_boolean_literals, - )), + |features: &Features| features.cfg_boolean_literals(), + ), cfg.span(), sess, features, @@ -711,7 +775,7 @@ pub fn eval_condition( } sym::target => { if let Some(features) = features - && !features.cfg_target_compact + && !features.cfg_target_compact() { feature_err( sess, @@ -831,7 +895,7 @@ pub fn find_deprecation( attrs: &[Attribute], ) -> Option<(Deprecation, Span)> { let mut depr: Option<(Deprecation, Span)> = None; - let is_rustc = features.staged_api; + let is_rustc = features.staged_api(); 'outer: for attr in attrs { if !attr.has_name(sym::deprecated) { @@ -891,7 +955,7 @@ pub fn find_deprecation( } } sym::suggestion => { - if !features.deprecated_suggestion { + if !features.deprecated_suggestion() { sess.dcx().emit_err( session_diagnostics::DeprecatedItemSuggestion { span: mi.span, @@ -909,7 +973,7 @@ pub fn find_deprecation( sess.dcx().emit_err(session_diagnostics::UnknownMetaItem { span: meta.span(), item: pprust::path_to_string(&mi.path), - expected: if features.deprecated_suggestion { + expected: if features.deprecated_suggestion() { &["since", "note", "suggestion"] } else { &["since", "note"] diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 626840aa6a3..9d08a9f5754 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -318,6 +318,13 @@ pub(crate) struct RustcPromotablePairing { pub span: Span, } +#[derive(Diagnostic)] +#[diag(attr_rustc_const_stable_indirect_pairing)] +pub(crate) struct RustcConstStableIndirectPairing { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(attr_rustc_allowed_unstable_pairing, code = E0789)] pub(crate) struct RustcAllowedUnstablePairing { diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 2437a43bd5a..2fa752384a1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -65,6 +65,7 @@ impl<'tcx> UniverseInfo<'tcx> { UniverseInfoInner::RelateTys { expected, found } => { let err = mbcx.infcx.err_ctxt().report_mismatched_types( &cause, + mbcx.param_env, expected, found, TypeError::RegionsPlaceholderMismatch, @@ -480,12 +481,11 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>( .try_report_from_nll() .or_else(|| { if let SubregionOrigin::Subtype(trace) = cause { - Some( - infcx.err_ctxt().report_and_explain_type_error( - *trace, - TypeError::RegionsPlaceholderMismatch, - ), - ) + Some(infcx.err_ctxt().report_and_explain_type_error( + *trace, + infcx.tcx.param_env(generic_param_scope), + TypeError::RegionsPlaceholderMismatch, + )) } else { None } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index a5f3298b02c..315851729b1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -959,13 +959,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { None } } - hir::ExprKind::MethodCall(_, _, args, span) => { - if let Some(def_id) = typeck_results.type_dependent_def_id(*hir_id) { - Some((def_id, *span, *args)) - } else { - None - } - } + hir::ExprKind::MethodCall(_, _, args, span) => typeck_results + .type_dependent_def_id(*hir_id) + .map(|def_id| (def_id, *span, *args)), _ => None, } }; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index a16c1931a55..abce98265b3 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -360,6 +360,7 @@ fn check_opaque_type_well_formed<'tcx>( .err_ctxt() .report_mismatched_types( &ObligationCause::misc(definition_span, def_id), + param_env, opaque_ty, definition_ty, err, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 7b60a632c30..a544d88e832 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1035,7 +1035,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn unsized_feature_enabled(&self) -> bool { let features = self.tcx().features(); - features.unsized_locals || features.unsized_fn_params + features.unsized_locals() || features.unsized_fn_params() } /// Equate the inferred type and the annotated type for user type annotations diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 71449350985..599b180f879 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -69,7 +69,7 @@ pub(crate) fn expand_assert<'cx>( // If `generic_assert` is enabled, generates rich captured outputs // // FIXME(c410-f3r) See https://github.com/rust-lang/rust/issues/96949 - else if cx.ecfg.features.generic_assert { + else if cx.ecfg.features.generic_assert() { context::Context::new(cx, call_site_span).build(cond_expr, panic_path()) } // If `generic_assert` is not enabled, only outputs a literal "assertion failed: ..." diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs similarity index 95% rename from compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs rename to compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 731945f5cbf..53e938ee216 100644 --- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -19,7 +19,7 @@ macro_rules! path { ($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] } } -pub(crate) fn expand_deriving_smart_ptr( +pub(crate) fn expand_deriving_coerce_pointee( cx: &ExtCtxt<'_>, span: Span, _mitem: &MetaItem, @@ -41,7 +41,7 @@ pub(crate) fn expand_deriving_smart_ptr( cx.dcx() .struct_span_err( span, - "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`", + "`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`", ) .emit(); return; @@ -54,7 +54,7 @@ pub(crate) fn expand_deriving_smart_ptr( cx.dcx() .struct_span_err( span, - "`SmartPointer` can only be derived on `struct`s with at least one field", + "`CoercePointee` can only be derived on `struct`s with at least one field", ) .emit(); return; @@ -64,7 +64,7 @@ pub(crate) fn expand_deriving_smart_ptr( cx.dcx() .struct_span_err( span, - "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`", + "`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`", ) .emit(); return; @@ -94,10 +94,10 @@ pub(crate) fn expand_deriving_smart_ptr( .collect(); let pointee_param_idx = if type_params.is_empty() { - // `#[derive(SmartPointer)]` requires at least one generic type on the target `struct` + // `#[derive(CoercePointee)]` requires at least one generic type on the target `struct` cx.dcx().struct_span_err( span, - "`SmartPointer` can only be derived on `struct`s that are generic over at least one type", + "`CoercePointee` can only be derived on `struct`s that are generic over at least one type", ).emit(); return; } else if type_params.len() == 1 { @@ -113,7 +113,7 @@ pub(crate) fn expand_deriving_smart_ptr( (None, _) => { cx.dcx().struct_span_err( span, - "exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits", + "exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits", ).emit(); return; } @@ -121,7 +121,7 @@ pub(crate) fn expand_deriving_smart_ptr( cx.dcx() .struct_span_err( vec![one, another], - "only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits", + "only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits", ) .emit(); return; @@ -185,7 +185,7 @@ pub(crate) fn expand_deriving_smart_ptr( .struct_span_err( pointee_ty_ident.span, format!( - "`derive(SmartPointer)` requires {} to be marked `?Sized`", + "`derive(CoercePointee)` requires {} to be marked `?Sized`", pointee_ty_ident.name ), ) @@ -195,7 +195,7 @@ pub(crate) fn expand_deriving_smart_ptr( let arg = GenericArg::Type(s_ty.clone()); let unsize = cx.path_all(span, true, path!(span, core::marker::Unsize), vec![arg]); pointee.bounds.push(cx.trait_bound(unsize, false)); - // Drop `#[pointee]` attribute since it should not be recognized outside `derive(SmartPointer)` + // Drop `#[pointee]` attribute since it should not be recognized outside `derive(CoercePointee)` pointee.attrs.retain(|attr| !attr.has_name(sym::pointee)); } diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 652e6f7740f..d4befd12190 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -222,7 +222,7 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, ' rustc_ast::visit::walk_attribute(self, attr); } fn visit_variant(&mut self, v: &'a rustc_ast::Variant) { - self.visit_ident(v.ident); + self.visit_ident(&v.ident); self.visit_vis(&v.vis); self.visit_variant_data(&v.data); visit_opt!(self, visit_anon_const, &v.disr_expr); diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index e884c0ec718..681fbd1651d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -22,12 +22,12 @@ macro path_std($($x:tt)*) { pub(crate) mod bounds; pub(crate) mod clone; +pub(crate) mod coerce_pointee; pub(crate) mod debug; pub(crate) mod decodable; pub(crate) mod default; pub(crate) mod encodable; pub(crate) mod hash; -pub(crate) mod smart_ptr; #[path = "cmp/eq.rs"] pub(crate) mod eq; diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 377d7f542cf..9eee92164cf 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -133,7 +133,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { PartialOrd: partial_ord::expand_deriving_partial_ord, RustcDecodable: decodable::expand_deriving_rustc_decodable, RustcEncodable: encodable::expand_deriving_rustc_encodable, - SmartPointer: smart_ptr::expand_deriving_smart_ptr, + CoercePointee: coerce_pointee::expand_deriving_coerce_pointee, } let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote); diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index d6603af101a..707c36d5046 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -313,14 +313,23 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { match m { ProcMacro::Derive(cd) => { cx.resolver.declare_proc_macro(cd.id); - cx.expr_call(span, proc_macro_ty_method_path(cx, custom_derive), thin_vec![ - cx.expr_str(span, cd.trait_name), - cx.expr_array_ref( - span, - cd.attrs.iter().map(|&s| cx.expr_str(span, s)).collect::>(), - ), - local_path(cx, cd.function_name), - ]) + // The call needs to use `harness_span` so that the const stability checker + // accepts it. + cx.expr_call( + harness_span, + proc_macro_ty_method_path(cx, custom_derive), + thin_vec![ + cx.expr_str(span, cd.trait_name), + cx.expr_array_ref( + span, + cd.attrs + .iter() + .map(|&s| cx.expr_str(span, s)) + .collect::>(), + ), + local_path(cx, cd.function_name), + ], + ) } ProcMacro::Attr(ca) | ProcMacro::Bang(ca) => { cx.resolver.declare_proc_macro(ca.id); @@ -330,7 +339,9 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { ProcMacro::Derive(_) => unreachable!(), }; - cx.expr_call(span, proc_macro_ty_method_path(cx, ident), thin_vec![ + // The call needs to use `harness_span` so that the const stability checker + // accepts it. + cx.expr_call(harness_span, proc_macro_ty_method_path(cx, ident), thin_vec![ cx.expr_str(span, ca.function_name.name), local_path(cx, ca.function_name), ]) diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 9fc0318df5d..42c7f5f0dc6 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -47,12 +47,12 @@ impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} impl, U: ?Sized> DispatchFromDyn> for Box {} -#[lang = "receiver"] -pub trait Receiver {} +#[lang = "legacy_receiver"] +pub trait LegacyReceiver {} -impl Receiver for &T {} -impl Receiver for &mut T {} -impl Receiver for Box {} +impl LegacyReceiver for &T {} +impl LegacyReceiver for &mut T {} +impl LegacyReceiver for Box {} #[lang = "copy"] pub unsafe trait Copy {} diff --git a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch index 646928893e9..3c81b04c0ea 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch @@ -38,7 +38,7 @@ diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index d9de37e..8293fce 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs -@@ -2996,42 +2996,6 @@ atomic_int! { +@@ -2996,44 +2996,6 @@ atomic_int! { 8, u64 AtomicU64 } @@ -52,7 +52,8 @@ index d9de37e..8293fce 100644 - unstable(feature = "integer_atomics", issue = "99069"), - unstable(feature = "integer_atomics", issue = "99069"), - unstable(feature = "integer_atomics", issue = "99069"), -- rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), +- rustc_const_unstable(feature = "integer_atomics", issue = "99069"), +- rustc_const_unstable(feature = "integer_atomics", issue = "99069"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"), - "i128", - "#![feature(integer_atomics)]\n\n", @@ -70,7 +71,8 @@ index d9de37e..8293fce 100644 - unstable(feature = "integer_atomics", issue = "99069"), - unstable(feature = "integer_atomics", issue = "99069"), - unstable(feature = "integer_atomics", issue = "99069"), -- rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), +- rustc_const_unstable(feature = "integer_atomics", issue = "99069"), +- rustc_const_unstable(feature = "integer_atomics", issue = "99069"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"), - "u128", - "#![feature(integer_atomics)]\n\n", diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index a318cae1722..daea789ee3e 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -79,7 +79,7 @@ pub(super) fn add_local_place_comments<'tcx>( return; } let TyAndLayout { ty, layout } = place.layout(); - let rustc_target::abi::LayoutS { size, align, .. } = layout.0.0; + let rustc_abi::LayoutData { size, align, .. } = layout.0.0; let (kind, extra) = place.debug_comment(); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index f0b78e5d7c6..79d76925df9 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -210,7 +210,6 @@ impl DebugContext { type_names::push_generic_params( tcx, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args), - enclosing_fn_def_id, &mut name, ); diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index f47bfdad131..0576b64ef6f 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -44,12 +44,12 @@ impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} impl, U: ?Sized> DispatchFromDyn> for Box {} -#[lang = "receiver"] -pub trait Receiver {} +#[lang = "legacy_receiver"] +pub trait LegacyReceiver {} -impl Receiver for &T {} -impl Receiver for &mut T {} -impl Receiver for Box {} +impl LegacyReceiver for &T {} +impl LegacyReceiver for &mut T {} +impl LegacyReceiver for Box {} #[lang = "copy"] pub unsafe trait Copy {} diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index b611f9ba8bc..7c52cba096b 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -30,7 +30,7 @@ use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt}; use rustc_span::Span; use rustc_span::def_id::DefId; use rustc_target::abi::call::FnAbi; -use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, WasmCAbi}; +use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, WasmCAbi, X86Abi}; use crate::common::{SignType, TypeReflection, type_is_pointer}; use crate::context::CodegenCx; @@ -1725,16 +1725,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn fptosi_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { self.fptoint_sat(true, val, dest_ty) } - - fn instrprof_increment( - &mut self, - _fn_name: RValue<'gcc>, - _hash: RValue<'gcc>, - _num_counters: RValue<'gcc>, - _index: RValue<'gcc>, - ) { - unimplemented!(); - } } impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { @@ -2347,6 +2337,12 @@ impl<'tcx> HasWasmCAbiOpt for Builder<'_, '_, 'tcx> { } } +impl<'tcx> HasX86AbiOpt for Builder<'_, '_, 'tcx> { + fn x86_abi_opt(&self) -> X86Abi { + self.cx.x86_abi_opt() + } +} + pub trait ToGccComp { fn to_gcc_comparison(&self) -> ComparisonOp; } diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs index 9ad2e90122f..65972a03e83 100644 --- a/compiler/rustc_codegen_gcc/src/callee.rs +++ b/compiler/rustc_codegen_gcc/src/callee.rs @@ -98,8 +98,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) // whether we are sharing generics or not. The important thing here is // that the visibility we apply to the declaration is the same one that // has been applied to the definition (wherever that definition may be). - let is_generic = - instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some(); + let is_generic = instance.args.non_erasable_generics().next().is_some(); if is_generic { // This is a monomorphization. Its expected visibility depends diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 7cb49bf7991..707b35967a6 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -19,7 +19,9 @@ use rustc_session::Session; use rustc_span::source_map::respan; use rustc_span::{DUMMY_SP, Span}; use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; -use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, TlsModel, WasmCAbi}; +use rustc_target::spec::{ + HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi, +}; use crate::callee::get_fn; use crate::common::SignType; @@ -538,6 +540,12 @@ impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> { } } +impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> { + fn x86_abi_opt(&self) -> X86Abi { + X86Abi { regparm: self.tcx.sess.opts.unstable_opts.regparm } + } +} + impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 183e9ddf8bf..db874afe1ab 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -197,7 +197,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`. /// If the type is an unsized struct, the regular layout is generated, - /// with the inner-most trailing unsized field using the "minimal unit" + /// with the innermost trailing unsized field using the "minimal unit" /// of that field's type - this is useful for taking the address of /// that field and ensuring the struct has the right alignment. fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 89f5305840b..55ee6dcdf87 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -77,20 +77,14 @@ pub(crate) unsafe fn codegen( // __rust_alloc_error_handler_should_panic let name = OomStrategy::SYMBOL; let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); - llvm::LLVMRustSetVisibility( - ll_g, - llvm::Visibility::from_generic(tcx.sess.default_visibility()), - ); + llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let val = tcx.sess.opts.unstable_opts.oom.should_panic(); let llval = llvm::LLVMConstInt(i8, val as u64, False); llvm::LLVMSetInitializer(ll_g, llval); let name = NO_ALLOC_SHIM_IS_UNSTABLE; let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); - llvm::LLVMRustSetVisibility( - ll_g, - llvm::Visibility::from_generic(tcx.sess.default_visibility()), - ); + llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let llval = llvm::LLVMConstInt(i8, 0, False); llvm::LLVMSetInitializer(ll_g, llval); } @@ -134,10 +128,7 @@ fn create_wrapper_function( None }; - llvm::LLVMRustSetVisibility( - llfn, - llvm::Visibility::from_generic(tcx.sess.default_visibility()), - ); + llvm::set_visibility(llfn, llvm::Visibility::from_generic(tcx.sess.default_visibility())); if tcx.sess.must_emit_unwind_tables() { let uwtable = @@ -151,7 +142,7 @@ fn create_wrapper_function( // -> ! DIFlagNoReturn attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); } - llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden); + llvm::set_visibility(callee, llvm::Visibility::Hidden); let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr()); diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index afdd2b581b8..bf77fc56d08 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1043,7 +1043,7 @@ unsafe fn embed_bitcode( let section = bitcode_section_name(cgcx); llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); - llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::LLVMSetGlobalConstant(llglobal, llvm::True); let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); @@ -1061,7 +1061,7 @@ unsafe fn embed_bitcode( c".llvmcmd" }; llvm::LLVMSetSection(llglobal, section.as_ptr()); - llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); } else { // We need custom section flags, so emit module-level inline assembly. let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; @@ -1096,7 +1096,7 @@ fn create_msvc_imps( let ptr_ty = Type::ptr_llcx(llcx); let globals = base::iter_globals(llmod) .filter(|&val| { - llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage + llvm::get_linkage(val) == llvm::Linkage::ExternalLinkage && llvm::LLVMIsDeclaration(val) == 0 }) .filter_map(|val| { @@ -1115,7 +1115,7 @@ fn create_msvc_imps( for (imp_name, val) in globals { let imp = llvm::LLVMAddGlobal(llmod, ptr_ty, imp_name.as_ptr()); llvm::LLVMSetInitializer(imp, val); - llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage); + llvm::set_linkage(imp, llvm::Linkage::ExternalLinkage); } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index dbf5298d64b..8702532c36e 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1165,39 +1165,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size); } - fn instrprof_increment( - &mut self, - fn_name: &'ll Value, - hash: &'ll Value, - num_counters: &'ll Value, - index: &'ll Value, - ) { - debug!( - "instrprof_increment() with args ({:?}, {:?}, {:?}, {:?})", - fn_name, hash, num_counters, index - ); - - let llfn = unsafe { llvm::LLVMRustGetInstrProfIncrementIntrinsic(self.cx().llmod) }; - let llty = self.cx.type_func( - &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_i32()], - self.cx.type_void(), - ); - let args = &[fn_name, hash, num_counters, index]; - let args = self.check_call("call", llty, llfn, args); - - unsafe { - let _ = llvm::LLVMRustBuildCall( - self.llbuilder, - llty, - llfn, - args.as_ptr() as *const &llvm::Value, - args.len() as c_uint, - [].as_ptr(), - 0 as c_uint, - ); - } - } - fn call( &mut self, llty: &'ll Type, @@ -1667,6 +1634,18 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { kcfi_bundle } + /// Emits a call to `llvm.instrprof.increment`. Used by coverage instrumentation. + #[instrument(level = "debug", skip(self))] + pub(crate) fn instrprof_increment( + &mut self, + fn_name: &'ll Value, + hash: &'ll Value, + num_counters: &'ll Value, + index: &'ll Value, + ) { + self.call_intrinsic("llvm.instrprof.increment", &[fn_name, hash, num_counters, index]); + } + /// Emits a call to `llvm.instrprof.mcdc.parameters`. /// /// This doesn't produce any code directly, but is used as input by @@ -1676,40 +1655,21 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { /// /// [`CodeGenPGO::emitMCDCParameters`]: /// https://github.com/rust-lang/llvm-project/blob/5399a24/clang/lib/CodeGen/CodeGenPGO.cpp#L1124 + #[instrument(level = "debug", skip(self))] pub(crate) fn mcdc_parameters( &mut self, fn_name: &'ll Value, hash: &'ll Value, bitmap_bits: &'ll Value, ) { - debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bits); - assert!( crate::llvm_util::get_version() >= (19, 0, 0), "MCDC intrinsics require LLVM 19 or later" ); - - let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCParametersIntrinsic(self.cx().llmod) }; - let llty = self.cx.type_func( - &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32()], - self.cx.type_void(), - ); - let args = &[fn_name, hash, bitmap_bits]; - let args = self.check_call("call", llty, llfn, args); - - unsafe { - let _ = llvm::LLVMRustBuildCall( - self.llbuilder, - llty, - llfn, - args.as_ptr() as *const &llvm::Value, - args.len() as c_uint, - [].as_ptr(), - 0 as c_uint, - ); - } + self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[fn_name, hash, bitmap_bits]); } + #[instrument(level = "debug", skip(self))] pub(crate) fn mcdc_tvbitmap_update( &mut self, fn_name: &'ll Value, @@ -1717,39 +1677,21 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { bitmap_index: &'ll Value, mcdc_temp: &'ll Value, ) { - debug!( - "mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?})", - fn_name, hash, bitmap_index, mcdc_temp - ); assert!( crate::llvm_util::get_version() >= (19, 0, 0), "MCDC intrinsics require LLVM 19 or later" ); - - let llfn = - unsafe { llvm::LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(self.cx().llmod) }; - let llty = self.cx.type_func( - &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_ptr()], - self.cx.type_void(), - ); let args = &[fn_name, hash, bitmap_index, mcdc_temp]; - let args = self.check_call("call", llty, llfn, args); - unsafe { - let _ = llvm::LLVMRustBuildCall( - self.llbuilder, - llty, - llfn, - args.as_ptr() as *const &llvm::Value, - args.len() as c_uint, - [].as_ptr(), - 0 as c_uint, - ); - } + self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", args); + } + + #[instrument(level = "debug", skip(self))] + pub(crate) fn mcdc_condbitmap_reset(&mut self, mcdc_temp: &'ll Value) { self.store(self.const_i32(0), mcdc_temp, self.tcx.data_layout.i32_align.abi); } + #[instrument(level = "debug", skip(self))] pub(crate) fn mcdc_condbitmap_update(&mut self, cond_index: &'ll Value, mcdc_temp: &'ll Value) { - debug!("mcdc_condbitmap_update() with args ({:?}, {:?})", cond_index, mcdc_temp); assert!( crate::llvm_util::get_version() >= (19, 0, 0), "MCDC intrinsics require LLVM 19 or later" diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 206a7069792..25037b97375 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -95,11 +95,10 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t // whether we are sharing generics or not. The important thing here is // that the visibility we apply to the declaration is the same one that // has been applied to the definition (wherever that definition may be). - unsafe { - llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); - let is_generic = - instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some(); + llvm::set_linkage(llfn, llvm::Linkage::ExternalLinkage); + unsafe { + let is_generic = instance.args.non_erasable_generics().next().is_some(); let is_hidden = if is_generic { // This is a monomorphization of a generic function. @@ -136,7 +135,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t || !cx.tcx.is_reachable_non_generic(instance_def_id)) }; if is_hidden { - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + llvm::set_visibility(llfn, llvm::Visibility::Hidden); } // MinGW: For backward compatibility we rely on the linker to decide whether it diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 0ced37b53a8..ff47eb944dd 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -219,8 +219,8 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); - llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage); } + llvm::set_linkage(g, llvm::Linkage::InternalLinkage); (s.to_owned(), g) }) .1; diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 33a85adeb87..1e3abcfd1af 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -172,29 +172,27 @@ fn check_and_apply_linkage<'ll, 'tcx>( if let Some(linkage) = attrs.import_linkage { debug!("get_static: sym={} linkage={:?}", sym, linkage); - unsafe { - // Declare a symbol `foo` with the desired linkage. - let g1 = cx.declare_global(sym, cx.type_i8()); - llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage)); + // Declare a symbol `foo` with the desired linkage. + let g1 = cx.declare_global(sym, cx.type_i8()); + llvm::set_linkage(g1, base::linkage_to_llvm(linkage)); - // Declare an internal global `extern_with_linkage_foo` which - // is initialized with the address of `foo`. If `foo` is - // discarded during linking (for example, if `foo` has weak - // linkage and there are no definitions), then - // `extern_with_linkage_foo` will instead be initialized to - // zero. - let mut real_name = "_rust_extern_with_linkage_".to_string(); - real_name.push_str(sym); - let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| { - cx.sess().dcx().emit_fatal(SymbolAlreadyDefined { - span: cx.tcx.def_span(def_id), - symbol_name: sym, - }) - }); - llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage); - llvm::LLVMSetInitializer(g2, g1); - g2 - } + // Declare an internal global `extern_with_linkage_foo` which + // is initialized with the address of `foo`. If `foo` is + // discarded during linking (for example, if `foo` has weak + // linkage and there are no definitions), then + // `extern_with_linkage_foo` will instead be initialized to + // zero. + let mut real_name = "_rust_extern_with_linkage_".to_string(); + real_name.push_str(sym); + let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| { + cx.sess().dcx().emit_fatal(SymbolAlreadyDefined { + span: cx.tcx.def_span(def_id), + symbol_name: sym, + }) + }); + llvm::set_linkage(g2, llvm::Linkage::InternalLinkage); + unsafe { llvm::LLVMSetInitializer(g2, g1) }; + g2 } else if cx.tcx.sess.target.arch == "x86" && let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym) { @@ -224,23 +222,21 @@ impl<'ll> CodegenCx<'ll, '_> { align: Align, kind: Option<&str>, ) -> &'ll Value { - unsafe { - let gv = match kind { - Some(kind) if !self.tcx.sess.fewer_names() => { - let name = self.generate_local_symbol_name(kind); - let gv = self.define_global(&name, self.val_ty(cv)).unwrap_or_else(|| { - bug!("symbol `{}` is already defined", name); - }); - llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage); - gv - } - _ => self.define_private_global(self.val_ty(cv)), - }; - llvm::LLVMSetInitializer(gv, cv); - set_global_alignment(self, gv, align); - llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global); - gv - } + let gv = match kind { + Some(kind) if !self.tcx.sess.fewer_names() => { + let name = self.generate_local_symbol_name(kind); + let gv = self.define_global(&name, self.val_ty(cv)).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", name); + }); + llvm::set_linkage(gv, llvm::Linkage::PrivateLinkage); + gv + } + _ => self.define_private_global(self.val_ty(cv)), + }; + unsafe { llvm::LLVMSetInitializer(gv, cv) }; + set_global_alignment(self, gv, align); + llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global); + gv } #[instrument(level = "debug", skip(self))] @@ -292,9 +288,7 @@ impl<'ll> CodegenCx<'ll, '_> { let g = self.declare_global(sym, llty); if !self.tcx.is_reachable_non_generic(def_id) { - unsafe { - llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden); - } + llvm::set_visibility(g, llvm::Visibility::Hidden); } g @@ -312,7 +306,7 @@ impl<'ll> CodegenCx<'ll, '_> { llvm::set_thread_local_mode(g, self.tls_model); } - let dso_local = unsafe { self.should_assume_dso_local(g, true) }; + let dso_local = self.should_assume_dso_local(g, true); if dso_local { unsafe { llvm::LLVMRustSetDSOLocal(g, true); @@ -401,8 +395,8 @@ impl<'ll> CodegenCx<'ll, '_> { let name = llvm::get_value_name(g).to_vec(); llvm::set_value_name(g, b""); - let linkage = llvm::LLVMRustGetLinkage(g); - let visibility = llvm::LLVMRustGetVisibility(g); + let linkage = llvm::get_linkage(g); + let visibility = llvm::get_visibility(g); let new_g = llvm::LLVMRustGetOrInsertGlobal( self.llmod, @@ -411,8 +405,8 @@ impl<'ll> CodegenCx<'ll, '_> { val_llty, ); - llvm::LLVMRustSetLinkage(new_g, linkage); - llvm::LLVMRustSetVisibility(new_g, visibility); + llvm::set_linkage(new_g, linkage); + llvm::set_visibility(new_g, visibility); // The old global has had its name removed but is returned by // get_static since it is in the instance cache. Provide an diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 2f830d6f941..067028a16ff 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -80,6 +80,7 @@ pub(crate) struct CodegenCx<'ll, 'tcx> { pub isize_ty: &'ll Type, + /// Extra codegen state needed when coverage instrumentation is enabled. pub coverage_cx: Option>, pub dbg_cx: Option>, @@ -592,11 +593,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { &self.statics_to_rauw } + /// Extra state that is only available when coverage instrumentation is enabled. #[inline] - pub(crate) fn coverage_context( - &self, - ) -> Option<&coverageinfo::CrateCoverageContext<'ll, 'tcx>> { - self.coverage_cx.as_ref() + pub(crate) fn coverage_cx(&self) -> &coverageinfo::CrateCoverageContext<'ll, 'tcx> { + self.coverage_cx.as_ref().expect("only called when coverage instrumentation is enabled") } pub(crate) fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) { @@ -605,7 +605,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { unsafe { let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr()); llvm::LLVMSetInitializer(g, array); - llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage); + llvm::set_linkage(g, llvm::Linkage::AppendingLinkage); llvm::LLVMSetSection(g, c"llvm.metadata".as_ptr()); } } @@ -1099,6 +1099,10 @@ impl<'ll> CodegenCx<'ll, '_> { if self.sess().instrument_coverage() { ifn!("llvm.instrprof.increment", fn(ptr, t_i64, t_i32, t_i32) -> void); + if crate::llvm_util::get_version() >= (19, 0, 0) { + ifn!("llvm.instrprof.mcdc.parameters", fn(ptr, t_i64, t_i32) -> void); + ifn!("llvm.instrprof.mcdc.tvbitmap.update", fn(ptr, t_i64, t_i32, ptr) -> void); + } } ifn!("llvm.type.test", fn(ptr, t_metadata) -> i1); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index 90f7dd733ca..feac97f3e2b 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -1,11 +1,9 @@ -use rustc_middle::mir::coverage::{ - ConditionInfo, CounterId, CovTerm, DecisionInfo, ExpressionId, MappingKind, SourceRegion, -}; +use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId, SourceRegion}; /// Must match the layout of `LLVMRustCounterKind`. #[derive(Copy, Clone, Debug)] #[repr(C)] -pub enum CounterKind { +pub(crate) enum CounterKind { Zero = 0, CounterValueReference = 1, Expression = 2, @@ -25,9 +23,9 @@ pub enum CounterKind { /// Must match the layout of `LLVMRustCounter`. #[derive(Copy, Clone, Debug)] #[repr(C)] -pub struct Counter { +pub(crate) struct Counter { // Important: The layout (order and types of fields) must match its C++ counterpart. - pub kind: CounterKind, + pub(crate) kind: CounterKind, id: u32, } @@ -36,7 +34,7 @@ impl Counter { pub(crate) const ZERO: Self = Self { kind: CounterKind::Zero, id: 0 }; /// Constructs a new `Counter` of kind `CounterValueReference`. - pub fn counter_value_reference(counter_id: CounterId) -> Self { + pub(crate) fn counter_value_reference(counter_id: CounterId) -> Self { Self { kind: CounterKind::CounterValueReference, id: counter_id.as_u32() } } @@ -59,7 +57,7 @@ impl Counter { /// Must match the layout of `LLVMRustCounterExprKind`. #[derive(Copy, Clone, Debug)] #[repr(C)] -pub enum ExprKind { +pub(crate) enum ExprKind { Subtract = 0, Add = 1, } @@ -69,48 +67,13 @@ pub enum ExprKind { /// Must match the layout of `LLVMRustCounterExpression`. #[derive(Copy, Clone, Debug)] #[repr(C)] -pub struct CounterExpression { - pub kind: ExprKind, - pub lhs: Counter, - pub rhs: Counter, +pub(crate) struct CounterExpression { + pub(crate) kind: ExprKind, + pub(crate) lhs: Counter, + pub(crate) rhs: Counter, } -/// Corresponds to enum `llvm::coverage::CounterMappingRegion::RegionKind`. -/// -/// Must match the layout of `LLVMRustCounterMappingRegionKind`. -#[derive(Copy, Clone, Debug)] -#[repr(C)] -enum RegionKind { - /// A CodeRegion associates some code with a counter - CodeRegion = 0, - - /// An ExpansionRegion represents a file expansion region that associates - /// a source range with the expansion of a virtual source file, such as - /// for a macro instantiation or #include file. - ExpansionRegion = 1, - - /// A SkippedRegion represents a source range with code that was skipped - /// by a preprocessor or similar means. - SkippedRegion = 2, - - /// A GapRegion is like a CodeRegion, but its count is only set as the - /// line execution count when its the only region in the line. - GapRegion = 3, - - /// A BranchRegion represents leaf-level boolean expressions and is - /// associated with two counters, each representing the number of times the - /// expression evaluates to true or false. - BranchRegion = 4, - - /// A DecisionRegion represents a top-level boolean expression and is - /// associated with a variable length bitmap index and condition number. - MCDCDecisionRegion = 5, - - /// A Branch Region can be extended to include IDs to facilitate MC/DC. - MCDCBranchRegion = 6, -} - -mod mcdc { +pub(crate) mod mcdc { use rustc_middle::mir::coverage::{ConditionId, ConditionInfo, DecisionInfo}; /// Must match the layout of `LLVMRustMCDCDecisionParameters`. @@ -121,8 +84,6 @@ mod mcdc { num_conditions: u16, } - // ConditionId in llvm is `unsigned int` at 18 while `int16_t` at - // [19](https://github.com/llvm/llvm-project/pull/81257). type LLVMConditionId = i16; /// Must match the layout of `LLVMRustMCDCBranchParameters`. @@ -133,38 +94,6 @@ mod mcdc { condition_ids: [LLVMConditionId; 2], } - #[repr(C)] - #[derive(Clone, Copy, Debug)] - enum ParameterTag { - None = 0, - Decision = 1, - Branch = 2, - } - /// Same layout with `LLVMRustMCDCParameters` - #[repr(C)] - #[derive(Clone, Copy, Debug)] - pub(crate) struct Parameters { - tag: ParameterTag, - decision_params: DecisionParameters, - branch_params: BranchParameters, - } - - impl Parameters { - pub(crate) fn none() -> Self { - Self { - tag: ParameterTag::None, - decision_params: Default::default(), - branch_params: Default::default(), - } - } - pub(crate) fn decision(decision_params: DecisionParameters) -> Self { - Self { tag: ParameterTag::Decision, decision_params, branch_params: Default::default() } - } - pub(crate) fn branch(branch_params: BranchParameters) -> Self { - Self { tag: ParameterTag::Branch, decision_params: Default::default(), branch_params } - } - } - impl From for BranchParameters { fn from(value: ConditionInfo) -> Self { let to_llvm_cond_id = |cond_id: Option| { @@ -186,267 +115,68 @@ mod mcdc { } } -/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the -/// coverage map, in accordance with the -/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). -/// The struct composes fields representing the `Counter` type and value(s) (injected counter -/// ID, or expression type and operands), the source file (an indirect index into a "filenames -/// array", encoded separately), and source location (start and end positions of the represented -/// code region). +/// A span of source code coordinates to be embedded in coverage metadata. /// -/// Corresponds to struct `llvm::coverage::CounterMappingRegion`. -/// -/// Must match the layout of `LLVMRustCounterMappingRegion`. -#[derive(Copy, Clone, Debug)] +/// Must match the layout of `LLVMRustCoverageSpan`. +#[derive(Clone, Debug)] #[repr(C)] -pub struct CounterMappingRegion { - /// The counter type and type-dependent counter data, if any. - counter: Counter, - - /// If the `RegionKind` is a `BranchRegion`, this represents the counter - /// for the false branch of the region. - false_counter: Counter, - - mcdc_params: mcdc::Parameters, - /// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the - /// file_id is an index into a function-specific `virtual_file_mapping` array of indexes - /// that, in turn, are used to look up the filename for this region. +pub(crate) struct CoverageSpan { + /// Local index into the function's local-to-global file ID table. + /// The value at that index is itself an index into the coverage filename + /// table in the CGU's `__llvm_covmap` section. file_id: u32, - /// If the `RegionKind` is an `ExpansionRegion`, the `expanded_file_id` can be used to find - /// the mapping regions created as a result of macro expansion, by checking if their file id - /// matches the expanded file id. - expanded_file_id: u32, - - /// 1-based starting line of the mapping region. + /// 1-based starting line of the source code span. start_line: u32, - - /// 1-based starting column of the mapping region. + /// 1-based starting column of the source code span. start_col: u32, - - /// 1-based ending line of the mapping region. + /// 1-based ending line of the source code span. end_line: u32, - - /// 1-based ending column of the mapping region. If the high bit is set, the current - /// mapping region is a gap area. + /// 1-based ending column of the source code span. High bit must be unset. end_col: u32, - - kind: RegionKind, } -impl CounterMappingRegion { - pub(crate) fn from_mapping( - mapping_kind: &MappingKind, - local_file_id: u32, - source_region: &SourceRegion, - ) -> Self { - let &SourceRegion { file_name: _, start_line, start_col, end_line, end_col } = - source_region; - match *mapping_kind { - MappingKind::Code(term) => Self::code_region( - Counter::from_term(term), - local_file_id, - start_line, - start_col, - end_line, - end_col, - ), - MappingKind::Branch { true_term, false_term } => Self::branch_region( - Counter::from_term(true_term), - Counter::from_term(false_term), - local_file_id, - start_line, - start_col, - end_line, - end_col, - ), - MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => { - Self::mcdc_branch_region( - Counter::from_term(true_term), - Counter::from_term(false_term), - mcdc_params, - local_file_id, - start_line, - start_col, - end_line, - end_col, - ) - } - MappingKind::MCDCDecision(decision_info) => Self::decision_region( - decision_info, - local_file_id, - start_line, - start_col, - end_line, - end_col, - ), - } - } - - pub(crate) fn code_region( - counter: Counter, - file_id: u32, - start_line: u32, - start_col: u32, - end_line: u32, - end_col: u32, - ) -> Self { - Self { - counter, - false_counter: Counter::ZERO, - mcdc_params: mcdc::Parameters::none(), - file_id, - expanded_file_id: 0, - start_line, - start_col, - end_line, - end_col, - kind: RegionKind::CodeRegion, - } - } - - pub(crate) fn branch_region( - counter: Counter, - false_counter: Counter, - file_id: u32, - start_line: u32, - start_col: u32, - end_line: u32, - end_col: u32, - ) -> Self { - Self { - counter, - false_counter, - mcdc_params: mcdc::Parameters::none(), - file_id, - expanded_file_id: 0, - start_line, - start_col, - end_line, - end_col, - kind: RegionKind::BranchRegion, - } - } - - pub(crate) fn mcdc_branch_region( - counter: Counter, - false_counter: Counter, - condition_info: ConditionInfo, - file_id: u32, - start_line: u32, - start_col: u32, - end_line: u32, - end_col: u32, - ) -> Self { - Self { - counter, - false_counter, - mcdc_params: mcdc::Parameters::branch(condition_info.into()), - file_id, - expanded_file_id: 0, - start_line, - start_col, - end_line, - end_col, - kind: RegionKind::MCDCBranchRegion, - } - } - - pub(crate) fn decision_region( - decision_info: DecisionInfo, - file_id: u32, - start_line: u32, - start_col: u32, - end_line: u32, - end_col: u32, - ) -> Self { - let mcdc_params = mcdc::Parameters::decision(decision_info.into()); - - Self { - counter: Counter::ZERO, - false_counter: Counter::ZERO, - mcdc_params, - file_id, - expanded_file_id: 0, - start_line, - start_col, - end_line, - end_col, - kind: RegionKind::MCDCDecisionRegion, - } - } - - // This function might be used in the future; the LLVM API is still evolving, as is coverage - // support. - #[allow(dead_code)] - pub(crate) fn expansion_region( - file_id: u32, - expanded_file_id: u32, - start_line: u32, - start_col: u32, - end_line: u32, - end_col: u32, - ) -> Self { - Self { - counter: Counter::ZERO, - false_counter: Counter::ZERO, - mcdc_params: mcdc::Parameters::none(), - file_id, - expanded_file_id, - start_line, - start_col, - end_line, - end_col, - kind: RegionKind::ExpansionRegion, - } - } - - // This function might be used in the future; the LLVM API is still evolving, as is coverage - // support. - #[allow(dead_code)] - pub(crate) fn skipped_region( - file_id: u32, - start_line: u32, - start_col: u32, - end_line: u32, - end_col: u32, - ) -> Self { - Self { - counter: Counter::ZERO, - false_counter: Counter::ZERO, - mcdc_params: mcdc::Parameters::none(), - file_id, - expanded_file_id: 0, - start_line, - start_col, - end_line, - end_col, - kind: RegionKind::SkippedRegion, - } - } - - // This function might be used in the future; the LLVM API is still evolving, as is coverage - // support. - #[allow(dead_code)] - pub(crate) fn gap_region( - counter: Counter, - file_id: u32, - start_line: u32, - start_col: u32, - end_line: u32, - end_col: u32, - ) -> Self { - Self { - counter, - false_counter: Counter::ZERO, - mcdc_params: mcdc::Parameters::none(), - file_id, - expanded_file_id: 0, - start_line, - start_col, - end_line, - end_col: (1_u32 << 31) | end_col, - kind: RegionKind::GapRegion, - } +impl CoverageSpan { + pub(crate) fn from_source_region(file_id: u32, code_region: &SourceRegion) -> Self { + let &SourceRegion { file_name: _, start_line, start_col, end_line, end_col } = code_region; + // Internally, LLVM uses the high bit of `end_col` to distinguish between + // code regions and gap regions, so it can't be used by the column number. + assert!(end_col & (1u32 << 31) == 0, "high bit of `end_col` must be unset: {end_col:#X}"); + Self { file_id, start_line, start_col, end_line, end_col } } } + +/// Must match the layout of `LLVMRustCoverageCodeRegion`. +#[derive(Clone, Debug)] +#[repr(C)] +pub(crate) struct CodeRegion { + pub(crate) span: CoverageSpan, + pub(crate) counter: Counter, +} + +/// Must match the layout of `LLVMRustCoverageBranchRegion`. +#[derive(Clone, Debug)] +#[repr(C)] +pub(crate) struct BranchRegion { + pub(crate) span: CoverageSpan, + pub(crate) true_counter: Counter, + pub(crate) false_counter: Counter, +} + +/// Must match the layout of `LLVMRustCoverageMCDCBranchRegion`. +#[derive(Clone, Debug)] +#[repr(C)] +pub(crate) struct MCDCBranchRegion { + pub(crate) span: CoverageSpan, + pub(crate) true_counter: Counter, + pub(crate) false_counter: Counter, + pub(crate) mcdc_branch_params: mcdc::BranchParameters, +} + +/// Must match the layout of `LLVMRustCoverageMCDCDecisionRegion`. +#[derive(Clone, Debug)] +#[repr(C)] +pub(crate) struct MCDCDecisionRegion { + pub(crate) span: CoverageSpan, + pub(crate) mcdc_decision_params: mcdc::DecisionParameters, +} diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index cee704a9c22..8edd788ee36 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -1,18 +1,23 @@ -use std::ffi::CStr; +use std::ffi::CString; use itertools::Itertools as _; -use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods}; +use rustc_abi::Align; +use rustc_codegen_ssa::traits::{ + BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods, +}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::IndexVec; +use rustc_middle::mir::coverage::MappingKind; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::Symbol; use rustc_span::def_id::DefIdSet; +use rustc_target::spec::HasTargetSpec; use tracing::debug; use crate::common::CodegenCx; -use crate::coverageinfo::ffi::CounterMappingRegion; +use crate::coverageinfo::ffi; use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector}; use crate::{coverageinfo, llvm}; @@ -49,11 +54,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { add_unused_functions(cx); } - let function_coverage_map = match cx.coverage_context() { - Some(ctx) => ctx.take_function_coverage_map(), - None => return, - }; - + let function_coverage_map = cx.coverage_cx().take_function_coverage_map(); if function_coverage_map.is_empty() { // This module has no functions with coverage instrumentation return; @@ -77,11 +78,9 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { // Generate the coverage map header, which contains the filenames used by // this CGU's coverage mappings, and store it in a well-known global. - let cov_data_val = generate_coverage_map(cx, covmap_version, filenames_size, filenames_val); - coverageinfo::save_cov_data_to_mod(cx, cov_data_val); + generate_covmap_record(cx, covmap_version, filenames_size, filenames_val); let mut unused_function_names = Vec::new(); - let covfun_section_name = coverageinfo::covfun_section_name(cx); // Encode coverage mappings and generate function records for (instance, function_coverage) in function_coverage_entries { @@ -110,9 +109,8 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { unused_function_names.push(mangled_function_name); } - save_function_record( + generate_covfun_record( cx, - &covfun_section_name, mangled_function_name, source_hash, filenames_ref, @@ -237,7 +235,10 @@ fn encode_mappings_for_function( let expressions = function_coverage.counter_expressions().collect::>(); let mut virtual_file_mapping = VirtualFileMapping::default(); - let mut mapping_regions = Vec::with_capacity(counter_regions.len()); + let mut code_regions = vec![]; + let mut branch_regions = vec![]; + let mut mcdc_branch_regions = vec![]; + let mut mcdc_decision_regions = vec![]; // Group mappings into runs with the same filename, preserving the order // yielded by `FunctionCoverage`. @@ -257,11 +258,36 @@ fn encode_mappings_for_function( // form suitable for FFI. for (mapping_kind, region) in counter_regions_for_file { debug!("Adding counter {mapping_kind:?} to map for {region:?}"); - mapping_regions.push(CounterMappingRegion::from_mapping( - &mapping_kind, - local_file_id.as_u32(), - region, - )); + let span = ffi::CoverageSpan::from_source_region(local_file_id.as_u32(), region); + match mapping_kind { + MappingKind::Code(term) => { + code_regions + .push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) }); + } + MappingKind::Branch { true_term, false_term } => { + branch_regions.push(ffi::BranchRegion { + span, + true_counter: ffi::Counter::from_term(true_term), + false_counter: ffi::Counter::from_term(false_term), + }); + } + MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => { + mcdc_branch_regions.push(ffi::MCDCBranchRegion { + span, + true_counter: ffi::Counter::from_term(true_term), + false_counter: ffi::Counter::from_term(false_term), + mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params), + }); + } + MappingKind::MCDCDecision(mcdc_decision_params) => { + mcdc_decision_regions.push(ffi::MCDCDecisionRegion { + span, + mcdc_decision_params: ffi::mcdc::DecisionParameters::from( + mcdc_decision_params, + ), + }); + } + } } } @@ -270,21 +296,24 @@ fn encode_mappings_for_function( coverageinfo::write_mapping_to_buffer( virtual_file_mapping.into_vec(), expressions, - mapping_regions, + &code_regions, + &branch_regions, + &mcdc_branch_regions, + &mcdc_decision_regions, buffer, ); }) } -/// Construct coverage map header and the array of function records, and combine them into the -/// coverage map. Save the coverage map data into the LLVM IR as a static global using a -/// specific, well-known section and name. -fn generate_coverage_map<'ll>( +/// Generates the contents of the covmap record for this CGU, which mostly +/// consists of a header and a list of filenames. The record is then stored +/// as a global variable in the `__llvm_covmap` section. +fn generate_covmap_record<'ll>( cx: &CodegenCx<'ll, '_>, version: u32, filenames_size: usize, filenames_val: &'ll llvm::Value, -) -> &'ll llvm::Value { +) { debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version); // Create the coverage data header (Note, fields 0 and 2 are now always zero, @@ -299,15 +328,37 @@ fn generate_coverage_map<'ll>( ); // Create the complete LLVM coverage data value to add to the LLVM IR - cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false) + let covmap_data = + cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false); + + let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe { + llvm::LLVMRustCoverageWriteMappingVarNameToString(s); + })) + .unwrap(); + debug!("covmap var name: {:?}", covmap_var_name); + + let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe { + llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s); + })) + .expect("covmap section name should not contain NUL"); + debug!("covmap section name: {:?}", covmap_section_name); + + let llglobal = llvm::add_global(cx.llmod, cx.val_ty(covmap_data), &covmap_var_name); + llvm::set_initializer(llglobal, covmap_data); + llvm::set_global_constant(llglobal, true); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::set_section(llglobal, &covmap_section_name); + // LLVM's coverage mapping format specifies 8-byte alignment for items in this section. + // + llvm::set_alignment(llglobal, Align::EIGHT); + cx.add_used_global(llglobal); } -/// Construct a function record and combine it with the function's coverage mapping data. -/// Save the function record into the LLVM IR as a static global using a -/// specific, well-known section and name. -fn save_function_record( +/// Generates the contents of the covfun record for this function, which +/// contains the function's coverage mapping data. The record is then stored +/// as a global variable in the `__llvm_covfun` section. +fn generate_covfun_record( cx: &CodegenCx<'_, '_>, - covfun_section_name: &CStr, mangled_function_name: &str, source_hash: u64, filenames_ref: u64, @@ -334,13 +385,28 @@ fn save_function_record( /*packed=*/ true, ); - coverageinfo::save_func_record_to_mod( - cx, - covfun_section_name, - func_name_hash, - func_record_val, - is_used, - ); + // Choose a variable name to hold this function's covfun data. + // Functions that are used have a suffix ("u") to distinguish them from + // unused copies of the same function (from different CGUs), so that if a + // linker sees both it won't discard the used copy's data. + let func_record_var_name = + CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" })) + .unwrap(); + debug!("function record var name: {:?}", func_record_var_name); + + let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name); + llvm::set_initializer(llglobal, func_record_val); + llvm::set_global_constant(llglobal, true); + llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage); + llvm::set_visibility(llglobal, llvm::Visibility::Hidden); + llvm::set_section(llglobal, cx.covfun_section_name()); + // LLVM's coverage mapping format specifies 8-byte alignment for items in this section. + // + llvm::set_alignment(llglobal, Align::EIGHT); + if cx.target_spec().supports_comdat() { + llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name); + } + cx.add_used_global(llglobal); } /// Each CGU will normally only emit coverage metadata for the functions that it actually generates. @@ -472,9 +538,5 @@ fn add_unused_function_coverage<'tcx>( // zero, because none of its counters/expressions are marked as seen. let function_coverage = FunctionCoverageCollector::unused(instance, function_coverage_info); - if let Some(coverage_context) = cx.coverage_context() { - coverage_context.function_coverage_map.borrow_mut().insert(instance, function_coverage); - } else { - bug!("Could not get the `coverage_context`"); - } + cx.coverage_cx().function_coverage_map.borrow_mut().insert(instance, function_coverage); } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 484a4d00c13..c6b2a623ea6 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -1,24 +1,20 @@ -use std::cell::RefCell; +use std::cell::{OnceCell, RefCell}; use std::ffi::{CStr, CString}; use libc::c_uint; use rustc_codegen_ssa::traits::{ - BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, - MiscCodegenMethods, StaticCodegenMethods, + BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods, }; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_llvm::RustString; -use rustc_middle::bug; use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::ty::Instance; use rustc_middle::ty::layout::HasTyCtxt; -use rustc_target::abi::{Align, Size}; -use rustc_target::spec::HasTargetSpec; +use rustc_target::abi::Size; use tracing::{debug, instrument}; use crate::builder::Builder; use crate::common::CodegenCx; -use crate::coverageinfo::ffi::{CounterExpression, CounterMappingRegion}; use crate::coverageinfo::map_data::FunctionCoverageCollector; use crate::llvm; @@ -33,6 +29,8 @@ pub(crate) struct CrateCoverageContext<'ll, 'tcx> { RefCell, FunctionCoverageCollector<'tcx>>>, pub(crate) pgo_func_name_var_map: RefCell, &'ll llvm::Value>>, pub(crate) mcdc_condition_bitmap_map: RefCell, Vec<&'ll llvm::Value>>>, + + covfun_section_name: OnceCell, } impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> { @@ -41,6 +39,7 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> { function_coverage_map: Default::default(), pgo_func_name_var_map: Default::default(), mcdc_condition_bitmap_map: Default::default(), + covfun_section_name: Default::default(), } } @@ -67,27 +66,38 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> { } } -// These methods used to be part of trait `CoverageInfoMethods`, which no longer -// exists after most coverage code was moved out of SSA. impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { pub(crate) fn coverageinfo_finalize(&self) { mapgen::finalize(self) } + /// Returns the section name to use when embedding per-function coverage information + /// in the object file, according to the target's object file format. LLVM's coverage + /// tools use information from this section when producing coverage reports. + /// + /// Typical values are: + /// - `__llvm_covfun` on Linux + /// - `__LLVM_COV,__llvm_covfun` on macOS (includes `__LLVM_COV,` segment prefix) + /// - `.lcovfun$M` on Windows (includes `$M` sorting suffix) + fn covfun_section_name(&self) -> &CStr { + self.coverage_cx().covfun_section_name.get_or_init(|| { + CString::new(llvm::build_byte_buffer(|s| unsafe { + llvm::LLVMRustCoverageWriteFuncSectionNameToString(self.llmod, s); + })) + .expect("covfun section name should not contain NUL") + }) + } + /// For LLVM codegen, returns a function-specific `Value` for a global /// string, to hold the function name passed to LLVM intrinsic /// `instrprof.increment()`. The `Value` is only created once per instance. /// Multiple invocations with the same instance return the same `Value`. fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value { - if let Some(coverage_context) = self.coverage_context() { - debug!("getting pgo_func_name_var for instance={:?}", instance); - let mut pgo_func_name_var_map = coverage_context.pgo_func_name_var_map.borrow_mut(); - pgo_func_name_var_map - .entry(instance) - .or_insert_with(|| create_pgo_func_name_var(self, instance)) - } else { - bug!("Could not get the `coverage_context`"); - } + debug!("getting pgo_func_name_var for instance={:?}", instance); + let mut pgo_func_name_var_map = self.coverage_cx().pgo_func_name_var_map.borrow_mut(); + pgo_func_name_var_map + .entry(instance) + .or_insert_with(|| create_pgo_func_name_var(self, instance)) } } @@ -121,11 +131,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { cond_bitmaps.push(cond_bitmap); } - self.coverage_context() - .expect("always present when coverage is enabled") - .mcdc_condition_bitmap_map - .borrow_mut() - .insert(instance, cond_bitmaps); + self.coverage_cx().mcdc_condition_bitmap_map.borrow_mut().insert(instance, cond_bitmaps); } #[instrument(level = "debug", skip(self))] @@ -146,8 +152,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { return; }; - let Some(coverage_context) = bx.coverage_context() else { return }; - let mut coverage_map = coverage_context.function_coverage_map.borrow_mut(); + let mut coverage_map = bx.coverage_cx().function_coverage_map.borrow_mut(); let func_coverage = coverage_map .entry(instance) .or_insert_with(|| FunctionCoverageCollector::new(instance, function_coverage_info)); @@ -189,7 +194,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { } CoverageKind::CondBitmapUpdate { index, decision_depth } => { drop(coverage_map); - let cond_bitmap = coverage_context + let cond_bitmap = bx + .coverage_cx() .try_get_mcdc_condition_bitmap(&instance, decision_depth) .expect("mcdc cond bitmap should have been allocated for updating"); let cond_index = bx.const_i32(index as i32); @@ -197,7 +203,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { } CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => { drop(coverage_map); - let cond_bitmap = coverage_context + let cond_bitmap = bx.coverage_cx() .try_get_mcdc_condition_bitmap(&instance, decision_depth) .expect("mcdc cond bitmap should have been allocated for merging into the global bitmap"); assert!( @@ -209,6 +215,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { let hash = bx.const_u64(function_coverage_info.function_source_hash); let bitmap_index = bx.const_u32(bitmap_idx); bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap); + bx.mcdc_condbitmap_reset(cond_bitmap); } } } @@ -257,8 +264,11 @@ pub(crate) fn write_filenames_section_to_buffer<'a>( pub(crate) fn write_mapping_to_buffer( virtual_file_mapping: Vec, - expressions: Vec, - mapping_regions: Vec, + expressions: Vec, + code_regions: &[ffi::CodeRegion], + branch_regions: &[ffi::BranchRegion], + mcdc_branch_regions: &[ffi::MCDCBranchRegion], + mcdc_decision_regions: &[ffi::MCDCDecisionRegion], buffer: &RustString, ) { unsafe { @@ -267,8 +277,14 @@ pub(crate) fn write_mapping_to_buffer( virtual_file_mapping.len() as c_uint, expressions.as_ptr(), expressions.len() as c_uint, - mapping_regions.as_ptr(), - mapping_regions.len() as c_uint, + code_regions.as_ptr(), + code_regions.len() as c_uint, + branch_regions.as_ptr(), + branch_regions.len() as c_uint, + mcdc_branch_regions.as_ptr(), + mcdc_branch_regions.len() as c_uint, + mcdc_decision_regions.as_ptr(), + mcdc_decision_regions.len() as c_uint, buffer, ); } @@ -281,82 +297,3 @@ pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 { pub(crate) fn mapping_version() -> u32 { unsafe { llvm::LLVMRustCoverageMappingVersion() } } - -pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>( - cx: &CodegenCx<'ll, 'tcx>, - cov_data_val: &'ll llvm::Value, -) { - let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe { - llvm::LLVMRustCoverageWriteMappingVarNameToString(s); - })) - .unwrap(); - debug!("covmap var name: {:?}", covmap_var_name); - - let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe { - llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s); - })) - .expect("covmap section name should not contain NUL"); - debug!("covmap section name: {:?}", covmap_section_name); - - let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name); - llvm::set_initializer(llglobal, cov_data_val); - llvm::set_global_constant(llglobal, true); - llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); - llvm::set_section(llglobal, &covmap_section_name); - // LLVM's coverage mapping format specifies 8-byte alignment for items in this section. - llvm::set_alignment(llglobal, Align::EIGHT); - cx.add_used_global(llglobal); -} - -pub(crate) fn save_func_record_to_mod<'ll, 'tcx>( - cx: &CodegenCx<'ll, 'tcx>, - covfun_section_name: &CStr, - func_name_hash: u64, - func_record_val: &'ll llvm::Value, - is_used: bool, -) { - // Assign a name to the function record. This is used to merge duplicates. - // - // In LLVM, a "translation unit" (effectively, a `Crate` in Rust) can describe functions that - // are included-but-not-used. If (or when) Rust generates functions that are - // included-but-not-used, note that a dummy description for a function included-but-not-used - // in a Crate can be replaced by full description provided by a different Crate. The two kinds - // of descriptions play distinct roles in LLVM IR; therefore, assign them different names (by - // appending "u" to the end of the function record var name, to prevent `linkonce_odr` merging. - let func_record_var_name = - CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" })) - .unwrap(); - debug!("function record var name: {:?}", func_record_var_name); - debug!("function record section name: {:?}", covfun_section_name); - - let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name); - llvm::set_initializer(llglobal, func_record_val); - llvm::set_global_constant(llglobal, true); - llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage); - llvm::set_visibility(llglobal, llvm::Visibility::Hidden); - llvm::set_section(llglobal, covfun_section_name); - // LLVM's coverage mapping format specifies 8-byte alignment for items in this section. - llvm::set_alignment(llglobal, Align::EIGHT); - if cx.target_spec().supports_comdat() { - llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name); - } - cx.add_used_global(llglobal); -} - -/// Returns the section name string to pass through to the linker when embedding -/// per-function coverage information in the object file, according to the target -/// platform's object file format. -/// -/// LLVM's coverage tools read coverage mapping details from this section when -/// producing coverage reports. -/// -/// Typical values are: -/// - `__llvm_covfun` on Linux -/// - `__LLVM_COV,__llvm_covfun` on macOS (includes `__LLVM_COV,` segment prefix) -/// - `.lcovfun$M` on Windows (includes `$M` sorting suffix) -pub(crate) fn covfun_section_name(cx: &CodegenCx<'_, '_>) -> CString { - CString::new(llvm::build_byte_buffer(|s| unsafe { - llvm::LLVMRustCoverageWriteFuncSectionNameToString(cx.llmod, s); - })) - .expect("covfun section name should not contain NUL") -} diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index f93d3e40b20..7947c9c8c8e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -76,7 +76,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global); - llvm::LLVMRustSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage); + llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage); // This should make sure that the whole section is not larger than // the string it contains. Otherwise we get a warning from GDB. llvm::LLVMSetAlignment(section_var, 1); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 1a8153a54e8..3de4ca77e7d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -350,7 +350,6 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { type_names::push_generic_params( tcx, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args), - enclosing_fn_def_id, &mut name, ); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index c9a17c9852d..d04b5257619 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -785,13 +785,12 @@ fn codegen_msvc_try<'ll>( let type_info = bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_ptr()), type_name], false); let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info)); - unsafe { - llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage); - if bx.cx.tcx.sess.target.supports_comdat() { - llvm::SetUniqueComdat(bx.llmod, tydesc); - } - llvm::LLVMSetInitializer(tydesc, type_info); + + llvm::set_linkage(tydesc, llvm::Linkage::LinkOnceODRLinkage); + if bx.cx.tcx.sess.target.supports_comdat() { + llvm::SetUniqueComdat(bx.llmod, tydesc); } + unsafe { llvm::LLVMSetInitializer(tydesc, type_info) }; // The flag value of 8 indicates that we are catching the exception by // reference instead of by value. We can't use catch by value because @@ -1064,7 +1063,7 @@ fn gen_fn<'ll, 'tcx>( cx.set_frame_pointer_type(llfn); cx.apply_target_cpu_attr(llfn); // FIXME(eddyb) find a nicer way to do this. - unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) }; + llvm::set_linkage(llfn, llvm::Linkage::InternalLinkage); let llbb = Builder::append_block(cx, llfn, "entry-block"); let bx = Builder::build(cx, llbb); codegen(bx); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index d0034de06c7..acc66076833 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1,9 +1,11 @@ #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] +use std::fmt::Debug; use std::marker::PhantomData; use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t}; +use rustc_macros::TryFromU32; use rustc_target::spec::SymbolVisibility; use super::RustString; @@ -19,6 +21,30 @@ pub type Bool = c_uint; pub const True: Bool = 1 as Bool; pub const False: Bool = 0 as Bool; +/// Wrapper for a raw enum value returned from LLVM's C APIs. +/// +/// For C enums returned by LLVM, it's risky to use a Rust enum as the return +/// type, because it would be UB if a later version of LLVM adds a new enum +/// value and returns it. Instead, return this raw wrapper, then convert to the +/// Rust-side enum explicitly. +#[repr(transparent)] +pub struct RawEnum { + value: u32, + /// We don't own or consume a `T`, but we can produce one. + _rust_side_type: PhantomData T>, +} + +impl> RawEnum { + #[track_caller] + pub(crate) fn to_rust(self) -> T + where + T::Error: Debug, + { + // If this fails, the Rust-side enum is out of sync with LLVM's enum. + T::try_from(self.value).expect("enum value returned by LLVM should be known") + } +} + #[derive(Copy, Clone, PartialEq)] #[repr(C)] #[allow(dead_code)] // Variants constructed by C++. @@ -108,26 +134,36 @@ pub enum CallConv { AvrInterrupt = 85, } -/// LLVMRustLinkage -#[derive(Copy, Clone, PartialEq)] +/// Must match the layout of `LLVMLinkage`. +#[derive(Copy, Clone, PartialEq, TryFromU32)] #[repr(C)] pub enum Linkage { ExternalLinkage = 0, AvailableExternallyLinkage = 1, LinkOnceAnyLinkage = 2, LinkOnceODRLinkage = 3, - WeakAnyLinkage = 4, - WeakODRLinkage = 5, - AppendingLinkage = 6, - InternalLinkage = 7, - PrivateLinkage = 8, - ExternalWeakLinkage = 9, - CommonLinkage = 10, + #[deprecated = "marked obsolete by LLVM"] + LinkOnceODRAutoHideLinkage = 4, + WeakAnyLinkage = 5, + WeakODRLinkage = 6, + AppendingLinkage = 7, + InternalLinkage = 8, + PrivateLinkage = 9, + #[deprecated = "marked obsolete by LLVM"] + DLLImportLinkage = 10, + #[deprecated = "marked obsolete by LLVM"] + DLLExportLinkage = 11, + ExternalWeakLinkage = 12, + #[deprecated = "marked obsolete by LLVM"] + GhostLinkage = 13, + CommonLinkage = 14, + LinkerPrivateLinkage = 15, + LinkerPrivateWeakLinkage = 16, } -// LLVMRustVisibility +/// Must match the layout of `LLVMVisibility`. #[repr(C)] -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, TryFromU32)] pub enum Visibility { Default = 0, Hidden = 1, @@ -945,7 +981,11 @@ unsafe extern "C" { // Operations on global variables, functions, and aliases (globals) pub fn LLVMIsDeclaration(Global: &Value) -> Bool; + pub fn LLVMGetLinkage(Global: &Value) -> RawEnum; + pub fn LLVMSetLinkage(Global: &Value, RustLinkage: Linkage); pub fn LLVMSetSection(Global: &Value, Section: *const c_char); + pub fn LLVMGetVisibility(Global: &Value) -> RawEnum; + pub fn LLVMSetVisibility(Global: &Value, Viz: Visibility); pub fn LLVMGetAlignment(Global: &Value) -> c_uint; pub fn LLVMSetAlignment(Global: &Value, Bytes: c_uint); pub fn LLVMSetDLLStorageClass(V: &Value, C: DLLStorageClass); @@ -1521,10 +1561,6 @@ unsafe extern "C" { ) -> bool; // Operations on global variables, functions, and aliases (globals) - pub fn LLVMRustGetLinkage(Global: &Value) -> Linkage; - pub fn LLVMRustSetLinkage(Global: &Value, RustLinkage: Linkage); - pub fn LLVMRustGetVisibility(Global: &Value) -> Visibility; - pub fn LLVMRustSetVisibility(Global: &Value, Viz: Visibility); pub fn LLVMRustSetDSOLocal(Global: &Value, is_dso_local: bool); // Operations on global variables @@ -1615,10 +1651,6 @@ unsafe extern "C" { pub fn LLVMRustSetAllowReassoc(Instr: &Value); // Miscellaneous instructions - pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &Value; - pub fn LLVMRustGetInstrProfMCDCParametersIntrinsic(M: &Module) -> &Value; - pub fn LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(M: &Module) -> &Value; - pub fn LLVMRustBuildCall<'a>( B: &Builder<'a>, Ty: &'a Type, @@ -1744,7 +1776,7 @@ unsafe extern "C" { ) -> bool; #[allow(improper_ctypes)] - pub fn LLVMRustCoverageWriteFilenamesSectionToBuffer( + pub(crate) fn LLVMRustCoverageWriteFilenamesSectionToBuffer( Filenames: *const *const c_char, FilenamesLen: size_t, Lengths: *const size_t, @@ -1753,33 +1785,39 @@ unsafe extern "C" { ); #[allow(improper_ctypes)] - pub fn LLVMRustCoverageWriteMappingToBuffer( + pub(crate) fn LLVMRustCoverageWriteMappingToBuffer( VirtualFileMappingIDs: *const c_uint, NumVirtualFileMappingIDs: c_uint, Expressions: *const crate::coverageinfo::ffi::CounterExpression, NumExpressions: c_uint, - MappingRegions: *const crate::coverageinfo::ffi::CounterMappingRegion, - NumMappingRegions: c_uint, + CodeRegions: *const crate::coverageinfo::ffi::CodeRegion, + NumCodeRegions: c_uint, + BranchRegions: *const crate::coverageinfo::ffi::BranchRegion, + NumBranchRegions: c_uint, + MCDCBranchRegions: *const crate::coverageinfo::ffi::MCDCBranchRegion, + NumMCDCBranchRegions: c_uint, + MCDCDecisionRegions: *const crate::coverageinfo::ffi::MCDCDecisionRegion, + NumMCDCDecisionRegions: c_uint, BufferOut: &RustString, ); - pub fn LLVMRustCoverageCreatePGOFuncNameVar( + pub(crate) fn LLVMRustCoverageCreatePGOFuncNameVar( F: &Value, FuncName: *const c_char, FuncNameLen: size_t, ) -> &Value; - pub fn LLVMRustCoverageHashByteArray(Bytes: *const c_char, NumBytes: size_t) -> u64; + pub(crate) fn LLVMRustCoverageHashByteArray(Bytes: *const c_char, NumBytes: size_t) -> u64; #[allow(improper_ctypes)] - pub fn LLVMRustCoverageWriteMapSectionNameToString(M: &Module, Str: &RustString); + pub(crate) fn LLVMRustCoverageWriteMapSectionNameToString(M: &Module, Str: &RustString); #[allow(improper_ctypes)] - pub fn LLVMRustCoverageWriteFuncSectionNameToString(M: &Module, Str: &RustString); + pub(crate) fn LLVMRustCoverageWriteFuncSectionNameToString(M: &Module, Str: &RustString); #[allow(improper_ctypes)] - pub fn LLVMRustCoverageWriteMappingVarNameToString(Str: &RustString); + pub(crate) fn LLVMRustCoverageWriteMappingVarNameToString(Str: &RustString); - pub fn LLVMRustCoverageMappingVersion() -> u32; + pub(crate) fn LLVMRustCoverageMappingVersion() -> u32; pub fn LLVMRustDebugMetadataVersion() -> u32; pub fn LLVMRustVersionMajor() -> u32; pub fn LLVMRustVersionMinor() -> u32; diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index e837022044e..6aac2eea81d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -232,15 +232,23 @@ pub fn set_global_constant(llglobal: &Value, is_constant: bool) { } } +pub fn get_linkage(llglobal: &Value) -> Linkage { + unsafe { LLVMGetLinkage(llglobal) }.to_rust() +} + pub fn set_linkage(llglobal: &Value, linkage: Linkage) { unsafe { - LLVMRustSetLinkage(llglobal, linkage); + LLVMSetLinkage(llglobal, linkage); } } +pub fn get_visibility(llglobal: &Value) -> Visibility { + unsafe { LLVMGetVisibility(llglobal) }.to_rust() +} + pub fn set_visibility(llglobal: &Value, visibility: Visibility) { unsafe { - LLVMRustSetVisibility(llglobal, visibility); + LLVMSetVisibility(llglobal, visibility); } } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 57936215ff1..aa38c02289d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -248,6 +248,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::new("perfmon")), ("aarch64", "paca") => Some(LLVMFeature::new("pauth")), ("aarch64", "pacg") => Some(LLVMFeature::new("pauth")), + ("aarch64", "pauth-lr") if get_version().0 < 19 => None, // Before LLVM 20 those two features were packaged together as b16b16 ("aarch64", "sve-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")), ("aarch64", "sme-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")), diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index bf6ef219873..ea8857b4739 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -39,9 +39,9 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { .emit_fatal(SymbolAlreadyDefined { span: self.tcx.def_span(def_id), symbol_name }) }); + llvm::set_linkage(g, base::linkage_to_llvm(linkage)); + llvm::set_visibility(g, base::visibility_to_llvm(visibility)); unsafe { - llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage)); - llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility)); if self.should_assume_dso_local(g, false) { llvm::LLVMRustSetDSOLocal(g, true); } @@ -61,7 +61,7 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance)); - unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) }; + llvm::set_linkage(lldecl, base::linkage_to_llvm(linkage)); let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); base::set_link_section(lldecl, attrs); if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR) @@ -78,21 +78,15 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { && linkage != Linkage::Private && self.tcx.is_compiler_builtins(LOCAL_CRATE) { - unsafe { - llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden); - } + llvm::set_visibility(lldecl, llvm::Visibility::Hidden); } else { - unsafe { - llvm::LLVMRustSetVisibility(lldecl, base::visibility_to_llvm(visibility)); - } + llvm::set_visibility(lldecl, base::visibility_to_llvm(visibility)); } debug!("predefine_fn: instance = {:?}", instance); - unsafe { - if self.should_assume_dso_local(lldecl, false) { - llvm::LLVMRustSetDSOLocal(lldecl, true); - } + if self.should_assume_dso_local(lldecl, false) { + unsafe { llvm::LLVMRustSetDSOLocal(lldecl, true) }; } self.instances.borrow_mut().insert(instance, lldecl); @@ -102,13 +96,13 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { impl CodegenCx<'_, '_> { /// Whether a definition or declaration can be assumed to be local to a group of /// libraries that form a single DSO or executable. - pub(crate) unsafe fn should_assume_dso_local( + pub(crate) fn should_assume_dso_local( &self, llval: &llvm::Value, is_declaration: bool, ) -> bool { - let linkage = unsafe { llvm::LLVMRustGetLinkage(llval) }; - let visibility = unsafe { llvm::LLVMRustGetVisibility(llval) }; + let linkage = llvm::get_linkage(llval); + let visibility = llvm::get_visibility(llval); if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) { return true; diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 1af666f818b..6be4c3f034f 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -191,7 +191,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`. /// If the type is an unsized struct, the regular layout is generated, - /// with the inner-most trailing unsized field using the "minimal unit" + /// with the innermost trailing unsized field using the "minimal unit" /// of that field's type - this is useful for taking the address of /// that field and ensuring the struct has the right alignment. fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type { diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 77c35a1fe79..d9669453f5a 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -312,7 +312,7 @@ fn exported_symbols_provider_local( match *mono_item { MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => { - if args.non_erasable_generics(tcx, def).next().is_some() { + if args.non_erasable_generics().next().is_some() { let symbol = ExportedSymbol::Generic(def, args); symbols.push((symbol, SymbolExportInfo { level: SymbolExportLevel::Rust, @@ -321,12 +321,9 @@ fn exported_symbols_provider_local( })); } } - MonoItem::Fn(Instance { def: InstanceKind::DropGlue(def_id, Some(ty)), args }) => { + MonoItem::Fn(Instance { def: InstanceKind::DropGlue(_, Some(ty)), args }) => { // A little sanity-check - assert_eq!( - args.non_erasable_generics(tcx, def_id).next(), - Some(GenericArgKind::Type(ty)) - ); + assert_eq!(args.non_erasable_generics().next(), Some(GenericArgKind::Type(ty))); symbols.push((ExportedSymbol::DropGlue(ty), SymbolExportInfo { level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, @@ -334,14 +331,11 @@ fn exported_symbols_provider_local( })); } MonoItem::Fn(Instance { - def: InstanceKind::AsyncDropGlueCtorShim(def_id, Some(ty)), + def: InstanceKind::AsyncDropGlueCtorShim(_, Some(ty)), args, }) => { // A little sanity-check - assert_eq!( - args.non_erasable_generics(tcx, def_id).next(), - Some(GenericArgKind::Type(ty)) - ); + assert_eq!(args.non_erasable_generics().next(), Some(GenericArgKind::Type(ty))); symbols.push((ExportedSymbol::AsyncDropGlueCtorShim(ty), SymbolExportInfo { level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f3d9a7d37e6..a726ee73aaa 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -888,7 +888,7 @@ impl CrateInfo { // below. // // In order to get this left-to-right dependency ordering, we use the reverse - // postorder of all crates putting the leaves at the right-most positions. + // postorder of all crates putting the leaves at the rightmost positions. let mut compiler_builtins = None; let mut used_crates: Vec<_> = tcx .postorder_cnums(()) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index d536419ab3c..a5bd3adbcdd 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -137,7 +137,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let inner = attr.meta_item_list(); match inner.as_deref() { Some([item]) if item.has_name(sym::linker) => { - if !tcx.features().used_with_arg { + if !tcx.features().used_with_arg() { feature_err( &tcx.sess, sym::used_with_arg, @@ -149,7 +149,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER; } Some([item]) if item.has_name(sym::compiler) => { - if !tcx.features().used_with_arg { + if !tcx.features().used_with_arg() { feature_err( &tcx.sess, sym::used_with_arg, @@ -213,7 +213,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { .emit(); } if is_closure - && !tcx.features().closure_track_caller + && !tcx.features().closure_track_caller() && !attr.span.allows_unstable(sym::closure_track_caller) { feature_err( @@ -268,7 +268,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // // This exception needs to be kept in sync with allowing // `#[target_feature]` on `main` and `start`. - } else if !tcx.features().target_feature_11 { + } else if !tcx.features().target_feature_11() { feature_err( &tcx.sess, sym::target_feature_11, @@ -584,7 +584,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // its parent function, which effectively inherits the features anyway. Boxing this closure // would result in this closure being compiled without the inherited target features, but this // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute. - if tcx.features().target_feature_11 + if tcx.features().target_feature_11() && tcx.is_closure_like(did.to_def_id()) && codegen_fn_attrs.inline != InlineAttr::Always { diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 526d2b86d48..1e5b4f3433d 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -110,14 +110,14 @@ fn push_debuginfo_type_name<'tcx>( ty_and_layout, &|output, visited| { push_item_name(tcx, def.did(), true, output); - push_generic_params_internal(tcx, args, def.did(), output, visited); + push_generic_params_internal(tcx, args, output, visited); }, output, visited, ); } else { push_item_name(tcx, def.did(), qualified, output); - push_generic_params_internal(tcx, args, def.did(), output, visited); + push_generic_params_internal(tcx, args, output, visited); } } ty::Tuple(component_types) => { @@ -251,13 +251,8 @@ fn push_debuginfo_type_name<'tcx>( let principal = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal); push_item_name(tcx, principal.def_id, qualified, output); - let principal_has_generic_params = push_generic_params_internal( - tcx, - principal.args, - principal.def_id, - output, - visited, - ); + let principal_has_generic_params = + push_generic_params_internal(tcx, principal.args, output, visited); let projection_bounds: SmallVec<[_; 4]> = trait_data .projection_bounds() @@ -538,13 +533,7 @@ pub fn compute_debuginfo_vtable_name<'tcx>( tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref); push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name); visited.clear(); - push_generic_params_internal( - tcx, - trait_ref.args, - trait_ref.def_id, - &mut vtable_name, - &mut visited, - ); + push_generic_params_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited); } else { vtable_name.push('_'); } @@ -647,12 +636,11 @@ fn push_unqualified_item_name( fn push_generic_params_internal<'tcx>( tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, - def_id: DefId, output: &mut String, visited: &mut FxHashSet>, ) -> bool { assert_eq!(args, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args)); - let mut args = args.non_erasable_generics(tcx, def_id).peekable(); + let mut args = args.non_erasable_generics().peekable(); if args.peek().is_none() { return false; } @@ -736,12 +724,11 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S pub fn push_generic_params<'tcx>( tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, - def_id: DefId, output: &mut String, ) { let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name"); let mut visited = FxHashSet::default(); - push_generic_params_internal(tcx, args, def_id, output, &mut visited); + push_generic_params_internal(tcx, args, output, &mut visited); } fn push_closure_or_coroutine_name<'tcx>( @@ -786,7 +773,7 @@ fn push_closure_or_coroutine_name<'tcx>( // FIXME(async_closures): This is probably not going to be correct w.r.t. // multiple coroutine flavors. Maybe truncate to (parent + 1)? let args = args.truncate_to(tcx, generics); - push_generic_params_internal(tcx, args, enclosing_fn_def_id, output, visited); + push_generic_params_internal(tcx, args, output, visited); } fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) { diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index dfe8fd616e4..0845bcc5749 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -5,7 +5,6 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::Applicability; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; -use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; @@ -61,30 +60,9 @@ pub(crate) fn from_target_feature( return None; }; - // Only allow features whose feature gates have been enabled. + // Only allow target features whose feature gates have been enabled. let allowed = match feature_gate.as_ref().copied() { - Some(sym::arm_target_feature) => rust_features.arm_target_feature, - Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature, - Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature, - Some(sym::mips_target_feature) => rust_features.mips_target_feature, - Some(sym::riscv_target_feature) => rust_features.riscv_target_feature, - Some(sym::avx512_target_feature) => rust_features.avx512_target_feature, - Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature, - Some(sym::tbm_target_feature) => rust_features.tbm_target_feature, - Some(sym::wasm_target_feature) => rust_features.wasm_target_feature, - Some(sym::rtm_target_feature) => rust_features.rtm_target_feature, - Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature, - Some(sym::bpf_target_feature) => rust_features.bpf_target_feature, - Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature, - Some(sym::csky_target_feature) => rust_features.csky_target_feature, - Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature, - Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature, - Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature, - Some(sym::sha512_sm_x86) => rust_features.sha512_sm_x86, - Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics, - Some(sym::xop_target_feature) => rust_features.xop_target_feature, - Some(sym::s390x_target_feature) => rust_features.s390x_target_feature, - Some(name) => bug!("unknown target feature gate {}", name), + Some(name) => rust_features.enabled(name), None => true, }; if !allowed { diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index c0c1085e949..50a51714146 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -437,14 +437,6 @@ pub trait BuilderMethods<'a, 'tcx>: /// Called for `StorageDead` fn lifetime_end(&mut self, ptr: Self::Value, size: Size); - fn instrprof_increment( - &mut self, - fn_name: Self::Value, - hash: Self::Value, - num_counters: Self::Value, - index: Self::Value, - ); - fn call( &mut self, llty: Self::Type, diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 24dbe688f36..3e4f83c8242 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -41,8 +41,6 @@ const_eval_const_context = {$kind -> *[other] {""} } -const_eval_const_stable = const-stable functions can only call other const-stable functions - const_eval_copy_nonoverlapping_overlapping = `copy_nonoverlapping` called on overlapping ranges @@ -259,6 +257,9 @@ const_eval_non_const_fn_call = const_eval_non_const_impl = impl defined here, but it is not `const` +const_eval_non_const_intrinsic = + cannot call non-const intrinsic `{$name}` in {const_eval_const_context}s + const_eval_not_enough_caller_args = calling a function with fewer arguments than it requires @@ -397,17 +398,29 @@ const_eval_uninhabited_enum_variant_read = read discriminant of an uninhabited enum variant const_eval_uninhabited_enum_variant_written = writing discriminant of an uninhabited enum variant + +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_indirect]` (but this requires team approval) + const_eval_unreachable = entering unreachable code const_eval_unreachable_unwind = unwinding past a stack frame that does not allow unwinding const_eval_unsized_local = unsized locals are not supported const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn +const_eval_unstable_in_stable_exposed = + const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]` + .is_function_call = mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features + .unstable_sugg = if the {$is_function_call2 -> + [true] caller + *[false] function + } is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + .bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) -const_eval_unstable_in_stable = - const-stable function cannot use `#[feature({$gate})]` - .unstable_sugg = if the function is not (yet) meant to be stable, make this function unstably const - .bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval) +const_eval_unstable_intrinsic = `{$name}` is not yet stable as a const intrinsic + .help = add `#![feature({$feature})]` to the crate attributes to enable const_eval_unterminated_c_string = reading a null-terminated string starting at {$pointer} with no null found before end of allocation diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 463a66d4e2e..004fb12419f 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -5,6 +5,7 @@ use std::borrow::Cow; use std::mem; use std::ops::Deref; +use rustc_attr::{ConstStability, StabilityLevel}; use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, LangItem}; @@ -28,8 +29,8 @@ use super::ops::{self, NonConstOp, Status}; use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop}; use super::resolver::FlowSensitiveAnalysis; use super::{ConstCx, Qualif}; -use crate::const_eval::is_unstable_const_fn; -use crate::errors::UnstableInStable; +use crate::check_consts::is_safe_to_expose_on_stable_const_fn; +use crate::errors; type QualifResults<'mir, 'tcx, Q> = rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>; @@ -274,19 +275,22 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { /// context. pub fn check_op_spanned>(&mut self, op: O, span: Span) { let gate = match op.status_in_item(self.ccx) { - Status::Allowed => return, - - Status::Unstable(gate) if self.tcx.features().active(gate) => { - let unstable_in_stable = self.ccx.is_const_stable_const_fn() - && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate); - if unstable_in_stable { - emit_unstable_in_stable_error(self.ccx, span, gate); + Status::Unstable { gate, safe_to_expose_on_stable, is_function_call } + if self.tcx.features().enabled(gate) => + { + // 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 + && self.enforce_recursive_const_stability() + && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate) + { + emit_unstable_in_stable_exposed_error(self.ccx, span, gate, is_function_call); } return; } - Status::Unstable(gate) => Some(gate), + Status::Unstable { gate, .. } => Some(gate), Status::Forbidden => None, }; @@ -304,7 +308,13 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { self.error_emitted = Some(reported); } - ops::DiagImportance::Secondary => self.secondary_errors.push(err), + ops::DiagImportance::Secondary => { + self.secondary_errors.push(err); + self.tcx.dcx().span_delayed_bug( + span, + "compilation must fail when there is a secondary const checker error", + ); + } } } @@ -569,6 +579,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { ty::FnPtr(..) => { self.check_op(ops::FnCallIndirect); + // We can get here without an error in miri-unleashed mode... might as well + // skip the rest of the checks as well then. return; } _ => { @@ -604,14 +616,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { let mut is_trait = false; // Attempting to call a trait method? - if tcx.trait_of_item(callee).is_some() { + if let Some(trait_did) = tcx.trait_of_item(callee) { trace!("attempting to call a trait method"); + + let trait_is_const = tcx.is_const_trait(trait_did); // trait method calls are only permitted when `effects` is enabled. - // we don't error, since that is handled by typeck. We try to resolve - // the trait into the concrete method, and uses that for const stability - // checks. + // typeck ensures the conditions for calling a const trait method are met, + // so we only error if the trait isn't const. We try to resolve the trait + // into the concrete method, and uses that for const stability checks. // FIXME(effects) we might consider moving const stability checks to typeck as well. - if tcx.features().effects { + if tcx.features().effects() && trait_is_const { + // This skips the check below that ensures we only call `const fn`. is_trait = true; if let Ok(Some(instance)) = @@ -625,18 +640,27 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { callee = def; } } else { + // if the trait is const but the user has not enabled the feature(s), + // suggest them. + let feature = if trait_is_const { + Some(if tcx.features().const_trait_impl() { + sym::effects + } else { + sym::const_trait_impl + }) + } else { + None + }; self.check_op(ops::FnCallNonConst { caller, callee, args: fn_args, span: *fn_span, call_source, - feature: Some(if tcx.features().const_trait_impl { - sym::effects - } else { - sym::const_trait_impl - }), + feature, }); + // If we allowed this, we're in miri-unleashed mode, so we might + // as well skip the remaining checks. return; } } @@ -650,29 +674,73 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // const-eval of the `begin_panic` fn assumes the argument is `&str` if tcx.is_lang_item(callee, LangItem::BeginPanic) { match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() { - ty::Ref(_, ty, _) if ty.is_str() => return, + ty::Ref(_, ty, _) if ty.is_str() => {} _ => self.check_op(ops::PanicNonStr), } + // Allow this call, skip all the checks below. + return; } // const-eval of `#[rustc_const_panic_str]` functions assumes the argument is `&&str` if tcx.has_attr(callee, sym::rustc_const_panic_str) { match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() { ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) => - { - return; + {} + _ => { + self.check_op(ops::PanicNonStr); } - _ => self.check_op(ops::PanicNonStr), } + // Allow this call, skip all the checks below. + return; } // This can be called on stable via the `vec!` macro. if tcx.is_lang_item(callee, LangItem::ExchangeMalloc) { self.check_op(ops::HeapAllocation); + // Allow this call, skip all the checks below. return; } - if !tcx.is_const_fn_raw(callee) && !is_trait { + // Intrinsics are language primitives, not regular calls, so treat them separately. + if let Some(intrinsic) = tcx.intrinsic(callee) { + match tcx.lookup_const_stability(callee) { + None => { + // Non-const intrinsic. + self.check_op(ops::IntrinsicNonConst { name: intrinsic.name }); + } + Some(ConstStability { feature: None, const_stable_indirect, .. }) => { + // Intrinsic does not need a separate feature gate (we rely on the + // regular stability checker). However, we have to worry about recursive + // const stability. + if !const_stable_indirect && self.enforce_recursive_const_stability() { + self.dcx().emit_err(errors::UnmarkedIntrinsicExposed { + span: self.span, + def_path: self.tcx.def_path_str(callee), + }); + } + } + Some(ConstStability { + feature: Some(feature), + level: StabilityLevel::Unstable { .. }, + const_stable_indirect, + .. + }) => { + self.check_op(ops::IntrinsicUnstable { + name: intrinsic.name, + feature, + const_stable_indirect, + }); + } + Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { + // All good. + } + } + // This completes the checks for intrinsics. + return; + } + + // Trait functions are not `const fn` so we have to skip them here. + if !tcx.is_const_fn(callee) && !is_trait { self.check_op(ops::FnCallNonConst { caller, callee, @@ -681,66 +749,68 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { call_source, feature: None, }); + // If we allowed this, we're in miri-unleashed mode, so we might + // as well skip the remaining checks. return; } - // If the `const fn` we are trying to call is not const-stable, ensure that we have - // the proper feature gate enabled. - if let Some((gate, implied_by)) = is_unstable_const_fn(tcx, callee) { - trace!(?gate, "calling unstable const fn"); - if self.span.allows_unstable(gate) { - return; + // Finally, stability for regular function calls -- this is the big one. + match tcx.lookup_const_stability(callee) { + Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { + // All good. } - if let Some(implied_by_gate) = implied_by - && self.span.allows_unstable(implied_by_gate) - { - return; + None | Some(ConstStability { feature: None, .. }) => { + // This doesn't need a separate const-stability check -- const-stability equals + // regular stability, and regular stability is checked separately. + // However, we *do* have to worry about *recursive* const stability. + if self.enforce_recursive_const_stability() + && !is_safe_to_expose_on_stable_const_fn(tcx, callee) + { + self.dcx().emit_err(errors::UnmarkedConstFnExposed { + span: self.span, + def_path: self.tcx.def_path_str(callee), + }); + } } + Some(ConstStability { + feature: Some(feature), + level: StabilityLevel::Unstable { implied_by: implied_feature, .. }, + .. + }) => { + // An unstable const fn with a feature gate. + let callee_safe_to_expose_on_stable = + is_safe_to_expose_on_stable_const_fn(tcx, callee); - // Calling an unstable function *always* requires that the corresponding gate - // (or implied gate) be enabled, even if the function has - // `#[rustc_allow_const_fn_unstable(the_gate)]`. - let gate_declared = |gate| tcx.features().declared(gate); - let feature_gate_declared = gate_declared(gate); - let implied_gate_declared = implied_by.is_some_and(gate_declared); - if !feature_gate_declared && !implied_gate_declared { - self.check_op(ops::FnCallUnstable(callee, Some(gate))); - return; - } + // We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if + // the callee is safe to expose, to avoid bypassing recursive stability. + if (self.span.allows_unstable(feature) + || implied_feature.is_some_and(|f| self.span.allows_unstable(f))) + && callee_safe_to_expose_on_stable + { + return; + } - // If this crate is not using stability attributes, or the caller is not claiming to be a - // stable `const fn`, that is all that is required. - if !self.ccx.is_const_stable_const_fn() { - trace!("crate not using stability attributes or caller not stably const"); - return; - } - - // Otherwise, we are something const-stable calling a const-unstable fn. - if super::rustc_allow_const_fn_unstable(tcx, caller, gate) { - trace!("rustc_allow_const_fn_unstable gate active"); - return; - } - - self.check_op(ops::FnCallUnstable(callee, Some(gate))); - return; - } - - // FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that - // have no `rustc_const_stable` attributes to be const-unstable as well. This - // should be fixed later. - let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none() - && tcx.lookup_stability(callee).is_some_and(|s| s.is_unstable()); - if callee_is_unstable_unmarked { - trace!("callee_is_unstable_unmarked"); - // We do not use `const` modifiers for intrinsic "functions", as intrinsics are - // `extern` functions, and these have no way to get marked `const`. So instead we - // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const` - if self.ccx.is_const_stable_const_fn() || tcx.intrinsic(callee).is_some() { - self.check_op(ops::FnCallUnstable(callee, None)); - return; + // We can't use `check_op` to check whether the feature is enabled because + // the logic is a bit different than elsewhere: local functions don't need + // the feature gate, and there might be an "implied" gate that also suffices + // to allow this. + let feature_enabled = callee.is_local() + || tcx.features().enabled(feature) + || implied_feature.is_some_and(|f| tcx.features().enabled(f)); + // 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 { + self.check_op(ops::FnCallUnstable { + def_id: callee, + feature, + safe_to_expose_on_stable: callee_safe_to_expose_on_stable, + }); + } } } - trace!("permitting call"); } // Forbid all `Drop` terminators unless the place being dropped is a local with no @@ -785,11 +855,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm), - TerminatorKind::Yield { .. } => self.check_op(ops::Coroutine( - self.tcx - .coroutine_kind(self.body.source.def_id()) - .expect("Only expected to have a yield in a coroutine"), - )), + TerminatorKind::Yield { .. } => { + self.check_op(ops::Coroutine( + self.tcx + .coroutine_kind(self.body.source.def_id()) + .expect("Only expected to have a yield in a coroutine"), + )); + } TerminatorKind::CoroutineDrop => { span_bug!( @@ -819,8 +891,19 @@ fn is_int_bool_float_or_char(ty: Ty<'_>) -> bool { ty.is_bool() || ty.is_integral() || ty.is_char() || ty.is_floating_point() } -fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) { +fn emit_unstable_in_stable_exposed_error( + ccx: &ConstCx<'_, '_>, + span: Span, + gate: Symbol, + is_function_call: bool, +) -> ErrorGuaranteed { let attr_span = ccx.tcx.def_span(ccx.def_id()).shrink_to_lo(); - ccx.dcx().emit_err(UnstableInStable { gate: gate.to_string(), span, attr_span }); + ccx.dcx().emit_err(errors::UnstableInStableExposed { + gate: gate.to_string(), + span, + attr_span, + is_function_call, + is_function_call2: is_function_call, + }) } diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index 15ac4cedcc3..56da6791847 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -59,10 +59,12 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { self.const_kind.expect("`const_kind` must not be called on a non-const fn") } - pub fn is_const_stable_const_fn(&self) -> bool { + pub fn enforce_recursive_const_stability(&self) -> bool { + // We can skip this if `staged_api` is not enabled, since in such crates + // `lookup_const_stability` will always be `None`. self.const_kind == Some(hir::ConstContext::ConstFn) - && self.tcx.features().staged_api - && is_const_stable_const_fn(self.tcx, self.def_id().to_def_id()) + && self.tcx.features().staged_api() + && is_safe_to_expose_on_stable_const_fn(self.tcx, self.def_id().to_def_id()) } fn is_async(&self) -> bool { @@ -90,50 +92,38 @@ pub fn rustc_allow_const_fn_unstable( attr::rustc_allow_const_fn_unstable(tcx.sess, attrs).any(|name| name == feature_gate) } -/// Returns `true` if the given `const fn` is "const-stable". +/// Returns `true` if the given `const fn` is "safe to expose on stable". /// /// Panics if the given `DefId` does not refer to a `const fn`. /// -/// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable" -/// functions can be called in a const-context by users of the stable compiler. "const-stable" -/// functions are subject to more stringent restrictions than "const-unstable" functions: They -/// cannot use unstable features and can only call other "const-stable" functions. -pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - // A default body in a `#[const_trait]` is not const-stable because const - // trait fns currently cannot be const-stable. We shouldn't - // restrict default bodies to only call const-stable functions. +/// This is relevant within a `staged_api` crate. Unlike with normal features, the use of unstable +/// const features *recursively* taints the functions that use them. This is to avoid accidentally +/// exposing e.g. the implementation of an unstable const intrinsic on stable. So we partition the +/// world into two functions: those that are safe to expose on stable (and hence may not use +/// unstable features, not even recursively), and those that are not. +pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + // A default body in a `#[const_trait]` is not const-stable because const trait fns currently + // cannot be const-stable. These functions can't be called from anything stable, so we shouldn't + // restrict them to only call const-stable functions. if tcx.is_const_default_method(def_id) { + // FIXME(const_trait_impl): we have to eventually allow some of these if these things can ever be stable. + // They should probably behave like regular `const fn` for that... return false; } // Const-stability is only relevant for `const fn`. - assert!(tcx.is_const_fn_raw(def_id)); + assert!(tcx.is_const_fn(def_id)); - // A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs - // to is const-stable. match tcx.lookup_const_stability(def_id) { - Some(stab) => stab.is_const_stable(), - None if is_parent_const_stable_trait(tcx, def_id) => { - // Remove this when `#![feature(const_trait_impl)]` is stabilized, - // returning `true` unconditionally. - tcx.dcx().span_delayed_bug( - tcx.def_span(def_id), - "trait implementations cannot be const stable yet", - ); - true + None => { + // Only marked functions can be trusted. Note that this may be a function in a + // non-staged-API crate where no recursive checks were done! + false + } + Some(stab) => { + // We consider things safe-to-expose if they are stable, if they don't have any explicit + // const stability attribute, or if they are marked as `const_stable_indirect`. + stab.is_const_stable() || stab.feature.is_none() || stab.const_stable_indirect } - None => false, // By default, items are not const stable. } } - -fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let local_def_id = def_id.expect_local(); - let hir_id = tcx.local_def_id_to_hir_id(local_def_id); - - let parent_owner_id = tcx.parent_hir_id(hir_id).owner; - if !tcx.is_const_trait_impl_raw(parent_owner_id.to_def_id()) { - return false; - } - - tcx.lookup_const_stability(parent_owner_id).is_some_and(|stab| stab.is_const_stable()) -} diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 5c4a899f28a..3ac06ae6491 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -26,8 +26,16 @@ use crate::{errors, fluent_generated}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Status { - Allowed, - Unstable(Symbol), + Unstable { + /// The feature that must be enabled to use this operation. + gate: Symbol, + /// Whether it is allowed to use this operation from stable `const fn`. + /// This will usually be `false`. + safe_to_expose_on_stable: bool, + /// We indicate whether this is a function call, since we can use targeted + /// diagnostics for "callee is not safe to expose om stable". + is_function_call: bool, + }, Forbidden, } @@ -40,9 +48,9 @@ pub enum DiagImportance { Secondary, } -/// An operation that is not *always* allowed in a const context. +/// An operation that is *not allowed* in a const context. pub trait NonConstOp<'tcx>: std::fmt::Debug { - /// Returns an enum indicating whether this operation is allowed within the given item. + /// Returns an enum indicating whether this operation can be enabled with a feature gate. fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { Status::Forbidden } @@ -114,7 +122,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { if let Ok(Some(ImplSource::UserDefined(data))) = implsrc { // FIXME(effects) revisit this - if !tcx.is_const_trait_impl_raw(data.impl_def_id) { + if !tcx.is_const_trait_impl(data.impl_def_id) { let span = tcx.def_span(data.impl_def_id); err.subdiagnostic(errors::NonConstImplNote { span }); } @@ -166,7 +174,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { let note = match self_ty.kind() { FnDef(def_id, ..) => { let span = tcx.def_span(*def_id); - if ccx.tcx.is_const_fn_raw(*def_id) { + if ccx.tcx.is_const_fn(*def_id) { span_bug!(span, "calling const FnDef errored when it shouldn't"); } @@ -298,30 +306,78 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { /// /// Contains the name of the feature that would allow the use of this function. #[derive(Debug)] -pub(crate) struct FnCallUnstable(pub DefId, pub Option); +pub(crate) struct FnCallUnstable { + pub def_id: DefId, + pub feature: Symbol, + pub safe_to_expose_on_stable: bool, +} impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { + fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { + Status::Unstable { + gate: self.feature, + 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> { - let FnCallUnstable(def_id, feature) = *self; - - let mut err = ccx - .dcx() - .create_err(errors::UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) }); - + let mut err = ccx.dcx().create_err(errors::UnstableConstFn { + span, + def_path: ccx.tcx.def_path_str(self.def_id), + }); // FIXME: make this translatable #[allow(rustc::untranslatable_diagnostic)] - if ccx.is_const_stable_const_fn() { - err.help(fluent_generated::const_eval_const_stable); - } else if ccx.tcx.sess.is_nightly_build() { - if let Some(feature) = feature { - err.help(format!("add `#![feature({feature})]` to the crate attributes to enable")); - } - } + err.help(format!("add `#![feature({})]` to the crate attributes to enable", self.feature)); err } } +/// A call to an intrinsic that is just not const-callable at all. +#[derive(Debug)] +pub(crate) struct IntrinsicNonConst { + pub name: Symbol, +} + +impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { + ccx.dcx().create_err(errors::NonConstIntrinsic { + span, + name: self.name, + kind: ccx.const_kind(), + }) + } +} + +/// A call to an intrinsic that is just not const-callable at all. +#[derive(Debug)] +pub(crate) struct IntrinsicUnstable { + pub name: Symbol, + pub feature: Symbol, + 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_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, + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { + ccx.dcx().create_err(errors::UnstableIntrinsic { + span, + name: self.name, + feature: self.feature, + }) + } +} + #[derive(Debug)] pub(crate) struct Coroutine(pub hir::CoroutineKind); impl<'tcx> NonConstOp<'tcx> for Coroutine { @@ -331,7 +387,11 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine { hir::CoroutineSource::Block, ) = self.0 { - Status::Unstable(sym::const_async_blocks) + Status::Unstable { + gate: sym::const_async_blocks, + safe_to_expose_on_stable: false, + is_function_call: false, + } } else { Status::Forbidden } 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 f98234ce7f3..0173a528c22 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 @@ -15,7 +15,7 @@ use crate::check_consts::rustc_allow_const_fn_unstable; /// elaboration. pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool { // Const-stable functions must always use the stable live drop checker... - if ccx.is_const_stable_const_fn() { + if ccx.enforce_recursive_const_stability() { // ...except if they have the feature flag set via `rustc_allow_const_fn_unstable`. return rustc_allow_const_fn_unstable( ccx.tcx, @@ -24,7 +24,7 @@ pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool { ); } - ccx.tcx.features().const_precise_live_drops + ccx.tcx.features().const_precise_live_drops() } /// Look for live drops in a const context. diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index ca0993f0580..037fdcbcf9b 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -1,25 +1,8 @@ +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::Symbol; -use {rustc_attr as attr, rustc_hir as hir}; - -/// Whether the `def_id` is an unstable const fn and what feature gate(s) are necessary to enable -/// it. -pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<(Symbol, Option)> { - if tcx.is_const_fn_raw(def_id) { - let const_stab = tcx.lookup_const_stability(def_id)?; - match const_stab.level { - attr::StabilityLevel::Unstable { implied_by, .. } => { - Some((const_stab.feature, implied_by)) - } - attr::StabilityLevel::Stable { .. } => None, - } - } else { - None - } -} pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { let parent_id = tcx.local_parent(def_id); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 2db43a0f787..d54c5b750f0 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -219,7 +219,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { } /// "Intercept" a function call, because we have something special to do for it. - /// All `#[rustc_do_not_const_check]` functions should be hooked here. + /// All `#[rustc_do_not_const_check]` functions MUST be hooked here. /// If this returns `Some` function, which may be `instance` or a different function with /// compatible arguments, then evaluation should continue with that function. /// If this returns `None`, the function call has been handled and the function has returned. @@ -431,8 +431,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // sensitive check here. But we can at least rule out functions that are not const at // all. That said, we have to allow calling functions inside a trait marked with // #[const_trait]. These *are* const-checked! - // FIXME: why does `is_const_fn_raw` not classify them as const? - if (!ecx.tcx.is_const_fn_raw(def) && !ecx.tcx.is_const_default_method(def)) + // FIXME(effects): why does `is_const_fn` not classify them as const? + if (!ecx.tcx.is_const_fn(def) && !ecx.tcx.is_const_default_method(def)) || ecx.tcx.has_attr(def, sym::rustc_do_not_const_check) { // We certainly do *not* want to actually call the fn diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 211668cf055..38b87b72634 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -14,7 +14,7 @@ use rustc_middle::mir::interpret::{ UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, }; use rustc_middle::ty::{self, Mutability, Ty}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use rustc_target::abi::WrappingRange; use rustc_target::abi::call::AdjustForForeignAbiError; @@ -44,11 +44,15 @@ pub(crate) struct MutablePtrInFinal { } #[derive(Diagnostic)] -#[diag(const_eval_unstable_in_stable)] -pub(crate) struct UnstableInStable { +#[diag(const_eval_unstable_in_stable_exposed)] +pub(crate) struct UnstableInStableExposed { pub gate: String, #[primary_span] pub span: Span, + #[help(const_eval_is_function_call)] + pub is_function_call: bool, + /// Need to duplicate the field so that fluent also provides it as a variable... + pub is_function_call2: bool, #[suggestion( const_eval_unstable_sugg, code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n", @@ -117,6 +121,34 @@ pub(crate) struct UnstableConstFn { pub def_path: String, } +#[derive(Diagnostic)] +#[diag(const_eval_unstable_intrinsic)] +#[help] +pub(crate) struct UnstableIntrinsic { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub feature: Symbol, +} + +#[derive(Diagnostic)] +#[diag(const_eval_unmarked_const_fn_exposed)] +#[help] +pub(crate) struct UnmarkedConstFnExposed { + #[primary_span] + pub span: Span, + pub def_path: String, +} + +#[derive(Diagnostic)] +#[diag(const_eval_unmarked_intrinsic_exposed)] +#[help] +pub(crate) struct UnmarkedIntrinsicExposed { + #[primary_span] + pub span: Span, + pub def_path: String, +} + #[derive(Diagnostic)] #[diag(const_eval_mutable_ref_escaping, code = E0764)] pub(crate) struct MutableRefEscaping { @@ -153,6 +185,15 @@ pub(crate) struct NonConstFnCall { pub kind: ConstContext, } +#[derive(Diagnostic)] +#[diag(const_eval_non_const_intrinsic)] +pub(crate) struct NonConstIntrinsic { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub kind: ConstContext, +} + #[derive(Diagnostic)] #[diag(const_eval_unallowed_op_in_const_context)] pub(crate) struct UnallowedOpInConstContext { diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index 7cb013fdbd8..53ff67f60e3 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -2,15 +2,13 @@ //! //! Algorithm based on Loukas Georgiadis, //! "Linear-Time Algorithms for Dominators and Related Problems", -//! +//! //! //! Additionally useful is the original Lengauer-Tarjan paper on this subject, //! "A Fast Algorithm for Finding Dominators in a Flowgraph" //! Thomas Lengauer and Robert Endre Tarjan. //! -use std::cmp::Ordering; - use rustc_index::{Idx, IndexSlice, IndexVec}; use super::ControlFlowGraph; @@ -64,9 +62,6 @@ fn is_small_path_graph(g: &G) -> bool { } fn dominators_impl(graph: &G) -> Inner { - // compute the post order index (rank) for each node - let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes()); - // We allocate capacity for the full set of nodes, because most of the time // most of the nodes *are* reachable. let mut parent: IndexVec = @@ -83,12 +78,10 @@ fn dominators_impl(graph: &G) -> Inner { pre_order_to_real.push(graph.start_node()); parent.push(PreorderIndex::ZERO); // the parent of the root node is the root for now. real_to_pre_order[graph.start_node()] = Some(PreorderIndex::ZERO); - let mut post_order_idx = 0; // Traverse the graph, collecting a number of things: // // * Preorder mapping (to it, and back to the actual ordering) - // * Postorder mapping (used exclusively for `cmp_in_dominator_order` on the final product) // * Parents for each vertex in the preorder tree // // These are all done here rather than through one of the 'standard' @@ -104,8 +97,6 @@ fn dominators_impl(graph: &G) -> Inner { continue 'recurse; } } - post_order_rank[pre_order_to_real[frame.pre_order_idx]] = post_order_idx; - post_order_idx += 1; stack.pop(); } @@ -282,7 +273,7 @@ fn dominators_impl(graph: &G) -> Inner { let time = compute_access_time(start_node, &immediate_dominators); - Inner { post_order_rank, immediate_dominators, time } + Inner { immediate_dominators, time } } /// Evaluate the link-eval virtual forest, providing the currently minimum semi @@ -348,7 +339,6 @@ fn compress( /// Tracks the list of dominators for each node. #[derive(Clone, Debug)] struct Inner { - post_order_rank: IndexVec, // Even though we track only the immediate dominator of each node, it's // possible to get its full list of dominators by looking up the dominator // of each dominator. @@ -379,17 +369,6 @@ impl Dominators { } } - /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator - /// relationship, the dominator will always precede the dominated. (The relative ordering - /// of two unrelated nodes will also be consistent, but otherwise the order has no - /// meaning.) This method cannot be used to determine if either Node dominates the other. - pub fn cmp_in_dominator_order(&self, lhs: Node, rhs: Node) -> Ordering { - match &self.kind { - Kind::Path => lhs.index().cmp(&rhs.index()), - Kind::General(g) => g.post_order_rank[rhs].cmp(&g.post_order_rank[lhs]), - } - } - /// Returns true if `a` dominates `b`. /// /// # Panics diff --git a/compiler/rustc_error_codes/src/error_codes/E0539.md b/compiler/rustc_error_codes/src/error_codes/E0539.md index cd28afbc48d..6b2e23ba2d8 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0539.md +++ b/compiler/rustc_error_codes/src/error_codes/E0539.md @@ -45,6 +45,7 @@ const fn unstable_fn() {} #[stable(feature = "stable_struct", since = "1.39.0")] // ok! struct Stable; +#[stable(feature = "stable_fn", since = "1.39.0")] #[rustc_const_stable(feature = "stable_fn", since = "1.39.0")] // ok! const fn stable_fn() {} ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0542.md b/compiler/rustc_error_codes/src/error_codes/E0542.md index be186dbd2cc..70590f2e48e 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0542.md +++ b/compiler/rustc_error_codes/src/error_codes/E0542.md @@ -30,6 +30,7 @@ To fix this issue, you need to provide the `since` field. Example: #[stable(feature = "_stable_fn", since = "1.0.0")] // ok! fn _stable_fn() {} +#[stable(feature = "_stable_const_fn", since = "1.0.0")] #[rustc_const_stable(feature = "_stable_const_fn", since = "1.0.0")] // ok! const fn _stable_const_fn() {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0636.md b/compiler/rustc_error_codes/src/error_codes/E0636.md index 57cf72db556..41fd701a8ed 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0636.md +++ b/compiler/rustc_error_codes/src/error_codes/E0636.md @@ -1,9 +1,9 @@ -A `#![feature]` attribute was declared multiple times. +The same feature is enabled multiple times with `#![feature]` attributes Erroneous code example: ```compile_fail,E0636 #![allow(stable_features)] #![feature(rust1)] -#![feature(rust1)] // error: the feature `rust1` has already been declared +#![feature(rust1)] // error: the feature `rust1` has already been enabled ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0667.md b/compiler/rustc_error_codes/src/error_codes/E0667.md index 0709a24c433..339bc068610 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0667.md +++ b/compiler/rustc_error_codes/src/error_codes/E0667.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + `impl Trait` is not allowed in path parameters. Erroneous code example: -```compile_fail,E0667 +```ignore (removed error code) fn some_fn(mut x: impl Iterator) -> ::Item { // error! x.next().unwrap() } @@ -11,7 +13,7 @@ fn some_fn(mut x: impl Iterator) -> ::Item { // error! You cannot use `impl Trait` in path parameters. If you want something equivalent, you can do this instead: -``` +```ignore (removed error code) fn some_fn(mut x: T) -> T::Item { // ok! x.next().unwrap() } diff --git a/compiler/rustc_error_codes/src/error_codes/E0705.md b/compiler/rustc_error_codes/src/error_codes/E0705.md index 317f3a47eff..e7d7d74cc4c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0705.md +++ b/compiler/rustc_error_codes/src/error_codes/E0705.md @@ -1,6 +1,6 @@ #### Note: this error code is no longer emitted by the compiler. -A `#![feature]` attribute was declared for a feature that is stable in the +A `#![feature]` attribute was used for a feature that is stable in the current edition, but not in all editions. Erroneous code example: diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 1adb6b9dcfe..0ccc71ae06c 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -58,9 +58,9 @@ impl HumanReadableErrorType { struct Margin { /// The available whitespace in the left that can be consumed when centering. pub whitespace_left: usize, - /// The column of the beginning of left-most span. + /// The column of the beginning of leftmost span. pub span_left: usize, - /// The column of the end of right-most span. + /// The column of the end of rightmost span. pub span_right: usize, /// The beginning of the line to be displayed. pub computed_left: usize, @@ -128,7 +128,7 @@ impl Margin { } else { 0 }; - // We want to show as much as possible, max_line_len is the right-most boundary for the + // We want to show as much as possible, max_line_len is the rightmost boundary for the // relevant code. self.computed_right = max(max_line_len, self.computed_left); @@ -685,7 +685,7 @@ impl HumanEmitter { buffer.puts(line_offset, code_offset, "...", Style::LineNumber); } if margin.was_cut_right(line_len) { - // We have stripped some code after the right-most span end, make it clear we did so. + // We have stripped some code after the rightmost span end, make it clear we did so. buffer.puts(line_offset, code_offset + taken - 3, "...", Style::LineNumber); } buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber); diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 57bac9d09d5..fcf3352bfc5 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -25,7 +25,7 @@ expand_collapse_debuginfo_illegal = illegal value for attribute #[collapse_debuginfo(no|external|yes)] expand_count_repetition_misplaced = - `count` can not be placed inside the inner-most repetition + `count` can not be placed inside the innermost repetition expand_crate_name_in_cfg_attr = `crate_name` within an `#![cfg_attr]` attribute is forbidden diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index f0cfe133a49..7e4bc508e5c 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1,5 +1,6 @@ use std::default::Default; use std::iter; +use std::path::Component::Prefix; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -865,7 +866,9 @@ impl SyntaxExtension { }) .unwrap_or_else(|| (None, helper_attrs)); let stability = attr::find_stability(sess, attrs, span); - let const_stability = attr::find_const_stability(sess, attrs, span); + // We set `is_const_fn` false to avoid getting any implicit const stability. + let const_stability = + attr::find_const_stability(sess, attrs, span, /* is_const_fn */ false); let body_stability = attr::find_body_stability(sess, attrs); if let Some((_, sp)) = const_stability { sess.dcx().emit_err(errors::MacroConstStability { @@ -1293,7 +1296,12 @@ pub fn resolve_path(sess: &Session, path: impl Into, span: Span) -> PRe base_path.push(path); Ok(base_path) } else { - Ok(path) + // This ensures that Windows verbatim paths are fixed if mixed path separators are used, + // which can happen when `concat!` is used to join paths. + match path.components().next() { + Some(Prefix(prefix)) if prefix.kind().is_verbatim() => Ok(path.components().collect()), + _ => Ok(path), + } } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index ea06415801f..dc6aa110f45 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -11,7 +11,8 @@ use rustc_ast::{ use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_feature::{ - ACCEPTED_FEATURES, AttributeSafety, Features, REMOVED_FEATURES, UNSTABLE_FEATURES, + ACCEPTED_LANG_FEATURES, AttributeSafety, EnabledLangFeature, EnabledLibFeature, Features, + REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES, }; use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::validate_attr; @@ -52,7 +53,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - let mut features = Features::default(); - // Process all features declared in the code. + // Process all features enabled in the code. for attr in krate_attrs { for mi in feature_list(attr) { let name = match mi.ident() { @@ -76,8 +77,8 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - } }; - // If the declared feature has been removed, issue an error. - if let Some(f) = REMOVED_FEATURES.iter().find(|f| name == f.feature.name) { + // If the enabled feature has been removed, issue an error. + if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| name == f.feature.name) { sess.dcx().emit_err(FeatureRemoved { span: mi.span(), reason: f.reason.map(|reason| FeatureRemovedReason { reason }), @@ -85,14 +86,17 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - continue; } - // If the declared feature is stable, record it. - if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { - let since = Some(Symbol::intern(f.since)); - features.set_declared_lang_feature(name, mi.span(), since); + // If the enabled feature is stable, record it. + if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| name == f.name) { + features.set_enabled_lang_feature(EnabledLangFeature { + gate_name: name, + attr_sp: mi.span(), + stable_since: Some(Symbol::intern(f.since)), + }); continue; } - // If `-Z allow-features` is used and the declared feature is + // If `-Z allow-features` is used and the enabled feature is // unstable and not also listed as one of the allowed features, // issue an error. if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() { @@ -102,9 +106,8 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - } } - // If the declared feature is unstable, record it. - if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name) { - (f.set_enabled)(&mut features); + // If the enabled feature is unstable, record it. + if UNSTABLE_LANG_FEATURES.iter().find(|f| name == f.name).is_some() { // When the ICE comes from core, alloc or std (approximation of the standard // library), there's a chance that the person hitting the ICE may be using // -Zbuild-std or similar with an untested target. The bug is probably in the @@ -115,13 +118,19 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - { sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); } - features.set_declared_lang_feature(name, mi.span(), None); + + features.set_enabled_lang_feature(EnabledLangFeature { + gate_name: name, + attr_sp: mi.span(), + stable_since: None, + }); continue; } - // Otherwise, the feature is unknown. Record it as a lib feature. - // It will be checked later. - features.set_declared_lib_feature(name, mi.span()); + // Otherwise, the feature is unknown. Enable it as a lib feature. + // It will be checked later whether the feature really exists. + features + .set_enabled_lib_feature(EnabledLibFeature { gate_name: name, attr_sp: mi.span() }); // Similar to above, detect internal lib features to suppress // the ICE message that asks for a report. @@ -396,7 +405,7 @@ impl<'a> StripUnconfigured<'a> { /// If attributes are not allowed on expressions, emit an error for `attr` #[instrument(level = "trace", skip(self))] pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { - if self.features.is_some_and(|features| !features.stmt_expr_attributes) + if self.features.is_some_and(|features| !features.stmt_expr_attributes()) && !attr.span.allows_unstable(sym::stmt_expr_attributes) { let mut err = feature_err( diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index a872b12e744..5ffafcaa542 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -867,7 +867,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { | Annotatable::FieldDef(..) | Annotatable::Variant(..) => panic!("unexpected annotatable"), }; - if self.cx.ecfg.features.proc_macro_hygiene { + if self.cx.ecfg.features.proc_macro_hygiene() { return; } feature_err( @@ -905,7 +905,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - if !self.cx.ecfg.features.proc_macro_hygiene { + if !self.cx.ecfg.features.proc_macro_hygiene() { annotatable.visit_with(&mut GateProcMacroInput { sess: &self.cx.sess }); } } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index f40f99b6ea1..fcc90c3ce0d 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -3,12 +3,11 @@ use std::collections::hash_map::Entry; use std::{mem, slice}; use ast::token::IdentIsRaw; -use rustc_ast as ast; use rustc_ast::token::NtPatKind::*; use rustc_ast::token::TokenKind::*; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; -use rustc_ast::{DUMMY_NODE_ID, NodeId}; +use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, TransparencyError}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; @@ -370,34 +369,32 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( pub fn compile_declarative_macro( sess: &Session, features: &Features, - def: &ast::Item, + macro_def: &ast::MacroDef, + ident: Ident, + attrs: &[ast::Attribute], + span: Span, + node_id: NodeId, edition: Edition, ) -> (SyntaxExtension, Vec<(usize, Span)>) { - debug!("compile_declarative_macro: {:?}", def); let mk_syn_ext = |expander| { SyntaxExtension::new( sess, features, SyntaxExtensionKind::LegacyBang(expander), - def.span, + span, Vec::new(), edition, - def.ident.name, - &def.attrs, - def.id != DUMMY_NODE_ID, + ident.name, + attrs, + node_id != DUMMY_NODE_ID, ) }; let dummy_syn_ext = |guar| (mk_syn_ext(Box::new(DummyExpander(guar))), Vec::new()); let dcx = sess.dcx(); - let lhs_nm = Ident::new(sym::lhs, def.span); - let rhs_nm = Ident::new(sym::rhs, def.span); + let lhs_nm = Ident::new(sym::lhs, span); + let rhs_nm = Ident::new(sym::rhs, span); let tt_spec = Some(NonterminalKind::TT); - - let macro_def = match &def.kind { - ast::ItemKind::MacroDef(def) => def, - _ => unreachable!(), - }; let macro_rules = macro_def.macro_rules; // Parse the macro_rules! invocation @@ -410,25 +407,22 @@ pub fn compile_declarative_macro( let argument_gram = vec![ mbe::TokenTree::Sequence(DelimSpan::dummy(), mbe::SequenceRepetition { tts: vec![ - mbe::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec), - mbe::TokenTree::token(token::FatArrow, def.span), - mbe::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec), + mbe::TokenTree::MetaVarDecl(span, lhs_nm, tt_spec), + mbe::TokenTree::token(token::FatArrow, span), + mbe::TokenTree::MetaVarDecl(span, rhs_nm, tt_spec), ], - separator: Some(Token::new( - if macro_rules { token::Semi } else { token::Comma }, - def.span, - )), - kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, def.span), + separator: Some(Token::new(if macro_rules { token::Semi } else { token::Comma }, span)), + kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, span), num_captures: 2, }), // to phase into semicolon-termination instead of semicolon-separation mbe::TokenTree::Sequence(DelimSpan::dummy(), mbe::SequenceRepetition { tts: vec![mbe::TokenTree::token( if macro_rules { token::Semi } else { token::Comma }, - def.span, + span, )], separator: None, - kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, def.span), + kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, span), num_captures: 0, }), ]; @@ -460,7 +454,7 @@ pub fn compile_declarative_macro( }; let s = parse_failure_msg(&token, track.get_expected_token()); - let sp = token.span.substitute_dummy(def.span); + let sp = token.span.substitute_dummy(span); let mut err = sess.dcx().struct_span_err(sp, s); err.span_label(sp, msg); annotate_doc_comment(&mut err, sess.source_map(), sp); @@ -468,7 +462,7 @@ pub fn compile_declarative_macro( return dummy_syn_ext(guar); } Error(sp, msg) => { - let guar = sess.dcx().span_err(sp.substitute_dummy(def.span), msg); + let guar = sess.dcx().span_err(sp.substitute_dummy(span), msg); return dummy_syn_ext(guar); } ErrorReported(guar) => { @@ -489,7 +483,7 @@ pub fn compile_declarative_macro( &TokenStream::new(vec![tt.clone()]), true, sess, - def.id, + node_id, features, edition, ) @@ -497,13 +491,13 @@ pub fn compile_declarative_macro( .unwrap(); // We don't handle errors here, the driver will abort // after parsing/expansion. We can report every error in every macro this way. - check_emission(check_lhs_nt_follows(sess, def, &tt)); + check_emission(check_lhs_nt_follows(sess, node_id, &tt)); return tt; } - sess.dcx().span_bug(def.span, "wrong-structured lhs") + sess.dcx().span_bug(span, "wrong-structured lhs") }) .collect::>(), - _ => sess.dcx().span_bug(def.span, "wrong-structured lhs"), + _ => sess.dcx().span_bug(span, "wrong-structured lhs"), }; let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] { @@ -515,17 +509,17 @@ pub fn compile_declarative_macro( &TokenStream::new(vec![tt.clone()]), false, sess, - def.id, + node_id, features, edition, ) .pop() .unwrap(); } - sess.dcx().span_bug(def.span, "wrong-structured rhs") + sess.dcx().span_bug(span, "wrong-structured rhs") }) .collect::>(), - _ => sess.dcx().span_bug(def.span, "wrong-structured rhs"), + _ => sess.dcx().span_bug(span, "wrong-structured rhs"), }; for rhs in &rhses { @@ -537,15 +531,9 @@ pub fn compile_declarative_macro( check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(lhs))); } - check_emission(macro_check::check_meta_variables( - &sess.psess, - def.id, - def.span, - &lhses, - &rhses, - )); + check_emission(macro_check::check_meta_variables(&sess.psess, node_id, span, &lhses, &rhses)); - let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules); + let (transparency, transparency_error) = attr::find_transparency(attrs, macro_rules); match transparency_error { Some(TransparencyError::UnknownTransparency(value, span)) => { dcx.span_err(span, format!("unknown macro transparency: `{value}`")); @@ -564,7 +552,7 @@ pub fn compile_declarative_macro( // Compute the spans of the macro rules for unused rule linting. // Also, we are only interested in non-foreign macros. - let rule_spans = if def.id != DUMMY_NODE_ID { + let rule_spans = if node_id != DUMMY_NODE_ID { lhses .iter() .zip(rhses.iter()) @@ -590,15 +578,15 @@ pub fn compile_declarative_macro( mbe::TokenTree::Delimited(.., delimited) => { mbe::macro_parser::compute_locs(&delimited.tts) } - _ => sess.dcx().span_bug(def.span, "malformed macro lhs"), + _ => sess.dcx().span_bug(span, "malformed macro lhs"), } }) .collect(); let expander = Box::new(MacroRulesMacroExpander { - name: def.ident, - span: def.span, - node_id: def.id, + name: ident, + span, + node_id, transparency, lhses, rhses, @@ -608,13 +596,13 @@ pub fn compile_declarative_macro( fn check_lhs_nt_follows( sess: &Session, - def: &ast::Item, + node_id: NodeId, lhs: &mbe::TokenTree, ) -> Result<(), ErrorGuaranteed> { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. if let mbe::TokenTree::Delimited(.., delimited) = lhs { - check_matcher(sess, def, &delimited.tts) + check_matcher(sess, node_id, &delimited.tts) } else { let msg = "invalid macro matcher; matchers must be contained in balanced delimiters"; Err(sess.dcx().span_err(lhs.span(), msg)) @@ -686,12 +674,12 @@ fn check_rhs(sess: &Session, rhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed fn check_matcher( sess: &Session, - def: &ast::Item, + node_id: NodeId, matcher: &[mbe::TokenTree], ) -> Result<(), ErrorGuaranteed> { let first_sets = FirstSets::new(matcher); let empty_suffix = TokenSet::empty(); - check_matcher_core(sess, def, &first_sets, matcher, &empty_suffix)?; + check_matcher_core(sess, node_id, &first_sets, matcher, &empty_suffix)?; Ok(()) } @@ -1028,7 +1016,7 @@ impl<'tt> TokenSet<'tt> { // see `FirstSets::new`. fn check_matcher_core<'tt>( sess: &Session, - def: &ast::Item, + node_id: NodeId, first_sets: &FirstSets<'tt>, matcher: &'tt [mbe::TokenTree], follow: &TokenSet<'tt>, @@ -1082,7 +1070,7 @@ fn check_matcher_core<'tt>( token::CloseDelim(d.delim), span.close, )); - check_matcher_core(sess, def, first_sets, &d.tts, &my_suffix)?; + check_matcher_core(sess, node_id, first_sets, &d.tts, &my_suffix)?; // don't track non NT tokens last.replace_with_irrelevant(); @@ -1114,7 +1102,7 @@ fn check_matcher_core<'tt>( // At this point, `suffix_first` is built, and // `my_suffix` is some TokenSet that we can use // for checking the interior of `seq_rep`. - let next = check_matcher_core(sess, def, first_sets, &seq_rep.tts, my_suffix)?; + let next = check_matcher_core(sess, node_id, first_sets, &seq_rep.tts, my_suffix)?; if next.maybe_empty { last.add_all(&next); } else { @@ -1144,7 +1132,7 @@ fn check_matcher_core<'tt>( // macro. (See #86567.) // Macros defined in the current crate have a real node id, // whereas macros from an external crate have a dummy id. - if def.id != DUMMY_NODE_ID + if node_id != DUMMY_NODE_ID && matches!(kind, NonterminalKind::Pat(PatParam { inferred: true })) && matches!( next_token, diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index c4ba98f581e..810a5d30c7e 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -23,11 +23,11 @@ pub(crate) enum MetaVarExpr { /// Ignore a meta-variable for repetition without expansion. Ignore(Ident), - /// The index of the repetition at a particular depth, where 0 is the inner-most + /// The index of the repetition at a particular depth, where 0 is the innermost /// repetition. The `usize` is the depth. Index(usize), - /// The length of the repetition at a particular depth, where 0 is the inner-most + /// The length of the repetition at a particular depth, where 0 is the innermost /// repetition. The `usize` is the depth. Len(usize), } diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 2edd289625e..1345f06d5ac 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -119,16 +119,16 @@ pub(super) fn parse( result } -/// Asks for the `macro_metavar_expr` feature if it is not already declared +/// Asks for the `macro_metavar_expr` feature if it is not enabled fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &Session, span: Span) { - if !features.macro_metavar_expr { + if !features.macro_metavar_expr() { let msg = "meta-variable expressions are unstable"; feature_err(sess, sym::macro_metavar_expr, span, msg).emit(); } } fn maybe_emit_macro_metavar_expr_concat_feature(features: &Features, sess: &Session, span: Span) { - if !features.macro_metavar_expr_concat { + if !features.macro_metavar_expr_concat() { let msg = "the `concat` meta-variable expression is unstable"; feature_err(sess, sym::macro_metavar_expr_concat, span, msg).emit(); } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index fb6fe0bb1d7..34811ca2b35 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -570,7 +570,7 @@ fn lockstep_iter_size( } } -/// Used solely by the `count` meta-variable expression, counts the outer-most repetitions at a +/// Used solely by the `count` meta-variable expression, counts the outermost repetitions at a /// given optional nested depth. /// /// For example, a macro parameter of `$( { $( $foo:ident ),* } )*` called with `{ a, b } { c }`: diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 53445804694..ac922f184dd 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -9,7 +9,7 @@ macro_rules! declare_features { $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr), )+) => { /// Formerly unstable features that have now been accepted (stabilized). - pub const ACCEPTED_FEATURES: &[Feature] = &[ + pub const ACCEPTED_LANG_FEATURES: &[Feature] = &[ $(Feature { name: sym::$feature, since: $ver, @@ -364,6 +364,8 @@ declare_features! ( (accepted, self_in_typedefs, "1.32.0", Some(49303)), /// Allows `Self` struct constructor (RFC 2302). (accepted, self_struct_ctor, "1.32.0", Some(51994)), + /// Shortern the tail expression lifetime + (accepted, shorter_tail_lifetimes, "CURRENT_RUSTC_VERSION", Some(123739)), /// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`. (accepted, slice_patterns, "1.42.0", Some(62254)), /// Allows use of `&foo[a..b]` as a slicing syntax. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 477760a4597..0069b07ad62 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -12,33 +12,31 @@ use crate::{Features, Stability}; type GateFn = fn(&Features) -> bool; -macro_rules! cfg_fn { - ($field: ident) => { - (|features| features.$field) as GateFn - }; -} - pub type GatedCfg = (Symbol, Symbol, GateFn); /// `cfg(...)`'s that are feature gated. const GATED_CFGS: &[GatedCfg] = &[ // (name in cfg, feature, function to check if the feature is enabled) - (sym::overflow_checks, sym::cfg_overflow_checks, cfg_fn!(cfg_overflow_checks)), - (sym::ub_checks, sym::cfg_ub_checks, cfg_fn!(cfg_ub_checks)), - (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), + (sym::overflow_checks, sym::cfg_overflow_checks, Features::cfg_overflow_checks), + (sym::ub_checks, sym::cfg_ub_checks, Features::cfg_ub_checks), + (sym::target_thread_local, sym::cfg_target_thread_local, Features::cfg_target_thread_local), ( sym::target_has_atomic_equal_alignment, sym::cfg_target_has_atomic_equal_alignment, - cfg_fn!(cfg_target_has_atomic_equal_alignment), + Features::cfg_target_has_atomic_equal_alignment, ), - (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), - (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)), - (sym::version, sym::cfg_version, cfg_fn!(cfg_version)), - (sym::relocation_model, sym::cfg_relocation_model, cfg_fn!(cfg_relocation_model)), - (sym::sanitizer_cfi_generalize_pointers, sym::cfg_sanitizer_cfi, cfg_fn!(cfg_sanitizer_cfi)), - (sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, cfg_fn!(cfg_sanitizer_cfi)), + ( + sym::target_has_atomic_load_store, + sym::cfg_target_has_atomic, + Features::cfg_target_has_atomic, + ), + (sym::sanitize, sym::cfg_sanitize, Features::cfg_sanitize), + (sym::version, sym::cfg_version, Features::cfg_version), + (sym::relocation_model, sym::cfg_relocation_model, Features::cfg_relocation_model), + (sym::sanitizer_cfi_generalize_pointers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi), + (sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi), // this is consistent with naming of the compiler flag it's for - (sym::fmt_debug, sym::fmt_debug, cfg_fn!(fmt_debug)), + (sym::fmt_debug, sym::fmt_debug, Features::fmt_debug), ]; /// Find a gated cfg determined by the `pred`icate which is given the cfg's name. @@ -220,7 +218,7 @@ macro_rules! gated { safety: AttributeSafety::Unsafe, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), + gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate), } }; (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { @@ -231,7 +229,7 @@ macro_rules! gated { safety: AttributeSafety::Unsafe, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)), + gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr), } }; ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => { @@ -242,7 +240,7 @@ macro_rules! gated { safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), + gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate), } }; ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { @@ -253,7 +251,7 @@ macro_rules! gated { safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)), + gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr), } }; } @@ -282,7 +280,7 @@ macro_rules! rustc_attr { safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)), + gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, Features::rustc_attrs), } }; } @@ -619,11 +617,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ DuplicatesOk, EncodeCrossCrate::Yes, "allow_internal_unstable side-steps feature gating and stability checks", ), - gated!( - rustc_allow_const_fn_unstable, Normal, - template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No, - "rustc_allow_const_fn_unstable side-steps feature gating and stability checks" - ), gated!( allow_internal_unsafe, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint", @@ -841,8 +834,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), rustc_attr!( - rustc_runtime, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, INTERNAL_UNSTABLE + rustc_const_stable_indirect, Normal, + template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL, + ), + gated!( + rustc_allow_const_fn_unstable, Normal, + template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No, + "rustc_allow_const_fn_unstable side-steps feature gating and stability checks" ), // ========================================================================== @@ -935,7 +933,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ Stability::Unstable, sym::rustc_attrs, "diagnostic items compiler internal support for linting", - cfg_fn!(rustc_attrs), + Features::rustc_attrs, ), }, gated!( @@ -1193,7 +1191,7 @@ pub static BUILTIN_ATTRIBUTE_MAP: LazyLock> pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool { match sym { sym::on_unimplemented => true, - sym::do_not_recommend => features.do_not_recommend, + sym::do_not_recommend => features.do_not_recommend(), _ => false, } } diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 8f4c0b0ac95..9f42d3ec45c 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -94,13 +94,13 @@ impl UnstableFeatures { fn find_lang_feature_issue(feature: Symbol) -> Option> { // Search in all the feature lists. - if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| f.feature.name == feature) { - return f.feature.issue; - } - if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| f.name == feature) { + if let Some(f) = UNSTABLE_LANG_FEATURES.iter().find(|f| f.name == feature) { return f.issue; } - if let Some(f) = REMOVED_FEATURES.iter().find(|f| f.feature.name == feature) { + if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature) { + return f.issue; + } + if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| f.feature.name == feature) { return f.feature.issue; } panic!("feature `{feature}` is not declared anywhere"); @@ -127,12 +127,14 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option { /// Formerly unstable features that have now been removed. - pub const REMOVED_FEATURES: &[RemovedFeature] = &[ + pub const REMOVED_LANG_FEATURES: &[RemovedFeature] = &[ $(RemovedFeature { feature: Feature { name: sym::$feature, @@ -85,6 +85,8 @@ declare_features! ( /// Allows default type parameters to influence type inference. (removed, default_type_parameter_fallback, "1.82.0", Some(27336), Some("never properly implemented; requires significant design work")), + /// Allows deriving traits as per `SmartPointer` specification + (removed, derive_smart_pointer, "1.79.0", Some(123430), Some("replaced by `CoercePointee`")), /// Allows using `#[doc(keyword = "...")]`. (removed, doc_keyword, "1.28.0", Some(51315), Some("merged into `#![feature(rustdoc_internals)]`")), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index f4795c75e48..93047d420ad 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -6,11 +6,6 @@ use rustc_span::symbol::{Symbol, sym}; use super::{Feature, to_nonzero}; -pub struct UnstableFeature { - pub feature: Feature, - pub set_enabled: fn(&mut Features), -} - #[derive(PartialEq)] enum FeatureStatus { Default, @@ -30,86 +25,98 @@ macro_rules! status_to_enum { }; } +/// A set of features to be used by later passes. +/// +/// There are two ways to check if a language feature `foo` is enabled: +/// - Directly with the `foo` method, e.g. `if tcx.features().foo() { ... }`. +/// - With the `enabled` method, e.g. `if tcx.features.enabled(sym::foo) { ... }`. +/// +/// The former is preferred. `enabled` should only be used when the feature symbol is not a +/// constant, e.g. a parameter, or when the feature is a library feature. +#[derive(Clone, Default, Debug)] +pub struct Features { + /// `#![feature]` attrs for language features, for error reporting. + enabled_lang_features: Vec, + /// `#![feature]` attrs for non-language (library) features. + enabled_lib_features: Vec, + /// `enabled_lang_features` + `enabled_lib_features`. + enabled_features: FxHashSet, +} + +/// Information about an enabled language feature. +#[derive(Debug, Copy, Clone)] +pub struct EnabledLangFeature { + /// Name of the feature gate guarding the language feature. + pub gate_name: Symbol, + /// Span of the `#[feature(...)]` attribute. + pub attr_sp: Span, + /// If the lang feature is stable, the version number when it was stabilized. + pub stable_since: Option, +} + +/// Information abhout an enabled library feature. +#[derive(Debug, Copy, Clone)] +pub struct EnabledLibFeature { + pub gate_name: Symbol, + pub attr_sp: Span, +} + +impl Features { + /// `since` should be set for stable features that are nevertheless enabled with a `#[feature]` + /// attribute, indicating since when they are stable. + pub fn set_enabled_lang_feature(&mut self, lang_feat: EnabledLangFeature) { + self.enabled_lang_features.push(lang_feat); + self.enabled_features.insert(lang_feat.gate_name); + } + + pub fn set_enabled_lib_feature(&mut self, lib_feat: EnabledLibFeature) { + self.enabled_lib_features.push(lib_feat); + self.enabled_features.insert(lib_feat.gate_name); + } + + /// Returns a list of [`EnabledLangFeature`] with info about: + /// + /// - Feature gate name. + /// - The span of the `#[feature]` attribute. + /// - For stable language features, version info for when it was stabilized. + pub fn enabled_lang_features(&self) -> &Vec { + &self.enabled_lang_features + } + + pub fn enabled_lib_features(&self) -> &Vec { + &self.enabled_lib_features + } + + pub fn enabled_features(&self) -> &FxHashSet { + &self.enabled_features + } + + /// Is the given feature enabled (via `#[feature(...)]`)? + pub fn enabled(&self, feature: Symbol) -> bool { + self.enabled_features.contains(&feature) + } +} + macro_rules! declare_features { ($( $(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr), )+) => { /// Unstable language features that are being implemented or being /// considered for acceptance (stabilization) or removal. - pub const UNSTABLE_FEATURES: &[UnstableFeature] = &[ - $(UnstableFeature { - feature: Feature { - name: sym::$feature, - since: $ver, - issue: to_nonzero($issue), - }, - // Sets this feature's corresponding bool within `features`. - set_enabled: |features| features.$feature = true, + pub const UNSTABLE_LANG_FEATURES: &[Feature] = &[ + $(Feature { + name: sym::$feature, + since: $ver, + issue: to_nonzero($issue), }),+ ]; - const NUM_FEATURES: usize = UNSTABLE_FEATURES.len(); - - /// A set of features to be used by later passes. - #[derive(Clone, Default, Debug)] - pub struct Features { - /// `#![feature]` attrs for language features, for error reporting. - /// "declared" here means that the feature is actually enabled in the current crate. - pub declared_lang_features: Vec<(Symbol, Span, Option)>, - /// `#![feature]` attrs for non-language (library) features. - /// "declared" here means that the feature is actually enabled in the current crate. - pub declared_lib_features: Vec<(Symbol, Span)>, - /// `declared_lang_features` + `declared_lib_features`. - pub declared_features: FxHashSet, - /// Active state of individual features (unstable only). - $( - $(#[doc = $doc])* - pub $feature: bool - ),+ - } - impl Features { - pub fn set_declared_lang_feature( - &mut self, - symbol: Symbol, - span: Span, - since: Option - ) { - self.declared_lang_features.push((symbol, span, since)); - self.declared_features.insert(symbol); - } - - pub fn set_declared_lib_feature(&mut self, symbol: Symbol, span: Span) { - self.declared_lib_features.push((symbol, span)); - self.declared_features.insert(symbol); - } - - /// This is intended for hashing the set of active features. - /// - /// The expectation is that this produces much smaller code than other alternatives. - /// - /// Note that the total feature count is pretty small, so this is not a huge array. - #[inline] - pub fn all_features(&self) -> [u8; NUM_FEATURES] { - [$(self.$feature as u8),+] - } - - /// Is the given feature explicitly declared, i.e. named in a - /// `#![feature(...)]` within the code? - pub fn declared(&self, feature: Symbol) -> bool { - self.declared_features.contains(&feature) - } - - /// Is the given feature active (enabled by the user)? - /// - /// Panics if the symbol doesn't correspond to a declared feature. - pub fn active(&self, feature: Symbol) -> bool { - match feature { - $( sym::$feature => self.$feature, )* - - _ => panic!("`{}` was not listed in `declare_features`", feature), + $( + pub fn $feature(&self) -> bool { + self.enabled_features.contains(&sym::$feature) } - } + )* /// Some features are known to be incomplete and using them is likely to have /// unanticipated results, such as compiler crashes. We warn the user about these @@ -119,8 +126,11 @@ macro_rules! declare_features { $( sym::$feature => status_to_enum!($status) == FeatureStatus::Incomplete, )* - // Accepted/removed features aren't in this file but are never incomplete. - _ if self.declared_features.contains(&feature) => false, + _ if self.enabled_features.contains(&feature) => { + // Accepted/removed features and library features aren't in this file but + // are never incomplete. + false + } _ => panic!("`{}` was not listed in `declare_features`", feature), } } @@ -132,7 +142,7 @@ macro_rules! declare_features { $( sym::$feature => status_to_enum!($status) == FeatureStatus::Internal, )* - _ if self.declared_features.contains(&feature) => { + _ if self.enabled_features.contains(&feature) => { // This could be accepted/removed, or a libs feature. // Accepted/removed features aren't in this file but are never internal // (a removed feature might have been internal, but that's now irrelevant). @@ -440,8 +450,6 @@ declare_features! ( (unstable, deprecated_suggestion, "1.61.0", Some(94785)), /// Allows deref patterns. (incomplete, deref_patterns, "1.79.0", Some(87121)), - /// Allows deriving `SmartPointer` traits - (unstable, derive_smart_pointer, "1.79.0", Some(123430)), /// Controls errors in trait implementations. (unstable, do_not_recommend, "1.67.0", Some(51992)), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. @@ -586,8 +594,6 @@ declare_features! ( (unstable, rust_cold_cc, "1.63.0", Some(97544)), /// Allows use of x86 SHA512, SM3 and SM4 target-features and intrinsics (unstable, sha512_sm_x86, "1.82.0", Some(126624)), - /// Shortern the tail expression lifetime - (unstable, shorter_tail_lifetimes, "1.79.0", Some(123739)), /// Allows the use of SIMD types in functions declared in `extern` blocks. (unstable, simd_ffi, "1.0.0", Some(27731)), /// Allows specialization of implementations (RFC 1210). diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 009c6c4aea5..1c268c8bbe0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -6,8 +6,8 @@ use rustc_ast::{ LitKind, TraitObjectSyntax, UintTy, }; pub use rustc_ast::{ - BinOp, BinOpKind, BindingMode, BorrowKind, ByRef, CaptureBy, ImplPolarity, IsAuto, Movability, - Mutability, UnOp, + BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, + ImplPolarity, IsAuto, Movability, Mutability, UnOp, }; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; @@ -502,19 +502,16 @@ pub enum GenericArgsParentheses { ParenSugar, } -/// A modifier on a trait bound. +/// The modifiers on a trait bound. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] -pub enum TraitBoundModifier { - /// `Type: Trait` - None, - /// `Type: !Trait` - Negative, - /// `Type: ?Trait` - Maybe, - /// `Type: const Trait` - Const, - /// `Type: ~const Trait` - MaybeConst, +pub struct TraitBoundModifiers { + pub constness: BoundConstness, + pub polarity: BoundPolarity, +} + +impl TraitBoundModifiers { + pub const NONE: Self = + TraitBoundModifiers { constness: BoundConstness::Never, polarity: BoundPolarity::Positive }; } #[derive(Clone, Copy, Debug, HashStable_Generic)] @@ -583,7 +580,6 @@ pub enum GenericParamKind<'hir> { ty: &'hir Ty<'hir>, /// Optional default value for the const generic param default: Option<&'hir ConstArg<'hir>>, - is_host_effect: bool, synthetic: bool, }, } @@ -3180,7 +3176,7 @@ pub struct PolyTraitRef<'hir> { /// The constness and polarity of the trait ref. /// /// The `async` modifier is lowered directly into a different trait for now. - pub modifiers: TraitBoundModifier, + pub modifiers: TraitBoundModifiers, /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`. pub trait_ref: TraitRef<'hir>, @@ -4085,7 +4081,7 @@ mod size_asserts { static_assert_size!(ForeignItem<'_>, 88); static_assert_size!(ForeignItemKind<'_>, 56); static_assert_size!(GenericArg<'_>, 16); - static_assert_size!(GenericBound<'_>, 48); + static_assert_size!(GenericBound<'_>, 64); static_assert_size!(Generics<'_>, 56); static_assert_size!(Impl<'_>, 80); static_assert_size!(ImplItem<'_>, 88); diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index ffe519b0e7d..322f8e2a517 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -935,7 +935,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>( match param.kind { GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { ref default, .. } => visit_opt!(visitor, visit_ty, default), - GenericParamKind::Const { ref ty, ref default, is_host_effect: _, synthetic: _ } => { + GenericParamKind::Const { ref ty, ref default, synthetic: _ } => { try_visit!(visitor.visit_ty(ty)); if let Some(ref default) = default { try_visit!(visitor.visit_const_param_default(param.hir_id, default)); diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index b161e6ba0fa..7d81f977c22 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -241,7 +241,7 @@ language_item_table! { DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0); DerefPure, sym::deref_pure, deref_pure_trait, Target::Trait, GenericRequirement::Exact(0); DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None; - Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None; + LegacyReceiver, sym::legacy_receiver, legacy_receiver_trait, Target::Trait, GenericRequirement::None; Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1); FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); @@ -415,14 +415,6 @@ language_item_table! { String, sym::String, string, Target::Struct, GenericRequirement::None; CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None; - - EffectsRuntime, sym::EffectsRuntime, effects_runtime, Target::Struct, GenericRequirement::None; - EffectsNoRuntime, sym::EffectsNoRuntime, effects_no_runtime, Target::Struct, GenericRequirement::None; - EffectsMaybe, sym::EffectsMaybe, effects_maybe, Target::Struct, GenericRequirement::None; - EffectsIntersection, sym::EffectsIntersection, effects_intersection, Target::Trait, GenericRequirement::None; - EffectsIntersectionOutput, sym::EffectsIntersectionOutput, effects_intersection_output, Target::AssocTy, GenericRequirement::None; - EffectsCompat, sym::EffectsCompat, effects_compat, Target::Trait, GenericRequirement::Exact(1); - EffectsTyCompat, sym::EffectsTyCompat, effects_ty_compat, Target::Trait, GenericRequirement::Exact(1); } pub enum GenericRequirement { diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 9a2c38e51e2..09ddc6ca9de 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -1,15 +1,9 @@ //! Bounds are restrictions applied to some types after they've been lowered from the HIR to the //! [`rustc_middle::ty`] form. -use rustc_data_structures::fx::FxIndexMap; use rustc_hir::LangItem; -use rustc_hir::def::DefKind; -use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_span::Span; -use rustc_span::def_id::DefId; - -use crate::hir_ty_lowering::PredicateFilter; /// Collects together a list of type bounds. These lists of bounds occur in many places /// in Rust's syntax: @@ -30,7 +24,6 @@ use crate::hir_ty_lowering::PredicateFilter; #[derive(Default, PartialEq, Eq, Clone, Debug)] pub(crate) struct Bounds<'tcx> { clauses: Vec<(ty::Clause<'tcx>, Span)>, - effects_min_tys: FxIndexMap, Span>, } impl<'tcx> Bounds<'tcx> { @@ -47,12 +40,9 @@ impl<'tcx> Bounds<'tcx> { pub(crate) fn push_trait_bound( &mut self, tcx: TyCtxt<'tcx>, - defining_def_id: DefId, bound_trait_ref: ty::PolyTraitRef<'tcx>, span: Span, polarity: ty::PredicatePolarity, - constness: Option, - predicate_filter: PredicateFilter, ) { let clause = ( bound_trait_ref @@ -68,137 +58,6 @@ impl<'tcx> Bounds<'tcx> { } else { self.clauses.push(clause); } - - // FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else. - // Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated - // type bounds. - if !tcx.features().effects { - return; - } - match predicate_filter { - PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => { - return; - } - PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { - // Ok. - } - } - - // For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the - // associated type of `` and make sure that the effect is compatible. - let compat_val = match (tcx.def_kind(defining_def_id), constness) { - // FIXME(effects): revisit the correctness of this - (_, Some(ty::BoundConstness::Const)) => tcx.consts.false_, - // body owners that can have trait bounds - ( - DefKind::Const | DefKind::Fn | DefKind::AssocFn, - Some(ty::BoundConstness::ConstIfConst), - ) => tcx.expected_host_effect_param_for_body(defining_def_id), - - (_, None) => { - if !tcx.is_const_trait(bound_trait_ref.def_id()) { - return; - } - tcx.consts.true_ - } - (DefKind::Trait, Some(ty::BoundConstness::ConstIfConst)) => { - // we are in a trait, where `bound_trait_ref` could be: - // (1) a super trait `trait Foo: ~const Bar`. - // - This generates `::Effects: TyCompat<::Effects>` - // - // (2) a where clause `where for<..> Something: ~const Bar`. - // - This generates `for<..> ::Effects: TyCompat<::Effects>` - let Some(own_fx) = tcx.associated_type_for_effects(defining_def_id) else { - tcx.dcx().span_delayed_bug(span, "should not have allowed `~const` on a trait that doesn't have `#[const_trait]`"); - return; - }; - let own_fx_ty = Ty::new_projection( - tcx, - own_fx, - ty::GenericArgs::identity_for_item(tcx, own_fx), - ); - let Some(their_fx) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) - else { - tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc"); - return; - }; - let their_fx_ty = - Ty::new_projection(tcx, their_fx, bound_trait_ref.skip_binder().args); - let compat = tcx.require_lang_item(LangItem::EffectsTyCompat, Some(span)); - let clause = bound_trait_ref - .map_bound(|_| { - let trait_ref = ty::TraitRef::new(tcx, compat, [own_fx_ty, their_fx_ty]); - ty::ClauseKind::Trait(ty::TraitPredicate { - trait_ref, - polarity: ty::PredicatePolarity::Positive, - }) - }) - .upcast(tcx); - - self.clauses.push((clause, span)); - return; - } - - (DefKind::Impl { of_trait: true }, Some(ty::BoundConstness::ConstIfConst)) => { - // this is a where clause on an impl header. - // push `::Effects` into the set for the `Min` bound. - let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else { - tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc"); - return; - }; - - let ty = bound_trait_ref - .map_bound(|trait_ref| Ty::new_projection(tcx, assoc, trait_ref.args)); - - // When the user has written `for<'a, T> X<'a, T>: ~const Foo`, replace the - // binders to dummy ones i.e. `X<'static, ()>` so they can be referenced in - // the `Min` associated type properly (which doesn't allow using `for<>`) - // This should work for any bound variables as long as they don't have any - // bounds e.g. `for`. - // FIXME(effects) reconsider this approach to allow compatibility with `for` - let ty = tcx.replace_bound_vars_uncached(ty, FnMutDelegate { - regions: &mut |_| tcx.lifetimes.re_static, - types: &mut |_| tcx.types.unit, - consts: &mut |_| unimplemented!("`~const` does not support const binders"), - }); - - self.effects_min_tys.insert(ty, span); - return; - } - // for - // ``` - // trait Foo { type Bar: ~const Trait } - // ``` - // ensure that `::Effects: TyCompat`. - // - // FIXME(effects) this is equality for now, which wouldn't be helpful for a non-const implementor - // that uses a `Bar` that implements `Trait` with `Maybe` effects. - (DefKind::AssocTy, Some(ty::BoundConstness::ConstIfConst)) => { - // FIXME(effects): implement this - return; - } - // probably illegal in this position. - (_, Some(ty::BoundConstness::ConstIfConst)) => { - tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered"); - return; - } - }; - // create a new projection type `::Effects` - let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else { - tcx.dcx().span_delayed_bug( - span, - "`~const` trait bound has no effect assoc yet no errors encountered?", - ); - return; - }; - let self_ty = Ty::new_projection(tcx, assoc, bound_trait_ref.skip_binder().args); - // make `::Effects: Compat` - let new_trait_ref = - ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::EffectsCompat, Some(span)), [ - ty::GenericArg::from(self_ty), - compat_val.into(), - ]); - self.clauses.push((bound_trait_ref.rebind(new_trait_ref).upcast(tcx), span)); } pub(crate) fn push_projection_bound( @@ -220,15 +79,22 @@ impl<'tcx> Bounds<'tcx> { self.clauses.insert(0, (trait_ref.upcast(tcx), span)); } - pub(crate) fn clauses( - &self, - // FIXME(effects): remove tcx - _tcx: TyCtxt<'tcx>, - ) -> impl Iterator, Span)> + '_ { - self.clauses.iter().cloned() + /// Push a `const` or `~const` bound as a `HostEffect` predicate. + pub(crate) fn push_const_bound( + &mut self, + tcx: TyCtxt<'tcx>, + bound_trait_ref: ty::PolyTraitRef<'tcx>, + host: ty::HostPolarity, + span: Span, + ) { + if tcx.is_const_trait(bound_trait_ref.def_id()) { + self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, host), span)); + } else { + tcx.dcx().span_delayed_bug(span, "tried to lower {host:?} bound for non-const trait"); + } } - pub(crate) fn effects_min_tys(&self) -> impl Iterator> + '_ { - self.effects_min_tys.keys().copied() + pub(crate) fn clauses(&self) -> impl Iterator, Span)> + '_ { + self.clauses.iter().cloned() } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 2aeeb9450ce..97f3f1c8ef2 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1166,7 +1166,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) return; } - if adt.is_union() && !tcx.features().transparent_unions { + if adt.is_union() && !tcx.features().transparent_unions() { feature_err( &tcx.sess, sym::transparent_unions, @@ -1301,7 +1301,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { let repr_type_ty = def.repr().discr_type().to_ty(tcx); if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { - if !tcx.features().repr128 { + if !tcx.features().repr128() { feature_err( &tcx.sess, sym::repr128, 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 75956165e87..9de96b7ba77 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -43,14 +43,13 @@ mod refine; /// - `impl_m`: type of the method we are checking /// - `trait_m`: the method in the trait /// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation +#[instrument(level = "debug", skip(tcx))] pub(super) fn compare_impl_method<'tcx>( tcx: TyCtxt<'tcx>, impl_m: ty::AssocItem, trait_m: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) { - debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref); - let _: Result<_, ErrorGuaranteed> = try { check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?; compare_method_predicate_entailment(tcx, impl_m, trait_m, impl_trait_ref)?; @@ -167,8 +166,6 @@ fn compare_method_predicate_entailment<'tcx>( trait_m: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let trait_to_impl_args = impl_trait_ref.args; - // This node-id should be used for the `body_id` field on each // `ObligationCause` (and the `FnCtxt`). // @@ -183,27 +180,18 @@ fn compare_method_predicate_entailment<'tcx>( kind: impl_m.kind, }); - // Create mapping from impl to placeholder. - let impl_to_placeholder_args = GenericArgs::identity_for_item(tcx, impl_m.def_id); - - // Create mapping from trait to placeholder. - let trait_to_placeholder_args = - impl_to_placeholder_args.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_args); - debug!("compare_impl_method: trait_to_placeholder_args={:?}", trait_to_placeholder_args); + // Create mapping from trait method to impl method. + let impl_def_id = impl_m.container_id(tcx); + let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_m.def_id).rebase_onto( + tcx, + impl_m.container_id(tcx), + impl_trait_ref.args, + ); + debug!(?trait_to_impl_args); let impl_m_predicates = tcx.predicates_of(impl_m.def_id); let trait_m_predicates = tcx.predicates_of(trait_m.def_id); - // Create obligations for each predicate declared by the impl - // definition in the context of the trait's parameter - // environment. We can't just use `impl_env.caller_bounds`, - // however, because we want to replace all late-bound regions with - // region variables. - let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap()); - let mut hybrid_preds = impl_predicates.instantiate_identity(tcx); - - debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); - // This is the only tricky bit of the new way we check implementation methods // We need to build a set of predicates where only the method-level bounds // are from the trait and we assume all other bounds from the implementation @@ -211,25 +199,43 @@ fn compare_method_predicate_entailment<'tcx>( // // We then register the obligations from the impl_m and check to see // if all constraints hold. - hybrid_preds.predicates.extend( - trait_m_predicates - .instantiate_own(tcx, trait_to_placeholder_args) - .map(|(predicate, _)| predicate), + let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap()); + let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates; + hybrid_preds.extend( + trait_m_predicates.instantiate_own(tcx, trait_to_impl_args).map(|(predicate, _)| predicate), ); - // Construct trait parameter environment and then shift it into the placeholder viewpoint. - // The key step here is to update the caller_bounds's predicates to be - // the new hybrid bounds we computed. + // FIXME(effects): This should be replaced with a more dedicated method. + let is_conditionally_const = tcx.is_conditionally_const(impl_def_id); + if is_conditionally_const { + // Augment the hybrid param-env with the const conditions + // of the impl header and the trait method. + hybrid_preds.extend( + tcx.const_conditions(impl_def_id) + .instantiate_identity(tcx) + .into_iter() + .chain( + tcx.const_conditions(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args), + ) + .map(|(trait_ref, _)| { + trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe) + }), + ); + } + let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id); - let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing); + let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); + debug!(caller_bounds=?param_env.caller_bounds()); let infcx = &tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new_with_diagnostics(infcx); - debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds()); - - let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_args); + // Create obligations for each predicate declared by the impl + // definition in the context of the hybrid param-env. This makes + // sure that the impl's method's where clauses are not more + // restrictive than the trait's method (and the impl itself). + let impl_m_own_bounds = impl_m_predicates.instantiate_own_identity(); for (predicate, span) in impl_m_own_bounds { let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id); let predicate = ocx.normalize(&normalize_cause, param_env, predicate); @@ -243,6 +249,34 @@ fn compare_method_predicate_entailment<'tcx>( ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate)); } + // If we're within a const implementation, we need to make sure that the method + // does not assume stronger `~const` bounds than the trait definition. + // + // This registers the `~const` bounds of the impl method, which we will prove + // using the hybrid param-env that we earlier augmented with the const conditions + // from the impl header and trait method declaration. + if is_conditionally_const { + for (const_condition, span) in + tcx.const_conditions(impl_m.def_id).instantiate_own_identity() + { + let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id); + let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition); + + let cause = + ObligationCause::new(span, impl_m_def_id, ObligationCauseCode::CompareImplItem { + impl_item_def_id: impl_m_def_id, + trait_item_def_id: trait_m.def_id, + kind: impl_m.kind, + }); + ocx.register_obligation(traits::Obligation::new( + tcx, + cause, + param_env, + const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + )); + } + } + // We now need to check that the signature of the impl method is // compatible with that of the trait method. We do this by // checking that `impl_fty <: trait_fty`. @@ -256,7 +290,6 @@ fn compare_method_predicate_entailment<'tcx>( // any associated types appearing in the fn arguments or return // type. - // Compute placeholder form of impl and trait method tys. let mut wf_tys = FxIndexSet::default(); let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars( @@ -267,9 +300,9 @@ fn compare_method_predicate_entailment<'tcx>( let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id); let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig); - debug!("compare_impl_method: impl_fty={:?}", impl_sig); + debug!(?impl_sig); - let trait_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_placeholder_args); + let trait_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_impl_args); let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig); // Next, add all inputs and output as well-formed tys. Importantly, @@ -280,9 +313,7 @@ fn compare_method_predicate_entailment<'tcx>( // We also have to add the normalized trait signature // as we don't normalize during implied bounds computation. wf_tys.extend(trait_sig.inputs_and_output.iter()); - let trait_fty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(trait_sig)); - - debug!("compare_impl_method: trait_fty={:?}", trait_fty); + debug!(?trait_sig); // FIXME: We'd want to keep more accurate spans than "the method signature" when // processing the comparison between the trait and impl fn, but we sadly lose them @@ -298,6 +329,7 @@ fn compare_method_predicate_entailment<'tcx>( let emitted = report_trait_method_mismatch( infcx, cause, + param_env, terr, (trait_m, trait_sig), (impl_m, impl_sig), @@ -455,8 +487,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // just so we don't ICE during instantiation later. check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?; - let trait_to_impl_args = impl_trait_ref.args; - let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id); let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span(); let cause = @@ -466,18 +496,18 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( kind: impl_m.kind, }); - // Create mapping from impl to placeholder. - let impl_to_placeholder_args = GenericArgs::identity_for_item(tcx, impl_m.def_id); - - // Create mapping from trait to placeholder. - let trait_to_placeholder_args = - impl_to_placeholder_args.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_args); + // Create mapping from trait to impl (i.e. impl trait header + impl method identity args). + let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_m.def_id).rebase_onto( + tcx, + impl_m.container_id(tcx), + impl_trait_ref.args, + ); let hybrid_preds = tcx .predicates_of(impl_m.container_id(tcx)) .instantiate_identity(tcx) .into_iter() - .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_to_placeholder_args)) + .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args)) .map(|(clause, _)| clause); let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error( @@ -511,7 +541,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( .instantiate_binder_with_fresh_vars( return_span, infer::HigherRankedType, - tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_placeholder_args), + tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_impl_args), ) .fold_with(&mut collector); @@ -581,7 +611,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( Err(terr) => { let mut diag = struct_span_code_err!( tcx.dcx(), - cause.span(), + cause.span, E0053, "method `{}` has an incompatible return type for trait", trait_m.name @@ -593,10 +623,10 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( hir.get_if_local(impl_m.def_id) .and_then(|node| node.fn_decl()) .map(|decl| (decl.output.span(), Cow::from("return type in trait"), false)), - Some(infer::ValuePairs::Terms(ExpectedFound { + Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound { expected: trait_return_ty.into(), found: impl_return_ty.into(), - })), + }))), terr, false, ); @@ -620,6 +650,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let emitted = report_trait_method_mismatch( infcx, cause, + param_env, terr, (trait_m, trait_sig), (impl_m, impl_sig), @@ -705,7 +736,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // Also, we only need to account for a difference in trait and impl args, // since we previously enforce that the trait method and impl method have the // same generics. - let num_trait_args = trait_to_impl_args.len(); + let num_trait_args = impl_trait_ref.args.len(); let num_impl_args = tcx.generics_of(impl_m.container_id(tcx)).own_params.len(); let ty = match ty.try_fold_with(&mut RemapHiddenTyRegions { tcx, @@ -933,6 +964,7 @@ impl<'tcx> ty::FallibleTypeFolder> for RemapHiddenTyRegions<'tcx> { fn report_trait_method_mismatch<'tcx>( infcx: &InferCtxt<'tcx>, mut cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, terr: TypeError<'tcx>, (trait_m, trait_sig): (ty::AssocItem, ty::FnSig<'tcx>), (impl_m, impl_sig): (ty::AssocItem, ty::FnSig<'tcx>), @@ -1018,10 +1050,10 @@ fn report_trait_method_mismatch<'tcx>( &mut diag, &cause, trait_err_span.map(|sp| (sp, Cow::from("type in trait"), false)), - Some(infer::ValuePairs::PolySigs(ExpectedFound { + Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound { expected: ty::Binder::dummy(trait_sig), found: ty::Binder::dummy(impl_sig), - })), + }))), terr, false, ); @@ -1041,12 +1073,7 @@ fn check_region_bounds_on_impl_item<'tcx>( let trait_generics = tcx.generics_of(trait_m.def_id); let trait_params = trait_generics.own_counts().lifetimes; - debug!( - "check_region_bounds_on_impl_item: \ - trait_generics={:?} \ - impl_generics={:?}", - trait_generics, impl_generics - ); + debug!(?trait_generics, ?impl_generics); // Must have same number of early-bound lifetime parameters. // Unfortunately, if the user screws up the bounds, then this @@ -1142,7 +1169,7 @@ fn extract_spans_for_error_reporting<'tcx>( TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => { (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i))) } - _ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)), + _ => (cause.span, tcx.hir().span_if_local(trait_m.def_id)), } } @@ -1710,8 +1737,7 @@ pub(super) fn compare_impl_const_raw( let trait_const_item = tcx.associated_item(trait_const_item_def); let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().instantiate_identity(); - - debug!("compare_impl_const(impl_trait_ref={:?})", impl_trait_ref); + debug!(?impl_trait_ref); compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?; compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?; @@ -1722,6 +1748,7 @@ pub(super) fn compare_impl_const_raw( /// The equivalent of [compare_method_predicate_entailment], but for associated constants /// instead of associated functions. // FIXME(generic_const_items): If possible extract the common parts of `compare_{type,const}_predicate_entailment`. +#[instrument(level = "debug", skip(tcx))] fn compare_const_predicate_entailment<'tcx>( tcx: TyCtxt<'tcx>, impl_ct: ty::AssocItem, @@ -1736,13 +1763,14 @@ fn compare_const_predicate_entailment<'tcx>( // because we shouldn't really have to deal with lifetimes or // predicates. In fact some of this should probably be put into // shared functions because of DRY violations... - let impl_args = GenericArgs::identity_for_item(tcx, impl_ct.def_id); - let trait_to_impl_args = - impl_args.rebase_onto(tcx, impl_ct.container_id(tcx), impl_trait_ref.args); + let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_ct.def_id).rebase_onto( + tcx, + impl_ct.container_id(tcx), + impl_trait_ref.args, + ); // Create a parameter environment that represents the implementation's - // method. - // Compute placeholder form of impl and trait const tys. + // associated const. let impl_ty = tcx.type_of(impl_ct_def_id).instantiate_identity(); let trait_ty = tcx.type_of(trait_ct.def_id).instantiate(tcx, trait_to_impl_args); @@ -1759,14 +1787,14 @@ fn compare_const_predicate_entailment<'tcx>( // The predicates declared by the impl definition, the trait and the // associated const in the trait are assumed. let impl_predicates = tcx.predicates_of(impl_ct_predicates.parent.unwrap()); - let mut hybrid_preds = impl_predicates.instantiate_identity(tcx); - hybrid_preds.predicates.extend( + let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates; + hybrid_preds.extend( trait_ct_predicates .instantiate_own(tcx, trait_to_impl_args) .map(|(predicate, _)| predicate), ); - let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing); + let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error( tcx, param_env, @@ -1776,7 +1804,7 @@ fn compare_const_predicate_entailment<'tcx>( let infcx = tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - let impl_ct_own_bounds = impl_ct_predicates.instantiate_own(tcx, impl_args); + let impl_ct_own_bounds = impl_ct_predicates.instantiate_own_identity(); for (predicate, span) in impl_ct_own_bounds { let cause = ObligationCause::misc(span, impl_ct_def_id); let predicate = ocx.normalize(&cause, param_env, predicate); @@ -1787,20 +1815,15 @@ fn compare_const_predicate_entailment<'tcx>( // There is no "body" here, so just pass dummy id. let impl_ty = ocx.normalize(&cause, param_env, impl_ty); - - debug!("compare_const_impl: impl_ty={:?}", impl_ty); + debug!(?impl_ty); let trait_ty = ocx.normalize(&cause, param_env, trait_ty); - - debug!("compare_const_impl: trait_ty={:?}", trait_ty); + debug!(?trait_ty); let err = ocx.sup(&cause, param_env, trait_ty, impl_ty); if let Err(terr) = err { - debug!( - "checking associated const for compatibility: impl ty {:?}, trait ty {:?}", - impl_ty, trait_ty - ); + debug!(?impl_ty, ?trait_ty); // Locate the Span containing just the type of the offending impl let (ty, _) = tcx.hir().expect_impl_item(impl_ct_def_id).expect_const(); @@ -1824,10 +1847,10 @@ fn compare_const_predicate_entailment<'tcx>( &mut diag, &cause, trait_c_span.map(|span| (span, Cow::from("type in trait"), false)), - Some(infer::ValuePairs::Terms(ExpectedFound { + Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound { expected: trait_ty.into(), found: impl_ty.into(), - })), + }))), terr, false, ); @@ -1845,14 +1868,13 @@ fn compare_const_predicate_entailment<'tcx>( ocx.resolve_regions_and_report_errors(impl_ct_def_id, &outlives_env) } +#[instrument(level = "debug", skip(tcx))] pub(super) fn compare_impl_ty<'tcx>( tcx: TyCtxt<'tcx>, impl_ty: ty::AssocItem, trait_ty: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) { - debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref); - let _: Result<(), ErrorGuaranteed> = try { compare_number_of_generics(tcx, impl_ty, trait_ty, false)?; compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?; @@ -1864,20 +1886,25 @@ pub(super) fn compare_impl_ty<'tcx>( /// The equivalent of [compare_method_predicate_entailment], but for associated types /// instead of associated functions. +#[instrument(level = "debug", skip(tcx))] fn compare_type_predicate_entailment<'tcx>( tcx: TyCtxt<'tcx>, impl_ty: ty::AssocItem, trait_ty: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let impl_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id); - let trait_to_impl_args = - impl_args.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.args); + let impl_def_id = impl_ty.container_id(tcx); + let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id).rebase_onto( + tcx, + impl_def_id, + impl_trait_ref.args, + ); let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id); let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id); - let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_args); + let impl_ty_own_bounds = impl_ty_predicates.instantiate_own_identity(); + // If there are no bounds, then there are no const conditions, so no need to check that here. if impl_ty_own_bounds.len() == 0 { // Nothing to check. return Ok(()); @@ -1887,29 +1914,46 @@ fn compare_type_predicate_entailment<'tcx>( // `ObligationCause` (and the `FnCtxt`). This is what // `regionck_item` expects. let impl_ty_def_id = impl_ty.def_id.expect_local(); - debug!("compare_type_predicate_entailment: trait_to_impl_args={:?}", trait_to_impl_args); + debug!(?trait_to_impl_args); // The predicates declared by the impl definition, the trait and the // associated type in the trait are assumed. let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap()); - let mut hybrid_preds = impl_predicates.instantiate_identity(tcx); - hybrid_preds.predicates.extend( + let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates; + hybrid_preds.extend( trait_ty_predicates .instantiate_own(tcx, trait_to_impl_args) .map(|(predicate, _)| predicate), ); - - debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds); + debug!(?hybrid_preds); let impl_ty_span = tcx.def_span(impl_ty_def_id); let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id); - let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing); + + let is_conditionally_const = tcx.is_conditionally_const(impl_ty.def_id); + if is_conditionally_const { + // Augment the hybrid param-env with the const conditions + // of the impl header and the trait assoc type. + hybrid_preds.extend( + tcx.const_conditions(impl_ty_predicates.parent.unwrap()) + .instantiate_identity(tcx) + .into_iter() + .chain( + tcx.const_conditions(trait_ty.def_id).instantiate_own(tcx, trait_to_impl_args), + ) + .map(|(trait_ref, _)| { + trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe) + }), + ); + } + + let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); + debug!(caller_bounds=?param_env.caller_bounds()); + let infcx = tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds()); - for (predicate, span) in impl_ty_own_bounds { let cause = ObligationCause::misc(span, impl_ty_def_id); let predicate = ocx.normalize(&cause, param_env, predicate); @@ -1923,6 +1967,29 @@ fn compare_type_predicate_entailment<'tcx>( ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate)); } + if is_conditionally_const { + // Validate the const conditions of the impl associated type. + let impl_ty_own_const_conditions = + tcx.const_conditions(impl_ty.def_id).instantiate_own_identity(); + for (const_condition, span) in impl_ty_own_const_conditions { + let normalize_cause = traits::ObligationCause::misc(span, impl_ty_def_id); + let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition); + + let cause = + ObligationCause::new(span, impl_ty_def_id, ObligationCauseCode::CompareImplItem { + impl_item_def_id: impl_ty_def_id, + trait_item_def_id: trait_ty.def_id, + kind: impl_ty.kind, + }); + ocx.register_obligation(traits::Obligation::new( + tcx, + cause, + param_env, + const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + )); + } + } + // Check that all obligations are satisfied by the implementation's // version. let errors = ocx.select_all_or_error(); @@ -2005,15 +2072,31 @@ pub(super) fn check_type_bounds<'tcx>( ObligationCause::new(impl_ty_span, impl_ty_def_id, code) }; - let obligations: Vec<_> = tcx + let mut obligations: Vec<_> = tcx .explicit_item_bounds(trait_ty.def_id) .iter_instantiated_copied(tcx, rebased_args) .map(|(concrete_ty_bound, span)| { - debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound); + debug!(?concrete_ty_bound); traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound) }) .collect(); - debug!("check_type_bounds: item_bounds={:?}", obligations); + + // 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) + .iter_instantiated_copied(tcx, rebased_args) + .map(|(c, span)| { + traits::Obligation::new( + tcx, + mk_cause(span), + param_env, + c.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + ) + }), + ); + } + debug!(item_bounds=?obligations); // Normalize predicates with the assumption that the GAT may always normalize // to its definition type. This should be the param-env we use to *prove* the @@ -2032,7 +2115,7 @@ pub(super) fn check_type_bounds<'tcx>( } else { ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate) }; - debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); + debug!(?normalized_predicate); obligation.predicate = normalized_predicate; ocx.register_obligation(obligation); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 06317a3b304..c75bdcec388 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -58,15 +58,9 @@ fn equate_intrinsic_type<'tcx>( // the host effect param should be invisible as it shouldn't matter // whether effects is enabled for the intrinsic provider crate. - let consts_count = if generics.host_effect_index.is_some() { - own_counts.consts - 1 - } else { - own_counts.consts - }; - if gen_count_ok(own_counts.lifetimes, n_lts, "lifetime") && gen_count_ok(own_counts.types, n_tps, "type") - && gen_count_ok(consts_count, n_cts, "const") + && gen_count_ok(own_counts.consts, n_cts, "const") { let _ = check_function_signature( tcx, diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 959b17b2d40..58210aaa066 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -612,7 +612,7 @@ pub fn check_function_signature<'tcx>( match err { TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(), - _ => cause.span(), + _ => cause.span, } } @@ -646,10 +646,10 @@ pub fn check_function_signature<'tcx>( &mut diag, &cause, None, - Some(infer::ValuePairs::PolySigs(ExpectedFound { + Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound { expected: expected_sig, found: actual_sig, - })), + }))), err, false, ); diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 1a5f4659812..bfa088fdefc 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -167,9 +167,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h } } if let Some(tail_expr) = blk.expr { - if visitor.tcx.features().shorter_tail_lifetimes - && blk.span.edition().at_least_rust_2024() - { + if blk.span.edition().at_least_rust_2024() { visitor.terminating_scopes.insert(tail_expr.hir_id.local_id); } visitor.visit_expr(tail_expr); @@ -466,7 +464,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h hir::ExprKind::If(cond, then, Some(otherwise)) => { let expr_cx = visitor.cx; - let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope { + let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope() + { ScopeData::IfThenRescope } else { ScopeData::IfThen @@ -481,7 +480,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h hir::ExprKind::If(cond, then, None) => { let expr_cx = visitor.cx; - let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope { + let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope() + { ScopeData::IfThenRescope } else { ScopeData::IfThen diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index f788456d4e9..499e42d31c9 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -32,7 +32,8 @@ use rustc_trait_selection::traits::misc::{ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ - self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, + self, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt, + WellFormedLoc, }; use rustc_type_ir::TypeFlags; use rustc_type_ir::solve::NoSolution; @@ -86,7 +87,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { self.body_def_id, ObligationCauseCode::WellFormed(loc), ); - self.ocx.register_obligation(traits::Obligation::new( + self.ocx.register_obligation(Obligation::new( self.tcx(), cause, self.param_env, @@ -110,7 +111,7 @@ where let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env }; - if !tcx.features().trivial_bounds { + if !tcx.features().trivial_bounds() { wfcx.check_false_global_bounds() } f(&mut wfcx)?; @@ -913,15 +914,10 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()), // Const parameters are well formed if their type is structural match. - hir::GenericParamKind::Const { - ty: hir_ty, - default: _, - is_host_effect: _, - synthetic: _, - } => { + hir::GenericParamKind::Const { ty: hir_ty, default: _, synthetic: _ } => { let ty = tcx.type_of(param.def_id).instantiate_identity(); - if tcx.features().unsized_const_params { + if tcx.features().unsized_const_params() { enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| { wfcx.register_bound( ObligationCause::new( @@ -935,7 +931,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ); Ok(()) }) - } else if tcx.features().adt_const_params { + } else if tcx.features().adt_const_params() { enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| { wfcx.register_bound( ObligationCause::new( @@ -1178,7 +1174,7 @@ fn check_type_defn<'tcx>( wfcx.body_def_id, ObligationCauseCode::Misc, ); - wfcx.register_obligation(traits::Obligation::new( + wfcx.register_obligation(Obligation::new( tcx, cause, wfcx.param_env, @@ -1374,6 +1370,30 @@ fn check_impl<'tcx>( obligation.cause.span = hir_self_ty.span; } } + + // Ensure that the `~const` where clauses of the trait hold for the impl. + if tcx.is_conditionally_const(item.owner_id.def_id) { + for (bound, _) in + tcx.const_conditions(trait_ref.def_id).instantiate(tcx, trait_ref.args) + { + let bound = wfcx.normalize( + item.span, + Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)), + bound, + ); + wfcx.register_obligation(Obligation::new( + tcx, + ObligationCause::new( + hir_self_ty.span, + wfcx.body_def_id, + ObligationCauseCode::WellFormed(None), + ), + wfcx.param_env, + bound.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + )) + } + } + debug!(?obligations); wfcx.register_obligations(obligations); } @@ -1566,7 +1586,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id wfcx.body_def_id, ObligationCauseCode::WhereClause(def_id.to_def_id(), DUMMY_SP), ); - traits::Obligation::new(tcx, cause, wfcx.param_env, pred) + Obligation::new(tcx, cause, wfcx.param_env, pred) }); let predicates = predicates.instantiate_identity(tcx); @@ -1698,9 +1718,9 @@ fn check_method_receiver<'tcx>( return Ok(()); } - let arbitrary_self_types_level = if tcx.features().arbitrary_self_types_pointers { + let arbitrary_self_types_level = if tcx.features().arbitrary_self_types_pointers() { Some(ArbitrarySelfTypesLevel::WithPointers) - } else if tcx.features().arbitrary_self_types { + } else if tcx.features().arbitrary_self_types() { Some(ArbitrarySelfTypesLevel::Basic) } else { None @@ -1801,7 +1821,7 @@ fn receiver_is_valid<'tcx>( autoderef = autoderef.include_raw_pointers(); } - let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, Some(span)); + let receiver_trait_def_id = tcx.require_lang_item(LangItem::LegacyReceiver, Some(span)); // Keep dereferencing `receiver_ty` until we get to `self_ty`. while let Some((potential_self_ty, _)) = autoderef.next() { @@ -1857,7 +1877,7 @@ fn receiver_is_implemented<'tcx>( let tcx = wfcx.tcx(); let trait_ref = ty::TraitRef::new(tcx, receiver_trait_def_id, [receiver_ty]); - let obligation = traits::Obligation::new(tcx, cause, wfcx.param_env, trait_ref); + let obligation = Obligation::new(tcx, cause, wfcx.param_env, trait_ref); if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) { true @@ -2193,7 +2213,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { .unwrap_or(obligation_span); } - let obligation = traits::Obligation::new( + let obligation = Obligation::new( tcx, traits::ObligationCause::new( span, diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 76c75d976ee..b4f6b5a9dd2 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -364,6 +364,7 @@ pub(crate) fn coerce_unsized_info<'tcx>( .err_ctxt() .report_mismatched_types( &cause, + param_env, mk_ptr(mt_b.ty), target, ty::error::TypeError::Mutability, diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index dfb3c088afb..2afc2aec1ba 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -77,7 +77,7 @@ impl<'tcx> InherentCollect<'tcx> { return Ok(()); } - if self.tcx.features().rustc_attrs { + if self.tcx.features().rustc_attrs() { let items = self.tcx.associated_item_def_ids(impl_def_id); if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) { @@ -115,7 +115,7 @@ impl<'tcx> InherentCollect<'tcx> { ) -> Result<(), ErrorGuaranteed> { let items = self.tcx.associated_item_def_ids(impl_def_id); if !self.tcx.hir().rustc_coherence_is_core() { - if self.tcx.features().rustc_attrs { + if self.tcx.features().rustc_attrs() { for &impl_item in items { if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) { let span = self.tcx.def_span(impl_def_id); diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index eea5a16ac6f..3aad4bafeb5 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -53,7 +53,7 @@ fn enforce_trait_manually_implementable( ) -> Result<(), ErrorGuaranteed> { let impl_header_span = tcx.def_span(impl_def_id); - if tcx.is_lang_item(trait_def_id, LangItem::Freeze) && !tcx.features().freeze_impls { + if tcx.is_lang_item(trait_def_id, LangItem::Freeze) && !tcx.features().freeze_impls() { feature_err( &tcx.sess, sym::freeze_impls, @@ -86,8 +86,8 @@ fn enforce_trait_manually_implementable( if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable = trait_def.specialization_kind { - if !tcx.features().specialization - && !tcx.features().min_specialization + if !tcx.features().specialization() + && !tcx.features().min_specialization() && !impl_header_span.allows_unstable(sym::specialization) && !impl_header_span.allows_unstable(sym::min_specialization) { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f63e2d40e39..3add801cf56 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -77,6 +77,8 @@ pub fn provide(providers: &mut Providers) { explicit_supertraits_containing_assoc_item: 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, type_param_predicates: predicates_of::type_param_predicates, trait_def, adt_def, @@ -1129,7 +1131,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { }; let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar); - if paren_sugar && !tcx.features().unboxed_closures { + if paren_sugar && !tcx.features().unboxed_closures() { tcx.dcx().emit_err(errors::ParenSugarAttribute { span: item.span }); } @@ -1595,7 +1597,7 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option( // Feature gate SIMD types in FFI, since I am not sure that the // ABIs are handled at all correctly. -huonw - if abi != abi::Abi::RustIntrinsic && !tcx.features().simd_ffi { + if abi != abi::Abi::RustIntrinsic && !tcx.features().simd_ffi() { let check = |hir_ty: &hir::Ty<'_>, ty: Ty<'_>| { if ty.is_simd() { let snip = tcx diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 14b6b17ed18..3eec0e12665 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -53,7 +53,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param_def_id_to_index, has_self: opaque_ty_generics.has_self, has_late_bound_regions: opaque_ty_generics.has_late_bound_regions, - host_effect_index: parent_generics.host_effect_index, }; } @@ -109,7 +108,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // We do not allow generic parameters in anon consts if we are inside // of a const parameter type, e.g. `struct Foo` is not allowed. None - } else if tcx.features().generic_const_exprs { + } else if tcx.features().generic_const_exprs() { let parent_node = tcx.parent_hir_node(hir_id); debug!(?parent_node); if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node @@ -161,7 +160,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param_def_id_to_index, has_self: generics.has_self, has_late_bound_regions: generics.has_late_bound_regions, - host_effect_index: None, }; } else { // HACK(eddyb) this provides the correct generics when @@ -292,12 +290,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let has_self = opt_self.is_some(); let mut parent_has_self = false; let mut own_start = has_self as u32; - let mut host_effect_index = None; let parent_count = parent_def_id.map_or(0, |def_id| { let generics = tcx.generics_of(def_id); assert!(!has_self); parent_has_self = generics.has_self; - host_effect_index = generics.host_effect_index; own_start = generics.count() as u32; generics.parent_count + generics.own_params.len() }); @@ -361,12 +357,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { kind, }) } - GenericParamKind::Const { ty: _, default, is_host_effect, synthetic } => { - if !matches!(allow_defaults, Defaults::Allowed) - && default.is_some() - // `host` effect params are allowed to have defaults. - && !is_host_effect - { + GenericParamKind::Const { ty: _, default, synthetic } => { + if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() { tcx.dcx().span_err( param.span, "defaults for const parameters are only allowed in \ @@ -376,27 +368,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let index = next_index(); - if is_host_effect { - if let Some(idx) = host_effect_index { - tcx.dcx().span_delayed_bug( - param.span, - format!("parent also has host effect param? index: {idx}, def: {def_id:?}"), - ); - } - - host_effect_index = Some(index as usize); - } - Some(ty::GenericParamDef { index, name: param.name.ident().name, def_id: param.def_id.to_def_id(), pure_wrt_drop: param.pure_wrt_drop, - kind: ty::GenericParamDefKind::Const { - has_default: default.is_some(), - is_host_effect, - synthetic, - }, + kind: ty::GenericParamDefKind::Const { has_default: default.is_some(), synthetic }, }) } })); @@ -459,7 +436,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param_def_id_to_index, has_self: has_self || parent_has_self, has_late_bound_regions: has_late_bound_regions(tcx, node), - host_effect_index, } } @@ -540,8 +516,7 @@ impl<'v> Visitor<'v> for AnonConstInParamTyDetector { type Result = ControlFlow<()>; fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result { - if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind - { + if let GenericParamKind::Const { ty, default: _, synthetic: _ } = p.kind { let prev = self.in_param_ty; self.in_param_ty = true; let res = self.visit_ty(ty); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 69ebd3a928a..b2ad42be6c7 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -40,7 +40,16 @@ fn associated_type_bounds<'tcx>( let mut bounds = Bounds::default(); icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter); // Associated types are implicitly sized unless a `?Sized` bound is found - icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); + match filter { + PredicateFilter::All + | PredicateFilter::SelfOnly + | PredicateFilter::SelfThatDefines(_) + | PredicateFilter::SelfAndAssociatedTypeBounds => { + icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); + } + // `ConstIfConst` is only interested in `~const` bounds. + PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} + } let trait_def_id = tcx.local_parent(assoc_item_def_id); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); @@ -58,7 +67,7 @@ fn associated_type_bounds<'tcx>( ) }); - let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent)); + let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent)); debug!( "associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id.to_def_id()), @@ -109,10 +118,19 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( } else { // Only collect *self* type bounds if the filter is for self. match filter { - PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => { + PredicateFilter::All => {} + PredicateFilter::SelfOnly => { return None; } - PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {} + PredicateFilter::SelfThatDefines(_) + | PredicateFilter::SelfConstIfConst + | PredicateFilter::SelfAndAssociatedTypeBounds + | PredicateFilter::ConstIfConst => { + unreachable!( + "invalid predicate filter for \ + `remap_gat_vars_and_recurse_into_nested_projections`" + ) + } } clause_ty = alias_ty.self_ty(); @@ -308,10 +326,20 @@ fn opaque_type_bounds<'tcx>( let mut bounds = Bounds::default(); icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter); // Opaque types are implicitly sized unless a `?Sized` bound is found - icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); + match filter { + PredicateFilter::All + | PredicateFilter::SelfOnly + | PredicateFilter::SelfThatDefines(_) + | PredicateFilter::SelfAndAssociatedTypeBounds => { + // Associated types are implicitly sized unless a `?Sized` bound is found + icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); + } + //`ConstIfConst` is only interested in `~const` bounds. + PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} + } debug!(?bounds); - tcx.arena.alloc_from_iter(bounds.clauses(tcx)) + tcx.arena.alloc_from_iter(bounds.clauses()) }) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 9bd8c70dcfe..644ff0c667c 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -12,6 +12,7 @@ use rustc_span::symbol::Ident; use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument, trace}; +use super::item_bounds::explicit_item_bounds_with_filter; use crate::bounds::Bounds; use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; @@ -78,7 +79,6 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic #[instrument(level = "trace", skip(tcx), ret)] fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> { use rustc_hir::*; - use rustc_middle::ty::Ty; match tcx.opt_rpitit_info(def_id.to_def_id()) { Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) => { @@ -106,7 +106,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen return ty::GenericPredicates { parent: Some(tcx.parent(def_id.to_def_id())), predicates: tcx.arena.alloc_from_iter(predicates), - effects_min_tys: ty::List::empty(), }; } @@ -128,7 +127,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen return ty::GenericPredicates { parent: Some(impl_def_id), predicates: tcx.arena.alloc_from_iter(impl_predicates), - effects_min_tys: ty::List::empty(), }; } @@ -154,7 +152,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // We use an `IndexSet` to preserve order of insertion. // Preserving the order of insertion is important here so as not to break UI tests. let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default(); - let mut effects_min_tys = Vec::new(); let hir_generics = node.generics().unwrap_or(NO_GENERICS); if let Node::Item(item) = node { @@ -189,8 +186,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen ty::List::empty(), PredicateFilter::All, ); - predicates.extend(bounds.clauses(tcx)); - effects_min_tys.extend(bounds.effects_min_tys()); + predicates.extend(bounds.clauses()); } // In default impls, we can assume that the self type implements @@ -223,7 +219,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen param.span, ); trace!(?bounds); - predicates.extend(bounds.clauses(tcx)); + predicates.extend(bounds.clauses()); trace!(?predicates); } hir::GenericParamKind::Const { .. } => { @@ -275,8 +271,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen bound_vars, PredicateFilter::All, ); - predicates.extend(bounds.clauses(tcx)); - effects_min_tys.extend(bounds.effects_min_tys()); + predicates.extend(bounds.clauses()); } hir::WherePredicate::RegionPredicate(region_pred) => { @@ -308,7 +303,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } } - if tcx.features().generic_const_exprs { + if tcx.features().generic_const_exprs() { predicates.extend(const_evaluatable_predicates_of(tcx, def_id)); } @@ -345,30 +340,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen debug!(?predicates); } - // add `Self::Effects: Compat` to ensure non-const impls don't get called - // in const contexts. - if let Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(..), .. }) = node - && let Some(host_effect_index) = generics.host_effect_index - { - let parent = generics.parent.unwrap(); - let Some(assoc_def_id) = tcx.associated_type_for_effects(parent) else { - bug!("associated_type_for_effects returned None when there is host effect in generics"); - }; - let effects = - Ty::new_projection(tcx, assoc_def_id, ty::GenericArgs::identity_for_item(tcx, parent)); - let param = generics.param_at(host_effect_index, tcx); - let span = tcx.def_span(param.def_id); - let host = ty::Const::new_param(tcx, ty::ParamConst::for_def(param)); - let compat = tcx.require_lang_item(LangItem::EffectsCompat, Some(span)); - let trait_ref = - ty::TraitRef::new(tcx, compat, [ty::GenericArg::from(effects), host.into()]); - predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span)); - } - ty::GenericPredicates { parent: generics.parent, predicates: tcx.arena.alloc_from_iter(predicates), - effects_min_tys: tcx.mk_type_list(&effects_min_tys), } } @@ -519,12 +493,11 @@ pub(super) fn explicit_predicates_of<'tcx>( ty::GenericPredicates { parent: predicates_and_bounds.parent, predicates: tcx.arena.alloc_slice(&predicates), - effects_min_tys: predicates_and_bounds.effects_min_tys, } } } else { if matches!(def_kind, DefKind::AnonConst) - && tcx.features().generic_const_exprs + && tcx.features().generic_const_exprs() && let Some(defaulted_param_def_id) = tcx.hir().opt_const_param_default_param_def_id(tcx.local_def_id_to_hir_id(def_id)) { @@ -571,7 +544,6 @@ pub(super) fn explicit_predicates_of<'tcx>( return GenericPredicates { parent: parent_preds.parent, predicates: { tcx.arena.alloc_from_iter(filtered_predicates) }, - effects_min_tys: parent_preds.effects_min_tys, }; } gather_explicit_predicates_of(tcx, def_id) @@ -650,7 +622,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>( // Combine the two lists to form the complete set of superbounds: let implied_bounds = - &*tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(where_bounds_that_match)); + &*tcx.arena.alloc_from_iter(bounds.clauses().chain(where_bounds_that_match)); debug!(?implied_bounds); // Now require that immediate supertraits are lowered, which will, in @@ -706,29 +678,76 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( assert_eq!( trait_predicate.self_ty(), ty, - "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + "expected `Self` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" ); } ty::ClauseKind::Projection(projection_predicate) => { assert_eq!( projection_predicate.self_ty(), ty, - "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + "expected `Self` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" ); } ty::ClauseKind::TypeOutlives(outlives_predicate) => { assert_eq!( outlives_predicate.0, ty, - "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + "expected `Self` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" ); } ty::ClauseKind::RegionOutlives(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) => { + | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::HostEffect(..) => { bug!( - "unexpected non-`Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + "unexpected non-`Self` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" + ); + } + } + } + } + PredicateFilter::ConstIfConst => { + for (clause, _) in bounds { + match clause.kind().skip_binder() { + ty::ClauseKind::HostEffect(ty::HostEffectPredicate { + trait_ref: _, + host: ty::HostPolarity::Maybe, + }) => {} + _ => { + bug!( + "unexpected non-`HostEffect` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" + ); + } + } + } + } + PredicateFilter::SelfConstIfConst => { + for (clause, _) in bounds { + match clause.kind().skip_binder() { + ty::ClauseKind::HostEffect(pred) => { + assert_eq!( + pred.host, + ty::HostPolarity::Maybe, + "expected `~const` predicate when computing `{filter:?}` \ + implied bounds: {clause:?}", + ); + assert_eq!( + pred.trait_ref.self_ty(), + ty, + "expected `Self` predicate when computing `{filter:?}` \ + implied bounds: {clause:?}" + ); + } + _ => { + bug!( + "unexpected non-`HostEffect` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" ); } } @@ -847,6 +866,147 @@ impl<'tcx> ItemCtxt<'tcx> { ); } - bounds.clauses(self.tcx).collect() + bounds.clauses().collect() } } + +/// Compute the conditions that need to hold for a conditionally-const item to be const. +/// That is, compute the set of `~const` where clauses for a given item. +/// +/// This query also computes the `~const` where clauses for associated types, which are +/// not "const", but which have item bounds which may be `~const`. These must hold for +/// the `~const` item bound to hold. +pub(super) fn const_conditions<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> ty::ConstConditions<'tcx> { + if !tcx.is_conditionally_const(def_id) { + bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}"); + } + + let (generics, trait_def_id_and_supertraits, has_parent) = match tcx.hir_node_by_def_id(def_id) + { + Node::Item(item) => match item.kind { + hir::ItemKind::Impl(impl_) => (impl_.generics, None, false), + hir::ItemKind::Fn(_, generics, _) => (generics, None, false), + hir::ItemKind::Trait(_, _, generics, supertraits, _) => { + (generics, Some((item.owner_id.def_id, supertraits)), false) + } + _ => bug!("const_conditions called on wrong item: {def_id:?}"), + }, + // While associated types are not really const, we do allow them to have `~const` + // bounds and where clauses. `const_conditions` is responsible for gathering + // these up so we can check them in `compare_type_predicate_entailment`, and + // in `HostEffect` goal computation. + Node::TraitItem(item) => match item.kind { + hir::TraitItemKind::Fn(_, _) | hir::TraitItemKind::Type(_, _) => { + (item.generics, None, true) + } + _ => bug!("const_conditions called on wrong item: {def_id:?}"), + }, + Node::ImplItem(item) => match item.kind { + hir::ImplItemKind::Fn(_, _) | hir::ImplItemKind::Type(_) => { + (item.generics, None, tcx.is_conditionally_const(tcx.local_parent(def_id))) + } + _ => bug!("const_conditions called on wrong item: {def_id:?}"), + }, + Node::ForeignItem(item) => match item.kind { + hir::ForeignItemKind::Fn(_, _, generics) => (generics, None, false), + _ => bug!("const_conditions called on wrong item: {def_id:?}"), + }, + // N.B. Tuple ctors are unconditionally constant. + Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(), + _ => bug!("const_conditions called on wrong item: {def_id:?}"), + }; + + let icx = ItemCtxt::new(tcx, def_id); + let mut bounds = Bounds::default(); + + for pred in generics.predicates { + match pred { + hir::WherePredicate::BoundPredicate(bound_pred) => { + let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty); + let bound_vars = tcx.late_bound_vars(bound_pred.hir_id); + icx.lowerer().lower_bounds( + ty, + bound_pred.bounds.iter(), + &mut bounds, + bound_vars, + PredicateFilter::ConstIfConst, + ); + } + _ => {} + } + } + + if let Some((def_id, supertraits)) = trait_def_id_and_supertraits { + bounds.push_const_bound( + tcx, + ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())), + ty::HostPolarity::Maybe, + DUMMY_SP, + ); + + icx.lowerer().lower_bounds( + tcx.types.self_param, + supertraits.into_iter(), + &mut bounds, + ty::List::empty(), + PredicateFilter::ConstIfConst, + ); + } + + ty::ConstConditions { + parent: has_parent.then(|| tcx.local_parent(def_id).to_def_id()), + predicates: tcx.arena.alloc_from_iter(bounds.clauses().map(|(clause, span)| { + ( + clause.kind().map_bound(|clause| match clause { + ty::ClauseKind::HostEffect(ty::HostEffectPredicate { + trait_ref, + host: ty::HostPolarity::Maybe, + }) => trait_ref, + _ => bug!("converted {clause:?}"), + }), + span, + ) + })), + } +} + +pub(super) fn implied_const_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> { + if !tcx.is_conditionally_const(def_id) { + bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}"); + } + + let bounds = match tcx.hir_node_by_def_id(def_id) { + Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => { + implied_predicates_with_filter( + tcx, + def_id.to_def_id(), + PredicateFilter::SelfConstIfConst, + ) + } + Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) => { + explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst) + } + _ => bug!("implied_const_bounds called on wrong item: {def_id:?}"), + }; + + bounds.map_bound(|bounds| { + &*tcx.arena.alloc_from_iter(bounds.iter().copied().map(|(clause, span)| { + ( + clause.kind().map_bound(|clause| match clause { + ty::ClauseKind::HostEffect(ty::HostEffectPredicate { + trait_ref, + host: ty::HostPolarity::Maybe, + }) => trait_ref, + _ => bug!("converted {clause:?}"), + }), + span, + ) + })) + }) +} 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 cb7f0901c7e..f7daef3e80c 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -33,18 +33,12 @@ use crate::errors; #[extension(trait RegionExt)] impl ResolvedArg { - fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { - debug!("ResolvedArg::early: def_id={:?}", param.def_id); - (param.def_id, ResolvedArg::EarlyBound(param.def_id)) + fn early(param: &GenericParam<'_>) -> ResolvedArg { + ResolvedArg::EarlyBound(param.def_id) } - fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { - let depth = ty::INNERMOST; - debug!( - "ResolvedArg::late: idx={:?}, param={:?} depth={:?} def_id={:?}", - idx, param, depth, param.def_id, - ); - (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id)) + fn late(idx: u32, param: &GenericParam<'_>) -> ResolvedArg { + ResolvedArg::LateBound(ty::INNERMOST, idx, param.def_id) } fn id(&self) -> Option { @@ -282,24 +276,33 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou fn late_arg_as_bound_arg<'tcx>( tcx: TyCtxt<'tcx>, - arg: &ResolvedArg, param: &GenericParam<'tcx>, ) -> ty::BoundVariableKind { - match arg { - ResolvedArg::LateBound(_, _, def_id) => { - let def_id = def_id.to_def_id(); - let name = tcx.item_name(def_id); - match param.kind { - GenericParamKind::Lifetime { .. } => { - ty::BoundVariableKind::Region(ty::BrNamed(def_id, name)) - } - GenericParamKind::Type { .. } => { - ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) - } - GenericParamKind::Const { .. } => ty::BoundVariableKind::Const, - } + let def_id = param.def_id.to_def_id(); + let name = tcx.item_name(def_id); + match param.kind { + GenericParamKind::Lifetime { .. } => { + ty::BoundVariableKind::Region(ty::BrNamed(def_id, name)) } - _ => bug!("{:?} is not a late argument", arg), + GenericParamKind::Type { .. } => { + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) + } + GenericParamKind::Const { .. } => ty::BoundVariableKind::Const, + } +} + +/// Turn a [`ty::GenericParamDef`] into a bound arg. Generally, this should only +/// be used when turning early-bound vars into late-bound vars when lowering +/// return type notation. +fn generic_param_def_as_bound_arg(param: &ty::GenericParamDef) -> ty::BoundVariableKind { + match param.kind { + ty::GenericParamDefKind::Lifetime => { + ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(param.def_id, param.name)) + } + ty::GenericParamDefKind::Type { .. } => { + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name)) + } + ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, } } @@ -360,10 +363,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let mut bound_vars: FxIndexMap = FxIndexMap::default(); let binders_iter = trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); - bound_vars.insert(pair.0, pair.1); - r + let arg = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param); + bound_vars.insert(param.def_id, arg); + late_arg_as_bound_arg(self.tcx, param) }); binders.extend(binders_iter); @@ -458,9 +460,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .iter() .enumerate() .map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); - (pair, r) + ( + (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), + late_arg_as_bound_arg(self.tcx, param), + ) }) .unzip(); @@ -492,8 +495,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let mut bound_vars = FxIndexMap::default(); debug!(?opaque.generics.params); for param in opaque.generics.params { - let (def_id, reg) = ResolvedArg::early(param); - bound_vars.insert(def_id, reg); + let arg = ResolvedArg::early(param); + bound_vars.insert(param.def_id, arg); } let hir_id = self.tcx.local_def_id_to_hir_id(opaque.def_id); @@ -618,9 +621,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .iter() .enumerate() .map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); - (pair, r) + ( + (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), + late_arg_as_bound_arg(self.tcx, param), + ) }) .unzip(); @@ -870,9 +874,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { .iter() .enumerate() .map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); - (pair, r) + ( + (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), + late_arg_as_bound_arg(self.tcx, param), + ) }) .unzip(); @@ -1052,19 +1057,21 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let bound_vars: FxIndexMap = generics .params .iter() - .map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - if self.tcx.is_late_bound(param.hir_id) { - let late_bound_idx = named_late_bound_vars; - named_late_bound_vars += 1; - ResolvedArg::late(late_bound_idx, param) - } else { + .map(|param| { + (param.def_id, match param.kind { + GenericParamKind::Lifetime { .. } => { + if self.tcx.is_late_bound(param.hir_id) { + let late_bound_idx = named_late_bound_vars; + named_late_bound_vars += 1; + ResolvedArg::late(late_bound_idx, param) + } else { + ResolvedArg::early(param) + } + } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { ResolvedArg::early(param) } - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - ResolvedArg::early(param) - } + }) }) .collect(); @@ -1075,11 +1082,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { matches!(param.kind, GenericParamKind::Lifetime { .. }) && self.tcx.is_late_bound(param.hir_id) }) - .enumerate() - .map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(late_bound_idx as u32, param); - late_arg_as_bound_arg(self.tcx, &pair.1, param) - }) + .map(|param| late_arg_as_bound_arg(self.tcx, param)) .collect(); self.record_late_bound_vars(hir_id, binders); let scope = Scope::Binder { @@ -1096,7 +1099,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { where F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>), { - let bound_vars = generics.params.iter().map(ResolvedArg::early).collect(); + let bound_vars = + generics.params.iter().map(|param| (param.def_id, ResolvedArg::early(param))).collect(); self.record_late_bound_vars(hir_id, vec![]); let scope = Scope::Binder { hir_id, @@ -1161,7 +1165,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id) && param.is_elided_lifetime() && !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async() - && !self.tcx.features().anonymous_lifetime_in_impl_trait + && !self.tcx.features().anonymous_lifetime_in_impl_trait() { let mut diag: rustc_errors::Diag<'_> = rustc_session::parse::feature_err( &self.tcx.sess, @@ -1639,17 +1643,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { constraint.ident, ty::AssocKind::Fn, ) { - bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).own_params.iter().map( - |param| match param.kind { - ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( - ty::BoundRegionKind::BrNamed(param.def_id, param.name), - ), - ty::GenericParamDefKind::Type { .. } => ty::BoundVariableKind::Ty( - ty::BoundTyKind::Param(param.def_id, param.name), - ), - ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, - }, - )); + bound_vars.extend( + self.tcx + .generics_of(assoc_fn.def_id) + .own_params + .iter() + .map(|param| generic_param_def_as_bound_arg(param)), + ); bound_vars.extend( self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars(), ); @@ -1968,17 +1968,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // Append the early-bound vars on the function, and then the late-bound ones. // We actually turn type parameters into higher-ranked types here, but we // deny them later in HIR lowering. - bound_vars.extend(self.tcx.generics_of(item_def_id).own_params.iter().map(|param| { - match param.kind { - ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( - ty::BoundRegionKind::BrNamed(param.def_id, param.name), - ), - ty::GenericParamDefKind::Type { .. } => { - ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name)) - } - ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, - } - })); + bound_vars.extend( + self.tcx + .generics_of(item_def_id) + .own_params + .iter() + .map(|param| generic_param_def_as_bound_arg(param)), + ); bound_vars.extend(self.tcx.fn_sig(item_def_id).instantiate_identity().bound_vars()); // SUBTLE: Stash the old bound vars onto the *item segment* before appending @@ -2239,7 +2235,7 @@ fn deny_non_region_late_bound( format!("late-bound {what} parameter not allowed on {where_}"), ); - let guar = diag.emit_unless(!tcx.features().non_lifetime_binders || !first); + let guar = diag.emit_unless(!tcx.features().non_lifetime_binders() || !first); first = false; *arg = ResolvedArg::Error(guar); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 470bcaeded1..84161ec7648 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -699,7 +699,7 @@ fn infer_placeholder_type<'tcx>( } fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) { - if !tcx.features().inherent_associated_types { + if !tcx.features().inherent_associated_types() { use rustc_session::parse::feature_err; use rustc_span::symbol::sym; feature_err( @@ -714,7 +714,7 @@ fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) { pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { use hir::intravisit::Visitor; - if tcx.features().lazy_type_alias { + if tcx.features().lazy_type_alias() { return true; } struct HasTait; diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index 1ccb7faaf30..e65420ea8bf 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -186,7 +186,6 @@ impl<'tcx> GenericsBuilder<'tcx> { param_def_id_to_index, has_self, has_late_bound_regions: sig_generics.has_late_bound_regions, - host_effect_index: sig_generics.host_effect_index, } } } @@ -279,8 +278,6 @@ impl<'tcx> PredicatesBuilder<'tcx> { ty::GenericPredicates { parent: self.parent, predicates: self.tcx.arena.alloc_from_iter(preds), - // FIXME(fn_delegation): Support effects. - effects_min_tys: ty::List::empty(), } } } @@ -472,10 +469,6 @@ fn check_constraints<'tcx>( })); }; - if tcx.has_host_param(sig_id) { - emit("delegation to a function with effect parameter is not supported yet"); - } - if let Some(local_sig_id) = sig_id.as_local() && tcx.hir().opt_delegation_sig_id(local_sig_id).is_some() { 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 4721a3a0cf5..a5709089db6 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -45,23 +45,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let hir::GenericBound::Trait(ptr) = hir_bound else { continue; }; - match ptr.modifiers { - hir::TraitBoundModifier::Maybe => unbounds.push(ptr), - hir::TraitBoundModifier::Negative => { + match ptr.modifiers.polarity { + hir::BoundPolarity::Maybe(_) => unbounds.push(ptr), + hir::BoundPolarity::Negative(_) => { if let Some(sized_def_id) = sized_def_id && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) { seen_negative_sized_bound = true; } } - hir::TraitBoundModifier::None => { + hir::BoundPolarity::Positive => { if let Some(sized_def_id) = sized_def_id && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) { seen_positive_sized_bound = true; } } - _ => {} } } }; @@ -89,7 +88,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; if seen_repeat { self.dcx().emit_err(err); - } else if !tcx.features().more_maybe_bounds { + } else if !tcx.features().more_maybe_bounds() { self.tcx().sess.create_feature_err(err, sym::more_maybe_bounds).emit(); }; } @@ -155,7 +154,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { for hir_bound in hir_bounds { // In order to avoid cycles, when we're lowering `SelfThatDefines`, // we skip over any traits that don't define the given associated type. - if let PredicateFilter::SelfThatDefines(assoc_name) = predicate_filter { if let Some(trait_ref) = hir_bound.trait_ref() && let Some(trait_did) = trait_ref.trait_def_id() @@ -169,20 +167,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match hir_bound { hir::GenericBound::Trait(poly_trait_ref) => { - let (constness, polarity) = match poly_trait_ref.modifiers { - hir::TraitBoundModifier::Const => { - (Some(ty::BoundConstness::Const), ty::PredicatePolarity::Positive) - } - hir::TraitBoundModifier::MaybeConst => ( - Some(ty::BoundConstness::ConstIfConst), - ty::PredicatePolarity::Positive, - ), - hir::TraitBoundModifier::None => (None, ty::PredicatePolarity::Positive), - hir::TraitBoundModifier::Negative => { - (None, ty::PredicatePolarity::Negative) - } - hir::TraitBoundModifier::Maybe => continue, + let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers; + let polarity = match polarity { + rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive, + rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative, + rustc_ast::BoundPolarity::Maybe(_) => continue, }; + let _ = self.lower_poly_trait_ref( &poly_trait_ref.trait_ref, poly_trait_ref.span, @@ -194,6 +185,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } hir::GenericBound::Outlives(lifetime) => { + // `ConstIfConst` is only interested in `~const` bounds. + if matches!( + predicate_filter, + PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst + ) { + continue; + } + let region = self.lower_lifetime(lifetime, RegionInferReason::OutlivesBound); bounds.push_region_bound( self.tcx(), @@ -393,21 +392,31 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }, ); - bounds.push_projection_bound( - tcx, - projection_term.map_bound(|projection_term| ty::ProjectionPredicate { - projection_term, - term, - }), - constraint.span, - ); + match predicate_filter { + PredicateFilter::All + | PredicateFilter::SelfOnly + | PredicateFilter::SelfThatDefines(_) + | PredicateFilter::SelfAndAssociatedTypeBounds => { + bounds.push_projection_bound( + tcx, + projection_term.map_bound(|projection_term| ty::ProjectionPredicate { + projection_term, + term, + }), + constraint.span, + ); + } + // `ConstIfConst` is only interested in `~const` bounds. + PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} + } } // Lower a constraint like `Item: Debug` as found in HIR bound `T: Iterator` // to a bound involving a projection: `::Item: Debug`. hir::AssocItemConstraintKind::Bound { bounds: hir_bounds } => { match predicate_filter { - PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {} - PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { + PredicateFilter::All + | PredicateFilter::SelfAndAssociatedTypeBounds + | PredicateFilter::ConstIfConst => { let projection_ty = projection_term .map_bound(|projection_term| projection_term.expect_ty(self.tcx())); // Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty` @@ -422,6 +431,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { predicate_filter, ); } + PredicateFilter::SelfOnly + | PredicateFilter::SelfThatDefines(_) + | PredicateFilter::SelfConstIfConst => {} } } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index a1ee120e855..f2ee4b0ccd4 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -40,8 +40,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut potential_assoc_types = Vec::new(); let dummy_self = self.tcx().types.trait_object_dummy_self; for trait_bound in hir_trait_bounds.iter().rev() { - // FIXME: This doesn't handle `? const`. - if trait_bound.modifiers == hir::TraitBoundModifier::Maybe { + if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity { continue; } if let GenericArgCountResult { @@ -51,7 +50,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } = self.lower_poly_trait_ref( &trait_bound.trait_ref, trait_bound.span, - None, + hir::BoundConstness::Never, ty::PredicatePolarity::Positive, dummy_self, &mut bounds, @@ -63,7 +62,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut trait_bounds = vec![]; let mut projection_bounds = vec![]; - for (pred, span) in bounds.clauses(tcx) { + for (pred, span) in bounds.clauses() { let bound_pred = pred.kind(); match bound_pred.skip_binder() { ty::ClauseKind::Trait(trait_pred) => { @@ -79,7 +78,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::ClauseKind::RegionOutlives(_) | ty::ClauseKind::ConstArgHasType(..) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) => { + | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::HostEffect(..) => { span_bug!(span, "did not expect {pred} clause in object bounds"); } } @@ -259,7 +259,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } }) .collect(); - let args = tcx.mk_args(&args); let span = i.bottom().1; let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| { @@ -292,7 +291,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .emit(); } - ty::ExistentialTraitRef { def_id: trait_ref.def_id, args } + ty::ExistentialTraitRef::new(tcx, trait_ref.def_id, args) }) }); 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 01768c89cca..dd0f250a8e2 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -63,7 +63,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_segment: &'_ hir::PathSegment<'_>, is_impl: bool, ) { - if self.tcx().features().unboxed_closures { + if self.tcx().features().unboxed_closures() { return; } @@ -343,7 +343,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { && let Some(hir_ty) = constraint.ty() && let ty = self.lower_ty(hir_ty) && (ty.is_enum() || ty.references_error()) - && tcx.features().associated_const_equality + && tcx.features().associated_const_equality() { Some(errors::AssocKindMismatchWrapInBracesSugg { lo: hir_ty.span.shrink_to_lo(), 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 fe0cd572609..0891642f2c8 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -81,6 +81,12 @@ pub enum PredicateFilter { /// For example, given `Self: Tr`, this would expand to `Self: Tr` /// and `::A: B`. SelfAndAssociatedTypeBounds, + + /// Filter only the `~const` bounds, which are lowered into `HostEffect` clauses. + ConstIfConst, + + /// Filter only the `~const` bounds which are *also* in the supertrait position. + SelfConstIfConst, } #[derive(Debug)] @@ -652,7 +658,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, trait_ref: &hir::TraitRef<'tcx>, span: Span, - constness: Option, + constness: hir::BoundConstness, polarity: ty::PredicatePolarity, self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, @@ -675,11 +681,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(self_ty), ); - if let Some(constness) = constness + if let hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) = constness && !self.tcx().is_const_trait(trait_def_id) { self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { - span: trait_ref.path.span, + span, modifier: constness.as_str(), }); } @@ -693,16 +699,49 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bound_vars, ); - debug!(?poly_trait_ref); - bounds.push_trait_bound( - tcx, - self.item_def_id().to_def_id(), - poly_trait_ref, - span, - polarity, - constness, - predicate_filter, - ); + match predicate_filter { + PredicateFilter::All + | PredicateFilter::SelfOnly + | PredicateFilter::SelfThatDefines(..) + | PredicateFilter::SelfAndAssociatedTypeBounds => { + debug!(?poly_trait_ref); + bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity); + + match constness { + hir::BoundConstness::Always(span) => { + if polarity == ty::PredicatePolarity::Positive { + bounds.push_const_bound( + tcx, + poly_trait_ref, + ty::HostPolarity::Const, + span, + ); + } + } + hir::BoundConstness::Maybe(_) => { + // We don't emit a const bound here, since that would mean that we + // unconditionally need to prove a `HostEffect` predicate, even when + // the predicates are being instantiated in a non-const context. This + // is instead handled in the `const_conditions` query. + } + hir::BoundConstness::Never => {} + } + } + // On the flip side, when filtering `ConstIfConst` bounds, we only need to convert + // `~const` bounds. All other predicates are handled in their respective queries. + // + // Note that like `PredicateFilter::SelfOnly`, we don't need to do any filtering + // here because we only call this on self bounds, and deal with the recursive case + // in `lower_assoc_item_constraint`. + PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => match constness { + hir::BoundConstness::Maybe(span) => { + if polarity == ty::PredicatePolarity::Positive { + bounds.push_const_bound(tcx, poly_trait_ref, ty::HostPolarity::Maybe, span); + } + } + hir::BoundConstness::Always(_) | hir::BoundConstness::Never => {} + }, + } let mut dup_constraints = FxIndexMap::default(); for constraint in trait_segment.args().constraints { @@ -1164,15 +1203,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.emit() } else if let Err(reported) = qself_ty.error_reported() { reported - } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() { - // `::Assoc` makes no sense. - struct_span_code_err!( - self.dcx(), - tcx.def_span(alias_ty.def_id), - E0667, - "`impl Trait` is not allowed in path parameters" - ) - .emit() // Already reported in an earlier stage. } else { self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?; @@ -1241,7 +1271,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle // errors (#108491) which mask the feature-gate error, needlessly confusing users // who use IATs by accident (#113265). - if !tcx.features().inherent_associated_types { + if !tcx.features().inherent_associated_types() { return Ok(None); } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 7f183324f04..d9c70c3cee6 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -57,7 +57,7 @@ pub(crate) fn check_impl_wf( tcx: TyCtxt<'_>, impl_def_id: LocalDefId, ) -> Result<(), ErrorGuaranteed> { - let min_specialization = tcx.features().min_specialization; + let min_specialization = tcx.features().min_specialization(); let mut res = Ok(()); debug_assert_matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. }); res = res.and(enforce_impl_params_are_constrained(tcx, impl_def_id)); diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 0355adfcb11..a394fc2fbb1 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -530,6 +530,7 @@ fn trait_specialization_kind<'tcx>( | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(..) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(..) => None, + | ty::ClauseKind::ConstEvaluatable(..) + | ty::ClauseKind::HostEffect(..) => None, } } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 71ee77f8f61..3ad35163191 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -116,7 +116,7 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi return; } - let extended_abi_support = tcx.features().extended_varargs_abi_support; + let extended_abi_support = tcx.features().extended_varargs_abi_support(); let conventions = match (extended_abi_support, abi.supports_varargs()) { // User enabled additional ABI support for varargs and function ABI matches those ones. (true, true) => return, @@ -155,7 +155,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { // FIXME(effects): remove once effects is implemented in old trait solver // or if the next solver is stabilized. - if tcx.features().effects && !tcx.next_trait_solver_globally() { + if tcx.features().effects() && !tcx.next_trait_solver_globally() { tcx.dcx().emit_err(errors::EffectsWithoutNextSolver); } @@ -172,7 +172,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let _ = tcx.ensure().crate_inherent_impls_overlap_check(()); }); - if tcx.features().rustc_attrs { + if tcx.features().rustc_attrs() { tcx.sess.time("outlives_dumping", || outlives::dump::inferred_outlives(tcx)); tcx.sess.time("variance_dumping", || variance::dump::variances(tcx)); collect::dump::opaque_hidden_types(tcx); diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index f576499ecac..2c1d443f951 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -53,7 +53,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) => {} + | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::HostEffect(..) => {} } } diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index e3cdb1bf5f7..c43917649de 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -23,7 +23,7 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau let crate_map = tcx.inferred_outlives_crate(()); crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]) } - DefKind::AnonConst if tcx.features().generic_const_exprs => { + DefKind::AnonConst if tcx.features().generic_const_exprs() => { let id = tcx.local_def_id_to_hir_id(item_def_id); if tcx.hir().opt_const_param_default_param_def_id(id).is_some() { // In `generics_of` we set the generics' parent to be our parent's parent which means that diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 9ebfd4f15ab..61214b99215 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -16,7 +16,6 @@ use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_hir::{ BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, - TraitBoundModifier, }; use rustc_span::FileName; use rustc_span::source_map::SourceMap; @@ -676,9 +675,16 @@ impl<'a> State<'a> { } fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef<'_>) { - // FIXME: This isn't correct! - if t.modifiers == TraitBoundModifier::Maybe { - self.word("?"); + let hir::TraitBoundModifiers { constness, polarity } = t.modifiers; + match constness { + hir::BoundConstness::Never => {} + hir::BoundConstness::Always(_) => self.word("const"), + hir::BoundConstness::Maybe(_) => self.word("~const"), + } + match polarity { + hir::BoundPolarity::Positive => {} + hir::BoundPolarity::Negative(_) => self.word("!"), + hir::BoundPolarity::Maybe(_) => self.word("?"), } self.print_formal_generic_params(t.bound_generic_params); self.print_trait_ref(&t.trait_ref); @@ -2128,7 +2134,7 @@ impl<'a> State<'a> { self.print_type(default); } } - GenericParamKind::Const { ty, ref default, is_host_effect: _, synthetic: _ } => { + GenericParamKind::Const { ty, ref default, synthetic: _ } => { self.word_space(":"); self.print_type(ty); if let Some(default) = default { diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index e68caa3e2e3..3372cae7a51 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -94,14 +94,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (None, arm.body.span) }; - let (span, code) = match prior_arm { + let code = match prior_arm { // The reason for the first arm to fail is not that the match arms diverge, // but rather that there's a prior obligation that doesn't hold. - None => { - (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src)) - } - Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => ( - expr.span, + None => ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src), + Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => { ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause { arm_block_id, arm_span, @@ -110,13 +107,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prior_arm_ty, prior_arm_span, scrut_span: scrut.span, + expr_span: expr.span, source: match_src, prior_non_diverging_arms: prior_non_diverging_arms.clone(), tail_defines_return_position_impl_trait, - })), - ), + })) + } }; - let cause = self.cause(span, code); + let cause = self.cause(arm_span, code); // This is the moral equivalent of `coercion.coerce(self, cause, arm.body, arm_ty)`. // We use it this way to be able to expand on the potential error and detect when a diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index fa6a86c6911..ed56bb9c455 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -20,7 +20,7 @@ use rustc_target::spec::abi; use rustc_trait_selection::error_reporting::traits::DefIdOrName; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use tracing::{debug, instrument, trace}; +use tracing::{debug, instrument}; use super::method::MethodCallee; use super::method::probe::ProbeScope; @@ -537,7 +537,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // This check is here because there is currently no way to express a trait bound for `FnDef` types only. if let ty::FnDef(def_id, _args) = *arg_ty.kind() { - if idx == 0 && !self.tcx.is_const_fn_raw(def_id) { + if idx == 0 && !self.tcx.is_const_fn(def_id) { self.dcx().emit_err(errors::ConstSelectMustBeConst { span }); } } else { @@ -843,27 +843,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_did: DefId, callee_args: GenericArgsRef<'tcx>, ) { - let tcx = self.tcx; + // FIXME(effects): We should be enforcing these effects unconditionally. + // This can be done as soon as we convert the standard library back to + // using const traits, since if we were to enforce these conditions now, + // we'd fail on basically every builtin trait call (i.e. `1 + 2`). + if !self.tcx.features().effects() { + return; + } - // fast-reject if callee doesn't have the host effect param (non-const) - let generics = tcx.generics_of(callee_did); - let Some(host_effect_index) = generics.host_effect_index else { return }; - - let effect = tcx.expected_host_effect_param_for_body(self.body_id); - - trace!(?effect, ?generics, ?callee_args); - - let param = callee_args.const_at(host_effect_index); - let cause = self.misc(span); - // We know the type of `effect` to be `bool`, there will be no opaque type inference. - match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::Yes, effect, param) { - Ok(infer::InferOk { obligations, value: () }) => { - self.register_predicates(obligations); + let host = match self.tcx.hir().body_const_context(self.body_id) { + Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => { + ty::HostPolarity::Const } - Err(e) => { - // FIXME(effects): better diagnostic - self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit(); + Some(hir::ConstContext::ConstFn) => ty::HostPolarity::Maybe, + None => return, + }; + + // FIXME(effects): Should this be `is_const_fn_raw`? It depends on if we move + // const stability checking here too, I guess. + if self.tcx.is_conditionally_const(callee_did) { + let q = self.tcx.const_conditions(callee_did); + // FIXME(effects): Use this span with a better cause code. + for (cond, _) in q.instantiate(self.tcx, callee_args) { + self.register_predicate(Obligation::new( + self.tcx, + self.misc(span), + self.param_env, + cond.to_host_effect_clause(self.tcx, host), + )); } + } else { + // FIXME(effects): This should eventually be caught here. + // For now, though, we defer some const checking to MIR. } } diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 8fa6ab8503d..483a8d1d9a9 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -721,7 +721,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { use rustc_middle::ty::cast::IntTy::*; if self.cast_ty.is_dyn_star() { - if fcx.tcx.features().dyn_star { + if fcx.tcx.features().dyn_star() { span_bug!(self.span, "should be handled by `coerce`"); } else { // Report "casting is invalid" rather than "non-primitive cast" @@ -876,20 +876,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { // A + SrcAuto> -> B + DstAuto>. need to make sure // - `Src` and `Dst` traits are the same // - traits have the same generic arguments - // - `SrcAuto` is a superset of `DstAuto` - (Some(src_principal), Some(dst_principal)) => { + // - projections are the same + // - `SrcAuto` (+auto traits implied by `Src`) is a superset of `DstAuto` + // + // Note that trait upcasting goes through a different mechanism (`coerce_unsized`) + // and is unaffected by this check. + (Some(src_principal), Some(_)) => { let tcx = fcx.tcx; - // Check that the traits are actually the same. - // The `dyn Src = dyn Dst` check below would suffice, - // but this may produce a better diagnostic. - // - // Note that trait upcasting goes through a different mechanism (`coerce_unsized`) - // and is unaffected by this check. - if src_principal.def_id() != dst_principal.def_id() { - return Err(CastError::DifferingKinds { src_kind, dst_kind }); - } - // We need to reconstruct trait object types. // `m_src` and `m_dst` won't work for us here because they will potentially // contain wrappers, which we do not care about. @@ -912,8 +906,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { ty::Dyn, )); - // `dyn Src = dyn Dst`, this checks for matching traits/generics - // This is `demand_eqtype`, but inlined to give a better error. + // `dyn Src = dyn Dst`, this checks for matching traits/generics/projections + // This is `fcx.demand_eqtype`, but inlined to give a better error. let cause = fcx.misc(self.span); if fcx .at(&cause, fcx.param_env) @@ -965,8 +959,35 @@ impl<'a, 'tcx> CastCheck<'tcx> { // dyn Auto -> dyn Auto'? ok. (None, None) => Ok(CastKind::PtrPtrCast), - // dyn Trait -> dyn Auto? should be ok, but we used to not allow it. - // FIXME: allow this + // dyn Trait -> dyn Auto? not ok (for now). + // + // Although dropping the principal is already allowed for unsizing coercions + // (e.g. `*const (dyn Trait + Auto)` to `*const dyn Auto`), dropping it is + // currently **NOT** allowed for (non-coercion) ptr-to-ptr casts (e.g + // `*const Foo` to `*const Bar` where `Foo` has a `dyn Trait + Auto` tail + // and `Bar` has a `dyn Auto` tail), because the underlying MIR operations + // currently work very differently: + // + // * A MIR unsizing coercion on raw pointers to trait objects (`*const dyn Src` + // to `*const dyn Dst`) is currently equivalent to downcasting the source to + // the concrete sized type that it was originally unsized from first (via a + // ptr-to-ptr cast from `*const Src` to `*const T` with `T: Sized`) and then + // unsizing this thin pointer to the target type (unsizing `*const T` to + // `*const Dst`). In particular, this means that the pointer's metadata + // (vtable) will semantically change, e.g. for const eval and miri, even + // though the vtables will always be merged for codegen. + // + // * A MIR ptr-to-ptr cast is currently equivalent to a transmute and does not + // change the pointer metadata (vtable) at all. + // + // In addition to this potentially surprising difference between coercion and + // non-coercion casts, casting away the principal with a MIR ptr-to-ptr cast + // is currently considered undefined behavior: + // + // As a validity invariant of pointers to trait objects, we currently require + // that the principal of the vtable in the pointer metadata exactly matches + // the principal of the pointee type, where "no principal" is also considered + // a kind of principal. (Some(_), None) => Err(CastError::DifferingKinds { src_kind, dst_kind }), // dyn Auto -> dyn Trait? not ok. diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 406d668e7a5..6fa958d9496 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -223,11 +223,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::Ref(r_b, _, mutbl_b) => { return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b); } - ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => { + ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star() => { return self.coerce_dyn_star(a, b, predicates, region); } ty::Adt(pin, _) - if self.tcx.features().pin_ergonomics + if self.tcx.features().pin_ergonomics() && self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => { return self.coerce_pin(a, b); @@ -698,7 +698,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } if let Some((sub, sup)) = has_trait_upcasting_coercion - && !self.tcx().features().trait_upcasting + && !self.tcx().features().trait_upcasting() { // Renders better when we erase regions, since they're not really the point here. let (sub, sup) = self.tcx.erase_regions((sub, sup)); @@ -712,7 +712,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { err.emit(); } - if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { + if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion() { feature_err( &self.tcx.sess, sym::unsized_tuple_coercion, @@ -732,7 +732,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { predicates: &'tcx ty::List>, b_region: ty::Region<'tcx>, ) -> CoerceResult<'tcx> { - if !self.tcx.features().dyn_star { + if !self.tcx.features().dyn_star() { return Err(TypeError::Mismatch); } @@ -1695,7 +1695,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { blk_id, expression, ); - if !fcx.tcx.features().unsized_locals { + if !fcx.tcx.features().unsized_locals() { unsized_return = self.is_return_ty_definitely_unsized(fcx); } } @@ -1709,7 +1709,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { return_expr_id, expression, ); - if !fcx.tcx.features().unsized_locals { + if !fcx.tcx.features().unsized_locals() { unsized_return = self.is_return_ty_definitely_unsized(fcx); } } @@ -1723,6 +1723,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { }) => { err = fcx.err_ctxt().report_mismatched_types( cause, + fcx.param_env, expected, found, coercion_error, @@ -1752,6 +1753,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { }) => { err = fcx.err_ctxt().report_mismatched_types( cause, + fcx.param_env, expected, found, coercion_error, @@ -1787,6 +1789,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { _ => { err = fcx.err_ctxt().report_mismatched_types( cause, + fcx.param_env, expected, found, coercion_error, @@ -1897,7 +1900,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { block_or_return_id: hir::HirId, expression: Option<&'tcx hir::Expr<'tcx>>, ) -> Diag<'infcx> { - let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err); + let mut err = + fcx.err_ctxt().report_mismatched_types(cause, fcx.param_env, expected, found, ty_err); let due_to_block = matches!(fcx.tcx.hir_node(block_or_return_id), hir::Node::Block(..)); diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 777248ff873..3399a9fe880 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -191,7 +191,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.at(cause, self.param_env) .sup(DefineOpaqueTypes::Yes, expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) - .map_err(|e| self.err_ctxt().report_mismatched_types(cause, expected, actual, e)) + .map_err(|e| { + self.err_ctxt().report_mismatched_types(cause, self.param_env, expected, actual, e) + }) } pub(crate) fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { @@ -218,7 +220,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.at(cause, self.param_env) .eq(DefineOpaqueTypes::Yes, expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) - .map_err(|e| self.err_ctxt().report_mismatched_types(cause, expected, actual, e)) + .map_err(|e| { + self.err_ctxt().report_mismatched_types(cause, self.param_env, expected, actual, e) + }) } pub(crate) fn demand_coerce( @@ -271,7 +275,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr = expr.peel_drop_temps(); let cause = self.misc(expr.span); let expr_ty = self.resolve_vars_if_possible(checked_ty); - let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e); + let mut err = + self.err_ctxt().report_mismatched_types(&cause, self.param_env, expected, expr_ty, e); self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, Some(e)); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f4d7b59e9c8..d6e5fab610e 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -10,7 +10,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordMap; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, StashKey, Subdiagnostic, pluralize, struct_span_code_err, + Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, pluralize, + struct_span_code_err, }; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -734,7 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // be known if explicitly specified via turbofish). self.deferred_transmute_checks.borrow_mut().push((*from, to, expr.hir_id)); } - if !tcx.features().unsized_fn_params { + if !tcx.features().unsized_fn_params() { // We want to remove some Sized bounds from std functions, // but don't want to expose the removal to stable Rust. // i.e., we don't want to allow @@ -1750,7 +1751,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // to tell them that in the diagnostic. Does not affect typeck. let is_constable = match element.kind { hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() { - ty::FnDef(def_id, _) if tcx.is_const_fn(def_id) => traits::IsConstable::Fn, + ty::FnDef(def_id, _) if tcx.is_stable_const_fn(def_id) => traits::IsConstable::Fn, _ => traits::IsConstable::No, }, hir::ExprKind::Path(qpath) => { @@ -1995,7 +1996,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(base_expr) = base_expr { // FIXME: We are currently creating two branches here in order to maintain // consistency. But they should be merged as much as possible. - let fru_tys = if self.tcx.features().type_changing_struct_update { + let fru_tys = if self.tcx.features().type_changing_struct_update() { if adt.is_struct() { // Make some fresh generic parameters for our ADT type. let fresh_args = self.fresh_args_for_item(base_expr.span, adt.did()); @@ -2026,7 +2027,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Err(_) => { span_bug!( - cause.span(), + cause.span, "subtyping remaining fields of type changing FRU failed: {target_ty} != {fru_ty}: {}::{}", variant.name, ident.name, @@ -2763,12 +2764,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field_ident.span, "field not available in `impl Future`, but it is available in its `Output`", ); - err.span_suggestion_verbose( - base.span.shrink_to_hi(), - "consider `await`ing on the `Future` and access the field of its `Output`", - ".await", - Applicability::MaybeIncorrect, - ); + match self.tcx.coroutine_kind(self.body_id) { + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => { + err.span_suggestion_verbose( + base.span.shrink_to_hi(), + "consider `await`ing on the `Future` to access the field", + ".await", + Applicability::MaybeIncorrect, + ); + } + _ => { + let mut span: MultiSpan = base.span.into(); + span.push_span_label(self.tcx.def_span(self.body_id), "this is not `async`"); + err.span_note( + span, + "this implements `Future` and its output type has the field, \ + but the future cannot be awaited in a synchronous function", + ); + } + } } fn ban_nonexisting_field( @@ -3538,7 +3552,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (ident, _def_scope) = self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block); - if !self.tcx.features().offset_of_enum { + if !self.tcx.features().offset_of_enum() { rustc_session::parse::feature_err( &self.tcx.sess, sym::offset_of_enum, @@ -3628,7 +3642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let field_ty = self.field_ty(expr.span, field, args); - if self.tcx.features().offset_of_slice { + if self.tcx.features().offset_of_slice() { self.require_type_has_static_alignment( field_ty, expr.span, @@ -3661,7 +3675,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && field.name == sym::integer(index) { if let Some(&field_ty) = tys.get(index) { - if self.tcx.features().offset_of_slice { + if self.tcx.features().offset_of_slice() { self.require_type_has_static_alignment( field_ty, expr.span, diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 4fd508ab896..68776c52555 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -7,8 +7,6 @@ use rustc_data_structures::unord::{UnordBag, UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::HirId; use rustc_hir::intravisit::Visitor; -use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; -use rustc_middle::bug; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; @@ -48,7 +46,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { self.fulfillment_cx.borrow_mut().pending_obligations() ); - let fallback_occurred = self.fallback_types() | self.fallback_effects(); + let fallback_occurred = self.fallback_types(); if !fallback_occurred { return; @@ -103,31 +101,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> { fallback_occurred } - fn fallback_effects(&self) -> bool { - let unsolved_effects = self.unsolved_effects(); - - if unsolved_effects.is_empty() { - return false; - } - - // not setting the `fallback_has_occurred` field here because - // that field is only used for type fallback diagnostics. - for effect in unsolved_effects { - let expected = self.tcx.consts.true_; - let cause = self.misc(DUMMY_SP); - match self.at(&cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, effect) { - Ok(InferOk { obligations, value: () }) => { - self.register_predicates(obligations); - } - Err(e) => { - bug!("cannot eq unsolved effect: {e:?}") - } - } - } - - true - } - // Tries to apply a fallback to `ty` if it is an unsolved variable. // // - Unconstrained ints are replaced with `i32`. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 2bc84d1ac67..0fc566c58f7 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1262,15 +1262,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => { self.fcx.ty_infer(Some(param), inf.span).into() } - ( - &GenericParamDefKind::Const { has_default, is_host_effect, .. }, - GenericArg::Infer(inf), - ) => { - if has_default && is_host_effect { - self.fcx.var_for_effect(param) - } else { - self.fcx.ct_infer(Some(param), inf.span).into() - } + (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { + self.fcx.ct_infer(Some(param), inf.span).into() } _ => unreachable!(), } @@ -1305,20 +1298,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.fcx.var_for_def(self.span, param) } } - GenericParamDefKind::Const { has_default, is_host_effect, .. } => { + GenericParamDefKind::Const { has_default, .. } => { if has_default { - // N.B. this is a bit of a hack. `infer_args` is passed depending on - // whether the user has provided generic args. E.g. for `Vec::new` - // we would have to infer the generic types. However, for `Vec::::new` - // where the allocator param `A` has a default we will *not* infer. But - // for effect params this is a different story: if the user has not written - // anything explicit for the effect param, we always need to try to infer - // it before falling back to default, such that a `const fn` such as - // `needs_drop::<()>` can still be called in const contexts. (if we defaulted - // instead of inferred, typeck would error) - if is_host_effect { - return self.fcx.var_for_effect(param); - } else if !infer_args { + if !infer_args { return tcx .const_param_default(param.def_id) .instantiate(tcx, preceding_args) @@ -1486,7 +1468,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return ty::Const::new_error(self.tcx, guar); } } - } else if self.tcx.features().generic_const_exprs { + } else if self.tcx.features().generic_const_exprs() { ct.normalize_internal(self.tcx, self.param_env) } else { ct diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index f29d6199a87..a6c249da103 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -827,6 +827,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { formal_and_expected_inputs[mismatch_idx.into()], provided_arg_tys[mismatch_idx.into()].0, ), + self.param_env, terr, ); err.span_label( @@ -912,7 +913,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trace = mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty); if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) { - let mut err = self.err_ctxt().report_and_explain_type_error(trace, *e); + let mut err = + self.err_ctxt().report_and_explain_type_error(trace, self.param_env, *e); suggest_confusable(&mut err); reported = Some(err.emit()); return false; @@ -940,7 +942,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx]; let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx]; let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty); - let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err); + let mut err = + self.err_ctxt().report_and_explain_type_error(trace, self.param_env, *err); self.emit_coerce_suggestions( &mut err, provided_args[*provided_idx], @@ -1113,7 +1116,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &mut err, &trace.cause, None, - Some(trace.values), + Some(self.param_env.and(trace.values)), e, true, ); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index 693cb4465cc..eb5fe3a86e4 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -52,6 +52,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) | ty::PredicateKind::Ambiguous => false, } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index e60bd1a312a..3940d138deb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -247,12 +247,6 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { // FIXME ideally this shouldn't use unwrap match param { - Some( - param @ ty::GenericParamDef { - kind: ty::GenericParamDefKind::Const { is_host_effect: true, .. }, - .. - }, - ) => self.var_for_effect(param).as_const().unwrap(), Some(param) => self.var_for_def(span, param).as_const().unwrap(), None => self.next_const_var(span), } @@ -404,7 +398,7 @@ fn default_fallback(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior { } // `feature(never_type_fallback)`: fallback to `!` or `()` trying to not break stuff - if tcx.features().never_type_fallback { + if tcx.features().never_type_fallback() { return DivergingFallbackBehavior::ContextDependent; } diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 5ae8d2230f8..f427b0b805e 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -141,7 +141,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { let var_ty = self.assign(p.span, p.hir_id, None); if let Some((ty_span, hir_id)) = self.outermost_fn_param_pat { - if !self.fcx.tcx.features().unsized_fn_params { + if !self.fcx.tcx.features().unsized_fn_params() { self.fcx.require_type_is_sized( var_ty, ty_span, @@ -158,7 +158,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { ), ); } - } else if !self.fcx.tcx.features().unsized_locals { + } else if !self.fcx.tcx.features().unsized_locals() { self.fcx.require_type_is_sized( var_ty, p.span, diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 85ee0a5cf7d..85e11ff6745 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -161,7 +161,7 @@ fn typeck_with_fallback<'tcx>( let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); let fn_sig = fcx.normalize(body.value.span, fn_sig); - check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params); + check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params()); } else { let expected_type = infer_type_if_missing(&fcx, node); let expected_type = expected_type.unwrap_or_else(fallback); diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 1d7b3433fe5..f2b55d3aa4e 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -536,15 +536,21 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // FIXME(arbitrary_self_types): We probably should limit the // situations where this can occur by adding additional restrictions // to the feature, like the self type can't reference method args. - if self.tcx.features().arbitrary_self_types { + if self.tcx.features().arbitrary_self_types() { self.err_ctxt() - .report_mismatched_types(&cause, method_self_ty, self_ty, terr) + .report_mismatched_types( + &cause, + self.param_env, + method_self_ty, + self_ty, + terr, + ) .emit(); } else { // This has/will have errored in wfcheck, which we cannot depend on from here, as typeck on functions // may run before wfcheck if the function is used in const eval. self.dcx().span_delayed_bug( - cause.span(), + cause.span, format!("{self_ty} was a subtype of {method_self_ty} but now is not?"), ); } diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 69b9be00276..e20a0cb67c3 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -369,17 +369,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Option>> { let (obligation, args) = self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types); - // FIXME(effects) find a better way to do this - // Operators don't have generic methods, but making them `#[const_trait]` gives them - // `const host: bool`. - let args = if self.tcx.is_const_trait(trait_def_id) { - self.tcx.mk_args_from_iter( - args.iter() - .chain([self.tcx.expected_host_effect_param_for_body(self.body_id).into()]), - ) - } else { - args - }; self.construct_obligation_for_trait(m_name, trait_def_id, obligation, args) } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 1be711887d9..569fdea11ce 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -404,7 +404,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mode, })); } else if bad_ty.reached_raw_pointer - && !self.tcx.features().arbitrary_self_types_pointers + && !self.tcx.features().arbitrary_self_types_pointers() && !self.tcx.sess.at_least_rust_2018() { // this case used to be allowed by the compiler, @@ -429,8 +429,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.resolve_vars_if_possible(ty.value); let guar = match *ty.kind() { ty::Infer(ty::TyVar(_)) => { - let raw_ptr_call = - bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types; + let raw_ptr_call = bad_ty.reached_raw_pointer + && !self.tcx.features().arbitrary_self_types(); let mut err = self.err_ctxt().emit_inference_failure_err( self.body_id, span, @@ -813,7 +813,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) => None, + | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::HostEffect(..) => None, } }); @@ -1146,7 +1147,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } ty::Adt(def, args) - if self.tcx.features().pin_ergonomics + if self.tcx.features().pin_ergonomics() && self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => { // make sure this is a pinned reference (and not a `Pin` or something) @@ -1195,7 +1196,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self_ty: Ty<'tcx>, unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, ) -> Option> { - if !self.tcx.features().pin_ergonomics { + if !self.tcx.features().pin_ergonomics() { return None; } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 9dd59541148..eaf40a193a6 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -537,7 +537,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && binding_id != self.binding_id { if self.check_and_add_sugg_binding(LetStmt { - ty_hir_id_opt: if let Some(ty) = ty { Some(ty.hir_id) } else { None }, + ty_hir_id_opt: ty.map(|ty| ty.hir_id), binding_id, span: pat.span, init_hir_id: init.hir_id, diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index e961752b24c..cba6586f01d 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -442,7 +442,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let features = self.tcx.features(); - if features.ref_pat_eat_one_layer_2024 || features.ref_pat_eat_one_layer_2024_structural { + if features.ref_pat_eat_one_layer_2024() || features.ref_pat_eat_one_layer_2024_structural() + { def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl()); if def_br == ByRef::Yes(Mutability::Not) { max_ref_mutbl = MutblCap::Not; @@ -490,7 +491,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - if self.tcx.features().string_deref_patterns + if self.tcx.features().string_deref_patterns() && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind { let tcx = self.tcx; @@ -675,10 +676,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let bm = match user_bind_annot { BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => { if pat.span.at_least_rust_2024() - && (self.tcx.features().ref_pat_eat_one_layer_2024 - || self.tcx.features().ref_pat_eat_one_layer_2024_structural) + && (self.tcx.features().ref_pat_eat_one_layer_2024() + || self.tcx.features().ref_pat_eat_one_layer_2024_structural()) { - if !self.tcx.features().mut_ref { + if !self.tcx.features().mut_ref() { feature_err( &self.tcx.sess, sym::mut_ref, @@ -2152,8 +2153,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let tcx = self.tcx; let features = tcx.features(); - let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024; - let ref_pat_eat_one_layer_2024_structural = features.ref_pat_eat_one_layer_2024_structural; + let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024(); + let ref_pat_eat_one_layer_2024_structural = + features.ref_pat_eat_one_layer_2024_structural(); let no_ref_mut_behind_and = ref_pat_eat_one_layer_2024 || ref_pat_eat_one_layer_2024_structural; diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 63cf483aa22..88982661c8f 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -488,7 +488,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let final_upvar_tys = self.final_upvar_tys(closure_def_id); debug!(?closure_hir_id, ?args, ?final_upvar_tys); - if self.tcx.features().unsized_locals || self.tcx.features().unsized_fn_params { + if self.tcx.features().unsized_locals() || self.tcx.features().unsized_fn_params() { for capture in self.typeck_results.borrow().closure_min_captures_flattened(closure_def_id) { @@ -2457,7 +2457,7 @@ fn truncate_capture_for_optimization( ) -> (Place<'_>, ty::UpvarCapture) { let is_shared_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not)); - // Find the right-most deref (if any). All the projections that come after this + // Find the rightmost deref (if any). All the projections that come after this // are fields or other "in-place pointer adjustments"; these refer therefore to // data owned by whatever pointer is being dereferenced here. let idx = place.projections.iter().rposition(|proj| ProjectionKind::Deref == proj.kind); diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index d3d092be222..391e640f8bc 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -830,7 +830,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { value = tcx.fold_regions(value, |_, _| tcx.lifetimes.re_erased); // Normalize consts in writeback, because GCE doesn't normalize eagerly. - if tcx.features().generic_const_exprs { + if tcx.features().generic_const_exprs() { value = value.fold_with(&mut EagerlyNormalizeConsts { tcx, param_env: self.fcx.param_env }); } diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index a006786aa75..1f46155abc8 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -68,7 +68,7 @@ pub(crate) fn assert_dep_graph(tcx: TyCtxt<'_>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. - if !tcx.features().rustc_attrs { + if !tcx.features().rustc_attrs() { return; } diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index d25fe4219b5..2075d4214c1 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -140,7 +140,7 @@ pub(crate) fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { } // can't add `#[rustc_clean]` etc without opting into this feature - if !tcx.features().rustc_attrs { + if !tcx.features().rustc_attrs() { return; } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index e3519dfb028..90d07964fda 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -489,17 +489,6 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } } } - ty::ConstKind::Infer(InferConst::EffectVar(vid)) => { - match self.infcx.unwrap().probe_effect_var(vid) { - Some(value) => return self.fold_const(value), - None => { - return self.canonicalize_const_var( - CanonicalVarInfo { kind: CanonicalVarKind::Effect }, - ct, - ); - } - } - } ty::ConstKind::Infer(InferConst::Fresh(_)) => { bug!("encountered a fresh const during canonicalization") } @@ -700,8 +689,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { .iter() .map(|v| CanonicalVarInfo { kind: match v.kind { - CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) - | CanonicalVarKind::Effect => { + CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => { return *v; } CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => { diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 8caedcd4053..fb5fc3a53fe 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -24,7 +24,6 @@ pub use instantiate::CanonicalExt; use rustc_index::IndexVec; pub use rustc_middle::infer::canonical::*; -use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, GenericArg, List, Ty, TyCtxt}; use rustc_span::Span; @@ -145,15 +144,6 @@ impl<'tcx> InferCtxt<'tcx> { CanonicalVarKind::Const(ui) => { self.next_const_var_in_universe(span, universe_map(ui)).into() } - CanonicalVarKind::Effect => { - let vid = self - .inner - .borrow_mut() - .effect_unification_table() - .new_key(EffectVarValue::Unknown) - .vid; - ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid)).into() - } CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }) => { let universe_mapped = universe_map(universe); let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound }; diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 57007752cad..0c151a11ad4 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -1,6 +1,5 @@ ///! Definition of `InferCtxtLike` from the librarified type layer. use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::SolverMode; use rustc_middle::ty::fold::TypeFoldable; @@ -88,15 +87,6 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { } } - fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> { - match self.probe_effect_var(vid) { - Some(ct) => ct, - None => { - ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(self.root_effect_var(vid))) - } - } - } - fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) } @@ -152,10 +142,6 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.inner.borrow_mut().const_unification_table().union(a, b); } - fn equate_effect_vids_raw(&self, a: rustc_type_ir::EffectVid, b: rustc_type_ir::EffectVid) { - self.inner.borrow_mut().effect_unification_table().union(a, b); - } - fn instantiate_ty_var_raw>( &self, relation: &mut R, @@ -189,13 +175,6 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.inner.borrow_mut().float_unification_table().union_value(vid, value); } - fn instantiate_effect_var_raw(&self, vid: rustc_type_ir::EffectVid, value: ty::Const<'tcx>) { - self.inner - .borrow_mut() - .effect_unification_table() - .union_value(vid, EffectVarValue::Known(value)); - } - fn instantiate_const_var_raw>( &self, relation: &mut R, diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index c4294111ebe..28eac5b7496 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -153,15 +153,6 @@ impl<'a, 'tcx> TypeFolder> for TypeFreshener<'a, 'tcx> { drop(inner); self.freshen_const(input, ty::InferConst::Fresh) } - ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => { - let mut inner = self.infcx.inner.borrow_mut(); - let input = - inner.effect_unification_table().probe_value(v).known().ok_or_else(|| { - ty::InferConst::EffectVar(inner.effect_unification_table().find(v).vid) - }); - drop(inner); - self.freshen_const(input, ty::InferConst::Fresh) - } ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => { if i >= self.const_freshen_count { bug!( diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 5afdf3c2454..be43cba97f0 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -26,9 +26,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::extension; pub use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues}; -use rustc_middle::infer::unify_key::{ - ConstVariableOrigin, ConstVariableValue, ConstVidKey, EffectVarValue, EffectVidKey, -}; +use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::traits::select; @@ -39,7 +37,7 @@ use rustc_middle::ty::fold::{ }; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ - self, ConstVid, EffectVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef, + self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef, GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, }; use rustc_middle::{bug, span_bug}; @@ -117,9 +115,6 @@ pub struct InferCtxtInner<'tcx> { /// Map from floating variable to the kind of float it represents. float_unification_storage: ut::UnificationTableStorage, - /// Map from effect variable to the effect param it represents. - effect_unification_storage: ut::UnificationTableStorage>, - /// Tracks the set of region variables and the constraints between them. /// /// This is initially `Some(_)` but when @@ -176,7 +171,6 @@ impl<'tcx> InferCtxtInner<'tcx> { const_unification_storage: Default::default(), int_unification_storage: Default::default(), float_unification_storage: Default::default(), - effect_unification_storage: Default::default(), region_constraint_storage: Some(Default::default()), region_obligations: vec![], opaque_type_storage: Default::default(), @@ -228,10 +222,6 @@ impl<'tcx> InferCtxtInner<'tcx> { self.const_unification_storage.with_log(&mut self.undo_log) } - fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, EffectVidKey<'tcx>> { - self.effect_unification_storage.with_log(&mut self.undo_log) - } - #[inline] pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> { self.region_constraint_storage @@ -524,7 +514,6 @@ impl fmt::Display for FixupError { ), Ty(_) => write!(f, "unconstrained type"), Const(_) => write!(f, "unconstrained const value"), - Effect(_) => write!(f, "unconstrained effect value"), } } } @@ -726,17 +715,6 @@ impl<'tcx> InferCtxt<'tcx> { vars } - pub fn unsolved_effects(&self) -> Vec> { - let mut inner = self.inner.borrow_mut(); - let mut table = inner.effect_unification_table(); - - (0..table.len()) - .map(|i| ty::EffectVid::from_usize(i)) - .filter(|&vid| table.probe_value(vid).is_unknown()) - .map(|v| ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v))) - .collect() - } - #[instrument(skip(self), level = "debug")] pub fn sub_regions( &self, @@ -899,13 +877,6 @@ impl<'tcx> InferCtxt<'tcx> { ty::Const::new_var(self.tcx, vid) } - fn next_effect_var(&self) -> ty::Const<'tcx> { - let effect_vid = - self.inner.borrow_mut().effect_unification_table().new_key(EffectVarValue::Unknown).vid; - - ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid)) - } - pub fn next_int_var(&self) -> Ty<'tcx> { let next_int_var_id = self.inner.borrow_mut().int_unification_table().new_key(ty::IntVarValue::Unknown); @@ -991,10 +962,7 @@ impl<'tcx> InferCtxt<'tcx> { Ty::new_var(self.tcx, ty_var_id).into() } - GenericParamDefKind::Const { is_host_effect, .. } => { - if is_host_effect { - return self.var_for_effect(param); - } + GenericParamDefKind::Const { .. } => { let origin = ConstVariableOrigin { param_def_id: Some(param.def_id), span }; let const_var_id = self .inner @@ -1007,16 +975,6 @@ impl<'tcx> InferCtxt<'tcx> { } } - pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { - let ty = self - .tcx - .type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"); - debug_assert_eq!(self.tcx.types.bool, ty); - self.next_effect_var().into() - } - /// Given a set of generics defined on a type or impl, returns the generic parameters mapping /// each type/region parameter to a fresh inference variable. pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> { @@ -1142,13 +1100,6 @@ impl<'tcx> InferCtxt<'tcx> { .probe_value(vid) .known() .unwrap_or(ct), - InferConst::EffectVar(vid) => self - .inner - .borrow_mut() - .effect_unification_table() - .probe_value(vid) - .known() - .unwrap_or(ct), InferConst::Fresh(_) => ct, }, ty::ConstKind::Param(_) @@ -1169,10 +1120,6 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().const_unification_table().find(var).vid } - pub fn root_effect_var(&self, var: ty::EffectVid) -> ty::EffectVid { - self.inner.borrow_mut().effect_unification_table().find(var).vid - } - /// Resolves an int var to a rigid int type, if it was constrained to one, /// or else the root int var in the unification table. pub fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { @@ -1238,10 +1185,6 @@ impl<'tcx> InferCtxt<'tcx> { } } - pub fn probe_effect_var(&self, vid: EffectVid) -> Option> { - self.inner.borrow_mut().effect_unification_table().probe_value(vid).known() - } - /// Attempts to resolve all type/region/const variables in /// `value`. Region inference must have been run already (e.g., /// by calling `resolve_regions_and_report_errors`). If some @@ -1511,14 +1454,6 @@ impl<'tcx> InferCtxt<'tcx> { ConstVariableValue::Known { .. } => true, } } - - TyOrConstInferVar::Effect(v) => { - // If `probe_value` returns `Some`, it never equals - // `ty::ConstKind::Infer(ty::InferConst::Effect(v))`. - // - // Not `inlined_probe_value(v)` because this call site is colder. - self.probe_effect_var(v).is_some() - } } } @@ -1545,8 +1480,6 @@ pub enum TyOrConstInferVar { /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`. Const(ConstVid), - /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::EffectVar(_))`. - Effect(EffectVid), } impl<'tcx> TyOrConstInferVar { @@ -1577,7 +1510,6 @@ impl<'tcx> TyOrConstInferVar { fn maybe_from_const(ct: ty::Const<'tcx>) -> Option { match ct.kind() { ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)), - ty::ConstKind::Infer(InferConst::EffectVar(v)) => Some(TyOrConstInferVar::Effect(v)), _ => None, } } diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index e23bb1aaa56..1afe50e336d 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -24,19 +24,9 @@ pub fn explicit_outlives_bounds<'tcx>( param_env .caller_bounds() .into_iter() - .map(ty::Clause::kind) + .filter_map(ty::Clause::as_region_outlives_clause) .filter_map(ty::Binder::no_bound_vars) - .filter_map(move |kind| match kind { - ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => { - Some(OutlivesBound::RegionSubRegion(r_b, r_a)) - } - ty::ClauseKind::Trait(_) - | ty::ClauseKind::TypeOutlives(_) - | ty::ClauseKind::Projection(_) - | ty::ClauseKind::ConstArgHasType(_, _) - | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) => None, - }) + .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)) } impl<'tcx> InferCtxt<'tcx> { diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 7049444db9b..32817dbcb21 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -660,7 +660,6 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { } } } - ty::ConstKind::Infer(InferConst::EffectVar(_)) => Ok(c), // FIXME: Unevaluated constants are also not rigid, so the current // approach of always relating them structurally is incomplete. // diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 64cc76f827e..6ec2e0152f0 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -176,9 +176,6 @@ impl<'a, 'tcx> FallibleTypeFolder> for FullTypeResolver<'a, 'tcx> { ty::ConstKind::Infer(InferConst::Fresh(_)) => { bug!("Unexpected const in full const resolver: {:?}", c); } - ty::ConstKind::Infer(InferConst::EffectVar(evid)) => { - return Err(FixupError { unresolved: super::TyOrConstInferVar::Effect(evid) }); - } _ => {} } c.try_super_fold_with(self) diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index 613cebc266d..394e07a81e7 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -4,7 +4,6 @@ use rustc_data_structures::{snapshot_vec as sv, unify as ut}; use rustc_middle::infer::unify_key::{ConstVariableValue, ConstVidKey}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid}; -use rustc_type_ir::EffectVid; use rustc_type_ir::visit::TypeVisitableExt; use tracing::instrument; use ut::UnifyKey; @@ -129,7 +128,6 @@ struct SnapshotVarData { int_vars: Range, float_vars: Range, const_vars: (Range, Vec), - effect_vars: Range, } impl SnapshotVarData { @@ -148,30 +146,16 @@ impl SnapshotVarData { &mut inner.const_unification_table(), vars_pre_snapshot.const_var_len, ); - let effect_vars = vars_since_snapshot( - &inner.effect_unification_table(), - vars_pre_snapshot.effect_var_len, - ); - let effect_vars = effect_vars.start.vid..effect_vars.end.vid; - - SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars, effect_vars } + SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars } } fn is_empty(&self) -> bool { - let SnapshotVarData { - region_vars, - type_vars, - int_vars, - float_vars, - const_vars, - effect_vars, - } = self; + let SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars } = self; region_vars.0.is_empty() && type_vars.0.is_empty() && int_vars.is_empty() && float_vars.is_empty() && const_vars.0.is_empty() - && effect_vars.is_empty() } } @@ -258,13 +242,6 @@ impl<'a, 'tcx> TypeFolder> for InferenceFudger<'a, 'tcx> { ct } } - ty::InferConst::EffectVar(vid) => { - if self.snapshot_vars.effect_vars.contains(&vid) { - self.infcx.next_effect_var() - } else { - ct - } - } ty::InferConst::Fresh(_) => { unreachable!("unexpected fresh infcx var") } diff --git a/compiler/rustc_infer/src/infer/snapshot/mod.rs b/compiler/rustc_infer/src/infer/snapshot/mod.rs index fa813500c54..b16c80cf201 100644 --- a/compiler/rustc_infer/src/infer/snapshot/mod.rs +++ b/compiler/rustc_infer/src/infer/snapshot/mod.rs @@ -23,7 +23,6 @@ struct VariableLengths { int_var_len: usize, float_var_len: usize, const_var_len: usize, - effect_var_len: usize, } impl<'tcx> InferCtxt<'tcx> { @@ -35,7 +34,6 @@ impl<'tcx> InferCtxt<'tcx> { int_var_len: inner.int_unification_table().len(), float_var_len: inner.float_unification_table().len(), const_var_len: inner.const_unification_table().len(), - effect_var_len: inner.effect_unification_table().len(), } } diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index 79ea0915c9c..713389f4618 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::{snapshot_vec as sv, unify as ut}; -use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey, RegionVidKey}; +use rustc_middle::infer::unify_key::{ConstVidKey, RegionVidKey}; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey}; use tracing::debug; @@ -22,7 +22,6 @@ pub(crate) enum UndoLog<'tcx> { ConstUnificationTable(sv::UndoLog>>), IntUnificationTable(sv::UndoLog>), FloatUnificationTable(sv::UndoLog>), - EffectUnificationTable(sv::UndoLog>>), RegionConstraintCollector(region_constraints::UndoLog<'tcx>), RegionUnificationTable(sv::UndoLog>>), ProjectionCache(traits::UndoLog<'tcx>), @@ -50,7 +49,6 @@ impl_from! { FloatUnificationTable(sv::UndoLog>), ConstUnificationTable(sv::UndoLog>>), - EffectUnificationTable(sv::UndoLog>>), RegionUnificationTable(sv::UndoLog>>), ProjectionCache(traits::UndoLog<'tcx>), @@ -65,7 +63,6 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo), UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo), UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo), - UndoLog::EffectUnificationTable(undo) => self.effect_unification_storage.reverse(undo), UndoLog::RegionConstraintCollector(undo) => { self.region_constraint_storage.as_mut().unwrap().reverse(undo) } diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 779ce976bec..2086483b94a 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -187,10 +187,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { value_count: usize, ) -> (Range, Vec) { let range = TyVid::from_usize(value_count)..TyVid::from_usize(self.num_vars()); - ( - range.start..range.end, - (range.start..range.end).map(|index| self.var_origin(index)).collect(), - ) + (range.clone(), range.map(|index| self.var_origin(index)).collect()) } /// Returns indices of all variables that are not yet diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 3189620e969..d3762e739db 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -836,6 +836,7 @@ fn test_unstable_options_tracking_hash() { tracked!(profile_emit, Some(PathBuf::from("abc"))); tracked!(profile_sample_use, Some(PathBuf::from("abc"))); tracked!(profiler_runtime, "abc".to_string()); + tracked!(regparm, Some(3)); tracked!(relax_elf_relocations, Some(true)); tracked!(remap_cwd_prefix, Some(PathBuf::from("abc"))); tracked!(sanitizer, SanitizerSet::ADDRESS); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index c4d709aa1f9..3fa43296dfc 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -203,14 +203,14 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i .current_use = this identifier can be confused with `{$existing_sym}` .other_use = other identifier used here -lint_cstring_ptr = getting the inner pointer of a temporary `CString` - .as_ptr_label = this pointer will be invalid - .unwrap_label = this `CString` 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 `as_ptr` the `CString` 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 - lint_custom_inner_attribute_unstable = custom inner attributes are unstable +lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped + .label_ptr = this pointer will immediately be invalid + .label_temporary = this `{$ty}` 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 `{$callee}` the `{$ty}` 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 + lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs index 63a8a949e96..9923f05df3c 100644 --- a/compiler/rustc_lint/src/async_fn_in_trait.rs +++ b/compiler/rustc_lint/src/async_fn_in_trait.rs @@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait { && let hir::IsAsync::Async(async_span) = sig.header.asyncness { // RTN can be used to bound `async fn` in traits in a better way than "always" - if cx.tcx.features().return_type_notation { + if cx.tcx.features().return_type_notation() { return; } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ef8100da9e2..dbb8c667532 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -4,21 +4,14 @@ //! AST visitor. Also see `rustc_session::lint::builtin`, which contains the //! definitions of lints that are emitted directly inside the main compiler. //! -//! To add a new lint to rustc, declare it here using `declare_lint!()`. +//! To add a new lint to rustc, declare it here using [`declare_lint!`]. //! Then add code to emit the new lint in the appropriate circumstances. -//! You can do that in an existing `LintPass` if it makes sense, or in a -//! new `LintPass`, or using `Session::add_lint` elsewhere in the -//! compiler. Only do the latter if the check can't be written cleanly as a -//! `LintPass` (also, note that such lints will need to be defined in -//! `rustc_session::lint::builtin`, not here). //! -//! If you define a new `EarlyLintPass`, you will also need to add it to the -//! `add_early_builtin!` or `add_early_builtin_with_new!` invocation in -//! `lib.rs`. Use the former for unit-like structs and the latter for structs -//! with a `pub fn new()`. +//! If you define a new [`EarlyLintPass`], you will also need to add it to the +//! [`crate::early_lint_methods!`] invocation in `lib.rs`. //! -//! If you define a new `LateLintPass`, you will also need to add it to the -//! `late_lint_methods!` invocation in `lib.rs`. +//! If you define a new [`LateLintPass`], you will also need to add it to the +//! [`crate::late_lint_methods!`] invocation in `lib.rs`. use std::fmt::Write; @@ -73,7 +66,6 @@ use crate::{ EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, fluent_generated as fluent, }; - declare_lint! { /// The `while_true` lint detects `while true { }`. /// @@ -241,7 +233,8 @@ declare_lint! { /// behavior. UNSAFE_CODE, Allow, - "usage of `unsafe` code and other potentially unsound constructs" + "usage of `unsafe` code and other potentially unsound constructs", + @eval_always = true } declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]); @@ -389,6 +382,7 @@ declare_lint! { report_in_external_macro } +#[derive(Default)] pub struct MissingDoc; impl_lint_pass!(MissingDoc => [MISSING_DOCS]); @@ -819,8 +813,8 @@ pub struct DeprecatedAttr { impl_lint_pass!(DeprecatedAttr => []); -impl DeprecatedAttr { - pub fn new() -> DeprecatedAttr { +impl Default for DeprecatedAttr { + fn default() -> Self { DeprecatedAttr { depr_attrs: deprecated_attributes() } } } @@ -1235,7 +1229,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { def_id: LocalDefId, ) { if fn_kind.asyncness().is_async() - && !cx.tcx.features().async_fn_track_caller + && !cx.tcx.features().async_fn_track_caller() // Now, check if the function has the `#[track_caller]` attribute && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller) { @@ -1424,7 +1418,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { // See also `tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs`. let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); if ty.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) - && cx.tcx.features().generic_const_exprs + && cx.tcx.features().generic_const_exprs() { return; } @@ -1538,7 +1532,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { use rustc_middle::ty::ClauseKind; - if cx.tcx.features().trivial_bounds { + if cx.tcx.features().trivial_bounds() { let predicates = cx.tcx.predicates_of(item.owner_id); for &(predicate, span) in predicates.predicates { let predicate_kind_name = match predicate.kind().skip_binder() { @@ -1554,7 +1548,9 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { // Ignore bounds that a user can't type | ClauseKind::WellFormed(..) // FIXME(generic_const_exprs): `ConstEvaluatable` can be written - | ClauseKind::ConstEvaluatable(..) => continue, + | ClauseKind::ConstEvaluatable(..) + // Users don't write this directly, only via another trait ref. + | ty::ClauseKind::HostEffect(..) => continue, }; if predicate.is_global() { cx.emit_span_lint(TRIVIAL_BOUNDS, span, BuiltinTrivialBounds { @@ -1892,11 +1888,11 @@ impl EarlyLintPass for KeywordIdents { fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) { self.check_tokens(cx, &mac.args.tokens); } - fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) { + fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: &Ident) { if ident.name.as_str().starts_with('\'') { self.check_ident_token(cx, UnderMacro(false), ident.without_first_quote(), "'"); } else { - self.check_ident_token(cx, UnderMacro(false), ident, ""); + self.check_ident_token(cx, UnderMacro(false), *ident, ""); } } } @@ -2287,13 +2283,15 @@ declare_lint_pass!( impl EarlyLintPass for IncompleteInternalFeatures { fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { let features = cx.builder.features(); - features - .declared_lang_features - .iter() - .map(|(name, span, _)| (name, span)) - .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span))) - .filter(|(&name, _)| features.incomplete(name) || features.internal(name)) - .for_each(|(&name, &span)| { + let lang_features = + features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); + let lib_features = + features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); + + lang_features + .chain(lib_features) + .filter(|(name, _)| features.incomplete(*name) || features.internal(*name)) + .for_each(|(name, span)| { if features.incomplete(name) { let note = rustc_feature::find_feature_issue(name, GateIssue::Language) .map(|n| BuiltinFeatureIssueNote { n }); @@ -2657,8 +2655,8 @@ declare_lint! { /// /// ### Explanation /// - /// Dereferencing a null pointer causes [undefined behavior] even as a place expression, - /// like `&*(0 as *const i32)` or `addr_of!(*(0 as *const i32))`. + /// Dereferencing a null pointer causes [undefined behavior] if it is accessed + /// (loaded from or stored to). /// /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html pub DEREF_NULLPTR, @@ -2673,14 +2671,14 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr { /// test if expression is a null ptr fn is_null_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { match &expr.kind { - rustc_hir::ExprKind::Cast(expr, ty) => { - if let rustc_hir::TyKind::Ptr(_) = ty.kind { + hir::ExprKind::Cast(expr, ty) => { + if let hir::TyKind::Ptr(_) = ty.kind { return is_zero(expr) || is_null_ptr(cx, expr); } } // check for call to `core::ptr::null` or `core::ptr::null_mut` - rustc_hir::ExprKind::Call(path, _) => { - if let rustc_hir::ExprKind::Path(ref qpath) = path.kind { + hir::ExprKind::Call(path, _) => { + if let hir::ExprKind::Path(ref qpath) = path.kind { if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() { return matches!( cx.tcx.get_diagnostic_name(def_id), @@ -2697,7 +2695,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr { /// test if expression is the literal `0` fn is_zero(expr: &hir::Expr<'_>) -> bool { match &expr.kind { - rustc_hir::ExprKind::Lit(lit) => { + hir::ExprKind::Lit(lit) => { if let LitKind::Int(a, _) = lit.node { return a == 0; } @@ -2707,8 +2705,16 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr { false } - if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind { - if is_null_ptr(cx, expr_deref) { + if let hir::ExprKind::Unary(hir::UnOp::Deref, expr_deref) = expr.kind + && is_null_ptr(cx, expr_deref) + { + if let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::AddrOf(hir::BorrowKind::Raw, ..), + .. + }) = cx.tcx.parent_hir_node(expr.hir_id) + { + // `&raw *NULL` is ok. + } else { cx.emit_span_lint(DEREF_NULLPTR, expr.span, BuiltinDerefNullptr { label: expr.span, }); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 39f90a8e9ed..4af1fd1baf9 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -1,18 +1,7 @@ -//! Implementation of lint checking. +//! Basic types for managing and implementing lints. //! -//! The lint checking is mostly consolidated into one pass which runs -//! after all other analyses. Throughout compilation, lint warnings -//! can be added via the `add_lint` method on the Session structure. This -//! requires a span and an ID of the node that the lint is being added to. The -//! lint isn't actually emitted at that time because it is unknown what the -//! actual lint level at that location is. -//! -//! To actually emit lint warnings/errors, a separate pass is used. -//! A context keeps track of the current state of all lint levels. -//! Upon entering a node of the ast which can modify the lint settings, the -//! previous lint state is pushed onto a stack and the ast is then recursed -//! upon. As the ast is traversed, this keeps track of the current lint level -//! for all lint attributes. +//! See for an +//! overview of how lints are implemented. use std::cell::Cell; use std::{iter, slice}; @@ -52,9 +41,6 @@ type LateLintPassFactory = dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync; /// Information about the registered lints. -/// -/// This is basically the subset of `Context` that we can -/// build early in the compile pipeline. pub struct LintStore { /// Registered lints. lints: Vec<&'static Lint>, diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs new file mode 100644 index 00000000000..a34c3e26778 --- /dev/null +++ b/compiler/rustc_lint/src/dangling.rs @@ -0,0 +1,223 @@ +use rustc_ast::visit::{visit_opt, walk_list}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; +use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem}; +use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_session::{declare_lint, impl_lint_pass}; +use rustc_span::Span; +use rustc_span::symbol::sym; + +use crate::lints::DanglingPointersFromTemporaries; +use crate::{LateContext, LateLintPass}; + +declare_lint! { + /// The `dangling_pointers_from_temporaries` lint detects getting a pointer to data + /// of a temporary that will immediately get dropped. + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// # unsafe fn use_data(ptr: *const u8) { } + /// fn gather_and_use(bytes: impl Iterator) { + /// let x: *const u8 = bytes.collect::>().as_ptr(); + /// unsafe { use_data(x) } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Getting a pointer from a temporary value will not prolong its lifetime, + /// which means that the value can be dropped and the allocation freed + /// while the pointer still exists, making the pointer dangling. + /// This is not an error (as far as the type system is concerned) + /// but probably is not what the user intended either. + /// + /// If you need stronger guarantees, consider using references instead, + /// as they are statically verified by the borrow-checker to never dangle. + pub DANGLING_POINTERS_FROM_TEMPORARIES, + Warn, + "detects getting a pointer from a temporary" +} + +/// 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: +/// - `owning_temporary.field` +/// - `owning_temporary[index]` +/// 3. No checks for ref-to-ptr conversions: +/// - `&raw [mut] temporary` +/// - `&temporary as *(const|mut) _` +/// - `ptr::from_ref(&temporary)` and friends +#[derive(Clone, Copy, Default)] +pub(crate) struct DanglingPointers; + +impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]); + +// This skips over const blocks, but they cannot use or return a dangling pointer anyways. +impl<'tcx> LateLintPass<'tcx> for DanglingPointers { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + _: FnKind<'tcx>, + _: &'tcx FnDecl<'tcx>, + body: &'tcx Body<'tcx>, + _: Span, + _: LocalDefId, + ) { + DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body) + } +} + +/// This produces a dangling pointer: +/// ```ignore (example) +/// let ptr = CString::new("hello").unwrap().as_ptr(); +/// foo(ptr) +/// ``` +/// +/// But this does not: +/// ```ignore (example) +/// foo(CString::new("hello").unwrap().as_ptr()) +/// ``` +/// +/// But this does: +/// ```ignore (example) +/// foo({ let ptr = CString::new("hello").unwrap().as_ptr(); ptr }) +/// ``` +/// +/// So we have to keep track of when we are inside of a function/method call argument. +struct DanglingPointerSearcher<'lcx, 'tcx> { + cx: &'lcx LateContext<'tcx>, + /// Keeps track of whether we are inside of function/method call arguments, + /// where this lint should not be emitted. + /// + /// See [the main doc][`Self`] for examples. + inside_call_args: bool, +} + +impl Visitor<'_> for DanglingPointerSearcher<'_, '_> { + fn visit_expr(&mut self, expr: &Expr<'_>) -> Self::Result { + if !self.inside_call_args { + lint_expr(self.cx, expr) + } + match expr.kind { + ExprKind::Call(lhs, args) | ExprKind::MethodCall(_, lhs, args, _) => { + self.visit_expr(lhs); + self.with_inside_call_args(true, |this| walk_list!(this, visit_expr, args)) + } + ExprKind::Block(&Block { stmts, expr, .. }, _) => { + self.with_inside_call_args(false, |this| walk_list!(this, visit_stmt, stmts)); + visit_opt!(self, visit_expr, expr) + } + _ => walk_expr(self, expr), + } + } +} + +impl DanglingPointerSearcher<'_, '_> { + fn with_inside_call_args( + &mut self, + inside_call_args: bool, + callback: impl FnOnce(&mut Self) -> R, + ) -> R { + let old = core::mem::replace(&mut self.inside_call_args, inside_call_args); + let result = callback(self); + self.inside_call_args = old; + result + } +} + +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) + && is_temporary_rvalue(receiver) + && let ty = cx.typeck_results().expr_ty(receiver) + && is_interesting(cx.tcx, ty) + { + // FIXME: use `emit_node_lint` when `#[primary_span]` is added. + cx.tcx.emit_node_span_lint( + DANGLING_POINTERS_FROM_TEMPORARIES, + expr.hir_id, + method.ident.span, + DanglingPointersFromTemporaries { + callee: method.ident.name, + ty, + ptr_span: method.ident.span, + temporary_span: receiver.span, + }, + ) + } +} + +fn is_temporary_rvalue(expr: &Expr<'_>) -> bool { + match expr.kind { + // Const is not temporary. + ExprKind::ConstBlock(..) | ExprKind::Repeat(..) | ExprKind::Lit(..) => false, + + // This is literally lvalue. + ExprKind::Path(..) => false, + + // Calls return rvalues. + ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) => true, + + // Inner blocks are rvalues. + ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::Block(..) => true, + + // FIXME: these should probably recurse and typecheck along the way. + // Some false negatives are possible for now. + ExprKind::Index(..) | ExprKind::Field(..) | ExprKind::Unary(..) => false, + + ExprKind::Struct(..) => true, + + // FIXME: this has false negatives, but I do not want to deal with 'static/const promotion just yet. + ExprKind::Array(..) => false, + + // These typecheck to `!` + ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) | ExprKind::Become(..) => { + false + } + + // These typecheck to `()` + ExprKind::Assign(..) | ExprKind::AssignOp(..) | ExprKind::Yield(..) => false, + + // Compiler-magic macros + ExprKind::AddrOf(..) | ExprKind::OffsetOf(..) | ExprKind::InlineAsm(..) => false, + + // We are not interested in these + ExprKind::Cast(..) + | ExprKind::Closure(..) + | ExprKind::Tup(..) + | ExprKind::DropTemps(..) + | ExprKind::Let(..) => false, + + // Not applicable + ExprKind::Type(..) | ExprKind::Err(..) => false, + } +} + +// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box, Box, +// or any of the above in arbitrary many nested Box'es. +fn is_interesting(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) + } else if let Some(def) = ty.ty_adt_def() { + for lang_item in [LangItem::String, LangItem::MaybeUninit] { + 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)) + } else { + false + } +} diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 2285877c9ef..acccff77a10 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -1,18 +1,8 @@ -//! Implementation of lint checking. +//! Implementation of the early lint pass. //! -//! The lint checking is mostly consolidated into one pass which runs -//! after all other analyses. Throughout compilation, lint warnings -//! can be added via the `add_lint` method on the Session structure. This -//! requires a span and an ID of the node that the lint is being added to. The -//! lint isn't actually emitted at that time because it is unknown what the -//! actual lint level at that location is. -//! -//! To actually emit lint warnings/errors, a separate pass is used. -//! A context keeps track of the current state of all lint levels. -//! Upon entering a node of the ast which can modify the lint settings, the -//! previous lint state is pushed onto a stack and the ast is then recursed -//! upon. As the ast is traversed, this keeps track of the current lint level -//! for all lint attributes. +//! The early lint pass works on AST nodes after macro expansion and name +//! resolution, just before AST lowering. These lints are for purely +//! syntactical lints. use rustc_ast::ptr::P; use rustc_ast::visit::{self as ast_visit, Visitor, walk_list}; @@ -121,6 +111,18 @@ 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); }) } @@ -190,7 +192,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> ast_visit::walk_ty(self, t); } - fn visit_ident(&mut self, ident: Ident) { + fn visit_ident(&mut self, ident: &Ident) { lint_callback!(self, check_ident, ident); } @@ -214,21 +216,6 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> }) } - fn visit_expr_post(&mut self, e: &'a ast::Expr) { - // 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), - .. - }) => { - self.check_id(coroutine_kind.closure_id()); - } - _ => {} - } - lint_callback!(self, check_expr_post, e); - } - fn visit_generic_arg(&mut self, arg: &'a ast::GenericArg) { lint_callback!(self, check_generic_arg, arg); ast_visit::walk_generic_arg(self, arg); @@ -312,6 +299,9 @@ impl LintPass for RuntimeCombinedEarlyLintPass<'_> { fn name(&self) -> &'static str { panic!() } + fn get_lints(&self) -> crate::LintVec { + panic!() + } } macro_rules! impl_early_lint_pass { diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 58fd11fcc29..bdfcc2c0a10 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -243,7 +243,7 @@ impl_lint_pass!( impl<'tcx> LateLintPass<'tcx> for IfLetRescope { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { - if expr.span.edition().at_least_rust_2024() || !cx.tcx.features().if_let_rescope { + if expr.span.edition().at_least_rust_2024() || !cx.tcx.features().if_let_rescope() { return; } if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) { diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index d029ad93407..cc40b67ab27 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -263,8 +263,8 @@ where && parent == self.parent_def_id { let opaque_span = self.tcx.def_span(opaque_def_id); - let new_capture_rules = - opaque_span.at_least_rust_2024() || self.tcx.features().lifetime_capture_rules_2024; + let new_capture_rules = opaque_span.at_least_rust_2024() + || self.tcx.features().lifetime_capture_rules_2024(); if !new_capture_rules && !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..))) { diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 94cc58e4956..2f338f42f19 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -427,9 +427,10 @@ declare_tool_lint! { /// More details on translatable diagnostics can be found /// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/translation.html). pub rustc::UNTRANSLATABLE_DIAGNOSTIC, - Deny, + Allow, "prevent creation of diagnostics which cannot be translated", - report_in_external_macro: true + report_in_external_macro: true, + @eval_always = true } declare_tool_lint! { @@ -440,9 +441,10 @@ declare_tool_lint! { /// More details on diagnostics implementations can be found /// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html). pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL, - Deny, + Allow, "prevent diagnostic creation outside of `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls", - report_in_external_macro: true + report_in_external_macro: true, + @eval_always = true } declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]); diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 6d5903ac467..9d35ce19b57 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -1,18 +1,7 @@ -//! Implementation of lint checking. +//! Implementation of the late lint pass. //! -//! The lint checking is mostly consolidated into one pass which runs -//! after all other analyses. Throughout compilation, lint warnings -//! can be added via the `add_lint` method on the Session structure. This -//! requires a span and an ID of the node that the lint is being added to. The -//! lint isn't actually emitted at that time because it is unknown what the -//! actual lint level at that location is. -//! -//! To actually emit lint warnings/errors, a separate pass is used. -//! A context keeps track of the current state of all lint levels. -//! Upon entering a node of the ast which can modify the lint settings, the -//! previous lint state is pushed onto a stack and the ast is then recursed -//! upon. As the ast is traversed, this keeps track of the current lint level -//! for all lint attributes. +//! The late lint pass Works on HIR nodes, towards the end of analysis (after +//! borrow checking, etc.). These lints have full type information available. use std::any::Any; use std::cell::Cell; @@ -26,11 +15,12 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::Session; use rustc_session::lint::LintPass; +use rustc_session::lint::builtin::HardwiredLints; use rustc_span::Span; use tracing::debug; use crate::passes::LateLintPassObject; -use crate::{LateContext, LateLintPass, LintStore}; +use crate::{LateContext, LateLintPass, LintId, LintStore}; /// Extract the [`LintStore`] from [`Session`]. /// @@ -326,6 +316,9 @@ impl LintPass for RuntimeCombinedLateLintPass<'_, '_> { fn name(&self) -> &'static str { panic!() } + fn get_lints(&self) -> crate::LintVec { + panic!() + } } macro_rules! impl_late_lint_pass { @@ -361,13 +354,20 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( // Note: `passes` is often empty. In that case, it's faster to run // `builtin_lints` directly rather than bundling it up into the // `RuntimeCombinedLateLintPass`. - let late_module_passes = &unerased_lint_store(tcx.sess).late_module_passes; - if late_module_passes.is_empty() { + let store = unerased_lint_store(tcx.sess); + + if store.late_module_passes.is_empty() { late_lint_mod_inner(tcx, module_def_id, context, builtin_lints); } else { - let mut passes: Vec<_> = late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); - passes.push(Box::new(builtin_lints)); - let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] }; + let builtin_lints = Box::new(builtin_lints) as Box>; + let mut binding = store + .late_module_passes + .iter() + .map(|mk_pass| (mk_pass)(tcx)) + .chain(std::iter::once(builtin_lints)) + .collect::>(); + + let pass = RuntimeCombinedLateLintPass { passes: binding.as_mut_slice() }; late_lint_mod_inner(tcx, module_def_id, context, pass); } } @@ -398,7 +398,7 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>( fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) { // Note: `passes` is often empty. - let mut passes: Vec<_> = + let passes: Vec<_> = unerased_lint_store(tcx.sess).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); if passes.is_empty() { @@ -416,7 +416,18 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) { only_module: false, }; - let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] }; + let lints_that_dont_need_to_run = tcx.lints_that_dont_need_to_run(()); + + let mut filtered_passes: Vec>> = passes + .into_iter() + .filter(|pass| { + let lints = (**pass).get_lints(); + !lints.iter().all(|lint| lints_that_dont_need_to_run.contains(&LintId::of(lint))) + }) + .collect(); + + filtered_passes.push(Box::new(HardwiredLints)); + let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] }; late_lint_crate_inner(tcx, context, pass); } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 95a8e7625ff..97a95787422 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,9 +1,9 @@ use rustc_ast_pretty::pprust; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{Diag, LintDiagnostic, MultiSpan}; use rustc_feature::{Features, GateIssue}; -use rustc_hir::HirId; use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::{CRATE_HIR_ID, HirId}; use rustc_index::IndexVec; use rustc_middle::bug; use rustc_middle::hir::nested_filter; @@ -115,6 +115,38 @@ impl LintLevelSets { } } +fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { + let store = unerased_lint_store(&tcx.sess); + + let map = tcx.shallow_lint_levels_on(rustc_hir::CRATE_OWNER_ID); + + let dont_need_to_run: FxIndexSet = store + .get_lints() + .into_iter() + .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 + } + } else { + None + } + }) + .collect(); + + let mut visitor = LintLevelMaximum { tcx, dont_need_to_run }; + visitor.process_opts(); + tcx.hir().walk_attributes(&mut visitor); + + visitor.dont_need_to_run +} + #[instrument(level = "trace", skip(tcx), ret)] fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap { let store = unerased_lint_store(tcx.sess); @@ -301,6 +333,83 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { } } +/// Visitor with the only function of visiting every item-like in a crate and +/// computing the highest level that every lint gets put to. +/// +/// E.g., if a crate has a global #![allow(lint)] attribute, but a single item +/// uses #[warn(lint)], this visitor will set that lint level as `Warn` +struct LintLevelMaximum<'tcx> { + tcx: TyCtxt<'tcx>, + /// The actual list of detected lints. + dont_need_to_run: FxIndexSet, +} + +impl<'tcx> LintLevelMaximum<'tcx> { + fn process_opts(&mut self) { + let store = unerased_lint_store(self.tcx.sess); + for (lint_group, level) in &self.tcx.sess.opts.lint_opts { + if *level != Level::Allow { + let Ok(lints) = store.find_lints(lint_group) else { + return; + }; + for lint in lints { + self.dont_need_to_run.swap_remove(&lint); + } + } + } + } +} + +impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> { + type NestedFilter = nested_filter::All; + + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() + } + + /// FIXME(blyxyas): In a future revision, we should also graph #![allow]s, + /// but that is handled with more care + fn visit_attribute(&mut self, attribute: &'tcx ast::Attribute) { + if matches!( + Level::from_attr(attribute), + Some( + Level::Warn + | Level::Deny + | Level::Forbid + | Level::Expect(..) + | Level::ForceWarn(..), + ) + ) { + let store = unerased_lint_store(self.tcx.sess); + let Some(meta) = attribute.meta() else { return }; + // Lint attributes are always a metalist inside a + // metalist (even with just one lint). + let Some(meta_item_list) = meta.meta_item_list() else { return }; + + for meta_list in meta_item_list { + // Convert Path to String + let Some(meta_item) = meta_list.meta_item() else { return }; + let ident: &str = &meta_item + .path + .segments + .iter() + .map(|segment| segment.ident.as_str()) + .collect::>() + .join("::"); + let Ok(lints) = store.find_lints( + // Lint attributes can only have literals + ident, + ) else { + return; + }; + for lint in lints { + self.dont_need_to_run.swap_remove(&lint); + } + } + } + } +} + pub struct LintLevelsBuilder<'s, P> { sess: &'s Session, features: &'s Features, @@ -858,7 +967,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { #[track_caller] fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool { let feature = if let Some(feature) = lint_id.lint.feature_gate - && !self.features.active(feature) + && !self.features.enabled(feature) { // Lint is behind a feature that is not enabled; eventually return false. feature @@ -934,7 +1043,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { shallow_lint_levels_on, ..*providers }; + *providers = Providers { shallow_lint_levels_on, lints_that_dont_need_to_run, ..*providers }; } pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option, &str) { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index a7faab0868d..86112277504 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -6,20 +6,14 @@ //! other phases of the compiler, which are generally required to hold in order //! to compile the program at all. //! -//! Most lints can be written as [LintPass] instances. These run after +//! Most lints can be written as [`LintPass`] instances. These run after //! all other analyses. The `LintPass`es built into rustc are defined //! within [rustc_session::lint::builtin], //! which has further comments on how to add such a lint. //! rustc can also load external lint plugins, as is done for Clippy. //! -//! Some of rustc's lints are defined elsewhere in the compiler and work by -//! calling `add_lint()` on the overall `Session` object. This works when -//! it happens before the main lint pass, which emits the lints stored by -//! `add_lint()`. To emit lints after the main lint pass (from codegen, for -//! example) requires more effort. See `emit_lint` and `GatherNodeLevels` -//! in `context.rs`. -//! -//! Some code also exists in [rustc_session::lint], [rustc_middle::lint]. +//! See for an +//! overview of how lints are implemented. //! //! ## Note //! @@ -46,6 +40,7 @@ mod async_closures; mod async_fn_in_trait; pub mod builtin; mod context; +mod dangling; mod deref_into_dyn_supertrait; mod drop_forget_useless; mod early; @@ -65,7 +60,6 @@ mod levels; mod lints; mod macro_expr_fragment_specifier_2024_migration; mod map_unit_fn; -mod methods; mod multiple_supertrait_upcastable; mod non_ascii_idents; mod non_fmt_panic; @@ -91,6 +85,7 @@ mod unused; use async_closures::AsyncClosureUsage; use async_fn_in_trait::AsyncFnInTrait; use builtin::*; +use dangling::*; use deref_into_dyn_supertrait::*; use drop_forget_useless::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; @@ -103,7 +98,6 @@ use invalid_from_utf8::*; use let_underscore::*; use macro_expr_fragment_specifier_2024_migration::*; use map_unit_fn::*; -use methods::*; use multiple_supertrait_upcastable::*; use non_ascii_idents::*; use non_fmt_panic::NonPanicFmt; @@ -170,7 +164,7 @@ early_lint_methods!( [ pub BuiltinCombinedEarlyLintPass, [ - UnusedParens: UnusedParens::new(), + UnusedParens: UnusedParens::default(), UnusedBraces: UnusedBraces, UnusedImportBraces: UnusedImportBraces, UnsafeCode: UnsafeCode, @@ -178,7 +172,7 @@ early_lint_methods!( AnonymousParameters: AnonymousParameters, EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), NonCamelCaseTypes: NonCamelCaseTypes, - DeprecatedAttr: DeprecatedAttr::new(), + DeprecatedAttr: DeprecatedAttr::default(), WhileTrue: WhileTrue, NonAsciiIdents: NonAsciiIdents, HiddenUnicodeCodepoints: HiddenUnicodeCodepoints, @@ -199,7 +193,6 @@ late_lint_methods!( ForLoopsOverFallibles: ForLoopsOverFallibles, DerefIntoDynSupertrait: DerefIntoDynSupertrait, DropForgetUseless: DropForgetUseless, - HardwiredLints: HardwiredLints, ImproperCTypesDeclarations: ImproperCTypesDeclarations, ImproperCTypesDefinitions: ImproperCTypesDefinitions, InvalidFromUtf8: InvalidFromUtf8, @@ -232,7 +225,7 @@ late_lint_methods!( UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller, ShadowedIntoIter: ShadowedIntoIter, DropTraitConstraints: DropTraitConstraints, - TemporaryCStringAsPtr: TemporaryCStringAsPtr, + DanglingPointers: DanglingPointers, NonPanicFmt: NonPanicFmt, NoopMethodCall: NoopMethodCall, EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums, @@ -280,6 +273,7 @@ fn register_builtins(store: &mut LintStore) { store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints()); store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints()); store.register_lints(&foreign_modules::get_lints()); + store.register_lints(&HardwiredLints::lint_vec()); add_lint_group!( "nonstandard_style", @@ -356,6 +350,7 @@ fn register_builtins(store: &mut LintStore) { store.register_renamed("non_fmt_panic", "non_fmt_panics"); store.register_renamed("unused_tuple_struct_fields", "dead_code"); store.register_renamed("static_mut_ref", "static_mut_refs"); + store.register_renamed("temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"); // These were moved to tool lints, but rustc still sees them when compiling normally, before // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use @@ -602,25 +597,25 @@ fn register_builtins(store: &mut LintStore) { } fn register_internals(store: &mut LintStore) { - store.register_lints(&LintPassImpl::get_lints()); + store.register_lints(&LintPassImpl::lint_vec()); store.register_early_pass(|| Box::new(LintPassImpl)); - store.register_lints(&DefaultHashTypes::get_lints()); + store.register_lints(&DefaultHashTypes::lint_vec()); store.register_late_mod_pass(|_| Box::new(DefaultHashTypes)); - store.register_lints(&QueryStability::get_lints()); + store.register_lints(&QueryStability::lint_vec()); store.register_late_mod_pass(|_| Box::new(QueryStability)); - store.register_lints(&ExistingDocKeyword::get_lints()); + store.register_lints(&ExistingDocKeyword::lint_vec()); store.register_late_mod_pass(|_| Box::new(ExistingDocKeyword)); - store.register_lints(&TyTyKind::get_lints()); + store.register_lints(&TyTyKind::lint_vec()); store.register_late_mod_pass(|_| Box::new(TyTyKind)); - store.register_lints(&TypeIr::get_lints()); + store.register_lints(&TypeIr::lint_vec()); store.register_late_mod_pass(|_| Box::new(TypeIr)); - store.register_lints(&Diagnostics::get_lints()); + store.register_lints(&Diagnostics::lint_vec()); store.register_late_mod_pass(|_| Box::new(Diagnostics)); - store.register_lints(&BadOptAccess::get_lints()); + store.register_lints(&BadOptAccess::lint_vec()); store.register_late_mod_pass(|_| Box::new(BadOptAccess)); - store.register_lints(&PassByValue::get_lints()); + store.register_lints(&PassByValue::lint_vec()); store.register_late_mod_pass(|_| Box::new(PassByValue)); - store.register_lints(&SpanUseEqCtxt::get_lints()); + store.register_lints(&SpanUseEqCtxt::lint_vec()); store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt)); // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 16cfae17d40..000f4b697bd 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1137,16 +1137,19 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> { pub name: Symbol, } -// methods.rs +// dangling.rs #[derive(LintDiagnostic)] -#[diag(lint_cstring_ptr)] +#[diag(lint_dangling_pointers_from_temporaries)] #[note] #[help] -pub(crate) struct CStringPtr { - #[label(lint_as_ptr_label)] - pub as_ptr: Span, - #[label(lint_unwrap_label)] - pub unwrap: Span, +// FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts +pub(crate) struct DanglingPointersFromTemporaries<'tcx> { + pub callee: Symbol, + pub ty: Ty<'tcx>, + #[label(lint_label_ptr)] + pub ptr_span: Span, + #[label(lint_label_temporary)] + pub temporary_span: Span, } // multiple_supertrait_upcastable.rs diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs deleted file mode 100644 index df22bf0972d..00000000000 --- a/compiler/rustc_lint/src/methods.rs +++ /dev/null @@ -1,69 +0,0 @@ -use rustc_hir::{Expr, ExprKind}; -use rustc_middle::ty; -use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::Span; -use rustc_span::symbol::sym; - -use crate::lints::CStringPtr; -use crate::{LateContext, LateLintPass, LintContext}; - -declare_lint! { - /// The `temporary_cstring_as_ptr` lint detects getting the inner pointer of - /// a temporary `CString`. - /// - /// ### Example - /// - /// ```rust - /// # #![allow(unused)] - /// # use std::ffi::CString; - /// let c_str = CString::new("foo").unwrap().as_ptr(); - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// The inner pointer of a `CString` lives only as long as the `CString` it - /// points to. Getting the inner pointer of a *temporary* `CString` allows the `CString` - /// to be dropped at the end of the statement, as it is not being referenced as far as the - /// typesystem is concerned. This means outside of the statement the pointer will point to - /// freed memory, which causes undefined behavior if the pointer is later dereferenced. - pub TEMPORARY_CSTRING_AS_PTR, - Warn, - "detects getting the inner pointer of a temporary `CString`" -} - -declare_lint_pass!(TemporaryCStringAsPtr => [TEMPORARY_CSTRING_AS_PTR]); - -impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::MethodCall(as_ptr_path, as_ptr_receiver, ..) = expr.kind - && as_ptr_path.ident.name == sym::as_ptr - && let ExprKind::MethodCall(unwrap_path, unwrap_receiver, ..) = as_ptr_receiver.kind - && (unwrap_path.ident.name == sym::unwrap || unwrap_path.ident.name == sym::expect) - { - lint_cstring_as_ptr(cx, as_ptr_path.ident.span, unwrap_receiver, as_ptr_receiver); - } - } -} - -fn lint_cstring_as_ptr( - cx: &LateContext<'_>, - as_ptr_span: Span, - source: &rustc_hir::Expr<'_>, - unwrap: &rustc_hir::Expr<'_>, -) { - let source_type = cx.typeck_results().expr_ty(source); - if let ty::Adt(def, args) = source_type.kind() { - if cx.tcx.is_diagnostic_item(sym::Result, def.did()) { - if let ty::Adt(adt, _) = args.type_at(0).kind() { - if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) { - cx.emit_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, CStringPtr { - as_ptr: as_ptr_span, - unwrap: unwrap.span, - }); - } - } - } - } -} diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 83a8ca4307e..1c27e1daa90 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -542,11 +542,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { } fn check_generic_param(&mut self, cx: &LateContext<'_>, param: &hir::GenericParam<'_>) { - if let GenericParamKind::Const { is_host_effect, .. } = param.kind { - // `host` params are explicitly allowed to be lowercase. - if is_host_effect { - return; - } + if let GenericParamKind::Const { .. } = param.kind { NonUpperCaseGlobals::check_upper_case(cx, "const parameter", ¶m.name.ident()); } } diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index a1d436e0d3d..9d84d36e779 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -110,7 +110,7 @@ macro_rules! declare_combined_late_lint_pass { $v fn get_lints() -> $crate::LintVec { let mut lints = Vec::new(); - $(lints.extend_from_slice(&$pass::get_lints());)* + $(lints.extend_from_slice(&$pass::lint_vec());)* lints } } @@ -124,6 +124,9 @@ macro_rules! declare_combined_late_lint_pass { fn name(&self) -> &'static str { panic!() } + fn get_lints(&self) -> LintVec { + panic!() + } } ) } @@ -133,7 +136,7 @@ macro_rules! early_lint_methods { ($macro:path, $args:tt) => ( $macro!($args, [ fn check_param(a: &rustc_ast::Param); - fn check_ident(a: rustc_span::symbol::Ident); + fn check_ident(a: &rustc_span::symbol::Ident); fn check_crate(a: &rustc_ast::Crate); fn check_crate_post(a: &rustc_ast::Crate); fn check_item(a: &rustc_ast::Item); @@ -222,7 +225,7 @@ macro_rules! declare_combined_early_lint_pass { $v fn get_lints() -> $crate::LintVec { let mut lints = Vec::new(); - $(lints.extend_from_slice(&$pass::get_lints());)* + $(lints.extend_from_slice(&$pass::lint_vec());)* lints } } @@ -236,6 +239,9 @@ macro_rules! declare_combined_early_lint_pass { fn name(&self) -> &'static str { panic!() } + fn get_lints(&self) -> LintVec { + panic!() + } } ) } diff --git a/compiler/rustc_lint/src/tail_expr_drop_order.rs b/compiler/rustc_lint/src/tail_expr_drop_order.rs index 44a36142ed4..89763059877 100644 --- a/compiler/rustc_lint/src/tail_expr_drop_order.rs +++ b/compiler/rustc_lint/src/tail_expr_drop_order.rs @@ -14,15 +14,14 @@ 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 of type - /// with a significant `Drop` implementation, such as locks. - /// In case there are also local variables of type with significant `Drop` implementation as well, - /// this lint warns you of a potential transposition in the drop order. - /// Your discretion on the new drop order introduced by Edition 2024 is required. + /// 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,edition2024 - /// #![feature(shorter_tail_lifetimes)] + /// ```rust,edition2021 /// #![warn(tail_expr_drop_order)] /// struct Droppy(i32); /// impl Droppy { @@ -37,12 +36,12 @@ declare_lint! { /// println!("loud drop {}", self.0); /// } /// } - /// fn edition_2024() -> i32 { + /// fn edition_2021() -> i32 { /// let another_droppy = Droppy(0); /// Droppy(1).get() /// } /// fn main() { - /// edition_2024(); + /// edition_2021(); /// } /// ``` /// @@ -137,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder { _: Span, def_id: rustc_span::def_id::LocalDefId, ) { - if cx.tcx.sess.at_least_rust_2024() && cx.tcx.features().shorter_tail_lifetimes { + if !body.value.span.edition().at_least_rust_2024() { Self::check_fn_or_closure(cx, fn_kind, body, def_id); } } @@ -185,8 +184,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LintVisitor<'a, 'tcx> { 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 for Edition 2024 onwards + if block.span.at_least_rust_2024() { + // We only lint up to Edition 2021 return; } let Some(tail_expr) = block.expr else { return }; diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 5a3666dcbd4..b793ec6a493 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -114,10 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return }; for bound in &bounds[..] { let def_id = bound.trait_ref.trait_def_id(); - if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) - // FIXME: ?Drop is not a thing. - && bound.modifiers != hir::TraitBoundModifier::Maybe - { + if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) { let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; cx.emit_span_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id }); } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 60ff925b40e..0751d35cb9c 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -167,7 +167,7 @@ declare_lint! { "detects ambiguous wide pointer comparisons" } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Default)] pub(crate) struct TypeLimits { /// Id of the last visited negated expression negated_expr_id: Option, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index ddc18c755a8..bbb290c9459 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1025,8 +1025,8 @@ pub(crate) struct UnusedParens { parens_in_cast_in_lt: Vec, } -impl UnusedParens { - pub(crate) fn new() -> Self { +impl Default for UnusedParens { + fn default() -> Self { Self { with_self_ty_parens: false, parens_in_cast_in_lt: Vec::new() } } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a4c49a15905..06a3e4a6743 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -377,7 +377,8 @@ declare_lint! { /// will not overflow. pub ARITHMETIC_OVERFLOW, Deny, - "arithmetic operation overflows" + "arithmetic operation overflows", + @eval_always = true } declare_lint! { @@ -401,7 +402,8 @@ declare_lint! { /// `panic!` or `unreachable!` macro instead in case the panic is intended. pub UNCONDITIONAL_PANIC, Deny, - "operation will cause a panic at runtime" + "operation will cause a panic at runtime", + @eval_always = true } declare_lint! { @@ -632,7 +634,8 @@ declare_lint! { /// is only available in a newer version. pub UNKNOWN_LINTS, Warn, - "unrecognized lint attribute" + "unrecognized lint attribute", + @eval_always = true } declare_lint! { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index c01fa5c54d6..601784f9732 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -312,6 +312,10 @@ pub struct Lint { pub feature_gate: Option, pub crate_level_only: bool, + + /// `true` if this lint should not be filtered out under any circustamces + /// (e.g. the unknown_attributes lint) + pub eval_always: bool, } /// Extra information for a future incompatibility lint. @@ -456,6 +460,7 @@ impl Lint { future_incompatible: None, feature_gate: None, crate_level_only: false, + eval_always: false, } } @@ -864,6 +869,7 @@ macro_rules! declare_lint { ); ); ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, + $(@eval_always = $eval_always:literal)? $(@feature_gate = $gate:ident;)? $(@future_incompatible = FutureIncompatibleInfo { reason: $reason:expr, @@ -885,6 +891,7 @@ macro_rules! declare_lint { ..$crate::FutureIncompatibleInfo::default_fields_for_macro() }),)? $(edition_lint_opts: Some(($crate::Edition::$lint_edition, $crate::$edition_level)),)? + $(eval_always: $eval_always,)? ..$crate::Lint::default_fields_for_macro() }; ); @@ -894,20 +901,23 @@ macro_rules! declare_lint { macro_rules! declare_tool_lint { ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr + $(, @eval_always = $eval_always:literal)? $(, @feature_gate = $gate:ident;)? ) => ( - $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @feature_gate = $gate;)?} + $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @eval_always = $eval_always)? $(, @feature_gate = $gate;)?} ); ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr, report_in_external_macro: $rep:expr + $(, @eval_always = $eval_always: literal)? $(, @feature_gate = $gate:ident;)? ) => ( - $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @feature_gate = $gate;)?} + $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @eval_always = $eval_always)? $(, @feature_gate = $gate;)?} ); ( $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr, $external:expr + $(, @eval_always = $eval_always: literal)? $(, @feature_gate = $gate:ident;)? ) => ( $(#[$attr])* @@ -921,6 +931,7 @@ macro_rules! declare_tool_lint { is_externally_loaded: true, $(feature_gate: Some(rustc_span::symbol::sym::$gate),)? crate_level_only: false, + $(eval_always: $eval_always,)? ..$crate::Lint::default_fields_for_macro() }; ); @@ -930,6 +941,7 @@ pub type LintVec = Vec<&'static Lint>; pub trait LintPass { fn name(&self) -> &'static str; + fn get_lints(&self) -> LintVec; } /// Implements `LintPass for $ty` with the given list of `Lint` statics. @@ -938,9 +950,11 @@ macro_rules! impl_lint_pass { ($ty:ty => [$($lint:expr),* $(,)?]) => { impl $crate::LintPass for $ty { fn name(&self) -> &'static str { stringify!($ty) } + fn get_lints(&self) -> $crate::LintVec { vec![$($lint),*] } } impl $ty { - pub fn get_lints() -> $crate::LintVec { vec![$($lint),*] } + #[allow(unused)] + pub fn lint_vec() -> $crate::LintVec { vec![$($lint),*] } } }; } diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index cda81d4a9b5..b32af5e5e75 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -33,45 +33,6 @@ static coverage::Counter fromRust(LLVMRustCounter Counter) { report_fatal_error("Bad LLVMRustCounterKind!"); } -// FFI equivalent of enum `llvm::coverage::CounterMappingRegion::RegionKind` -// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L213-L234 -enum class LLVMRustCounterMappingRegionKind { - CodeRegion = 0, - ExpansionRegion = 1, - SkippedRegion = 2, - GapRegion = 3, - BranchRegion = 4, - MCDCDecisionRegion = 5, - MCDCBranchRegion = 6 -}; - -static coverage::CounterMappingRegion::RegionKind -fromRust(LLVMRustCounterMappingRegionKind Kind) { - switch (Kind) { - case LLVMRustCounterMappingRegionKind::CodeRegion: - return coverage::CounterMappingRegion::CodeRegion; - case LLVMRustCounterMappingRegionKind::ExpansionRegion: - return coverage::CounterMappingRegion::ExpansionRegion; - case LLVMRustCounterMappingRegionKind::SkippedRegion: - return coverage::CounterMappingRegion::SkippedRegion; - case LLVMRustCounterMappingRegionKind::GapRegion: - return coverage::CounterMappingRegion::GapRegion; - case LLVMRustCounterMappingRegionKind::BranchRegion: - return coverage::CounterMappingRegion::BranchRegion; - case LLVMRustCounterMappingRegionKind::MCDCDecisionRegion: - return coverage::CounterMappingRegion::MCDCDecisionRegion; - case LLVMRustCounterMappingRegionKind::MCDCBranchRegion: - return coverage::CounterMappingRegion::MCDCBranchRegion; - } - report_fatal_error("Bad LLVMRustCounterMappingRegionKind!"); -} - -enum LLVMRustMCDCParametersTag { - None = 0, - Decision = 1, - Branch = 2, -}; - struct LLVMRustMCDCDecisionParameters { uint32_t BitmapIdx; uint16_t NumConditions; @@ -82,47 +43,58 @@ struct LLVMRustMCDCBranchParameters { int16_t ConditionIDs[2]; }; -struct LLVMRustMCDCParameters { - LLVMRustMCDCParametersTag Tag; - LLVMRustMCDCDecisionParameters DecisionParameters; - LLVMRustMCDCBranchParameters BranchParameters; -}; - #if LLVM_VERSION_GE(19, 0) -static coverage::mcdc::Parameters fromRust(LLVMRustMCDCParameters Params) { - switch (Params.Tag) { - case LLVMRustMCDCParametersTag::None: - return std::monostate(); - case LLVMRustMCDCParametersTag::Decision: - return coverage::mcdc::DecisionParameters( - Params.DecisionParameters.BitmapIdx, - Params.DecisionParameters.NumConditions); - case LLVMRustMCDCParametersTag::Branch: - return coverage::mcdc::BranchParameters( - static_cast( - Params.BranchParameters.ConditionID), - {static_cast( - Params.BranchParameters.ConditionIDs[0]), - static_cast( - Params.BranchParameters.ConditionIDs[1])}); - } - report_fatal_error("Bad LLVMRustMCDCParametersTag!"); +static coverage::mcdc::BranchParameters +fromRust(LLVMRustMCDCBranchParameters Params) { + return coverage::mcdc::BranchParameters( + Params.ConditionID, {Params.ConditionIDs[0], Params.ConditionIDs[1]}); +} + +static coverage::mcdc::DecisionParameters +fromRust(LLVMRustMCDCDecisionParameters Params) { + return coverage::mcdc::DecisionParameters(Params.BitmapIdx, + Params.NumConditions); } #endif -// FFI equivalent of struct `llvm::coverage::CounterMappingRegion` -// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L211-L304 -struct LLVMRustCounterMappingRegion { - LLVMRustCounter Count; - LLVMRustCounter FalseCount; - LLVMRustMCDCParameters MCDCParameters; +// Must match the layout of +// `rustc_codegen_llvm::coverageinfo::ffi::CoverageSpan`. +struct LLVMRustCoverageSpan { uint32_t FileID; - uint32_t ExpandedFileID; uint32_t LineStart; uint32_t ColumnStart; uint32_t LineEnd; uint32_t ColumnEnd; - LLVMRustCounterMappingRegionKind Kind; +}; + +// Must match the layout of `rustc_codegen_llvm::coverageinfo::ffi::CodeRegion`. +struct LLVMRustCoverageCodeRegion { + LLVMRustCoverageSpan Span; + LLVMRustCounter Count; +}; + +// Must match the layout of +// `rustc_codegen_llvm::coverageinfo::ffi::BranchRegion`. +struct LLVMRustCoverageBranchRegion { + LLVMRustCoverageSpan Span; + LLVMRustCounter TrueCount; + LLVMRustCounter FalseCount; +}; + +// Must match the layout of +// `rustc_codegen_llvm::coverageinfo::ffi::MCDCBranchRegion`. +struct LLVMRustCoverageMCDCBranchRegion { + LLVMRustCoverageSpan Span; + LLVMRustCounter TrueCount; + LLVMRustCounter FalseCount; + LLVMRustMCDCBranchParameters MCDCBranchParams; +}; + +// Must match the layout of +// `rustc_codegen_llvm::coverageinfo::ffi::MCDCDecisionRegion`. +struct LLVMRustCoverageMCDCDecisionRegion { + LLVMRustCoverageSpan Span; + LLVMRustMCDCDecisionParameters MCDCDecisionParams; }; // FFI equivalent of enum `llvm::coverage::CounterExpression::ExprKind` @@ -174,28 +146,16 @@ extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer( extern "C" void LLVMRustCoverageWriteMappingToBuffer( const unsigned *VirtualFileMappingIDs, unsigned NumVirtualFileMappingIDs, const LLVMRustCounterExpression *RustExpressions, unsigned NumExpressions, - const LLVMRustCounterMappingRegion *RustMappingRegions, - unsigned NumMappingRegions, RustStringRef BufferOut) { + const LLVMRustCoverageCodeRegion *CodeRegions, unsigned NumCodeRegions, + const LLVMRustCoverageBranchRegion *BranchRegions, + unsigned NumBranchRegions, + const LLVMRustCoverageMCDCBranchRegion *MCDCBranchRegions, + unsigned NumMCDCBranchRegions, + const LLVMRustCoverageMCDCDecisionRegion *MCDCDecisionRegions, + unsigned NumMCDCDecisionRegions, RustStringRef BufferOut) { // Convert from FFI representation to LLVM representation. - SmallVector MappingRegions; - MappingRegions.reserve(NumMappingRegions); - for (const auto &Region : ArrayRef( - RustMappingRegions, NumMappingRegions)) { - MappingRegions.emplace_back( - fromRust(Region.Count), fromRust(Region.FalseCount), -#if LLVM_VERSION_LT(19, 0) - coverage::CounterMappingRegion::MCDCParameters{}, -#endif - Region.FileID, Region.ExpandedFileID, // File IDs, then region info. - Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd, - fromRust(Region.Kind) -#if LLVM_VERSION_GE(19, 0) - , - fromRust(Region.MCDCParameters) -#endif - ); - } + // Expressions: std::vector Expressions; Expressions.reserve(NumExpressions); for (const auto &Expression : @@ -205,6 +165,46 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer( fromRust(Expression.RHS)); } + std::vector MappingRegions; + MappingRegions.reserve(NumCodeRegions + NumBranchRegions + + NumMCDCBranchRegions + NumMCDCDecisionRegions); + + // Code regions: + for (const auto &Region : ArrayRef(CodeRegions, NumCodeRegions)) { + MappingRegions.push_back(coverage::CounterMappingRegion::makeRegion( + fromRust(Region.Count), Region.Span.FileID, Region.Span.LineStart, + Region.Span.ColumnStart, Region.Span.LineEnd, Region.Span.ColumnEnd)); + } + + // Branch regions: + for (const auto &Region : ArrayRef(BranchRegions, NumBranchRegions)) { + MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion( + fromRust(Region.TrueCount), fromRust(Region.FalseCount), + Region.Span.FileID, Region.Span.LineStart, Region.Span.ColumnStart, + Region.Span.LineEnd, Region.Span.ColumnEnd)); + } + +#if LLVM_VERSION_GE(19, 0) + // MC/DC branch regions: + for (const auto &Region : ArrayRef(MCDCBranchRegions, NumMCDCBranchRegions)) { + MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion( + fromRust(Region.TrueCount), fromRust(Region.FalseCount), + Region.Span.FileID, Region.Span.LineStart, Region.Span.ColumnStart, + Region.Span.LineEnd, Region.Span.ColumnEnd, + fromRust(Region.MCDCBranchParams))); + } + + // MC/DC decision regions: + for (const auto &Region : + ArrayRef(MCDCDecisionRegions, NumMCDCDecisionRegions)) { + MappingRegions.push_back(coverage::CounterMappingRegion::makeDecisionRegion( + fromRust(Region.MCDCDecisionParams), Region.Span.FileID, + Region.Span.LineStart, Region.Span.ColumnStart, Region.Span.LineEnd, + Region.Span.ColumnEnd)); + } +#endif + + // Write the converted expressions and mappings to a byte buffer. auto CoverageMappingWriter = coverage::CoverageMappingWriter( ArrayRef(VirtualFileMappingIDs, NumVirtualFileMappingIDs), Expressions, MappingRegions); diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 910c27da954..9f941637d8c 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1531,45 +1531,6 @@ extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, ArrayRef(OpBundles))); } -extern "C" LLVMValueRef -LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) { -#if LLVM_VERSION_GE(20, 0) - return wrap(llvm::Intrinsic::getOrInsertDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_increment)); -#else - return wrap(llvm::Intrinsic::getDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_increment)); -#endif -} - -extern "C" LLVMValueRef -LLVMRustGetInstrProfMCDCParametersIntrinsic(LLVMModuleRef M) { -#if LLVM_VERSION_LT(19, 0) - report_fatal_error("LLVM 19.0 is required for mcdc intrinsic functions"); -#endif -#if LLVM_VERSION_GE(20, 0) - return wrap(llvm::Intrinsic::getOrInsertDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_mcdc_parameters)); -#else - return wrap(llvm::Intrinsic::getDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_mcdc_parameters)); -#endif -} - -extern "C" LLVMValueRef -LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(LLVMModuleRef M) { -#if LLVM_VERSION_LT(19, 0) - report_fatal_error("LLVM 19.0 is required for mcdc intrinsic functions"); -#endif -#if LLVM_VERSION_GE(20, 0) - return wrap(llvm::Intrinsic::getOrInsertDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_mcdc_tvbitmap_update)); -#else - return wrap(llvm::Intrinsic::getDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_mcdc_tvbitmap_update)); -#endif -} - extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, LLVMValueRef Src, unsigned SrcAlign, @@ -1658,86 +1619,6 @@ extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B, unwrap(B)->SetInsertPoint(unwrap(BB), Point); } -enum class LLVMRustLinkage { - ExternalLinkage = 0, - AvailableExternallyLinkage = 1, - LinkOnceAnyLinkage = 2, - LinkOnceODRLinkage = 3, - WeakAnyLinkage = 4, - WeakODRLinkage = 5, - AppendingLinkage = 6, - InternalLinkage = 7, - PrivateLinkage = 8, - ExternalWeakLinkage = 9, - CommonLinkage = 10, -}; - -static LLVMRustLinkage toRust(LLVMLinkage Linkage) { - switch (Linkage) { - case LLVMExternalLinkage: - return LLVMRustLinkage::ExternalLinkage; - case LLVMAvailableExternallyLinkage: - return LLVMRustLinkage::AvailableExternallyLinkage; - case LLVMLinkOnceAnyLinkage: - return LLVMRustLinkage::LinkOnceAnyLinkage; - case LLVMLinkOnceODRLinkage: - return LLVMRustLinkage::LinkOnceODRLinkage; - case LLVMWeakAnyLinkage: - return LLVMRustLinkage::WeakAnyLinkage; - case LLVMWeakODRLinkage: - return LLVMRustLinkage::WeakODRLinkage; - case LLVMAppendingLinkage: - return LLVMRustLinkage::AppendingLinkage; - case LLVMInternalLinkage: - return LLVMRustLinkage::InternalLinkage; - case LLVMPrivateLinkage: - return LLVMRustLinkage::PrivateLinkage; - case LLVMExternalWeakLinkage: - return LLVMRustLinkage::ExternalWeakLinkage; - case LLVMCommonLinkage: - return LLVMRustLinkage::CommonLinkage; - default: - report_fatal_error("Invalid LLVMRustLinkage value!"); - } -} - -static LLVMLinkage fromRust(LLVMRustLinkage Linkage) { - switch (Linkage) { - case LLVMRustLinkage::ExternalLinkage: - return LLVMExternalLinkage; - case LLVMRustLinkage::AvailableExternallyLinkage: - return LLVMAvailableExternallyLinkage; - case LLVMRustLinkage::LinkOnceAnyLinkage: - return LLVMLinkOnceAnyLinkage; - case LLVMRustLinkage::LinkOnceODRLinkage: - return LLVMLinkOnceODRLinkage; - case LLVMRustLinkage::WeakAnyLinkage: - return LLVMWeakAnyLinkage; - case LLVMRustLinkage::WeakODRLinkage: - return LLVMWeakODRLinkage; - case LLVMRustLinkage::AppendingLinkage: - return LLVMAppendingLinkage; - case LLVMRustLinkage::InternalLinkage: - return LLVMInternalLinkage; - case LLVMRustLinkage::PrivateLinkage: - return LLVMPrivateLinkage; - case LLVMRustLinkage::ExternalWeakLinkage: - return LLVMExternalWeakLinkage; - case LLVMRustLinkage::CommonLinkage: - return LLVMCommonLinkage; - } - report_fatal_error("Invalid LLVMRustLinkage value!"); -} - -extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) { - return toRust(LLVMGetLinkage(V)); -} - -extern "C" void LLVMRustSetLinkage(LLVMValueRef V, - LLVMRustLinkage RustLinkage) { - LLVMSetLinkage(V, fromRust(RustLinkage)); -} - extern "C" bool LLVMRustConstIntGetZExtValue(LLVMValueRef CV, uint64_t *value) { auto C = unwrap(CV); if (C->getBitWidth() > 64) @@ -1765,45 +1646,6 @@ extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, return true; } -enum class LLVMRustVisibility { - Default = 0, - Hidden = 1, - Protected = 2, -}; - -static LLVMRustVisibility toRust(LLVMVisibility Vis) { - switch (Vis) { - case LLVMDefaultVisibility: - return LLVMRustVisibility::Default; - case LLVMHiddenVisibility: - return LLVMRustVisibility::Hidden; - case LLVMProtectedVisibility: - return LLVMRustVisibility::Protected; - } - report_fatal_error("Invalid LLVMRustVisibility value!"); -} - -static LLVMVisibility fromRust(LLVMRustVisibility Vis) { - switch (Vis) { - case LLVMRustVisibility::Default: - return LLVMDefaultVisibility; - case LLVMRustVisibility::Hidden: - return LLVMHiddenVisibility; - case LLVMRustVisibility::Protected: - return LLVMProtectedVisibility; - } - report_fatal_error("Invalid LLVMRustVisibility value!"); -} - -extern "C" LLVMRustVisibility LLVMRustGetVisibility(LLVMValueRef V) { - return toRust(LLVMGetVisibility(V)); -} - -extern "C" void LLVMRustSetVisibility(LLVMValueRef V, - LLVMRustVisibility RustVisibility) { - LLVMSetVisibility(V, fromRust(RustVisibility)); -} - extern "C" void LLVMRustSetDSOLocal(LLVMValueRef Global, bool is_dso_local) { unwrap(Global)->setDSOLocal(is_dso_local); } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 72f1e599247..1055f27c1e4 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -253,7 +253,10 @@ impl DiagnosticDeriveVariantBuilder { let mut field_binding = binding_info.binding.clone(); field_binding.set_span(field.ty.span()); - let ident = field.ident.as_ref().unwrap(); + let Some(ident) = field.ident.as_ref() else { + span_err(field.span().unwrap(), "tuple structs are not supported").emit(); + return TokenStream::new(); + }; let ident = format_ident!("{}", ident); // strip `r#` prefix, if present quote! { diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs index 9cdb9fbab12..a78cf2b63d0 100644 --- a/compiler/rustc_macros/src/diagnostics/error.rs +++ b/compiler/rustc_macros/src/diagnostics/error.rs @@ -56,7 +56,7 @@ fn path_to_string(path: &syn::Path) -> String { /// Returns an error diagnostic on span `span` with msg `msg`. #[must_use] pub(crate) fn span_err>(span: impl MultiSpan, msg: T) -> Diagnostic { - Diagnostic::spanned(span, Level::Error, msg) + Diagnostic::spanned(span, Level::Error, format!("derive(Diagnostic): {}", msg.into())) } /// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 5946b11828e..612a36ba9aa 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -243,7 +243,7 @@ impl SetOnce for SpannedOption { *self = Some((value, span)); } Some((_, prev_span)) => { - span_err(span, "specified multiple times") + span_err(span, "attribute specified multiple times") .span_note(*prev_span, "previously specified here") .emit(); } diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index f46c795b956..0df674eb4c9 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -20,6 +20,7 @@ mod lift; mod query; mod serialize; mod symbols; +mod try_from; mod type_foldable; mod type_visitable; @@ -165,3 +166,12 @@ decl_derive!( suggestion_part, applicability)] => diagnostics::subdiagnostic_derive ); + +decl_derive! { + [TryFromU32] => + /// Derives `TryFrom` for the annotated `enum`, which must have no fields. + /// Each variant maps to the value it would produce under an `as u32` cast. + /// + /// The error type is `u32`. + try_from::try_from_u32 +} diff --git a/compiler/rustc_macros/src/try_from.rs b/compiler/rustc_macros/src/try_from.rs new file mode 100644 index 00000000000..9338c1c2b33 --- /dev/null +++ b/compiler/rustc_macros/src/try_from.rs @@ -0,0 +1,55 @@ +use proc_macro2::TokenStream; +use quote::{quote, quote_spanned}; +use syn::Data; +use syn::spanned::Spanned; +use synstructure::Structure; + +pub(crate) fn try_from_u32(s: Structure<'_>) -> TokenStream { + let span_error = |span, message: &str| { + quote_spanned! { span => const _: () = ::core::compile_error!(#message); } + }; + + // Must be applied to an enum type. + if let Some(span) = match &s.ast().data { + Data::Enum(_) => None, + Data::Struct(s) => Some(s.struct_token.span()), + Data::Union(u) => Some(u.union_token.span()), + } { + return span_error(span, "type is not an enum (TryFromU32)"); + } + + // The enum's variants must not have fields. + let variant_field_errors = s + .variants() + .iter() + .filter_map(|v| v.ast().fields.iter().map(|f| f.span()).next()) + .map(|span| span_error(span, "enum variant cannot have fields (TryFromU32)")) + .collect::(); + if !variant_field_errors.is_empty() { + return variant_field_errors; + } + + let ctor = s + .variants() + .iter() + .map(|v| v.construct(|_, _| -> TokenStream { unreachable!() })) + .collect::>(); + // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here? + #[allow(keyword_idents_2024)] + s.gen_impl(quote! { + // The surrounding code might have shadowed these identifiers. + use ::core::convert::TryFrom; + use ::core::primitive::u32; + use ::core::result::Result::{self, Ok, Err}; + + gen impl TryFrom for @Self { + type Error = u32; + + #[allow(deprecated)] // Don't warn about deprecated variants. + fn try_from(value: u32) -> Result { + #( if value == const { #ctor as u32 } { return Ok(#ctor) } )* + Err(value) + } + } + }) +} diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 8adec7554a8..16623915c40 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -28,7 +28,7 @@ use rustc_session::lint::{self, BuiltinLintDiag}; use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; use rustc_span::edition::Edition; -use rustc_span::symbol::{Symbol, sym}; +use rustc_span::symbol::{Ident, Symbol, sym}; use rustc_span::{DUMMY_SP, Span}; use rustc_target::spec::{PanicStrategy, Target, TargetTriple}; use tracing::{debug, info, trace}; @@ -97,7 +97,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } pub enum LoadedMacro { - MacroDef(ast::Item, Edition), + MacroDef { def: MacroDef, ident: Ident, attrs: AttrVec, span: Span, edition: Edition }, ProcMacro(SyntaxExtension), } diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 39fa23766b5..641d1d8e798 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -170,7 +170,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { let mut upstream_in_dylibs = FxHashSet::default(); - if tcx.features().rustc_private { + if tcx.features().rustc_private() { // We need this to prevent users of `rustc_driver` from linking dynamically to `std` // which does not work as `std` is also statically linked into `rustc_driver`. diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index c7953d50406..1e6bc413118 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -265,7 +265,7 @@ impl<'tcx> Collector<'tcx> { NativeLibKind::RawDylib } "link-arg" => { - if !features.link_arg_attribute { + if !features.link_arg_attribute() { feature_err( sess, sym::link_arg_attribute, @@ -314,7 +314,7 @@ impl<'tcx> Collector<'tcx> { .emit_err(errors::LinkCfgSinglePredicate { span: item.span() }); continue; }; - if !features.link_cfg { + if !features.link_cfg() { feature_err( sess, sym::link_cfg, @@ -384,7 +384,7 @@ impl<'tcx> Collector<'tcx> { }; macro report_unstable_modifier($feature: ident) { - if !features.$feature { + if !features.$feature() { // FIXME: make this translatable #[expect(rustc::untranslatable_diagnostic)] feature_err( diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 7bb40996d58..926eb4f6210 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -1,7 +1,6 @@ use std::any::Any; use std::mem; -use rustc_ast as ast; use rustc_attr::Deprecation; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -275,6 +274,8 @@ provide! { tcx, def_id, other, cdata, impl_parent => { table } defaultness => { table_direct } constness => { table_direct } + const_conditions => { table } + implied_const_bounds => { table_defaulted_array } coerce_unsized_info => { Ok(cdata .root @@ -330,7 +331,6 @@ provide! { tcx, def_id, other, cdata, .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys"))) } - associated_type_for_effects => { table } associated_types_for_impl_traits_in_associated_fn => { table_defaulted_array } visibility => { cdata.get_visibility(def_id.index) } @@ -591,27 +591,16 @@ impl CStore { let data = self.get_crate_data(id.krate); if data.root.is_proc_macro_crate() { - return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, tcx)); - } - - let span = data.get_span(id.index, sess); - - LoadedMacro::MacroDef( - ast::Item { + LoadedMacro::ProcMacro(data.load_proc_macro(id.index, tcx)) + } else { + LoadedMacro::MacroDef { + def: data.get_macro(id.index, sess), ident: data.item_ident(id.index, sess), - id: ast::DUMMY_NODE_ID, - span, attrs: data.get_item_attrs(id.index, sess).collect(), - kind: ast::ItemKind::MacroDef(data.get_macro(id.index, sess)), - vis: ast::Visibility { - span: span.shrink_to_lo(), - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - tokens: None, - }, - data.root.edition, - ) + span: data.get_span(id.index, sess), + edition: data.root.edition, + } + } } pub fn def_span_untracked(&self, def_id: DefId, sess: &Session) -> Span { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index afe03531861..47f7a8b7c20 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1081,7 +1081,7 @@ fn should_encode_mir( && (generics.requires_monomorphization(tcx) || tcx.cross_crate_inlinable(def_id))); // The function has a `const` modifier or is in a `#[const_trait]`. - let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id()) + let is_const_fn = tcx.is_const_fn(def_id.to_def_id()) || tcx.is_const_default_method(def_id.to_def_id()); (is_const_fn, opt) } @@ -1433,6 +1433,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } } + if tcx.is_conditionally_const(def_id) { + record!(self.tables.const_conditions[def_id] <- self.tcx.const_conditions(def_id)); + } if should_encode_type(tcx, local_id, def_kind) { record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); } @@ -1456,10 +1459,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tcx.explicit_super_predicates_of(def_id).skip_binder()); record_defaulted_array!(self.tables.explicit_implied_predicates_of[def_id] <- self.tcx.explicit_implied_predicates_of(def_id).skip_binder()); - let module_children = self.tcx.module_children_local(local_id); 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()); + } } if let DefKind::TraitAlias = def_kind { record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); @@ -1479,9 +1485,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { for &def_id in associated_item_def_ids { self.encode_info_for_assoc_item(def_id); } - if let Some(assoc_def_id) = self.tcx.associated_type_for_effects(def_id) { - record!(self.tables.associated_type_for_effects[def_id] <- assoc_def_id); - } } if let DefKind::Closure | DefKind::SyntheticCoroutineBody = def_kind && let Some(coroutine_kind) = self.tcx.coroutine_kind(def_id) @@ -1652,6 +1655,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let ty::AssocKind::Type = item.kind { 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()); + } } } AssocItemContainer::ImplContainer => { @@ -1765,7 +1772,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_stability(&mut self, def_id: DefId) { // The query lookup can take a measurable amount of time in crates with many items. Check if // the stability attributes are even enabled before using their queries. - if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { + if self.feat.staged_api() || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { if let Some(stab) = self.tcx.lookup_stability(def_id) { record!(self.tables.lookup_stability[def_id] <- stab) } @@ -1776,7 +1783,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_const_stability(&mut self, def_id: DefId) { // The query lookup can take a measurable amount of time in crates with many items. Check if // the stability attributes are even enabled before using their queries. - if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { + if self.feat.staged_api() || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { if let Some(stab) = self.tcx.lookup_const_stability(def_id) { record!(self.tables.lookup_const_stability[def_id] <- stab) } @@ -1787,7 +1794,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_default_body_stability(&mut self, def_id: DefId) { // The query lookup can take a measurable amount of time in crates with many items. Check if // the stability attributes are even enabled before using their queries. - if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { + if self.feat.staged_api() || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { if let Some(stab) = self.tcx.lookup_default_body_stability(def_id) { record!(self.tables.lookup_default_body_stability[def_id] <- stab) } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 79bd1c13b12..a00ca27aacc 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -392,9 +392,9 @@ define_tables! { inferred_outlives_of: Table, Span)>>, explicit_super_predicates_of: Table, Span)>>, explicit_implied_predicates_of: Table, Span)>>, + implied_const_bounds: Table, Span)>>, inherent_impls: Table>, associated_types_for_impl_traits_in_associated_fn: Table>, - associated_type_for_effects: Table>>, opt_rpitit_info: Table>>, is_effects_desugaring: Table, unused_generic_params: Table, @@ -436,6 +436,7 @@ define_tables! { thir_abstract_const: Table>>>, impl_parent: Table, constness: Table, + const_conditions: Table>>, defaultness: Table, // FIXME(eddyb) perhaps compute this on the fly if cheap enough? coerce_unsized_info: Table>, diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 8cb602d9ea8..485d1c14df3 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -27,6 +27,7 @@ rustc_graphviz = { path = "../rustc_graphviz" } rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_index = { path = "../rustc_index" } +rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_query_system = { path = "../rustc_query_system" } rustc_serialize = { path = "../rustc_serialize" } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 52fe9956b47..7e77923fcdf 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -8,7 +8,7 @@ macro_rules! arena_types { ($macro:path) => ( $macro!([ - [] layout: rustc_target::abi::LayoutS, + [] layout: rustc_abi::LayoutData, [] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>, // AdtDef are interned and compared by address [decode] adt_def: rustc_middle::ty::AdtDefData, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 8fd5ff1f369..926691013dd 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -329,7 +329,7 @@ impl<'hir> Map<'hir> { BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability), BodyOwnerKind::Fn if self.tcx.is_constructor(def_id) => return None, - BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.tcx.is_const_fn_raw(def_id) => { + BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.tcx.is_const_fn(def_id) => { ConstContext::ConstFn } BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id) => ConstContext::ConstFn, diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index cf692b145b8..7f9211043d6 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -172,70 +172,3 @@ impl<'tcx> UnifyValue for ConstVariableValue<'tcx> { } } } - -/// values for the effect inference variable -#[derive(Clone, Copy, Debug)] -pub enum EffectVarValue<'tcx> { - Unknown, - Known(ty::Const<'tcx>), -} - -impl<'tcx> EffectVarValue<'tcx> { - pub fn known(self) -> Option> { - match self { - EffectVarValue::Unknown => None, - EffectVarValue::Known(value) => Some(value), - } - } - - pub fn is_unknown(self) -> bool { - match self { - EffectVarValue::Unknown => true, - EffectVarValue::Known(_) => false, - } - } -} - -impl<'tcx> UnifyValue for EffectVarValue<'tcx> { - type Error = NoError; - - fn unify_values(value1: &Self, value2: &Self) -> Result { - match (*value1, *value2) { - (EffectVarValue::Unknown, EffectVarValue::Unknown) => Ok(EffectVarValue::Unknown), - (EffectVarValue::Unknown, EffectVarValue::Known(val)) - | (EffectVarValue::Known(val), EffectVarValue::Unknown) => { - Ok(EffectVarValue::Known(val)) - } - (EffectVarValue::Known(_), EffectVarValue::Known(_)) => { - bug!("equating known inference variables: {value1:?} {value2:?}") - } - } - } -} - -#[derive(PartialEq, Copy, Clone, Debug)] -pub struct EffectVidKey<'tcx> { - pub vid: ty::EffectVid, - pub phantom: PhantomData>, -} - -impl<'tcx> From for EffectVidKey<'tcx> { - fn from(vid: ty::EffectVid) -> Self { - EffectVidKey { vid, phantom: PhantomData } - } -} - -impl<'tcx> UnifyKey for EffectVidKey<'tcx> { - type Value = EffectVarValue<'tcx>; - #[inline] - fn index(&self) -> u32 { - self.vid.as_u32() - } - #[inline] - fn from_index(i: u32) -> Self { - EffectVidKey::from(ty::EffectVid::from_u32(i)) - } - fn tag() -> &'static str { - "EffectVidKey" - } -} diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index ee34ccd889f..c0688aff183 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -422,15 +422,15 @@ impl<'tcx> TyCtxt<'tcx> { debug!("stability: skipping span={:?} since it is internal", span); return EvalResult::Allow; } - if self.features().declared(feature) { + if self.features().enabled(feature) { return EvalResult::Allow; } // If this item was previously part of a now-stabilized feature which is still - // active (i.e. the user hasn't removed the attribute for the stabilized feature + // enabled (i.e. the user hasn't removed the attribute for the stabilized feature // yet) then allow use of this item. if let Some(implied_by) = implied_by - && self.features().declared(implied_by) + && self.features().enabled(implied_by) { return EvalResult::Allow; } @@ -509,7 +509,7 @@ impl<'tcx> TyCtxt<'tcx> { debug!("body stability: skipping span={:?} since it is internal", span); return EvalResult::Allow; } - if self.features().declared(feature) { + if self.features().enabled(feature) { return EvalResult::Allow; } diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs index a3fe8f9cffa..7bb41193d5c 100644 --- a/compiler/rustc_middle/src/mir/graphviz.rs +++ b/compiler/rustc_middle/src/mir/graphviz.rs @@ -17,7 +17,7 @@ where let mirs = def_ids .iter() .flat_map(|def_id| { - if tcx.is_const_fn_raw(*def_id) { + if tcx.is_const_fn(*def_id) { vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)] } else { vec![tcx.instance_mir(ty::InstanceKind::Item(*def_id))] diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 59bc55269a3..2ecf1d0bcf8 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -116,7 +116,7 @@ impl<'tcx> TyCtxt<'tcx> { // @lcnr believes that successfully evaluating even though there are // used generic parameters is a bug of evaluation, so checking for it // here does feel somewhat sensible. - if !self.features().generic_const_exprs && ct.args.has_non_region_param() { + if !self.features().generic_const_exprs() && ct.args.has_non_region_param() { let def_kind = self.def_kind(instance.def_id()); assert!( matches!( diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 56ca9167d4d..d8d99deeb2c 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -86,11 +86,9 @@ impl<'tcx> MonoItem<'tcx> { } } - pub fn is_generic_fn(&self, tcx: TyCtxt<'tcx>) -> bool { + pub fn is_generic_fn(&self) -> bool { match self { - MonoItem::Fn(instance) => { - instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some() - } + MonoItem::Fn(instance) => instance.args.non_erasable_generics().next().is_some(), MonoItem::Static(..) | MonoItem::GlobalAsm(..) => false, } } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 2a3a070a6e7..e690bf74b6b 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -277,9 +277,9 @@ pub fn create_dump_file<'tcx>( ) })?; } - Ok(fs::File::create_buffered(&file_path).map_err(|e| { + fs::File::create_buffered(&file_path).map_err(|e| { io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}")) - })?) + }) } /////////////////////////////////////////////////////////////////////////// @@ -317,7 +317,7 @@ pub fn write_mir_pretty<'tcx>( }; // For `const fn` we want to render both the optimized MIR and the MIR for ctfe. - if tcx.is_const_fn_raw(def_id) { + if tcx.is_const_fn(def_id) { render_body(w, tcx.optimized_mir(def_id))?; writeln!(w)?; writeln!(w, "// MIR FOR CTFE")?; diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 48bf4ffced0..5f8427bd707 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -370,6 +370,7 @@ tcx_lifetime! { rustc_middle::ty::FnSig, rustc_middle::ty::GenericArg, rustc_middle::ty::GenericPredicates, + rustc_middle::ty::ConstConditions, rustc_middle::ty::inhabitedness::InhabitedPredicate, rustc_middle::ty::Instance, rustc_middle::ty::InstanceKind, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f8ba606e087..d7a60a843b7 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -29,6 +29,7 @@ use rustc_hir::def_id::{ use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate}; use rustc_index::IndexVec; +use rustc_lint_defs::LintId; use rustc_macros::rustc_queries; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{QueryCache, QueryMode, QueryState, try_get_cached}; @@ -422,6 +423,11 @@ rustc_queries! { desc { "computing `#[expect]`ed lints in this crate" } } + query lints_that_dont_need_to_run(_: ()) -> &'tcx FxIndexSet { + arena_cache + desc { "Computing all lints that are explicitly enabled or with a default level greater than Allow" } + } + query expn_that_defined(key: DefId) -> rustc_span::ExpnId { desc { |tcx| "getting the expansion that defined `{}`", tcx.def_path_str(key) } separate_provide_extern @@ -683,6 +689,24 @@ rustc_queries! { } } + query const_conditions( + key: DefId + ) -> ty::ConstConditions<'tcx> { + desc { |tcx| "computing the conditions for `{}` to be considered const", + tcx.def_path_str(key) + } + separate_provide_extern + } + + query implied_const_bounds( + key: DefId + ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> { + desc { |tcx| "computing the implied `~const` bounds for `{}`", + tcx.def_path_str(key) + } + separate_provide_extern + } + /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. query type_param_predicates( @@ -723,12 +747,11 @@ rustc_queries! { desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) } } - /// Returns `true` if this is a const fn, use the `is_const_fn` to know whether your crate - /// actually sees it as const fn (e.g., the const-fn-ness might be unstable and you might - /// not have the feature gate active). + /// Returns `true` if this is a const fn / const impl. /// /// **Do not call this function manually.** It is only meant to cache the base data for the - /// `is_const_fn` function. Consider using `is_const_fn` or `is_const_fn_raw` instead. + /// higher-level functions. Consider using `is_const_fn` or `is_const_trait_impl` instead. + /// Also note that neither of them takes into account feature gates and stability. query constness(key: DefId) -> hir::Constness { desc { |tcx| "checking if item is const: `{}`", tcx.def_path_str(key) } separate_provide_extern @@ -854,12 +877,6 @@ rustc_queries! { separate_provide_extern } - query associated_type_for_effects(def_id: DefId) -> Option { - desc { |tcx| "creating associated items for effects in `{}`", tcx.def_path_str(def_id) } - cache_on_disk_if { def_id.is_local() } - separate_provide_extern - } - /// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding /// associated item. query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId { diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 8ee8b4c4823..40e5ec45959 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -92,16 +92,6 @@ impl<'tcx> ObligationCause<'tcx> { ObligationCause { span, body_id: CRATE_DEF_ID, code: Default::default() } } - pub fn span(&self) -> Span { - match *self.code() { - ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - arm_span, - .. - }) => arm_span, - _ => self.span, - } - } - #[inline] pub fn code(&self) -> &ObligationCauseCode<'tcx> { &self.code @@ -517,10 +507,17 @@ pub struct MatchExpressionArmCause<'tcx> { pub prior_arm_block_id: Option, pub prior_arm_ty: Ty<'tcx>, pub prior_arm_span: Span, + /// Span of the scrutinee of the match (the matched value). pub scrut_span: Span, + /// Source of the match, i.e. `match` or a desugaring. pub source: hir::MatchSource, + /// Span of the *whole* match expr. + pub expr_span: Span, + /// Spans of the previous arms except for those that diverge (i.e. evaluate to `!`). + /// + /// These are used for pointing out errors that may affect several arms. pub prior_non_diverging_arms: Vec, - // Is the expectation of this match expression an RPIT? + /// Is the expectation of this match expression an RPIT? pub tail_defines_return_position_impl_trait: Option, } diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index 26dcae001e0..515aabbe2fc 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -61,7 +61,7 @@ pub enum OverlapMode { impl OverlapMode { pub fn get(tcx: TyCtxt<'_>, trait_id: DefId) -> OverlapMode { - let with_negative_coherence = tcx.features().with_negative_coherence; + let with_negative_coherence = tcx.features().with_negative_coherence(); let strict_coherence = tcx.has_attr(trait_id, sym::rustc_strict_coherence); if with_negative_coherence { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 7e533bc4291..ef9dfdd2f96 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -386,6 +386,17 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [(ty::Claus } } +impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> + for [(ty::PolyTraitRef<'tcx>, Span)] +{ + 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>> RefDecodable<'tcx, D> for ty::List { diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index eb715be22b1..5ab85a69ce6 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -109,6 +109,7 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn new_unevaluated(tcx: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Const<'tcx> { + tcx.debug_assert_args_compatible(uv.def, uv.args); Const::new(tcx, ty::ConstKind::Unevaluated(uv)) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c2a55060490..5ae9c589ec4 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -12,7 +12,7 @@ use std::marker::PhantomData; use std::ops::{Bound, Deref}; use std::{fmt, iter, mem}; -use rustc_abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; +use rustc_abi::{FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx}; use rustc_ast::{self as ast, attr}; use rustc_data_structures::defer; use rustc_data_structures::fingerprint::Fingerprint; @@ -78,10 +78,10 @@ use crate::traits::solve::{ use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericArg, GenericArgs, - GenericArgsRef, GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, - ParamTy, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, - PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, - Visibility, + GenericArgsRef, GenericParamDefKind, HostPolarity, ImplPolarity, List, ListWithCachedTypeInfo, + ParamConst, ParamTy, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, + PredicateKind, PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, + TyKind, TyVid, Visibility, }; #[allow(rustc::usage_of_ty_tykind)] @@ -279,6 +279,26 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.debug_assert_args_compatible(def_id, args); } + /// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection` + /// are compatible with the `DefId`. Since we're missing a `Self` type, stick on + /// a dummy self type and forward to `debug_assert_args_compatible`. + fn debug_assert_existential_args_compatible( + self, + def_id: Self::DefId, + args: Self::GenericArgs, + ) { + // FIXME: We could perhaps add a `skip: usize` to `debug_assert_args_compatible` + // to avoid needing to reintern the set of args... + if cfg!(debug_assertions) { + self.debug_assert_args_compatible( + def_id, + self.mk_args_from_iter( + [self.types.trait_object_dummy_self.into()].into_iter().chain(args.iter()), + ), + ); + } + } + fn mk_type_list_from_iter(self, args: I) -> T::Output where I: Iterator, @@ -363,6 +383,28 @@ 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 { + self.is_conditionally_const(def_id) + } + + fn const_conditions( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl IntoIterator>>> { + ty::EarlyBinder::bind( + self.const_conditions(def_id).instantiate_identity(self).into_iter().map(|(c, _)| c), + ) + } + + fn implied_const_bounds( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl IntoIterator>>> { + ty::EarlyBinder::bind( + self.implied_const_bounds(def_id).iter_identity_copied().map(|(c, _)| c), + ) + } + fn has_target_features(self, def_id: DefId) -> bool { !self.codegen_fn_attrs(def_id).target_features.is_empty() } @@ -626,13 +668,6 @@ bidirectional_lang_item_map! { Destruct, DiscriminantKind, DynMetadata, - EffectsCompat, - EffectsIntersection, - EffectsIntersectionOutput, - EffectsMaybe, - EffectsNoRuntime, - EffectsRuntime, - EffectsTyCompat, Fn, FnMut, FnOnce, @@ -690,15 +725,15 @@ impl<'tcx> rustc_type_ir::inherent::Safety> for hir::Safety { impl<'tcx> rustc_type_ir::inherent::Features> for &'tcx rustc_feature::Features { fn generic_const_exprs(self) -> bool { - self.generic_const_exprs + self.generic_const_exprs() } fn coroutine_clone(self) -> bool { - self.coroutine_clone + self.coroutine_clone() } fn associated_const_equality(self) -> bool { - self.associated_const_equality + self.associated_const_equality() } } @@ -731,7 +766,7 @@ pub struct CtxtInterners<'tcx> { pat: InternedSet<'tcx, PatternKind<'tcx>>, const_allocation: InternedSet<'tcx, Allocation>, bound_variable_kinds: InternedSet<'tcx, List>, - layout: InternedSet<'tcx, LayoutS>, + layout: InternedSet<'tcx, LayoutData>, adt_def: InternedSet<'tcx, AdtDefData>, external_constraints: InternedSet<'tcx, ExternalConstraintsData>>, predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData>>, @@ -2176,7 +2211,7 @@ macro_rules! nop_slice_lift { nop_slice_lift! {ty::ValTree<'a> => ty::ValTree<'tcx>} TrivialLiftImpls! { - ImplPolarity, PredicatePolarity, Promoted + ImplPolarity, PredicatePolarity, Promoted, HostPolarity, } macro_rules! sty_debug_print { @@ -2434,7 +2469,7 @@ direct_interners! { region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>, pat: pub mk_pat(PatternKind<'tcx>): Pattern -> Pattern<'tcx>, const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, - layout: pub mk_layout(LayoutS): Layout -> Layout<'tcx>, + layout: pub mk_layout(LayoutData): Layout -> Layout<'tcx>, adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>, external_constraints: pub mk_external_constraints(ExternalConstraintsData>): ExternalConstraints -> ExternalConstraints<'tcx>, @@ -3085,38 +3120,24 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Whether the `def_id` counts as const fn in the current crate, considering all active - /// feature gates - pub fn is_const_fn(self, def_id: DefId) -> bool { - if self.is_const_fn_raw(def_id) { - match self.lookup_const_stability(def_id) { - Some(stability) if stability.is_const_unstable() => { - // has a `rustc_const_unstable` attribute, check whether the user enabled the - // corresponding feature gate. - self.features().declared(stability.feature) - } - // functions without const stability are either stable user written - // const fn or the user is using feature gates and we thus don't - // care what they do - _ => true, + /// Whether `def_id` is a stable const fn (i.e., doesn't need any feature gates to be called). + /// + /// When this is `false`, the function may still be callable as a `const fn` due to features + /// being enabled! + pub fn is_stable_const_fn(self, def_id: DefId) -> bool { + self.is_const_fn(def_id) + && match self.lookup_const_stability(def_id) { + None => true, // a fn in a non-staged_api crate + Some(stability) if stability.is_const_stable() => true, + _ => false, } - } else { - false - } } + // FIXME(effects): Please remove this. It's a footgun. /// Whether the trait impl is marked const. This does not consider stability or feature gates. - pub fn is_const_trait_impl_raw(self, def_id: DefId) -> bool { - let Some(local_def_id) = def_id.as_local() else { return false }; - let node = self.hir_node_by_def_id(local_def_id); - - matches!( - node, - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), - .. - }) if matches!(constness, hir::Constness::Const) - ) + pub fn is_const_trait_impl(self, def_id: DefId) -> bool { + self.def_kind(def_id) == DefKind::Impl { of_trait: true } + && self.constness(def_id) == hir::Constness::Const } pub fn intrinsic(self, def_id: impl IntoQueryParam + Copy) -> Option { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 4f408ee1574..84f52bfe48f 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -70,7 +70,7 @@ impl<'tcx> Ty<'tcx> { /// ADTs with no type arguments. pub fn is_simple_text(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { - Adt(def, args) => args.non_erasable_generics(tcx, def.did()).next().is_none(), + Adt(_, args) => args.non_erasable_generics().next().is_none(), Ref(_, ty, _) => ty.is_simple_text(tcx), _ => self.is_simple_ty(), } @@ -193,7 +193,7 @@ fn suggest_changing_unsized_bound( .enumerate() .filter(|(_, bound)| { if let hir::GenericBound::Trait(poly) = bound - && poly.modifiers == hir::TraitBoundModifier::Maybe + && let hir::BoundPolarity::Maybe(_) = poly.modifiers.polarity && poly.trait_ref.trait_def_id() == def_id { true @@ -592,9 +592,6 @@ impl<'tcx> TypeVisitor> for IsSuggestableVisitor<'tcx> { match c.kind() { ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {} - // effect variables are always suggestable, because they are not visible - ConstKind::Infer(InferConst::EffectVar(_)) => {} - ConstKind::Infer(..) | ConstKind::Bound(..) | ConstKind::Placeholder(..) diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index b02eff3bfd6..c49824bb418 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -35,9 +35,6 @@ impl<'tcx> TypeError<'tcx> { TypeError::CyclicTy(_) => "cyclic type of infinite size".into(), TypeError::CyclicConst(_) => "encountered a self-referencing constant".into(), TypeError::Mismatch => "types differ".into(), - TypeError::ConstnessMismatch(values) => { - format!("expected {} bound, found {} bound", values.expected, values.found).into() - } TypeError::PolarityMismatch(values) => { format!("expected {} polarity, found {} polarity", values.expected, values.found) .into() diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 92a975c028e..704a197aa49 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -265,6 +265,12 @@ impl FlagComputation { ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { self.add_args(trait_pred.trait_ref.args); } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate { + trait_ref, + host: _, + })) => { + self.add_args(trait_ref.args); + } ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( a, b, @@ -354,9 +360,7 @@ impl FlagComputation { self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); match infer { InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH), - InferConst::Var(_) | InferConst::EffectVar(_) => { - self.add_flags(TypeFlags::HAS_CT_INFER) - } + InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER), } } ty::ConstKind::Bound(debruijn, _) => { diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index daf1362e25c..737f1362b34 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -501,12 +501,8 @@ impl<'tcx> GenericArgs<'tcx> { #[inline] pub fn non_erasable_generics( &'tcx self, - tcx: TyCtxt<'tcx>, - def_id: DefId, ) -> impl DoubleEndedIterator> + 'tcx { - let generics = tcx.generics_of(def_id); - self.iter().enumerate().filter_map(|(i, k)| match k.unpack() { - _ if Some(i) == generics.host_effect_index => None, + self.iter().filter_map(|k| match k.unpack() { ty::GenericArgKind::Lifetime(_) => None, generic => Some(generic), }) diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 660686f4aa2..19779740227 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -14,7 +14,7 @@ use crate::ty::{EarlyBinder, GenericArgsRef}; pub enum GenericParamDefKind { Lifetime, Type { has_default: bool, synthetic: bool }, - Const { has_default: bool, is_host_effect: bool, synthetic: bool }, + Const { has_default: bool, synthetic: bool }, } impl GenericParamDefKind { @@ -81,10 +81,6 @@ impl GenericParamDef { } } - pub fn is_host_effect(&self) -> bool { - matches!(self.kind, GenericParamDefKind::Const { is_host_effect: true, .. }) - } - pub fn default_value<'tcx>( &self, tcx: TyCtxt<'tcx>, @@ -133,9 +129,6 @@ pub struct Generics { pub has_self: bool, pub has_late_bound_regions: Option, - - // The index of the host effect when instantiated. (i.e. might be index to parent args) - pub host_effect_index: Option, } impl<'tcx> rustc_type_ir::inherent::GenericsOf> for &'tcx Generics { @@ -216,12 +209,10 @@ impl<'tcx> Generics { pub fn own_requires_monomorphization(&self) -> bool { for param in &self.own_params { match param.kind { - GenericParamDefKind::Type { .. } - | GenericParamDefKind::Const { is_host_effect: false, .. } => { + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { return true; } - GenericParamDefKind::Lifetime - | GenericParamDefKind::Const { is_host_effect: true, .. } => {} + GenericParamDefKind::Lifetime => {} } } false @@ -300,8 +291,6 @@ impl<'tcx> Generics { own_params.start = 1; } - let verbose = tcx.sess.verbose_internals(); - // Filter the default arguments. // // This currently uses structural equality instead @@ -316,8 +305,6 @@ impl<'tcx> Generics { param.default_value(tcx).is_some_and(|default| { default.instantiate(tcx, args) == args[param.index as usize] }) - // filter out trailing effect params, if we're not in `-Zverbose-internals`. - || (!verbose && matches!(param.kind, GenericParamDefKind::Const { is_host_effect: true, .. })) }) .count(); @@ -373,7 +360,6 @@ impl<'tcx> Generics { pub struct GenericPredicates<'tcx> { pub parent: Option, pub predicates: &'tcx [(Clause<'tcx>, Span)], - pub effects_min_tys: &'tcx ty::List>, } impl<'tcx> GenericPredicates<'tcx> { @@ -395,7 +381,9 @@ impl<'tcx> GenericPredicates<'tcx> { EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args) } - pub fn instantiate_own_identity(self) -> impl Iterator, Span)> { + pub fn instantiate_own_identity( + self, + ) -> impl Iterator, Span)> + DoubleEndedIterator + ExactSizeIterator { EarlyBinder::bind(self.predicates).iter_identity_copied() } @@ -433,3 +421,73 @@ impl<'tcx> GenericPredicates<'tcx> { instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s)); } } + +/// `~const` bounds for a given item. This is represented using a struct much like +/// `GenericPredicates`, where you can either choose to only instantiate the "own" +/// bounds or all of the bounds including those from the parent. This distinction +/// is necessary for code like `compare_method_predicate_entailment`. +#[derive(Copy, Clone, Default, Debug, TyEncodable, TyDecodable, HashStable)] +pub struct ConstConditions<'tcx> { + pub parent: Option, + pub predicates: &'tcx [(ty::PolyTraitRef<'tcx>, Span)], +} + +impl<'tcx> ConstConditions<'tcx> { + pub fn instantiate( + self, + tcx: TyCtxt<'tcx>, + args: GenericArgsRef<'tcx>, + ) -> Vec<(ty::PolyTraitRef<'tcx>, Span)> { + let mut instantiated = vec![]; + self.instantiate_into(tcx, &mut instantiated, args); + instantiated + } + + pub fn instantiate_own( + self, + tcx: TyCtxt<'tcx>, + args: GenericArgsRef<'tcx>, + ) -> impl Iterator, Span)> + DoubleEndedIterator + ExactSizeIterator + { + EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args) + } + + pub fn instantiate_own_identity( + self, + ) -> impl Iterator, Span)> + DoubleEndedIterator + ExactSizeIterator + { + EarlyBinder::bind(self.predicates).iter_identity_copied() + } + + #[instrument(level = "debug", skip(self, tcx))] + fn instantiate_into( + self, + tcx: TyCtxt<'tcx>, + instantiated: &mut Vec<(ty::PolyTraitRef<'tcx>, Span)>, + args: GenericArgsRef<'tcx>, + ) { + if let Some(def_id) = self.parent { + tcx.const_conditions(def_id).instantiate_into(tcx, instantiated, args); + } + instantiated.extend( + self.predicates.iter().map(|&(p, s)| (EarlyBinder::bind(p).instantiate(tcx, args), s)), + ); + } + + pub fn instantiate_identity(self, tcx: TyCtxt<'tcx>) -> Vec<(ty::PolyTraitRef<'tcx>, Span)> { + let mut instantiated = vec![]; + self.instantiate_identity_into(tcx, &mut instantiated); + instantiated + } + + fn instantiate_identity_into( + self, + tcx: TyCtxt<'tcx>, + instantiated: &mut Vec<(ty::PolyTraitRef<'tcx>, Span)>, + ) { + if let Some(def_id) = self.parent { + tcx.const_conditions(def_id).instantiate_identity_into(tcx, instantiated); + } + instantiated.extend(self.predicates.iter().copied()); + } +} diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index b1c5ff50fdc..e237d382900 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -204,7 +204,7 @@ impl<'tcx> Instance<'tcx> { } // If this a non-generic instance, it cannot be a shared monomorphization. - self.args.non_erasable_generics(tcx, self.def_id()).next()?; + self.args.non_erasable_generics().next()?; // compiler_builtins cannot use upstream monomorphizations. if tcx.is_compiler_builtins(LOCAL_CRATE) { @@ -476,7 +476,6 @@ impl<'tcx> Instance<'tcx> { pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> { let args = GenericArgs::for_item(tcx, def_id, |param, _| match param.kind { ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), - ty::GenericParamDefKind::Const { is_host_effect: true, .. } => tcx.consts.true_.into(), ty::GenericParamDefKind::Type { .. } => { bug!("Instance::mono: {:?} has type parameters", def_id) } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 3670b6bbc77..990fc37a1f3 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -4,7 +4,7 @@ use std::{cmp, fmt}; use rustc_abi::Primitive::{self, Float, Int, Pointer}; use rustc_abi::{ - Abi, AddressSpace, Align, FieldsShape, HasDataLayout, Integer, LayoutCalculator, LayoutS, + Abi, AddressSpace, Align, FieldsShape, HasDataLayout, Integer, LayoutCalculator, LayoutData, PointeeInfo, PointerKind, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, Variants, }; use rustc_error_messages::DiagMessage; @@ -21,7 +21,9 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use rustc_target::abi::call::FnAbi; use rustc_target::abi::{FieldIdx, TyAbiInterface, VariantIdx, call}; use rustc_target::spec::abi::Abi as SpecAbi; -use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, PanicStrategy, Target, WasmCAbi}; +use rustc_target::spec::{ + HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, PanicStrategy, Target, WasmCAbi, X86Abi, +}; use tracing::debug; use {rustc_abi as abi, rustc_hir as hir}; @@ -396,7 +398,7 @@ impl<'tcx> SizeSkeleton<'tcx> { ), } } - ty::Array(inner, len) if tcx.features().transmute_generic_consts => { + ty::Array(inner, len) if tcx.features().transmute_generic_consts() => { let len_eval = len.try_to_target_usize(tcx); if len_eval == Some(0) { return Ok(SizeSkeleton::Known(Size::from_bytes(0), None)); @@ -544,6 +546,12 @@ impl<'tcx> HasWasmCAbiOpt for TyCtxt<'tcx> { } } +impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> { + fn x86_abi_opt(&self) -> X86Abi { + X86Abi { regparm: self.sess.opts.unstable_opts.regparm } + } +} + impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> { #[inline] fn tcx(&self) -> TyCtxt<'tcx> { @@ -595,6 +603,12 @@ impl<'tcx> HasWasmCAbiOpt for LayoutCx<'tcx> { } } +impl<'tcx> HasX86AbiOpt for LayoutCx<'tcx> { + fn x86_abi_opt(&self) -> X86Abi { + self.calc.cx.x86_abi_opt() + } +} + impl<'tcx> HasTyCtxt<'tcx> for LayoutCx<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.calc.cx @@ -737,7 +751,7 @@ where ty::Adt(def, _) => def.variant(variant_index).fields.len(), _ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty), }; - tcx.mk_layout(LayoutS { + tcx.mk_layout(LayoutData { variants: Variants::Single { index: variant_index }, fields: match NonZero::new(fields) { Some(fields) => FieldsShape::Union(fields), @@ -774,7 +788,7 @@ where let tcx = cx.tcx(); let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> { TyAndLayout { - layout: tcx.mk_layout(LayoutS::scalar(cx, tag)), + layout: tcx.mk_layout(LayoutData::scalar(cx, tag)), ty: tag.primitive().to_ty(tcx), } }; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ed24fcc7eb8..b92fc864b49 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -84,12 +84,13 @@ pub use self::parameterized::ParameterizedOverTcx; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate, - ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, NormalizesTo, - OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection, - PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate, - PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, - PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, - TraitPredicate, TraitRef, TypeOutlivesPredicate, + ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, + HostEffectPredicate, NormalizesTo, OutlivesPredicate, PolyCoercePredicate, + PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef, + PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate, + PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate, + RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, TraitPredicate, TraitRef, + TypeOutlivesPredicate, }; pub use self::region::BoundRegionKind::*; pub use self::region::{ @@ -1994,14 +1995,82 @@ impl<'tcx> TyCtxt<'tcx> { (ident, scope) } + /// Checks whether this is a `const fn`. Returns `false` for non-functions. + /// + /// Even if this returns `true`, constness may still be unstable! #[inline] - pub fn is_const_fn_raw(self, def_id: DefId) -> bool { + pub fn is_const_fn(self, def_id: DefId) -> bool { matches!( self.def_kind(def_id), - DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::Closure + DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Closure ) && self.constness(def_id) == hir::Constness::Const } + /// Whether this item is conditionally constant for the purposes of the + /// effects implementation. + /// + /// This roughly corresponds to all const functions and other callable + /// items, along with const impls and traits, and associated types within + /// those impls and traits. + pub fn is_conditionally_const(self, def_id: impl Into) -> bool { + let def_id: DefId = def_id.into(); + match self.def_kind(def_id) { + DefKind::Impl { of_trait: true } => { + self.constness(def_id) == hir::Constness::Const + && self.is_const_trait( + self.trait_id_of_impl(def_id) + .expect("expected trait for trait implementation"), + ) + } + DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => { + self.constness(def_id) == hir::Constness::Const + } + DefKind::Trait => self.is_const_trait(def_id), + DefKind::AssocTy | DefKind::AssocFn => { + let parent_def_id = self.parent(def_id); + match self.def_kind(parent_def_id) { + DefKind::Impl { of_trait: false } => { + self.constness(def_id) == hir::Constness::Const + } + DefKind::Impl { of_trait: true } | DefKind::Trait => { + self.is_conditionally_const(parent_def_id) + } + _ => bug!("unexpected parent item of associated item: {parent_def_id:?}"), + } + } + DefKind::Closure | DefKind::OpaqueTy => { + // Closures and RPITs will eventually have const conditions + // for `~const` bounds. + false + } + DefKind::Ctor(_, CtorKind::Const) + | DefKind::Impl { of_trait: false } + | DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::TyParam + | DefKind::Const + | DefKind::ConstParam + | DefKind::Static { .. } + | DefKind::AssocConst + | DefKind::Macro(_) + | DefKind::ExternCrate + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::Field + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::SyntheticCoroutineBody => false, + } + } + #[inline] pub fn is_const_trait(self, def_id: DefId) -> bool { self.trait_def(def_id).constness == hir::Constness::Const diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 7e1255f606c..43bdce5b576 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -132,6 +132,7 @@ parameterized_over_tcx! { ty::Ty, ty::FnSig, ty::GenericPredicates, + ty::ConstConditions, ty::TraitRef, ty::Const, ty::Predicate, diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index d20cb368278..3ecaa3e22d3 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -19,6 +19,7 @@ pub type ExistentialPredicate<'tcx> = ir::ExistentialPredicate>; pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef>; pub type ExistentialProjection<'tcx> = ir::ExistentialProjection>; pub type TraitPredicate<'tcx> = ir::TraitPredicate>; +pub type HostEffectPredicate<'tcx> = ir::HostEffectPredicate>; pub type ClauseKind<'tcx> = ir::ClauseKind>; pub type PredicateKind<'tcx> = ir::PredicateKind>; pub type NormalizesTo<'tcx> = ir::NormalizesTo>; @@ -143,6 +144,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::AliasRelate(..) | PredicateKind::NormalizesTo(..) => false, PredicateKind::Clause(ClauseKind::Trait(_)) + | PredicateKind::Clause(ClauseKind::HostEffect(..)) | PredicateKind::Clause(ClauseKind::RegionOutlives(_)) | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) | PredicateKind::Clause(ClauseKind::Projection(_)) @@ -644,6 +646,7 @@ impl<'tcx> Predicate<'tcx> { match predicate.skip_binder() { PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)), PredicateKind::Clause(ClauseKind::Projection(..)) + | PredicateKind::Clause(ClauseKind::HostEffect(..)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) | PredicateKind::NormalizesTo(..) | PredicateKind::AliasRelate(..) @@ -664,6 +667,7 @@ impl<'tcx> Predicate<'tcx> { match predicate.skip_binder() { PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)), PredicateKind::Clause(ClauseKind::Trait(..)) + | PredicateKind::Clause(ClauseKind::HostEffect(..)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) | PredicateKind::NormalizesTo(..) | PredicateKind::AliasRelate(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index b5495fa282b..0248aad53e2 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1208,7 +1208,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } } - if self.tcx().features().return_type_notation + if self.tcx().features().return_type_notation() && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) = self.tcx().opt_rpitit_info(def_id) && let ty::Alias(_, alias_ty) = @@ -3075,6 +3075,15 @@ define_print! { p!(print(self.trait_ref.print_trait_sugared())) } + ty::HostEffectPredicate<'tcx> { + let constness = match self.host { + ty::HostPolarity::Const => { "const" } + ty::HostPolarity::Maybe => { "~const" } + }; + p!(print(self.trait_ref.self_ty()), ": {constness} "); + p!(print(self.trait_ref.print_trait_sugared())) + } + ty::TypeAndMut<'tcx> { p!(write("{}", self.mutbl.prefix_str()), print(self.ty)) } @@ -3087,6 +3096,7 @@ define_print! { ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)), ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)), ty::ClauseKind::Projection(predicate) => p!(print(predicate)), + ty::ClauseKind::HostEffect(predicate) => p!(print(predicate)), ty::ClauseKind::ConstArgHasType(ct, ty) => { p!("the constant `", print(ct), "` has type `", print(ty), "`") }, diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 4c7bcb1bf2e..504a3c8a6d8 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -1,7 +1,5 @@ use std::iter; -use rustc_hir as hir; -use rustc_target::spec::abi; pub use rustc_type_ir::relate::*; use crate::ty::error::{ExpectedFound, TypeError}; @@ -121,26 +119,6 @@ impl<'tcx> Relate> for &'tcx ty::List Relate> for hir::Safety { - fn relate>>( - _relation: &mut R, - a: hir::Safety, - b: hir::Safety, - ) -> RelateResult<'tcx, hir::Safety> { - if a != b { Err(TypeError::SafetyMismatch(ExpectedFound::new(true, a, b))) } else { Ok(a) } - } -} - -impl<'tcx> Relate> for abi::Abi { - fn relate>>( - _relation: &mut R, - a: abi::Abi, - b: abi::Abi, - ) -> RelateResult<'tcx, abi::Abi> { - if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(ExpectedFound::new(true, a, b))) } - } -} - impl<'tcx> Relate> for ty::GenericArgsRef<'tcx> { fn relate>>( relation: &mut R, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index cd9ff9b60d8..4872d8c89eb 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -264,8 +264,6 @@ TrivialTypeTraversalImpls! { // interners). TrivialTypeTraversalAndLiftImpls! { ::rustc_hir::def_id::DefId, - ::rustc_hir::Safety, - ::rustc_target::spec::abi::Abi, crate::ty::ClosureKind, crate::ty::ParamConst, crate::ty::ParamTy, @@ -276,6 +274,11 @@ TrivialTypeTraversalAndLiftImpls! { rustc_target::abi::Size, } +TrivialLiftImpls! { + ::rustc_hir::Safety, + ::rustc_target::spec::abi::Abi, +} + /////////////////////////////////////////////////////////////////////////// // Lift implementations diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 74de378c4d7..d8362ccc0a9 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -750,7 +750,7 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn new_diverging_default(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - if tcx.features().never_type_fallback { tcx.types.never } else { tcx.types.unit } + if tcx.features().never_type_fallback() { tcx.types.never } else { tcx.types.unit } } // lang and diagnostic tys diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 9a3049f3be6..7fd7e463acf 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -17,10 +17,10 @@ use rustc_span::sym; use rustc_target::abi::{Float, Integer, IntegerType, Size}; use rustc_target::spec::abi::Abi; use smallvec::{SmallVec, smallvec}; -use tracing::{debug, instrument, trace}; +use tracing::{debug, instrument}; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::query::{IntoQueryParam, Providers}; +use crate::query::Providers; use crate::ty::layout::{FloatExt, IntegerExt}; use crate::ty::{ self, Asyncness, FallibleTypeFolder, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeFoldable, @@ -865,48 +865,6 @@ impl<'tcx> TyCtxt<'tcx> { || self.extern_crate(key).is_some_and(|e| e.is_direct()) } - /// Whether the item has a host effect param. This is different from `TyCtxt::is_const`, - /// because the item must also be "maybe const", and the crate where the item is - /// defined must also have the effects feature enabled. - pub fn has_host_param(self, def_id: impl IntoQueryParam) -> bool { - self.generics_of(def_id).host_effect_index.is_some() - } - - pub fn expected_host_effect_param_for_body(self, def_id: impl Into) -> ty::Const<'tcx> { - let def_id = def_id.into(); - // FIXME(effects): This is suspicious and should probably not be done, - // especially now that we enforce host effects and then properly handle - // effect vars during fallback. - let mut host_always_on = - !self.features().effects || self.sess.opts.unstable_opts.unleash_the_miri_inside_of_you; - - // Compute the constness required by the context. - let const_context = self.hir().body_const_context(def_id); - - let kind = self.def_kind(def_id); - debug_assert_ne!(kind, DefKind::ConstParam); - - if self.has_attr(def_id, sym::rustc_do_not_const_check) { - trace!("do not const check this context"); - host_always_on = true; - } - - match const_context { - _ if host_always_on => self.consts.true_, - Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { .. }) => { - self.consts.false_ - } - Some(hir::ConstContext::ConstFn) => { - let host_idx = self - .generics_of(def_id) - .host_effect_index - .expect("ConstContext::Maybe must have host effect param"); - ty::GenericArgs::identity_for_item(self, def_id).const_at(host_idx) - } - None => self.consts.true_, - } - } - /// Expand any [weak alias types][weak] contained within the given `value`. /// /// This should be used over other normalization routines in situations where @@ -1826,8 +1784,8 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { /// cause an ICE that we otherwise may want to prevent. pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { if (matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic) - && tcx.features().intrinsics) - || (tcx.has_attr(def_id, sym::rustc_intrinsic) && tcx.features().rustc_attrs) + && tcx.features().intrinsics()) + || (tcx.has_attr(def_id, sym::rustc_intrinsic) && tcx.features().rustc_attrs()) { Some(ty::IntrinsicDef { name: tcx.item_name(def_id.into()), 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 1e67e759aa2..112eac32264 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -163,7 +163,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = this.tcx; - if tcx.features().unsized_fn_params { + if tcx.features().unsized_fn_params() { let ty = expr.ty; let param_env = this.param_env; diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 7170aebee7d..37cedd8cf5c 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -149,7 +149,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let ty::Adt(def, _) = ty.kind() && tcx.is_lang_item(def.did(), LangItem::String) { - if !tcx.features().string_deref_patterns { + if !tcx.features().string_deref_patterns() { span_bug!( test.span, "matching on `String` went through without enabling string_deref_patterns" diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index dfc82f705a8..a7e56b8f589 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -1048,8 +1048,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // | +------------|outer_scope cache|--+ | // +------------------------------|middle_scope cache|------+ // - // Now, a new, inner-most scope is added along with a new drop into - // both inner-most and outer-most scopes: + // Now, a new, innermost scope is added along with a new drop into + // both innermost and outermost scopes: // // +------------------------------------------------------------+ // | +----------------------------------+ | @@ -1061,11 +1061,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // +----=----------------|invalid middle_scope cache|-----------+ // // If, when adding `drop(new)` we do not invalidate the cached blocks for both - // outer_scope and middle_scope, then, when building drops for the inner (right-most) + // outer_scope and middle_scope, then, when building drops for the inner (rightmost) // scope, the old, cached blocks, without `drop(new)` will get used, producing the // wrong results. // - // Note that this code iterates scopes from the inner-most to the outer-most, + // Note that this code iterates scopes from the innermost to the outermost, // invalidating caches of each scope visited. This way bare minimum of the // caches gets invalidated. i.e., if a new drop is added into the middle scope, the // cache of outer scope stays intact. diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 8512763a595..f3e6301d9d1 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -509,20 +509,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } ExprKind::RawBorrow { arg, .. } => { if let ExprKind::Scope { value: arg, .. } = self.thir[arg].kind - // THIR desugars UNSAFE_STATIC into *UNSAFE_STATIC_REF, where - // UNSAFE_STATIC_REF holds the addr of the UNSAFE_STATIC, so: take two steps && let ExprKind::Deref { arg } = self.thir[arg].kind - // FIXME(workingjubiee): we lack a clear reason to reject ThreadLocalRef here, - // but we also have no conclusive reason to allow it either! - && let ExprKind::StaticRef { .. } = self.thir[arg].kind { - // A raw ref to a place expr, even an "unsafe static", is okay! - // We short-circuit to not recursively traverse this expression. + // Taking a raw ref to a deref place expr is always safe. + // Make sure the expression we're deref'ing is safe, though. + visit::walk_expr(self, &self.thir[arg]); return; - // note: const_mut_refs enables this code, and it currently remains unsafe: - // static mut BYTE: u8 = 0; - // static mut BYTE_PTR: *mut u8 = unsafe { addr_of_mut!(BYTE) }; - // static mut DEREF_BYTE_PTR: *mut u8 = unsafe { addr_of_mut!(*BYTE_PTR) }; } } ExprKind::Deref { arg } => { diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 5995d60e7e0..e2823456477 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -281,7 +281,14 @@ impl<'tcx> Cx<'tcx> { .unwrap_or_else(|e| panic!("could not compute layout for {param_env_ty:?}: {e:?}")) .size; - let lit = ScalarInt::try_from_uint(discr_offset as u128, size).unwrap(); + let (lit, overflowing) = ScalarInt::truncate_from_uint(discr_offset as u128, size); + if overflowing { + // An erroneous enum with too many variants for its repr will emit E0081 and E0370 + self.tcx.dcx().span_delayed_bug( + source.span, + "overflowing enum wasn't rejected by hir analysis", + ); + } let kind = ExprKind::NonHirLiteral { lit, user_ty: None }; let offset = self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind }); @@ -777,7 +784,7 @@ impl<'tcx> Cx<'tcx> { if_then_scope: region::Scope { id: then.hir_id.local_id, data: { - if expr.span.at_least_rust_2024() && tcx.features().if_let_rescope { + if expr.span.at_least_rust_2024() && tcx.features().if_let_rescope() { region::ScopeData::IfThenRescope } else { region::ScopeData::IfThen 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 ae77bce6bb1..8498df59ce6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1126,7 +1126,7 @@ fn report_non_exhaustive_match<'p, 'tcx>( .map(|witness| cx.print_witness_pat(witness)) .collect::>() .join(" | "); - if witnesses.iter().all(|p| p.is_never_pattern()) && cx.tcx.features().never_patterns { + if witnesses.iter().all(|p| p.is_never_pattern()) && cx.tcx.features().never_patterns() { // Arms with a never pattern don't take a body. pattern } else { diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index faee40faa3f..d0f62bd82d1 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -1177,7 +1177,7 @@ struct PlaceInfo<'tcx> { /// The projection used to go from parent to this node (only None for root). proj_elem: Option, - /// The left-most child. + /// The leftmost child. first_child: Option, /// Index of the sibling to the right of this node. diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 0a413d68020..cd291058977 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1497,7 +1497,7 @@ fn check_field_tys_sized<'tcx>( ) { // No need to check if unsized_locals/unsized_fn_params is disabled, // since we will error during typeck. - if !tcx.features().unsized_locals && !tcx.features().unsized_fn_params { + if !tcx.features().unsized_locals() && !tcx.features().unsized_fn_params() { return; } diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 94088156756..cf9f6981c5a 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -5,7 +5,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::DirectedGraph; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; -use rustc_middle::bug; use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op}; use tracing::{debug, debug_span, instrument}; @@ -58,13 +57,13 @@ pub(super) struct CoverageCounters { counter_increment_sites: IndexVec, /// Coverage counters/expressions that are associated with individual BCBs. - bcb_counters: IndexVec>, + node_counters: IndexVec>, /// Coverage counters/expressions that are associated with the control-flow /// edge between two BCBs. /// /// We currently don't iterate over this map, but if we do in the future, /// switch it back to `FxIndexMap` to avoid query stability hazards. - bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>, + edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>, /// Table of expression data, associating each expression ID with its /// corresponding operator (+ or -) and its LHS/RHS operands. @@ -78,20 +77,20 @@ impl CoverageCounters { /// Ensures that each BCB node needing a counter has one, by creating physical /// counters or counter expressions for nodes and edges as required. pub(super) fn make_bcb_counters( - basic_coverage_blocks: &CoverageGraph, + graph: &CoverageGraph, bcb_needs_counter: &BitSet, ) -> Self { - let mut counters = MakeBcbCounters::new(basic_coverage_blocks, bcb_needs_counter); - counters.make_bcb_counters(); + let mut builder = CountersBuilder::new(graph, bcb_needs_counter); + builder.make_bcb_counters(); - counters.coverage_counters + builder.counters } fn with_num_bcbs(num_bcbs: usize) -> Self { Self { counter_increment_sites: IndexVec::new(), - bcb_counters: IndexVec::from_elem_n(None, num_bcbs), - bcb_edge_counters: FxHashMap::default(), + node_counters: IndexVec::from_elem_n(None, num_bcbs), + edge_counters: FxHashMap::default(), expressions: IndexVec::new(), expressions_memo: FxHashMap::default(), } @@ -104,24 +103,18 @@ impl CoverageCounters { BcbCounter::Counter { id } } - /// Creates a new physical counter attached a BCB node. - /// The node must not already have a counter. + /// Creates a new physical counter for a BCB node. fn make_phys_node_counter(&mut self, bcb: BasicCoverageBlock) -> BcbCounter { - let counter = self.make_counter_inner(CounterIncrementSite::Node { bcb }); - debug!(?bcb, ?counter, "node gets a physical counter"); - self.set_bcb_counter(bcb, counter) + self.make_counter_inner(CounterIncrementSite::Node { bcb }) } - /// Creates a new physical counter attached to a BCB edge. - /// The edge must not already have a counter. + /// Creates a new physical counter for a BCB edge. fn make_phys_edge_counter( &mut self, from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, ) -> BcbCounter { - let counter = self.make_counter_inner(CounterIncrementSite::Edge { from_bcb, to_bcb }); - debug!(?from_bcb, ?to_bcb, ?counter, "edge gets a physical counter"); - self.set_bcb_edge_counter(from_bcb, to_bcb, counter) + self.make_counter_inner(CounterIncrementSite::Edge { from_bcb, to_bcb }) } fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter { @@ -193,35 +186,31 @@ impl CoverageCounters { self.counter_increment_sites.len() } - fn set_bcb_counter(&mut self, bcb: BasicCoverageBlock, counter_kind: BcbCounter) -> BcbCounter { - if let Some(replaced) = self.bcb_counters[bcb].replace(counter_kind) { - bug!( - "attempt to set a BasicCoverageBlock coverage counter more than once; \ - {bcb:?} already had counter {replaced:?}", - ); - } else { - counter_kind - } + fn set_node_counter(&mut self, bcb: BasicCoverageBlock, counter: BcbCounter) -> BcbCounter { + let existing = self.node_counters[bcb].replace(counter); + assert!( + existing.is_none(), + "node {bcb:?} already has a counter: {existing:?} => {counter:?}" + ); + counter } - fn set_bcb_edge_counter( + fn set_edge_counter( &mut self, from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, - counter_kind: BcbCounter, + counter: BcbCounter, ) -> BcbCounter { - if let Some(replaced) = self.bcb_edge_counters.insert((from_bcb, to_bcb), counter_kind) { - bug!( - "attempt to set an edge counter more than once; from_bcb: \ - {from_bcb:?} already had counter {replaced:?}", - ); - } else { - counter_kind - } + let existing = self.edge_counters.insert((from_bcb, to_bcb), counter); + assert!( + existing.is_none(), + "edge ({from_bcb:?} -> {to_bcb:?}) already has a counter: {existing:?} => {counter:?}" + ); + counter } pub(super) fn term_for_bcb(&self, bcb: BasicCoverageBlock) -> Option { - self.bcb_counters[bcb].map(|counter| counter.as_term()) + self.node_counters[bcb].map(|counter| counter.as_term()) } /// Returns an iterator over all the nodes/edges in the coverage graph that @@ -238,7 +227,7 @@ impl CoverageCounters { pub(super) fn bcb_nodes_with_coverage_expressions( &self, ) -> impl Iterator + Captures<'_> { - self.bcb_counters.iter_enumerated().filter_map(|(bcb, &counter_kind)| match counter_kind { + self.node_counters.iter_enumerated().filter_map(|(bcb, &counter)| match counter { // Yield the BCB along with its associated expression ID. Some(BcbCounter::Expression { id }) => Some((bcb, id)), // This BCB is associated with a counter or nothing, so skip it. @@ -265,22 +254,20 @@ impl CoverageCounters { } } -/// Helper struct that allows counter creation to inspect the BCB graph. -struct MakeBcbCounters<'a> { - coverage_counters: CoverageCounters, - basic_coverage_blocks: &'a CoverageGraph, +/// Helper struct that allows counter creation to inspect the BCB graph, and +/// the set of nodes that need counters. +struct CountersBuilder<'a> { + counters: CoverageCounters, + graph: &'a CoverageGraph, bcb_needs_counter: &'a BitSet, } -impl<'a> MakeBcbCounters<'a> { - fn new( - basic_coverage_blocks: &'a CoverageGraph, - bcb_needs_counter: &'a BitSet, - ) -> Self { - assert_eq!(basic_coverage_blocks.num_nodes(), bcb_needs_counter.domain_size()); +impl<'a> CountersBuilder<'a> { + fn new(graph: &'a CoverageGraph, bcb_needs_counter: &'a BitSet) -> Self { + assert_eq!(graph.num_nodes(), bcb_needs_counter.domain_size()); Self { - coverage_counters: CoverageCounters::with_num_bcbs(basic_coverage_blocks.num_nodes()), - basic_coverage_blocks, + counters: CoverageCounters::with_num_bcbs(graph.num_nodes()), + graph, bcb_needs_counter, } } @@ -293,13 +280,12 @@ impl<'a> MakeBcbCounters<'a> { // // The traversal tries to ensure that, when a loop is encountered, all // nodes within the loop are visited before visiting any nodes outside - // the loop. It also keeps track of which loop(s) the traversal is - // currently inside. - let mut traversal = TraverseCoverageGraphWithLoops::new(self.basic_coverage_blocks); + // the loop. + let mut traversal = TraverseCoverageGraphWithLoops::new(self.graph); while let Some(bcb) = traversal.next() { let _span = debug_span!("traversal", ?bcb).entered(); if self.bcb_needs_counter.contains(bcb) { - self.make_node_counter_and_out_edge_counters(&traversal, bcb); + self.make_node_counter_and_out_edge_counters(bcb); } } @@ -312,36 +298,41 @@ impl<'a> MakeBcbCounters<'a> { /// Make sure the given node has a node counter, and then make sure each of /// its out-edges has an edge counter (if appropriate). - #[instrument(level = "debug", skip(self, traversal))] - fn make_node_counter_and_out_edge_counters( - &mut self, - traversal: &TraverseCoverageGraphWithLoops<'_>, - from_bcb: BasicCoverageBlock, - ) { + #[instrument(level = "debug", skip(self))] + fn make_node_counter_and_out_edge_counters(&mut self, from_bcb: BasicCoverageBlock) { // First, ensure that this node has a counter of some kind. // We might also use that counter to compute one of the out-edge counters. let node_counter = self.get_or_make_node_counter(from_bcb); - let successors = self.basic_coverage_blocks.successors[from_bcb].as_slice(); + let successors = self.graph.successors[from_bcb].as_slice(); // If this node's out-edges won't sum to the node's counter, // then there's no reason to create edge counters here. - if !self.basic_coverage_blocks[from_bcb].is_out_summable { + if !self.graph[from_bcb].is_out_summable { return; } - // Determine the set of out-edges that don't yet have edge counters. - let candidate_successors = self.basic_coverage_blocks.successors[from_bcb] + // When choosing which out-edge should be given a counter expression, ignore edges that + // already have counters, or could use the existing counter of their target node. + let out_edge_has_counter = |to_bcb| { + if self.counters.edge_counters.contains_key(&(from_bcb, to_bcb)) { + return true; + } + self.graph.sole_predecessor(to_bcb) == Some(from_bcb) + && self.counters.node_counters[to_bcb].is_some() + }; + + // Determine the set of out-edges that could benefit from being given an expression. + let candidate_successors = self.graph.successors[from_bcb] .iter() .copied() - .filter(|&to_bcb| self.edge_has_no_counter(from_bcb, to_bcb)) + .filter(|&to_bcb| !out_edge_has_counter(to_bcb)) .collect::>(); debug!(?candidate_successors); // If there are out-edges without counters, choose one to be given an expression // (computed from this node and the other out-edges) instead of a physical counter. - let Some(expression_to_bcb) = - self.choose_out_edge_for_expression(traversal, &candidate_successors) + let Some(target_bcb) = self.choose_out_edge_for_expression(from_bcb, &candidate_successors) else { return; }; @@ -353,43 +344,44 @@ impl<'a> MakeBcbCounters<'a> { .iter() .copied() // Skip the chosen edge, since we'll calculate its count from this sum. - .filter(|&to_bcb| to_bcb != expression_to_bcb) + .filter(|&edge_target_bcb| edge_target_bcb != target_bcb) .map(|to_bcb| self.get_or_make_edge_counter(from_bcb, to_bcb)) .collect::>(); - let Some(sum_of_all_other_out_edges) = - self.coverage_counters.make_sum(&other_out_edge_counters) + let Some(sum_of_all_other_out_edges) = self.counters.make_sum(&other_out_edge_counters) else { return; }; // Now create an expression for the chosen edge, by taking the counter // for its source node and subtracting the sum of its sibling out-edges. - let expression = self.coverage_counters.make_expression( - node_counter, - Op::Subtract, - sum_of_all_other_out_edges, - ); + let expression = + self.counters.make_expression(node_counter, Op::Subtract, sum_of_all_other_out_edges); - debug!("{expression_to_bcb:?} gets an expression: {expression:?}"); - if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(expression_to_bcb) { - // This edge normally wouldn't get its own counter, so attach the expression - // to its target node instead, so that `edge_has_no_counter` can see it. - assert_eq!(sole_pred, from_bcb); - self.coverage_counters.set_bcb_counter(expression_to_bcb, expression); - } else { - self.coverage_counters.set_bcb_edge_counter(from_bcb, expression_to_bcb, expression); - } + debug!("{target_bcb:?} gets an expression: {expression:?}"); + self.counters.set_edge_counter(from_bcb, target_bcb, expression); } #[instrument(level = "debug", skip(self))] fn get_or_make_node_counter(&mut self, bcb: BasicCoverageBlock) -> BcbCounter { // If the BCB already has a counter, return it. - if let Some(counter_kind) = self.coverage_counters.bcb_counters[bcb] { - debug!("{bcb:?} already has a counter: {counter_kind:?}"); - return counter_kind; + if let Some(counter) = self.counters.node_counters[bcb] { + debug!("{bcb:?} already has a counter: {counter:?}"); + return counter; } - let predecessors = self.basic_coverage_blocks.predecessors[bcb].as_slice(); + let counter = self.make_node_counter_inner(bcb); + self.counters.set_node_counter(bcb, counter) + } + + fn make_node_counter_inner(&mut self, bcb: BasicCoverageBlock) -> BcbCounter { + // If the node's sole in-edge already has a counter, use that. + if let Some(sole_pred) = self.graph.sole_predecessor(bcb) + && let Some(&edge_counter) = self.counters.edge_counters.get(&(sole_pred, bcb)) + { + return edge_counter; + } + + let predecessors = self.graph.predecessors[bcb].as_slice(); // Handle cases where we can't compute a node's count from its in-edges: // - START_BCB has no in-edges, so taking the sum would panic (or be wrong). @@ -398,7 +390,9 @@ impl<'a> MakeBcbCounters<'a> { // leading to infinite recursion. if predecessors.len() <= 1 || predecessors.contains(&bcb) { debug!(?bcb, ?predecessors, "node has <=1 predecessors or is its own predecessor"); - return self.coverage_counters.make_phys_node_counter(bcb); + let counter = self.counters.make_phys_node_counter(bcb); + debug!(?bcb, ?counter, "node gets a physical counter"); + return counter; } // A BCB with multiple incoming edges can compute its count by ensuring that counters @@ -408,13 +402,11 @@ impl<'a> MakeBcbCounters<'a> { .copied() .map(|from_bcb| self.get_or_make_edge_counter(from_bcb, bcb)) .collect::>(); - let sum_of_in_edges: BcbCounter = self - .coverage_counters - .make_sum(&in_edge_counters) - .expect("there must be at least one in-edge"); + let sum_of_in_edges: BcbCounter = + self.counters.make_sum(&in_edge_counters).expect("there must be at least one in-edge"); debug!("{bcb:?} gets a new counter (sum of predecessor counters): {sum_of_in_edges:?}"); - self.coverage_counters.set_bcb_counter(bcb, sum_of_in_edges) + sum_of_in_edges } #[instrument(level = "debug", skip(self))] @@ -422,10 +414,25 @@ impl<'a> MakeBcbCounters<'a> { &mut self, from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, + ) -> BcbCounter { + // If the edge already has a counter, return it. + if let Some(&counter) = self.counters.edge_counters.get(&(from_bcb, to_bcb)) { + debug!("Edge {from_bcb:?}->{to_bcb:?} already has a counter: {counter:?}"); + return counter; + } + + let counter = self.make_edge_counter_inner(from_bcb, to_bcb); + self.counters.set_edge_counter(from_bcb, to_bcb, counter) + } + + fn make_edge_counter_inner( + &mut self, + from_bcb: BasicCoverageBlock, + to_bcb: BasicCoverageBlock, ) -> BcbCounter { // If the target node has exactly one in-edge (i.e. this one), then just // use the node's counter, since it will have the same value. - if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(to_bcb) { + if let Some(sole_pred) = self.graph.sole_predecessor(to_bcb) { assert_eq!(sole_pred, from_bcb); // This call must take care not to invoke `get_or_make_edge` for // this edge, since that would result in infinite recursion! @@ -434,33 +441,27 @@ impl<'a> MakeBcbCounters<'a> { // If the source node has exactly one out-edge (i.e. this one) and would have // the same execution count as that edge, then just use the node's counter. - if let Some(simple_succ) = self.basic_coverage_blocks.simple_successor(from_bcb) { + if let Some(simple_succ) = self.graph.simple_successor(from_bcb) { assert_eq!(simple_succ, to_bcb); return self.get_or_make_node_counter(from_bcb); } - // If the edge already has a counter, return it. - if let Some(&counter_kind) = - self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)) - { - debug!("Edge {from_bcb:?}->{to_bcb:?} already has a counter: {counter_kind:?}"); - return counter_kind; - } - // Make a new counter to count this edge. - self.coverage_counters.make_phys_edge_counter(from_bcb, to_bcb) + let counter = self.counters.make_phys_edge_counter(from_bcb, to_bcb); + debug!(?from_bcb, ?to_bcb, ?counter, "edge gets a physical counter"); + counter } /// Given a set of candidate out-edges (represented by their successor node), /// choose one to be given a counter expression instead of a physical counter. fn choose_out_edge_for_expression( &self, - traversal: &TraverseCoverageGraphWithLoops<'_>, + from_bcb: BasicCoverageBlock, candidate_successors: &[BasicCoverageBlock], ) -> Option { // Try to find a candidate that leads back to the top of a loop, // because reloop edges tend to be executed more times than loop-exit edges. - if let Some(reloop_target) = self.find_good_reloop_edge(traversal, &candidate_successors) { + if let Some(reloop_target) = self.find_good_reloop_edge(from_bcb, &candidate_successors) { debug!("Selecting reloop target {reloop_target:?} to get an expression"); return Some(reloop_target); } @@ -479,7 +480,7 @@ impl<'a> MakeBcbCounters<'a> { /// for them to be able to avoid a physical counter increment. fn find_good_reloop_edge( &self, - traversal: &TraverseCoverageGraphWithLoops<'_>, + from_bcb: BasicCoverageBlock, candidate_successors: &[BasicCoverageBlock], ) -> Option { // If there are no candidates, avoid iterating over the loop stack. @@ -488,14 +489,15 @@ impl<'a> MakeBcbCounters<'a> { } // Consider each loop on the current traversal context stack, top-down. - for reloop_bcbs in traversal.reloop_bcbs_per_loop() { + for loop_header_node in self.graph.loop_headers_containing(from_bcb) { // Try to find a candidate edge that doesn't exit this loop. for &target_bcb in candidate_successors { // An edge is a reloop edge if its target dominates any BCB that has // an edge back to the loop header. (Otherwise it's an exit edge.) - let is_reloop_edge = reloop_bcbs.iter().any(|&reloop_bcb| { - self.basic_coverage_blocks.dominates(target_bcb, reloop_bcb) - }); + let is_reloop_edge = self + .graph + .reloop_predecessors(loop_header_node) + .any(|reloop_bcb| self.graph.dominates(target_bcb, reloop_bcb)); if is_reloop_edge { // We found a good out-edge to be given an expression. return Some(target_bcb); @@ -508,21 +510,4 @@ impl<'a> MakeBcbCounters<'a> { None } - - #[inline] - fn edge_has_no_counter( - &self, - from_bcb: BasicCoverageBlock, - to_bcb: BasicCoverageBlock, - ) -> bool { - let edge_counter = - if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(to_bcb) { - assert_eq!(sole_pred, from_bcb); - self.coverage_counters.bcb_counters[to_bcb] - } else { - self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)).copied() - }; - - edge_counter.is_none() - } } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index d839f46cfbd..168262bf01c 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -1,10 +1,11 @@ use std::cmp::Ordering; use std::collections::VecDeque; +use std::iter; use std::ops::{Index, IndexMut}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::graph::dominators::{self, Dominators}; +use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::graph::{self, DirectedGraph, StartNode}; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; @@ -20,7 +21,17 @@ pub(crate) struct CoverageGraph { bb_to_bcb: IndexVec>, pub(crate) successors: IndexVec>, pub(crate) predecessors: IndexVec>, + dominators: Option>, + /// Allows nodes to be compared in some total order such that _if_ + /// `a` dominates `b`, then `a < b`. If neither node dominates the other, + /// their relative order is consistent but arbitrary. + dominator_order_rank: IndexVec, + /// A loop header is a node that dominates one or more of its predecessors. + is_loop_header: BitSet, + /// For each node, the loop header node of its nearest enclosing loop. + /// This forms a linked list that can be traversed to find all enclosing loops. + enclosing_loop_header: IndexVec>, } impl CoverageGraph { @@ -54,9 +65,47 @@ impl CoverageGraph { } } - let mut this = Self { bcbs, bb_to_bcb, successors, predecessors, dominators: None }; + let num_nodes = bcbs.len(); + let mut this = Self { + bcbs, + bb_to_bcb, + successors, + predecessors, + dominators: None, + dominator_order_rank: IndexVec::from_elem_n(0, num_nodes), + is_loop_header: BitSet::new_empty(num_nodes), + enclosing_loop_header: IndexVec::from_elem_n(None, num_nodes), + }; + assert_eq!(num_nodes, this.num_nodes()); - this.dominators = Some(dominators::dominators(&this)); + // Set the dominators first, because later init steps rely on them. + this.dominators = Some(graph::dominators::dominators(&this)); + + // Iterate over all nodes, such that dominating nodes are visited before + // the nodes they dominate. Either preorder or reverse postorder is fine. + let dominator_order = graph::iterate::reverse_post_order(&this, this.start_node()); + // The coverage graph is created by traversal, so all nodes are reachable. + assert_eq!(dominator_order.len(), this.num_nodes()); + for (rank, bcb) in (0u32..).zip(dominator_order) { + // The dominator rank of each node is its index in a dominator-order traversal. + this.dominator_order_rank[bcb] = rank; + + // A node is a loop header if it dominates any of its predecessors. + if this.reloop_predecessors(bcb).next().is_some() { + this.is_loop_header.insert(bcb); + } + + // If the immediate dominator is a loop header, that's our enclosing loop. + // Otherwise, inherit the immediate dominator's enclosing loop. + // (Dominator order ensures that we already processed the dominator.) + if let Some(dom) = this.dominators().immediate_dominator(bcb) { + this.enclosing_loop_header[bcb] = this + .is_loop_header + .contains(dom) + .then_some(dom) + .or_else(|| this.enclosing_loop_header[dom]); + } + } // The coverage graph's entry-point node (bcb0) always starts with bb0, // which never has predecessors. Any other blocks merged into bcb0 can't @@ -151,9 +200,14 @@ impl CoverageGraph { if bb.index() < self.bb_to_bcb.len() { self.bb_to_bcb[bb] } else { None } } + #[inline(always)] + fn dominators(&self) -> &Dominators { + self.dominators.as_ref().unwrap() + } + #[inline(always)] pub(crate) fn dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool { - self.dominators.as_ref().unwrap().dominates(dom, node) + self.dominators().dominates(dom, node) } #[inline(always)] @@ -162,7 +216,7 @@ impl CoverageGraph { a: BasicCoverageBlock, b: BasicCoverageBlock, ) -> Ordering { - self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b) + self.dominator_order_rank[a].cmp(&self.dominator_order_rank[b]) } /// Returns the source of this node's sole in-edge, if it has exactly one. @@ -193,6 +247,36 @@ impl CoverageGraph { None } } + + /// For each loop that contains the given node, yields the "loop header" + /// node representing that loop, from innermost to outermost. If the given + /// node is itself a loop header, it is yielded first. + pub(crate) fn loop_headers_containing( + &self, + bcb: BasicCoverageBlock, + ) -> impl Iterator + Captures<'_> { + let self_if_loop_header = self.is_loop_header.contains(bcb).then_some(bcb).into_iter(); + + let mut curr = Some(bcb); + let strictly_enclosing = iter::from_fn(move || { + let enclosing = self.enclosing_loop_header[curr?]; + curr = enclosing; + enclosing + }); + + self_if_loop_header.chain(strictly_enclosing) + } + + /// For the given node, yields the subset of its predecessor nodes that + /// it dominates. If that subset is non-empty, the node is a "loop header", + /// and each of those predecessors represents an in-edge that jumps back to + /// the top of its loop. + pub(crate) fn reloop_predecessors( + &self, + to_bcb: BasicCoverageBlock, + ) -> impl Iterator + Captures<'_> { + self.predecessors[to_bcb].iter().copied().filter(move |&pred| self.dominates(to_bcb, pred)) + } } impl Index for CoverageGraph { @@ -418,15 +502,12 @@ struct TraversalContext { pub(crate) struct TraverseCoverageGraphWithLoops<'a> { basic_coverage_blocks: &'a CoverageGraph, - backedges: IndexVec>, context_stack: Vec, visited: BitSet, } impl<'a> TraverseCoverageGraphWithLoops<'a> { pub(crate) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self { - let backedges = find_loop_backedges(basic_coverage_blocks); - let worklist = VecDeque::from([basic_coverage_blocks.start_node()]); let context_stack = vec![TraversalContext { loop_header: None, worklist }]; @@ -435,17 +516,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { // of the stack as loops are entered, and popped off of the stack when a loop's worklist is // exhausted. let visited = BitSet::new_empty(basic_coverage_blocks.num_nodes()); - Self { basic_coverage_blocks, backedges, context_stack, visited } - } - - /// For each loop on the loop context stack (top-down), yields a list of BCBs - /// within that loop that have an outgoing edge back to the loop header. - pub(crate) fn reloop_bcbs_per_loop(&self) -> impl Iterator { - self.context_stack - .iter() - .rev() - .filter_map(|context| context.loop_header) - .map(|header_bcb| self.backedges[header_bcb].as_slice()) + Self { basic_coverage_blocks, context_stack, visited } } pub(crate) fn next(&mut self) -> Option { @@ -467,7 +538,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { } debug!("Visiting {bcb:?}"); - if self.backedges[bcb].len() > 0 { + if self.basic_coverage_blocks.is_loop_header.contains(bcb) { debug!("{bcb:?} is a loop header! Start a new TraversalContext..."); self.context_stack .push(TraversalContext { loop_header: Some(bcb), worklist: VecDeque::new() }); @@ -545,29 +616,6 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { } } -fn find_loop_backedges( - basic_coverage_blocks: &CoverageGraph, -) -> IndexVec> { - let num_bcbs = basic_coverage_blocks.num_nodes(); - let mut backedges = IndexVec::from_elem_n(Vec::::new(), num_bcbs); - - // Identify loops by their backedges. - for (bcb, _) in basic_coverage_blocks.iter_enumerated() { - for &successor in &basic_coverage_blocks.successors[bcb] { - if basic_coverage_blocks.dominates(successor, bcb) { - let loop_header = successor; - let backedge_from_bcb = bcb; - debug!( - "Found BCB backedge: {:?} -> loop_header: {:?}", - backedge_from_bcb, loop_header - ); - backedges[loop_header].push(backedge_from_bcb); - } - } - } - backedges -} - fn short_circuit_preorder<'a, 'tcx, F, Iter>( body: &'a mir::Body<'tcx>, filtered_successors: F, diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index bc86ae22a0d..2db7c6cf1d6 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -363,7 +363,7 @@ fn calc_test_vectors_index(conditions: &mut Vec) -> usize { let ConditionInfo { condition_id, true_next_id, false_next_id } = branch.condition_info; [true_next_id, false_next_id] .into_iter() - .filter_map(std::convert::identity) + .flatten() .for_each(|next_id| indegree_stats[next_id] += 1); (condition_id, branch) }) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index da7d20cf19a..085c738f1f9 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -87,7 +87,7 @@ fn remove_unwanted_expansion_spans(covspans: &mut Vec) { covspans.retain(|covspan| { match covspan.expn_kind { // Retain only the first await-related or macro-expanded covspan with this span. - Some(ExpnKind::Desugaring(kind)) if kind == DesugaringKind::Await => { + Some(ExpnKind::Desugaring(DesugaringKind::Await)) => { deduplicated_spans.insert(covspan.span) } Some(ExpnKind::Macro(MacroKind::Bang, _)) => deduplicated_spans.insert(covspan.span), diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index daf868559bc..79c62372df0 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -288,7 +288,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()), evaluated: IndexVec::with_capacity(num_values), next_opaque: Some(1), - feature_unsized_locals: tcx.features().unsized_locals, + feature_unsized_locals: tcx.features().unsized_locals(), ssa, dominators, reused_locals: BitSet::new_empty(local_decls.len()), diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index c9f24764cc2..42d6bdf6cee 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -439,12 +439,7 @@ impl<'tcx> Inliner<'tcx> { // Reachability pass defines which functions are eligible for inlining. Generally inlining // other functions is incorrect because they could reference symbols that aren't exported. - let is_generic = callsite - .callee - .args - .non_erasable_generics(self.tcx, callsite.callee.def_id()) - .next() - .is_some(); + let is_generic = callsite.callee.args.non_erasable_generics().next().is_some(); if !is_generic && !cross_crate_inlinable { return Err("not exported"); } diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 86c4b241a2b..fa9a6bfcf7c 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -673,7 +673,7 @@ impl<'tcx> Validator<'_, 'tcx> { } // Make sure the callee is a `const fn`. let is_const_fn = match *fn_ty.kind() { - ty::FnDef(def_id, _) => self.tcx.is_const_fn_raw(def_id), + ty::FnDef(def_id, _) => self.tcx.is_const_fn(def_id), _ => false, }; if !is_const_fn { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index b4d084d4dff..8df6e63deeb 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -504,7 +504,7 @@ fn collect_items_rec<'tcx>( // Check for PMEs and emit a diagnostic if one happened. To try to show relevant edges of the // mono item graph. if tcx.dcx().err_count() > error_count - && starting_item.node.is_generic_fn(tcx) + && starting_item.node.is_generic_fn() && starting_item.node.is_user_defined() { let formatted_item = with_no_trimmed_paths!(starting_item.node.to_string()); @@ -1522,7 +1522,6 @@ fn create_mono_items_for_default_impls<'tcx>( // it, to validate whether or not the impl is legal to instantiate at all. let only_region_params = |param: &ty::GenericParamDef, _: &_| match param.kind { GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), - GenericParamDefKind::Const { is_host_effect: true, .. } => tcx.consts.true_.into(), GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { unreachable!( "`own_requires_monomorphization` check means that \ diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 9bf7e67417e..e2a6d392ca0 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -229,7 +229,7 @@ where } let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); - let is_volatile = is_incremental_build && mono_item.is_generic_fn(cx.tcx); + let is_volatile = is_incremental_build && mono_item.is_generic_fn(); let cgu_name = match characteristic_def_id { Some(def_id) => compute_codegen_unit_name( @@ -822,7 +822,7 @@ fn mono_item_visibility<'tcx>( return Visibility::Hidden; } - let is_generic = instance.args.non_erasable_generics(tcx, def_id).next().is_some(); + let is_generic = instance.args.non_erasable_generics().next().is_some(); // Upstream `DefId` instances get different handling than local ones. let Some(def_id) = def_id.as_local() else { diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 23634d35c07..63608f9e856 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -431,7 +431,6 @@ impl, I: Interner> TypeFolder for Canonicaliz ); CanonicalVarKind::Const(self.delegate.universe_of_ct(vid).unwrap()) } - ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect, ty::InferConst::Fresh(_) => todo!(), }, ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode { diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index f2654f7534e..71c87714745 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -76,9 +76,6 @@ impl, I: Interner> TypeFolder for EagerResolv resolved } } - ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => { - self.delegate.opportunistic_resolve_effect_var(vid) - } _ => { if c.has_infer() { c.super_fold_with(self) 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 c9c0d6391fc..f6a5f20a639 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -100,6 +100,15 @@ 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. + fn consider_additional_alias_assumptions( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + alias_ty: ty::AliasTy, + ) -> Vec>; + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, @@ -270,11 +279,6 @@ where ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Vec>; - - fn consider_builtin_effects_intersection_candidate( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - ) -> Result, NoSolution>; } impl EvalCtxt<'_, D> @@ -481,9 +485,6 @@ where Some(TraitSolverLangItem::TransmuteTrait) => { G::consider_builtin_transmute_candidate(self, goal) } - Some(TraitSolverLangItem::EffectsIntersection) => { - G::consider_builtin_effects_intersection_candidate(self, goal) - } _ => Err(NoSolution), } }; @@ -602,6 +603,8 @@ where )); } + candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty)); + if kind != ty::Projection { return; } diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs new file mode 100644 index 00000000000..8d57ad8f255 --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -0,0 +1,345 @@ +//! Dealing with host effect goals, i.e. enforcing the constness in +//! `T: const Trait` or `T: ~const Trait`. + +use rustc_type_ir::fast_reject::DeepRejectCtxt; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{self as ty, Interner, elaborate}; +use tracing::instrument; + +use super::assembly::Candidate; +use crate::delegate::SolverDelegate; +use crate::solve::assembly::{self}; +use crate::solve::{ + BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution, + QueryResult, +}; + +impl assembly::GoalKind for ty::HostEffectPredicate +where + D: SolverDelegate, + I: Interner, +{ + fn self_ty(self) -> I::Ty { + self.self_ty() + } + + fn trait_ref(self, _: I) -> ty::TraitRef { + self.trait_ref + } + + fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self { + self.with_self_ty(cx, self_ty) + } + + fn trait_def_id(self, _: I) -> I::DefId { + self.def_id() + } + + fn probe_and_match_goal_against_assumption( + ecx: &mut EvalCtxt<'_, D>, + source: rustc_type_ir::solve::CandidateSource, + goal: Goal, + assumption: ::Clause, + then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult, + ) -> Result, NoSolution> { + if let Some(host_clause) = assumption.as_host_effect_clause() { + if host_clause.def_id() == goal.predicate.def_id() + && host_clause.host().satisfies(goal.predicate.host) + { + if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( + goal.predicate.trait_ref.args, + host_clause.skip_binder().trait_ref.args, + ) { + return Err(NoSolution); + } + + ecx.probe_trait_candidate(source).enter(|ecx| { + let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause); + ecx.eq( + goal.param_env, + goal.predicate.trait_ref, + assumption_trait_pred.trait_ref, + )?; + then(ecx) + }) + } else { + Err(NoSolution) + } + } else { + Err(NoSolution) + } + } + + /// Register additional assumptions for aliases corresponding to `~const` item bounds. + /// + /// Unlike item bounds, they are not simply implied by the well-formedness of the alias. + /// Instead, they only hold if the const conditons on the alias also hold. This is why + /// we also register the const conditions of the alias after matching the goal against + /// the assumption. + fn consider_additional_alias_assumptions( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + alias_ty: ty::AliasTy, + ) -> Vec> { + let cx = ecx.cx(); + let mut candidates = vec![]; + + // FIXME(effects): 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) + .iter_instantiated(cx, alias_ty.args) + .map(|trait_ref| trait_ref.to_host_effect_clause(cx, goal.predicate.host)), + ) { + candidates.extend(Self::probe_and_match_goal_against_assumption( + ecx, + CandidateSource::AliasBound, + goal, + clause, + |ecx| { + // Const conditions must hold for the implied const bound to hold. + ecx.add_goals( + GoalSource::Misc, + cx.const_conditions(alias_ty.def_id) + .iter_instantiated(cx, alias_ty.args) + .map(|trait_ref| { + goal.with( + cx, + trait_ref.to_host_effect_clause(cx, goal.predicate.host), + ) + }), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + )); + } + + candidates + } + + fn consider_impl_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + impl_def_id: ::DefId, + ) -> Result, NoSolution> { + let cx = ecx.cx(); + + let impl_trait_ref = cx.impl_trait_ref(impl_def_id); + if !DeepRejectCtxt::relate_rigid_infer(ecx.cx()) + .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args) + { + return Err(NoSolution); + } + + let impl_polarity = cx.impl_polarity(impl_def_id); + match impl_polarity { + ty::ImplPolarity::Negative => return Err(NoSolution), + ty::ImplPolarity::Reservation => { + unimplemented!("reservation impl for const trait: {:?}", goal) + } + ty::ImplPolarity::Positive => {} + }; + + if !cx.is_const_impl(impl_def_id) { + return Err(NoSolution); + } + + ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { + let impl_args = ecx.fresh_args_for_item(impl_def_id); + ecx.record_impl_args(impl_args); + let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args); + + ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; + let where_clause_bounds = cx + .predicates_of(impl_def_id) + .iter_instantiated(cx, impl_args) + .map(|pred| goal.with(cx, pred)); + ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); + + // For this impl to be `const`, we need to check its `~const` bounds too. + let const_conditions = cx + .const_conditions(impl_def_id) + .iter_instantiated(cx, impl_args) + .map(|bound_trait_ref| { + goal.with(cx, bound_trait_ref.to_host_effect_clause(cx, goal.predicate.host)) + }); + ecx.add_goals(GoalSource::ImplWhereBound, const_conditions); + + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } + + fn consider_error_guaranteed_candidate( + ecx: &mut EvalCtxt<'_, D>, + _guar: ::ErrorGuaranteed, + ) -> Result, NoSolution> { + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) + } + + fn consider_auto_trait_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("auto traits are never const") + } + + fn consider_trait_alias_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("trait aliases are never const") + } + + fn consider_builtin_sized_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("Sized is never const") + } + + fn consider_builtin_copy_clone_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + todo!("Copy/Clone is not yet const") + } + + fn consider_builtin_pointer_like_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("PointerLike is not const") + } + + fn consider_builtin_fn_ptr_trait_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + todo!("Fn* are not yet const") + } + + fn consider_builtin_fn_trait_candidates( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + _kind: rustc_type_ir::ClosureKind, + ) -> Result, NoSolution> { + todo!("Fn* are not yet const") + } + + fn consider_builtin_async_fn_trait_candidates( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + _kind: rustc_type_ir::ClosureKind, + ) -> Result, NoSolution> { + todo!("AsyncFn* are not yet const") + } + + fn consider_builtin_async_fn_kind_helper_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("AsyncFnKindHelper is not const") + } + + fn consider_builtin_tuple_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("Tuple trait is not const") + } + + fn consider_builtin_pointee_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("Pointee is not const") + } + + fn consider_builtin_future_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("Future is not const") + } + + fn consider_builtin_iterator_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + todo!("Iterator is not yet const") + } + + fn consider_builtin_fused_iterator_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("FusedIterator is not const") + } + + fn consider_builtin_async_iterator_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("AsyncIterator is not const") + } + + fn consider_builtin_coroutine_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("Coroutine is not const") + } + + fn consider_builtin_discriminant_kind_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("DiscriminantKind is not const") + } + + fn consider_builtin_async_destruct_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("AsyncDestruct is not const") + } + + fn consider_builtin_destruct_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("Destruct is not const") + } + + fn consider_builtin_transmute_candidate( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Result, NoSolution> { + unreachable!("TransmuteFrom is not const") + } + + fn consider_structural_builtin_unsize_candidates( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + ) -> Vec> { + unreachable!("Unsize is not const") + } +} + +impl EvalCtxt<'_, D> +where + D: SolverDelegate, + I: Interner, +{ + #[instrument(level = "trace", skip(self))] + pub(super) fn compute_host_effect_goal( + &mut self, + goal: Goal>, + ) -> QueryResult { + let candidates = self.assemble_and_evaluate_candidates(goal); + self.merge_candidates(candidates) + } +} diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 71ce0cce772..e2fd0dd2a25 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -170,7 +170,7 @@ where // // We don't do so for `NormalizesTo` goals as we erased the expected term and // bailing with overflow here would prevent us from detecting a type-mismatch, - // causing a coherence error in diesel, see #131969. We still bail with verflow + // causing a coherence error in diesel, see #131969. We still bail with overflow // when later returning from the parent AliasRelate goal. if !self.is_normalizes_to_goal { let num_non_region_vars = diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index cbefc826fb7..7608253882a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -291,7 +291,7 @@ where search_graph, nested_goals: NestedGoals::new(), tainted: Ok(()), - inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values, input), + inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values), }; for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { @@ -443,6 +443,9 @@ where ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { self.compute_trait_goal(Goal { param_env, predicate }) } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => { + self.compute_host_effect_goal(Goal { param_env, predicate }) + } ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => { self.compute_projection_goal(Goal { param_env, predicate }) } diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 85474bf37b4..1607fbb1b6a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -13,7 +13,7 @@ use rustc_type_ir::{self as ty, Interner}; use crate::delegate::SolverDelegate; use crate::solve::eval_ctxt::canonical; use crate::solve::{ - CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, QueryInput, + CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, QueryResult, inspect, }; @@ -119,6 +119,9 @@ impl WipCanonicalGoalEvaluation { } } +/// This only exists during proof tree building and does not have +/// a corresponding struct in `inspect`. We need this to track a +/// bunch of metadata about the current evaluation. #[derive_where(PartialEq, Eq, Debug; I: Interner)] struct WipCanonicalGoalEvaluationStep { /// Unlike `EvalCtxt::var_values`, we append a new @@ -128,7 +131,6 @@ struct WipCanonicalGoalEvaluationStep { /// This is necessary as we otherwise don't unify these /// vars when instantiating multiple `CanonicalState`. var_values: Vec, - instantiated_goal: QueryInput, probe_depth: usize, evaluation: WipProbe, } @@ -145,16 +147,12 @@ impl WipCanonicalGoalEvaluationStep { current } - fn finalize(self) -> inspect::CanonicalGoalEvaluationStep { + fn finalize(self) -> inspect::Probe { let evaluation = self.evaluation.finalize(); match evaluation.kind { - inspect::ProbeKind::Root { .. } => (), + inspect::ProbeKind::Root { .. } => evaluation, _ => unreachable!("unexpected root evaluation: {evaluation:?}"), } - inspect::CanonicalGoalEvaluationStep { - instantiated_goal: self.instantiated_goal, - evaluation, - } } } @@ -328,11 +326,9 @@ impl, I: Interner> ProofTreeBuilder { pub(crate) fn new_goal_evaluation_step( &mut self, var_values: ty::CanonicalVarValues, - instantiated_goal: QueryInput, ) -> ProofTreeBuilder { self.nested(|| WipCanonicalGoalEvaluationStep { var_values: var_values.var_values.to_vec(), - instantiated_goal, evaluation: WipProbe { initial_num_var_values: var_values.len(), steps: vec![], diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index a475a58e483..6793779b205 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -13,6 +13,7 @@ mod alias_relate; mod assembly; +mod effect_goals; mod eval_ctxt; pub mod inspect; mod normalizes_to; @@ -182,12 +183,6 @@ where let (ct, ty) = goal.predicate; let ct_ty = match ct.kind() { - // FIXME: Ignore effect vars because canonicalization doesn't handle them correctly - // and if we stall on the var then we wind up creating ambiguity errors in a probe - // for this goal which contains an effect var. Which then ends up ICEing. - ty::ConstKind::Infer(ty::InferConst::EffectVar(_)) => { - return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); - } ty::ConstKind::Infer(_) => { return self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } 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 4d8b193ee49..7287cdf74bf 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 @@ -193,6 +193,14 @@ where } } + fn consider_additional_alias_assumptions( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + _alias_ty: ty::AliasTy, + ) -> Vec> { + vec![] + } + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal>, @@ -911,68 +919,6 @@ where ) -> Result, NoSolution> { panic!("`TransmuteFrom` does not have an associated type: {:?}", goal) } - - fn consider_builtin_effects_intersection_candidate( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - ) -> Result, NoSolution> { - let ty::Tuple(types) = goal.predicate.self_ty().kind() else { - return Err(NoSolution); - }; - - let cx = ecx.cx(); - - let mut first_non_maybe = None; - let mut non_maybe_count = 0; - for ty in types.iter() { - if !matches!(ty::EffectKind::try_from_ty(cx, ty), Some(ty::EffectKind::Maybe)) { - first_non_maybe.get_or_insert(ty); - non_maybe_count += 1; - } - } - - match non_maybe_count { - 0 => { - let ty = ty::EffectKind::Maybe.to_ty(cx); - ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { - ecx.instantiate_normalizes_to_term(goal, ty.into()); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) - } - 1 => { - let ty = first_non_maybe.unwrap(); - ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { - ecx.instantiate_normalizes_to_term(goal, ty.into()); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) - } - _ => { - let mut min = ty::EffectKind::Maybe; - - for ty in types.iter() { - // We can't find the intersection if the types used are generic. - // - // FIXME(effects): do we want to look at where clauses to get some - // clue for the case where generic types are being used? - let Some(kind) = ty::EffectKind::try_from_ty(cx, ty) else { - return Err(NoSolution); - }; - - let Some(result) = ty::EffectKind::intersection(min, kind) else { - return Err(NoSolution); - }; - - min = result; - } - - let ty = min.to_ty(cx); - ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { - ecx.instantiate_normalizes_to_term(goal, ty.into()); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) - } - } - } } impl EvalCtxt<'_, D> 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 a8d6536baad..08cc89d950e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -39,6 +39,14 @@ where self.def_id() } + fn consider_additional_alias_assumptions( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + _alias_ty: ty::AliasTy, + ) -> Vec> { + vec![] + } + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal>, @@ -719,47 +727,6 @@ where } }) } - - fn consider_builtin_effects_intersection_candidate( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - ) -> Result, NoSolution> { - if goal.predicate.polarity != ty::PredicatePolarity::Positive { - return Err(NoSolution); - } - - let ty::Tuple(types) = goal.predicate.self_ty().kind() else { - return Err(NoSolution); - }; - - let cx = ecx.cx(); - let maybe_count = types - .iter() - .filter_map(|ty| ty::EffectKind::try_from_ty(cx, ty)) - .filter(|&ty| ty == ty::EffectKind::Maybe) - .count(); - - // Don't do concrete type check unless there are more than one type that will influence the result. - // This would allow `(Maybe, T): Min` pass even if we know nothing about `T`. - if types.len() - maybe_count > 1 { - let mut min = ty::EffectKind::Maybe; - - for ty in types.iter() { - let Some(kind) = ty::EffectKind::try_from_ty(ecx.cx(), ty) else { - return Err(NoSolution); - }; - - let Some(result) = ty::EffectKind::intersection(min, kind) else { - return Err(NoSolution); - }; - - min = result; - } - } - - ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) - .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) - } } impl EvalCtxt<'_, D> diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs index 41108c91f2e..e1f19beb53a 100644 --- a/compiler/rustc_parse/src/lexer/diagnostics.rs +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -85,7 +85,7 @@ pub(super) fn report_suspicious_mismatch_block( } } - // Find the inner-most span candidate for final report + // Find the innermost span candidate for final report let candidate_span = matched_spans.into_iter().rev().find(|&(_, same_ident)| !same_ident).map(|(span, _)| span); diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 3613b7b862d..e5e70ba2033 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -99,6 +99,10 @@ passes_collapse_debuginfo = passes_confusables = attribute should be applied to an inherent method .label = not an inherent method +passes_const_stable_not_stable = + attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]` + .label = attribute specified here + passes_continue_labeled_block = `continue` pointing to a labeled block .label = labeled blocks cannot be `continue`'d @@ -245,6 +249,19 @@ passes_doc_test_unknown_include = unknown `doc` attribute `{$path}` .suggestion = use `doc = include_str!` instead +passes_doc_test_unknown_passes = + unknown `doc` attribute `{$path}` + .note = `doc` attribute `{$path}` no longer functions; see issue #44136 + .label = no longer functions + .help = you may want to use `doc(document_private_items)` + .no_op_note = `doc({$path})` is now a no-op + +passes_doc_test_unknown_plugins = + unknown `doc` attribute `{$path}` + .note = `doc` attribute `{$path}` no longer functions; see issue #44136 and CVE-2018-1000622 + .label = no longer functions + .no_op_note = `doc({$path})` is now a no-op + passes_doc_test_unknown_spotlight = unknown `doc` attribute `{$path}` .note = `doc(spotlight)` was renamed to `doc(notable_trait)` @@ -256,7 +273,7 @@ passes_duplicate_diagnostic_item_in_crate = .note = the diagnostic item is first defined in crate `{$orig_crate_name}` passes_duplicate_feature_err = - the feature `{$feature}` has already been declared + the feature `{$feature}` has already been enabled passes_duplicate_lang_item = found duplicate lang item `{$lang_item_name}` @@ -452,10 +469,10 @@ passes_may_dangle = `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl passes_maybe_string_interpolation = you might have meant to use string interpolation in this string literal + passes_missing_const_err = - attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` .help = make the function or method const - .label = attribute specified here passes_missing_const_stab_attr = {$descr} has missing const stability attribute @@ -605,6 +622,10 @@ passes_remove_fields = passes_repr_align_function = `repr(align)` attributes on functions are unstable +passes_repr_align_greater_than_target_max = + alignment must not be greater than `isize::MAX` bytes + .note = `isize::MAX` is {$size} for the current target + passes_repr_conflicting = conflicting representation hints diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index d0cc123c41a..b1267562f7b 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -12,7 +12,7 @@ use super::layout_test::ensure_wf; use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedField}; pub fn test_abi(tcx: TyCtxt<'_>) { - if !tcx.features().rustc_attrs { + if !tcx.features().rustc_attrs() { // if the `rustc_attrs` feature is not enabled, don't bother testing ABI return; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8b30546d5cc..8c4592cbb36 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -34,6 +34,7 @@ use rustc_session::lint::builtin::{ use rustc_session::parse::feature_err; use rustc_span::symbol::{Symbol, kw, sym}; use rustc_span::{BytePos, DUMMY_SP, Span}; +use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; @@ -262,7 +263,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::cfg_attr // need to be fixed | sym::cfi_encoding // FIXME(cfi_encoding) - | sym::pointee // FIXME(derive_smart_pointer) + | sym::pointee // FIXME(derive_coerce_pointee) | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) | sym::used // handled elsewhere to restrict to static items | sym::repr // handled elsewhere to restrict to type decls items @@ -918,12 +919,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }; match item_kind { Some(ItemKind::Impl(i)) => { - let is_valid = matches!(&i.self_ty.kind, hir::TyKind::Tup([_])) - || if let hir::TyKind::BareFn(bare_fn_ty) = &i.self_ty.kind { - bare_fn_ty.decl.inputs.len() == 1 - } else { - false - } + let is_valid = doc_fake_variadic_is_allowed_self_ty(i.self_ty) || if let Some(&[hir::GenericArg::Type(ty)]) = i .of_trait .as_ref() @@ -1183,19 +1179,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sym::masked => self.check_doc_masked(attr, meta, hir_id, target), - // no_default_passes: deprecated - // passes: deprecated - // plugins: removed, but rustdoc warns about it itself - sym::cfg - | sym::hidden - | sym::no_default_passes - | sym::notable_trait - | sym::passes - | sym::plugins => {} + sym::cfg | sym::hidden | sym::notable_trait => {} sym::rust_logo => { if self.check_attr_crate_level(attr, meta, hir_id) - && !self.tcx.features().rustdoc_internals + && !self.tcx.features().rustdoc_internals() { feature_err( &self.tcx.sess, @@ -1240,6 +1228,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sugg: (attr.meta().unwrap().span, applicability), }, ); + } else if i_meta.has_name(sym::passes) + || i_meta.has_name(sym::no_default_passes) + { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + i_meta.span, + errors::DocTestUnknownPasses { path, span: i_meta.span }, + ); + } else if i_meta.has_name(sym::plugins) { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + i_meta.span, + errors::DocTestUnknownPlugins { path, span: i_meta.span }, + ); } else { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, @@ -1766,7 +1770,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } sym::align => { if let (Target::Fn | Target::Method(MethodKind::Inherent), false) = - (target, self.tcx.features().fn_align) + (target, self.tcx.features().fn_align()) { feature_err( &self.tcx.sess, @@ -1782,7 +1786,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::Union | Target::Enum | Target::Fn - | Target::Method(_) => continue, + | Target::Method(_) => {} _ => { self.dcx().emit_err( errors::AttrApplication::StructEnumFunctionMethodUnion { @@ -1792,6 +1796,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ); } } + + self.check_align_value(hint); } sym::packed => { if target != Target::Struct && target != Target::Union { @@ -1889,6 +1895,45 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + fn check_align_value(&self, item: &MetaItemInner) { + match item.singleton_lit_list() { + Some(( + _, + MetaItemLit { + kind: ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed), .. + }, + )) => { + let val = literal.get() as u64; + if val > 2_u64.pow(29) { + // for values greater than 2^29, a different error will be emitted, make sure that happens + self.dcx().span_delayed_bug( + item.span(), + "alignment greater than 2^29 should be errored on elsewhere", + ); + } else { + // only do this check when <= 2^29 to prevent duplicate errors: + // alignment greater than 2^29 not supported + // alignment is too large for the current target + + let max = + Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64; + if val > max { + self.dcx().emit_err(errors::InvalidReprAlignForTarget { + span: item.span(), + size: max, + }); + } + } + } + + // if the attribute is malformed, singleton_lit_list may not be of the expected type or may be None + // but an error will have already been emitted, so this code should just skip such attributes + Some((_, _)) | None => { + self.dcx().span_delayed_bug(item.span(), "malformed repr(align(N))"); + } + } + } + fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) { let mut used_linker_span = None; let mut used_compiler_span = None; @@ -1994,7 +2039,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) { match target { Target::Fn | Target::Method(_) - if self.tcx.is_const_fn_raw(hir_id.expect_owner().to_def_id()) => {} + if self.tcx.is_const_fn(hir_id.expect_owner().to_def_id()) => {} // FIXME(#80564): We permit struct fields and match arms to have an // `#[allow_internal_unstable]` attribute with just a lint, because we previously // erroneously allowed it and some crates used it accidentally, to be compatible @@ -2292,10 +2337,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &mut diag, &cause, None, - Some(ValuePairs::PolySigs(ExpectedFound { + Some(param_env.and(ValuePairs::PolySigs(ExpectedFound { expected: ty::Binder::dummy(expected_sig), found: ty::Binder::dummy(sig), - })), + }))), terr, false, ); @@ -2622,3 +2667,20 @@ fn check_duplicates( }, } } + +fn doc_fake_variadic_is_allowed_self_ty(self_ty: &hir::Ty<'_>) -> bool { + matches!(&self_ty.kind, hir::TyKind::Tup([_])) + || if let hir::TyKind::BareFn(bare_fn_ty) = &self_ty.kind { + bare_fn_ty.decl.inputs.len() == 1 + } else { + false + } + || (if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &self_ty.kind + && let Some(&[hir::GenericArg::Type(ty)]) = + path.segments.last().map(|last| last.args().args) + { + doc_fake_variadic_is_allowed_self_ty(ty) + } else { + false + }) +} diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 0dad94a9939..f5ece513956 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -87,7 +87,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { let is_feature_allowed = |feature_gate| { // All features require that the corresponding gate be enabled, // even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`. - if !tcx.features().active(feature_gate) { + if !tcx.features().enabled(feature_gate) { return false; } @@ -105,7 +105,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { // If this crate is not using stability attributes, or this function is not claiming to be a // stable `const fn`, that is all that is required. - if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { + if !tcx.features().staged_api() || tcx.has_attr(def_id, sym::rustc_const_unstable) { return true; } @@ -135,7 +135,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { let required_gates = required_gates.unwrap_or(&[]); let missing_gates: Vec<_> = - required_gates.iter().copied().filter(|&g| !features.active(g)).collect(); + required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect(); match missing_gates.as_slice() { [] => { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index f01ddbd47ef..8bd767c1243 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -323,6 +323,27 @@ pub(crate) struct DocTestUnknownSpotlight { pub span: Span, } +#[derive(LintDiagnostic)] +#[diag(passes_doc_test_unknown_passes)] +#[note] +#[help] +#[note(passes_no_op_note)] +pub(crate) struct DocTestUnknownPasses { + pub path: String, + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(passes_doc_test_unknown_plugins)] +#[note] +#[note(passes_no_op_note)] +pub(crate) struct DocTestUnknownPlugins { + pub path: String, + #[label] + pub span: Span, +} + #[derive(LintDiagnostic)] #[diag(passes_doc_test_unknown_include)] pub(crate) struct DocTestUnknownInclude { @@ -546,6 +567,15 @@ pub(crate) struct ReprConflicting { pub hint_spans: Vec, } +#[derive(Diagnostic)] +#[diag(passes_repr_align_greater_than_target_max, code = E0589)] +#[note] +pub(crate) struct InvalidReprAlignForTarget { + #[primary_span] + pub span: Span, + pub size: u64, +} + #[derive(LintDiagnostic)] #[diag(passes_repr_conflicting, code = E0566)] pub(crate) struct ReprConflictingLint; @@ -1553,12 +1583,20 @@ pub(crate) struct DuplicateFeatureErr { pub span: Span, pub feature: Symbol, } + #[derive(Diagnostic)] #[diag(passes_missing_const_err)] pub(crate) struct MissingConstErr { #[primary_span] #[help] pub fn_sig_span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_const_stable_not_stable)] +pub(crate) struct ConstStableNotStable { + #[primary_span] + pub fn_sig_span: Span, #[label] pub const_span: Span, } diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 3aef88e771f..93729a7f6df 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -18,7 +18,7 @@ use crate::errors::{ }; pub fn test_layout(tcx: TyCtxt<'_>) { - if !tcx.features().rustc_attrs { + if !tcx.features().rustc_attrs() { // if the `rustc_attrs` feature is not enabled, don't bother testing layout return; } diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 91ba2fa7548..8a360c017ad 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -144,7 +144,7 @@ impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> { fn lib_features(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> LibFeatures { // If `staged_api` is not enabled then we aren't allowed to define lib // features; there is no point collecting them. - if !tcx.features().staged_api { + if !tcx.features().staged_api() { return LibFeatures::default(); } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 056318fbcb7..0ec151ceb45 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -322,7 +322,7 @@ impl<'tcx> ReachableContext<'tcx> { self.visit(ty); // Manually visit to actually see the trait's `DefId`. Type visitors won't see it if let Some(trait_ref) = dyn_ty.principal() { - let ExistentialTraitRef { def_id, args } = trait_ref.skip_binder(); + let ExistentialTraitRef { def_id, args, .. } = trait_ref.skip_binder(); self.visit_def_id(def_id, "", &""); self.visit(args); } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 751c87a9fe5..f69cc74fba2 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -10,13 +10,13 @@ use rustc_attr::{ }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; -use rustc_feature::ACCEPTED_FEATURES; +use rustc_feature::{ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; +use rustc_hir::{Constness, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; use rustc_middle::middle::privacy::EffectiveVisibilities; @@ -27,7 +27,6 @@ use rustc_session::lint; use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED}; use rustc_span::Span; use rustc_span::symbol::{Symbol, sym}; -use rustc_target::spec::abi::Abi; use tracing::{debug, info}; use crate::errors; @@ -107,6 +106,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { def_id: LocalDefId, item_sp: Span, fn_sig: Option<&'tcx hir::FnSig<'tcx>>, + is_foreign_item: bool, kind: AnnotationKind, inherit_deprecation: InheritDeprecation, inherit_const_stability: InheritConstStability, @@ -144,7 +144,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - if !self.tcx.features().staged_api { + if !self.tcx.features().staged_api() { // Propagate unstability. This can happen even for non-staged-api crates in case // -Zforce-unstable-if-unmarked is set. if let Some(stab) = self.parent_stab { @@ -163,30 +163,62 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } let stab = attr::find_stability(self.tcx.sess, attrs, item_sp); - let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item_sp); + let const_stab = attr::find_const_stability( + self.tcx.sess, + attrs, + item_sp, + fn_sig.is_some_and(|s| s.header.is_const()), + ); let body_stab = attr::find_body_stability(self.tcx.sess, attrs); - let mut const_span = None; - let const_stab = const_stab.map(|(const_stab, const_span_node)| { - self.index.const_stab_map.insert(def_id, const_stab); - const_span = Some(const_span_node); - const_stab - }); - - // If the current node is a function, has const stability attributes and if it doesn not have an intrinsic ABI, - // check if the function/method is const or the parent impl block is const - if let (Some(const_span), Some(fn_sig)) = (const_span, fn_sig) - && fn_sig.header.abi != Abi::RustIntrinsic + // If the current node is a function with const stability attributes (directly given or + // implied), check if the function/method is const or the parent impl block is const. + if let Some(fn_sig) = fn_sig && !fn_sig.header.is_const() - && (!self.in_trait_impl || !self.tcx.is_const_fn_raw(def_id.to_def_id())) + // We have to exclude foreign items as they might be intrinsics. Sadly we can't check + // their ABI; `fn_sig.abi` is *not* correct for foreign functions. + && !is_foreign_item + && const_stab.is_some() + && (!self.in_trait_impl || !self.tcx.is_const_fn(def_id.to_def_id())) + { + self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span }); + } + + // If this is marked const *stable*, it must also be regular-stable. + if let Some((const_stab, const_span)) = const_stab + && let Some(fn_sig) = fn_sig + && const_stab.is_const_stable() + && !stab.is_some_and(|(s, _)| s.is_stable()) { self.tcx .dcx() - .emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span, const_span }); + .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span }); } + // Stable *language* features shouldn't be used as unstable library features. + // (Not doing this for stable library features is checked by tidy.) + if let Some(( + ConstStability { level: Unstable { .. }, feature: Some(feature), .. }, + const_span, + )) = const_stab + { + if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() { + self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { + span: const_span, + item_sp, + }); + } + } + + let const_stab = const_stab.map(|(const_stab, _span)| { + self.index.const_stab_map.insert(def_id, const_stab); + const_stab + }); + // `impl const Trait for Type` items forward their const stability to their // immediate children. + // FIXME(effects): how is this supposed to interact with `#[rustc_const_stable_indirect]`? + // Currently, once that is set, we do not inherit anything from the parent any more. if const_stab.is_none() { debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab); if let Some(parent) = self.parent_const_stab { @@ -247,8 +279,10 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } + // Stable *language* features shouldn't be used as unstable library features. + // (Not doing this for stable library features is checked by tidy.) if let Stability { level: Unstable { .. }, feature } = stab { - if ACCEPTED_FEATURES.iter().find(|f| f.name == feature).is_some() { + if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() { self.tcx .dcx() .emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp }); @@ -260,21 +294,13 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { self.index.implications.insert(implied_by, feature); } - if let Some(ConstStability { level: Unstable { .. }, feature, .. }) = const_stab { - if ACCEPTED_FEATURES.iter().find(|f| f.name == feature).is_some() { - self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { - span: const_span.unwrap(), // If const_stab contains Some(..), same is true for const_span - item_sp, - }); - } - } if let Some(ConstStability { level: Unstable { implied_by: Some(implied_by), .. }, feature, .. }) = const_stab { - self.index.implications.insert(implied_by, feature); + self.index.implications.insert(implied_by, feature.unwrap()); } self.index.stab_map.insert(def_id, stab); @@ -372,6 +398,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ctor_def_id, i.span, None, + /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -390,6 +417,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { i.owner_id.def_id, i.span, fn_sig, + /* is_foreign_item */ false, kind, InheritDeprecation::Yes, const_stab_inherit, @@ -409,6 +437,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ti.owner_id.def_id, ti.span, fn_sig, + /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -432,6 +461,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ii.owner_id.def_id, ii.span, fn_sig, + /* is_foreign_item */ false, kind, InheritDeprecation::Yes, InheritConstStability::No, @@ -447,6 +477,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { var.def_id, var.span, None, + /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -457,6 +488,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ctor_def_id, var.span, None, + /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -475,6 +507,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { s.def_id, s.span, None, + /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -486,10 +519,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { + let fn_sig = match &i.kind { + rustc_hir::ForeignItemKind::Fn(fn_sig, ..) => Some(fn_sig), + _ => None, + }; self.annotate( i.owner_id.def_id, i.span, - None, + fn_sig, + /* is_foreign_item */ true, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -512,6 +550,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { p.def_id, p.span, None, + /* is_foreign_item */ false, kind, InheritDeprecation::No, InheritConstStability::No, @@ -540,8 +579,10 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } } - fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) { - if !self.tcx.features().staged_api { + fn check_missing_or_wrong_const_stability(&self, def_id: LocalDefId, span: Span) { + // The visitor runs for "unstable-if-unmarked" crates, but we don't yet support + // that on the const side. + if !self.tcx.features().staged_api() { return; } @@ -554,10 +595,11 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } let is_const = self.tcx.is_const_fn(def_id.to_def_id()) - || self.tcx.is_const_trait_impl_raw(def_id.to_def_id()); + || self.tcx.is_const_trait_impl(def_id.to_def_id()); let is_stable = self.tcx.lookup_stability(def_id).is_some_and(|stability| stability.level.is_stable()); - let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none(); + let missing_const_stability_attribute = + self.tcx.lookup_const_stability(def_id).is_none_or(|s| s.feature.is_none()); if is_const && is_stable && missing_const_stability_attribute { let descr = self.tcx.def_descr(def_id.to_def_id()); @@ -587,7 +629,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } // Ensure stable `const fn` have a const stability attribute. - self.check_missing_const_stability(i.owner_id.def_id, i.span); + self.check_missing_or_wrong_const_stability(i.owner_id.def_id, i.span); intravisit::walk_item(self, i) } @@ -601,7 +643,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id()); if self.tcx.impl_trait_ref(impl_def_id).is_none() { self.check_missing_stability(ii.owner_id.def_id, ii.span); - self.check_missing_const_stability(ii.owner_id.def_id, ii.span); + self.check_missing_or_wrong_const_stability(ii.owner_id.def_id, ii.span); } intravisit::walk_impl_item(self, ii); } @@ -670,6 +712,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID), None, + /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -732,12 +775,23 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // For implementations of traits, check the stability of each item // individually as it's possible to have a stable trait with unstable // items. - hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => { + hir::ItemKind::Impl(hir::Impl { + constness, + of_trait: Some(ref t), + self_ty, + items, + .. + }) => { let features = self.tcx.features(); - if features.staged_api { + if features.staged_api() { let attrs = self.tcx.hir().attrs(item.hir_id()); let stab = attr::find_stability(self.tcx.sess, attrs, item.span); - let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item.span); + let const_stab = attr::find_const_stability( + self.tcx.sess, + attrs, + item.span, + matches!(constness, Constness::Const), + ); // If this impl block has an #[unstable] attribute, give an // error if all involved types and traits are stable, because @@ -762,8 +816,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable // needs to have an error emitted. - if features.const_trait_impl - && self.tcx.is_const_trait_impl_raw(item.owner_id.to_def_id()) + if features.const_trait_impl() + && self.tcx.is_const_trait_impl(item.owner_id.to_def_id()) && const_stab.is_some_and(|(stab, _)| stab.is_const_stable()) { self.tcx.dcx().emit_err(errors::TraitImplConstStable { span: item.span }); @@ -926,7 +980,7 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> { /// libraries, identify activated features that don't exist and error about them. pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let is_staged_api = - tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api; + tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api(); if is_staged_api { let effective_visibilities = &tcx.effective_visibilities(()); let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities }; @@ -935,33 +989,33 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { tcx.hir().visit_all_item_likes_in_crate(&mut missing); } - let declared_lang_features = &tcx.features().declared_lang_features; + let enabled_lang_features = tcx.features().enabled_lang_features(); let mut lang_features = UnordSet::default(); - for &(feature, span, since) in declared_lang_features { - if let Some(since) = since { + for EnabledLangFeature { gate_name, attr_sp, stable_since } in enabled_lang_features { + if let Some(version) = stable_since { // Warn if the user has enabled an already-stable lang feature. - unnecessary_stable_feature_lint(tcx, span, feature, since); + unnecessary_stable_feature_lint(tcx, *attr_sp, *gate_name, *version); } - if !lang_features.insert(feature) { + if !lang_features.insert(gate_name) { // Warn if the user enables a lang feature multiple times. - tcx.dcx().emit_err(errors::DuplicateFeatureErr { span, feature }); + tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name }); } } - let declared_lib_features = &tcx.features().declared_lib_features; + let enabled_lib_features = tcx.features().enabled_lib_features(); let mut remaining_lib_features = FxIndexMap::default(); - for (feature, span) in declared_lib_features { - if remaining_lib_features.contains_key(&feature) { + for EnabledLibFeature { gate_name, attr_sp } in enabled_lib_features { + if remaining_lib_features.contains_key(gate_name) { // Warn if the user enables a lib feature multiple times. - tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature }); + tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name }); } - remaining_lib_features.insert(feature, *span); + remaining_lib_features.insert(*gate_name, *attr_sp); } // `stdbuild` has special handling for `libc`, so we need to // recognise the feature when building std. // Likewise, libtest is handled specially, so `test` isn't // available as we'd like it to be. - // FIXME: only remove `libc` when `stdbuild` is active. + // FIXME: only remove `libc` when `stdbuild` is enabled. // FIXME: remove special casing for `test`. // FIXME(#120456) - is `swap_remove` correct? remaining_lib_features.swap_remove(&sym::libc); @@ -987,7 +1041,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { /// time, less loading from metadata is performed and thus compiler performance is improved. fn check_features<'tcx>( tcx: TyCtxt<'tcx>, - remaining_lib_features: &mut FxIndexMap<&Symbol, Span>, + remaining_lib_features: &mut FxIndexMap, remaining_implications: &mut UnordMap, defined_features: &LibFeatures, all_implications: &UnordMap, @@ -1021,7 +1075,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { // All local crate implications need to have the feature that implies it confirmed to exist. let mut remaining_implications = tcx.stability_implications(LOCAL_CRATE).clone(); - // We always collect the lib features declared in the current crate, even if there are + // We always collect the lib features enabled in the current crate, even if there are // no unknown features, because the collection also does feature attribute validation. let local_defined_features = tcx.lib_features(LOCAL_CRATE); if !remaining_lib_features.is_empty() || !remaining_implications.is_empty() { @@ -1057,7 +1111,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { } for (feature, span) in remaining_lib_features { - tcx.dcx().emit_err(errors::UnknownFeature { span, feature: *feature }); + tcx.dcx().emit_err(errors::UnknownFeature { span, feature }); } for (&implied_by, &feature) in remaining_implications.to_sorted_stable_ord() { diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 70a9319d666..0e132b27fb4 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -891,7 +891,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { print::write_slice_like(&mut s, &prefix, has_dot_dot, &suffix).unwrap(); s } - Never if self.tcx.features().never_patterns => "!".to_string(), + Never if self.tcx.features().never_patterns() => "!".to_string(), Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => "_".to_string(), Missing { .. } => bug!( "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug, @@ -915,7 +915,7 @@ fn would_print_as_wildcard(tcx: TyCtxt<'_>, p: &WitnessPat<'_, '_>) -> bool { | Constructor::NonExhaustive | Constructor::Hidden | Constructor::PrivateUninhabited => true, - Constructor::Never if !tcx.features().never_patterns => true, + Constructor::Never if !tcx.features().never_patterns() => true, _ => false, } } @@ -929,7 +929,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { type PatData = &'p Pat<'tcx>; fn is_exhaustive_patterns_feature_on(&self) -> bool { - self.tcx.features().exhaustive_patterns + self.tcx.features().exhaustive_patterns() } fn ctor_arity(&self, ctor: &crate::constructor::Constructor, ty: &Self::Ty) -> usize { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index f67c4cb922c..05954143aee 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -32,8 +32,8 @@ use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, use rustc_middle::query::Providers; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ - self, Const, GenericArgs, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitor, + self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitor, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -137,6 +137,10 @@ where ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => { self.visit_trait(trait_ref) } + ty::ClauseKind::HostEffect(pred) => { + try_visit!(self.visit_trait(pred.trait_ref)); + pred.host.visit_with(self) + } ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_term: projection_ty, term, @@ -246,10 +250,10 @@ where ty::ExistentialPredicate::Trait(trait_ref) => trait_ref, ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx), ty::ExistentialPredicate::AutoTrait(def_id) => { - ty::ExistentialTraitRef { def_id, args: GenericArgs::empty() } + ty::ExistentialTraitRef::new(tcx, def_id, ty::GenericArgs::empty()) } }; - let ty::ExistentialTraitRef { def_id, args: _ } = trait_ref; + let ty::ExistentialTraitRef { def_id, .. } = trait_ref; try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)); } } diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index 5e450979273..5a72e80a0a5 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -111,13 +111,25 @@ impl<'a> HashStable> for SourceFile { impl<'tcx> HashStable> for rustc_feature::Features { fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { // Unfortunately we cannot exhaustively list fields here, since the - // struct is macro generated. - self.declared_lang_features.hash_stable(hcx, hasher); - self.declared_lib_features.hash_stable(hcx, hasher); - - self.all_features()[..].hash_stable(hcx, hasher); - for feature in rustc_feature::UNSTABLE_FEATURES.iter() { - feature.feature.name.hash_stable(hcx, hasher); - } + // struct has private fields (to ensure its invariant is maintained) + self.enabled_lang_features().hash_stable(hcx, hasher); + self.enabled_lib_features().hash_stable(hcx, hasher); + } +} + +impl<'tcx> HashStable> for rustc_feature::EnabledLangFeature { + fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { + let rustc_feature::EnabledLangFeature { gate_name, attr_sp, stable_since } = self; + gate_name.hash_stable(hcx, hasher); + attr_sp.hash_stable(hcx, hasher); + stable_since.hash_stable(hcx, hasher); + } +} + +impl<'tcx> HashStable> for rustc_feature::EnabledLibFeature { + fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { + let rustc_feature::EnabledLibFeature { gate_name, attr_sp } = self; + gate_name.hash_stable(hcx, hasher); + attr_sp.hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 0ca6bb8c07d..bdf940a04b5 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -177,7 +177,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let loaded_macro = self.cstore().load_macro_untracked(def_id, self.tcx); let macro_data = match loaded_macro { - LoadedMacro::MacroDef(item, edition) => self.compile_macro(&item, edition), + LoadedMacro::MacroDef { def, ident, attrs, span, edition } => { + self.compile_macro(&def, ident, &attrs, span, ast::DUMMY_NODE_ID, edition) + } LoadedMacro::ProcMacro(ext) => MacroData::new(Lrc::new(ext)), }; @@ -1321,7 +1323,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // Visit attributes after items for backward compatibility. // This way they can use `macro_rules` defined later. self.visit_vis(&item.vis); - self.visit_ident(item.ident); + self.visit_ident(&item.ident); item.kind.walk(item, AssocCtxt::Trait, self); visit::walk_list!(self, visit_attribute, &item.attrs); } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 0047f2c4b51..a825458dc89 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -199,8 +199,10 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { }, ItemKind::Const(..) => DefKind::Const, ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn, - ItemKind::MacroDef(..) => { - let macro_data = self.resolver.compile_macro(i, self.resolver.tcx.sess.edition()); + ItemKind::MacroDef(def) => { + let edition = self.resolver.tcx.sess.edition(); + let macro_data = + self.resolver.compile_macro(def, i.ident, &i.attrs, i.span, i.id, edition); let macro_kind = macro_data.ext.macro_kind(); opt_macro_data = Some(macro_data); DefKind::Macro(macro_kind) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 8ae77902bce..b80e0e196ca 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -606,7 +606,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::BuiltinTypes => match this.builtin_types_bindings.get(&ident.name) { Some(binding) => { if matches!(ident.name, sym::f16) - && !this.tcx.features().f16 + && !this.tcx.features().f16() && !ident.span.allows_unstable(sym::f16) && finalize.is_some() && innermost_result.is_none() @@ -620,7 +620,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .emit(); } if matches!(ident.name, sym::f128) - && !this.tcx.features().f128 + && !this.tcx.features().f128() && !ident.span.allows_unstable(sym::f128) && finalize.is_some() && innermost_result.is_none() diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 98db36b12be..adb0ba7c820 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1205,7 +1205,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r } fn visit_assoc_item_constraint(&mut self, constraint: &'ast AssocItemConstraint) { - self.visit_ident(constraint.ident); + self.visit_ident(&constraint.ident); if let Some(ref gen_args) = constraint.gen_args { // Forbid anonymous lifetimes in GAT parameters until proper semantics are decided. self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { @@ -2683,7 +2683,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::Item( - if self.r.tcx.features().generic_const_items { + if self.r.tcx.features().generic_const_items() { HasGenericParams::Yes(generics.span) } else { HasGenericParams::No @@ -2888,7 +2888,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { RibKind::Normal => { // FIXME(non_lifetime_binders): Stop special-casing // const params to error out here. - if self.r.tcx.features().non_lifetime_binders + if self.r.tcx.features().non_lifetime_binders() && matches!(param.kind, GenericParamKind::Type { .. }) { Res::Def(def_kind, def_id.to_def_id()) @@ -4411,10 +4411,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let tcx = self.r.tcx(); let gate_err_sym_msg = match prim { - PrimTy::Float(FloatTy::F16) if !tcx.features().f16 => { + PrimTy::Float(FloatTy::F16) if !tcx.features().f16() => { Some((sym::f16, "the type `f16` is unstable")) } - PrimTy::Float(FloatTy::F128) if !tcx.features().f128 => { + PrimTy::Float(FloatTy::F128) if !tcx.features().f128() => { Some((sym::f128, "the type `f128` is unstable")) } _ => None, @@ -4565,7 +4565,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } AnonConstKind::InlineConst => ConstantHasGenerics::Yes, AnonConstKind::ConstArg(_) => { - if self.r.tcx.features().generic_const_exprs || is_trivial_const_arg { + if self.r.tcx.features().generic_const_exprs() || is_trivial_const_arg { ConstantHasGenerics::Yes } else { ConstantHasGenerics::No(NoConstantGenericsReason::NonTrivialConstArg) @@ -4582,7 +4582,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn resolve_expr_field(&mut self, f: &'ast ExprField, e: &'ast Expr) { self.resolve_expr(&f.expr, Some(e)); - self.visit_ident(f.ident); + self.visit_ident(&f.ident); walk_list!(self, visit_attribute, f.attrs.iter()); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 50fbdcaf9dc..f0632a21091 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1198,7 +1198,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the // benefits of including them here outweighs the small number of false positives. Some(Res::Def(DefKind::Struct | DefKind::Enum, _)) - if self.r.tcx.features().adt_const_params => + if self.r.tcx.features().adt_const_params() => { Applicability::MaybeIncorrect } @@ -2773,7 +2773,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // Avoid suggesting placing lifetime parameters on constant items unless the relevant // feature is enabled. Suggest the parent item as a possible location if applicable. if let LifetimeBinderKind::ConstItem = kind - && !self.r.tcx().features().generic_const_items + && !self.r.tcx().features().generic_const_items() { continue; } @@ -2934,7 +2934,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .emit(); } NoConstantGenericsReason::NonTrivialConstArg => { - assert!(!self.r.tcx.features().generic_const_exprs); + assert!(!self.r.tcx.features().generic_const_exprs()); self.r .dcx() .create_err(errors::ParamInNonTrivialAnonConst { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index e43c8718665..1dc27776cb0 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -661,7 +661,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // We are trying to avoid reporting this error if other related errors were reported. - if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes { + if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes() { let is_macro = match res { Res::Def(..) => true, Res::NonMacroAttr(..) => false, @@ -690,7 +690,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && namespace.ident.name == sym::diagnostic && !(attribute.ident.name == sym::on_unimplemented || (attribute.ident.name == sym::do_not_recommend - && self.tcx.features().do_not_recommend)) + && self.tcx.features().do_not_recommend())) { let distance = edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5); @@ -1007,10 +1007,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { { let feature = stability.feature; - let is_allowed = |feature| { - self.tcx.features().declared_features.contains(&feature) - || span.allows_unstable(feature) - }; + let is_allowed = + |feature| self.tcx.features().enabled(feature) || span.allows_unstable(feature); let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature)); if !is_allowed(feature) && !allowed_by_implication { let lint_buffer = &mut self.lint_buffer; @@ -1124,9 +1122,25 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Compile the macro into a `SyntaxExtension` and its rule spans. /// /// Possibly replace its expander to a pre-defined one for built-in macros. - pub(crate) fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> MacroData { - let (mut ext, mut rule_spans) = - compile_declarative_macro(self.tcx.sess, self.tcx.features(), item, edition); + pub(crate) fn compile_macro( + &mut self, + macro_def: &ast::MacroDef, + ident: Ident, + attrs: &[ast::Attribute], + span: Span, + node_id: NodeId, + edition: Edition, + ) -> MacroData { + let (mut ext, mut rule_spans) = compile_declarative_macro( + self.tcx.sess, + self.tcx.features(), + macro_def, + ident, + attrs, + span, + node_id, + edition, + ); if let Some(builtin_name) = ext.builtin_name { // The macro was marked with `#[rustc_builtin_macro]`. @@ -1134,28 +1148,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // The macro is a built-in, replace its expander function // while still taking everything else from the source code. // If we already loaded this builtin macro, give a better error message than 'no such builtin macro'. - match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) { + match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(span)) { BuiltinMacroState::NotYetSeen(builtin_ext) => { ext.kind = builtin_ext; rule_spans = Vec::new(); } - BuiltinMacroState::AlreadySeen(span) => { - self.dcx().emit_err(errors::AttemptToDefineBuiltinMacroTwice { - span: item.span, - note_span: span, - }); + BuiltinMacroState::AlreadySeen(note_span) => { + self.dcx() + .emit_err(errors::AttemptToDefineBuiltinMacroTwice { span, note_span }); } } } else { - self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { - span: item.span, - ident: item.ident, - }); + self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { span, ident }); } } - let ItemKind::MacroDef(def) = &item.kind else { unreachable!() }; - MacroData { ext: Lrc::new(ext), rule_spans, macro_rules: def.macro_rules } + MacroData { ext: Lrc::new(ext), rule_spans, macro_rules: macro_def.macro_rules } } fn path_accessible( 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 83dcceeaa84..cba79a02f8b 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 @@ -245,11 +245,15 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc alias_ty.to_ty(tcx), ); debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx)); - ty::ExistentialPredicate::Projection(ty::ExistentialProjection { - def_id: assoc_ty.def_id, - args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args, - term: resolved.into(), - }) + ty::ExistentialPredicate::Projection( + ty::ExistentialProjection::erase_self_ty( + tcx, + ty::ProjectionPredicate { + projection_term: alias_ty.into(), + term: resolved.into(), + }, + ), + ) }) }) }) @@ -318,10 +322,11 @@ pub(crate) fn transform_instance<'tcx>( .lang_items() .drop_trait() .unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item")); - let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { + let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new_from_args( + tcx, def_id, - args: List::empty(), - }); + ty::List::empty(), + )); let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]); let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn); instance.args = tcx.mk_args_trait(self_ty, List::empty()); diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 1816d1278fe..893c532f1fb 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -136,3 +136,6 @@ session_unsupported_crate_type_for_target = dropping unsupported crate type `{$crate_type}` for target `{$target_triple}` session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5 + +session_unsupported_regparm = `-Zregparm={$regparm}` is unsupported (valid values 0-3) +session_unsupported_regparm_arch = `-Zregparm=N` is only supported on x86 diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index dbb74d1e244..20e8fb38b88 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -485,6 +485,16 @@ pub(crate) struct FunctionReturnRequiresX86OrX8664; #[diag(session_function_return_thunk_extern_requires_non_large_code_model)] pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel; +#[derive(Diagnostic)] +#[diag(session_unsupported_regparm)] +pub(crate) struct UnsupportedRegparm { + pub(crate) regparm: u32, +} + +#[derive(Diagnostic)] +#[diag(session_unsupported_regparm_arch)] +pub(crate) struct UnsupportedRegparmArch; + #[derive(Diagnostic)] #[diag(session_failed_to_create_profiler)] pub(crate) struct FailedToCreateProfiler { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f9964b59a94..54a4621db24 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2000,6 +2000,11 @@ options! { "enable queries of the dependency graph for regression testing (default: no)"), randomize_layout: bool = (false, parse_bool, [TRACKED], "randomize the layout of types (default: no)"), + regparm: Option = (None, parse_opt_number, [TRACKED], + "On x86-32 targets, setting this to N causes the compiler to pass N arguments \ + in registers EAX, EDX, and ECX instead of on the stack for\ + \"C\", \"cdecl\", and \"stdcall\" fn.\ + It is UNSOUND to link together crates that use different values for this flag!"), relax_elf_relocations: Option = (None, parse_opt_bool, [TRACKED], "whether ELF relocations can be relaxed"), remap_cwd_prefix: Option = (None, parse_opt_pathbuf, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 27879d817b2..1963cf4eb7c 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1337,6 +1337,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } + if let Some(regparm) = sess.opts.unstable_opts.regparm { + if regparm > 3 { + sess.dcx().emit_err(errors::UnsupportedRegparm { regparm }); + } + if sess.target.arch != "x86" { + sess.dcx().emit_err(errors::UnsupportedRegparmArch); + } + } + // The code model check applies to `thunk` and `thunk-extern`, but not `thunk-inline`, so it is // kept as a `match` to force a change if new ones are added, even if we currently only support // `thunk-extern` like Clang. diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index e9c3b3ffc1d..7be7db1fd3d 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -380,11 +380,12 @@ impl RustcInternal for ExistentialProjection { type T<'tcx> = rustc_ty::ExistentialProjection<'tcx>; fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { - rustc_ty::ExistentialProjection { - def_id: self.def_id.0.internal(tables, tcx), - args: self.generic_args.internal(tables, tcx), - term: self.term.internal(tables, tcx), - } + rustc_ty::ExistentialProjection::new_from_args( + tcx, + self.def_id.0.internal(tables, tcx), + self.generic_args.internal(tables, tcx), + self.term.internal(tables, tcx), + ) } } @@ -403,10 +404,11 @@ impl RustcInternal for ExistentialTraitRef { type T<'tcx> = rustc_ty::ExistentialTraitRef<'tcx>; fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { - rustc_ty::ExistentialTraitRef { - def_id: self.def_id.0.internal(tables, tcx), - args: self.generic_args.internal(tables, tcx), - } + rustc_ty::ExistentialTraitRef::new_from_args( + tcx, + self.def_id.0.internal(tables, tcx), + self.generic_args.internal(tables, tcx), + ) } } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 8fa8f2ac402..9514ec883ae 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -161,8 +161,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; - let GenericPredicates { parent, predicates, effects_min_tys: _ } = - tables.tcx.predicates_of(def_id); + let GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id); stable_mir::ty::GenericPredicates { parent: parent.map(|did| tables.trait_def(did)), predicates: predicates @@ -183,8 +182,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { ) -> stable_mir::ty::GenericPredicates { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; - let GenericPredicates { parent, predicates, effects_min_tys: _ } = - tables.tcx.explicit_predicates_of(def_id); + let GenericPredicates { parent, predicates } = tables.tcx.explicit_predicates_of(def_id); stable_mir::ty::GenericPredicates { parent: parent.map(|did| tables.trait_def(did)), predicates: predicates diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 06f01aebf9b..dbfcde56f6e 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -50,7 +50,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::Layout<'tcx> { } impl<'tcx> Stable<'tcx> - for rustc_abi::LayoutS + for rustc_abi::LayoutData { type T = LayoutShape; diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index b9372283feb..8f05f859c07 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -68,7 +68,7 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialTraitRef<'tcx> { type T = stable_mir::ty::ExistentialTraitRef; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { - let ty::ExistentialTraitRef { def_id, args } = self; + let ty::ExistentialTraitRef { def_id, args, .. } = self; stable_mir::ty::ExistentialTraitRef { def_id: tables.trait_def(*def_id), generic_args: args.stable(tables), @@ -95,7 +95,7 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialProjection<'tcx> { type T = stable_mir::ty::ExistentialProjection; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { - let ty::ExistentialProjection { def_id, args, term } = self; + let ty::ExistentialProjection { def_id, args, term, .. } = self; stable_mir::ty::ExistentialProjection { def_id: tables.trait_def(*def_id), generic_args: args.stable(tables), @@ -588,7 +588,6 @@ impl<'tcx> Stable<'tcx> for ty::Generics { .has_late_bound_regions .as_ref() .map(|late_bound_regions| late_bound_regions.stable(tables)), - host_effect_index: self.host_effect_index, } } } @@ -603,7 +602,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind { ty::GenericParamDefKind::Type { has_default, synthetic } => { GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic } } - ty::GenericParamDefKind::Const { has_default, is_host_effect: _, synthetic: _ } => { + ty::GenericParamDefKind::Const { has_default, synthetic: _ } => { GenericParamDefKind::Const { has_default: *has_default } } } @@ -690,6 +689,9 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> { ClauseKind::ConstEvaluatable(const_) => { stable_mir::ty::ClauseKind::ConstEvaluatable(const_.stable(tables)) } + ClauseKind::HostEffect(..) => { + todo!() + } } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3ab482072b8..890c4fdafef 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -171,9 +171,11 @@ symbols! { CallOnceFuture, CallRefFuture, Capture, + Cell, Center, Cleanup, Clone, + CoercePointee, CoerceUnsized, Command, ConstParamTy, @@ -195,14 +197,6 @@ symbols! { Display, DoubleEndedIterator, Duration, - EffectsCompat, - EffectsIntersection, - EffectsIntersectionOutput, - EffectsMaybe, - EffectsNoRuntime, - EffectsRuntime, - EffectsTyCompat, - Effects__, Encodable, Encoder, Enumerate, @@ -315,7 +309,6 @@ symbols! { Sized, SliceIndex, SliceIter, - SmartPointer, Some, SpanCtxt, String, @@ -417,6 +410,7 @@ symbols! { arm, arm_target_feature, array, + as_mut_ptr, as_ptr, as_ref, as_str, @@ -740,6 +734,7 @@ symbols! { deref_pure, deref_target, derive, + derive_coerce_pointee, derive_const, derive_default_enum, derive_smart_pointer, @@ -1133,6 +1128,7 @@ symbols! { lazy_normalization_consts, lazy_type_alias, le, + legacy_receiver, len, let_chains, let_else, @@ -1573,7 +1569,6 @@ symbols! { readonly, realloc, reason, - receiver, recursion_limit, reexport_test_harness_main, ref_pat_eat_one_layer_2024, @@ -1668,6 +1663,7 @@ symbols! { rustc_confusables, rustc_const_panic_str, rustc_const_stable, + rustc_const_stable_indirect, rustc_const_unstable, rustc_conversion_suggestion, rustc_deallocator, @@ -1737,7 +1733,6 @@ symbols! { rustc_reallocator, rustc_regions, rustc_reservation_impl, - rustc_runtime, rustc_safe_intrinsic, rustc_serialize, rustc_skip_during_method_dispatch, diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 78e6b9ec6e8..5c5ab435dbd 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -135,7 +135,7 @@ fn symbol_name_provider<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty // This closure determines the instantiating crate for instances that // need an instantiating-crate-suffix for their symbol name, in order // to differentiate between local copies. - if is_generic(instance, tcx) { + if is_generic(instance) { // For generics we might find re-usable upstream instances. If there // is one, we rely on the symbol being instantiated locally. instance.upstream_monomorphization(tcx).unwrap_or(LOCAL_CRATE) @@ -241,7 +241,7 @@ fn compute_symbol_name<'tcx>( // the ID of the instantiating crate. This avoids symbol conflicts // in case the same instances is emitted in two crates of the same // project. - let avoid_cross_crate_conflicts = is_generic(instance, tcx) || is_globally_shared_function; + let avoid_cross_crate_conflicts = is_generic(instance) || is_globally_shared_function; let instantiating_crate = avoid_cross_crate_conflicts.then(compute_instantiating_crate); @@ -276,6 +276,6 @@ fn compute_symbol_name<'tcx>( symbol } -fn is_generic<'tcx>(instance: Instance<'tcx>, tcx: TyCtxt<'tcx>) -> bool { - instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some() +fn is_generic<'tcx>(instance: Instance<'tcx>) -> bool { + instance.args.non_erasable_generics().next().is_some() } diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index 8cfb65c1c50..73bd8d7555b 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -18,7 +18,7 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. - if !tcx.features().rustc_attrs { + if !tcx.features().rustc_attrs() { return; } diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index 4a21935623b..ffec76370d0 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -1,6 +1,7 @@ use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; use crate::spec::HasTargetSpec; +use crate::spec::abi::Abi as SpecAbi; #[derive(Copy, Clone)] enum RegPassKind { @@ -359,3 +360,30 @@ where ); } } + +pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi) +where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + if abi == SpecAbi::RustIntrinsic { + return; + } + + let grlen = cx.data_layout().pointer_size.bits(); + + for arg in fn_abi.args.iter_mut() { + if arg.is_ignore() { + continue; + } + + // LLVM integers types do not differentiate between signed or unsigned integers. + // Some LoongArch instructions do not have a `.w` suffix version, they use all the + // GRLEN bits. By explicitly setting the `signext` or `zeroext` attribute + // according to signedness to avoid unnecessary integer extending instructions. + // + // This is similar to the RISC-V case, see + // https://github.com/rust-lang/rust/issues/114508 for details. + extend_integer_width(arg, grlen); + } +} diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 832246495bc..25b001b57e8 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -1,12 +1,15 @@ -use std::fmt; use std::str::FromStr; +use std::{fmt, iter}; pub use rustc_abi::{Reg, RegKind}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; -use crate::abi::{self, Abi, Align, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; -use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi}; +use crate::abi::{ + self, Abi, AddressSpace, Align, HasDataLayout, Pointer, Size, TyAbiInterface, TyAndLayout, +}; +use crate::spec::abi::Abi as SpecAbi; +use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi}; mod aarch64; mod amdgpu; @@ -631,7 +634,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { ) -> Result<(), AdjustForForeignAbiError> where Ty: TyAbiInterface<'a, C> + Copy, - C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt, + C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt + HasX86AbiOpt, { if abi == spec::abi::Abi::X86Interrupt { if let Some(arg) = self.args.first_mut() { @@ -643,14 +646,18 @@ impl<'a, Ty> FnAbi<'a, Ty> { let spec = cx.target_spec(); match &spec.arch[..] { "x86" => { - let flavor = if let spec::abi::Abi::Fastcall { .. } - | spec::abi::Abi::Vectorcall { .. } = abi - { - x86::Flavor::FastcallOrVectorcall - } else { - x86::Flavor::General + let (flavor, regparm) = match abi { + spec::abi::Abi::Fastcall { .. } | spec::abi::Abi::Vectorcall { .. } => { + (x86::Flavor::FastcallOrVectorcall, None) + } + spec::abi::Abi::C { .. } + | spec::abi::Abi::Cdecl { .. } + | spec::abi::Abi::Stdcall { .. } => { + (x86::Flavor::General, cx.x86_abi_opt().regparm) + } + _ => (x86::Flavor::General, None), }; - x86::compute_abi_info(cx, self, flavor); + x86::compute_abi_info(cx, self, x86::X86Options { flavor, regparm }); } "x86_64" => match abi { spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self), @@ -716,6 +723,118 @@ impl<'a, Ty> FnAbi<'a, Ty> { Ok(()) } + + pub fn adjust_for_rust_abi(&mut self, cx: &C, abi: SpecAbi) + where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, + { + let spec = cx.target_spec(); + match &spec.arch[..] { + "x86" => x86::compute_rust_abi_info(cx, self, abi), + "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self, abi), + "loongarch64" => loongarch::compute_rust_abi_info(cx, self, abi), + _ => {} + }; + + for (arg_idx, arg) in self + .args + .iter_mut() + .enumerate() + .map(|(idx, arg)| (Some(idx), arg)) + .chain(iter::once((None, &mut self.ret))) + { + if arg.is_ignore() { + continue; + } + + if arg_idx.is_none() && arg.layout.size > Pointer(AddressSpace::DATA).size(cx) * 2 { + // Return values larger than 2 registers using a return area + // pointer. LLVM and Cranelift disagree about how to return + // values that don't fit in the registers designated for return + // values. LLVM will force the entire return value to be passed + // by return area pointer, while Cranelift will look at each IR level + // return value independently and decide to pass it in a + // register or not, which would result in the return value + // being passed partially in registers and partially through a + // return area pointer. + // + // While Cranelift may need to be fixed as the LLVM behavior is + // generally more correct with respect to the surface language, + // forcing this behavior in rustc itself makes it easier for + // other backends to conform to the Rust ABI and for the C ABI + // rustc already handles this behavior anyway. + // + // In addition LLVM's decision to pass the return value in + // registers or using a return area pointer depends on how + // exactly the return type is lowered to an LLVM IR type. For + // example `Option` can be lowered as `{ i128, i128 }` + // in which case the x86_64 backend would use a return area + // pointer, or it could be passed as `{ i32, i128 }` in which + // case the x86_64 backend would pass it in registers by taking + // advantage of an LLVM ABI extension that allows using 3 + // registers for the x86_64 sysv call conv rather than the + // officially specified 2 registers. + // + // FIXME: Technically we should look at the amount of available + // return registers rather than guessing that there are 2 + // registers for return values. In practice only a couple of + // architectures have less than 2 return registers. None of + // which supported by Cranelift. + // + // NOTE: This adjustment is only necessary for the Rust ABI as + // for other ABI's the calling convention implementations in + // rustc_target already ensure any return value which doesn't + // fit in the available amount of return registers is passed in + // the right way for the current target. + arg.make_indirect(); + continue; + } + + match arg.layout.abi { + Abi::Aggregate { .. } => {} + + // This is a fun case! The gist of what this is doing is + // that we want callers and callees to always agree on the + // ABI of how they pass SIMD arguments. If we were to *not* + // make these arguments indirect then they'd be immediates + // in LLVM, which means that they'd used whatever the + // appropriate ABI is for the callee and the caller. That + // means, for example, if the caller doesn't have AVX + // enabled but the callee does, then passing an AVX argument + // across this boundary would cause corrupt data to show up. + // + // This problem is fixed by unconditionally passing SIMD + // arguments through memory between callers and callees + // which should get them all to agree on ABI regardless of + // target feature sets. Some more information about this + // issue can be found in #44367. + // + // Note that the intrinsic ABI is exempt here as + // that's how we connect up to LLVM and it's unstable + // anyway, we control all calls to it in libstd. + Abi::Vector { .. } if abi != SpecAbi::RustIntrinsic && spec.simd_types_indirect => { + arg.make_indirect(); + continue; + } + + _ => continue, + } + // Compute `Aggregate` ABI. + + let is_indirect_not_on_stack = + matches!(arg.mode, PassMode::Indirect { on_stack: false, .. }); + assert!(is_indirect_not_on_stack); + + let size = arg.layout.size; + if !arg.layout.is_unsized() && size <= Pointer(AddressSpace::DATA).size(cx) { + // We want to pass small aggregates as immediates, but using + // an LLVM aggregate type for this leads to bad optimizations, + // so we pick an appropriately sized integer type instead. + arg.cast_to(Reg { kind: RegKind::Integer, size }); + } + } + } } impl FromStr for Conv { diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index be6bc701b49..f96169e6a61 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -7,6 +7,7 @@ use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; use crate::spec::HasTargetSpec; +use crate::spec::abi::Abi as SpecAbi; #[derive(Copy, Clone)] enum RegPassKind { @@ -365,3 +366,29 @@ where ); } } + +pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi) +where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + if abi == SpecAbi::RustIntrinsic { + return; + } + + let xlen = cx.data_layout().pointer_size.bits(); + + for arg in fn_abi.args.iter_mut() { + if arg.is_ignore() { + continue; + } + + // LLVM integers types do not differentiate between signed or unsigned integers. + // Some RISC-V instructions do not have a `.w` suffix version, they use all the + // XLEN bits. By explicitly setting the `signext` or `zeroext` attribute + // according to signedness to avoid unnecessary integer extending instructions. + // + // See https://github.com/rust-lang/rust/issues/114508 for details. + extend_integer_width(arg, xlen); + } +} diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index d9af83d3205..e907beecb38 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -1,6 +1,9 @@ use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind}; -use crate::abi::{Abi, Align, HasDataLayout, TyAbiInterface, TyAndLayout}; +use crate::abi::{ + Abi, AddressSpace, Align, Float, HasDataLayout, Pointer, TyAbiInterface, TyAndLayout, +}; use crate::spec::HasTargetSpec; +use crate::spec::abi::Abi as SpecAbi; #[derive(PartialEq)] pub(crate) enum Flavor { @@ -8,7 +11,12 @@ pub(crate) enum Flavor { FastcallOrVectorcall, } -pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor) +pub(crate) struct X86Options { + pub flavor: Flavor, + pub regparm: Option, +} + +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, @@ -128,58 +136,109 @@ where } } - if flavor == Flavor::FastcallOrVectorcall { - // Mark arguments as InReg like clang does it, - // so our fastcall/vectorcall is compatible with C/C++ fastcall/vectorcall. + fill_inregs(cx, fn_abi, opts, false); +} - // Clang reference: lib/CodeGen/TargetInfo.cpp - // See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs() +pub(crate) fn fill_inregs<'a, Ty, C>( + cx: &C, + fn_abi: &mut FnAbi<'a, Ty>, + opts: X86Options, + rust_abi: bool, +) where + Ty: TyAbiInterface<'a, C> + Copy, +{ + if opts.flavor != Flavor::FastcallOrVectorcall && opts.regparm.is_none_or(|x| x == 0) { + return; + } + // Mark arguments as InReg like clang does it, + // so our fastcall/vectorcall is compatible with C/C++ fastcall/vectorcall. - // IsSoftFloatABI is only set to true on ARM platforms, - // which in turn can't be x86? + // Clang reference: lib/CodeGen/TargetInfo.cpp + // See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs() - let mut free_regs = 2; + // IsSoftFloatABI is only set to true on ARM platforms, + // which in turn can't be x86? - for arg in fn_abi.args.iter_mut() { - let attrs = match arg.mode { - PassMode::Ignore - | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { - continue; - } - PassMode::Direct(ref mut attrs) => attrs, - PassMode::Pair(..) - | PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } - | PassMode::Cast { .. } => { - unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode) - } - }; + // 2 for fastcall/vectorcall, regparm limited by 3 otherwise + let mut free_regs = opts.regparm.unwrap_or(2).into(); - // At this point we know this must be a primitive of sorts. - let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap(); - assert_eq!(unit.size, arg.layout.size); - if unit.kind == RegKind::Float { + // For types generating PassMode::Cast, InRegs will not be set. + // Maybe, this is a FIXME + let has_casts = fn_abi.args.iter().any(|arg| matches!(arg.mode, PassMode::Cast { .. })); + if has_casts && rust_abi { + return; + } + + for arg in fn_abi.args.iter_mut() { + let attrs = match arg.mode { + PassMode::Ignore | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { continue; } - - let size_in_regs = (arg.layout.size.bits() + 31) / 32; - - if size_in_regs == 0 { - continue; + PassMode::Direct(ref mut attrs) => attrs, + PassMode::Pair(..) + | PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } + | PassMode::Cast { .. } => { + unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode) } + }; - if size_in_regs > free_regs { - break; - } + // At this point we know this must be a primitive of sorts. + let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap(); + assert_eq!(unit.size, arg.layout.size); + if matches!(unit.kind, RegKind::Float | RegKind::Vector) { + continue; + } - free_regs -= size_in_regs; + let size_in_regs = (arg.layout.size.bits() + 31) / 32; - if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer { - attrs.set(ArgAttribute::InReg); - } + if size_in_regs == 0 { + continue; + } - if free_regs == 0 { - break; - } + if size_in_regs > free_regs { + break; + } + + free_regs -= size_in_regs; + + if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer { + attrs.set(ArgAttribute::InReg); + } + + if free_regs == 0 { + break; + } + } +} + +pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi) +where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + // Avoid returning floats in x87 registers on x86 as loading and storing from x87 + // registers will quiet signalling NaNs. Also avoid using SSE registers since they + // are not always available (depending on target features). + if !fn_abi.ret.is_ignore() + // Intrinsics themselves are not actual "real" functions, so theres no need to change their ABIs. + && abi != SpecAbi::RustIntrinsic + { + let has_float = match fn_abi.ret.layout.abi { + Abi::Scalar(s) => matches!(s.primitive(), Float(_)), + Abi::ScalarPair(s1, s2) => { + matches!(s1.primitive(), Float(_)) || matches!(s2.primitive(), Float(_)) + } + _ => false, // anyway not passed via registers on x86 + }; + if has_float { + if fn_abi.ret.layout.size <= Pointer(AddressSpace::DATA).size(cx) { + // Same size or smaller than pointer, return in a register. + fn_abi.ret.cast_to(Reg { kind: RegKind::Integer, size: fn_abi.ret.layout.size }); + } else { + // Larger than a pointer, return indirectly. + fn_abi.ret.make_indirect(); + } + return; } } } diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_target/src/spec/abi/mod.rs index cac0cf9959d..c2095155afa 100644 --- a/compiler/rustc_target/src/spec/abi/mod.rs +++ b/compiler/rustc_target/src/spec/abi/mod.rs @@ -184,7 +184,7 @@ pub fn is_enabled( ) -> Result<(), AbiDisabled> { let s = is_stable(name); if let Err(AbiDisabled::Unstable { feature, .. }) = s { - if features.active(feature) || span.allows_unstable(feature) { + if features.enabled(feature) || span.allows_unstable(feature) { return Ok(()); } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 24f5646a9ea..f4cbe47e0f3 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1803,6 +1803,7 @@ supported_targets! { ("wasm32-unknown-emscripten", wasm32_unknown_emscripten), ("wasm32-unknown-unknown", wasm32_unknown_unknown), + ("wasm32v1-none", wasm32v1_none), ("wasm32-wasi", wasm32_wasi), ("wasm32-wasip1", wasm32_wasip1), ("wasm32-wasip2", wasm32_wasip2), @@ -2096,6 +2097,18 @@ pub trait HasWasmCAbiOpt { fn wasm_c_abi_opt(&self) -> WasmCAbi; } +/// x86 (32-bit) abi options. +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct X86Abi { + /// On x86-32 targets, the regparm N causes the compiler to pass arguments + /// in registers EAX, EDX, and ECX instead of on the stack. + pub regparm: Option, +} + +pub trait HasX86AbiOpt { + fn x86_abi_opt(&self) -> X86Abi; +} + type StaticCow = Cow<'static, T>; /// Optional aspects of a target specification. diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs index 2519b935c03..7648f81fd4d 100644 --- a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs +++ b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs @@ -21,6 +21,7 @@ pub(crate) fn target() -> Target { "-Vgcc_ntox86_cxx", ]), env: "nto70".into(), + vendor: "pc".into(), stack_probes: StackProbeType::Inline, ..base::nto_qnx::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs index 68d51193564..603c0f99314 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { code_model: Some(CodeModel::Medium), cpu: "generic".into(), - features: "+f,+d".into(), + features: "+f,+d,+lsx".into(), llvm_abiname: "lp64d".into(), max_atomic_width: Some(64), supported_sanitizers: SanitizerSet::ADDRESS diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs index 25d3559d920..d7044dde0f1 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { code_model: Some(CodeModel::Medium), cpu: "generic".into(), - features: "+f,+d".into(), + features: "+f,+d,+lsx".into(), llvm_abiname: "lp64d".into(), max_atomic_width: Some(64), crt_static_default: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs index 1995de9dd2d..0e0e13fd1d8 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs @@ -20,6 +20,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(32), atomic_cas: false, features: "+forced-atomics".into(), + llvm_abiname: "ilp32".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs index bd37cf80b48..669c1702fda 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs @@ -29,6 +29,7 @@ pub(crate) fn target() -> Target { atomic_cas: true, features: "+m".into(), + llvm_abiname: "ilp32".into(), executables: true, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs index 32df30ddb5e..477a6c0e9eb 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs @@ -20,6 +20,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(32), atomic_cas: false, features: "+m,+forced-atomics".into(), + llvm_abiname: "ilp32".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs index 61c887031bc..68146788d20 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs @@ -19,6 +19,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv32".into(), max_atomic_width: Some(32), features: "+m,+a".into(), + llvm_abiname: "ilp32".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs index 9795af56569..e12c3af6f8f 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs @@ -27,6 +27,7 @@ pub(crate) fn target() -> Target { atomic_cas: true, features: "+m,+a,+c".into(), + llvm_abiname: "ilp32".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs index cc28198e3ff..adc76f3cdb5 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs @@ -19,6 +19,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv32".into(), max_atomic_width: Some(32), features: "+m,+a,+c".into(), + llvm_abiname: "ilp32".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs index 62397dcae9a..31c9180c509 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs @@ -21,6 +21,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv32".into(), max_atomic_width: Some(32), features: "+m,+a,+c".into(), + llvm_abiname: "ilp32".into(), panic_strategy: PanicStrategy::Unwind, relocation_model: RelocModel::Static, ..Default::default() diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs index 0eaabc60cbc..88d112a012d 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs @@ -20,6 +20,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv32".into(), max_atomic_width: Some(32), features: "+m,+a,+c".into(), + llvm_abiname: "ilp32".into(), panic_strategy: PanicStrategy::Unwind, relocation_model: RelocModel::Static, ..Default::default() diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs index 9ae84ace457..cec97f86538 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs @@ -30,6 +30,7 @@ pub(crate) fn target() -> Target { atomic_cas: true, features: "+m,+c".into(), + llvm_abiname: "ilp32".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs index 0ae49debc3a..0e00fc69b41 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs @@ -20,6 +20,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(32), atomic_cas: false, features: "+m,+c,+forced-atomics".into(), + llvm_abiname: "ilp32".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs index 5f3917edf70..e86549806dd 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs @@ -21,6 +21,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv32".into(), max_atomic_width: Some(32), features: "+m,+c".into(), + llvm_abiname: "ilp32".into(), panic_strategy: PanicStrategy::Unwind, relocation_model: RelocModel::Static, ..Default::default() diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs index d514f8efcd0..d62ecc07a5d 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs @@ -22,6 +22,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv64".into(), max_atomic_width: Some(64), features: "+m,+a,+c".into(), + llvm_abiname: "lp64".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, code_model: Some(CodeModel::Medium), diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs index a737e46de1b..9c181665581 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs @@ -24,6 +24,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv64".into(), max_atomic_width: Some(64), features: "+m,+a,+c".into(), + llvm_abiname: "lp64".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, code_model: Some(CodeModel::Medium), diff --git a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs new file mode 100644 index 00000000000..bf35ae009c6 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs @@ -0,0 +1,51 @@ +//! A "bare wasm" target representing a WebAssembly output that does not import +//! anything from its environment and also specifies an _upper_ bound on the set +//! of WebAssembly proposals that are supported. +//! +//! It's equivalent to the `wasm32-unknown-unknown` target with the additional +//! flags `-Ctarget-cpu=mvp` and `-Ctarget-feature=+mutable-globals`. This +//! enables just the features specified in +//! +//! This is a _separate target_ because using `wasm32-unknown-unknown` with +//! those target flags doesn't automatically rebuild libcore / liballoc with +//! them, and in order to get those libraries rebuilt you need to use the +//! nightly Rust feature `-Zbuild-std`. This target is for people who want to +//! use stable Rust, and target a stable set pf WebAssembly features. + +use crate::spec::{Cc, LinkerFlavor, Target, base}; + +pub(crate) fn target() -> Target { + let mut options = base::wasm::options(); + options.os = "none".into(); + + // WebAssembly 1.0 shipped in 2019 and included exactly one proposal + // after the initial "MVP" feature set: "mutable-globals". + options.cpu = "mvp".into(); + options.features = "+mutable-globals".into(); + + options.add_pre_link_args(LinkerFlavor::WasmLld(Cc::No), &[ + // For now this target just never has an entry symbol no matter the output + // type, so unconditionally pass this. + "--no-entry", + ]); + options.add_pre_link_args(LinkerFlavor::WasmLld(Cc::Yes), &[ + // Make sure clang uses LLD as its linker and is configured appropriately + // otherwise + "--target=wasm32-unknown-unknown", + "-Wl,--no-entry", + ]); + + Target { + llvm_target: "wasm32-unknown-unknown".into(), + metadata: crate::spec::TargetMetadata { + description: Some("WebAssembly".into()), + tier: Some(2), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), + arch: "wasm32".into(), + options, + } +} diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs index 1aa82494a49..245a5f06765 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs @@ -21,6 +21,7 @@ pub(crate) fn target() -> Target { "-Vgcc_ntox86_64_cxx", ]), env: "nto71".into(), + vendor: "pc".into(), ..base::nto_qnx::opts() }, } diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs index fc5bd846e02..cc5931be860 100644 --- a/compiler/rustc_target/src/spec/tests/tests_impl.rs +++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs @@ -121,7 +121,13 @@ impl Target { // Check dynamic linking stuff // BPF: when targeting user space vms (like rbpf), those can load dynamic libraries. // hexagon: when targeting QuRT, that OS can load dynamic libraries. - if self.os == "none" && (self.arch != "bpf" && self.arch != "hexagon") { + // wasm{32,64}: dynamic linking is inherent in the definition of the VM. + if self.os == "none" + && (self.arch != "bpf" + && self.arch != "hexagon" + && self.arch != "wasm32" + && self.arch != "wasm64") + { assert!(!self.dynamic_linking); } if self.only_cdylib @@ -152,6 +158,17 @@ impl Target { if self.crt_static_default || self.crt_static_allows_dylibs { assert!(self.crt_static_respected); } + + // Check that RISC-V targets always specify which ABI they use. + match &*self.arch { + "riscv32" => { + assert_matches!(&*self.llvm_abiname, "ilp32" | "ilp32f" | "ilp32d" | "ilp32e") + } + "riscv64" => { + assert_matches!(&*self.llvm_abiname, "lp64" | "lp64f" | "lp64d" | "lp64q") + } + _ => {} + } } // Add your target to the whitelist if it has `std` library diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index e92366d5c5c..3df8f0590a3 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -167,6 +167,8 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("pacg", Stable, &[]), // FEAT_PAN ("pan", Stable, &[]), + // FEAT_PAuth_LR + ("pauth-lr", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_PMUv3 ("pmuv3", Stable, &[]), // FEAT_RNG @@ -316,7 +318,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]), ("lzcnt", Stable, &[]), ("movbe", Stable, &[]), - ("pclmulqdq", Stable, &[]), + ("pclmulqdq", Stable, &["sse2"]), ("popcnt", Stable, &[]), ("prfchw", Unstable(sym::prfchw_target_feature), &[]), ("rdrand", Stable, &[]), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index df5800ab58a..574cf1e88b1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -75,6 +75,7 @@ use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags}; use crate::infer; use crate::infer::relate::{self, RelateResult, TypeRelation}; use crate::infer::{InferCtxt, TypeTrace, ValuePairs}; +use crate::solve::deeply_normalize_for_diagnostics; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, }; @@ -145,21 +146,31 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub fn report_mismatched_types( &self, cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, err: TypeError<'tcx>, ) -> Diag<'a> { - self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err) + self.report_and_explain_type_error( + TypeTrace::types(cause, true, expected, actual), + param_env, + err, + ) } pub fn report_mismatched_consts( &self, cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, expected: ty::Const<'tcx>, actual: ty::Const<'tcx>, err: TypeError<'tcx>, ) -> Diag<'a> { - self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err) + self.report_and_explain_type_error( + TypeTrace::consts(cause, true, expected, actual), + param_env, + err, + ) } pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option> { @@ -381,7 +392,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Some(ty) if expected == ty => { let source_map = self.tcx.sess.source_map(); err.span_suggestion( - source_map.end_point(cause.span()), + source_map.end_point(cause.span), "try removing this `?`", "", Applicability::MachineApplicable, @@ -401,6 +412,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { source, ref prior_non_diverging_arms, scrut_span, + expr_span, .. }) => match source { hir::MatchSource::TryDesugar(scrut_hir_id) => { @@ -419,7 +431,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Some(ty) if expected == ty => { let source_map = self.tcx.sess.source_map(); err.span_suggestion( - source_map.end_point(cause.span()), + source_map.end_point(cause.span), "try removing this `?`", "", Applicability::MachineApplicable, @@ -449,12 +461,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { format!("this and all prior arms are found to be of type `{t}`"), ); } - let outer = if any_multiline_arm || !source_map.is_multiline(cause.span) { + let outer = if any_multiline_arm || !source_map.is_multiline(expr_span) { // Cover just `match` and the scrutinee expression, not // the entire match body, to reduce diagram noise. - cause.span.shrink_to_lo().to(scrut_span) + expr_span.shrink_to_lo().to(scrut_span) } else { - cause.span + expr_span }; let msg = "`match` arms have incompatible types"; err.span_label(outer, msg); @@ -1133,11 +1145,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { diag: &mut Diag<'_>, cause: &ObligationCause<'tcx>, secondary_span: Option<(Span, Cow<'static, str>, bool)>, - mut values: Option>, + mut values: Option>>, terr: TypeError<'tcx>, prefer_label: bool, ) { - let span = cause.span(); + let span = cause.span; // For some types of errors, expected-found does not make // sense, so just ignore the values we were given. @@ -1241,8 +1253,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let (expected_found, exp_found, is_simple_error, values) = match values { None => (None, Mismatch::Fixed("type"), false, None), - Some(values) => { - let values = self.resolve_vars_if_possible(values); + Some(ty::ParamEnvAnd { param_env, value: values }) => { + let mut values = self.resolve_vars_if_possible(values); + if self.next_trait_solver() { + values = deeply_normalize_for_diagnostics(self, param_env, values); + } let (is_simple_error, exp_found) = match values { ValuePairs::Terms(ExpectedFound { expected, found }) => { match (expected.unpack(), found.unpack()) { @@ -1628,7 +1643,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { terr: TypeError<'tcx>, ) -> Vec { let mut suggestions = Vec::new(); - let span = trace.cause.span(); + let span = trace.cause.span; let values = self.resolve_vars_if_possible(trace.values); if let Some((expected, found)) = values.ty() { match (expected.kind(), found.kind()) { @@ -1773,18 +1788,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub fn report_and_explain_type_error( &self, trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, terr: TypeError<'tcx>, ) -> Diag<'a> { debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); - let span = trace.cause.span(); + let span = trace.cause.span; let failure_code = trace.cause.as_failure_code_diag( terr, span, self.type_error_additional_suggestions(&trace, terr), ); let mut diag = self.dcx().create_err(failure_code); - self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false); + self.note_type_err( + &mut diag, + &trace.cause, + None, + Some(param_env.and(trace.values)), + terr, + false, + ); diag } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index 14c2bf19a9c..4398af76ab2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -237,7 +237,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { expected_args: GenericArgsRef<'tcx>, actual_args: GenericArgsRef<'tcx>, ) -> Diag<'tcx> { - let span = cause.span(); + let span = cause.span; let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) = if let ObligationCauseCode::WhereClause(def_id, span) diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 62204f63dd0..0cf7c43beb5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -894,7 +894,7 @@ fn foo(&self) -> Self::T { String::new() } // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting. let trait_bounds = bounds.iter().filter_map(|bound| match bound { - hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifier::None => { + hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifiers::NONE => { Some(ptr) } _ => None, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 94610a9e0e6..833358b2e14 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -295,7 +295,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut err = match origin { infer::Subtype(box trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); - let mut err = self.report_and_explain_type_error(trace, terr); + let mut err = self.report_and_explain_type_error( + trace, + self.tcx.param_env(generic_param_scope), + terr, + ); match (*sub, *sup) { (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {} (ty::RePlaceholder(_), _) => { @@ -646,7 +650,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } infer::Subtype(box trace) => { let terr = TypeError::RegionsPlaceholderMismatch; - return self.report_and_explain_type_error(trace, terr); + return self.report_and_explain_type_error( + trace, + self.tcx.param_env(generic_param_scope), + terr, + ); } _ => { return self.report_concrete_failure( 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 549beafd196..6014ed555b6 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 @@ -156,8 +156,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (leaf_trait_predicate, &obligation) }; - let (main_trait_predicate, leaf_trait_predicate, predicate_constness) = self.get_effects_trait_pred_override(main_trait_predicate, leaf_trait_predicate, span); - let main_trait_ref = main_trait_predicate.to_poly_trait_ref(); let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref(); @@ -228,7 +226,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let err_msg = self.get_standard_error_message( main_trait_predicate, message, - predicate_constness, + None, append_const_msg, post_message, ); @@ -289,13 +287,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } - if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Drop) - && matches!(predicate_constness, Some(ty::BoundConstness::ConstIfConst | ty::BoundConstness::Const)) - { - err.note("`~const Drop` was renamed to `~const Destruct`"); - err.note("See for more details"); - } - let explanation = get_explanation_based_on_obligation( self.tcx, &obligation, @@ -541,6 +532,29 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => { + // FIXME(effects): We should recompute the predicate with `~const` + // if it's `const`, and if it holds, explain that this bound only + // *conditionally* holds. If that fails, we should also do selection + // to drill this down to an impl or built-in source, so we can + // point at it and explain that while the trait *is* implemented, + // that implementation is not const. + let err_msg = self.get_standard_error_message( + bound_predicate.rebind(ty::TraitPredicate { + trait_ref: predicate.trait_ref, + polarity: ty::PredicatePolarity::Positive, + }), + None, + Some(match predicate.host { + ty::HostPolarity::Maybe => ty::BoundConstness::ConstIfConst, + ty::HostPolarity::Const => ty::BoundConstness::Const, + }), + None, + String::new(), + ); + struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg) + } + ty::PredicateKind::Subtype(predicate) => { // Errors for Subtype predicates show up as // `FulfillmentErrorCode::SubtypeError`, @@ -1290,7 +1304,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ( Some(( data.projection_term, - false, self.resolve_vars_if_possible(normalized_term), data.term, )), @@ -1335,7 +1348,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { derive_better_type_error(lhs, rhs) { ( - Some((lhs, true, self.resolve_vars_if_possible(expected_term), rhs)), + Some((lhs, self.resolve_vars_if_possible(expected_term), rhs)), better_type_err, ) } else if let Some(rhs) = rhs.to_alias_term() @@ -1343,7 +1356,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { derive_better_type_error(rhs, lhs) { ( - Some((rhs, true, self.resolve_vars_if_possible(expected_term), lhs)), + Some((rhs, self.resolve_vars_if_possible(expected_term), lhs)), better_type_err, ) } else { @@ -1354,7 +1367,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; let msg = values - .and_then(|(predicate, _, normalized_term, expected_term)| { + .and_then(|(predicate, normalized_term, expected_term)| { self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term) }) .unwrap_or_else(|| { @@ -1431,8 +1444,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &mut diag, &obligation.cause, secondary_span, - values.map(|(_, _, normalized_ty, expected_ty)| { - infer::ValuePairs::Terms(ExpectedFound::new(true, expected_ty, normalized_ty)) + values.map(|(_, normalized_ty, expected_ty)| { + obligation.param_env.and(infer::ValuePairs::Terms(ExpectedFound::new( + true, + expected_ty, + normalized_ty, + ))) }), err, false, @@ -1818,6 +1835,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if impl_trait_ref.references_error() { return false; } + let self_ty = impl_trait_ref.self_ty().to_string(); err.highlighted_help(vec![ StringPart::normal(format!( "the trait `{}` ", @@ -1825,16 +1843,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { )), StringPart::highlighted("is"), StringPart::normal(" implemented for `"), - StringPart::highlighted(impl_trait_ref.self_ty().to_string()), + if let [TypeError::Sorts(_)] = &terrs[..] { + StringPart::normal(self_ty) + } else { + StringPart::highlighted(self_ty) + }, StringPart::normal("`"), ]); if let [TypeError::Sorts(exp_found)] = &terrs[..] { let exp_found = self.resolve_vars_if_possible(*exp_found); - err.help(format!( - "for that trait implementation, expected `{}`, found `{}`", - exp_found.expected, exp_found.found - )); + err.highlighted_help(vec![ + StringPart::normal("for that trait implementation, "), + StringPart::normal("expected `"), + StringPart::highlighted(exp_found.expected.to_string()), + StringPart::normal("`, found `"), + StringPart::highlighted(exp_found.found.to_string()), + StringPart::normal("`"), + ]); } true @@ -2143,6 +2169,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // First, attempt to add note to this error with an async-await-specific // message, and fall back to regular note otherwise. if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { + let mut long_ty_file = None; self.note_obligation_cause_code( obligation.cause.body_id, err, @@ -2151,7 +2178,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation.cause.code(), &mut vec![], &mut Default::default(), + &mut long_ty_file, ); + if let Some(file) = long_ty_file { + err.note(format!( + "the full name for the type has been written to '{}'", + file.display(), + )); + err.note("consider using `--verbose` to print the full type name to the console"); + } self.suggest_unsized_bound_if_applicable(err, obligation); if let Some(span) = err.span.primary_span() && let Some(mut diag) = @@ -2371,52 +2406,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) } - /// For effects predicates such as `::Effects: Compat`, pretend that the - /// predicate that failed was `u32: Add`. Return the constness of such predicate to later - /// print as `u32: ~const Add`. - fn get_effects_trait_pred_override( - &self, - p: ty::PolyTraitPredicate<'tcx>, - leaf: ty::PolyTraitPredicate<'tcx>, - span: Span, - ) -> (ty::PolyTraitPredicate<'tcx>, ty::PolyTraitPredicate<'tcx>, Option) - { - let trait_ref = p.to_poly_trait_ref(); - if !self.tcx.is_lang_item(trait_ref.def_id(), LangItem::EffectsCompat) { - return (p, leaf, None); - } - - let Some(ty::Alias(ty::AliasTyKind::Projection, projection)) = - trait_ref.self_ty().no_bound_vars().map(Ty::kind) - else { - return (p, leaf, None); - }; - - let constness = trait_ref.skip_binder().args.const_at(1); - - let constness = if constness == self.tcx.consts.true_ || constness.is_ct_infer() { - None - } else if constness == self.tcx.consts.false_ { - Some(ty::BoundConstness::Const) - } else if matches!(constness.kind(), ty::ConstKind::Param(_)) { - Some(ty::BoundConstness::ConstIfConst) - } else { - self.dcx().span_bug(span, format!("Unknown constness argument: {constness:?}")); - }; - - let new_pred = p.map_bound(|mut trait_pred| { - trait_pred.trait_ref = projection.trait_ref(self.tcx); - trait_pred - }); - - let new_leaf = leaf.map_bound(|mut trait_pred| { - trait_pred.trait_ref = projection.trait_ref(self.tcx); - trait_pred - }); - - (new_pred, new_leaf, constness) - } - fn add_tuple_trait_message( &self, obligation_cause_code: &ObligationCauseCode<'tcx>, @@ -2654,6 +2643,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; self.report_and_explain_type_error( TypeTrace::trait_refs(&cause, true, expected_trait_ref, found_trait_ref), + obligation.param_env, terr, ) } @@ -2744,6 +2734,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { return Ok(self.report_and_explain_type_error( TypeTrace::trait_refs(&obligation.cause, true, expected_trait_ref, found_trait_ref), + obligation.param_env, ty::error::TypeError::Mismatch, )); } @@ -3026,7 +3017,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, span: Span, ) -> Result, ErrorGuaranteed> { - if !self.tcx.features().generic_const_exprs { + if !self.tcx.features().generic_const_exprs() { let guar = self .dcx() .struct_span_err(span, "constant expression depends on a generic parameter") diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index ba57909fc23..b108a9352a5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -287,6 +287,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self .report_mismatched_types( &error.obligation.cause, + error.obligation.param_env, expected_found.expected, expected_found.found, *err, @@ -295,6 +296,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => { let mut diag = self.report_mismatched_consts( &error.obligation.cause, + error.obligation.param_env, expected_found.expected, expected_found.found, *err, @@ -303,6 +305,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let ObligationCauseCode::WhereClause(..) | ObligationCauseCode::WhereClauseInExpr(..) = code { + let mut long_ty_file = None; self.note_obligation_cause_code( error.obligation.cause.body_id, &mut diag, @@ -311,7 +314,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { code, &mut vec![], &mut Default::default(), + &mut long_ty_file, ); + if let Some(file) = long_ty_file { + diag.note(format!( + "the full name for the type has been written to '{}'", + file.display(), + )); + diag.note( + "consider using `--verbose` to print the full type name to the console", + ); + } } diag.emit() } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs index f4c5733d4a6..c47c2169691 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -144,6 +144,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation.cause.span, suggest_increasing_limit, |err| { + let mut long_ty_file = None; self.note_obligation_cause_code( obligation.cause.body_id, err, @@ -152,7 +153,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation.cause.code(), &mut vec![], &mut Default::default(), + &mut long_ty_file, ); + if let Some(file) = long_ty_file { + err.note(format!( + "the full name for the type has been written to '{}'", + file.display(), + )); + err.note( + "consider using `--verbose` to print the full type name to the console", + ); + } }, ); } 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 677905a3085..a7d1f1bd8d0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3,6 +3,7 @@ use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::iter; +use std::path::PathBuf; use itertools::{EitherOrBoth, Itertools}; use rustc_data_structures::fx::FxHashSet; @@ -2703,6 +2704,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Add a note for the item obligation that remains - normally a note pointing to the // bound that introduced the obligation (e.g. `T: Send`). debug!(?next_code); + let mut long_ty_file = None; self.note_obligation_cause_code( obligation.cause.body_id, err, @@ -2711,6 +2713,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { next_code.unwrap(), &mut Vec::new(), &mut Default::default(), + &mut long_ty_file, ); } @@ -2723,11 +2726,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { cause_code: &ObligationCauseCode<'tcx>, obligated_types: &mut Vec>, seen_requirements: &mut FxHashSet, + long_ty_file: &mut Option, ) where T: Upcast, ty::Predicate<'tcx>>, { - let mut long_ty_file = None; - let tcx = self.tcx; let predicate = predicate.upcast(tcx); let suggest_remove_deref = |err: &mut Diag<'_, G>, expr: &hir::Expr<'_>| { @@ -2957,9 +2959,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ObligationCauseCode::Coercion { source, target } => { let source = - tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut long_ty_file); + tcx.short_ty_string(self.resolve_vars_if_possible(source), long_ty_file); let target = - tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut long_ty_file); + tcx.short_ty_string(self.resolve_vars_if_possible(target), long_ty_file); err.note(with_forced_trimmed_paths!(format!( "required for the cast from `{source}` to `{target}`", ))); @@ -3044,7 +3046,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if local { err.note("all local variables must have a statically known size"); } - if !tcx.features().unsized_locals { + if !tcx.features().unsized_locals() { err.help("unsized locals are gated as an unstable feature"); } } @@ -3125,7 +3127,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.note("all function arguments must have a statically known size"); } if tcx.sess.opts.unstable_features.is_nightly_build() - && !tcx.features().unsized_fn_params + && !tcx.features().unsized_fn_params() { err.help("unsized fn params are gated as an unstable feature"); } @@ -3249,7 +3251,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; if !is_upvar_tys_infer_tuple { - let ty_str = tcx.short_ty_string(ty, &mut long_ty_file); + let ty_str = tcx.short_ty_string(ty, long_ty_file); let msg = format!("required because it appears within the type `{ty_str}`"); match ty.kind() { ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) { @@ -3327,6 +3329,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.parent_code, obligated_types, seen_requirements, + long_ty_file, ) }); } else { @@ -3339,6 +3342,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { cause_code.peel_derives(), obligated_types, seen_requirements, + long_ty_file, ) }); } @@ -3347,8 +3351,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut parent_trait_pred = self.resolve_vars_if_possible(data.derived.parent_trait_pred); let parent_def_id = parent_trait_pred.def_id(); - let self_ty_str = tcx - .short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut long_ty_file); + let self_ty_str = + tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file); let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string(); let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`"); let mut is_auto_trait = false; @@ -3444,10 +3448,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { count, pluralize!(count) )); - let self_ty = tcx.short_ty_string( - parent_trait_pred.skip_binder().self_ty(), - &mut long_ty_file, - ); + let self_ty = tcx + .short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file); err.note(format!( "required for `{self_ty}` to implement `{}`", parent_trait_pred.print_modifiers_and_trait_path() @@ -3463,6 +3465,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.parent_code, obligated_types, seen_requirements, + long_ty_file, ) }); } @@ -3479,6 +3482,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.parent_code, obligated_types, seen_requirements, + long_ty_file, ) }); } @@ -3493,6 +3497,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { nested, obligated_types, seen_requirements, + long_ty_file, ) }); let mut multispan = MultiSpan::from(span); @@ -3523,6 +3528,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { parent_code, obligated_types, seen_requirements, + long_ty_file, ) }); } @@ -3562,7 +3568,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ObligationCauseCode::OpaqueReturnType(expr_info) => { if let Some((expr_ty, hir_id)) = expr_info { - let expr_ty = self.tcx.short_ty_string(expr_ty, &mut long_ty_file); + let expr_ty = self.tcx.short_ty_string(expr_ty, long_ty_file); let expr = self.infcx.tcx.hir().expect_expr(hir_id); err.span_label( expr.span, @@ -3574,14 +3580,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } } - - if let Some(file) = long_ty_file { - err.note(format!( - "the full name for the type has been written to '{}'", - file.display(), - )); - err.note("consider using `--verbose` to print the full type name to the console"); - } } #[instrument( @@ -3594,52 +3592,64 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, span: Span, ) { - if let Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) = - self.tcx.coroutine_kind(obligation.cause.body_id) + let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + + let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); + let impls_future = self.type_implements_trait( + future_trait, + [self.tcx.instantiate_bound_regions_with_erased(self_ty)], + obligation.param_env, + ); + if !impls_future.must_apply_modulo_regions() { + return; + } + + let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; + // `::Output` + let projection_ty = trait_pred.map_bound(|trait_pred| { + Ty::new_projection( + self.tcx, + item_def_id, + // Future::Output has no args + [trait_pred.self_ty()], + ) + }); + let InferOk { value: projection_ty, .. } = + self.at(&obligation.cause, obligation.param_env).normalize(projection_ty); + + debug!( + normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty) + ); + let try_obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())), + ); + debug!(try_trait_obligation = ?try_obligation); + if self.predicate_may_hold(&try_obligation) + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) + && snippet.ends_with('?') { - let future_trait = self.tcx.require_lang_item(LangItem::Future, None); - - let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); - let impls_future = self.type_implements_trait( - future_trait, - [self.tcx.instantiate_bound_regions_with_erased(self_ty)], - obligation.param_env, - ); - if !impls_future.must_apply_modulo_regions() { - return; - } - - let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; - // `::Output` - let projection_ty = trait_pred.map_bound(|trait_pred| { - Ty::new_projection( - self.tcx, - item_def_id, - // Future::Output has no args - [trait_pred.self_ty()], - ) - }); - let InferOk { value: projection_ty, .. } = - self.at(&obligation.cause, obligation.param_env).normalize(projection_ty); - - debug!( - normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty) - ); - let try_obligation = self.mk_trait_obligation_with_new_self_ty( - obligation.param_env, - trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())), - ); - debug!(try_trait_obligation = ?try_obligation); - if self.predicate_may_hold(&try_obligation) - && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) - && snippet.ends_with('?') - { - err.span_suggestion_verbose( - span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), - "consider `await`ing on the `Future`", - ".await", - Applicability::MaybeIncorrect, - ); + match self.tcx.coroutine_kind(obligation.cause.body_id) { + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => { + err.span_suggestion_verbose( + span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), + "consider `await`ing on the `Future`", + ".await", + Applicability::MaybeIncorrect, + ); + } + _ => { + let mut span: MultiSpan = span.with_lo(span.hi() - BytePos(1)).into(); + span.push_span_label( + self.tcx.def_span(obligation.cause.body_id), + "this is not `async`", + ); + err.span_note( + span, + "this implements `Future` and its output type supports \ + `?`, but the future cannot be awaited in a synchronous function", + ); + } } } } @@ -4498,7 +4508,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, ) { // Don't suggest if RTN is active -- we should prefer a where-clause bound instead. - if self.tcx.features().return_type_notation { + if self.tcx.features().return_type_notation() { return; } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 4975a9ce0c7..e735020a63e 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -344,7 +344,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { }; let mut nested_goals = vec![]; - self.candidates_recur(&mut candidates, &mut nested_goals, &last_eval_step.evaluation); + self.candidates_recur(&mut candidates, &mut nested_goals, &last_eval_step); candidates } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 12aeee0d02f..934fe9ec47c 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -806,7 +806,8 @@ impl<'tcx> AutoTraitFinder<'tcx> { | ty::PredicateKind::Subtype(..) // FIXME(generic_const_exprs): you can absolutely add this as a where clauses | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) - | ty::PredicateKind::Coerce(..) => {} + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {} ty::PredicateKind::Ambiguous => return false, }; } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index c258832bf2b..1be3c964454 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -40,7 +40,7 @@ pub fn is_const_evaluatable<'tcx>( ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer), }; - if tcx.features().generic_const_exprs { + if tcx.features().generic_const_exprs() { let ct = tcx.expand_abstract_consts(unexpanded_ct); let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() { diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 364a13b3a75..a068f25fe35 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -245,6 +245,7 @@ fn predicate_references_self<'tcx>( | ty::ClauseKind::RegionOutlives(..) // FIXME(generic_const_exprs): this can mention `Self` | ty::ClauseKind::ConstEvaluatable(..) + | ty::ClauseKind::HostEffect(..) => None, } } @@ -254,7 +255,7 @@ fn super_predicates_have_non_lifetime_binders( trait_def_id: DefId, ) -> SmallVec<[Span; 1]> { // If non_lifetime_binders is disabled, then exit early - if !tcx.features().non_lifetime_binders { + if !tcx.features().non_lifetime_binders() { return SmallVec::new(); } tcx.explicit_super_predicates_of(trait_def_id) @@ -284,7 +285,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) => false, + | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::HostEffect(..) => false, }) } @@ -327,7 +329,7 @@ pub fn dyn_compatibility_violations_for_assoc_item( .collect(), // Associated types can only be dyn-compatible if they have `Self: Sized` bounds. ty::AssocKind::Type => { - if !tcx.features().generic_associated_types_extended + if !tcx.features().generic_associated_types_extended() && !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index e56f1866970..1754418156d 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -372,7 +372,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { | ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) - | ty::PredicateKind::ConstEquate(..) => { + | ty::PredicateKind::ConstEquate(..) + // FIXME(effects): We may need to do this using the higher-ranked + // pred instead of just instantiating it with placeholders b/c of + // higher-ranked implied bound issues in the old solver. + | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => { let pred = ty::Binder::dummy(infcx.enter_forall_and_leak_universe(binder)); let mut obligations = PredicateObligations::with_capacity(1); obligations.push(obligation.with(infcx.tcx, pred)); @@ -398,6 +402,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ) } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => { + ProcessResult::Changed(Default::default()) + } + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => { if infcx.considering_regions { infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)); @@ -450,7 +458,6 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::ConstKind::Infer(var) => { let var = match var { ty::InferConst::Var(vid) => TyOrConstInferVar::Const(vid), - ty::InferConst::EffectVar(vid) => TyOrConstInferVar::Effect(vid), ty::InferConst::Fresh(_) => { bug!("encountered fresh const in fulfill") } @@ -598,7 +605,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::ConstEquate(c1, c2) => { let tcx = self.selcx.tcx(); assert!( - tcx.features().generic_const_exprs, + tcx.features().generic_const_exprs(), "`ConstEquate` without a feature gate: {c1:?} {c2:?}", ); // FIXME: we probably should only try to unify abstract constants diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index cffb9b59841..cdf24887e76 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -346,7 +346,7 @@ pub fn normalize_param_env_or_error<'tcx>( let mut predicates: Vec<_> = util::elaborate( tcx, unnormalized_env.caller_bounds().into_iter().map(|predicate| { - if tcx.features().generic_const_exprs { + if tcx.features().generic_const_exprs() { return predicate; } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index d246d37f748..12e00ec79ac 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -402,7 +402,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx #[instrument(skip(self), level = "debug")] fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { let tcx = self.selcx.tcx(); - if tcx.features().generic_const_exprs + if tcx.features().generic_const_exprs() || !needs_normalization(&constant, self.param_env.reveal()) { constant diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index cc634b65a0b..0803dd74b89 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -189,7 +189,7 @@ pub(super) fn poly_project_and_unify_term<'cx, 'tcx>( ProjectAndUnifyResult::MismatchedProjectionTypes(e) => Err(e), ProjectAndUnifyResult::Holds(obligations) if old_universe != new_universe - && selcx.tcx().features().generic_associated_types_extended => + && selcx.tcx().features().generic_associated_types_extended() => { // If the `generic_associated_types_extended` feature is active, then we ignore any // obligations references lifetimes from any universe greater than or equal to the @@ -1180,7 +1180,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( selcx.tcx(), selcx.tcx().require_lang_item( LangItem::Sized, - Some(obligation.cause.span()), + Some(obligation.cause.span), ), [self_ty], ), @@ -1600,7 +1600,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( // exist. Instead, `Pointee` should be a supertrait of `Sized`. let sized_predicate = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span())), + tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)), [self_ty], ); obligations.push(obligation.with(tcx, sized_predicate)); diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 76017299f2c..bb44645a4ce 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -90,7 +90,7 @@ impl<'tcx> InferCtxt<'tcx> { assert!(!self.intercrate); let c_pred = self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values); - self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred) + self.tcx.at(obligation.cause.span).evaluate_obligation(c_pred) } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index dfd0cab6905..c6e41e57f0c 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -96,6 +96,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound // if we ever support that ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) @@ -200,6 +201,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound // if we ever support that ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) 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 ac38c9e24a2..e027586563e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -244,7 +244,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .param_env .caller_bounds() .iter() - .filter(|p| !p.references_error()) .filter_map(|p| p.as_trait_clause()) // Micro-optimization: filter out predicates relating to different traits. .filter(|p| p.def_id() == stack.obligation.predicate.def_id()) @@ -394,7 +393,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = obligation.self_ty().skip_binder(); match *self_ty.kind() { ty::Closure(def_id, _) => { - let is_const = self.tcx().is_const_fn_raw(def_id); + let is_const = self.tcx().is_const_fn(def_id); debug!(?kind, ?obligation, "assemble_unboxed_candidates"); match self.infcx.closure_kind(self_ty) { Some(closure_kind) => { @@ -414,7 +413,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::CoroutineClosure(def_id, args) => { let args = args.as_coroutine_closure(); - let is_const = self.tcx().is_const_fn_raw(def_id); + let is_const = self.tcx().is_const_fn(def_id); if let Some(closure_kind) = self.infcx.closure_kind(self_ty) // Ambiguity if upvars haven't been constrained yet && !args.tupled_upvars_ty().is_ty_var() @@ -547,7 +546,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396). - ty::FnDef(def_id, _args) => { + ty::FnDef(def_id, _) => { let tcx = self.tcx(); if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible() && tcx.codegen_fn_attrs(def_id).target_features.is_empty() @@ -876,7 +875,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if let Some(principal) = data.principal() { - if !self.infcx.tcx.features().dyn_compatible_for_dispatch { + if !self.infcx.tcx.features().dyn_compatible_for_dispatch() { principal.with_self_ty(self.tcx(), self_ty) } else if self.tcx().is_dyn_compatible(principal.def_id()) { principal.with_self_ty(self.tcx(), self_ty) @@ -936,7 +935,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let tcx = self.tcx(); - if tcx.features().trait_upcasting { + if tcx.features().trait_upcasting() { return None; } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 9a49fd7e77e..e7d3004aa20 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -402,7 +402,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut assume = predicate.trait_ref.args.const_at(2); // FIXME(min_generic_const_exprs): We should shallowly normalize this. - if self.tcx().features().generic_const_exprs { + if self.tcx().features().generic_const_exprs() { assume = assume.normalize_internal(self.tcx(), obligation.param_env); } let Some(assume) = @@ -626,7 +626,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { for assoc_type in assoc_types { let defs: &ty::Generics = tcx.generics_of(assoc_type); - if !defs.own_params.is_empty() && !tcx.features().generic_associated_types_extended { + if !defs.own_params.is_empty() && !tcx.features().generic_associated_types_extended() { tcx.dcx().span_delayed_bug( obligation.cause.span, "GATs in trait object shouldn't have been considered", diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 4757430a21c..ec4114fd9d7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -645,6 +645,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.evaluate_trait_predicate_recursively(previous_stack, obligation) } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => { + // FIXME(effects): It should be relatively straightforward to implement + // old trait solver support for `HostEffect` bounds; or at least basic + // support for them. + todo!() + } + ty::PredicateKind::Subtype(p) => { let p = bound_predicate.rebind(p); // Does this code ever run? @@ -865,7 +872,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::PredicateKind::ConstEquate(c1, c2) => { let tcx = self.tcx(); assert!( - tcx.features().generic_const_exprs, + tcx.features().generic_const_exprs(), "`ConstEquate` without a feature gate: {c1:?} {c2:?}", ); @@ -1821,8 +1828,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { |cand: ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars(); // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, - // `DiscriminantKindCandidate`, `ConstDestructCandidate` - // to anything else. + // or `DiscriminantKindCandidate` to anything else. // // This is a fix for #53123 and prevents winnowing from accidentally extending the // lifetime of a variable. @@ -2195,7 +2201,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { match self.tcx().coroutine_movability(coroutine_def_id) { hir::Movability::Static => None, hir::Movability::Movable => { - if self.tcx().features().coroutine_clone { + if self.tcx().features().coroutine_clone() { let resolved_upvars = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); let resolved_witness = diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index b82a3433645..0e45f7a195f 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -136,7 +136,7 @@ pub fn translate_args_with_cause<'tcx>( } pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool { - tcx.features().specialization || tcx.features().min_specialization + tcx.features().specialization() || tcx.features().min_specialization() } /// Is `impl1` a specialization of `impl2`? diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index f8d98eb856e..23b5f62b5ca 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -82,7 +82,7 @@ impl<'tcx> At<'_, 'tcx> { } Ok(self.infcx.resolve_vars_if_possible(new_infer_ct)) - } else if self.infcx.tcx.features().generic_const_exprs { + } else if self.infcx.tcx.features().generic_const_exprs() { Ok(ct.normalize_internal(self.infcx.tcx, self.param_env)) } else { Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx)) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 07e68e5a3e8..437343b569c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -170,6 +170,10 @@ pub fn clause_obligations<'tcx>( ty::ClauseKind::Trait(t) => { wf.compute_trait_pred(t, Elaborate::None); } + ty::ClauseKind::HostEffect(..) => { + // Technically the well-formedness of this predicate is implied by + // the corresponding trait predicate it should've been generated beside. + } ty::ClauseKind::RegionOutlives(..) => {} ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => { wf.compute(ty.into()); @@ -836,7 +840,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { // obligations that don't refer to Self and // checking those - let defer_to_coercion = tcx.features().dyn_compatible_for_dispatch; + let defer_to_coercion = tcx.features().dyn_compatible_for_dispatch(); if !defer_to_coercion { if let Some(principal) = data.principal_def_id() { @@ -1021,6 +1025,7 @@ pub(crate) fn required_region_bounds<'tcx>( } } ty::ClauseKind::Trait(_) + | ty::ClauseKind::HostEffect(..) | ty::ClauseKind::RegionOutlives(_) | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index f01a12b0a00..3e2794f6489 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -55,6 +55,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool { | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => false, ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::NormalizesTo(..) | ty::PredicateKind::AliasRelate(..) diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index 4732e968f6b..6a98be18503 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +rustc_abi = { path = "../rustc_abi", optional = true } rustc_ast_ir = { path = "../rustc_ast_ir", optional = true } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir", optional = true } @@ -12,19 +13,18 @@ rustc_infer = { path = "../rustc_infer", optional = true } rustc_macros = { path = "../rustc_macros", optional = true } rustc_middle = { path = "../rustc_middle", optional = true } rustc_span = { path = "../rustc_span", optional = true } -rustc_target = { path = "../rustc_target", optional = true } tracing = "0.1" # tidy-alphabetical-end [features] rustc = [ + "dep:rustc_abi", + "dep:rustc_ast_ir", "dep:rustc_hir", "dep:rustc_infer", "dep:rustc_macros", "dep:rustc_middle", "dep:rustc_span", - "dep:rustc_target", - "dep:rustc_ast_ir", ] [dev-dependencies] diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs index a5c47c480e1..c4c01a8fac3 100644 --- a/compiler/rustc_transmute/src/layout/mod.rs +++ b/compiler/rustc_transmute/src/layout/mod.rs @@ -62,10 +62,10 @@ impl Ref for ! { pub mod rustc { use std::fmt::{self, Write}; + use rustc_abi::Layout; use rustc_middle::mir::Mutability; use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError}; use rustc_middle::ty::{self, Ty}; - use rustc_target::abi::Layout; /// A reference in the layout. #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 17eddbfcd7f..94ca4c13d08 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -171,12 +171,12 @@ where #[cfg(feature = "rustc")] pub(crate) mod rustc { + use rustc_abi::{ + FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants, + }; use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError}; use rustc_middle::ty::{self, AdtDef, AdtKind, List, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::ErrorGuaranteed; - use rustc_target::abi::{ - FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants, - }; use super::Tree; use crate::layout::rustc::{Def, Ref, layout_of}; @@ -206,7 +206,7 @@ pub(crate) mod rustc { impl<'tcx> Tree, Ref<'tcx>> { pub(crate) fn from_ty(ty: Ty<'tcx>, cx: LayoutCx<'tcx>) -> Result { - use rustc_target::abi::HasDataLayout; + use rustc_abi::HasDataLayout; let layout = layout_of(cx, ty)?; if let Err(e) = ty.error_reported() { @@ -446,7 +446,7 @@ pub(crate) mod rustc { /// Constructs a `Tree` representing the value of a enum tag. fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self { - use rustc_target::abi::Endian; + use rustc_abi::Endian; let size = tag.size(); let bits = tag.to_bits(size); let bytes: [u8; 16]; diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 13691204c96..48149a08de8 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -1,8 +1,7 @@ use std::iter; -use rustc_abi::Float::*; -use rustc_abi::Primitive::{Float, Pointer}; -use rustc_abi::{Abi, AddressSpace, PointerKind, Scalar, Size}; +use rustc_abi::Primitive::Pointer; +use rustc_abi::{Abi, PointerKind, Scalar, Size}; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_middle::bug; @@ -14,8 +13,7 @@ use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt}; use rustc_session::config::OptLevel; use rustc_span::def_id::DefId; use rustc_target::abi::call::{ - ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind, - RiscvInterruptKind, + ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, RiscvInterruptKind, }; use rustc_target::spec::abi::Abi as SpecAbi; use tracing::debug; @@ -679,6 +677,8 @@ fn fn_abi_adjust_for_abi<'tcx>( let tcx = cx.tcx(); if abi == SpecAbi::Rust || abi == SpecAbi::RustCall || abi == SpecAbi::RustIntrinsic { + fn_abi.adjust_for_rust_abi(cx, abi); + // Look up the deduced parameter attributes for this function, if we have its def ID and // we're optimizing in non-incremental mode. We'll tag its parameters with those attributes // as appropriate. @@ -689,131 +689,9 @@ fn fn_abi_adjust_for_abi<'tcx>( &[] }; - let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, arg_idx: Option| { + for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() { if arg.is_ignore() { - return; - } - - // Avoid returning floats in x87 registers on x86 as loading and storing from x87 - // registers will quiet signalling NaNs. - if tcx.sess.target.arch == "x86" - && arg_idx.is_none() - // Intrinsics themselves are not actual "real" functions, so theres no need to - // change their ABIs. - && abi != SpecAbi::RustIntrinsic - { - match arg.layout.abi { - // Handle similar to the way arguments with an `Abi::Aggregate` abi are handled - // below, by returning arguments up to the size of a pointer (32 bits on x86) - // cast to an appropriately sized integer. - Abi::Scalar(s) if s.primitive() == Float(F32) => { - // Same size as a pointer, return in a register. - arg.cast_to(Reg::i32()); - return; - } - Abi::Scalar(s) if s.primitive() == Float(F64) => { - // Larger than a pointer, return indirectly. - arg.make_indirect(); - return; - } - Abi::ScalarPair(s1, s2) - if matches!(s1.primitive(), Float(F32 | F64)) - || matches!(s2.primitive(), Float(F32 | F64)) => - { - // Larger than a pointer, return indirectly. - arg.make_indirect(); - return; - } - _ => {} - }; - } - - if arg_idx.is_none() && arg.layout.size > Pointer(AddressSpace::DATA).size(cx) * 2 { - // Return values larger than 2 registers using a return area - // pointer. LLVM and Cranelift disagree about how to return - // values that don't fit in the registers designated for return - // values. LLVM will force the entire return value to be passed - // by return area pointer, while Cranelift will look at each IR level - // return value independently and decide to pass it in a - // register or not, which would result in the return value - // being passed partially in registers and partially through a - // return area pointer. - // - // While Cranelift may need to be fixed as the LLVM behavior is - // generally more correct with respect to the surface language, - // forcing this behavior in rustc itself makes it easier for - // other backends to conform to the Rust ABI and for the C ABI - // rustc already handles this behavior anyway. - // - // In addition LLVM's decision to pass the return value in - // registers or using a return area pointer depends on how - // exactly the return type is lowered to an LLVM IR type. For - // example `Option` can be lowered as `{ i128, i128 }` - // in which case the x86_64 backend would use a return area - // pointer, or it could be passed as `{ i32, i128 }` in which - // case the x86_64 backend would pass it in registers by taking - // advantage of an LLVM ABI extension that allows using 3 - // registers for the x86_64 sysv call conv rather than the - // officially specified 2 registers. - // - // FIXME: Technically we should look at the amount of available - // return registers rather than guessing that there are 2 - // registers for return values. In practice only a couple of - // architectures have less than 2 return registers. None of - // which supported by Cranelift. - // - // NOTE: This adjustment is only necessary for the Rust ABI as - // for other ABI's the calling convention implementations in - // rustc_target already ensure any return value which doesn't - // fit in the available amount of return registers is passed in - // the right way for the current target. - arg.make_indirect(); - return; - } - - match arg.layout.abi { - Abi::Aggregate { .. } => {} - - // This is a fun case! The gist of what this is doing is - // that we want callers and callees to always agree on the - // ABI of how they pass SIMD arguments. If we were to *not* - // make these arguments indirect then they'd be immediates - // in LLVM, which means that they'd used whatever the - // appropriate ABI is for the callee and the caller. That - // means, for example, if the caller doesn't have AVX - // enabled but the callee does, then passing an AVX argument - // across this boundary would cause corrupt data to show up. - // - // This problem is fixed by unconditionally passing SIMD - // arguments through memory between callers and callees - // which should get them all to agree on ABI regardless of - // target feature sets. Some more information about this - // issue can be found in #44367. - // - // Note that the intrinsic ABI is exempt here as - // that's how we connect up to LLVM and it's unstable - // anyway, we control all calls to it in libstd. - Abi::Vector { .. } - if abi != SpecAbi::RustIntrinsic && tcx.sess.target.simd_types_indirect => - { - arg.make_indirect(); - return; - } - - _ => return, - } - // Compute `Aggregate` ABI. - - let is_indirect_not_on_stack = - matches!(arg.mode, PassMode::Indirect { on_stack: false, .. }); - assert!(is_indirect_not_on_stack, "{:?}", arg); - - let size = arg.layout.size; - if !arg.layout.is_unsized() && size <= Pointer(AddressSpace::DATA).size(cx) { - // We want to pass small aggregates as immediates, but using - // an LLVM aggregate type for this leads to bad optimizations, - // so we pick an appropriately sized integer type instead. - arg.cast_to(Reg { kind: RegKind::Integer, size }); + continue; } // If we deduced that this parameter was read-only, add that to the attribute list now. @@ -821,9 +699,7 @@ fn fn_abi_adjust_for_abi<'tcx>( // The `readonly` parameter only applies to pointers, so we can only do this if the // argument was passed indirectly. (If the argument is passed directly, it's an SSA // value, so it's implicitly immutable.) - if let (Some(arg_idx), &mut PassMode::Indirect { ref mut attrs, .. }) = - (arg_idx, &mut arg.mode) - { + if let &mut PassMode::Indirect { ref mut attrs, .. } = &mut arg.mode { // The `deduced_param_attrs` list could be empty if this is a type of function // we can't deduce any parameters for, so make sure the argument index is in // bounds. @@ -834,11 +710,6 @@ fn fn_abi_adjust_for_abi<'tcx>( } } } - }; - - fixup(&mut fn_abi.ret, None); - for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() { - fixup(arg, Some(arg_idx)); } } else { fn_abi diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index a057caa9329..16fd28201c2 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -4,9 +4,8 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, ImplTraitInTraitData, Ty, TyCtxt}; +use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_span::sym; use rustc_span::symbol::kw; pub(crate) fn provide(providers: &mut Providers) { @@ -15,7 +14,6 @@ pub(crate) fn provide(providers: &mut Providers) { associated_item_def_ids, associated_items, associated_types_for_impl_traits_in_associated_fn, - associated_type_for_effects, associated_type_for_impl_trait_in_trait, impl_item_implementor_ids, ..*providers @@ -46,8 +44,7 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { ) }) .copied(), - ) - .chain(tcx.associated_type_for_effects(def_id)), + ), ) } hir::ItemKind::Impl(impl_) => { @@ -73,8 +70,7 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { ) }) .copied() - })) - .chain(tcx.associated_type_for_effects(def_id)), + })), ) } _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"), @@ -171,134 +167,6 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A } } -/// Given an `def_id` of a trait or a trait impl: -/// -/// If `def_id` is a trait that has `#[const_trait]`, then it synthesizes -/// a new def id corresponding to a new associated type for the effects. -/// -/// If `def_id` is an impl, then synthesize the associated type according -/// to the constness of the impl. -fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - // don't synthesize the associated type even if the user has written `const_trait` - // if the effects feature is disabled. - if !tcx.features().effects { - return None; - } - let (feed, parent_did) = match tcx.def_kind(def_id) { - DefKind::Trait => { - let trait_def_id = def_id; - let attr = tcx.get_attr(def_id, sym::const_trait)?; - - let span = attr.span; - let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, kw::Empty, DefKind::AssocTy); - - let local_def_id = trait_assoc_ty.def_id(); - let def_id = local_def_id.to_def_id(); - - // Copy span of the attribute. - trait_assoc_ty.def_ident_span(Some(span)); - - trait_assoc_ty.associated_item(ty::AssocItem { - name: kw::Empty, - kind: ty::AssocKind::Type, - def_id, - trait_item_def_id: None, - container: ty::TraitContainer, - fn_has_self_parameter: false, - opt_rpitit_info: None, - is_effects_desugaring: true, - }); - - // No default type - trait_assoc_ty.defaultness(hir::Defaultness::Default { has_value: false }); - - trait_assoc_ty.is_type_alias_impl_trait(false); - - (trait_assoc_ty, trait_def_id) - } - DefKind::Impl { .. } => { - let impl_def_id = def_id; - let trait_id = tcx.trait_id_of_impl(def_id.to_def_id())?; - - // first get the DefId of the assoc type on the trait, if there is not, - // then we don't need to generate it on the impl. - let trait_assoc_id = tcx.associated_type_for_effects(trait_id)?; - - // FIXME(effects): span - let span = tcx.def_ident_span(def_id).unwrap(); - - let impl_assoc_ty = tcx.at(span).create_def(def_id, kw::Empty, DefKind::AssocTy); - - let local_def_id = impl_assoc_ty.def_id(); - let def_id = local_def_id.to_def_id(); - - impl_assoc_ty.def_ident_span(Some(span)); - - impl_assoc_ty.associated_item(ty::AssocItem { - name: kw::Empty, - kind: ty::AssocKind::Type, - def_id, - trait_item_def_id: Some(trait_assoc_id), - container: ty::ImplContainer, - fn_has_self_parameter: false, - opt_rpitit_info: None, - is_effects_desugaring: true, - }); - - // no default value. - impl_assoc_ty.defaultness(hir::Defaultness::Final); - - // set the type of the associated type! If this is a const impl, - // we set to Maybe, otherwise we set to `Runtime`. - let type_def_id = if tcx.is_const_trait_impl_raw(impl_def_id.to_def_id()) { - tcx.require_lang_item(hir::LangItem::EffectsMaybe, Some(span)) - } else { - tcx.require_lang_item(hir::LangItem::EffectsRuntime, Some(span)) - }; - // FIXME(effects): make impls use `Min` for their effect types - impl_assoc_ty.type_of(ty::EarlyBinder::bind(Ty::new_adt( - tcx, - tcx.adt_def(type_def_id), - ty::GenericArgs::empty(), - ))); - - (impl_assoc_ty, impl_def_id) - } - def_kind => bug!( - "associated_type_for_effects: {:?} should be Trait or Impl but is {:?}", - def_id, - def_kind - ), - }; - - feed.feed_hir(); - - // visibility is public. - feed.visibility(ty::Visibility::Public); - - // Copy generics_of of the trait/impl, making the trait/impl as parent. - feed.generics_of({ - let parent_generics = tcx.generics_of(parent_did); - let parent_count = parent_generics.parent_count + parent_generics.own_params.len(); - - ty::Generics { - parent: Some(parent_did.to_def_id()), - parent_count, - own_params: vec![], - param_def_id_to_index: parent_generics.param_def_id_to_index.clone(), - has_self: false, - has_late_bound_regions: None, - host_effect_index: parent_generics.host_effect_index, - } - }); - feed.explicit_item_super_predicates(ty::EarlyBinder::bind(&[])); - - // There are no inferred outlives for the synthesized associated type. - feed.inferred_outlives_of(&[]); - - Some(feed.def_id().to_def_id()) -} - /// Given an `fn_def_id` of a trait or a trait implementation: /// /// if `fn_def_id` is a function defined inside a trait, then it synthesizes @@ -494,7 +362,6 @@ fn associated_type_for_impl_trait_in_impl( param_def_id_to_index, has_self: false, has_late_bound_regions: trait_assoc_generics.has_late_bound_regions, - host_effect_index: parent_generics.host_effect_index, } }); diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 391985ce88a..4b770d9938c 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -406,7 +406,7 @@ fn thir_abstract_const<'tcx>( tcx: TyCtxt<'tcx>, def: LocalDefId, ) -> Result>>, ErrorGuaranteed> { - if !tcx.features().generic_const_exprs { + if !tcx.features().generic_const_exprs() { return Ok(None); } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index e755e90aa65..94b80e2694d 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -6,7 +6,7 @@ use rustc_abi::Integer::{I8, I32}; use rustc_abi::Primitive::{self, Float, Int, Pointer}; use rustc_abi::{ Abi, AbiAndPrefAlign, AddressSpace, Align, FieldsShape, HasDataLayout, LayoutCalculatorError, - LayoutS, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange, + LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange, }; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; @@ -131,7 +131,7 @@ fn univariant_uninterned<'tcx>( fields: &IndexSlice>, repr: &ReprOptions, kind: StructKind, -) -> Result, &'tcx LayoutError<'tcx>> { +) -> Result, &'tcx LayoutError<'tcx>> { let pack = repr.pack; if pack.is_some() && repr.align.is_some() { cx.tcx().dcx().bug("struct cannot be packed and aligned"); @@ -159,7 +159,7 @@ fn layout_of_uncached<'tcx>( assert!(size.bits() <= 128); Scalar::Initialized { value, valid_range: WrappingRange::full(size) } }; - let scalar = |value: Primitive| tcx.mk_layout(LayoutS::scalar(cx, scalar_unit(value))); + let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value))); let univariant = |fields: &IndexSlice>, repr: &ReprOptions, kind| { @@ -170,7 +170,7 @@ fn layout_of_uncached<'tcx>( Ok(match *ty.kind() { ty::Pat(ty, pat) => { let layout = cx.layout_of(ty)?.layout; - let mut layout = LayoutS::clone(&layout.0); + let mut layout = LayoutData::clone(&layout.0); match *pat { ty::PatternKind::Range { start, end, include_end } => { if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &mut layout.abi { @@ -206,11 +206,11 @@ fn layout_of_uncached<'tcx>( } // Basic scalars. - ty::Bool => tcx.mk_layout(LayoutS::scalar(cx, Scalar::Initialized { + ty::Bool => tcx.mk_layout(LayoutData::scalar(cx, Scalar::Initialized { value: Int(I8, false), valid_range: WrappingRange { start: 0, end: 1 }, })), - ty::Char => tcx.mk_layout(LayoutS::scalar(cx, Scalar::Initialized { + ty::Char => tcx.mk_layout(LayoutData::scalar(cx, Scalar::Initialized { value: Int(I32, false), valid_range: WrappingRange { start: 0, end: 0x10FFFF }, })), @@ -220,7 +220,7 @@ fn layout_of_uncached<'tcx>( ty::FnPtr(..) => { let mut ptr = scalar_unit(Pointer(dl.instruction_address_space)); ptr.valid_range_mut().start = 1; - tcx.mk_layout(LayoutS::scalar(cx, ptr)) + tcx.mk_layout(LayoutData::scalar(cx, ptr)) } // The never type. @@ -235,7 +235,7 @@ fn layout_of_uncached<'tcx>( let pointee = tcx.normalize_erasing_regions(param_env, pointee); if pointee.is_sized(tcx, param_env) { - return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); + return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr))); } let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() @@ -272,7 +272,7 @@ fn layout_of_uncached<'tcx>( let metadata_layout = cx.layout_of(metadata_ty)?; // If the metadata is a 1-zst, then the pointer is thin. if metadata_layout.is_1zst() { - return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); + return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr))); } let Abi::Scalar(metadata) = metadata_layout.abi else { @@ -285,7 +285,7 @@ fn layout_of_uncached<'tcx>( match unsized_part.kind() { ty::Foreign(..) => { - return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); + return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr))); } ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)), ty::Dynamic(..) => { @@ -337,7 +337,7 @@ fn layout_of_uncached<'tcx>( let largest_niche = if count != 0 { element.largest_niche } else { None }; - tcx.mk_layout(LayoutS { + tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: element.size, count }, abi, @@ -350,7 +350,7 @@ fn layout_of_uncached<'tcx>( } ty::Slice(element) => { let element = cx.layout_of(element)?; - tcx.mk_layout(LayoutS { + tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: element.size, count: 0 }, abi: Abi::Aggregate { sized: false }, @@ -361,7 +361,7 @@ fn layout_of_uncached<'tcx>( unadjusted_abi_align: element.align.abi, }) } - ty::Str => tcx.mk_layout(LayoutS { + ty::Str => tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, abi: Abi::Aggregate { sized: false }, @@ -532,7 +532,7 @@ fn layout_of_uncached<'tcx>( FieldsShape::Array { stride: e_ly.size, count: e_len } }; - tcx.mk_layout(LayoutS { + tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields, abi, @@ -835,7 +835,7 @@ fn coroutine_layout<'tcx>( }; let tag_layout = TyAndLayout { ty: discr_int.to_ty(tcx, /* signed = */ false), - layout: tcx.mk_layout(LayoutS::scalar(cx, tag)), + layout: tcx.mk_layout(LayoutData::scalar(cx, tag)), }; let promoted_layouts = ineligible_locals.iter().map(|local| { @@ -991,7 +991,7 @@ fn coroutine_layout<'tcx>( Abi::Aggregate { sized: true } }; - let layout = tcx.mk_layout(LayoutS { + let layout = tcx.mk_layout(LayoutData { variants: Variants::Multiple { tag, tag_encoding: TagEncoding::Direct, diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 28a81b1b062..aa499995bcb 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -150,6 +150,16 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { }); } + // We extend the param-env of our item with the const conditions of the item, + // since we're allowed to assume `~const` bounds hold within the item itself. + if tcx.is_conditionally_const(def_id) { + predicates.extend( + tcx.const_conditions(def_id).instantiate_identity(tcx).into_iter().map( + |(trait_ref, _)| trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + ), + ); + } + let local_did = def_id.as_local(); let unnormalized_env = diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index f20beb79750..c06a578d8ec 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -496,8 +496,8 @@ where /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity), /// but on an iterator of values that deref to a `TypeFoldable`. - pub fn iter_identity_copied(self) -> impl Iterator::Target> { - self.value.into_iter().map(|v| *v) + pub fn iter_identity_copied(self) -> IterIdentityCopied { + IterIdentityCopied { it: self.value.into_iter() } } } @@ -546,6 +546,44 @@ where { } +pub struct IterIdentityCopied { + it: Iter::IntoIter, +} + +impl Iterator for IterIdentityCopied +where + Iter::Item: Deref, + ::Target: Copy, +{ + type Item = ::Target; + + fn next(&mut self) -> Option { + self.it.next().map(|i| *i) + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl DoubleEndedIterator for IterIdentityCopied +where + Iter::IntoIter: DoubleEndedIterator, + Iter::Item: Deref, + ::Target: Copy, +{ + fn next_back(&mut self) -> Option { + self.it.next_back().map(|i| *i) + } +} + +impl ExactSizeIterator for IterIdentityCopied +where + Iter::IntoIter: ExactSizeIterator, + Iter::Item: Deref, + ::Target: Copy, +{ +} pub struct EarlyBinderIter { t: T, _tcx: PhantomData, diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 07cb8b037ec..3fb7d87bcc4 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -108,7 +108,6 @@ impl CanonicalVarInfo { CanonicalVarKind::PlaceholderRegion(..) => false, CanonicalVarKind::Const(_) => true, CanonicalVarKind::PlaceholderConst(_) => false, - CanonicalVarKind::Effect => true, } } @@ -118,17 +117,15 @@ impl CanonicalVarInfo { CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) | CanonicalVarKind::Const(_) - | CanonicalVarKind::PlaceholderConst(_) - | CanonicalVarKind::Effect => false, + | CanonicalVarKind::PlaceholderConst(_) => false, } } pub fn expect_placeholder_index(self) -> usize { match self.kind { - CanonicalVarKind::Ty(_) - | CanonicalVarKind::Region(_) - | CanonicalVarKind::Const(_) - | CanonicalVarKind::Effect => panic!("expected placeholder: {self:?}"), + CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => { + panic!("expected placeholder: {self:?}") + } CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(), CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(), @@ -161,9 +158,6 @@ pub enum CanonicalVarKind { /// Some kind of const inference variable. Const(UniverseIndex), - /// Effect variable `'?E`. - Effect, - /// A "placeholder" that represents "any const". PlaceholderConst(I::PlaceholderConst), } @@ -180,7 +174,6 @@ impl CanonicalVarKind { CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => { UniverseIndex::ROOT } - CanonicalVarKind::Effect => UniverseIndex::ROOT, } } @@ -205,8 +198,7 @@ impl CanonicalVarKind { CanonicalVarKind::PlaceholderConst(placeholder) => { CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui)) } - CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) - | CanonicalVarKind::Effect => { + CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => { assert_eq!(ui, UniverseIndex::ROOT); self } @@ -311,10 +303,6 @@ impl CanonicalVarValues { Region::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() } - CanonicalVarKind::Effect => { - Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) - .into() - } CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => { Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 7a8c612057f..03dfe547ced 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -84,32 +84,12 @@ rustc_index::newtype_index! { pub struct ConstVid {} } -rustc_index::newtype_index! { - /// An **effect** **v**ariable **ID**. - /// - /// Handling effect infer variables happens separately from const infer variables - /// because we do not want to reuse any of the const infer machinery. If we try to - /// relate an effect variable with a normal one, we would ICE, which can catch bugs - /// where we are not correctly using the effect var for an effect param. Fallback - /// is also implemented on top of having separate effect and normal const variables. - #[encodable] - #[orderable] - #[debug_format = "?{}e"] - #[gate_rustc_only] - pub struct EffectVid {} -} - /// An inference variable for a const, for use in const generics. #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))] pub enum InferConst { /// Infer the value of the const. Var(ConstVid), - /// Infer the value of the effect. - /// - /// For why this is separate from the `Var` variant above, see the - /// documentation on `EffectVid`. - EffectVar(EffectVid), /// A fresh const variable. See `infer::freshen` for more details. Fresh(u32), } @@ -118,7 +98,6 @@ impl fmt::Debug for InferConst { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { InferConst::Var(var) => write!(f, "{var:?}"), - InferConst::EffectVar(var) => write!(f, "{var:?}"), InferConst::Fresh(var) => write!(f, "Fresh({var:?})"), } } @@ -128,7 +107,7 @@ impl fmt::Debug for InferConst { impl HashStable for InferConst { fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { match self { - InferConst::Var(_) | InferConst::EffectVar(_) => { + InferConst::Var(_) => { panic!("const variables should not be hashed: {self:?}") } InferConst::Fresh(i) => i.hash_stable(hcx, hasher), diff --git a/compiler/rustc_type_ir/src/effects.rs b/compiler/rustc_type_ir/src/effects.rs deleted file mode 100644 index ab43533dd86..00000000000 --- a/compiler/rustc_type_ir/src/effects.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::Interner; -use crate::inherent::*; -use crate::lang_items::TraitSolverLangItem::{EffectsMaybe, EffectsNoRuntime, EffectsRuntime}; - -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum EffectKind { - Maybe, - Runtime, - NoRuntime, -} - -impl EffectKind { - pub fn try_from_def_id(cx: I, def_id: I::DefId) -> Option { - if cx.is_lang_item(def_id, EffectsMaybe) { - Some(EffectKind::Maybe) - } else if cx.is_lang_item(def_id, EffectsRuntime) { - Some(EffectKind::Runtime) - } else if cx.is_lang_item(def_id, EffectsNoRuntime) { - Some(EffectKind::NoRuntime) - } else { - None - } - } - - pub fn to_def_id(self, cx: I) -> I::DefId { - let lang_item = match self { - EffectKind::Maybe => EffectsMaybe, - EffectKind::NoRuntime => EffectsNoRuntime, - EffectKind::Runtime => EffectsRuntime, - }; - - cx.require_lang_item(lang_item) - } - - pub fn try_from_ty(cx: I, ty: I::Ty) -> Option { - if let crate::Adt(def, _) = ty.kind() { - Self::try_from_def_id(cx, def.def_id()) - } else { - None - } - } - - pub fn to_ty(self, cx: I) -> I::Ty { - I::Ty::new_adt(cx, cx.adt_def(self.to_def_id(cx)), Default::default()) - } - - /// Returns an intersection between two effect kinds. If one effect kind - /// is more permissive than the other (e.g. `Maybe` vs `Runtime`), this - /// returns the less permissive effect kind (`Runtime`). - pub fn intersection(a: Self, b: Self) -> Option { - use EffectKind::*; - match (a, b) { - (Maybe, x) | (x, Maybe) => Some(x), - (Runtime, Runtime) => Some(Runtime), - (NoRuntime, NoRuntime) => Some(NoRuntime), - (Runtime, NoRuntime) | (NoRuntime, Runtime) => None, - } - } -} diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index dac45ff2aba..72d392ecd7b 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -4,7 +4,6 @@ use smallvec::smallvec; use crate::data_structures::HashSet; use crate::inherent::*; -use crate::lang_items::TraitSolverLangItem; use crate::outlives::{Component, push_outlives_components}; use crate::{self as ty, Interner, Upcast as _}; @@ -130,70 +129,6 @@ impl> Elaborator { return; } - // HACK(effects): The following code is required to get implied bounds for effects associated - // types to work with super traits. - // - // Suppose `data` is a trait predicate with the form `::Fx: EffectsCompat` - // and we know that `trait Tr: ~const SuperTr`, we need to elaborate this predicate into - // `::Fx: EffectsCompat`. - // - // Since the semantics for elaborating bounds about effects is equivalent to elaborating - // bounds about super traits (elaborate `T: Tr` into `T: SuperTr`), we place effects elaboration - // next to super trait elaboration. - if cx.is_lang_item(data.def_id(), TraitSolverLangItem::EffectsCompat) - && matches!(self.mode, Filter::All) - { - // first, ensure that the predicate we've got looks like a `::Fx: EffectsCompat`. - if let ty::Alias(ty::AliasTyKind::Projection, alias_ty) = data.self_ty().kind() - { - // look for effects-level bounds that look like `::Fx: TyCompat<::Fx>` - // on the trait, which is proof to us that `Tr: ~const SuperTr`. We're looking for bounds on the - // associated trait, so we use `explicit_implied_predicates_of` since it gives us more than just - // `Self: SuperTr` bounds. - let bounds = cx.explicit_implied_predicates_of(cx.parent(alias_ty.def_id)); - - // instantiate the implied bounds, so we get `::Fx` and not `::Fx`. - let elaborated = bounds.iter_instantiated(cx, alias_ty.args).filter_map( - |(clause, _)| { - let ty::ClauseKind::Trait(tycompat_bound) = - clause.kind().skip_binder() - else { - return None; - }; - if !cx.is_lang_item( - tycompat_bound.def_id(), - TraitSolverLangItem::EffectsTyCompat, - ) { - return None; - } - - // extract `::Fx` from the `TyCompat` bound. - let supertrait_effects_ty = - tycompat_bound.trait_ref.args.type_at(1); - let ty::Alias(ty::AliasTyKind::Projection, supertrait_alias_ty) = - supertrait_effects_ty.kind() - else { - return None; - }; - - // The self types (`T`) must be equal for `::Fx` and `::Fx`. - if supertrait_alias_ty.self_ty() != alias_ty.self_ty() { - return None; - }; - - // replace the self type in the original bound `::Fx: EffectsCompat` - // to the effects type of the super trait. (`::Fx`) - let elaborated_bound = data.with_self_ty(cx, supertrait_effects_ty); - Some( - elaboratable - .child(bound_clause.rebind(elaborated_bound).upcast(cx)), - ) - }, - ); - self.extend_deduped(elaborated); - } - } - let map_to_child_clause = |(index, (clause, span)): (usize, (I::Clause, I::Span))| { elaboratable.child_with_derived_cause( @@ -220,6 +155,16 @@ impl> Elaborator { ), }; } + // `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| { + elaboratable.child( + trait_ref + .to_host_effect_clause(cx, data.host) + .instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)), + ) + }), + ), ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => { // We know that `T: 'a` for some type `T`. We can // often elaborate this. For example, if we know that diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs index 8a6d37b7d23..cdff77f742d 100644 --- a/compiler/rustc_type_ir/src/error.rs +++ b/compiler/rustc_type_ir/src/error.rs @@ -27,10 +27,9 @@ impl ExpectedFound { #[cfg_attr(feature = "nightly", rustc_pass_by_value)] pub enum TypeError { Mismatch, - ConstnessMismatch(ExpectedFound), - PolarityMismatch(ExpectedFound), - SafetyMismatch(ExpectedFound), - AbiMismatch(ExpectedFound), + PolarityMismatch(#[type_visitable(ignore)] ExpectedFound), + SafetyMismatch(#[type_visitable(ignore)] ExpectedFound), + AbiMismatch(#[type_visitable(ignore)] ExpectedFound), Mutability, ArgumentMutability(usize), TupleSize(ExpectedFound), @@ -73,9 +72,9 @@ impl TypeError { pub fn must_include_note(self) -> bool { use self::TypeError::*; match self { - CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | ConstnessMismatch(_) - | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) - | ArgumentSorts(..) | Sorts(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false, + CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | PolarityMismatch(_) | Mismatch + | AbiMismatch(_) | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_) + | VariadicMismatch(_) | TargetFeatureCast(_) => false, Mutability | ArgumentMutability(_) diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index b9f5cde653e..7c6a3c65ebf 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -38,10 +38,6 @@ pub trait InferCtxtLike: Sized { &self, vid: ty::ConstVid, ) -> ::Const; - fn opportunistic_resolve_effect_var( - &self, - vid: ty::EffectVid, - ) -> ::Const; fn opportunistic_resolve_lt_var( &self, vid: ty::RegionVid, @@ -71,7 +67,6 @@ pub trait InferCtxtLike: Sized { fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid); fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid); fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid); - fn equate_effect_vids_raw(&self, a: ty::EffectVid, b: ty::EffectVid); fn instantiate_ty_var_raw>( &self, @@ -83,11 +78,6 @@ pub trait InferCtxtLike: Sized { ) -> RelateResult; fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue); fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue); - fn instantiate_effect_var_raw( - &self, - vid: ty::EffectVid, - value: ::Const, - ); fn instantiate_const_var_raw>( &self, relation: &mut R, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index f7875bb5152..5af1aa2f8fa 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -208,14 +208,14 @@ pub trait Tys>: fn output(self) -> I::Ty; } -pub trait Abi>: Copy + Debug + Hash + Eq + Relate { +pub trait Abi>: Copy + Debug + Hash + Eq { fn rust() -> Self; /// Whether this ABI is `extern "Rust"`. fn is_rust(self) -> bool; } -pub trait Safety>: Copy + Debug + Hash + Eq + Relate { +pub trait Safety>: Copy + Debug + Hash + Eq { fn safe() -> Self; fn is_safe(self) -> bool; @@ -468,6 +468,14 @@ pub trait Clause>: .transpose() } + fn as_host_effect_clause(self) -> Option>> { + self.kind() + .map_bound( + |clause| if let ty::ClauseKind::HostEffect(t) = clause { Some(t) } else { None }, + ) + .transpose() + } + fn as_projection_clause(self) -> Option>> { self.kind() .map_bound( diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index f06017d7e5c..6a8113b38b7 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -15,9 +15,7 @@ use crate::solve::{ CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode, }; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; -use crate::{ - search_graph, {self as ty}, -}; +use crate::{self as ty, search_graph}; pub trait Interner: Sized @@ -26,6 +24,7 @@ pub trait Interner: + IrPrint> + IrPrint> + IrPrint> + + IrPrint> + IrPrint> + IrPrint> + IrPrint> @@ -173,6 +172,10 @@ pub trait Interner: fn debug_assert_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs); + /// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection` + /// are compatible with the `DefId`. + fn debug_assert_existential_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs); + fn mk_type_list_from_iter(self, args: I) -> T::Output where I: Iterator, @@ -226,6 +229,16 @@ pub trait Interner: def_id: Self::DefId, ) -> ty::EarlyBinder>; + fn is_const_impl(self, def_id: Self::DefId) -> bool; + fn const_conditions( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>>>; + fn implied_const_bounds( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>>>; + fn has_target_features(self, def_id: Self::DefId) -> bool; fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId; diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs index d57d0816680..0c71f3a3df2 100644 --- a/compiler/rustc_type_ir/src/ir_print.rs +++ b/compiler/rustc_type_ir/src/ir_print.rs @@ -2,8 +2,8 @@ use std::fmt; use crate::{ AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig, - Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate, SubtypePredicate, - TraitPredicate, TraitRef, + HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate, + SubtypePredicate, TraitPredicate, TraitRef, }; pub trait IrPrint { @@ -53,6 +53,7 @@ define_display_via_print!( NormalizesTo, SubtypePredicate, CoercePredicate, + HostEffectPredicate, AliasTy, AliasTerm, FnSig, diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index c680c844746..d6ca22a90a4 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -20,13 +20,6 @@ pub enum TraitSolverLangItem { Destruct, DiscriminantKind, DynMetadata, - EffectsCompat, - EffectsIntersection, - EffectsIntersectionOutput, - EffectsMaybe, - EffectsNoRuntime, - EffectsRuntime, - EffectsTyCompat, Fn, FnMut, FnOnce, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 9e6d1f424ba..e7ca24178cb 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -43,7 +43,6 @@ mod macros; mod binder; mod canonical; mod const_kind; -mod effects; mod flags; mod generic_arg; mod infer_ctxt; @@ -67,7 +66,6 @@ pub use canonical::*; #[cfg(feature = "nightly")] pub use codec::*; pub use const_kind::*; -pub use effects::*; pub use flags::*; pub use generic_arg::*; pub use infer_ctxt::*; diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index b613505f826..c3164550348 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -111,6 +111,13 @@ impl ty::Binder> { pub fn def_id(&self) -> I::DefId { self.skip_binder().def_id } + + pub fn to_host_effect_clause(self, cx: I, host: HostPolarity) -> I::Clause { + self.map_bound(|trait_ref| { + ty::ClauseKind::HostEffect(HostEffectPredicate { trait_ref, host }) + }) + .upcast(cx) + } } #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] @@ -289,9 +296,26 @@ impl ty::Binder> { pub struct ExistentialTraitRef { pub def_id: I::DefId, pub args: I::GenericArgs, + /// This field exists to prevent the creation of `ExistentialTraitRef` without + /// calling [`ExistentialTraitRef::new_from_args`]. + _use_existential_trait_ref_new_instead: (), } impl ExistentialTraitRef { + pub fn new_from_args(interner: I, trait_def_id: I::DefId, args: I::GenericArgs) -> Self { + interner.debug_assert_existential_args_compatible(trait_def_id, args); + Self { def_id: trait_def_id, args, _use_existential_trait_ref_new_instead: () } + } + + pub fn new( + interner: I, + trait_def_id: I::DefId, + args: impl IntoIterator>, + ) -> Self { + let args = interner.mk_args_from_iter(args.into_iter().map(Into::into)); + Self::new_from_args(interner, trait_def_id, args) + } + pub fn erase_self_ty(interner: I, trait_ref: TraitRef) -> ExistentialTraitRef { // Assert there is a Self. trait_ref.args.type_at(0); @@ -299,6 +323,7 @@ impl ExistentialTraitRef { ExistentialTraitRef { def_id: trait_ref.def_id, args: interner.mk_args(&trait_ref.args.as_slice()[1..]), + _use_existential_trait_ref_new_instead: (), } } @@ -336,9 +361,33 @@ pub struct ExistentialProjection { pub def_id: I::DefId, pub args: I::GenericArgs, pub term: I::Term, + + /// This field exists to prevent the creation of `ExistentialProjection` + /// without using [`ExistentialProjection::new_from_args`]. + use_existential_projection_new_instead: (), } impl ExistentialProjection { + pub fn new_from_args( + interner: I, + def_id: I::DefId, + args: I::GenericArgs, + term: I::Term, + ) -> ExistentialProjection { + interner.debug_assert_existential_args_compatible(def_id, args); + Self { def_id, args, term, use_existential_projection_new_instead: () } + } + + pub fn new( + interner: I, + def_id: I::DefId, + args: impl IntoIterator>, + term: I::Term, + ) -> ExistentialProjection { + let args = interner.mk_args_from_iter(args.into_iter().map(Into::into)); + Self::new_from_args(interner, def_id, args, term) + } + /// Extracts the underlying existential trait reference from this projection. /// For example, if this is a projection of `exists T. ::Item == X`, /// then this function would return an `exists T. T: Iterator` existential trait @@ -347,7 +396,7 @@ impl ExistentialProjection { let def_id = interner.parent(self.def_id); let args_count = interner.generics_of(def_id).count() - 1; let args = interner.mk_args(&self.args.as_slice()[..args_count]); - ExistentialTraitRef { def_id, args } + ExistentialTraitRef { def_id, args, _use_existential_trait_ref_new_instead: () } } pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate { @@ -372,6 +421,7 @@ impl ExistentialProjection { def_id: projection_predicate.projection_term.def_id, args: interner.mk_args(&projection_predicate.projection_term.args.as_slice()[1..]), term: projection_predicate.term, + use_existential_projection_new_instead: (), } } } @@ -702,6 +752,64 @@ impl fmt::Debug for NormalizesTo { } } +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +pub struct HostEffectPredicate { + pub trait_ref: ty::TraitRef, + pub host: HostPolarity, +} + +impl HostEffectPredicate { + pub fn self_ty(self) -> I::Ty { + self.trait_ref.self_ty() + } + + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + Self { trait_ref: self.trait_ref.with_self_ty(interner, self_ty), ..self } + } + + pub fn def_id(self) -> I::DefId { + self.trait_ref.def_id + } +} + +impl ty::Binder> { + pub fn def_id(self) -> I::DefId { + // Ok to skip binder since trait `DefId` does not care about regions. + self.skip_binder().def_id() + } + + pub fn self_ty(self) -> ty::Binder { + self.map_bound(|trait_ref| trait_ref.self_ty()) + } + + #[inline] + pub fn host(self) -> HostPolarity { + self.skip_binder().host + } +} + +#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +pub enum HostPolarity { + /// May be called in const environments if the callee is const. + Maybe, + /// Always allowed to be called in const environments. + Const, +} + +impl HostPolarity { + pub fn satisfies(self, goal: HostPolarity) -> bool { + match (self, goal) { + (HostPolarity::Const, HostPolarity::Const | HostPolarity::Maybe) => true, + (HostPolarity::Maybe, HostPolarity::Maybe) => true, + (HostPolarity::Maybe, HostPolarity::Const) => false, + } + } +} + /// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates /// whether the `a` type is the type that we should label as "expected" when /// presenting user diagnostics. diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index 46202dbb0f2..21f4456abd1 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -37,6 +37,12 @@ pub enum ClauseKind { /// Constant initializer must evaluate successfully. ConstEvaluatable(I::Const), + + /// Enforces the constness of the predicate we're calling. Like a projection + /// goal from a where clause, it's always going to be paired with a + /// corresponding trait clause; this just enforces the *constness* of that + /// implementation. + HostEffect(ty::HostEffectPredicate), } #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] @@ -110,6 +116,7 @@ impl fmt::Debug for ClauseKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"), + ClauseKind::HostEffect(data) => data.fmt(f), ClauseKind::Trait(a) => a.fmt(f), ClauseKind::RegionOutlives(pair) => pair.fmt(f), ClauseKind::TypeOutlives(pair) => pair.fmt(f), diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index e1f3e493e36..ad17911830b 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -174,12 +174,17 @@ impl Relate for ty::FnSig { ExpectedFound::new(true, a, b) })); } - let safety = relation.relate(a.safety, b.safety)?; - let abi = relation.relate(a.abi, b.abi)?; + + if a.safety != b.safety { + return Err(TypeError::SafetyMismatch(ExpectedFound::new(true, a.safety, b.safety))); + } + + if a.abi != b.abi { + return Err(TypeError::AbiMismatch(ExpectedFound::new(true, a.abi, b.abi))); + }; let a_inputs = a.inputs(); let b_inputs = b.inputs(); - if a_inputs.len() != b_inputs.len() { return Err(TypeError::ArgCount); } @@ -212,26 +217,12 @@ impl Relate for ty::FnSig { Ok(ty::FnSig { inputs_and_output: cx.mk_type_list_from_iter(inputs_and_output)?, c_variadic: a.c_variadic, - safety, - abi, + safety: a.safety, + abi: a.abi, }) } } -impl Relate for ty::BoundConstness { - fn relate>( - _relation: &mut R, - a: ty::BoundConstness, - b: ty::BoundConstness, - ) -> RelateResult { - if a != b { - Err(TypeError::ConstnessMismatch(ExpectedFound::new(true, a, b))) - } else { - Ok(a) - } - } -} - impl Relate for ty::AliasTy { fn relate>( relation: &mut R, @@ -333,7 +324,7 @@ impl Relate for ty::ExistentialProjection { a.args, b.args, )?; - Ok(ty::ExistentialProjection { def_id: a.def_id, args, term }) + Ok(ty::ExistentialProjection::new_from_args(relation.cx(), a.def_id, args, term)) } } } @@ -373,7 +364,7 @@ impl Relate for ty::ExistentialTraitRef { })) } else { let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::ExistentialTraitRef { def_id: a.def_id, args }) + Ok(ty::ExistentialTraitRef::new_from_args(relation.cx(), a.def_id, args)) } } } @@ -659,29 +650,18 @@ impl> Relate for ty::Binder { } } -impl Relate for ty::PredicatePolarity { - fn relate>( - _relation: &mut R, - a: ty::PredicatePolarity, - b: ty::PredicatePolarity, - ) -> RelateResult { - if a != b { - Err(TypeError::PolarityMismatch(ExpectedFound::new(true, a, b))) - } else { - Ok(a) - } - } -} - impl Relate for ty::TraitPredicate { fn relate>( relation: &mut R, a: ty::TraitPredicate, b: ty::TraitPredicate, ) -> RelateResult> { - Ok(ty::TraitPredicate { - trait_ref: relation.relate(a.trait_ref, b.trait_ref)?, - polarity: relation.relate(a.polarity, b.polarity)?, - }) + let trait_ref = relation.relate(a.trait_ref, b.trait_ref)?; + if a.polarity != b.polarity { + return Err(TypeError::PolarityMismatch(ExpectedFound::new( + true, a.polarity, b.polarity, + ))); + } + Ok(ty::TraitPredicate { trait_ref, polarity: a.polarity }) } } diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index 60a953801a4..17a3912730f 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -179,23 +179,9 @@ where Ok(a) } - ( - ty::ConstKind::Infer(ty::InferConst::EffectVar(a_vid)), - ty::ConstKind::Infer(ty::InferConst::EffectVar(b_vid)), - ) => { - infcx.equate_effect_vids_raw(a_vid, b_vid); - Ok(a) - } - // All other cases of inference with other variables are errors. - ( - ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)), - ty::ConstKind::Infer(_), - ) - | ( - ty::ConstKind::Infer(_), - ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)), - ) => { + (ty::ConstKind::Infer(ty::InferConst::Var(_)), ty::ConstKind::Infer(_)) + | (ty::ConstKind::Infer(_), ty::ConstKind::Infer(ty::InferConst::Var(_))) => { panic!( "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}" ) @@ -211,16 +197,6 @@ where Ok(a) } - (ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)), _) => { - infcx.instantiate_effect_var_raw(vid, b); - Ok(b) - } - - (_, ty::ConstKind::Infer(ty::InferConst::EffectVar(vid))) => { - infcx.instantiate_effect_var_raw(vid, a); - Ok(a) - } - (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) if infcx.cx().features().generic_const_exprs() || infcx.next_trait_solver() => { diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs index 138ba8bac88..d0e618dc6f9 100644 --- a/compiler/rustc_type_ir/src/solve/inspect.rs +++ b/compiler/rustc_type_ir/src/solve/inspect.rs @@ -23,9 +23,7 @@ use std::hash::Hash; use derive_where::derive_where; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; -use crate::solve::{ - CandidateSource, CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult, -}; +use crate::solve::{CandidateSource, CanonicalInput, Certainty, Goal, GoalSource, QueryResult}; use crate::{Canonical, CanonicalVarValues, Interner}; /// Some `data` together with information about how they relate to the input @@ -69,15 +67,10 @@ pub struct CanonicalGoalEvaluation { #[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] pub enum CanonicalGoalEvaluationKind { Overflow, - Evaluation { final_revision: CanonicalGoalEvaluationStep }, -} - -#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] -pub struct CanonicalGoalEvaluationStep { - pub instantiated_goal: QueryInput, - - /// The actual evaluation of the goal, always `ProbeKind::Root`. - pub evaluation: Probe, + Evaluation { + /// This is always `ProbeKind::Root`. + final_revision: Probe, + }, } /// A self-contained computation during trait solving. This either diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index b7f6ef4ffbb..499e6d3dd37 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -861,7 +861,11 @@ pub struct TypeAndMut { pub struct FnSig { pub inputs_and_output: I::Tys, pub c_variadic: bool, + #[type_visitable(ignore)] + #[type_foldable(identity)] pub safety: I::Safety, + #[type_visitable(ignore)] + #[type_foldable(identity)] pub abi: I::Abi, } diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index 09a43b17955..10b164eae02 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -372,8 +372,12 @@ pub struct CoroutineClosureSignature { /// Always false pub c_variadic: bool, /// Always `Normal` (safe) + #[type_visitable(ignore)] + #[type_foldable(identity)] pub safety: I::Safety, /// Always `RustCall` + #[type_visitable(ignore)] + #[type_foldable(identity)] pub abi: I::Abi, } diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs index 1a0a2479f6f..aaf69e2648d 100644 --- a/compiler/rustc_type_ir_macros/src/lib.rs +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -1,18 +1,73 @@ -use quote::quote; -use syn::parse_quote; +use quote::{ToTokens, quote}; use syn::visit_mut::VisitMut; +use syn::{Attribute, parse_quote}; use synstructure::decl_derive; decl_derive!( - [TypeFoldable_Generic] => type_foldable_derive + [TypeVisitable_Generic, attributes(type_visitable)] => type_visitable_derive ); decl_derive!( - [TypeVisitable_Generic] => type_visitable_derive + [TypeFoldable_Generic, attributes(type_foldable)] => type_foldable_derive ); decl_derive!( [Lift_Generic] => lift_derive ); +fn has_ignore_attr(attrs: &[Attribute], name: &'static str, meta: &'static str) -> bool { + let mut ignored = false; + attrs.iter().for_each(|attr| { + if !attr.path().is_ident(name) { + return; + } + let _ = attr.parse_nested_meta(|nested| { + if nested.path.is_ident(meta) { + ignored = true; + } + Ok(()) + }); + }); + + ignored +} + +fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + if let syn::Data::Union(_) = s.ast().data { + panic!("cannot derive on union") + } + + if !s.ast().generics.type_params().any(|ty| ty.ident == "I") { + s.add_impl_generic(parse_quote! { I }); + } + + s.filter(|bi| !has_ignore_attr(&bi.ast().attrs, "type_visitable", "ignore")); + + s.add_where_predicate(parse_quote! { I: Interner }); + s.add_bounds(synstructure::AddBounds::Fields); + let body_visit = s.each(|bind| { + quote! { + match ::rustc_ast_ir::visit::VisitorResult::branch( + ::rustc_type_ir::visit::TypeVisitable::visit_with(#bind, __visitor) + ) { + ::core::ops::ControlFlow::Continue(()) => {}, + ::core::ops::ControlFlow::Break(r) => { + return ::rustc_ast_ir::visit::VisitorResult::from_residual(r); + }, + } + } + }); + s.bind_with(|_| synstructure::BindStyle::Move); + + s.bound_impl(quote!(::rustc_type_ir::visit::TypeVisitable), quote! { + fn visit_with<__V: ::rustc_type_ir::visit::TypeVisitor>( + &self, + __visitor: &mut __V + ) -> __V::Result { + match *self { #body_visit } + <__V::Result as ::rustc_ast_ir::visit::VisitorResult>::output() + } + }) +} + fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { if let syn::Data::Union(_) = s.ast().data { panic!("cannot derive on union") @@ -29,12 +84,23 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke let bindings = vi.bindings(); vi.construct(|_, index| { let bind = &bindings[index]; - quote! { - ::rustc_type_ir::fold::TypeFoldable::try_fold_with(#bind, __folder)? + + // retain value of fields with #[type_foldable(identity)] + if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") { + bind.to_token_stream() + } else { + quote! { + ::rustc_type_ir::fold::TypeFoldable::try_fold_with(#bind, __folder)? + } } }) }); + // We filter fields which get ignored and don't require them to implement + // `TypeFoldable`. We do so after generating `body_fold` as we still need + // to generate code for them. + s.filter(|bi| !has_ignore_attr(&bi.ast().attrs, "type_foldable", "identity")); + s.add_bounds(synstructure::AddBounds::Fields); s.bound_impl(quote!(::rustc_type_ir::fold::TypeFoldable), quote! { fn try_fold_with<__F: ::rustc_type_ir::fold::FallibleTypeFolder>( self, @@ -113,39 +179,3 @@ fn lift(mut ty: syn::Type) -> syn::Type { ty } - -fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { - if let syn::Data::Union(_) = s.ast().data { - panic!("cannot derive on union") - } - - if !s.ast().generics.type_params().any(|ty| ty.ident == "I") { - s.add_impl_generic(parse_quote! { I }); - } - - s.add_where_predicate(parse_quote! { I: Interner }); - s.add_bounds(synstructure::AddBounds::Fields); - let body_visit = s.each(|bind| { - quote! { - match ::rustc_ast_ir::visit::VisitorResult::branch( - ::rustc_type_ir::visit::TypeVisitable::visit_with(#bind, __visitor) - ) { - ::core::ops::ControlFlow::Continue(()) => {}, - ::core::ops::ControlFlow::Break(r) => { - return ::rustc_ast_ir::visit::VisitorResult::from_residual(r); - }, - } - } - }); - s.bind_with(|_| synstructure::BindStyle::Move); - - s.bound_impl(quote!(::rustc_type_ir::visit::TypeVisitable), quote! { - fn visit_with<__V: ::rustc_type_ir::visit::TypeVisitor>( - &self, - __visitor: &mut __V - ) -> __V::Result { - match *self { #body_visit } - <__V::Result as ::rustc_ast_ir::visit::VisitorResult>::output() - } - }) -} diff --git a/compiler/stable_mir/README.md b/compiler/stable_mir/README.md index 31dee955f49..ab2546e377a 100644 --- a/compiler/stable_mir/README.md +++ b/compiler/stable_mir/README.md @@ -1,93 +1,33 @@ -This crate is regularly synced with its mirror in the rustc repo at `compiler/rustc_smir`. +This crate is currently developed in-tree together with the compiler. -We use `git subtree` for this to preserve commits and allow the rustc repo to -edit these crates without having to touch this repo. This keeps the crates compiling -while allowing us to independently work on them here. The effort of keeping them in -sync is pushed entirely onto us, without affecting rustc workflows negatively. -This may change in the future, but changes to policy should only be done via a -compiler team MCP. +Our goal is to start publishing `stable_mir` into crates.io. +Until then, users will use this as any other rustc crate, by installing +the rustup component `rustc-dev`, and declaring `stable-mir` as an external crate. -## Instructions for working on this crate locally - -Since the crate is the same in the rustc repo and here, the dependencies on rustc_* crates -will only either work here or there, but never in both places at the same time. Thus we use -optional dependencies on the rustc_* crates, requiring local development to use - -``` -cargo build --no-default-features -Zavoid-dev-deps -``` - -in order to compile successfully. - -## Instructions for syncing - -### Updating this repository - -In the rustc repo, execute - -``` -git subtree push --prefix=compiler/rustc_smir url_to_your_fork_of_project_stable_mir some_feature_branch -``` - -and then open a PR of your `some_feature_branch` against https://github.com/rust-lang/project-stable-mir - -### Updating the rustc library - -First we need to bump our stack limit, as the rustc repo otherwise quickly hits that: - -``` -ulimit -s 60000 -``` - -#### Maximum function recursion depth (1000) reached - -Then we need to disable `dash` as the default shell for sh scripts, as otherwise we run into a -hard limit of a recursion depth of 1000: - -``` -sudo dpkg-reconfigure dash -``` - -and then select `No` to disable dash. - - -#### Patching your `git worktree` - -The regular git worktree does not scale to repos of the size of the rustc repo. -So download the `git-subtree.sh` from https://github.com/gitgitgadget/git/pull/493/files and run - -``` -sudo cp --backup /path/to/patched/git-subtree.sh /usr/lib/git-core/git-subtree -sudo chmod --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree -sudo chown --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree -``` - -#### Actually doing a sync - -In the rustc repo, execute - -``` -git subtree pull --prefix=compiler/rustc_smir https://github.com/rust-lang/project-stable-mir smir -``` - -Note: only ever sync to rustc from the project-stable-mir's `smir` branch. Do not sync with your own forks. - -Then open a PR against rustc just like a regular PR. +See the StableMIR ["Getting Started"](https://rust-lang.github.io/project-stable-mir/getting-started.html) +guide for more information. ## Stable MIR Design -The stable-mir will follow a similar approach to proc-macro2. It’s -implementation will eventually be broken down into two main crates: +The stable-mir will follow a similar approach to proc-macro2. Its +implementation is split between two main crates: - `stable_mir`: Public crate, to be published on crates.io, which will contain -the stable data structure as well as proxy APIs to make calls to the -compiler. -- `rustc_smir`: The compiler crate that will translate from internal MIR to -SMIR. This crate will also implement APIs that will be invoked by -stable-mir to query the compiler for more information. +the stable data structure as well as calls to `rustc_smir` APIs. The +translation between stable and internal constructs will also be done in this crate, +however, this is currently implemented in the `rustc_smir` crate.[^translation]. +- `rustc_smir`: This crate implements the public APIs to the compiler. +It is responsible for gathering all the information requested, and providing +the data in its unstable form. -This will help tools to communicate with the rust compiler via stable APIs. Tools will depend on -`stable_mir` crate, which will invoke the compiler using APIs defined in `rustc_smir`. I.e.: +[^translation]: This is currently implemented in the `rustc_smir` crate, +but we are working to change that. + +I.e., +tools will depend on `stable_mir` crate, +which will invoke the compiler using APIs defined in `rustc_smir`. + +I.e.: ``` ┌──────────────────────────────────┐ ┌──────────────────────────────────┐ @@ -104,9 +44,3 @@ This will help tools to communicate with the rust compiler via stable APIs. Tool More details can be found here: https://hackmd.io/XhnYHKKuR6-LChhobvlT-g?view - -For now, the code for these two crates are in separate modules of this crate. -The modules have the same name for simplicity. We also have a third module, -`rustc_internal` which will expose APIs and definitions that allow users to -gather information from internal MIR constructs that haven't been exposed in -the `stable_mir` module. diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 9e6fbc8ea0c..8db1258b65f 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -1393,7 +1393,6 @@ pub struct Generics { pub param_def_id_to_index: Vec<(GenericDef, u32)>, pub has_self: bool, pub has_late_bound_regions: Option, - pub host_effect_index: Option, } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] diff --git a/config.example.toml b/config.example.toml index 168ac353cff..d5b904ebf3d 100644 --- a/config.example.toml +++ b/config.example.toml @@ -84,6 +84,9 @@ # Wheter to build Enzyme as AutoDiff backend. #enzyme = false +# Whether to build LLVM with support for it's gpu offload runtime. +#offload = false + # Indicates whether ccache is used when building LLVM. Set to `true` to use the first `ccache` in # PATH, or set an absolute path to use a specific version. #ccache = false @@ -419,6 +422,9 @@ # passed to cargo invocations. #jobs = 0 +# What custom diff tool to use for displaying compiletest tests. +#compiletest-diff-tool = + # ============================================================================= # General install configuration options # ============================================================================= diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 3e791416820..bc354650a8e 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -196,7 +196,7 @@ use core::marker::{Tuple, Unsize}; use core::mem::{self, SizedTypeProperties}; use core::ops::{ AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, - DerefPure, DispatchFromDyn, Receiver, + DerefPure, DispatchFromDyn, LegacyReceiver, }; use core::pin::{Pin, PinCoerceUnsized}; use core::ptr::{self, NonNull, Unique}; @@ -2378,8 +2378,8 @@ impl DerefMut for Box { #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl DerefPure for Box {} -#[unstable(feature = "receiver_trait", issue = "none")] -impl Receiver for Box {} +#[unstable(feature = "legacy_receiver_trait", issue = "none")] +impl LegacyReceiver for Box {} #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Box { diff --git a/library/alloc/src/collections/binary_heap/tests.rs b/library/alloc/src/collections/binary_heap/tests.rs index c18318724a4..ad0a020a1a9 100644 --- a/library/alloc/src/collections/binary_heap/tests.rs +++ b/library/alloc/src/collections/binary_heap/tests.rs @@ -350,7 +350,7 @@ fn test_drain_forget() { mem::forget(it); })) .unwrap(); - // Behaviour after leaking is explicitly unspecified and order is arbitrary, + // Behavior after leaking is explicitly unspecified and order is arbitrary, // so it's fine if these start failing, but probably worth knowing. assert!(q.is_empty()); assert_eq!(a.dropped() + b.dropped() + c.dropped(), 1); @@ -377,7 +377,7 @@ fn test_drain_sorted_forget() { mem::forget(it); })) .unwrap(); - // Behaviour after leaking is explicitly unspecified, + // Behavior after leaking is explicitly unspecified, // so it's fine if these start failing, but probably worth knowing. assert_eq!(q.len(), 2); assert_eq!(a.dropped(), 0); diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs index 47372938fbe..d137d2721ee 100644 --- a/library/alloc/src/collections/btree/append.rs +++ b/library/alloc/src/collections/btree/append.rs @@ -79,7 +79,7 @@ impl Root { } open_node.push(key, value, right_tree); - // Go down to the right-most leaf again. + // Go down to the rightmost leaf again. cur_node = open_node.forget_type().last_leaf_edge().into_node(); } diff --git a/library/alloc/src/collections/btree/fix.rs b/library/alloc/src/collections/btree/fix.rs index 95fb52b7f77..09edea3555a 100644 --- a/library/alloc/src/collections/btree/fix.rs +++ b/library/alloc/src/collections/btree/fix.rs @@ -102,7 +102,7 @@ impl Root { pub fn fix_right_border_of_plentiful(&mut self) { let mut cur_node = self.borrow_mut(); while let Internal(internal) = cur_node.force() { - // Check if right-most child is underfull. + // Check if rightmost child is underfull. let mut last_kv = internal.last_kv().consider_for_balancing(); debug_assert!(last_kv.left_child_len() >= MIN_LEN * 2); let right_child_len = last_kv.right_child_len(); diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index d0e413778f8..db16d82be7d 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1216,7 +1216,7 @@ mod test_extract_if { { let mut it = map.extract_if(|dummy, _| dummy.query(true)); catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err(); - // Iterator behaviour after a panic is explicitly unspecified, + // Iterator behavior after a panic is explicitly unspecified, // so this is just the current implementation: let result = catch_unwind(AssertUnwindSafe(|| it.next())); assert!(matches!(result, Ok(None))); diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 5c513d34fc9..2a853ef4216 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -1521,7 +1521,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { right_node.val_area_mut(..count - 1), ); - // Move the left-most stolen pair to the parent. + // Move the leftmost stolen pair to the parent. let k = left_node.key_area_mut(new_left_len).assume_init_read(); let v = left_node.val_area_mut(new_left_len).assume_init_read(); let (k, v) = self.parent.replace_kv(k, v); @@ -1570,7 +1570,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { // Move leaf data. { - // Move the right-most stolen pair to the parent. + // Move the rightmost stolen pair to the parent. let k = right_node.key_area_mut(count - 1).assume_init_read(); let v = right_node.val_area_mut(count - 1).assume_init_read(); let (k, v) = self.parent.replace_kv(k, v); diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 50a5f3c5b1e..dd9dfa3f5e2 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -129,6 +129,7 @@ #![feature(iter_advance_by)] #![feature(iter_next_chunk)] #![feature(layout_for_ptr)] +#![feature(legacy_receiver_trait)] #![feature(local_waker)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array_transpose)] @@ -138,7 +139,6 @@ #![feature(ptr_internals)] #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] -#![feature(receiver_trait)] #![feature(set_ptr_value)] #![feature(sized_type_properties)] #![feature(slice_from_ptr_range)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 45de0617f33..85a9120c7e2 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -103,7 +103,7 @@ impl RawVec { /// `RawVec` with capacity `usize::MAX`. Useful for implementing /// delayed allocation. #[must_use] - #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))] pub const fn new() -> Self { Self::new_in(Global) } @@ -179,7 +179,7 @@ impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. #[inline] - #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))] pub const fn new_in(alloc: A) -> Self { Self { inner: RawVecInner::new_in(alloc, align_of::()), _marker: PhantomData } } @@ -409,7 +409,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { impl RawVecInner { #[inline] - #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))] const fn new_in(alloc: A, align: usize) -> Self { let ptr = unsafe { core::mem::transmute(align) }; // `cap: 0` means "unallocated". zero-sized types are ignored. diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index e98ae7c31ad..9fdd51ce331 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -252,7 +252,7 @@ use core::intrinsics::abort; use core::iter; use core::marker::{PhantomData, Unsize}; use core::mem::{self, ManuallyDrop, align_of_val_raw}; -use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver}; +use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; #[cfg(not(no_global_oom_handling))] use core::pin::Pin; @@ -2222,8 +2222,8 @@ unsafe impl PinCoerceUnsized for Weak {} #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl DerefPure for Rc {} -#[unstable(feature = "receiver_trait", issue = "none")] -impl Receiver for Rc {} +#[unstable(feature = "legacy_receiver_trait", issue = "none")] +impl LegacyReceiver for Rc {} #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc { @@ -2312,7 +2312,16 @@ impl Default for Rc { /// ``` #[inline] fn default() -> Rc { - Rc::new(Default::default()) + unsafe { + Self::from_inner( + Box::leak(Box::write(Box::new_uninit(), RcInner { + strong: Cell::new(1), + weak: Cell::new(1), + value: T::default(), + })) + .into(), + ) + } } } @@ -3066,7 +3075,7 @@ impl Weak { /// /// drop(strong); /// // But not any more. We can do weak.as_ptr(), but accessing the pointer would lead to - /// // undefined behaviour. + /// // undefined behavior. /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); /// ``` /// diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 52ceb8b45f9..26c1ba2a5c4 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -269,8 +269,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn replace(&self, from: P, to: &str) -> String { - // Fast path for ASCII to ASCII case. - + // Fast path for replacing a single ASCII character with another. if let Some(from_byte) = match from.as_utf8_pattern() { Some(Utf8Pattern::StringPattern([from_byte])) => Some(*from_byte), Some(Utf8Pattern::CharPattern(c)) => c.as_ascii().map(|ascii_char| ascii_char.to_u8()), @@ -280,8 +279,13 @@ impl str { return unsafe { replace_ascii(self.as_bytes(), from_byte, *to_byte) }; } } - - let mut result = String::new(); + // Set result capacity to self.len() when from.len() <= to.len() + let default_capacity = match from.as_utf8_pattern() { + Some(Utf8Pattern::StringPattern(s)) if s.len() <= to.len() => self.len(), + Some(Utf8Pattern::CharPattern(c)) if c.len_utf8() <= to.len() => self.len(), + _ => 0, + }; + let mut result = String::with_capacity(default_capacity); let mut last_end = 0; for (start, part) in self.match_indices(from) { result.push_str(unsafe { self.get_unchecked(last_end..start) }); diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index acbc325a514..15a1b0f2834 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -18,7 +18,7 @@ use core::intrinsics::abort; use core::iter; use core::marker::{PhantomData, Unsize}; use core::mem::{self, ManuallyDrop, align_of_val_raw}; -use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver}; +use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, LegacyReceiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; use core::pin::{Pin, PinCoerceUnsized}; use core::ptr::{self, NonNull}; @@ -804,7 +804,7 @@ impl Arc { // observe a non-zero strong count. Therefore we need at least "Release" ordering // in order to synchronize with the `compare_exchange_weak` in `Weak::upgrade`. // - // "Acquire" ordering is not required. When considering the possible behaviours + // "Acquire" ordering is not required. When considering the possible behaviors // of `data_fn` we only need to look at what it could do with a reference to a // non-upgradeable `Weak`: // - It can *clone* the `Weak`, increasing the weak reference count. @@ -2189,8 +2189,8 @@ unsafe impl PinCoerceUnsized for Weak {} #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl DerefPure for Arc {} -#[unstable(feature = "receiver_trait", issue = "none")] -impl Receiver for Arc {} +#[unstable(feature = "legacy_receiver_trait", issue = "none")] +impl LegacyReceiver for Arc {} #[cfg(not(no_global_oom_handling))] impl Arc { @@ -2788,7 +2788,7 @@ impl Weak { /// /// drop(strong); /// // But not any more. We can do weak.as_ptr(), but accessing the pointer would lead to - /// // undefined behaviour. + /// // undefined behavior. /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); /// ``` /// @@ -3447,13 +3447,16 @@ impl Default for Arc { /// assert_eq!(*x, 0); /// ``` fn default() -> Arc { - let x = Box::into_raw(Box::write(Box::new_uninit(), ArcInner { - strong: atomic::AtomicUsize::new(1), - weak: atomic::AtomicUsize::new(1), - data: T::default(), - })); - // SAFETY: `Box::into_raw` consumes the `Box` and never returns null - unsafe { Self::from_inner(NonNull::new_unchecked(x)) } + unsafe { + Self::from_inner( + Box::leak(Box::write(Box::new_uninit(), ArcInner { + strong: atomic::AtomicUsize::new(1), + weak: atomic::AtomicUsize::new(1), + data: T::default(), + })) + .into(), + ) + } } } diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs index bcc5bf4d65b..ba57d940d8c 100644 --- a/library/alloc/src/vec/is_zero.rs +++ b/library/alloc/src/vec/is_zero.rs @@ -172,7 +172,7 @@ macro_rules! impl_is_zero_option_of_bool { fn is_zero(&self) -> bool { // SAFETY: This is *not* a stable layout guarantee, but // inside `core` we're allowed to rely on the current rustc - // behaviour that options of bools will be one byte with + // behavior that options of bools will be one byte with // no padding, so long as they're nested less than 254 deep. let raw: u8 = unsafe { core::mem::transmute(*self) }; raw == 0 diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs index bfc31a626fa..544f60da587 100644 --- a/library/alloc/tests/boxed.rs +++ b/library/alloc/tests/boxed.rs @@ -4,6 +4,7 @@ use core::mem::MaybeUninit; use core::ptr::NonNull; #[test] +#[cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))] fn uninitialized_zero_size_box() { assert_eq!( &*Box::<()>::new_uninit() as *const _, diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs index 3f1c58bbd72..32d15c386cb 100644 --- a/library/core/benches/lib.rs +++ b/library/core/benches/lib.rs @@ -8,7 +8,6 @@ #![feature(iter_array_chunks)] #![feature(iter_next_chunk)] #![feature(iter_advance_by)] -#![feature(isqrt)] extern crate test; diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 68f00d07529..8f48af24557 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -173,7 +173,7 @@ pub unsafe trait GlobalAlloc { /// # Safety /// /// The caller has to ensure that `layout` has non-zero size. Like `alloc` - /// zero sized `layout` can result in undefined behaviour. + /// zero sized `layout` can result in undefined behavior. /// However the allocated block of memory is guaranteed to be initialized. /// /// # Errors @@ -234,7 +234,7 @@ pub unsafe trait GlobalAlloc { /// does not overflow `isize` (i.e., the rounded value must be less than or /// equal to `isize::MAX`). /// - /// If these are not followed, undefined behaviour can result. + /// If these are not followed, undefined behavior can result. /// /// (Extension subtraits might provide more specific bounds on /// behavior, e.g., guarantee a sentinel address or a null pointer diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index fca32b9d3c5..95cf9427e02 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -66,7 +66,6 @@ impl Layout { #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")] #[inline] - #[rustc_allow_const_fn_unstable(ptr_alignment_type)] pub const fn from_size_align(size: usize, align: usize) -> Result { if Layout::is_size_align_valid(size, align) { // SAFETY: Layout::is_size_align_valid checks the preconditions for this call. @@ -127,7 +126,6 @@ impl Layout { #[rustc_const_stable(feature = "const_alloc_layout_unchecked", since = "1.36.0")] #[must_use] #[inline] - #[rustc_allow_const_fn_unstable(ptr_alignment_type)] pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { assert_unsafe_precondition!( check_library_ub, @@ -159,7 +157,7 @@ impl Layout { #[must_use = "this returns the minimum alignment, \ without modifying the layout"] #[inline] - #[rustc_allow_const_fn_unstable(ptr_alignment_type)] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(ptr_alignment_type))] pub const fn align(&self) -> usize { self.align.as_usize() } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index e1fa43296d0..7e6c042274d 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -304,6 +304,7 @@ pub use once::OnceCell; /// ``` /// /// See the [module-level documentation](self) for more. +#[cfg_attr(not(test), rustc_diagnostic_item = "Cell")] #[stable(feature = "rust1", since = "1.0.0")] #[repr(transparent)] #[rustc_pub_transparent] @@ -1221,7 +1222,7 @@ impl RefCell { /// Unlike `RefCell::borrow`, this method is unsafe because it does not /// return a `Ref`, thus leaving the borrow flag untouched. Mutably /// borrowing the `RefCell` while the reference returned by this method - /// is alive is undefined behaviour. + /// is alive is undefined behavior. /// /// # Examples /// @@ -2287,6 +2288,7 @@ impl SyncUnsafeCell { /// Unwraps the value, consuming the cell. #[inline] + #[rustc_const_unstable(feature = "sync_unsafe_cell", issue = "95439")] pub const fn into_inner(self) -> T { self.value.into_inner() } diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index d323fbeac9c..5ac33516684 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -79,6 +79,7 @@ impl T> LazyCell { /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string())); /// ``` #[unstable(feature = "lazy_cell_into_inner", issue = "125623")] + #[rustc_const_unstable(feature = "lazy_cell_into_inner", issue = "125623")] pub const fn into_inner(this: Self) -> Result { match this.state.into_inner() { State::Init(data) => Ok(data), diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 30c0fff3104..206bbf5690e 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -320,8 +320,9 @@ impl char { /// '1'.is_digit(37); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_char_is_digit", issue = "132241")] #[inline] - pub fn is_digit(self, radix: u32) -> bool { + pub const fn is_digit(self, radix: u32) -> bool { self.to_digit(radix).is_some() } @@ -1770,7 +1771,7 @@ const fn len_utf16(code: u32) -> usize { /// Panics if the buffer is not large enough. /// A buffer of length four is large enough to encode any `char`. #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] -#[rustc_const_stable(feature = "const_char_encode_utf8", since = "1.83.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_char_encode_utf8", since = "1.83.0"))] #[doc(hidden)] #[inline] #[rustc_allow_const_fn_unstable(const_eval_select)] diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 4377b4993b8..5a3b9365cd2 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -380,7 +380,7 @@ pub struct AssertParamIsEq { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] // This is a lang item only so that `BinOp::Cmp` in MIR can return it. -// It has no special behaviour, but does require that the three variants +// It has no special behavior, but does require that the three variants // `Less`/`Equal`/`Greater` remain `-1_i8`/`0_i8`/`+1_i8` respectively. #[lang = "Ordering"] #[repr(i8)] diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 15b00b9aa44..93dd351b029 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -137,11 +137,11 @@ enum FromBytesWithNulErrorKind { // FIXME: const stability attributes should not be required here, I think impl FromBytesWithNulError { - #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0"))] const fn interior_nul(pos: usize) -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) } } - #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0"))] const fn not_nul_terminated() -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated } } @@ -464,7 +464,9 @@ impl CStr { /// behavior when `ptr` is used inside the `unsafe` block: /// /// ```no_run - /// # #![allow(unused_must_use)] #![allow(temporary_cstring_as_ptr)] + /// # #![allow(unused_must_use)] + /// # #![cfg_attr(bootstrap, expect(temporary_cstring_as_ptr))] + /// # #![cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))] /// use std::ffi::CString; /// /// // Do not do this: @@ -730,7 +732,7 @@ impl AsRef for CStr { /// located within `isize::MAX` from `ptr`. #[inline] #[unstable(feature = "cstr_internals", issue = "none")] -#[rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0"))] #[rustc_allow_const_fn_unstable(const_eval_select)] const unsafe fn strlen(ptr: *const c_char) -> usize { const fn strlen_ct(s: *const c_char) -> usize { diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 4cbcfb07795..f3b54230bc1 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -333,7 +333,10 @@ pub struct Arguments<'a> { #[unstable(feature = "fmt_internals", issue = "none")] impl<'a> Arguments<'a> { #[inline] - #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] + #[cfg_attr( + bootstrap, + rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none") + )] pub const fn new_const(pieces: &'a [&'static str; N]) -> Self { const { assert!(N <= 1) }; Arguments { pieces, fmt: None, args: &[] } @@ -438,6 +441,7 @@ impl<'a> Arguments<'a> { #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")] #[must_use] #[inline] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] pub const fn as_str(&self) -> Option<&'static str> { match (self.pieces, self.args) { ([], []) => Some(""), diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index eee4a9e4c6c..af6f0da88de 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -94,11 +94,11 @@ pub struct Argument<'a> { } #[rustc_diagnostic_item = "ArgumentMethods"] -impl<'a> Argument<'a> { +impl Argument<'_> { #[inline(always)] - fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> { + fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'a> { Argument { - // INVARIANT: this creates an `ArgumentType<'b>` from a `&'b T` and + // INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and // a `fn(&T, ...)`, so the invariant is maintained. ty: ArgumentType::Placeholder { value: NonNull::from(x).cast(), @@ -110,43 +110,43 @@ impl<'a> Argument<'a> { } #[inline(always)] - pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'b> { + pub fn new_display(x: &T) -> Argument<'_> { Self::new(x, Display::fmt) } #[inline(always)] - pub fn new_debug<'b, T: Debug>(x: &'b T) -> Argument<'b> { + pub fn new_debug(x: &T) -> Argument<'_> { Self::new(x, Debug::fmt) } #[inline(always)] - pub fn new_debug_noop<'b, T: Debug>(x: &'b T) -> Argument<'b> { + pub fn new_debug_noop(x: &T) -> Argument<'_> { Self::new(x, |_, _| Ok(())) } #[inline(always)] - pub fn new_octal<'b, T: Octal>(x: &'b T) -> Argument<'b> { + pub fn new_octal(x: &T) -> Argument<'_> { Self::new(x, Octal::fmt) } #[inline(always)] - pub fn new_lower_hex<'b, T: LowerHex>(x: &'b T) -> Argument<'b> { + pub fn new_lower_hex(x: &T) -> Argument<'_> { Self::new(x, LowerHex::fmt) } #[inline(always)] - pub fn new_upper_hex<'b, T: UpperHex>(x: &'b T) -> Argument<'b> { + pub fn new_upper_hex(x: &T) -> Argument<'_> { Self::new(x, UpperHex::fmt) } #[inline(always)] - pub fn new_pointer<'b, T: Pointer>(x: &'b T) -> Argument<'b> { + pub fn new_pointer(x: &T) -> Argument<'_> { Self::new(x, Pointer::fmt) } #[inline(always)] - pub fn new_binary<'b, T: Binary>(x: &'b T) -> Argument<'b> { + pub fn new_binary(x: &T) -> Argument<'_> { Self::new(x, Binary::fmt) } #[inline(always)] - pub fn new_lower_exp<'b, T: LowerExp>(x: &'b T) -> Argument<'b> { + pub fn new_lower_exp(x: &T) -> Argument<'_> { Self::new(x, LowerExp::fmt) } #[inline(always)] - pub fn new_upper_exp<'b, T: UpperExp>(x: &'b T) -> Argument<'b> { + pub fn new_upper_exp(x: &T) -> Argument<'_> { Self::new(x, UpperExp::fmt) } #[inline(always)] diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index a69f0afdb0a..78df51f2bc4 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -506,7 +506,7 @@ pub const fn black_box(dummy: T) -> T { /// # } /// ``` #[unstable(feature = "hint_must_use", issue = "94745")] -#[rustc_const_unstable(feature = "hint_must_use", issue = "94745")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "hint_must_use", issue = "94745"))] #[must_use] // <-- :) #[inline(always)] pub const fn must_use(value: T) -> T { diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 97e727633c5..fc09da7bcbc 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -14,9 +14,10 @@ //! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, -//! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done -//! without T-lang consultation, because it bakes a feature into the language that cannot be -//! replicated in user code without compiler support. +//! `#[rustc_const_stable_indirect]` needs to be added to the intrinsic (`#[rustc_const_unstable]` +//! can be removed then). Such a change should not be done without T-lang consultation, because it +//! may bake a feature into the language that cannot be replicated in user code without compiler +//! support. //! //! # Volatiles //! @@ -930,7 +931,7 @@ extern "rust-intrinsic" { /// on most platforms. /// On Unix, the /// process will probably terminate with a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or - /// `SIGBUS`. The precise behaviour is not guaranteed and not stable. + /// `SIGBUS`. The precise behavior is not guaranteed and not stable. #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn abort() -> !; @@ -943,7 +944,11 @@ extern "rust-intrinsic" { /// reach code marked with this function. /// /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`]. - #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")] + #[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0") + )] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unreachable() -> !; } @@ -958,7 +963,8 @@ extern "rust-intrinsic" { /// own, or if it does not enable any significant optimizations. /// /// The stabilized version of this intrinsic is [`core::hint::assert_unchecked`]. -#[rustc_const_stable(feature = "const_assume", since = "1.77.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assume", since = "1.77.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] @@ -980,7 +986,11 @@ pub const unsafe fn assume(b: bool) { /// any safety invariants. /// /// This intrinsic does not have a stable counterpart. -#[rustc_const_unstable(feature = "const_likely", issue = "none")] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") +)] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_nounwind] @@ -1000,7 +1010,11 @@ pub const fn likely(b: bool) -> bool { /// any safety invariants. /// /// This intrinsic does not have a stable counterpart. -#[rustc_const_unstable(feature = "const_likely", issue = "none")] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") +)] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_nounwind] @@ -1041,7 +1055,8 @@ extern "rust-intrinsic" { /// This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_stable(feature = "const_assert_type", since = "1.59.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn assert_inhabited(); @@ -1050,7 +1065,8 @@ extern "rust-intrinsic" { /// zero-initialization: This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_stable(feature = "const_assert_type2", since = "1.75.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn assert_zero_valid(); @@ -1058,7 +1074,8 @@ extern "rust-intrinsic" { /// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_stable(feature = "const_assert_type2", since = "1.75.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn assert_mem_uninitialized_valid(); @@ -1071,7 +1088,8 @@ extern "rust-intrinsic" { /// any safety invariants. /// /// Consider using [`core::panic::Location::caller`] instead. - #[rustc_const_stable(feature = "const_caller_location", since = "1.79.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn caller_location() -> &'static crate::panic::Location<'static>; @@ -1085,7 +1103,8 @@ extern "rust-intrinsic" { /// it does not require an `unsafe` block. /// Therefore, implementations must not require the user to uphold /// any safety invariants. - #[rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn forget(_: T); @@ -1384,14 +1403,15 @@ extern "rust-intrinsic" { /// Like [`transmute`], but even less checked at compile-time: rather than /// giving an error for `size_of::() != size_of::()`, it's - /// **Undefined Behaviour** at runtime. + /// **Undefined Behavior** at runtime. /// /// Prefer normal `transmute` where possible, for the extra checking, since /// both do exactly the same thing at runtime, if they both compile. /// /// This is not expected to ever be exposed directly to users, rather it /// may eventually be exposed through some more-constrained API. - #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn transmute_unchecked(src: Src) -> Dst; @@ -1408,7 +1428,8 @@ extern "rust-intrinsic" { /// any safety invariants. /// /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). - #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn needs_drop() -> bool; @@ -1430,7 +1451,8 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is [`pointer::offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] - #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn offset(dst: Ptr, offset: Delta) -> Ptr; @@ -1448,7 +1470,8 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is [`pointer::wrapping_offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] - #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn arith_offset(dst: *const T, offset: isize) -> *const T; @@ -2131,7 +2154,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `count_ones` method. For example, /// [`u32::count_ones`] - #[rustc_const_stable(feature = "const_ctpop", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn ctpop(x: T) -> u32; @@ -2172,7 +2196,8 @@ extern "rust-intrinsic" { /// let num_leading = ctlz(x); /// assert_eq!(num_leading, 16); /// ``` - #[rustc_const_stable(feature = "const_ctlz", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn ctlz(x: T) -> u32; @@ -2194,7 +2219,8 @@ extern "rust-intrinsic" { /// let num_leading = unsafe { ctlz_nonzero(x) }; /// assert_eq!(num_leading, 3); /// ``` - #[rustc_const_stable(feature = "constctlz", since = "1.50.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn ctlz_nonzero(x: T) -> u32; @@ -2234,7 +2260,8 @@ extern "rust-intrinsic" { /// let num_trailing = cttz(x); /// assert_eq!(num_trailing, 16); /// ``` - #[rustc_const_stable(feature = "const_cttz", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn cttz(x: T) -> u32; @@ -2256,7 +2283,8 @@ extern "rust-intrinsic" { /// let num_trailing = unsafe { cttz_nonzero(x) }; /// assert_eq!(num_trailing, 3); /// ``` - #[rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn cttz_nonzero(x: T) -> u32; @@ -2270,7 +2298,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `swap_bytes` method. For example, /// [`u32::swap_bytes`] - #[rustc_const_stable(feature = "const_bswap", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn bswap(x: T) -> T; @@ -2285,7 +2314,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `reverse_bits` method. For example, /// [`u32::reverse_bits`] - #[rustc_const_stable(feature = "const_bitreverse", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn bitreverse(x: T) -> T; @@ -2311,7 +2341,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_add` method. For example, /// [`u32::overflowing_add`] - #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn add_with_overflow(x: T, y: T) -> (T, bool); @@ -2326,7 +2357,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_sub` method. For example, /// [`u32::overflowing_sub`] - #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn sub_with_overflow(x: T, y: T) -> (T, bool); @@ -2341,7 +2373,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_mul` method. For example, /// [`u32::overflowing_mul`] - #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn mul_with_overflow(x: T, y: T) -> (T, bool); @@ -2360,7 +2393,11 @@ extern "rust-intrinsic" { /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_div` method. For example, /// [`u32::checked_div`] - #[rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0")] + #[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0") + )] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unchecked_div(x: T, y: T) -> T; /// Returns the remainder of an unchecked division, resulting in @@ -2369,7 +2406,11 @@ extern "rust-intrinsic" { /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_rem` method. For example, /// [`u32::checked_rem`] - #[rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0")] + #[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0") + )] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unchecked_rem(x: T, y: T) -> T; @@ -2379,7 +2420,8 @@ extern "rust-intrinsic" { /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_shl` method. For example, /// [`u32::checked_shl`] - #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unchecked_shl(x: T, y: U) -> T; /// Performs an unchecked right shift, resulting in undefined behavior when @@ -2388,7 +2430,8 @@ extern "rust-intrinsic" { /// Safe wrappers for this intrinsic are available on the integer /// primitives via the `checked_shr` method. For example, /// [`u32::checked_shr`] - #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unchecked_shr(x: T, y: U) -> T; @@ -2397,7 +2440,8 @@ extern "rust-intrinsic" { /// /// The stable counterpart of this intrinsic is `unchecked_add` on the various /// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`]. - #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unchecked_add(x: T, y: T) -> T; @@ -2406,7 +2450,8 @@ extern "rust-intrinsic" { /// /// The stable counterpart of this intrinsic is `unchecked_sub` on the various /// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`]. - #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unchecked_sub(x: T, y: T) -> T; @@ -2415,7 +2460,8 @@ extern "rust-intrinsic" { /// /// The stable counterpart of this intrinsic is `unchecked_mul` on the various /// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`]. - #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn unchecked_mul(x: T, y: T) -> T; @@ -2429,7 +2475,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `rotate_left` method. For example, /// [`u32::rotate_left`] - #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn rotate_left(x: T, shift: u32) -> T; @@ -2444,7 +2491,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `rotate_right` method. For example, /// [`u32::rotate_right`] - #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn rotate_right(x: T, shift: u32) -> T; @@ -2459,7 +2507,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_add` method. For example, /// [`u32::wrapping_add`] - #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn wrapping_add(a: T, b: T) -> T; @@ -2473,7 +2522,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_sub` method. For example, /// [`u32::wrapping_sub`] - #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn wrapping_sub(a: T, b: T) -> T; @@ -2487,7 +2537,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_mul` method. For example, /// [`u32::wrapping_mul`] - #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn wrapping_mul(a: T, b: T) -> T; @@ -2502,7 +2553,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_add` method. For example, /// [`u32::saturating_add`] - #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn saturating_add(a: T, b: T) -> T; @@ -2516,7 +2568,8 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_sub` method. For example, /// [`u32::saturating_sub`] - #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn saturating_sub(a: T, b: T) -> T; @@ -2527,7 +2580,8 @@ extern "rust-intrinsic" { /// This intrinsic can *only* be called where the pointer is a local without /// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it /// trivially obeys runtime-MIR rules about derefs in operands. - #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn read_via_copy(ptr: *const T) -> T; @@ -2537,7 +2591,8 @@ extern "rust-intrinsic" { /// This intrinsic can *only* be called where the pointer is a local without /// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so /// that it trivially obeys runtime-MIR rules about derefs in operands. - #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn write_via_move(ptr: *mut T, value: T); @@ -2550,7 +2605,8 @@ extern "rust-intrinsic" { /// any safety invariants. /// /// The stabilized version of this intrinsic is [`core::mem::discriminant`]. - #[rustc_const_stable(feature = "const_discriminant", since = "1.75.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn discriminant_value(v: &T) -> ::Discriminant; @@ -2584,7 +2640,8 @@ extern "rust-intrinsic" { pub fn nontemporal_store(ptr: *mut T, val: T); /// See documentation of `<*const T>::offset_from` for details. - #[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn ptr_offset_from(ptr: *const T, base: *const T) -> isize; @@ -2850,7 +2907,8 @@ pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { /// assertions are enabled whenever the *user crate* has UB checks enabled. However, if the /// user has UB checks disabled, the checks will still get optimized out. This intrinsic is /// primarily used by [`ub_checks::assert_unsafe_precondition`]. -#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // just for UB checks #[unstable(feature = "core_intrinsics", issue = "none")] #[inline(always)] #[rustc_intrinsic] @@ -2935,7 +2993,8 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize { /// The stabilized version of this intrinsic is [`core::mem::size_of`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_stable(feature = "const_size_of", since = "1.40.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_size_of", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn size_of() -> usize { @@ -2952,7 +3011,8 @@ pub const fn size_of() -> usize { /// The stabilized version of this intrinsic is [`core::mem::align_of`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_min_align_of", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn min_align_of() -> usize { @@ -3065,7 +3125,8 @@ pub const fn type_id() -> u128 { /// change the possible layouts of pointers. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn aggregate_raw_ptr, D, M>(_data: D, _meta: M) -> P { @@ -3090,7 +3151,11 @@ impl AggregateRawPtr<*mut T> for *mut P { /// This is used to implement functions like `ptr::metadata`. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")] +#[cfg_attr( + bootstrap, + cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")) +)] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn ptr_metadata + ?Sized, M>(_ptr: *const P) -> M { @@ -3197,7 +3262,15 @@ pub const fn ptr_metadata + ?Sized, M>(_ptr: *cons #[rustc_diagnostic_item = "ptr_copy_nonoverlapping"] pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] + #[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0") + )] + #[cfg_attr( + not(bootstrap), + rustc_const_unstable(feature = "core_intrinsics", issue = "none") + )] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); } @@ -3301,7 +3374,15 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us #[rustc_diagnostic_item = "ptr_copy"] pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] + #[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0") + )] + #[cfg_attr( + not(bootstrap), + rustc_const_unstable(feature = "core_intrinsics", issue = "none") + )] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] fn copy(src: *const T, dst: *mut T, count: usize); } @@ -3382,7 +3463,8 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { #[rustc_diagnostic_item = "ptr_write_bytes"] pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { extern "rust-intrinsic" { - #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] #[rustc_nounwind] fn write_bytes(dst: *mut T, val: u8, count: usize); } @@ -3643,6 +3725,7 @@ pub const unsafe fn copysignf128(_x: f128, _y: f128) -> f128 { /// Inform Miri that a given pointer definitely has a certain alignment. #[cfg(miri)] +#[rustc_allow_const_fn_unstable(const_eval_select)] pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize) { extern "Rust" { /// Miri-provided extern function to promise that a given pointer is properly aligned for diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index a2ab39caade..6539964bc09 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -298,7 +298,7 @@ define!( ); define!( "mir_unwind_unreachable", - /// An unwind action that triggers undefined behaviour. + /// An unwind action that triggers undefined behavior. fn UnwindUnreachable() -> UnwindActionArg ); define!( diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 6d30f350337..2a0ef0189d1 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -71,7 +71,7 @@ pub use self::{ /// this can be useful for specializing [`FromIterator`] implementations or recovering the /// remaining elements after an iterator has been partially exhausted. /// -/// Note that implementations do not necessarily have to provide access to the inner-most +/// Note that implementations do not necessarily have to provide access to the innermost /// source of a pipeline. A stateful intermediate adapter might eagerly evaluate a part /// of the pipeline and expose its internal storage as source. /// diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 86660f2e375..2cf2ea58fd4 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -346,7 +346,6 @@ pub trait IntoIterator { fn into_iter(self) -> Self::IntoIter; } -#[rustc_const_unstable(feature = "const_intoiterator_identity", issue = "90603")] #[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for I { type Item = I::Item; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 16877566765..74f79059fe4 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -107,6 +107,7 @@ // // Library features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(const_fmt_arguments_new))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(const_align_of_val)] @@ -121,11 +122,8 @@ #![feature(const_eval_select)] #![feature(const_exact_div)] #![feature(const_float_methods)] -#![feature(const_fmt_arguments_new)] #![feature(const_hash)] #![feature(const_heap)] -#![feature(const_index_range_slice_index)] -#![feature(const_likely)] #![feature(const_nonnull_new)] #![feature(const_num_midpoint)] #![feature(const_option_ext)] @@ -136,6 +134,7 @@ #![feature(const_raw_ptr_comparison)] #![feature(const_size_of_val)] #![feature(const_size_of_val_raw)] +#![feature(const_sockaddr_setters)] #![feature(const_strict_overflow_ops)] #![feature(const_swap)] #![feature(const_try)] @@ -144,13 +143,13 @@ #![feature(const_typed_swap)] #![feature(const_ub_checks)] #![feature(const_unicode_case_lookup)] +#![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(isqrt)] #![feature(lazy_get)] #![feature(link_cfg)] #![feature(non_null_from_ref)] @@ -159,6 +158,7 @@ #![feature(ptr_alignment_type)] #![feature(ptr_metadata)] #![feature(set_ptr_value)] +#![feature(slice_as_chunks)] #![feature(slice_ptr_get)] #![feature(str_internals)] #![feature(str_split_inclusive_remainder)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index aed6be4c627..1c5c58d64a2 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1063,53 +1063,10 @@ pub trait FnPtr: Copy + Clone { } /// Derive macro generating impls of traits related to smart pointers. -#[rustc_builtin_macro(SmartPointer, attributes(pointee))] +#[rustc_builtin_macro(CoercePointee, attributes(pointee))] #[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)] -#[unstable(feature = "derive_smart_pointer", issue = "123430")] -pub macro SmartPointer($item:item) { +#[unstable(feature = "derive_coerce_pointee", issue = "123430")] +#[cfg(not(bootstrap))] +pub macro CoercePointee($item:item) { /* compiler built-in */ } - -// Support traits and types for the desugaring of const traits and -// `~const` bounds. Not supposed to be used by anything other than -// the compiler. -#[doc(hidden)] -#[unstable( - feature = "effect_types", - issue = "none", - reason = "internal module for implementing effects" -)] -#[allow(missing_debug_implementations)] // these unit structs don't need `Debug` impls. -pub mod effects { - #[lang = "EffectsNoRuntime"] - pub struct NoRuntime; - #[lang = "EffectsMaybe"] - pub struct Maybe; - #[lang = "EffectsRuntime"] - pub struct Runtime; - - #[lang = "EffectsCompat"] - pub trait Compat<#[rustc_runtime] const RUNTIME: bool> {} - - impl Compat for NoRuntime {} - impl Compat for Runtime {} - impl<#[rustc_runtime] const RUNTIME: bool> Compat for Maybe {} - - #[lang = "EffectsTyCompat"] - #[marker] - pub trait TyCompat {} - - impl TyCompat for T {} - impl TyCompat for T {} - - #[lang = "EffectsIntersection"] - pub trait Intersection { - #[lang = "EffectsIntersectionOutput"] - type Output: ?Sized; - } - - // FIXME(effects): remove this after next trait solver lands - impl Intersection for () { - type Output = Maybe; - } -} diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index ea73cfc3781..b4252ef0103 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -723,7 +723,7 @@ impl MaybeUninit { /// this does not constitute a stable guarantee), because the only /// requirement the compiler knows about it is that the data pointer must be /// non-null. Dropping such a `Vec` however will cause undefined - /// behaviour. + /// behavior. /// /// [`assume_init`]: MaybeUninit::assume_init /// [`Vec`]: ../../std/vec/struct.Vec.html diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index d3360c18207..0d1f4a9ea3e 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -373,6 +373,7 @@ impl IpAddr { /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true); /// ``` #[unstable(feature = "ip", issue = "27709")] + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[must_use] #[inline] pub const fn is_benchmarking(&self) -> bool { diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs index 4e339172b68..9204797e6e1 100644 --- a/library/core/src/net/socket_addr.rs +++ b/library/core/src/net/socket_addr.rs @@ -49,6 +49,15 @@ pub enum SocketAddr { /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 /// [`IPv4` address]: Ipv4Addr /// +/// # Textual representation +/// +/// `SocketAddrV4` provides a [`FromStr`](crate::str::FromStr) implementation. +/// It accepts an IPv4 address in its [textual representation], followed by a +/// single `:`, followed by the port encoded as a decimal integer. Other +/// formats are not accepted. +/// +/// [textual representation]: Ipv4Addr#textual-representation +/// /// # Examples /// /// ``` @@ -82,6 +91,32 @@ pub struct SocketAddrV4 { /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// [`IPv6` address]: Ipv6Addr /// +/// # Textual representation +/// +/// `SocketAddrV6` provides a [`FromStr`](crate::str::FromStr) implementation, +/// based on the bracketed format recommended by [IETF RFC 5952], +/// with scope identifiers based on those specified in [IETF RFC 4007]. +/// +/// It accepts addresses consisting of the following elements, in order: +/// - A left square bracket (`[`) +/// - The [textual representation] of an IPv6 address +/// - _Optionally_, a percent sign (`%`) followed by the scope identifier +/// encoded as a decimal integer +/// - A right square bracket (`]`) +/// - A colon (`:`) +/// - The port, encoded as a decimal integer. +/// +/// For example, the string `[2001:db8::413]:443` represents a `SocketAddrV6` +/// with the address `2001:db8::413` and port `443`. The string +/// `[2001:db8::413%612]:443` represents the same address and port, with a +/// scope identifier of `612`. +/// +/// Other formats are not accepted. +/// +/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952#section-6 +/// [IETF RFC 4007]: https://tools.ietf.org/html/rfc4007#section-11 +/// [textual representation]: Ipv6Addr#textual-representation +/// /// # Examples /// /// ``` @@ -92,6 +127,10 @@ pub struct SocketAddrV4 { /// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket)); /// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); /// assert_eq!(socket.port(), 8080); +/// +/// let mut with_scope = socket.clone(); +/// with_scope.set_scope_id(3); +/// assert_eq!("[2001:db8::1%3]:8080".parse(), Ok(with_scope)); /// ``` #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[stable(feature = "rust1", since = "1.0.0")] @@ -159,9 +198,10 @@ impl SocketAddr { /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1))); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_ip(&mut self, new_ip: IpAddr) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_ip(&mut self, new_ip: IpAddr) { // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away. match (self, new_ip) { (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip), @@ -202,9 +242,10 @@ impl SocketAddr { /// socket.set_port(1025); /// assert_eq!(socket.port(), 1025); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_port(&mut self, new_port: u16) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_port(&mut self, new_port: u16) { match *self { SocketAddr::V4(ref mut a) => a.set_port(new_port), SocketAddr::V6(ref mut a) => a.set_port(new_port), @@ -307,9 +348,10 @@ impl SocketAddrV4 { /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1)); /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1)); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_ip(&mut self, new_ip: Ipv4Addr) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_ip(&mut self, new_ip: Ipv4Addr) { self.ip = new_ip; } @@ -342,9 +384,10 @@ impl SocketAddrV4 { /// socket.set_port(4242); /// assert_eq!(socket.port(), 4242); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_port(&mut self, new_port: u16) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_port(&mut self, new_port: u16) { self.port = new_port; } } @@ -403,9 +446,10 @@ impl SocketAddrV6 { /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0)); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_ip(&mut self, new_ip: Ipv6Addr) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_ip(&mut self, new_ip: Ipv6Addr) { self.ip = new_ip; } @@ -438,9 +482,10 @@ impl SocketAddrV6 { /// socket.set_port(4242); /// assert_eq!(socket.port(), 4242); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_port(&mut self, new_port: u16) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_port(&mut self, new_port: u16) { self.port = new_port; } @@ -485,9 +530,10 @@ impl SocketAddrV6 { /// socket.set_flowinfo(56); /// assert_eq!(socket.flowinfo(), 56); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_flowinfo(&mut self, new_flowinfo: u32) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_flowinfo(&mut self, new_flowinfo: u32) { self.flowinfo = new_flowinfo; } @@ -527,9 +573,10 @@ impl SocketAddrV6 { /// socket.set_scope_id(42); /// assert_eq!(socket.scope_id(), 42); /// ``` - #[stable(feature = "sockaddr_setters", since = "1.9.0")] #[inline] - pub fn set_scope_id(&mut self, new_scope_id: u32) { + #[stable(feature = "sockaddr_setters", since = "1.9.0")] + #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + pub const fn set_scope_id(&mut self, new_scope_id: u32) { self.scope_id = new_scope_id; } } diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 5ab2ab50d7c..e8161cce2fe 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -288,7 +288,6 @@ impl f128 { // concerns about portability, so this implementation is for // private use internally. #[inline] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub(crate) const fn abs_private(self) -> f128 { // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. unsafe { @@ -319,7 +318,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_infinite(self) -> bool { (self == f128::INFINITY) | (self == f128::NEG_INFINITY) } @@ -346,7 +344,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, // the comparison is not true, exactly as desired. @@ -380,7 +377,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_subnormal(self) -> bool { matches!(self.classify(), FpCategory::Subnormal) } @@ -412,7 +408,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_normal(self) -> bool { matches!(self.classify(), FpCategory::Normal) } @@ -437,7 +432,6 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn classify(self) -> FpCategory { let bits = self.to_bits(); match (bits & Self::MAN_MASK, bits & Self::EXP_MASK) { @@ -915,7 +909,6 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_bits(self) -> u128 { // SAFETY: `u128` is a plain old datatype so we can always transmute to it. @@ -964,7 +957,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_bits(v: u128) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u128` is a plain old datatype so we can always transmute from it. @@ -991,7 +983,6 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_be_bytes(self) -> [u8; 16] { self.to_bits().to_be_bytes() @@ -1017,7 +1008,6 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_le_bytes(self) -> [u8; 16] { self.to_bits().to_le_bytes() @@ -1054,7 +1044,6 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_ne_bytes(self) -> [u8; 16] { self.to_bits().to_ne_bytes() @@ -1082,7 +1071,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_be_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_be_bytes(bytes)) } @@ -1109,7 +1097,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_le_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_le_bytes(bytes)) } @@ -1146,7 +1133,6 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 60a88496696..8b3f3b7d19b 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -282,7 +282,6 @@ impl f16 { // concerns about portability, so this implementation is for // private use internally. #[inline] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub(crate) const fn abs_private(self) -> f16 { // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. unsafe { mem::transmute::(mem::transmute::(self) & !Self::SIGN_MASK) } @@ -310,7 +309,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_infinite(self) -> bool { (self == f16::INFINITY) | (self == f16::NEG_INFINITY) } @@ -336,7 +334,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, // the comparison is not true, exactly as desired. @@ -368,7 +365,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_subnormal(self) -> bool { matches!(self.classify(), FpCategory::Subnormal) } @@ -398,7 +394,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_normal(self) -> bool { matches!(self.classify(), FpCategory::Normal) } @@ -422,7 +417,6 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn classify(self) -> FpCategory { let b = self.to_bits(); match (b & Self::MAN_MASK, b & Self::EXP_MASK) { @@ -901,7 +895,6 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_bits(self) -> u16 { // SAFETY: `u16` is a plain old datatype so we can always transmute to it. @@ -949,7 +942,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_bits(v: u16) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u16` is a plain old datatype so we can always transmute from it. @@ -975,7 +967,6 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_be_bytes(self) -> [u8; 2] { self.to_bits().to_be_bytes() @@ -1000,7 +991,6 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_le_bytes(self) -> [u8; 2] { self.to_bits().to_le_bytes() @@ -1038,7 +1028,6 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_ne_bytes(self) -> [u8; 2] { self.to_bits().to_ne_bytes() @@ -1062,7 +1051,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_be_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_be_bytes(bytes)) } @@ -1085,7 +1073,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_le_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_le_bytes(bytes)) } @@ -1119,7 +1106,6 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 7241b3ff6a3..3a9060df286 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -449,7 +449,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_add(self, rhs: Self) -> Option { let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict integer addition. Computes `self + rhs`, panicking @@ -545,7 +545,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option { let (a, b) = self.overflowing_add_unsigned(rhs); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict addition with an unsigned integer. Computes `self + rhs`, @@ -601,7 +601,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_sub(self, rhs: Self) -> Option { let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict integer subtraction. Computes `self - rhs`, panicking if @@ -697,7 +697,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option { let (a, b) = self.overflowing_sub_unsigned(rhs); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict subtraction with an unsigned integer. Computes `self - rhs`, @@ -753,7 +753,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_mul(self, rhs: Self) -> Option { let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict integer multiplication. Computes `self * rhs`, panicking if @@ -849,7 +849,7 @@ macro_rules! int_impl { without modifying the original"] #[inline] pub const fn checked_div(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) { + if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) { None } else { // SAFETY: div by zero and by INT_MIN have been checked above @@ -924,7 +924,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_div_euclid(self, rhs: Self) -> Option { // Using `&` helps LLVM see that it is the same check made in division. - if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { + if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { None } else { Some(self.div_euclid(rhs)) @@ -997,7 +997,7 @@ macro_rules! int_impl { without modifying the original"] #[inline] pub const fn checked_rem(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) { + if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) { None } else { // SAFETY: div by zero and by INT_MIN have been checked above @@ -1071,7 +1071,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_rem_euclid(self, rhs: Self) -> Option { // Using `&` helps LLVM see that it is the same check made in division. - if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { + if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { None } else { Some(self.rem_euclid(rhs)) @@ -1142,7 +1142,7 @@ macro_rules! int_impl { #[inline] pub const fn checked_neg(self) -> Option { let (a, b) = self.overflowing_neg(); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Unchecked negation. Computes `-self`, assuming overflow cannot occur. @@ -1629,11 +1629,10 @@ macro_rules! int_impl { /// /// Basic usage: /// ``` - /// #![feature(isqrt)] #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_isqrt(), Some(3));")] /// ``` - #[unstable(feature = "isqrt", issue = "116226")] - #[rustc_const_unstable(feature = "isqrt", issue = "116226")] + #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2564,7 +2563,7 @@ macro_rules! int_impl { without modifying the original"] pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { // Using `&` helps LLVM see that it is the same check made in division. - if unlikely!((self == Self::MIN) & (rhs == -1)) { + if intrinsics::unlikely((self == Self::MIN) & (rhs == -1)) { (self, true) } else { (self / rhs, false) @@ -2595,7 +2594,7 @@ macro_rules! int_impl { without modifying the original"] pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { // Using `&` helps LLVM see that it is the same check made in division. - if unlikely!((self == Self::MIN) & (rhs == -1)) { + if intrinsics::unlikely((self == Self::MIN) & (rhs == -1)) { (self, true) } else { (self.div_euclid(rhs), false) @@ -2625,7 +2624,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - if unlikely!(rhs == -1) { + if intrinsics::unlikely(rhs == -1) { (0, self == Self::MIN) } else { (self % rhs, false) @@ -2657,7 +2656,7 @@ macro_rules! int_impl { #[inline] #[track_caller] pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { - if unlikely!(rhs == -1) { + if intrinsics::unlikely(rhs == -1) { (0, self == Self::MIN) } else { (self.rem_euclid(rhs), false) @@ -2686,7 +2685,7 @@ macro_rules! int_impl { without modifying the original"] #[allow(unused_attributes)] pub const fn overflowing_neg(self) -> (Self, bool) { - if unlikely!(self == Self::MIN) { + if intrinsics::unlikely(self == Self::MIN) { (Self::MIN, true) } else { (-self, false) @@ -2880,11 +2879,10 @@ macro_rules! int_impl { /// /// Basic usage: /// ``` - /// #![feature(isqrt)] #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")] /// ``` - #[unstable(feature = "isqrt", issue = "116226")] - #[rustc_const_unstable(feature = "isqrt", issue = "116226")] + #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -3181,44 +3179,6 @@ macro_rules! int_impl { } } - /// Calculates the middle point of `self` and `rhs`. - /// - /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a - /// sufficiently-large signed integral type. This implies that the result is - /// always rounded towards negative infinity and that no overflow will ever occur. - /// - /// # Examples - /// - /// ``` - /// #![feature(num_midpoint)] - #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] - #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-1), -1);")] - #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(0), -1);")] - /// ``` - #[unstable(feature = "num_midpoint", issue = "110840")] - #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] - #[rustc_allow_const_fn_unstable(const_num_midpoint)] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn midpoint(self, rhs: Self) -> Self { - const U: $UnsignedT = <$SelfT>::MIN.unsigned_abs(); - - // Map an $SelfT to an $UnsignedT - // ex: i8 [-128; 127] to [0; 255] - const fn map(a: $SelfT) -> $UnsignedT { - (a as $UnsignedT) ^ U - } - - // Map an $UnsignedT to an $SelfT - // ex: u8 [0; 255] to [-128; 127] - const fn demap(a: $UnsignedT) -> $SelfT { - (a ^ U) as $SelfT - } - - demap(<$UnsignedT>::midpoint(map(self), map(rhs))) - } - /// Returns the logarithm of the number with respect to an arbitrary base, /// rounded down. /// diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 5e2f45884dd..9a5e211dd60 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -16,13 +16,6 @@ macro_rules! try_opt { }; } -#[allow_internal_unstable(const_likely)] -macro_rules! unlikely { - ($e: expr) => { - intrinsics::unlikely($e) - }; -} - // Use this when the generated code should differ between signed and unsigned types. macro_rules! sign_dependent_expr { (signed ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => { @@ -131,6 +124,37 @@ macro_rules! midpoint_impl { ((self ^ rhs) >> 1) + (self & rhs) } }; + ($SelfT:ty, signed) => { + /// Calculates the middle point of `self` and `rhs`. + /// + /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a + /// sufficiently-large signed integral type. This implies that the result is + /// always rounded towards zero and that no overflow will ever occur. + /// + /// # Examples + /// + /// ``` + /// #![feature(num_midpoint)] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] + #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(2), 0);")] + #[doc = concat!("assert_eq!((-7", stringify!($SelfT), ").midpoint(0), -3);")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")] + /// ``` + #[unstable(feature = "num_midpoint", issue = "110840")] + #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn midpoint(self, rhs: Self) -> Self { + // Use the well known branchless algorithm from Hacker's Delight to compute + // `(a + b) / 2` without overflowing: `((a ^ b) >> 1) + (a & b)`. + let t = ((self ^ rhs) >> 1) + (self & rhs); + // Except that it fails for integers whose sum is an odd negative number as + // their floor is one less than their average. So we adjust the result. + t + (if t < 0 { 1 } else { 0 } & (self ^ rhs)) + } + }; ($SelfT:ty, $WideT:ty, unsigned) => { /// Calculates the middle point of `self` and `rhs`. /// @@ -154,6 +178,32 @@ macro_rules! midpoint_impl { ((self as $WideT + rhs as $WideT) / 2) as $SelfT } }; + ($SelfT:ty, $WideT:ty, signed) => { + /// Calculates the middle point of `self` and `rhs`. + /// + /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a + /// sufficiently-large signed integral type. This implies that the result is + /// always rounded towards zero and that no overflow will ever occur. + /// + /// # Examples + /// + /// ``` + /// #![feature(num_midpoint)] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] + #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(2), 0);")] + #[doc = concat!("assert_eq!((-7", stringify!($SelfT), ").midpoint(0), -3);")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")] + /// ``` + #[unstable(feature = "num_midpoint", issue = "110840")] + #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn midpoint(self, rhs: $SelfT) -> $SelfT { + ((self as $WideT + rhs as $WideT) / 2) as $SelfT + } + }; } macro_rules! widening_impl { @@ -307,6 +357,7 @@ impl i8 { from_xe_bytes_doc = "", bound_condition = "", } + midpoint_impl! { i8, i16, signed } } impl i16 { @@ -330,6 +381,7 @@ impl i16 { from_xe_bytes_doc = "", bound_condition = "", } + midpoint_impl! { i16, i32, signed } } impl i32 { @@ -353,6 +405,7 @@ impl i32 { from_xe_bytes_doc = "", bound_condition = "", } + midpoint_impl! { i32, i64, signed } } impl i64 { @@ -376,6 +429,7 @@ impl i64 { from_xe_bytes_doc = "", bound_condition = "", } + midpoint_impl! { i64, i128, signed } } impl i128 { @@ -401,6 +455,7 @@ impl i128 { from_xe_bytes_doc = "", bound_condition = "", } + midpoint_impl! { i128, signed } } #[cfg(target_pointer_width = "16")] @@ -425,6 +480,7 @@ impl isize { from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(), bound_condition = " on 16-bit targets", } + midpoint_impl! { isize, i32, signed } } #[cfg(target_pointer_width = "32")] @@ -449,6 +505,7 @@ impl isize { from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(), bound_condition = " on 32-bit targets", } + midpoint_impl! { isize, i64, signed } } #[cfg(target_pointer_width = "64")] @@ -473,6 +530,7 @@ impl isize { from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(), bound_condition = " on 64-bit targets", } + midpoint_impl! { isize, i128, signed } } /// If the 6th bit is set ascii is lower case. @@ -1397,7 +1455,7 @@ from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } #[doc(hidden)] #[inline(always)] #[unstable(issue = "none", feature = "std_internals")] -#[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_from_str", since = "1.82.0"))] pub const fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool { radix <= 16 && digits.len() <= mem::size_of::() * 2 - is_signed_ty as usize } @@ -1416,6 +1474,7 @@ fn from_str_radix_panic_rt(radix: u32) -> ! { #[cfg_attr(feature = "panic_immediate_abort", inline)] #[cold] #[track_caller] +#[rustc_allow_const_fn_unstable(const_eval_select)] const fn from_str_radix_panic(radix: u32) { // The only difference between these two functions is their panic message. intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt); diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index e5c9a7e086a..f6e271954fe 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -355,7 +355,7 @@ where } /// Creates a non-zero without checking whether the value is non-zero. - /// This results in undefined behaviour if the value is zero. + /// This results in undefined behavior if the value is zero. /// /// # Safety /// @@ -952,9 +952,9 @@ macro_rules! nonzero_integer { /// Multiplies two non-zero integers together, /// assuming overflow cannot occur. - /// Overflow is unchecked, and it is undefined behaviour to overflow + /// Overflow is unchecked, and it is undefined behavior to overflow /// *even if the result would wrap to a non-zero value*. - /// The behaviour is undefined as soon as + /// The behavior is undefined as soon as #[doc = sign_dependent_expr!{ $signedness ? if signed { @@ -1323,9 +1323,9 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// Adds an unsigned integer to a non-zero value, /// assuming overflow cannot occur. - /// Overflow is unchecked, and it is undefined behaviour to overflow + /// Overflow is unchecked, and it is undefined behavior to overflow /// *even if the result would wrap to a non-zero value*. - /// The behaviour is undefined as soon as + /// The behavior is undefined as soon as #[doc = concat!("`self + rhs > ", stringify!($Int), "::MAX`.")] /// /// # Examples @@ -1527,7 +1527,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// /// Basic usage: /// ``` - /// #![feature(isqrt)] /// # use std::num::NonZero; /// # /// # fn main() { test().unwrap(); } @@ -1539,8 +1538,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Some(()) /// # } /// ``` - #[unstable(feature = "isqrt", issue = "116226")] - #[rustc_const_unstable(feature = "isqrt", issue = "116226")] + #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1599,7 +1598,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// Computes the absolute value of self. #[doc = concat!("See [`", stringify!($Int), "::abs`]")] - /// for documentation on overflow behaviour. + /// for documentation on overflow behavior. /// /// # Example /// @@ -1878,7 +1877,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// Negates self, overflowing if this is equal to the minimum value. /// #[doc = concat!("See [`", stringify!($Int), "::overflowing_neg`]")] - /// for documentation on overflow behaviour. + /// for documentation on overflow behavior. /// /// # Example /// @@ -1943,7 +1942,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// of the type. /// #[doc = concat!("See [`", stringify!($Int), "::wrapping_neg`]")] - /// for documentation on overflow behaviour. + /// for documentation on overflow behavior. /// /// # Example /// diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index d9036abecc5..eb4ea4b3c40 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -491,7 +491,7 @@ macro_rules! uint_impl { // Per , // LLVM is happy to re-form the intrinsic later if useful. - if unlikely!(intrinsics::add_with_overflow(self, rhs).1) { + if intrinsics::unlikely(intrinsics::add_with_overflow(self, rhs).1) { None } else { // SAFETY: Just checked it doesn't overflow @@ -593,7 +593,7 @@ macro_rules! uint_impl { #[inline] pub const fn checked_add_signed(self, rhs: $SignedT) -> Option { let (a, b) = self.overflowing_add_signed(rhs); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict addition with a signed integer. Computes `self + rhs`, @@ -845,7 +845,7 @@ macro_rules! uint_impl { #[inline] pub const fn checked_mul(self, rhs: Self) -> Option { let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict integer multiplication. Computes `self * rhs`, panicking if @@ -940,7 +940,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn checked_div(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { + if intrinsics::unlikely(rhs == 0) { None } else { // SAFETY: div by zero has been checked above and unsigned types have no other @@ -1001,7 +1001,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn checked_div_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { + if intrinsics::unlikely(rhs == 0) { None } else { Some(self.div_euclid(rhs)) @@ -1061,7 +1061,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn checked_rem(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { + if intrinsics::unlikely(rhs == 0) { None } else { // SAFETY: div by zero has been checked above and unsigned types have no other @@ -1123,7 +1123,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn checked_rem_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { + if intrinsics::unlikely(rhs == 0) { None } else { Some(self.rem_euclid(rhs)) @@ -1362,7 +1362,7 @@ macro_rules! uint_impl { #[inline] pub const fn checked_neg(self) -> Option { let (a, b) = self.overflowing_neg(); - if unlikely!(b) { None } else { Some(a) } + if intrinsics::unlikely(b) { None } else { Some(a) } } /// Strict negation. Computes `-self`, panicking unless `self == @@ -2753,11 +2753,10 @@ macro_rules! uint_impl { /// /// Basic usage: /// ``` - /// #![feature(isqrt)] #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")] /// ``` - #[unstable(feature = "isqrt", issue = "116226")] - #[rustc_const_unstable(feature = "isqrt", issue = "116226")] + #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -3009,7 +3008,7 @@ macro_rules! uint_impl { // overflow cases it instead ends up returning the maximum value // of the type, and can return 0 for 0. #[inline] - #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_pow", since = "1.50.0"))] const fn one_less_than_next_power_of_two(self) -> Self { if self <= 1 { return 0; } @@ -3086,7 +3085,7 @@ macro_rules! uint_impl { /// ``` #[inline] #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", - reason = "needs decision on wrapping behaviour")] + reason = "needs decision on wrapping behavior")] #[rustc_const_unstable(feature = "wrapping_next_power_of_two", issue = "32463")] #[must_use = "this returns the result of the operation, \ without modifying the original"] diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index 1ac6d3161c2..1156b389e28 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -1043,7 +1043,7 @@ macro_rules! wrapping_int_impl_unsigned { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", - reason = "needs decision on wrapping behaviour")] + reason = "needs decision on wrapping behavior")] pub fn next_power_of_two(self) -> Self { Wrapping(self.0.wrapping_next_power_of_two()) } diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index f0d2c761ef3..1ef9990c00a 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -15,7 +15,7 @@ /// /// Types that implement `Deref` or `DerefMut` are often called "smart /// pointers" and the mechanism of deref coercion has been specifically designed -/// to facilitate the pointer-like behaviour that name suggests. Often, the +/// to facilitate the pointer-like behavior that name suggests. Often, the /// purpose of a "smart pointer" type is to change the ownership semantics /// of a contained value (for example, [`Rc`][rc] or [`Cow`][cow]) or the /// storage semantics of a contained value (for example, [`Box`][box]). @@ -42,7 +42,7 @@ /// 1. a value of the type transparently behaves like a value of the target /// type; /// 1. the implementation of the deref function is cheap; and -/// 1. users of the type will not be surprised by any deref coercion behaviour. +/// 1. users of the type will not be surprised by any deref coercion behavior. /// /// In general, deref traits **should not** be implemented if: /// @@ -185,7 +185,7 @@ impl Deref for &mut T { /// /// Types that implement `DerefMut` or `Deref` are often called "smart /// pointers" and the mechanism of deref coercion has been specifically designed -/// to facilitate the pointer-like behaviour that name suggests. Often, the +/// to facilitate the pointer-like behavior that name suggests. Often, the /// purpose of a "smart pointer" type is to change the ownership semantics /// of a contained value (for example, [`Rc`][rc] or [`Cow`][cow]) or the /// storage semantics of a contained value (for example, [`Box`][box]). @@ -297,15 +297,21 @@ unsafe impl DerefPure for &mut T {} /// Indicates that a struct can be used as a method receiver, without the /// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box`, /// `Rc`, `&T`, and `Pin

`. -#[lang = "receiver"] -#[unstable(feature = "receiver_trait", issue = "none")] +/// +/// This trait will shortly be removed and replaced with a more generic +/// facility based around the current "arbitrary self types" unstable feature. +/// That new facility will use a replacement trait called `Receiver` which is +/// why this is now named `LegacyReceiver`. +#[cfg_attr(bootstrap, lang = "receiver")] +#[cfg_attr(not(bootstrap), lang = "legacy_receiver")] +#[unstable(feature = "legacy_receiver_trait", issue = "none")] #[doc(hidden)] -pub trait Receiver { +pub trait LegacyReceiver { // Empty. } -#[unstable(feature = "receiver_trait", issue = "none")] -impl Receiver for &T {} +#[unstable(feature = "legacy_receiver_trait", issue = "none")] +impl LegacyReceiver for &T {} -#[unstable(feature = "receiver_trait", issue = "none")] -impl Receiver for &mut T {} +#[unstable(feature = "legacy_receiver_trait", issue = "none")] +impl LegacyReceiver for &mut T {} diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 5464bf645d9..c9f47e5daad 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -168,8 +168,8 @@ pub use self::control_flow::ControlFlow; pub use self::coroutine::{Coroutine, CoroutineState}; #[unstable(feature = "deref_pure_trait", issue = "87121")] pub use self::deref::DerefPure; -#[unstable(feature = "receiver_trait", issue = "none")] -pub use self::deref::Receiver; +#[unstable(feature = "legacy_receiver_trait", issue = "none")] +pub use self::deref::LegacyReceiver; #[stable(feature = "rust1", since = "1.0.0")] pub use self::deref::{Deref, DerefMut}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 0b996c40c04..2aa4f172368 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -150,7 +150,7 @@ //! It is further guaranteed that, for the cases above, one can //! [`mem::transmute`] from all valid values of `T` to `Option` and //! from `Some::(_)` to `T` (but transmuting `None::` to `T` -//! is undefined behaviour). +//! is undefined behavior). //! //! # Method overview //! diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs index af2c83b5460..1d950eb3625 100644 --- a/library/core/src/panic/panic_info.rs +++ b/library/core/src/panic/panic_info.rs @@ -168,6 +168,7 @@ impl<'a> PanicMessage<'a> { #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")] #[must_use] #[inline] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] pub const fn as_str(&self) -> Option<&'static str> { self.message.as_str() } diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 7420579e3ce..9071d6719a3 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -50,7 +50,8 @@ const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C #[track_caller] #[lang = "panic_fmt"] // needed for const-evaluated panics #[rustc_do_not_const_check] // hooked by const-eval -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() @@ -84,7 +85,9 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { // and unwinds anyway, we will hit the "unwinding out of nounwind function" guard, // which causes a "panic in a function that cannot unwind". #[rustc_nounwind] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable +#[rustc_allow_const_fn_unstable(const_eval_select)] pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! { #[inline] // this should always be inlined into `panic_nounwind_fmt` #[track_caller] @@ -131,7 +134,8 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable #[lang = "panic"] // used by lints and miri for panics pub const fn panic(expr: &'static str) -> ! { // Use Arguments::new_const instead of format_args!("{expr}") to potentially @@ -169,7 +173,8 @@ macro_rules! panic_const { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] - #[rustc_const_unstable(feature = "panic_internals", issue = "none")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable #[lang = stringify!($lang)] pub const fn $lang() -> ! { // Use Arguments::new_const instead of format_args!("{expr}") to potentially @@ -216,7 +221,8 @@ panic_const! { #[cfg_attr(feature = "panic_immediate_abort", inline)] #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics #[rustc_nounwind] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable pub const fn panic_nounwind(expr: &'static str) -> ! { panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ false); } @@ -232,7 +238,8 @@ pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! { #[track_caller] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable pub const fn panic_explicit() -> ! { panic_display(&"explicit panic"); } @@ -249,7 +256,8 @@ pub fn unreachable_display(x: &T) -> ! { #[inline] #[track_caller] #[rustc_diagnostic_item = "panic_str_2015"] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable pub const fn panic_str_2015(expr: &str) -> ! { panic_display(&expr); } @@ -259,7 +267,8 @@ pub const fn panic_str_2015(expr: &str) -> ! { #[rustc_do_not_const_check] // hooked by const-eval // enforce a &&str argument in const-check and hook this by const-eval #[rustc_const_panic_str] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable pub const fn panic_display(x: &T) -> ! { panic_fmt(format_args!("{}", *x)); } @@ -327,8 +336,9 @@ fn panic_in_cleanup() -> ! { } /// This function is used instead of panic_fmt in const eval. -#[lang = "const_panic_fmt"] -#[rustc_const_unstable(feature = "panic_internals", issue = "none")] +#[lang = "const_panic_fmt"] // needed by const-eval machine to replace calls to `panic_fmt` lang item +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if let Some(msg) = fmt.as_str() { // The panic_display function is hooked by const eval. diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 5d5733d38fc..254b306fcaa 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -921,7 +921,7 @@ #![stable(feature = "pin", since = "1.33.0")] use crate::hash::{Hash, Hasher}; -use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver}; +use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver}; #[allow(unused_imports)] use crate::{ cell::{RefCell, UnsafeCell}, @@ -1692,8 +1692,8 @@ impl> DerefMut for Pin { #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl DerefPure for Pin {} -#[unstable(feature = "receiver_trait", issue = "none")] -impl Receiver for Pin {} +#[unstable(feature = "legacy_receiver_trait", issue = "none")] +impl LegacyReceiver for Pin {} #[stable(feature = "pin", since = "1.33.0")] impl fmt::Debug for Pin { diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 95fa6c9c950..4a6fca5085c 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -100,7 +100,7 @@ mod prim_bool {} /// /// Both match arms must produce values of type [`u32`], but since `break` never produces a value /// at all we know it can never produce a value which isn't a [`u32`]. This illustrates another -/// behaviour of the `!` type - expressions with type `!` will coerce into any other type. +/// behavior of the `!` type - expressions with type `!` will coerce into any other type. /// /// [`u32`]: prim@u32 /// [`exit`]: ../std/process/fn.exit.html @@ -134,7 +134,7 @@ mod prim_bool {} /// /// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns` /// feature is present this means we can exhaustively match on [`Result`] by just taking the -/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain +/// [`Ok`] variant. This illustrates another behavior of `!` - it can be used to "delete" certain /// enum variants from generic types like `Result`. /// /// ## Infinite loops @@ -351,7 +351,7 @@ mod prim_never {} /// ``` /// /// ```no_run -/// // Undefined behaviour +/// // Undefined behavior /// let _ = unsafe { char::from_u32_unchecked(0x110000) }; /// ``` /// @@ -568,7 +568,7 @@ impl () {} /// Instead of coercing a reference to a raw pointer, you can use the macros /// [`ptr::addr_of!`] (for `*const T`) and [`ptr::addr_of_mut!`] (for `*mut T`). /// These macros allow you to create raw pointers to fields to which you cannot -/// create a reference (without causing undefined behaviour), such as an +/// create a reference (without causing undefined behavior), such as an /// unaligned field. This might be necessary if packed structs or uninitialized /// memory is involved. /// @@ -1453,7 +1453,7 @@ mod prim_usize {} /// &[bool] can only point to an allocation containing the integer values `1` /// ([`true`](../std/keyword.true.html)) or `0` ([`false`](../std/keyword.false.html)), but /// creating a &[bool] that points to an allocation containing -/// the value `3` causes undefined behaviour. +/// the value `3` causes undefined behavior. /// In fact, [Option]\<&T> has the same memory representation as a /// nullable but aligned pointer, and can be passed across FFI boundaries as such. /// @@ -1612,6 +1612,9 @@ mod prim_ref {} /// pointers, make your type [`Option`](core::option#options-and-pointers-nullable-pointers) /// with your required signature. /// +/// Note that FFI requires additional care to ensure that the ABI for both sides of the call match. +/// The exact requirements are not currently documented. +/// /// ### Safety /// /// Plain function pointers are obtained by casting either plain functions, or closures that don't @@ -1750,8 +1753,13 @@ mod prim_ref {} /// is also used rarely. So, most likely you do not have to worry about ABI compatibility. /// /// But assuming such circumstances, what are the rules? For this section, we are only considering -/// the ABI of direct Rust-to-Rust calls, not linking in general -- once functions are imported via -/// `extern` blocks, there are more things to consider that we do not go into here. +/// the ABI of direct Rust-to-Rust calls (with both definition and callsite visible to the +/// Rust compiler), not linking in general -- once functions are imported via `extern` blocks, there +/// are more things to consider that we do not go into here. Note that this also applies to +/// passing/calling functions across language boundaries via function pointers. +/// +/// **Nothing in this section should be taken as a guarantee for non-Rust-to-Rust calls, even with +/// types from `core::ffi` or `libc`**. /// /// For two signatures to be considered *ABI-compatible*, they must use a compatible ABI string, /// must take the same number of arguments, the individual argument types and the return types must diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index 50706fca5b0..2538d60a8ee 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -41,7 +41,7 @@ impl Alignment { /// This provides the same numerical value as [`mem::align_of`], /// but in an `Alignment` instead of a `usize`. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn of() -> Self { // SAFETY: rustc ensures that type alignment is always a power of two. @@ -53,7 +53,7 @@ impl Alignment { /// /// Note that `0` is not a power of two, nor a valid alignment. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn new(align: usize) -> Option { if align.is_power_of_two() { @@ -73,7 +73,7 @@ impl Alignment { /// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`. /// It must *not* be zero. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const unsafe fn new_unchecked(align: usize) -> Self { assert_unsafe_precondition!( @@ -89,7 +89,7 @@ impl Alignment { /// Returns the alignment as a [`usize`]. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn as_usize(self) -> usize { self.0 as usize @@ -97,7 +97,7 @@ impl Alignment { /// Returns the alignment as a [NonZero]<[usize]>. #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn as_nonzero(self) -> NonZero { // SAFETY: All the discriminants are non-zero. @@ -118,7 +118,7 @@ impl Alignment { /// assert_eq!(Alignment::new(1024).unwrap().log2(), 10); /// ``` #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn log2(self) -> u32 { self.as_nonzero().trailing_zeros() @@ -148,7 +148,7 @@ impl Alignment { /// assert_ne!(one.mask(Alignment::of::().mask()), one); /// ``` #[unstable(feature = "ptr_alignment_type", issue = "102070")] - #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))] #[inline] pub const fn mask(self) -> usize { // SAFETY: The alignment is always nonzero, and therefore decrementing won't overflow. diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 9ee0fb5948e..75d681d76df 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -39,6 +39,7 @@ impl *const T { } #[inline] + #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] const fn const_impl(ptr: *const u8) -> bool { match (ptr).guaranteed_eq(null_mut()) { Some(res) => res, @@ -113,7 +114,7 @@ impl *const T { /// println!("{:?}", unsafe { &*bad }); /// ``` #[unstable(feature = "set_ptr_value", issue = "75091")] - #[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[must_use = "returns a new pointer rather than modifying its argument"] #[inline] pub const fn with_metadata_of(self, meta: *const U) -> *const U @@ -409,6 +410,7 @@ impl *const T { T: Sized, { #[inline] + #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool { #[inline] fn runtime(this: *const (), count: isize, size: usize) -> bool { @@ -704,7 +706,7 @@ impl *const T { /// but it provides slightly more information to the optimizer, which can /// sometimes allow it to optimize slightly better with some backends. /// - /// This method can be though of as recovering the `count` that was passed + /// This method can be thought of as recovering the `count` that was passed /// to [`add`](#method.add) (or, with the parameters in the other order, /// to [`sub`](#method.sub)). The following are all equivalent, assuming /// that their safety preconditions are met: @@ -761,6 +763,7 @@ impl *const T { where T: Sized, { + #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_ptr_ge(this: *const (), origin: *const ()) -> bool { fn runtime(this: *const (), origin: *const ()) -> bool { this >= origin @@ -902,6 +905,7 @@ impl *const T { { #[cfg(debug_assertions)] #[inline] + #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] fn runtime(this: *const (), count: usize, size: usize) -> bool { @@ -1010,6 +1014,7 @@ impl *const T { { #[cfg(debug_assertions)] #[inline] + #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] fn runtime(this: *const (), count: usize, size: usize) -> bool { @@ -1622,6 +1627,7 @@ impl *const T { } #[inline] + #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] const fn const_impl(ptr: *const (), align: usize) -> bool { // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead. ptr.align_offset(align) == 0 diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 09c4002dbc7..5f20cb2ee72 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -92,7 +92,7 @@ pub trait Thin = Pointee; /// /// assert_eq!(std::ptr::metadata("foo"), 3_usize); /// ``` -#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[inline] pub const fn metadata(ptr: *const T) -> ::Metadata { ptr_metadata(ptr) @@ -106,7 +106,7 @@ pub const fn metadata(ptr: *const T) -> ::Metadata { /// /// [`slice::from_raw_parts`]: crate::slice::from_raw_parts #[unstable(feature = "ptr_metadata", issue = "81513")] -#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[inline] pub const fn from_raw_parts( data_pointer: *const impl Thin, @@ -120,7 +120,7 @@ pub const fn from_raw_parts( /// /// See the documentation of [`from_raw_parts`] for more details. #[unstable(feature = "ptr_metadata", issue = "81513")] -#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[inline] pub const fn from_raw_parts_mut( data_pointer: *mut impl Thin, diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index f769b515877..e9f5bf4404e 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -134,7 +134,7 @@ //! # Provenance //! //! Pointers are not *simply* an "integer" or "address". For instance, it's uncontroversial -//! to say that a Use After Free is clearly Undefined Behaviour, even if you "get lucky" +//! to say that a Use After Free is clearly Undefined Behavior, even if you "get lucky" //! and the freed memory gets reallocated before your read/write (in fact this is the //! worst-case scenario, UAFs would be much less concerning if this didn't happen!). //! As another example, consider that [`wrapping_offset`] is documented to "remember" @@ -591,8 +591,8 @@ pub const fn null_mut() -> *mut T { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[inline(always)] #[must_use] -#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub const fn without_provenance(addr: usize) -> *const T { // An int-to-pointer transmute currently has exactly the intended semantics: it creates a // pointer without provenance. Note that this is *not* a stable guarantee about transmute @@ -602,7 +602,7 @@ pub const fn without_provenance(addr: usize) -> *const T { unsafe { mem::transmute(addr) } } -/// Creates a new pointer that is dangling, but well-aligned. +/// Creates a new pointer that is dangling, but non-null and well-aligned. /// /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. @@ -613,8 +613,8 @@ pub const fn without_provenance(addr: usize) -> *const T { /// some other means. #[inline(always)] #[must_use] -#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub const fn dangling() -> *const T { without_provenance(mem::align_of::()) } @@ -634,8 +634,8 @@ pub const fn dangling() -> *const T { /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[inline(always)] #[must_use] -#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub const fn without_provenance_mut(addr: usize) -> *mut T { // An int-to-pointer transmute currently has exactly the intended semantics: it creates a // pointer without provenance. Note that this is *not* a stable guarantee about transmute @@ -645,7 +645,7 @@ pub const fn without_provenance_mut(addr: usize) -> *mut T { unsafe { mem::transmute(addr) } } -/// Creates a new pointer that is dangling, but well-aligned. +/// Creates a new pointer that is dangling, but non-null and well-aligned. /// /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. @@ -656,8 +656,8 @@ pub const fn without_provenance_mut(addr: usize) -> *mut T { /// some other means. #[inline(always)] #[must_use] -#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub const fn dangling_mut() -> *mut T { without_provenance_mut(mem::align_of::()) } @@ -1125,7 +1125,7 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { unsafe { swap_nonoverlapping_simple_untyped(x, y, count) } } -/// Same behaviour and safety conditions as [`swap_nonoverlapping`] +/// Same behavior and safety conditions as [`swap_nonoverlapping`] /// /// LLVM can vectorize this (at least it can for the power-of-two-sized types /// `swap_nonoverlapping` tries to use) so no need to manually SIMD it. @@ -1854,6 +1854,7 @@ pub unsafe fn write_volatile(dst: *mut T, src: T) { /// Any questions go to @nagisa. #[allow(ptr_to_integer_transmute_in_consts)] #[lang = "align_offset"] +#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] pub(crate) const unsafe fn align_offset(p: *const T, a: usize) -> usize { // FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <= // 1, where the method versions of these operations are not inlined. @@ -2107,13 +2108,39 @@ pub fn addr_eq(p: *const T, q: *const U) -> bool { /// Compares the *addresses* of the two function pointers for equality. /// -/// Function pointers comparisons can have surprising results since -/// they are never guaranteed to be unique and could vary between different -/// code generation units. Furthermore, different functions could have the -/// same address after being merged together. +/// This is the same as `f == g`, but using this function makes clear that the potentially +/// surprising semantics of function pointer comparison are involved. +/// +/// There are **very few guarantees** about how functions are compiled and they have no intrinsic +/// “identity”; in particular, this comparison: +/// +/// * May return `true` unexpectedly, in cases where functions are equivalent. +/// +/// For example, the following program is likely (but not guaranteed) to print `(true, true)` +/// when compiled with optimization: +/// +/// ``` +/// # #![feature(ptr_fn_addr_eq)] +/// let f: fn(i32) -> i32 = |x| x; +/// let g: fn(i32) -> i32 = |x| x + 0; // different closure, different body +/// let h: fn(u32) -> u32 = |x| x + 0; // different signature too +/// dbg!(std::ptr::fn_addr_eq(f, g), std::ptr::fn_addr_eq(f, h)); // not guaranteed to be equal +/// ``` +/// +/// * May return `false` in any case. +/// +/// This is particularly likely with generic functions but may happen with any function. +/// (From an implementation perspective, this is possible because functions may sometimes be +/// processed more than once by the compiler, resulting in duplicate machine code.) +/// +/// Despite these false positives and false negatives, this comparison can still be useful. +/// Specifically, if +/// +/// * `T` is the same type as `U`, `T` is a [subtype] of `U`, or `U` is a [subtype] of `T`, and +/// * `ptr::fn_addr_eq(f, g)` returns true, +/// +/// then calling `f` and calling `g` will be equivalent. /// -/// This is the same as `f == g` but using this function makes clear -/// that you are aware of these potentially surprising semantics. /// /// # Examples /// @@ -2125,6 +2152,8 @@ pub fn addr_eq(p: *const T, q: *const U) -> bool { /// fn b() { println!("b"); } /// assert!(!ptr::fn_addr_eq(a as fn(), b as fn())); /// ``` +/// +/// [subtype]: https://doc.rust-lang.org/reference/subtyping.html #[unstable(feature = "ptr_fn_addr_eq", issue = "129322")] #[inline(always)] #[must_use = "function pointer comparison produces a value"] diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 782934fc311..408e722267a 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -94,7 +94,7 @@ impl *mut T { /// // This dereference is UB. The pointer only has provenance for `x` but points to `y`. /// println!("{:?}", unsafe { &*bad }); #[unstable(feature = "set_ptr_value", issue = "75091")] - #[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] #[must_use = "returns a new pointer rather than modifying its argument"] #[inline] pub const fn with_metadata_of(self, meta: *const U) -> *mut U @@ -405,6 +405,7 @@ impl *mut T { T: Sized, { #[inline] + #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool { #[inline] fn runtime(this: *const (), count: isize, size: usize) -> bool { @@ -867,7 +868,7 @@ impl *mut T { /// but it provides slightly more information to the optimizer, which can /// sometimes allow it to optimize slightly better with some backends. /// - /// This method can be though of as recovering the `count` that was passed + /// This method can be thought of as recovering the `count` that was passed /// to [`add`](#method.add) (or, with the parameters in the other order, /// to [`sub`](#method.sub)). The following are all equivalent, assuming /// that their safety preconditions are met: @@ -984,6 +985,7 @@ impl *mut T { { #[cfg(debug_assertions)] #[inline] + #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] fn runtime(this: *const (), count: usize, size: usize) -> bool { @@ -1092,6 +1094,7 @@ impl *mut T { { #[cfg(debug_assertions)] #[inline] + #[rustc_allow_const_fn_unstable(const_eval_select)] const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] fn runtime(this: *const (), count: usize, size: usize) -> bool { @@ -1871,6 +1874,7 @@ impl *mut T { } #[inline] + #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] const fn const_impl(ptr: *mut (), align: usize) -> bool { // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead. ptr.align_offset(align) == 0 diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index d91bbe1a5a1..86ef1f3f005 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -107,9 +107,7 @@ impl NonNull { #[must_use] #[inline] pub const fn dangling() -> Self { - // SAFETY: mem::align_of() returns a non-zero usize which is then casted - // to a *mut T. Therefore, `ptr` is not null and the conditions for - // calling new_unchecked() are respected. + // SAFETY: ptr::dangling_mut() returns a non-null well-aligned pointer. unsafe { let ptr = crate::ptr::dangling_mut::(); NonNull::new_unchecked(ptr) @@ -1510,7 +1508,6 @@ impl NonNull<[T]> { #[inline] #[must_use] #[unstable(feature = "slice_ptr_get", issue = "74265")] - #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] pub const fn as_non_null_ptr(self) -> NonNull { self.cast() } diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index 4810ebe01f9..a796820a7e4 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -92,6 +92,7 @@ impl Unique { /// Creates a new `Unique` if `ptr` is non-null. #[inline] + #[rustc_const_unstable(feature = "ptr_internals", issue = "none")] pub const fn new(ptr: *mut T) -> Option { if let Some(pointer) = NonNull::new(ptr) { Some(Unique { pointer, _marker: PhantomData }) diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index a03e9fbae11..21e0460072f 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -346,6 +346,8 @@ pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool { /// If any of these loads produces something for which `contains_nonascii` /// (above) returns true, then we know the answer is false. #[inline] +#[rustc_allow_const_fn_unstable(const_raw_ptr_comparison, const_pointer_is_aligned)] // only in a debug assertion +#[rustc_allow_const_fn_unstable(const_align_offset)] // behavior does not change when `align_offset` fails const fn is_ascii(s: &[u8]) -> bool { const USIZE_SIZE: usize = mem::size_of::(); diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 1769612def0..9cb00644e64 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -257,3 +257,29 @@ impl SliceContains for i8 { memchr::memchr(byte, bytes).is_some() } } + +macro_rules! impl_slice_contains { + ($($t:ty),*) => { + $( + impl SliceContains for $t { + #[inline] + fn slice_contains(&self, arr: &[$t]) -> bool { + // Make our LANE_COUNT 4x the normal lane count (aiming for 128 bit vectors). + // The compiler will nicely unroll it. + const LANE_COUNT: usize = 4 * (128 / (mem::size_of::<$t>() * 8)); + // SIMD + let mut chunks = arr.chunks_exact(LANE_COUNT); + for chunk in &mut chunks { + if chunk.iter().fold(false, |acc, x| acc | (*x == *self)) { + return true; + } + } + // Scalar remainder + return chunks.remainder().iter().any(|x| *x == *self); + } + } + )* + }; +} + +impl_slice_contains!(u16, u32, u64, i16, i32, i64, f32, f64, usize, isize); diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index bc8571c8503..231ab7396ad 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -31,6 +31,7 @@ where #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] +#[rustc_allow_const_fn_unstable(const_eval_select)] const fn slice_start_index_len_fail(index: usize, len: usize) -> ! { // FIXME(const-hack): once integer formatting in panics is possible, we // should use the same implementation at compiletime and runtime. @@ -52,6 +53,7 @@ const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] +#[rustc_allow_const_fn_unstable(const_eval_select)] const fn slice_end_index_len_fail(index: usize, len: usize) -> ! { // FIXME(const-hack): once integer formatting in panics is possible, we // should use the same implementation at compiletime and runtime. @@ -73,6 +75,7 @@ const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] +#[rustc_allow_const_fn_unstable(const_eval_select)] const fn slice_index_order_fail(index: usize, end: usize) -> ! { // FIXME(const-hack): once integer formatting in panics is possible, we // should use the same implementation at compiletime and runtime. @@ -310,7 +313,6 @@ unsafe impl SliceIndex<[T]> for usize { /// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here /// than there are for a general `Range` (which might be `100..3`). -#[rustc_const_unstable(feature = "const_index_range_slice_index", issue = "none")] unsafe impl SliceIndex<[T]> for ops::IndexRange { type Output = [T]; diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs index be19c3d3bc1..57604623262 100644 --- a/library/core/src/slice/memchr.rs +++ b/library/core/src/slice/memchr.rs @@ -15,7 +15,7 @@ const USIZE_BYTES: usize = mem::size_of::(); /// bytes where the borrow propagated all the way to the most significant /// bit." #[inline] -#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))] const fn contains_zero_byte(x: usize) -> bool { x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0 } @@ -23,7 +23,7 @@ const fn contains_zero_byte(x: usize) -> bool { /// Returns the first index matching the byte `x` in `text`. #[inline] #[must_use] -#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))] pub const fn memchr(x: u8, text: &[u8]) -> Option { // Fast path for small slices. if text.len() < 2 * USIZE_BYTES { @@ -34,7 +34,7 @@ pub const fn memchr(x: u8, text: &[u8]) -> Option { } #[inline] -#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))] const fn memchr_naive(x: u8, text: &[u8]) -> Option { let mut i = 0; @@ -52,7 +52,7 @@ const fn memchr_naive(x: u8, text: &[u8]) -> Option { #[rustc_allow_const_fn_unstable(const_cmp)] #[rustc_allow_const_fn_unstable(const_align_offset)] -#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))] const fn memchr_aligned(x: u8, text: &[u8]) -> Option { // Scan for a single byte value by reading two `usize` words at a time. // diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index dbcfe946440..27e51afa800 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1265,6 +1265,7 @@ impl [T] { /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] + #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked(&self) -> &[[T; N]] { @@ -1310,6 +1311,7 @@ impl [T] { /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] + #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1344,6 +1346,7 @@ impl [T] { /// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] + #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1422,6 +1425,7 @@ impl [T] { /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] + #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked_mut(&mut self) -> &mut [[T; N]] { @@ -1462,6 +1466,7 @@ impl [T] { /// assert_eq!(v, &[1, 1, 2, 2, 9]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] + #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] @@ -1502,6 +1507,7 @@ impl [T] { /// assert_eq!(v, &[9, 1, 1, 2, 2]); /// ``` #[unstable(feature = "slice_as_chunks", issue = "74985")] + #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[track_caller] #[must_use] diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index eb60effe813..665c9fc67d0 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -57,9 +57,9 @@ use crate::{cmp, fmt}; /// [`Searcher`] type, which does the actual work of finding /// occurrences of the pattern in a string. /// -/// Depending on the type of the pattern, the behaviour of methods like +/// Depending on the type of the pattern, the behavior of methods like /// [`str::find`] and [`str::contains`] can change. The table below describes -/// some of those behaviours. +/// some of those behaviors. /// /// | Pattern type | Match condition | /// |--------------------------|-------------------------------------------| @@ -162,7 +162,9 @@ pub trait Pattern: Sized { } /// Returns the pattern as utf-8 bytes if possible. - fn as_utf8_pattern(&self) -> Option>; + fn as_utf8_pattern(&self) -> Option> { + None + } } /// Result of calling [`Pattern::as_utf8_pattern()`]. /// Can be used for inspecting the contents of a [`Pattern`] in cases @@ -675,11 +677,6 @@ impl Pattern for MultiCharEqPattern { fn into_searcher(self, haystack: &str) -> MultiCharEqSearcher<'_, C> { MultiCharEqSearcher { haystack, char_eq: self.0, char_indices: haystack.char_indices() } } - - #[inline] - fn as_utf8_pattern(&self) -> Option> { - None - } } unsafe impl<'a, C: MultiCharEq> Searcher<'a> for MultiCharEqSearcher<'a, C> { @@ -770,11 +767,6 @@ macro_rules! pattern_methods { { ($pmap)(self).strip_suffix_of(haystack) } - - #[inline] - fn as_utf8_pattern(&self) -> Option> { - None - } }; } diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 17ba18c2a66..93b4ad5c1c9 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -2122,7 +2122,8 @@ macro_rules! atomic_int { $stable_access:meta, $stable_from:meta, $stable_nand:meta, - $const_stable:meta, + $const_stable_new:meta, + $const_stable_into_inner:meta, $diagnostic_item:meta, $s_int_type:literal, $extra_feature:expr, @@ -2204,7 +2205,7 @@ macro_rules! atomic_int { /// ``` #[inline] #[$stable] - #[$const_stable] + #[$const_stable_new] #[must_use] pub const fn new(v: $int_type) -> Self { Self {v: UnsafeCell::new(v)} @@ -2406,7 +2407,7 @@ macro_rules! atomic_int { /// ``` #[inline] #[$stable_access] - #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")] + #[$const_stable_into_inner] pub const fn into_inner(self) -> $int_type { self.v.into_inner() } @@ -3054,6 +3055,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI8"), "i8", "", @@ -3072,6 +3074,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU8"), "u8", "", @@ -3090,6 +3093,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI16"), "i16", "", @@ -3108,6 +3112,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU16"), "u16", "", @@ -3126,6 +3131,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI32"), "i32", "", @@ -3144,6 +3150,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU32"), "u32", "", @@ -3162,6 +3169,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI64"), "i64", "", @@ -3180,6 +3188,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU64"), "u64", "", @@ -3197,7 +3206,8 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "99069"), unstable(feature = "integer_atomics", issue = "99069"), unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_unstable(feature = "integer_atomics", issue = "99069"), + rustc_const_unstable(feature = "integer_atomics", issue = "99069"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"), "i128", "#![feature(integer_atomics)]\n\n", @@ -3215,7 +3225,8 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "99069"), unstable(feature = "integer_atomics", issue = "99069"), unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_unstable(feature = "integer_atomics", issue = "99069"), + rustc_const_unstable(feature = "integer_atomics", issue = "99069"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"), "u128", "#![feature(integer_atomics)]\n\n", @@ -3238,6 +3249,7 @@ macro_rules! atomic_int_ptr_sized { stable(feature = "atomic_from", since = "1.23.0"), stable(feature = "atomic_nand", since = "1.27.0"), rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicIsize"), "isize", "", @@ -3256,6 +3268,7 @@ macro_rules! atomic_int_ptr_sized { stable(feature = "atomic_from", since = "1.23.0"), stable(feature = "atomic_nand", since = "1.27.0"), rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"), + rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicUsize"), "usize", "", diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs index fbf8dafad18..af25f139739 100644 --- a/library/core/src/sync/exclusive.rs +++ b/library/core/src/sync/exclusive.rs @@ -106,6 +106,7 @@ impl Exclusive { /// Unwrap the value contained in the `Exclusive` #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] pub const fn into_inner(self) -> T { @@ -129,6 +130,7 @@ impl Exclusive { /// access to the underlying value, but _pinned_ `Exclusive`s only /// produce _pinned_ access to the underlying value. #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { @@ -152,6 +154,7 @@ impl Exclusive { /// a _pinned mutable_ reference to a `T`. This allows you to skip /// building an `Exclusive` with [`Exclusive::new`]. #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut Exclusive> { diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 3e795e7b5e3..fb7af8234dd 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -321,7 +321,7 @@ impl<'a> ContextBuilder<'a> { /// Creates a ContextBuilder from a Waker. #[inline] #[unstable(feature = "local_waker", issue = "118959")] - #[rustc_const_stable(feature = "const_waker", since = "1.82.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_waker", since = "1.82.0"))] pub const fn from_waker(waker: &'a Waker) -> Self { // SAFETY: LocalWaker is just Waker without thread safety let local_waker = unsafe { transmute(waker) }; @@ -379,7 +379,7 @@ impl<'a> ContextBuilder<'a> { /// Builds the `Context`. #[inline] #[unstable(feature = "local_waker", issue = "118959")] - #[rustc_const_stable(feature = "const_waker", since = "1.82.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_waker", since = "1.82.0"))] pub const fn build(self) -> Context<'a> { let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self; Context { waker, local_waker, ext: AssertUnwindSafe(ext), _marker, _marker2 } diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index daaaf5a7195..91566439ade 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -47,7 +47,7 @@ use crate::intrinsics::{self, const_eval_select}; /// order to call it. Since the precompiled standard library is built with full debuginfo and these /// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough /// debuginfo to have a measurable compile-time impact on debug builds. -#[allow_internal_unstable(const_ub_checks)] // permit this to be called in stably-const fn +#[cfg_attr(bootstrap, allow_internal_unstable(const_ub_checks))] // permit this to be called in stably-const fn #[macro_export] #[unstable(feature = "ub_checks", issue = "none")] macro_rules! assert_unsafe_precondition { @@ -64,7 +64,8 @@ macro_rules! assert_unsafe_precondition { #[rustc_no_mir_inline] #[inline] #[rustc_nounwind] - #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] + #[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( @@ -90,8 +91,9 @@ pub use intrinsics::ub_checks as check_library_ub; /// /// The intention is to not do that when running in the interpreter, as that one has its own /// language UB checks which generally produce better errors. -#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] #[inline] +#[rustc_allow_const_fn_unstable(const_eval_select)] pub(crate) const fn check_language_ub() -> bool { #[inline] fn runtime() -> bool { @@ -116,6 +118,7 @@ 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 { ptr.is_aligned_to(align) && (is_zst || !ptr.is_null()) } @@ -132,6 +135,7 @@ 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( src: *const (), dst: *const (), diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 5d6921845d0..2a9f1660a62 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -17,11 +17,13 @@ #![feature(clone_to_uninit)] #![feature(const_align_of_val_raw)] #![feature(const_align_offset)] +#![feature(const_bigint_helper_methods)] #![feature(const_black_box)] +#![feature(const_eval_select)] #![feature(const_hash)] #![feature(const_heap)] -#![feature(const_likely)] #![feature(const_nonnull_new)] +#![feature(const_num_midpoint)] #![feature(const_option_ext)] #![feature(const_pin_2)] #![feature(const_pointer_is_aligned)] @@ -46,11 +48,11 @@ #![feature(get_many_mut)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] +#![feature(inline_const_pat)] #![feature(int_roundings)] #![feature(ip)] #![feature(ip_from)] #![feature(is_ascii_octdigit)] -#![feature(isqrt)] #![feature(iter_advance_by)] #![feature(iter_array_chunks)] #![feature(iter_chain)] @@ -104,6 +106,37 @@ #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] +/// Version of `assert_matches` that ignores fancy runtime printing in const context and uses structural equality. +macro_rules! assert_eq_const_safe { + ($left:expr, $right:expr$(, $($arg:tt)+)?) => { + { + fn runtime() { + assert_eq!($left, $right, $($arg)*); + } + const fn compiletime() { + assert!(matches!($left, const { $right })); + } + core::intrinsics::const_eval_select((), compiletime, runtime) + } + }; +} + +/// Creates a test for runtime and a test for constant-time. +macro_rules! test_runtime_and_compiletime { + ($( + $(#[$attr:meta])* + fn $test:ident() $block:block + )*) => { + $( + $(#[$attr])* + #[test] + fn $test() $block + $(#[$attr])* + const _: () = $block; + )* + } +} + mod alloc; mod any; mod array; diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 6a26bd15a66..474d57049ab 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -17,42 +17,6 @@ macro_rules! int_module { num::test_num(10 as $T, 2 as $T); } - #[test] - fn test_rem_euclid() { - assert_eq!((-1 as $T).rem_euclid(MIN), MAX); - } - - #[test] - pub fn test_abs() { - assert_eq!((1 as $T).abs(), 1 as $T); - assert_eq!((0 as $T).abs(), 0 as $T); - assert_eq!((-1 as $T).abs(), 1 as $T); - } - - #[test] - fn test_signum() { - assert_eq!((1 as $T).signum(), 1 as $T); - assert_eq!((0 as $T).signum(), 0 as $T); - assert_eq!((-0 as $T).signum(), 0 as $T); - assert_eq!((-1 as $T).signum(), -1 as $T); - } - - #[test] - fn test_is_positive() { - assert!((1 as $T).is_positive()); - assert!(!(0 as $T).is_positive()); - assert!(!(-0 as $T).is_positive()); - assert!(!(-1 as $T).is_positive()); - } - - #[test] - fn test_is_negative() { - assert!(!(1 as $T).is_negative()); - assert!(!(0 as $T).is_negative()); - assert!(!(-0 as $T).is_negative()); - assert!((-1 as $T).is_negative()); - } - #[test] fn test_bitwise_operators() { assert_eq!(0b1110 as $T, (0b1100 as $T).bitor(0b1010 as $T)); @@ -63,6 +27,40 @@ macro_rules! int_module { assert_eq!(-(0b11 as $T) - (1 as $T), (0b11 as $T).not()); } + test_runtime_and_compiletime! { + + fn test_rem_euclid() { + assert_eq_const_safe!((-1 as $T).rem_euclid(MIN), MAX); + } + + fn test_abs() { + assert_eq_const_safe!((1 as $T).abs(), 1 as $T); + assert_eq_const_safe!((0 as $T).abs(), 0 as $T); + assert_eq_const_safe!((-1 as $T).abs(), 1 as $T); + } + + fn test_signum() { + assert_eq_const_safe!((1 as $T).signum(), 1 as $T); + assert_eq_const_safe!((0 as $T).signum(), 0 as $T); + assert_eq_const_safe!((-0 as $T).signum(), 0 as $T); + assert_eq_const_safe!((-1 as $T).signum(), -1 as $T); + } + + fn test_is_positive() { + assert!((1 as $T).is_positive()); + assert!(!(0 as $T).is_positive()); + assert!(!(-0 as $T).is_positive()); + assert!(!(-1 as $T).is_positive()); + } + + fn test_is_negative() { + assert!(!(1 as $T).is_negative()); + assert!(!(0 as $T).is_negative()); + assert!(!(-0 as $T).is_negative()); + assert!((-1 as $T).is_negative()); + } + } + const A: $T = 0b0101100; const B: $T = 0b0100001; const C: $T = 0b1111001; @@ -70,134 +68,126 @@ macro_rules! int_module { const _0: $T = 0; const _1: $T = !0; - #[test] - fn test_count_ones() { - assert_eq!(A.count_ones(), 3); - assert_eq!(B.count_ones(), 2); - assert_eq!(C.count_ones(), 5); - } + test_runtime_and_compiletime! { + fn test_count_ones() { + assert_eq_const_safe!(A.count_ones(), 3); + assert_eq_const_safe!(B.count_ones(), 2); + assert_eq_const_safe!(C.count_ones(), 5); + } - #[test] - fn test_count_zeros() { - assert_eq!(A.count_zeros(), $T::BITS - 3); - assert_eq!(B.count_zeros(), $T::BITS - 2); - assert_eq!(C.count_zeros(), $T::BITS - 5); - } + fn test_count_zeros() { + assert_eq_const_safe!(A.count_zeros(), $T::BITS - 3); + assert_eq_const_safe!(B.count_zeros(), $T::BITS - 2); + assert_eq_const_safe!(C.count_zeros(), $T::BITS - 5); + } - #[test] - fn test_leading_trailing_ones() { - let a: $T = 0b0101_1111; - assert_eq!(a.trailing_ones(), 5); - assert_eq!((!a).leading_ones(), $T::BITS - 7); + fn test_leading_trailing_ones() { + const A: $T = 0b0101_1111; + assert_eq_const_safe!(A.trailing_ones(), 5); + assert_eq_const_safe!((!A).leading_ones(), $T::BITS - 7); - assert_eq!(a.reverse_bits().leading_ones(), 5); + assert_eq_const_safe!(A.reverse_bits().leading_ones(), 5); - assert_eq!(_1.leading_ones(), $T::BITS); - assert_eq!(_1.trailing_ones(), $T::BITS); + assert_eq_const_safe!(_1.leading_ones(), $T::BITS); + assert_eq_const_safe!(_1.trailing_ones(), $T::BITS); - assert_eq!((_1 << 1).trailing_ones(), 0); - assert_eq!(MAX.leading_ones(), 0); + assert_eq_const_safe!((_1 << 1).trailing_ones(), 0); + assert_eq_const_safe!(MAX.leading_ones(), 0); - assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1); - assert_eq!(MAX.trailing_ones(), $T::BITS - 1); + assert_eq_const_safe!((_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq_const_safe!(MAX.trailing_ones(), $T::BITS - 1); - assert_eq!(_0.leading_ones(), 0); - assert_eq!(_0.trailing_ones(), 0); + assert_eq_const_safe!(_0.leading_ones(), 0); + assert_eq_const_safe!(_0.trailing_ones(), 0); - let x: $T = 0b0010_1100; - assert_eq!(x.leading_ones(), 0); - assert_eq!(x.trailing_ones(), 0); - } + const X: $T = 0b0010_1100; + assert_eq_const_safe!(X.leading_ones(), 0); + assert_eq_const_safe!(X.trailing_ones(), 0); + } - #[test] - fn test_rotate() { - assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); - assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); - assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); + fn test_rotate() { + assert_eq_const_safe!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); + assert_eq_const_safe!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); + assert_eq_const_safe!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); - // Rotating these should make no difference - // - // We test using 124 bits because to ensure that overlong bit shifts do - // not cause undefined behaviour. See #10183. - assert_eq!(_0.rotate_left(124), _0); - assert_eq!(_1.rotate_left(124), _1); - assert_eq!(_0.rotate_right(124), _0); - assert_eq!(_1.rotate_right(124), _1); + // Rotating these should make no difference + // + // We test using 124 bits because to ensure that overlong bit shifts do + // not cause undefined behavior. See #10183. + assert_eq_const_safe!(_0.rotate_left(124), _0); + assert_eq_const_safe!(_1.rotate_left(124), _1); + assert_eq_const_safe!(_0.rotate_right(124), _0); + assert_eq_const_safe!(_1.rotate_right(124), _1); - // Rotating by 0 should have no effect - assert_eq!(A.rotate_left(0), A); - assert_eq!(B.rotate_left(0), B); - assert_eq!(C.rotate_left(0), C); - // Rotating by a multiple of word size should also have no effect - assert_eq!(A.rotate_left(128), A); - assert_eq!(B.rotate_left(128), B); - assert_eq!(C.rotate_left(128), C); - } + // Rotating by 0 should have no effect + assert_eq_const_safe!(A.rotate_left(0), A); + assert_eq_const_safe!(B.rotate_left(0), B); + assert_eq_const_safe!(C.rotate_left(0), C); + // Rotating by a multiple of word size should also have no effect + assert_eq_const_safe!(A.rotate_left(128), A); + assert_eq_const_safe!(B.rotate_left(128), B); + assert_eq_const_safe!(C.rotate_left(128), C); + } - #[test] - fn test_swap_bytes() { - assert_eq!(A.swap_bytes().swap_bytes(), A); - assert_eq!(B.swap_bytes().swap_bytes(), B); - assert_eq!(C.swap_bytes().swap_bytes(), C); + fn test_swap_bytes() { + assert_eq_const_safe!(A.swap_bytes().swap_bytes(), A); + assert_eq_const_safe!(B.swap_bytes().swap_bytes(), B); + assert_eq_const_safe!(C.swap_bytes().swap_bytes(), C); - // Swapping these should make no difference - assert_eq!(_0.swap_bytes(), _0); - assert_eq!(_1.swap_bytes(), _1); - } + // Swapping these should make no difference + assert_eq_const_safe!(_0.swap_bytes(), _0); + assert_eq_const_safe!(_1.swap_bytes(), _1); + } - #[test] - fn test_le() { - assert_eq!($T::from_le(A.to_le()), A); - assert_eq!($T::from_le(B.to_le()), B); - assert_eq!($T::from_le(C.to_le()), C); - assert_eq!($T::from_le(_0), _0); - assert_eq!($T::from_le(_1), _1); - assert_eq!(_0.to_le(), _0); - assert_eq!(_1.to_le(), _1); - } + fn test_le() { + assert_eq_const_safe!($T::from_le(A.to_le()), A); + assert_eq_const_safe!($T::from_le(B.to_le()), B); + assert_eq_const_safe!($T::from_le(C.to_le()), C); + assert_eq_const_safe!($T::from_le(_0), _0); + assert_eq_const_safe!($T::from_le(_1), _1); + assert_eq_const_safe!(_0.to_le(), _0); + assert_eq_const_safe!(_1.to_le(), _1); + } - #[test] - fn test_be() { - assert_eq!($T::from_be(A.to_be()), A); - assert_eq!($T::from_be(B.to_be()), B); - assert_eq!($T::from_be(C.to_be()), C); - assert_eq!($T::from_be(_0), _0); - assert_eq!($T::from_be(_1), _1); - assert_eq!(_0.to_be(), _0); - assert_eq!(_1.to_be(), _1); - } + fn test_be() { + assert_eq_const_safe!($T::from_be(A.to_be()), A); + assert_eq_const_safe!($T::from_be(B.to_be()), B); + assert_eq_const_safe!($T::from_be(C.to_be()), C); + assert_eq_const_safe!($T::from_be(_0), _0); + assert_eq_const_safe!($T::from_be(_1), _1); + assert_eq_const_safe!(_0.to_be(), _0); + assert_eq_const_safe!(_1.to_be(), _1); + } - #[test] - fn test_signed_checked_div() { - assert_eq!((10 as $T).checked_div(2), Some(5)); - assert_eq!((5 as $T).checked_div(0), None); - assert_eq!(isize::MIN.checked_div(-1), None); - } + fn test_signed_checked_div() { + assert_eq_const_safe!((10 as $T).checked_div(2), Some(5)); + assert_eq_const_safe!((5 as $T).checked_div(0), None); + assert_eq_const_safe!(isize::MIN.checked_div(-1), None); + } - #[test] - fn test_saturating_abs() { - assert_eq!((0 as $T).saturating_abs(), 0); - assert_eq!((123 as $T).saturating_abs(), 123); - assert_eq!((-123 as $T).saturating_abs(), 123); - assert_eq!((MAX - 2).saturating_abs(), MAX - 2); - assert_eq!((MAX - 1).saturating_abs(), MAX - 1); - assert_eq!(MAX.saturating_abs(), MAX); - assert_eq!((MIN + 2).saturating_abs(), MAX - 1); - assert_eq!((MIN + 1).saturating_abs(), MAX); - assert_eq!(MIN.saturating_abs(), MAX); - } + fn test_saturating_abs() { + assert_eq_const_safe!((0 as $T).saturating_abs(), 0); + assert_eq_const_safe!((123 as $T).saturating_abs(), 123); + assert_eq_const_safe!((-123 as $T).saturating_abs(), 123); + assert_eq_const_safe!((MAX - 2).saturating_abs(), MAX - 2); + assert_eq_const_safe!((MAX - 1).saturating_abs(), MAX - 1); + assert_eq_const_safe!(MAX.saturating_abs(), MAX); + assert_eq_const_safe!((MIN + 2).saturating_abs(), MAX - 1); + assert_eq_const_safe!((MIN + 1).saturating_abs(), MAX); + assert_eq_const_safe!(MIN.saturating_abs(), MAX); + } - #[test] - fn test_saturating_neg() { - assert_eq!((0 as $T).saturating_neg(), 0); - assert_eq!((123 as $T).saturating_neg(), -123); - assert_eq!((-123 as $T).saturating_neg(), 123); - assert_eq!((MAX - 2).saturating_neg(), MIN + 3); - assert_eq!((MAX - 1).saturating_neg(), MIN + 2); - assert_eq!(MAX.saturating_neg(), MIN + 1); - assert_eq!((MIN + 2).saturating_neg(), MAX - 1); - assert_eq!((MIN + 1).saturating_neg(), MAX); - assert_eq!(MIN.saturating_neg(), MAX); + fn test_saturating_neg() { + assert_eq_const_safe!((0 as $T).saturating_neg(), 0); + assert_eq_const_safe!((123 as $T).saturating_neg(), -123); + assert_eq_const_safe!((-123 as $T).saturating_neg(), 123); + assert_eq_const_safe!((MAX - 2).saturating_neg(), MIN + 3); + assert_eq_const_safe!((MAX - 1).saturating_neg(), MIN + 2); + assert_eq_const_safe!(MAX.saturating_neg(), MIN + 1); + assert_eq_const_safe!((MIN + 2).saturating_neg(), MAX - 1); + assert_eq_const_safe!((MIN + 1).saturating_neg(), MAX); + assert_eq_const_safe!(MIN.saturating_neg(), MAX); + } } #[test] @@ -222,173 +212,173 @@ macro_rules! int_module { assert_eq!(from_str::<$T>("x"), None); } - #[test] - fn test_from_str_radix() { - assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T)); - assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T)); - assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T)); - assert_eq!(i32::from_str_radix("123", 16), Ok(291 as i32)); - assert_eq!(i32::from_str_radix("ffff", 16), Ok(65535 as i32)); - assert_eq!(i32::from_str_radix("FFFF", 16), Ok(65535 as i32)); - assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T)); - assert_eq!($T::from_str_radix("Z", 36), Ok(35 as $T)); + test_runtime_and_compiletime! { + fn test_from_str_radix() { + assert_eq_const_safe!($T::from_str_radix("123", 10), Ok(123 as $T)); + assert_eq_const_safe!($T::from_str_radix("1001", 2), Ok(9 as $T)); + assert_eq_const_safe!($T::from_str_radix("123", 8), Ok(83 as $T)); + assert_eq_const_safe!(i32::from_str_radix("123", 16), Ok(291 as i32)); + assert_eq_const_safe!(i32::from_str_radix("ffff", 16), Ok(65535 as i32)); + assert_eq_const_safe!(i32::from_str_radix("FFFF", 16), Ok(65535 as i32)); + assert_eq_const_safe!($T::from_str_radix("z", 36), Ok(35 as $T)); + assert_eq_const_safe!($T::from_str_radix("Z", 36), Ok(35 as $T)); - assert_eq!($T::from_str_radix("-123", 10), Ok(-123 as $T)); - assert_eq!($T::from_str_radix("-1001", 2), Ok(-9 as $T)); - assert_eq!($T::from_str_radix("-123", 8), Ok(-83 as $T)); - assert_eq!(i32::from_str_radix("-123", 16), Ok(-291 as i32)); - assert_eq!(i32::from_str_radix("-ffff", 16), Ok(-65535 as i32)); - assert_eq!(i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32)); - assert_eq!($T::from_str_radix("-z", 36), Ok(-35 as $T)); - assert_eq!($T::from_str_radix("-Z", 36), Ok(-35 as $T)); + assert_eq_const_safe!($T::from_str_radix("-123", 10), Ok(-123 as $T)); + assert_eq_const_safe!($T::from_str_radix("-1001", 2), Ok(-9 as $T)); + assert_eq_const_safe!($T::from_str_radix("-123", 8), Ok(-83 as $T)); + assert_eq_const_safe!(i32::from_str_radix("-123", 16), Ok(-291 as i32)); + assert_eq_const_safe!(i32::from_str_radix("-ffff", 16), Ok(-65535 as i32)); + assert_eq_const_safe!(i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32)); + assert_eq_const_safe!($T::from_str_radix("-z", 36), Ok(-35 as $T)); + assert_eq_const_safe!($T::from_str_radix("-Z", 36), Ok(-35 as $T)); - assert_eq!($T::from_str_radix("Z", 35).ok(), None::<$T>); - assert_eq!($T::from_str_radix("-9", 2).ok(), None::<$T>); - assert_eq!($T::from_str_radix("10_0", 10).ok(), None::<$T>); - assert_eq!(u32::from_str_radix("-9", 10).ok(), None::); - } + assert!($T::from_str_radix("Z", 35).is_err()); + assert!($T::from_str_radix("-9", 2).is_err()); + assert!($T::from_str_radix("10_0", 10).is_err()); + assert!(u32::from_str_radix("-9", 10).is_err()); + } - #[test] - fn test_pow() { - let mut r = 2 as $T; - assert_eq!(r.pow(2), 4 as $T); - assert_eq!(r.pow(0), 1 as $T); - assert_eq!(r.wrapping_pow(2), 4 as $T); - assert_eq!(r.wrapping_pow(0), 1 as $T); - assert_eq!(r.checked_pow(2), Some(4 as $T)); - assert_eq!(r.checked_pow(0), Some(1 as $T)); - assert_eq!(r.overflowing_pow(2), (4 as $T, false)); - assert_eq!(r.overflowing_pow(0), (1 as $T, false)); - assert_eq!(r.saturating_pow(2), 4 as $T); - assert_eq!(r.saturating_pow(0), 1 as $T); + fn test_pow() { + { + const R: $T = 2; + assert_eq_const_safe!(R.pow(2), 4 as $T); + assert_eq_const_safe!(R.pow(0), 1 as $T); + assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); + assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); + assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); + assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); + assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); + assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); + assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); + } - r = MAX; - // use `^` to represent .pow() with no overflow. - // if itest::MAX == 2^j-1, then itest is a `j` bit int, - // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`, - // thussaturating_pow the overflowing result is exactly 1. - assert_eq!(r.wrapping_pow(2), 1 as $T); - assert_eq!(r.checked_pow(2), None); - assert_eq!(r.overflowing_pow(2), (1 as $T, true)); - assert_eq!(r.saturating_pow(2), MAX); - //test for negative exponent. - r = -2 as $T; - assert_eq!(r.pow(2), 4 as $T); - assert_eq!(r.pow(3), -8 as $T); - assert_eq!(r.pow(0), 1 as $T); - assert_eq!(r.wrapping_pow(2), 4 as $T); - assert_eq!(r.wrapping_pow(3), -8 as $T); - assert_eq!(r.wrapping_pow(0), 1 as $T); - assert_eq!(r.checked_pow(2), Some(4 as $T)); - assert_eq!(r.checked_pow(3), Some(-8 as $T)); - assert_eq!(r.checked_pow(0), Some(1 as $T)); - assert_eq!(r.overflowing_pow(2), (4 as $T, false)); - assert_eq!(r.overflowing_pow(3), (-8 as $T, false)); - assert_eq!(r.overflowing_pow(0), (1 as $T, false)); - assert_eq!(r.saturating_pow(2), 4 as $T); - assert_eq!(r.saturating_pow(3), -8 as $T); - assert_eq!(r.saturating_pow(0), 1 as $T); - } + { + const R: $T = MAX; + // use `^` to represent .pow() with no overflow. + // if itest::MAX == 2^j-1, then itest is a `j` bit int, + // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`, + // thussaturating_pow the overflowing result is exactly 1. + assert_eq_const_safe!(R.wrapping_pow(2), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), None); + assert_eq_const_safe!(R.overflowing_pow(2), (1 as $T, true)); + assert_eq_const_safe!(R.saturating_pow(2), MAX); + } - #[test] - fn test_div_floor() { - let a: $T = 8; - let b = 3; - assert_eq!(a.div_floor(b), 2); - assert_eq!(a.div_floor(-b), -3); - assert_eq!((-a).div_floor(b), -3); - assert_eq!((-a).div_floor(-b), 2); - } + { + // test for negative exponent. + const R: $T = -2; + assert_eq_const_safe!(R.pow(2), 4 as $T); + assert_eq_const_safe!(R.pow(3), -8 as $T); + assert_eq_const_safe!(R.pow(0), 1 as $T); + assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); + assert_eq_const_safe!(R.wrapping_pow(3), -8 as $T); + assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); + assert_eq_const_safe!(R.checked_pow(3), Some(-8 as $T)); + assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); + assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); + assert_eq_const_safe!(R.overflowing_pow(3), (-8 as $T, false)); + assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); + assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); + assert_eq_const_safe!(R.saturating_pow(3), -8 as $T); + assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); + } + } - #[test] - fn test_div_ceil() { - let a: $T = 8; - let b = 3; - assert_eq!(a.div_ceil(b), 3); - assert_eq!(a.div_ceil(-b), -2); - assert_eq!((-a).div_ceil(b), -2); - assert_eq!((-a).div_ceil(-b), 3); - } + fn test_div_floor() { + const A: $T = 8; + const B: $T = 3; + assert_eq_const_safe!(A.div_floor(B), 2); + assert_eq_const_safe!(A.div_floor(-B), -3); + assert_eq_const_safe!((-A).div_floor(B), -3); + assert_eq_const_safe!((-A).div_floor(-B), 2); + } - #[test] - fn test_next_multiple_of() { - assert_eq!((16 as $T).next_multiple_of(8), 16); - assert_eq!((23 as $T).next_multiple_of(8), 24); - assert_eq!((16 as $T).next_multiple_of(-8), 16); - assert_eq!((23 as $T).next_multiple_of(-8), 16); - assert_eq!((-16 as $T).next_multiple_of(8), -16); - assert_eq!((-23 as $T).next_multiple_of(8), -16); - assert_eq!((-16 as $T).next_multiple_of(-8), -16); - assert_eq!((-23 as $T).next_multiple_of(-8), -24); - assert_eq!(MIN.next_multiple_of(-1), MIN); - } + fn test_div_ceil() { + const A: $T = 8; + const B: $T = 3; + assert_eq_const_safe!(A.div_ceil(B), 3); + assert_eq_const_safe!(A.div_ceil(-B), -2); + assert_eq_const_safe!((-A).div_ceil(B), -2); + assert_eq_const_safe!((-A).div_ceil(-B), 3); + } - #[test] - fn test_checked_next_multiple_of() { - assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16)); - assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24)); - assert_eq!((16 as $T).checked_next_multiple_of(-8), Some(16)); - assert_eq!((23 as $T).checked_next_multiple_of(-8), Some(16)); - assert_eq!((-16 as $T).checked_next_multiple_of(8), Some(-16)); - assert_eq!((-23 as $T).checked_next_multiple_of(8), Some(-16)); - assert_eq!((-16 as $T).checked_next_multiple_of(-8), Some(-16)); - assert_eq!((-23 as $T).checked_next_multiple_of(-8), Some(-24)); - assert_eq!((1 as $T).checked_next_multiple_of(0), None); - assert_eq!(MAX.checked_next_multiple_of(2), None); - assert_eq!(MIN.checked_next_multiple_of(-3), None); - assert_eq!(MIN.checked_next_multiple_of(-1), Some(MIN)); - } + fn test_next_multiple_of() { + assert_eq_const_safe!((16 as $T).next_multiple_of(8), 16); + assert_eq_const_safe!((23 as $T).next_multiple_of(8), 24); + assert_eq_const_safe!((16 as $T).next_multiple_of(-8), 16); + assert_eq_const_safe!((23 as $T).next_multiple_of(-8), 16); + assert_eq_const_safe!((-16 as $T).next_multiple_of(8), -16); + assert_eq_const_safe!((-23 as $T).next_multiple_of(8), -16); + assert_eq_const_safe!((-16 as $T).next_multiple_of(-8), -16); + assert_eq_const_safe!((-23 as $T).next_multiple_of(-8), -24); + assert_eq_const_safe!(MIN.next_multiple_of(-1), MIN); + } - #[test] - fn test_carrying_add() { - assert_eq!($T::MAX.carrying_add(1, false), ($T::MIN, true)); - assert_eq!($T::MAX.carrying_add(0, true), ($T::MIN, true)); - assert_eq!($T::MAX.carrying_add(1, true), ($T::MIN + 1, true)); - assert_eq!($T::MAX.carrying_add(-1, false), ($T::MAX - 1, false)); - assert_eq!($T::MAX.carrying_add(-1, true), ($T::MAX, false)); // no intermediate overflow - assert_eq!($T::MIN.carrying_add(-1, false), ($T::MAX, true)); - assert_eq!($T::MIN.carrying_add(-1, true), ($T::MIN, false)); // no intermediate overflow - assert_eq!((0 as $T).carrying_add($T::MAX, true), ($T::MIN, true)); - assert_eq!((0 as $T).carrying_add($T::MIN, true), ($T::MIN + 1, false)); - } + fn test_checked_next_multiple_of() { + assert_eq_const_safe!((16 as $T).checked_next_multiple_of(8), Some(16)); + assert_eq_const_safe!((23 as $T).checked_next_multiple_of(8), Some(24)); + assert_eq_const_safe!((16 as $T).checked_next_multiple_of(-8), Some(16)); + assert_eq_const_safe!((23 as $T).checked_next_multiple_of(-8), Some(16)); + assert_eq_const_safe!((-16 as $T).checked_next_multiple_of(8), Some(-16)); + assert_eq_const_safe!((-23 as $T).checked_next_multiple_of(8), Some(-16)); + assert_eq_const_safe!((-16 as $T).checked_next_multiple_of(-8), Some(-16)); + assert_eq_const_safe!((-23 as $T).checked_next_multiple_of(-8), Some(-24)); + assert_eq_const_safe!((1 as $T).checked_next_multiple_of(0), None); + assert_eq_const_safe!(MAX.checked_next_multiple_of(2), None); + assert_eq_const_safe!(MIN.checked_next_multiple_of(-3), None); + assert_eq_const_safe!(MIN.checked_next_multiple_of(-1), Some(MIN)); + } - #[test] - fn test_borrowing_sub() { - assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); - assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); - assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); - assert_eq!($T::MIN.borrowing_sub(-1, false), ($T::MIN + 1, false)); - assert_eq!($T::MIN.borrowing_sub(-1, true), ($T::MIN, false)); // no intermediate overflow - assert_eq!($T::MAX.borrowing_sub(-1, false), ($T::MIN, true)); - assert_eq!($T::MAX.borrowing_sub(-1, true), ($T::MAX, false)); // no intermediate overflow - assert_eq!((0 as $T).borrowing_sub($T::MIN, false), ($T::MIN, true)); - assert_eq!((0 as $T).borrowing_sub($T::MIN, true), ($T::MAX, false)); - } + fn test_carrying_add() { + assert_eq_const_safe!(MAX.carrying_add(1, false), (MIN, true)); + assert_eq_const_safe!(MAX.carrying_add(0, true), (MIN, true)); + assert_eq_const_safe!(MAX.carrying_add(1, true), (MIN + 1, true)); + assert_eq_const_safe!(MAX.carrying_add(-1, false), (MAX - 1, false)); + assert_eq_const_safe!(MAX.carrying_add(-1, true), (MAX, false)); // no intermediate overflow + assert_eq_const_safe!(MIN.carrying_add(-1, false), (MAX, true)); + assert_eq_const_safe!(MIN.carrying_add(-1, true), (MIN, false)); // no intermediate overflow + assert_eq_const_safe!((0 as $T).carrying_add(MAX, true), (MIN, true)); + assert_eq_const_safe!((0 as $T).carrying_add(MIN, true), (MIN + 1, false)); + } - #[test] - fn test_midpoint() { - assert_eq!(<$T>::midpoint(1, 3), 2); - assert_eq!(<$T>::midpoint(3, 1), 2); + fn test_borrowing_sub() { + assert_eq_const_safe!(MIN.borrowing_sub(1, false), (MAX, true)); + assert_eq_const_safe!(MIN.borrowing_sub(0, true), (MAX, true)); + assert_eq_const_safe!(MIN.borrowing_sub(1, true), (MAX - 1, true)); + assert_eq_const_safe!(MIN.borrowing_sub(-1, false), (MIN + 1, false)); + assert_eq_const_safe!(MIN.borrowing_sub(-1, true), (MIN, false)); // no intermediate overflow + assert_eq_const_safe!(MAX.borrowing_sub(-1, false), (MIN, true)); + assert_eq_const_safe!(MAX.borrowing_sub(-1, true), (MAX, false)); // no intermediate overflow + assert_eq_const_safe!((0 as $T).borrowing_sub(MIN, false), (MIN, true)); + assert_eq_const_safe!((0 as $T).borrowing_sub(MIN, true), (MAX, false)); + } - assert_eq!(<$T>::midpoint(0, 0), 0); - assert_eq!(<$T>::midpoint(0, 2), 1); - assert_eq!(<$T>::midpoint(2, 0), 1); - assert_eq!(<$T>::midpoint(2, 2), 2); + fn test_midpoint() { + assert_eq_const_safe!(<$T>::midpoint(1, 3), 2); + assert_eq_const_safe!(<$T>::midpoint(3, 1), 2); - assert_eq!(<$T>::midpoint(1, 4), 2); - assert_eq!(<$T>::midpoint(4, 1), 2); - assert_eq!(<$T>::midpoint(3, 4), 3); - assert_eq!(<$T>::midpoint(4, 3), 3); + assert_eq_const_safe!(<$T>::midpoint(0, 0), 0); + assert_eq_const_safe!(<$T>::midpoint(0, 2), 1); + assert_eq_const_safe!(<$T>::midpoint(2, 0), 1); + assert_eq_const_safe!(<$T>::midpoint(2, 2), 2); - assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), -1); - assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), -1); - assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); - assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); + assert_eq_const_safe!(<$T>::midpoint(1, 4), 2); + assert_eq_const_safe!(<$T>::midpoint(4, 1), 2); + assert_eq_const_safe!(<$T>::midpoint(3, 4), 3); + assert_eq_const_safe!(<$T>::midpoint(4, 3), 3); - assert_eq!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); - assert_eq!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); - assert_eq!(<$T>::midpoint(<$T>::MAX, 6), <$T>::MAX / 2 + 3); - assert_eq!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), 0); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), 0); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); + + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, 6), <$T>::MAX / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3); + } } }; } diff --git a/library/core/tests/num/midpoint.rs b/library/core/tests/num/midpoint.rs new file mode 100644 index 00000000000..71e98006784 --- /dev/null +++ b/library/core/tests/num/midpoint.rs @@ -0,0 +1,54 @@ +//! Test the following expectations: +//! - midpoint(a, b) == (a + b) / 2 +//! - midpoint(a, b) == midpoint(b, a) +//! - midpoint(-a, -b) == -midpoint(a, b) + +#[test] +#[cfg(not(miri))] +fn midpoint_obvious_impl_i8() { + for a in i8::MIN..=i8::MAX { + for b in i8::MIN..=i8::MAX { + assert_eq!(i8::midpoint(a, b), ((a as i16 + b as i16) / 2) as i8); + } + } +} + +#[test] +#[cfg(not(miri))] +fn midpoint_obvious_impl_u8() { + for a in u8::MIN..=u8::MAX { + for b in u8::MIN..=u8::MAX { + assert_eq!(u8::midpoint(a, b), ((a as u16 + b as u16) / 2) as u8); + } + } +} + +#[test] +#[cfg(not(miri))] +fn midpoint_order_expectation_i8() { + for a in i8::MIN..=i8::MAX { + for b in i8::MIN..=i8::MAX { + assert_eq!(i8::midpoint(a, b), i8::midpoint(b, a)); + } + } +} + +#[test] +#[cfg(not(miri))] +fn midpoint_order_expectation_u8() { + for a in u8::MIN..=u8::MAX { + for b in u8::MIN..=u8::MAX { + assert_eq!(u8::midpoint(a, b), u8::midpoint(b, a)); + } + } +} + +#[test] +#[cfg(not(miri))] +fn midpoint_negative_expectation() { + for a in 0..=i8::MAX { + for b in 0..=i8::MAX { + assert_eq!(i8::midpoint(-a, -b), -i8::midpoint(a, b)); + } + } +} diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index 6da9b9a1329..0add9a01e68 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -28,6 +28,7 @@ mod dec2flt; mod flt2dec; mod int_log; mod int_sqrt; +mod midpoint; mod ops; mod wrapping; diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index f4fa789461e..ad8e48491e8 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -2,7 +2,6 @@ macro_rules! uint_module { ($T:ident) => { use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use core::$T::*; - use std::str::FromStr; use crate::num; @@ -35,122 +34,115 @@ macro_rules! uint_module { const _0: $T = 0; const _1: $T = !0; - #[test] - fn test_count_ones() { - assert!(A.count_ones() == 3); - assert!(B.count_ones() == 2); - assert!(C.count_ones() == 5); + test_runtime_and_compiletime! { + fn test_count_ones() { + assert!(A.count_ones() == 3); + assert!(B.count_ones() == 2); + assert!(C.count_ones() == 5); + } + + fn test_count_zeros() { + assert!(A.count_zeros() == $T::BITS - 3); + assert!(B.count_zeros() == $T::BITS - 2); + assert!(C.count_zeros() == $T::BITS - 5); + } + + fn test_leading_trailing_ones() { + const A: $T = 0b0101_1111; + assert_eq_const_safe!(A.trailing_ones(), 5); + assert_eq_const_safe!((!A).leading_ones(), $T::BITS - 7); + + assert_eq_const_safe!(A.reverse_bits().leading_ones(), 5); + + assert_eq_const_safe!(_1.leading_ones(), $T::BITS); + assert_eq_const_safe!(_1.trailing_ones(), $T::BITS); + + assert_eq_const_safe!((_1 << 1).trailing_ones(), 0); + assert_eq_const_safe!((_1 >> 1).leading_ones(), 0); + + assert_eq_const_safe!((_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq_const_safe!((_1 >> 1).trailing_ones(), $T::BITS - 1); + + assert_eq_const_safe!(_0.leading_ones(), 0); + assert_eq_const_safe!(_0.trailing_ones(), 0); + + const X: $T = 0b0010_1100; + assert_eq_const_safe!(X.leading_ones(), 0); + assert_eq_const_safe!(X.trailing_ones(), 0); + } + + fn test_rotate() { + assert_eq_const_safe!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); + assert_eq_const_safe!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); + assert_eq_const_safe!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); + + // Rotating these should make no difference + // + // We test using 124 bits because to ensure that overlong bit shifts do + // not cause undefined behavior. See #10183. + assert_eq_const_safe!(_0.rotate_left(124), _0); + assert_eq_const_safe!(_1.rotate_left(124), _1); + assert_eq_const_safe!(_0.rotate_right(124), _0); + assert_eq_const_safe!(_1.rotate_right(124), _1); + + // Rotating by 0 should have no effect + assert_eq_const_safe!(A.rotate_left(0), A); + assert_eq_const_safe!(B.rotate_left(0), B); + assert_eq_const_safe!(C.rotate_left(0), C); + // Rotating by a multiple of word size should also have no effect + assert_eq_const_safe!(A.rotate_left(128), A); + assert_eq_const_safe!(B.rotate_left(128), B); + assert_eq_const_safe!(C.rotate_left(128), C); + } + + fn test_swap_bytes() { + assert_eq_const_safe!(A.swap_bytes().swap_bytes(), A); + assert_eq_const_safe!(B.swap_bytes().swap_bytes(), B); + assert_eq_const_safe!(C.swap_bytes().swap_bytes(), C); + + // Swapping these should make no difference + assert_eq_const_safe!(_0.swap_bytes(), _0); + assert_eq_const_safe!(_1.swap_bytes(), _1); + } + + fn test_reverse_bits() { + assert_eq_const_safe!(A.reverse_bits().reverse_bits(), A); + assert_eq_const_safe!(B.reverse_bits().reverse_bits(), B); + assert_eq_const_safe!(C.reverse_bits().reverse_bits(), C); + + // Swapping these should make no difference + assert_eq_const_safe!(_0.reverse_bits(), _0); + assert_eq_const_safe!(_1.reverse_bits(), _1); + } + + fn test_le() { + assert_eq_const_safe!($T::from_le(A.to_le()), A); + assert_eq_const_safe!($T::from_le(B.to_le()), B); + assert_eq_const_safe!($T::from_le(C.to_le()), C); + assert_eq_const_safe!($T::from_le(_0), _0); + assert_eq_const_safe!($T::from_le(_1), _1); + assert_eq_const_safe!(_0.to_le(), _0); + assert_eq_const_safe!(_1.to_le(), _1); + } + + fn test_be() { + assert_eq_const_safe!($T::from_be(A.to_be()), A); + assert_eq_const_safe!($T::from_be(B.to_be()), B); + assert_eq_const_safe!($T::from_be(C.to_be()), C); + assert_eq_const_safe!($T::from_be(_0), _0); + assert_eq_const_safe!($T::from_be(_1), _1); + assert_eq_const_safe!(_0.to_be(), _0); + assert_eq_const_safe!(_1.to_be(), _1); + } + + fn test_unsigned_checked_div() { + assert_eq_const_safe!((10 as $T).checked_div(2), Some(5)); + assert_eq_const_safe!((5 as $T).checked_div(0), None); + } } - #[test] - fn test_count_zeros() { - assert!(A.count_zeros() == $T::BITS - 3); - assert!(B.count_zeros() == $T::BITS - 2); - assert!(C.count_zeros() == $T::BITS - 5); - } - - #[test] - fn test_leading_trailing_ones() { - let a: $T = 0b0101_1111; - assert_eq!(a.trailing_ones(), 5); - assert_eq!((!a).leading_ones(), $T::BITS - 7); - - assert_eq!(a.reverse_bits().leading_ones(), 5); - - assert_eq!(_1.leading_ones(), $T::BITS); - assert_eq!(_1.trailing_ones(), $T::BITS); - - assert_eq!((_1 << 1).trailing_ones(), 0); - assert_eq!((_1 >> 1).leading_ones(), 0); - - assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1); - assert_eq!((_1 >> 1).trailing_ones(), $T::BITS - 1); - - assert_eq!(_0.leading_ones(), 0); - assert_eq!(_0.trailing_ones(), 0); - - let x: $T = 0b0010_1100; - assert_eq!(x.leading_ones(), 0); - assert_eq!(x.trailing_ones(), 0); - } - - #[test] - fn test_rotate() { - assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); - assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); - assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); - - // Rotating these should make no difference - // - // We test using 124 bits because to ensure that overlong bit shifts do - // not cause undefined behaviour. See #10183. - assert_eq!(_0.rotate_left(124), _0); - assert_eq!(_1.rotate_left(124), _1); - assert_eq!(_0.rotate_right(124), _0); - assert_eq!(_1.rotate_right(124), _1); - - // Rotating by 0 should have no effect - assert_eq!(A.rotate_left(0), A); - assert_eq!(B.rotate_left(0), B); - assert_eq!(C.rotate_left(0), C); - // Rotating by a multiple of word size should also have no effect - assert_eq!(A.rotate_left(128), A); - assert_eq!(B.rotate_left(128), B); - assert_eq!(C.rotate_left(128), C); - } - - #[test] - fn test_swap_bytes() { - assert_eq!(A.swap_bytes().swap_bytes(), A); - assert_eq!(B.swap_bytes().swap_bytes(), B); - assert_eq!(C.swap_bytes().swap_bytes(), C); - - // Swapping these should make no difference - assert_eq!(_0.swap_bytes(), _0); - assert_eq!(_1.swap_bytes(), _1); - } - - #[test] - fn test_reverse_bits() { - assert_eq!(A.reverse_bits().reverse_bits(), A); - assert_eq!(B.reverse_bits().reverse_bits(), B); - assert_eq!(C.reverse_bits().reverse_bits(), C); - - // Swapping these should make no difference - assert_eq!(_0.reverse_bits(), _0); - assert_eq!(_1.reverse_bits(), _1); - } - - #[test] - fn test_le() { - assert_eq!($T::from_le(A.to_le()), A); - assert_eq!($T::from_le(B.to_le()), B); - assert_eq!($T::from_le(C.to_le()), C); - assert_eq!($T::from_le(_0), _0); - assert_eq!($T::from_le(_1), _1); - assert_eq!(_0.to_le(), _0); - assert_eq!(_1.to_le(), _1); - } - - #[test] - fn test_be() { - assert_eq!($T::from_be(A.to_be()), A); - assert_eq!($T::from_be(B.to_be()), B); - assert_eq!($T::from_be(C.to_be()), C); - assert_eq!($T::from_be(_0), _0); - assert_eq!($T::from_be(_1), _1); - assert_eq!(_0.to_be(), _0); - assert_eq!(_1.to_be(), _1); - } - - #[test] - fn test_unsigned_checked_div() { - assert!((10 as $T).checked_div(2) == Some(5)); - assert!((5 as $T).checked_div(0) == None); - } - - fn from_str(t: &str) -> Option { - FromStr::from_str(t).ok() + fn from_str(t: &str) -> Option { + core::str::FromStr::from_str(t).ok() } #[test] @@ -166,52 +158,55 @@ macro_rules! uint_module { assert_eq!(from_str::<$T>("x"), None); } - #[test] - pub fn test_parse_bytes() { - assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T)); - assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T)); - assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T)); - assert_eq!(u16::from_str_radix("123", 16), Ok(291 as u16)); - assert_eq!(u16::from_str_radix("ffff", 16), Ok(65535 as u16)); - assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T)); + test_runtime_and_compiletime! { + fn test_parse_bytes() { + assert_eq_const_safe!($T::from_str_radix("123", 10), Ok(123 as $T)); + assert_eq_const_safe!($T::from_str_radix("1001", 2), Ok(9 as $T)); + assert_eq_const_safe!($T::from_str_radix("123", 8), Ok(83 as $T)); + assert_eq_const_safe!(u16::from_str_radix("123", 16), Ok(291 as u16)); + assert_eq_const_safe!(u16::from_str_radix("ffff", 16), Ok(65535 as u16)); + assert_eq_const_safe!($T::from_str_radix("z", 36), Ok(35 as $T)); - assert_eq!($T::from_str_radix("Z", 10).ok(), None::<$T>); - assert_eq!($T::from_str_radix("_", 2).ok(), None::<$T>); - } + assert!($T::from_str_radix("Z", 10).is_err()); + assert!($T::from_str_radix("_", 2).is_err()); + } - #[test] - fn test_pow() { - let mut r = 2 as $T; - assert_eq!(r.pow(2), 4 as $T); - assert_eq!(r.pow(0), 1 as $T); - assert_eq!(r.wrapping_pow(2), 4 as $T); - assert_eq!(r.wrapping_pow(0), 1 as $T); - assert_eq!(r.checked_pow(2), Some(4 as $T)); - assert_eq!(r.checked_pow(0), Some(1 as $T)); - assert_eq!(r.overflowing_pow(2), (4 as $T, false)); - assert_eq!(r.overflowing_pow(0), (1 as $T, false)); - assert_eq!(r.saturating_pow(2), 4 as $T); - assert_eq!(r.saturating_pow(0), 1 as $T); + fn test_pow() { + { + const R: $T = 2; + assert_eq_const_safe!(R.pow(2), 4 as $T); + assert_eq_const_safe!(R.pow(0), 1 as $T); + assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); + assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); + assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); + assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); + assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); + assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); + assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); + } - r = MAX; - // use `^` to represent .pow() with no overflow. - // if itest::MAX == 2^j-1, then itest is a `j` bit int, - // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`, - // thussaturating_pow the overflowing result is exactly 1. - assert_eq!(r.wrapping_pow(2), 1 as $T); - assert_eq!(r.checked_pow(2), None); - assert_eq!(r.overflowing_pow(2), (1 as $T, true)); - assert_eq!(r.saturating_pow(2), MAX); - } + { + const R: $T = $T::MAX; + // use `^` to represent .pow() with no overflow. + // if itest::MAX == 2^j-1, then itest is a `j` bit int, + // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`, + // thussaturating_pow the overflowing result is exactly 1. + assert_eq_const_safe!(R.wrapping_pow(2), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), None); + assert_eq_const_safe!(R.overflowing_pow(2), (1 as $T, true)); + assert_eq_const_safe!(R.saturating_pow(2), MAX); + } + } - #[test] - fn test_isqrt() { - assert_eq!((0 as $T).isqrt(), 0 as $T); - assert_eq!((1 as $T).isqrt(), 1 as $T); - assert_eq!((2 as $T).isqrt(), 1 as $T); - assert_eq!((99 as $T).isqrt(), 9 as $T); - assert_eq!((100 as $T).isqrt(), 10 as $T); - assert_eq!($T::MAX.isqrt(), (1 << ($T::BITS / 2)) - 1); + fn test_isqrt() { + assert_eq_const_safe!((0 as $T).isqrt(), 0 as $T); + assert_eq_const_safe!((1 as $T).isqrt(), 1 as $T); + assert_eq_const_safe!((2 as $T).isqrt(), 1 as $T); + assert_eq_const_safe!((99 as $T).isqrt(), 9 as $T); + assert_eq_const_safe!((100 as $T).isqrt(), 10 as $T); + assert_eq_const_safe!($T::MAX.isqrt(), (1 << ($T::BITS / 2)) - 1); + } } #[cfg(not(miri))] // Miri is too slow @@ -233,85 +228,79 @@ macro_rules! uint_module { } } - #[test] - fn test_div_floor() { - assert_eq!((8 as $T).div_floor(3), 2); - } + test_runtime_and_compiletime! { + fn test_div_floor() { + assert_eq_const_safe!((8 as $T).div_floor(3), 2); + } - #[test] - fn test_div_ceil() { - assert_eq!((8 as $T).div_ceil(3), 3); - } + fn test_div_ceil() { + assert_eq_const_safe!((8 as $T).div_ceil(3), 3); + } - #[test] - fn test_next_multiple_of() { - assert_eq!((16 as $T).next_multiple_of(8), 16); - assert_eq!((23 as $T).next_multiple_of(8), 24); - assert_eq!(MAX.next_multiple_of(1), MAX); - } + fn test_next_multiple_of() { + assert_eq_const_safe!((16 as $T).next_multiple_of(8), 16); + assert_eq_const_safe!((23 as $T).next_multiple_of(8), 24); + assert_eq_const_safe!(MAX.next_multiple_of(1), MAX); + } - #[test] - fn test_checked_next_multiple_of() { - assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16)); - assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24)); - assert_eq!((1 as $T).checked_next_multiple_of(0), None); - assert_eq!(MAX.checked_next_multiple_of(2), None); - } + fn test_checked_next_multiple_of() { + assert_eq_const_safe!((16 as $T).checked_next_multiple_of(8), Some(16)); + assert_eq_const_safe!((23 as $T).checked_next_multiple_of(8), Some(24)); + assert_eq_const_safe!((1 as $T).checked_next_multiple_of(0), None); + assert_eq_const_safe!(MAX.checked_next_multiple_of(2), None); + } - #[test] - fn test_is_next_multiple_of() { - assert!((12 as $T).is_multiple_of(4)); - assert!(!(12 as $T).is_multiple_of(5)); - assert!((0 as $T).is_multiple_of(0)); - assert!(!(12 as $T).is_multiple_of(0)); - } + fn test_is_next_multiple_of() { + assert!((12 as $T).is_multiple_of(4)); + assert!(!(12 as $T).is_multiple_of(5)); + assert!((0 as $T).is_multiple_of(0)); + assert!(!(12 as $T).is_multiple_of(0)); + } - #[test] - fn test_carrying_add() { - assert_eq!($T::MAX.carrying_add(1, false), (0, true)); - assert_eq!($T::MAX.carrying_add(0, true), (0, true)); - assert_eq!($T::MAX.carrying_add(1, true), (1, true)); + fn test_carrying_add() { + assert_eq_const_safe!($T::MAX.carrying_add(1, false), (0, true)); + assert_eq_const_safe!($T::MAX.carrying_add(0, true), (0, true)); + assert_eq_const_safe!($T::MAX.carrying_add(1, true), (1, true)); - assert_eq!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false)); - assert_eq!($T::MIN.carrying_add(0, true), (1, false)); - assert_eq!($T::MIN.carrying_add($T::MAX, true), (0, true)); - } + assert_eq_const_safe!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false)); + assert_eq_const_safe!($T::MIN.carrying_add(0, true), (1, false)); + assert_eq_const_safe!($T::MIN.carrying_add($T::MAX, true), (0, true)); + } - #[test] - fn test_borrowing_sub() { - assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); - assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); - assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); + fn test_borrowing_sub() { + assert_eq_const_safe!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); + assert_eq_const_safe!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); + assert_eq_const_safe!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); - assert_eq!($T::MAX.borrowing_sub($T::MAX, false), (0, false)); - assert_eq!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false)); - assert_eq!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true)); - } + assert_eq_const_safe!($T::MAX.borrowing_sub($T::MAX, false), (0, false)); + assert_eq_const_safe!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false)); + assert_eq_const_safe!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true)); + } - #[test] - fn test_midpoint() { - assert_eq!(<$T>::midpoint(1, 3), 2); - assert_eq!(<$T>::midpoint(3, 1), 2); + fn test_midpoint() { + assert_eq_const_safe!(<$T>::midpoint(1, 3), 2); + assert_eq_const_safe!(<$T>::midpoint(3, 1), 2); - assert_eq!(<$T>::midpoint(0, 0), 0); - assert_eq!(<$T>::midpoint(0, 2), 1); - assert_eq!(<$T>::midpoint(2, 0), 1); - assert_eq!(<$T>::midpoint(2, 2), 2); + assert_eq_const_safe!(<$T>::midpoint(0, 0), 0); + assert_eq_const_safe!(<$T>::midpoint(0, 2), 1); + assert_eq_const_safe!(<$T>::midpoint(2, 0), 1); + assert_eq_const_safe!(<$T>::midpoint(2, 2), 2); - assert_eq!(<$T>::midpoint(1, 4), 2); - assert_eq!(<$T>::midpoint(4, 1), 2); - assert_eq!(<$T>::midpoint(3, 4), 3); - assert_eq!(<$T>::midpoint(4, 3), 3); + assert_eq_const_safe!(<$T>::midpoint(1, 4), 2); + assert_eq_const_safe!(<$T>::midpoint(4, 1), 2); + assert_eq_const_safe!(<$T>::midpoint(3, 4), 3); + assert_eq_const_safe!(<$T>::midpoint(4, 3), 3); - assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2); - assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), (<$T>::MAX - <$T>::MIN) / 2); - assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); - assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), (<$T>::MAX - <$T>::MIN) / 2); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); - assert_eq!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); - assert_eq!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); - assert_eq!(<$T>::midpoint(<$T>::MAX, 6), (<$T>::MAX - <$T>::MIN) / 2 + 3); - assert_eq!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, 6), (<$T>::MAX - <$T>::MIN) / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3); + } } }; } diff --git a/library/proc_macro/src/bridge/symbol.rs b/library/proc_macro/src/bridge/symbol.rs index 37aaee6b215..edad6e7ac39 100644 --- a/library/proc_macro/src/bridge/symbol.rs +++ b/library/proc_macro/src/bridge/symbol.rs @@ -76,7 +76,7 @@ impl Symbol { .all(|b| matches!(b, b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9')) } - // Mimics the behaviour of `Symbol::can_be_raw` from `rustc_span` + // Mimics the behavior of `Symbol::can_be_raw` from `rustc_span` fn can_be_raw(string: &str) -> bool { match string { "_" | "super" | "self" | "Self" | "crate" => false, diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index fa8ea95b891..b79ad1c3119 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -1098,7 +1098,7 @@ mod test_extract_if { _ => panic!(), }); catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err(); - // Iterator behaviour after a panic is explicitly unspecified, + // Iterator behavior after a panic is explicitly unspecified, // so this is just the current implementation: let result = catch_unwind(AssertUnwindSafe(|| it.next())); assert!(result.is_err()); diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 97a1b846a91..d732a15117e 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -618,7 +618,7 @@ impl Error for JoinPathsError { /// /// # Deprecation /// -/// This function is deprecated because the behaviour on Windows is not correct. +/// This function is deprecated because the behavior on Windows is not correct. /// The 'HOME' environment variable is not standard on Windows, and may not produce /// desired results; for instance, under Cygwin or Mingw it will return `/home/you` /// when it should return `C:\Users\you`. diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 85023540a81..b952c85addf 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -453,6 +453,29 @@ impl Read for VecDeque { Ok(n) } + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + let (front, back) = self.as_slices(); + + // Use only the front buffer if it is big enough to fill `buf`, else use + // the back buffer too. + match buf.split_at_mut_checked(front.len()) { + None => buf.copy_from_slice(&front[..buf.len()]), + Some((buf_front, buf_back)) => match back.split_at_checked(buf_back.len()) { + Some((back, _)) => { + buf_front.copy_from_slice(front); + buf_back.copy_from_slice(back); + } + None => { + self.clear(); + return Err(io::Error::READ_EXACT_EOF); + } + }, + } + + self.drain(..buf.len()); + Ok(()) + } + #[inline] fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { let (ref mut front, _) = self.as_slices(); @@ -462,6 +485,29 @@ impl Read for VecDeque { Ok(()) } + fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { + let len = cursor.capacity(); + let (front, back) = self.as_slices(); + + match front.split_at_checked(cursor.capacity()) { + Some((front, _)) => cursor.append(front), + None => { + cursor.append(front); + match back.split_at_checked(cursor.capacity()) { + Some((back, _)) => cursor.append(back), + None => { + cursor.append(back); + self.clear(); + return Err(io::Error::READ_EXACT_EOF); + } + } + } + } + + self.drain(..len); + Ok(()) + } + #[inline] fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { // The total len is known upfront so we can reserve it in a single call. diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 8c1a3c76829..1de52eb7b21 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -364,6 +364,7 @@ #![feature(std_internals)] #![feature(str_internals)] #![feature(strict_provenance_atomic_ptr)] +#![feature(sync_unsafe_cell)] #![feature(ub_checks)] // tidy-alphabetical-end // diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index a964db2e0ac..ba6481f052c 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -153,7 +153,7 @@ pub trait FileExt { /// /// It is possible to inadvertently set this flag, like in the example below. /// Therefore, it is important to be vigilant while changing options to mitigate - /// unexpected behaviour. + /// unexpected behavior. /// /// ```no_run /// use std::fs::File; diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 63edfdb82f3..62125f885b2 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1167,7 +1167,7 @@ impl FusedIterator for Ancestors<'_> {} /// path.push(r"..\otherdir"); /// path.push("system32"); /// -/// The behaviour of `PathBuf` may be changed to a panic on such inputs +/// The behavior of `PathBuf` may be changed to a panic on such inputs /// in the future. [`Extend::extend`] should be used to add multi-part paths. #[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")] #[stable(feature = "rust1", since = "1.0.0")] @@ -1409,7 +1409,7 @@ impl PathBuf { /// (That is, it will have the same parent.) /// /// The argument is not sanitized, so can include separators. This - /// behaviour may be changed to a panic in the future. + /// behavior may be changed to a panic in the future. /// /// [`self.file_name`]: Path::file_name /// [`pop`]: PathBuf::pop diff --git a/library/std/src/process.rs b/library/std/src/process.rs index f24fe353e55..6933528cdbd 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -119,7 +119,7 @@ //! when given a `.bat` file as the application to run, it will automatically //! convert that into running `cmd.exe /c` with the batch file as the next argument. //! -//! For historical reasons Rust currently preserves this behaviour when using +//! For historical reasons Rust currently preserves this behavior when using //! [`Command::new`], and escapes the arguments according to `cmd.exe` rules. //! Due to the complexity of `cmd.exe` argument handling, it might not be //! possible to safely escape some special characters, and using them will result @@ -2318,7 +2318,7 @@ pub fn exit(code: i32) -> ! { /// Rust IO buffers (eg, from `BufWriter`) will not be flushed. /// Likewise, C stdio buffers will (on most platforms) not be flushed. /// -/// This is in contrast to the default behaviour of [`panic!`] which unwinds +/// This is in contrast to the default behavior of [`panic!`] which unwinds /// the current thread's stack and calls all destructors. /// When `panic="abort"` is set, either as an argument to `rustc` or in a /// crate's Cargo.toml, [`panic!`] and `abort` are similar. However, diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index 88cc95caf40..fb0b495961c 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -96,9 +96,23 @@ fn stdout_works() { #[test] #[cfg_attr(any(windows, target_os = "vxworks"), ignore)] fn set_current_dir_works() { + // On many Unix platforms this will use the posix_spawn path. let mut cmd = shell_cmd(); cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped()); assert_eq!(run_output(cmd), "/\n"); + + // Also test the fork/exec path by setting a pre_exec function. + #[cfg(unix)] + { + use crate::os::unix::process::CommandExt; + + let mut cmd = shell_cmd(); + cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped()); + unsafe { + cmd.pre_exec(|| Ok(())); + } + assert_eq!(run_output(cmd), "/\n"); + } } #[test] diff --git a/library/std/src/random.rs b/library/std/src/random.rs index cdb88c795bf..45f51dd37b0 100644 --- a/library/std/src/random.rs +++ b/library/std/src/random.rs @@ -38,7 +38,7 @@ use crate::sys::random as sys; /// Vita | `arc4random_buf` /// Hermit | `read_entropy` /// Horizon | `getrandom` shim -/// Hurd, L4Re, QNX | `/dev/urandom` +/// AIX, Hurd, L4Re, QNX | `/dev/urandom` /// Redox | `/scheme/rand` /// RTEMS | [`arc4random_buf`](https://docs.rtems.org/branches/master/bsp-howto/getentropy.html) /// SGX | [`rdrand`](https://en.wikipedia.org/wiki/RDRAND) diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 80e7c3c026b..b2492238bd3 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -110,7 +110,7 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // handle does not match the current ID, we should attempt to use the // current thread ID here instead of unconditionally creating a new // one. Also see #130210. - let thread = Thread::new_main(thread::current_id()); + let thread = unsafe { Thread::new_main(thread::current_id()) }; if let Err(_thread) = thread::set_current(thread) { // `thread::current` will create a new handle if none has been set yet. // Thus, if someone uses it before main, this call will fail. That's a diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs index 34acd9c9a94..2c8ba411f30 100644 --- a/library/std/src/sync/mpmc/array.rs +++ b/library/std/src/sync/mpmc/array.rs @@ -484,7 +484,7 @@ impl Channel { /// /// # Panicking /// If a destructor panics, the remaining messages are leaked, matching the - /// behaviour of the unbounded channel. + /// behavior of the unbounded channel. /// /// # Safety /// This method must only be called when dropping the last receiver. The diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index 993df9314fc..27db4b634fb 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -288,7 +288,7 @@ impl Once { /// /// If this [`Once`] has been poisoned because an initialization closure has /// panicked, this method will also panic. Use [`wait_force`](Self::wait_force) - /// if this behaviour is not desired. + /// if this behavior is not desired. #[unstable(feature = "once_wait", issue = "127527")] pub fn wait(&self) { if !self.inner.is_completed() { diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index be615a5a8ef..0ae3cf4df36 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -634,6 +634,26 @@ impl From for OnceLock { #[stable(feature = "once_cell", since = "1.70.0")] impl PartialEq for OnceLock { + /// Equality for two `OnceLock`s. + /// + /// Two `OnceLock`s are equal if they either both contain values and their + /// values are equal, or if neither contains a value. + /// + /// # Examples + /// + /// ``` + /// use std::sync::OnceLock; + /// + /// let five = OnceLock::new(); + /// five.set(5).unwrap(); + /// + /// let also_five = OnceLock::new(); + /// also_five.set(5).unwrap(); + /// + /// assert!(five == also_five); + /// + /// assert!(OnceLock::::new() == OnceLock::::new()); + /// ``` #[inline] fn eq(&self, other: &OnceLock) -> bool { self.get() == other.get() diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs index 5d0110cf55d..8f7d786e32f 100644 --- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/pal/unix/process/process_fuchsia.rs @@ -273,7 +273,7 @@ impl ExitStatus { // We don't know what someone who calls into_raw() will do with this value, but it should // have the conventional Unix representation. Despite the fact that this is not // standardised in SuS or POSIX, all Unix systems encode the signal and exit status the - // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every + // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behavior on every // Unix.) // // The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index 4551d49e841..8faf1fda546 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -448,7 +448,6 @@ impl Command { use core::sync::atomic::{AtomicU8, Ordering}; use crate::mem::MaybeUninit; - use crate::sys::weak::weak; use crate::sys::{self, cvt_nz, on_broken_pipe_flag_used}; if self.get_gid().is_some() @@ -462,6 +461,8 @@ impl Command { cfg_if::cfg_if! { if #[cfg(target_os = "linux")] { + use crate::sys::weak::weak; + weak! { fn pidfd_spawnp( *mut libc::c_int, @@ -575,16 +576,44 @@ impl Command { } } - // Solaris, glibc 2.29+, and musl 1.24+ can set a new working directory, - // and maybe others will gain this non-POSIX function too. We'll check - // for this weak symbol as soon as it's needed, so we can return early - // otherwise to do a manual chdir before exec. - weak! { - fn posix_spawn_file_actions_addchdir_np( - *mut libc::posix_spawn_file_actions_t, - *const libc::c_char - ) -> libc::c_int + type PosixSpawnAddChdirFn = unsafe extern "C" fn( + *mut libc::posix_spawn_file_actions_t, + *const libc::c_char, + ) -> libc::c_int; + + /// Get the function pointer for adding a chdir action to a + /// `posix_spawn_file_actions_t`, if available, assuming a dynamic libc. + /// + /// Some platforms can set a new working directory for a spawned process in the + /// `posix_spawn` path. This function looks up the function pointer for adding + /// such an action to a `posix_spawn_file_actions_t` struct. + #[cfg(not(all(target_os = "linux", target_env = "musl")))] + fn get_posix_spawn_addchdir() -> Option { + use crate::sys::weak::weak; + + weak! { + fn posix_spawn_file_actions_addchdir_np( + *mut libc::posix_spawn_file_actions_t, + *const libc::c_char + ) -> libc::c_int + } + + posix_spawn_file_actions_addchdir_np.get() } + + /// Get the function pointer for adding a chdir action to a + /// `posix_spawn_file_actions_t`, if available, on platforms where the function + /// is known to exist. + /// + /// Weak symbol lookup doesn't work with statically linked libcs, so in cases + /// where static linking is possible we need to either check for the presence + /// of the symbol at compile time or know about it upfront. + #[cfg(all(target_os = "linux", target_env = "musl"))] + fn get_posix_spawn_addchdir() -> Option { + // Our minimum required musl supports this function, so we can just use it. + Some(libc::posix_spawn_file_actions_addchdir_np) + } + let addchdir = match self.get_cwd() { Some(cwd) => { if cfg!(target_vendor = "apple") { @@ -597,7 +626,10 @@ impl Command { return Ok(None); } } - match posix_spawn_file_actions_addchdir_np.get() { + // Check for the availability of the posix_spawn addchdir + // function now. If it isn't available, bail and use the + // fork/exec path. + match get_posix_spawn_addchdir() { Some(f) => Some((f, cwd)), None => return Ok(None), } diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index b237fa481e2..5a9bfccc1fa 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1159,7 +1159,7 @@ pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()> // Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10 // Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the // computer is in Developer Mode, but SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE must be - // added to dwFlags to opt into this behaviour. + // added to dwFlags to opt into this behavior. let result = cvt(unsafe { c::CreateSymbolicLinkW( link.as_ptr(), diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index 95b51e704f9..17bb03fe7af 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -47,7 +47,7 @@ impl EnvKey { } } -// Comparing Windows environment variable keys[1] are behaviourally the +// Comparing Windows environment variable keys[1] are behaviorally the // composition of two operations[2]: // // 1. Case-fold both strings. This is done using a language-independent @@ -338,8 +338,8 @@ impl Command { // If at least one of stdin, stdout or stderr are set (i.e. are non null) // then set the `hStd` fields in `STARTUPINFO`. - // Otherwise skip this and allow the OS to apply its default behaviour. - // This provides more consistent behaviour between Win7 and Win8+. + // Otherwise skip this and allow the OS to apply its default behavior. + // This provides more consistent behavior between Win7 and Win8+. let is_set = |stdio: &Handle| !stdio.as_raw_handle().is_null(); if is_set(&stderr) || is_set(&stdout) || is_set(&stdin) { si.dwFlags |= c::STARTF_USESTDHANDLES; @@ -507,7 +507,7 @@ where Exists: FnMut(PathBuf) -> Option>, { // 1. Child paths - // This is for consistency with Rust's historic behaviour. + // This is for consistency with Rust's historic behavior. if let Some(paths) = child_paths { for path in env::split_paths(paths).filter(|p| !p.as_os_str().is_empty()) { if let Some(path) = exists(path) { diff --git a/library/std/src/sys/pal/windows/process/tests.rs b/library/std/src/sys/pal/windows/process/tests.rs index b567151b721..1bcc5fa6b20 100644 --- a/library/std/src/sys/pal/windows/process/tests.rs +++ b/library/std/src/sys/pal/windows/process/tests.rs @@ -191,7 +191,7 @@ fn windows_exe_resolver() { /* Some of the following tests may need to be changed if you are deliberately - changing the behaviour of `resolve_exe`. + changing the behavior of `resolve_exe`. */ let empty_paths = || None; diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs index 28bce529cd9..2c8ce42f414 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/pal/windows/thread.rs @@ -99,7 +99,7 @@ impl Thread { } // Attempt to use high-precision sleep (Windows 10, version 1803+). // On error fallback to the standard `Sleep` function. - // Also preserves the zero duration behaviour of `Sleep`. + // Also preserves the zero duration behavior of `Sleep`. if dur.is_zero() || high_precision_sleep(dur).is_err() { unsafe { c::Sleep(super::dur2timeout(dur)) } } diff --git a/library/std/src/sys/path/windows/tests.rs b/library/std/src/sys/path/windows/tests.rs index 623c6236166..f2a60e30bc6 100644 --- a/library/std/src/sys/path/windows/tests.rs +++ b/library/std/src/sys/path/windows/tests.rs @@ -119,7 +119,7 @@ fn test_windows_prefix_components() { /// See #101358. /// -/// Note that the exact behaviour here may change in the future. +/// Note that the exact behavior here may change in the future. /// In which case this test will need to adjusted. #[test] fn broken_unc_path() { diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs index 073fdc45e61..e3cb79285cd 100644 --- a/library/std/src/sys/random/linux.rs +++ b/library/std/src/sys/random/linux.rs @@ -30,7 +30,7 @@ //! data the system has available at the time. //! //! So in conclusion, we always want the output of the non-blocking pool, but -//! may need to wait until it is initalized. The default behaviour of `getrandom` +//! may need to wait until it is initalized. The default behavior of `getrandom` //! is to wait until the non-blocking pool is initialized and then draw from there, //! so if `getrandom` is available, we use its default to generate the bytes. For //! `HashMap`, however, we need to specify the `GRND_INSECURE` flags, but that @@ -39,7 +39,7 @@ //! succeed if the pool is initialized. If it isn't, we fall back to the file //! access method. //! -//! The behaviour of `/dev/urandom` is inverse to that of `getrandom`: it always +//! The behavior of `/dev/urandom` is inverse to that of `getrandom`: it always //! yields data, even when the pool is not initialized. For generating `HashMap` //! keys, this is not important, so we can use it directly. For secure data //! however, we need to wait until initialization, which we can do by `poll`ing diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index edc2cacdfd8..f42351deb92 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -40,6 +40,7 @@ cfg_if::cfg_if! { mod horizon; pub use horizon::fill_bytes; } else if #[cfg(any( + target_os = "aix", target_os = "hurd", target_os = "l4re", target_os = "nto", diff --git a/library/std/src/sys/sync/condvar/no_threads.rs b/library/std/src/sys/sync/condvar/no_threads.rs index 36b89c5f5be..2a67ed766aa 100644 --- a/library/std/src/sys/sync/condvar/no_threads.rs +++ b/library/std/src/sys/sync/condvar/no_threads.rs @@ -5,7 +5,7 @@ pub struct Condvar {} impl Condvar { #[inline] - #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))] pub const fn new() -> Condvar { Condvar {} } diff --git a/library/std/src/sys/sync/condvar/pthread.rs b/library/std/src/sys/sync/condvar/pthread.rs index 986cd0cb7d1..cee728e35cd 100644 --- a/library/std/src/sys/sync/condvar/pthread.rs +++ b/library/std/src/sys/sync/condvar/pthread.rs @@ -66,7 +66,7 @@ impl Drop for AllocatedCondvar { // On DragonFly pthread_cond_destroy() returns EINVAL if called on // a condvar that was just initialized with // libc::PTHREAD_COND_INITIALIZER. Once it is used or - // pthread_cond_init() is called, this behaviour no longer occurs. + // pthread_cond_init() is called, this behavior no longer occurs. debug_assert!(r == 0 || r == libc::EINVAL); } else { debug_assert_eq!(r, 0); diff --git a/library/std/src/sys/sync/mutex/no_threads.rs b/library/std/src/sys/sync/mutex/no_threads.rs index 4a13c55fb8b..7b243575e01 100644 --- a/library/std/src/sys/sync/mutex/no_threads.rs +++ b/library/std/src/sys/sync/mutex/no_threads.rs @@ -10,7 +10,7 @@ unsafe impl Sync for Mutex {} // no threads on this platform impl Mutex { #[inline] - #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))] pub const fn new() -> Mutex { Mutex { locked: Cell::new(false) } } diff --git a/library/std/src/sys/sync/mutex/pthread.rs b/library/std/src/sys/sync/mutex/pthread.rs index 87c95f45f96..abd58122523 100644 --- a/library/std/src/sys/sync/mutex/pthread.rs +++ b/library/std/src/sys/sync/mutex/pthread.rs @@ -65,7 +65,7 @@ impl Drop for AllocatedMutex { // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER. // Once it is used (locked/unlocked) or pthread_mutex_init() is called, - // this behaviour no longer occurs. + // this behavior no longer occurs. debug_assert!(r == 0 || r == libc::EINVAL); } else { debug_assert_eq!(r, 0); @@ -88,7 +88,7 @@ impl Mutex { /// since the `lock` and the lock must have occurred on the current thread. /// /// # Safety - /// Causes undefined behaviour if the mutex is not locked. + /// Causes undefined behavior if the mutex is not locked. #[inline] pub(crate) unsafe fn get_assert_locked(&self) -> *mut libc::pthread_mutex_t { unsafe { self.inner.get_unchecked().0.get() } diff --git a/library/std/src/sys/sync/once/no_threads.rs b/library/std/src/sys/sync/once/no_threads.rs index cdcffe790f5..fb1b496510a 100644 --- a/library/std/src/sys/sync/once/no_threads.rs +++ b/library/std/src/sys/sync/once/no_threads.rs @@ -35,7 +35,7 @@ unsafe impl Sync for Once {} impl Once { #[inline] - #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_once_new", since = "1.32.0"))] pub const fn new() -> Once { Once { state: Cell::new(State::Incomplete) } } diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs index 3e83a4a088f..177d0d7744a 100644 --- a/library/std/src/sys/sync/once/queue.rs +++ b/library/std/src/sys/sync/once/queue.rs @@ -116,7 +116,7 @@ fn to_state(current: StateAndQueue) -> usize { impl Once { #[inline] - #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_once_new", since = "1.32.0"))] pub const fn new() -> Once { Once { state_and_queue: AtomicPtr::new(ptr::without_provenance_mut(INCOMPLETE)) } } diff --git a/library/std/src/sys/sync/once_box.rs b/library/std/src/sys/sync/once_box.rs index 9d24db2245a..4105af50329 100644 --- a/library/std/src/sys/sync/once_box.rs +++ b/library/std/src/sys/sync/once_box.rs @@ -36,7 +36,7 @@ impl OnceBox { /// ``` /// /// # Safety - /// This causes undefined behaviour if the assumption above is violated. + /// This causes undefined behavior if the assumption above is violated. #[inline] pub unsafe fn get_unchecked(&self) -> &T { unsafe { &*self.ptr.load(Relaxed) } diff --git a/library/std/src/sys/sync/rwlock/futex.rs b/library/std/src/sys/sync/rwlock/futex.rs index df22c36dd5a..447048edf76 100644 --- a/library/std/src/sys/sync/rwlock/futex.rs +++ b/library/std/src/sys/sync/rwlock/futex.rs @@ -283,7 +283,7 @@ impl RwLock { futex_wake(&self.writer_notify) // Note that FreeBSD and DragonFlyBSD don't tell us whether they woke // up any threads or not, and always return `false` here. That still - // results in correct behaviour: it just means readers get woken up as + // results in correct behavior: it just means readers get woken up as // well in case both readers and writers were waiting. } diff --git a/library/std/src/sys/sync/rwlock/no_threads.rs b/library/std/src/sys/sync/rwlock/no_threads.rs index 789ef9b29e5..6965e2e2cab 100644 --- a/library/std/src/sys/sync/rwlock/no_threads.rs +++ b/library/std/src/sys/sync/rwlock/no_threads.rs @@ -10,7 +10,7 @@ unsafe impl Sync for RwLock {} // no threads on this platform impl RwLock { #[inline] - #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))] pub const fn new() -> RwLock { RwLock { mode: Cell::new(0) } } diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs index 733f51cae8c..889961915f4 100644 --- a/library/std/src/sys/sync/rwlock/queue.rs +++ b/library/std/src/sys/sync/rwlock/queue.rs @@ -8,7 +8,7 @@ //! * `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 +//! that can easily lead to undefined behavior in safe Rust code when not properly //! guarded against. //! * On some platforms (e.g. macOS), the lock is very slow. //! diff --git a/library/std/src/sys/sync/thread_parking/darwin.rs b/library/std/src/sys/sync/thread_parking/darwin.rs index 96e3d23c332..0553c5e19a9 100644 --- a/library/std/src/sys/sync/thread_parking/darwin.rs +++ b/library/std/src/sys/sync/thread_parking/darwin.rs @@ -5,7 +5,7 @@ //! rejection from the App Store). //! //! Therefore, we need to look for other synchronization primitives. Luckily, Darwin -//! supports semaphores, which allow us to implement the behaviour we need with +//! supports semaphores, which allow us to implement the behavior we need with //! only one primitive (as opposed to a mutex-condvar pair). We use the semaphore //! provided by libdispatch, as the underlying Mach semaphore is only dubiously //! public. diff --git a/library/std/src/sys/sync/thread_parking/pthread.rs b/library/std/src/sys/sync/thread_parking/pthread.rs index 5f195d0bb0c..76df73b2a8e 100644 --- a/library/std/src/sys/sync/thread_parking/pthread.rs +++ b/library/std/src/sys/sync/thread_parking/pthread.rs @@ -97,7 +97,7 @@ impl Parker { /// The constructed parker must never be moved. pub unsafe fn new_in_place(parker: *mut Parker) { // Use the default mutex implementation to allow for simpler initialization. - // This could lead to undefined behaviour when deadlocking. This is avoided + // This could lead to undefined behavior when deadlocking. This is avoided // by not deadlocking. Note in particular the unlocking operation before any // panic, as code after the panic could try to park again. (&raw mut (*parker).state).write(AtomicUsize::new(EMPTY)); diff --git a/library/std/src/sys/sync/thread_parking/windows7.rs b/library/std/src/sys/sync/thread_parking/windows7.rs index 8f7e66c46ef..f7585e882f0 100644 --- a/library/std/src/sys/sync/thread_parking/windows7.rs +++ b/library/std/src/sys/sync/thread_parking/windows7.rs @@ -35,7 +35,7 @@ // different implementations. // // Unfortunately, NT Keyed Events are an undocumented Windows API. However: -// - This API is relatively simple with obvious behaviour, and there are +// - This API is relatively simple with obvious behavior, and there are // several (unofficial) articles documenting the details. [1] // - `parking_lot` has been using this API for years (on Windows versions // before Windows 8). [2] Many big projects extensively use parking_lot, @@ -43,7 +43,7 @@ // - It is the underlying API used by Windows SRW locks and Windows critical // sections. [3] [4] // - The source code of the implementations of Wine, ReactOs, and Windows XP -// are available and match the expected behaviour. +// are available and match the expected behavior. // - The main risk with an undocumented API is that it might change in the // future. But since we only use it for older versions of Windows, that's not // a problem. diff --git a/library/std/src/sys/thread_local/key/racy.rs b/library/std/src/sys/thread_local/key/racy.rs index 69f11458c32..97df8997b80 100644 --- a/library/std/src/sys/thread_local/key/racy.rs +++ b/library/std/src/sys/thread_local/key/racy.rs @@ -30,7 +30,7 @@ const KEY_SENTVAL: usize = 0; const KEY_SENTVAL: usize = libc::PTHREAD_KEYS_MAX + 1; impl LazyKey { - #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))] pub const fn new(dtor: Option) -> LazyKey { LazyKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor } } diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index f5a2aaa6c6a..58f291ffdb9 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -60,7 +60,7 @@ struct Value { } impl Storage { - #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))] pub const fn new() -> Storage { Storage { key: LazyKey::new(Some(destroy_value::)), marker: PhantomData } } diff --git a/library/std/src/sys/thread_local/statik.rs b/library/std/src/sys/thread_local/statik.rs index ba94caa6690..4da01a84acf 100644 --- a/library/std/src/sys/thread_local/statik.rs +++ b/library/std/src/sys/thread_local/statik.rs @@ -14,12 +14,11 @@ pub macro thread_local_inner { (@key $t:ty, const $init:expr) => {{ const __INIT: $t = $init; + // NOTE: Please update the shadowing test in `tests/thread.rs` if these types are renamed. unsafe { - use $crate::thread::LocalKey; - use $crate::thread::local_impl::EagerStorage; - - LocalKey::new(|_| { - static VAL: EagerStorage<$t> = EagerStorage { value: __INIT }; + $crate::thread::LocalKey::new(|_| { + static VAL: $crate::thread::local_impl::EagerStorage<$t> = + $crate::thread::local_impl::EagerStorage { value: __INIT }; &VAL.value }) } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 88bf186700f..9edb3fa4193 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -237,7 +237,7 @@ impl LocalKey { reason = "recently added to create a key", issue = "none" )] - #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] + #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))] pub const unsafe fn new(inner: fn(Option<&mut Option>) -> *const T) -> LocalKey { LocalKey { inner } } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 39753888509..227ee9d64f3 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -158,9 +158,12 @@ #[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] mod tests; +use core::cell::SyncUnsafeCell; +use core::ffi::CStr; +use core::mem::MaybeUninit; + use crate::any::Any; use crate::cell::UnsafeCell; -use crate::ffi::CStr; use crate::marker::PhantomData; use crate::mem::{self, ManuallyDrop, forget}; use crate::num::NonZero; @@ -875,7 +878,7 @@ pub fn sleep(dur: Duration) { /// /// # Platform-specific behavior /// -/// This function uses [`sleep`] internally, see its platform-specific behaviour. +/// This function uses [`sleep`] internally, see its platform-specific behavior. /// /// /// # Examples @@ -946,7 +949,7 @@ pub fn sleep_until(deadline: Instant) { } /// Used to ensure that `park` and `park_timeout` do not unwind, as that can -/// cause undefined behaviour if not handled correctly (see #102398 for context). +/// cause undefined behavior if not handled correctly (see #102398 for context). struct PanicGuard; impl Drop for PanicGuard { @@ -1125,7 +1128,7 @@ pub fn park_timeout(dur: Duration) { let guard = PanicGuard; // SAFETY: park_timeout is called on the parker owned by this thread. unsafe { - current().inner.as_ref().parker().park_timeout(dur); + current().0.parker().park_timeout(dur); } // No panic occurred, do not abort. forget(guard); @@ -1232,30 +1235,31 @@ impl ThreadId { // Thread //////////////////////////////////////////////////////////////////////////////// -/// The internal representation of a `Thread`'s name. -enum ThreadName { - Main, - Other(ThreadNameString), - Unnamed, -} - // This module ensures private fields are kept private, which is necessary to enforce the safety requirements. mod thread_name_string { use core::str; - use super::ThreadName; use crate::ffi::{CStr, CString}; /// Like a `String` it's guaranteed UTF-8 and like a `CString` it's null terminated. pub(crate) struct ThreadNameString { inner: CString, } + + impl ThreadNameString { + pub fn as_str(&self) -> &str { + // SAFETY: `self.inner` is only initialised via `String`, which upholds the validity invariant of `str`. + unsafe { str::from_utf8_unchecked(self.inner.to_bytes()) } + } + } + impl core::ops::Deref for ThreadNameString { type Target = CStr; fn deref(&self) -> &CStr { &self.inner } } + impl From for ThreadNameString { fn from(s: String) -> Self { Self { @@ -1263,34 +1267,82 @@ mod thread_name_string { } } } - impl ThreadName { - pub fn as_cstr(&self) -> Option<&CStr> { - match self { - ThreadName::Main => Some(c"main"), - ThreadName::Other(other) => Some(other), - ThreadName::Unnamed => None, - } - } - - pub fn as_str(&self) -> Option<&str> { - // SAFETY: `as_cstr` can only return `Some` for a fixed CStr or a `ThreadNameString`, - // which is guaranteed to be UTF-8. - self.as_cstr().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) }) - } - } } pub(crate) use thread_name_string::ThreadNameString; -/// The internal representation of a `Thread` handle -struct Inner { - name: ThreadName, // Guaranteed to be UTF-8 +static MAIN_THREAD_INFO: SyncUnsafeCell<(MaybeUninit, MaybeUninit)> = + SyncUnsafeCell::new((MaybeUninit::uninit(), MaybeUninit::uninit())); + +/// The internal representation of a `Thread` that is not the main thread. +struct OtherInner { + name: Option, id: ThreadId, parker: Parker, } +/// The internal representation of a `Thread` handle. +#[derive(Clone)] +enum Inner { + /// Represents the main thread. May only be constructed by Thread::new_main. + Main(&'static (ThreadId, Parker)), + /// Represents any other thread. + Other(Pin>), +} + impl Inner { - fn parker(self: Pin<&Self>) -> Pin<&Parker> { - unsafe { Pin::map_unchecked(self, |inner| &inner.parker) } + fn id(&self) -> ThreadId { + match self { + Self::Main((thread_id, _)) => *thread_id, + Self::Other(other) => other.id, + } + } + + fn cname(&self) -> Option<&CStr> { + match self { + Self::Main(_) => Some(c"main"), + Self::Other(other) => other.name.as_deref(), + } + } + + fn name(&self) -> Option<&str> { + match self { + Self::Main(_) => Some("main"), + Self::Other(other) => other.name.as_ref().map(ThreadNameString::as_str), + } + } + + fn into_raw(self) -> *const () { + match self { + // Just return the pointer to `MAIN_THREAD_INFO`. + Self::Main(ptr) => crate::ptr::from_ref(ptr).cast(), + Self::Other(arc) => { + // Safety: We only expose an opaque pointer, which maintains the `Pin` invariant. + let inner = unsafe { Pin::into_inner_unchecked(arc) }; + Arc::into_raw(inner) as *const () + } + } + } + + /// # Safety + /// + /// See [`Thread::from_raw`]. + unsafe fn from_raw(ptr: *const ()) -> Self { + // If the pointer is to `MAIN_THREAD_INFO`, we know it is the `Main` variant. + if crate::ptr::eq(ptr.cast(), &MAIN_THREAD_INFO) { + Self::Main(unsafe { &*ptr.cast() }) + } else { + // Safety: Upheld by caller + Self::Other(unsafe { Pin::new_unchecked(Arc::from_raw(ptr as *const OtherInner)) }) + } + } + + fn parker(&self) -> Pin<&Parker> { + match self { + Self::Main((_, parker_ref)) => Pin::static_ref(parker_ref), + Self::Other(inner) => unsafe { + Pin::map_unchecked(inner.as_ref(), |inner| &inner.parker) + }, + } } } @@ -1314,33 +1366,47 @@ impl Inner { /// docs of [`Builder`] and [`spawn`] for more details. /// /// [`thread::current`]: current::current -pub struct Thread { - inner: Pin>, -} +pub struct Thread(Inner); impl Thread { /// Used only internally to construct a thread object without spawning. pub(crate) fn new(id: ThreadId, name: String) -> Thread { - Self::new_inner(id, ThreadName::Other(name.into())) + Self::new_inner(id, Some(ThreadNameString::from(name))) } pub(crate) fn new_unnamed(id: ThreadId) -> Thread { - Self::new_inner(id, ThreadName::Unnamed) + Self::new_inner(id, None) } - /// Constructs the thread handle for the main thread. - pub(crate) fn new_main(id: ThreadId) -> Thread { - Self::new_inner(id, ThreadName::Main) + /// Used in runtime to construct main thread + /// + /// # Safety + /// + /// This must only ever be called once, and must be called on the main thread. + pub(crate) unsafe fn new_main(thread_id: ThreadId) -> Thread { + // Safety: As this is only called once and on the main thread, nothing else is accessing MAIN_THREAD_INFO + // as the only other read occurs in `main_thread_info` *after* the main thread has been constructed, + // and this function is the only one that constructs the main thread. + // + // Pre-main thread spawning cannot hit this either, as the caller promises that this is only called on the main thread. + let main_thread_info = unsafe { &mut *MAIN_THREAD_INFO.get() }; + + unsafe { Parker::new_in_place((&raw mut main_thread_info.1).cast()) }; + main_thread_info.0.write(thread_id); + + // Store a `'static` ref to the initialised ThreadId and Parker, + // to avoid having to repeatedly prove initialisation. + Self(Inner::Main(unsafe { &*MAIN_THREAD_INFO.get().cast() })) } - fn new_inner(id: ThreadId, name: ThreadName) -> Thread { + fn new_inner(id: ThreadId, name: Option) -> Thread { // We have to use `unsafe` here to construct the `Parker` in-place, // which is required for the UNIX implementation. // // SAFETY: We pin the Arc immediately after creation, so its address never // changes. let inner = unsafe { - let mut arc = Arc::::new_uninit(); + let mut arc = Arc::::new_uninit(); let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr(); (&raw mut (*ptr).name).write(name); (&raw mut (*ptr).id).write(id); @@ -1348,7 +1414,7 @@ impl Thread { Pin::new_unchecked(arc.assume_init()) }; - Thread { inner } + Self(Inner::Other(inner)) } /// Like the public [`park`], but callable on any handle. This is used to @@ -1357,7 +1423,7 @@ impl Thread { /// # Safety /// May only be called from the thread to which this handle belongs. pub(crate) unsafe fn park(&self) { - unsafe { self.inner.as_ref().parker().park() } + unsafe { self.0.parker().park() } } /// Atomically makes the handle's token available if it is not already. @@ -1393,7 +1459,7 @@ impl Thread { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn unpark(&self) { - self.inner.as_ref().parker().unpark(); + self.0.parker().unpark(); } /// Gets the thread's unique identifier. @@ -1413,7 +1479,7 @@ impl Thread { #[stable(feature = "thread_id", since = "1.19.0")] #[must_use] pub fn id(&self) -> ThreadId { - self.inner.id + self.0.id() } /// Gets the thread's name. @@ -1456,7 +1522,11 @@ impl Thread { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] pub fn name(&self) -> Option<&str> { - self.inner.name.as_str() + self.0.name() + } + + fn cname(&self) -> Option<&CStr> { + self.0.cname() } /// Consumes the `Thread`, returning a raw pointer. @@ -1480,9 +1550,7 @@ impl Thread { /// ``` #[unstable(feature = "thread_raw", issue = "97523")] pub fn into_raw(self) -> *const () { - // Safety: We only expose an opaque pointer, which maintains the `Pin` invariant. - let inner = unsafe { Pin::into_inner_unchecked(self.inner) }; - Arc::into_raw(inner) as *const () + self.0.into_raw() } /// Constructs a `Thread` from a raw pointer. @@ -1504,11 +1572,7 @@ impl Thread { #[unstable(feature = "thread_raw", issue = "97523")] pub unsafe fn from_raw(ptr: *const ()) -> Thread { // Safety: Upheld by caller. - unsafe { Thread { inner: Pin::new_unchecked(Arc::from_raw(ptr as *const Inner)) } } - } - - fn cname(&self) -> Option<&CStr> { - self.inner.name.as_cstr() + unsafe { Thread(Inner::from_raw(ptr)) } } } diff --git a/library/std/src/time.rs b/library/std/src/time.rs index f28a0568a3c..9f4f8a0d088 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -178,9 +178,9 @@ pub struct Instant(time::Instant); /// system. /// /// A `SystemTime` does not count leap seconds. -/// `SystemTime::now()`'s behaviour around a leap second +/// `SystemTime::now()`'s behavior around a leap second /// is the same as the operating system's wall clock. -/// The precise behaviour near a leap second +/// The precise behavior near a leap second /// (e.g. whether the clock appears to run slow or fast, or stop, or jump) /// depends on platform and configuration, /// so should not be relied on. diff --git a/library/stdarch b/library/stdarch index c881fe3231b..ff9a4445038 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit c881fe3231b3947a4766aa15a26a93022fbb8723 +Subproject commit ff9a4445038eae46fd095188740946808581bc0e diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 04909cd7921..d7ae0299dd6 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1092,9 +1092,6 @@ class RustBuild(object): if not os.path.exists(cargo_dir): eprint('ERROR: vendoring required, but .cargo/config does not exist.') raise Exception("{} not found".format(cargo_dir)) - else: - if os.path.exists(cargo_dir): - shutil.rmtree(cargo_dir) def parse_args(args): """Parse the command line arguments that the python script needs.""" diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 15137fbb2b5..2e173c9e6df 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -72,6 +72,7 @@ v("llvm-libunwind", "rust.llvm-libunwind", "use LLVM libunwind") o("optimize-llvm", "llvm.optimize", "build optimized LLVM") o("llvm-assertions", "llvm.assertions", "build LLVM with assertions") o("llvm-enzyme", "llvm.enzyme", "build LLVM with enzyme") +o("llvm-offload", "llvm.offload", "build LLVM with gpu offload support") o("llvm-plugins", "llvm.plugins", "build LLVM with plugin interface") o("debug-assertions", "rust.debug-assertions", "build with debugging assertions") o("debug-assertions-std", "rust.debug-assertions-std", "build the standard library with debugging assertions") diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 27bbc8bd8ff..e13d4ccc618 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -15,7 +15,6 @@ use std::path::{Path, PathBuf}; use std::process::Stdio; use std::{env, fs, str}; -use build_helper::git::get_closest_merge_commit; use serde_derive::Deserialize; use crate::core::build_steps::tool::SourceType; @@ -27,7 +26,7 @@ use crate::core::builder::{ use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection}; use crate::utils::exec::command; use crate::utils::helpers::{ - self, exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date, + exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date, }; use crate::{CLang, Compiler, DependencyType, GitRepo, LLVM_TOOLS, Mode}; @@ -125,23 +124,9 @@ impl Step for Std { // Force compilation of the standard library from source if the `library` is modified. This allows // library team to compile the standard library without needing to compile the compiler with // the `rust.download-rustc=true` option. - let force_recompile = - if builder.rust_info().is_managed_git_subrepository() && builder.download_rustc() { - let closest_merge_commit = - get_closest_merge_commit(Some(&builder.src), &builder.config.git_config(), &[]) - .unwrap(); - - // Check if `library` has changes (returns false otherwise) - !t!(helpers::git(Some(&builder.src)) - .args(["diff-index", "--quiet", &closest_merge_commit]) - .arg("--") - .arg(builder.src.join("library")) - .as_command_mut() - .status()) - .success() - } else { - false - }; + let force_recompile = builder.rust_info().is_managed_git_subrepository() + && builder.download_rustc() + && builder.config.last_modified_commit(&["library"], "download-rustc", true).is_none(); run.builder.ensure(Std { compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index ca2b8742647..69ec832a44a 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -170,7 +170,14 @@ impl Step for RustbookSrc

{ builder.add_rustc_lib_path(compiler, &mut rustbook_cmd); } - rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).run(builder); + rustbook_cmd + .arg("build") + .arg(&src) + .arg("-d") + .arg(&out) + .arg("--rust-root") + .arg(&builder.src) + .run(builder); for lang in &self.languages { let out = out.join(lang); diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index a2d40f6fbd8..ffb7d9a9e0e 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -472,6 +472,21 @@ impl Step for Llvm { cfg.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects.join(";")); } + let mut enabled_llvm_runtimes = Vec::new(); + + if builder.config.llvm_offload { + enabled_llvm_runtimes.push("offload"); + //FIXME(ZuseZ4): LLVM intends to drop the offload dependency on openmp. + //Remove this line once they achieved it. + enabled_llvm_runtimes.push("openmp"); + } + + if !enabled_llvm_runtimes.is_empty() { + enabled_llvm_runtimes.sort(); + enabled_llvm_runtimes.dedup(); + cfg.define("LLVM_ENABLE_RUNTIMES", enabled_llvm_runtimes.join(";")); + } + if let Some(num_linkers) = builder.config.llvm_link_jobs { if num_linkers > 0 { cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string()); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index e25b571acba..2ad1b39a87c 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1734,13 +1734,15 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the } else { // We need to properly build cargo using the suitable stage compiler. - // HACK: currently tool stages are off-by-one compared to compiler stages, i.e. if - // you give `tool::Cargo` a stage 1 rustc, it will cause stage 2 rustc to be built - // and produce a cargo built with stage 2 rustc. To fix this, we need to chop off - // the compiler stage by 1 to align with expected `./x test run-make --stage N` - // behavior, i.e. we need to pass `N - 1` compiler stage to cargo. See also Miri - // which does a similar hack. - let compiler = builder.compiler(builder.top_stage - 1, compiler.host); + let compiler = builder.download_rustc().then_some(compiler).unwrap_or_else(|| + // HACK: currently tool stages are off-by-one compared to compiler stages, i.e. if + // you give `tool::Cargo` a stage 1 rustc, it will cause stage 2 rustc to be built + // and produce a cargo built with stage 2 rustc. To fix this, we need to chop off + // the compiler stage by 1 to align with expected `./x test run-make --stage N` + // behavior, i.e. we need to pass `N - 1` compiler stage to cargo. See also Miri + // which does a similar hack. + builder.compiler(builder.top_stage - 1, compiler.host)); + builder.ensure(tool::Cargo { compiler, target: compiler.host }) }; @@ -1834,6 +1836,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the if builder.config.cmd.only_modified() { cmd.arg("--only-modified"); } + if let Some(compiletest_diff_tool) = &builder.config.compiletest_diff_tool { + cmd.arg("--compiletest-diff-tool").arg(compiletest_diff_tool); + } let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] }; flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests)); @@ -3549,9 +3554,7 @@ impl Step for TestFloatParse { let path = self.path.to_str().unwrap(); let crate_name = self.path.components().last().unwrap().as_os_str().to_str().unwrap(); - if !builder.download_rustc() { - builder.ensure(compile::Std::new(compiler, self.host)); - } + builder.ensure(tool::TestFloatParse { host: self.host }); // Run any unit tests in the crate let cargo_test = tool::prepare_tool_cargo( diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index f5afa6c4c6c..bb837eb8137 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1,8 +1,6 @@ use std::path::PathBuf; use std::{env, fs}; -use build_helper::git::get_closest_merge_commit; - use crate::core::build_steps::compile; use crate::core::build_steps::toolstate::ToolState; use crate::core::builder; @@ -10,7 +8,7 @@ use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, use crate::core::config::TargetSelection; use crate::utils::channel::GitInfo; use crate::utils::exec::{BootstrapCommand, command}; -use crate::utils::helpers::{add_dylib_path, exe, git, t}; +use crate::utils::helpers::{add_dylib_path, exe, t}; use crate::{Compiler, Kind, Mode, gha}; #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -596,28 +594,11 @@ impl Step for Rustdoc { && target_compiler.stage > 0 && builder.rust_info().is_managed_git_subrepository() { - let commit = get_closest_merge_commit( - Some(&builder.config.src), - &builder.config.git_config(), - &[], - ) - .unwrap(); + let files_to_track = &["src/librustdoc", "src/tools/rustdoc"]; - let librustdoc_src = builder.config.src.join("src/librustdoc"); - let rustdoc_src = builder.config.src.join("src/tools/rustdoc"); - - // FIXME: The change detection logic here is quite similar to `Config::download_ci_rustc_commit`. - // It would be better to unify them. - let has_changes = !git(Some(&builder.config.src)) - .allow_failure() - .run_always() - .args(["diff-index", "--quiet", &commit]) - .arg("--") - .arg(librustdoc_src) - .arg(rustdoc_src) - .run(builder); - - if !has_changes { + // Check if unchanged + if builder.config.last_modified_commit(files_to_track, "download-rustc", true).is_some() + { let precompiled_rustdoc = builder .config .ci_rustc_dir() @@ -1097,6 +1078,38 @@ tool_extended!((self, builder), Rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, add_bins_to_sysroot = ["rustfmt", "cargo-fmt"]; ); +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct TestFloatParse { + pub host: TargetSelection, +} + +impl Step for TestFloatParse { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = false; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/etc/test-float-parse") + } + + fn run(self, builder: &Builder<'_>) { + let bootstrap_host = builder.config.build; + let compiler = builder.compiler(builder.top_stage, bootstrap_host); + + builder.ensure(ToolBuild { + compiler, + target: bootstrap_host, + tool: "test-float-parse", + mode: Mode::ToolStd, + path: "src/etc/test-float-parse", + source_type: SourceType::InTree, + extra_features: Vec::new(), + allow_features: "", + cargo_args: Vec::new(), + }); + } +} + impl Builder<'_> { /// Gets a `BootstrapCommand` which is ready to run `tool` in `stage` built for /// `host`. diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index aeb81b14638..139ca7eb52e 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -224,6 +224,7 @@ pub struct Config { pub llvm_assertions: bool, pub llvm_tests: bool, pub llvm_enzyme: bool, + pub llvm_offload: bool, pub llvm_plugins: bool, pub llvm_optimize: bool, pub llvm_thin_lto: bool, @@ -368,6 +369,9 @@ pub struct Config { /// The paths to work with. For example: with `./x check foo bar` we get /// `paths=["foo", "bar"]`. pub paths: Vec, + + /// Command for visual diff display, e.g. `diff-tool --color=always`. + pub compiletest_diff_tool: Option, } #[derive(Clone, Debug, Default)] @@ -892,6 +896,7 @@ define_config! { android_ndk: Option = "android-ndk", optimized_compiler_builtins: Option = "optimized-compiler-builtins", jobs: Option = "jobs", + compiletest_diff_tool: Option = "compiletest-diff-tool", } } @@ -934,6 +939,7 @@ define_config! { use_libcxx: Option = "use-libcxx", use_linker: Option = "use-linker", allow_old_toolchain: Option = "allow-old-toolchain", + offload: Option = "offload", polly: Option = "polly", clang: Option = "clang", enable_warnings: Option = "enable-warnings", @@ -1512,6 +1518,7 @@ impl Config { android_ndk, optimized_compiler_builtins, jobs, + compiletest_diff_tool, } = toml.build.unwrap_or_default(); config.jobs = Some(threads_from_config(flags.jobs.unwrap_or(jobs.unwrap_or(0)))); @@ -1642,6 +1649,7 @@ impl Config { // we'll infer default values for them later let mut llvm_tests = None; let mut llvm_enzyme = None; + let mut llvm_offload = None; let mut llvm_plugins = None; let mut debug = None; let mut debug_assertions = None; @@ -1879,6 +1887,7 @@ impl Config { use_libcxx, use_linker, allow_old_toolchain, + offload, polly, clang, enable_warnings, @@ -1895,6 +1904,7 @@ impl Config { set(&mut config.ninja_in_file, ninja); llvm_tests = tests; llvm_enzyme = enzyme; + llvm_offload = offload; llvm_plugins = plugins; set(&mut config.llvm_optimize, optimize_toml); set(&mut config.llvm_thin_lto, thin_lto); @@ -1916,6 +1926,7 @@ impl Config { set(&mut config.llvm_use_libcxx, use_libcxx); config.llvm_use_linker.clone_from(&use_linker); config.llvm_allow_old_toolchain = allow_old_toolchain.unwrap_or(false); + config.llvm_offload = offload.unwrap_or(false); config.llvm_polly = polly.unwrap_or(false); config.llvm_clang = clang.unwrap_or(false); config.llvm_enable_warnings = enable_warnings.unwrap_or(false); @@ -2092,6 +2103,7 @@ impl Config { config.llvm_tests = llvm_tests.unwrap_or(false); config.llvm_enzyme = llvm_enzyme.unwrap_or(false); + config.llvm_offload = llvm_offload.unwrap_or(false); config.llvm_plugins = llvm_plugins.unwrap_or(false); config.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true)); @@ -2158,6 +2170,7 @@ impl Config { config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(DebuginfoLevel::None); config.optimized_compiler_builtins = optimized_compiler_builtins.unwrap_or(config.channel != "dev"); + config.compiletest_diff_tool = compiletest_diff_tool; let download_rustc = config.download_rustc_commit.is_some(); // See https://github.com/rust-lang/compiler-team/issues/326 @@ -2754,25 +2767,25 @@ impl Config { } }; - let files_to_track = &[ - self.src.join("compiler"), - self.src.join("library"), - self.src.join("src/version"), - self.src.join("src/stage0"), - self.src.join("src/ci/channel"), - ]; + let files_to_track = + &["compiler", "library", "src/version", "src/stage0", "src/ci/channel"]; // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. - let commit = - get_closest_merge_commit(Some(&self.src), &self.git_config(), files_to_track).unwrap(); - if commit.is_empty() { - println!("ERROR: could not find commit hash for downloading rustc"); - println!("HELP: maybe your repository history is too shallow?"); - println!("HELP: consider disabling `download-rustc`"); - println!("HELP: or fetch enough history to include one upstream commit"); - crate::exit!(1); - } + let commit = match self.last_modified_commit(files_to_track, "download-rustc", if_unchanged) + { + Some(commit) => commit, + None => { + if if_unchanged { + return None; + } + println!("ERROR: could not find commit hash for downloading rustc"); + println!("HELP: maybe your repository history is too shallow?"); + println!("HELP: consider disabling `download-rustc`"); + println!("HELP: or fetch enough history to include one upstream commit"); + crate::exit!(1); + } + }; if CiEnv::is_ci() && { let head_sha = @@ -2787,31 +2800,7 @@ impl Config { return None; } - // Warn if there were changes to the compiler or standard library since the ancestor commit. - let has_changes = !t!(helpers::git(Some(&self.src)) - .args(["diff-index", "--quiet", &commit]) - .arg("--") - .args(files_to_track) - .as_command_mut() - .status()) - .success(); - if has_changes { - if if_unchanged { - if self.is_verbose() { - println!( - "WARNING: saw changes to compiler/ or library/ since {commit}; \ - ignoring `download-rustc`" - ); - } - return None; - } - println!( - "WARNING: `download-rustc` is enabled, but there are changes to \ - compiler/ or library/" - ); - } - - Some(commit.to_string()) + Some(commit) } fn parse_download_ci_llvm( @@ -2882,14 +2871,7 @@ impl Config { // Warn if there were changes to the compiler or standard library since the ancestor commit. let mut git = helpers::git(Some(&self.src)); - git.args(["diff-index", "--quiet", &commit, "--"]); - - // Handle running from a directory other than the top level - let top_level = &self.src; - - for path in modified_paths { - git.arg(top_level.join(path)); - } + git.args(["diff-index", "--quiet", &commit, "--"]).args(modified_paths); let has_changes = !t!(git.as_command_mut().status()).success(); if has_changes { @@ -2981,6 +2963,7 @@ pub(crate) fn check_incompatible_options_for_ci_llvm( use_libcxx, use_linker, allow_old_toolchain, + offload, polly, clang, enable_warnings, @@ -3003,6 +2986,7 @@ pub(crate) fn check_incompatible_options_for_ci_llvm( err!(current_llvm_config.use_libcxx, use_libcxx); err!(current_llvm_config.use_linker, use_linker); err!(current_llvm_config.allow_old_toolchain, allow_old_toolchain); + err!(current_llvm_config.offload, offload); err!(current_llvm_config.polly, polly); err!(current_llvm_config.clang, clang); err!(current_llvm_config.build_config, build_config); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 3924a6d714e..ba74cabcd30 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -541,27 +541,32 @@ impl Build { } let output = helpers::git(Some(&self.src)) .args(["config", "--file"]) - .arg(self.config.src.join(".gitmodules")) + .arg(".gitmodules") .args(["--get-regexp", "path"]) .run_capture(self) .stdout(); - for line in output.lines() { + std::thread::scope(|s| { // Look for `submodule.$name.path = $path` // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer` - let submodule = line.split_once(' ').unwrap().1; - self.update_existing_submodule(submodule); - } + for line in output.lines() { + let submodule = line.split_once(' ').unwrap().1; + let config = self.config.clone(); + s.spawn(move || { + Self::update_existing_submodule(&config, submodule); + }); + } + }); } /// Updates the given submodule only if it's initialized already; nothing happens otherwise. - pub fn update_existing_submodule(&self, submodule: &str) { + pub fn update_existing_submodule(config: &Config, submodule: &str) { // Avoid running git when there isn't a git checkout. - if !self.config.submodules() { + if !config.submodules() { return; } if GitInfo::new(false, Path::new(submodule)).is_managed_git_subrepository() { - self.config.update_submodule(submodule); + config.update_submodule(submodule); } } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 9169bc90a45..b9cf8f05316 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -280,4 +280,14 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "Allow setting `--jobs` in config.toml with `build.jobs`.", }, + ChangeInfo { + change_id: 131181, + severity: ChangeSeverity::Info, + summary: "New option `build.compiletest-diff-tool` that adds support for a custom differ for compiletest", + }, + ChangeInfo { + change_id: 131513, + severity: ChangeSeverity::Info, + summary: "New option `llvm.offload` to control whether the llvm offload runtime for GPU support is built. Implicitly enables the openmp runtime as dependency.", + }, ]; diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs index c361abb9c9e..4a9ecc7a4f8 100644 --- a/src/bootstrap/src/utils/channel.rs +++ b/src/bootstrap/src/utils/channel.rs @@ -10,7 +10,7 @@ use std::path::Path; use super::helpers; use crate::Build; -use crate::utils::helpers::{output, t}; +use crate::utils::helpers::{start_process, t}; #[derive(Clone, Default)] pub enum GitInfo { @@ -56,7 +56,7 @@ impl GitInfo { } // Ok, let's scrape some info - let ver_date = output( + let ver_date = start_process( helpers::git(Some(dir)) .arg("log") .arg("-1") @@ -65,14 +65,14 @@ impl GitInfo { .as_command_mut(), ); let ver_hash = - output(helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").as_command_mut()); - let short_ver_hash = output( + start_process(helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").as_command_mut()); + let short_ver_hash = start_process( helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD").as_command_mut(), ); GitInfo::Present(Some(Info { - commit_date: ver_date.trim().to_string(), - sha: ver_hash.trim().to_string(), - short_sha: short_ver_hash.trim().to_string(), + commit_date: ver_date().trim().to_string(), + sha: ver_hash().trim().to_string(), + short_sha: short_ver_hash().trim().to_string(), })) } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 2519ace92b9..7162007e9f0 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -288,6 +288,33 @@ pub fn output(cmd: &mut Command) -> String { String::from_utf8(output.stdout).unwrap() } +/// Spawn a process and return a closure that will wait for the process +/// to finish and then return its output. This allows the spawned process +/// to do work without immediately blocking bootstrap. +#[track_caller] +pub fn start_process(cmd: &mut Command) -> impl FnOnce() -> String { + let child = match cmd.stderr(Stdio::inherit()).stdout(Stdio::piped()).spawn() { + Ok(child) => child, + Err(e) => fail(&format!("failed to execute command: {cmd:?}\nERROR: {e}")), + }; + + let command = format!("{:?}", cmd); + + move || { + let output = child.wait_with_output().unwrap(); + + if !output.status.success() { + panic!( + "command did not execute successfully: {}\n\ + expected success, got: {}", + command, output.status + ); + } + + String::from_utf8(output.stdout).unwrap() + } +} + /// Returns the last-modified time for `path`, or zero if it doesn't exist. pub fn mtime(path: &Path) -> SystemTime { fs::metadata(path).and_then(|f| f.modified()).unwrap_or(UNIX_EPOCH) diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile new file mode 100644 index 00000000000..dcfea77149e --- /dev/null +++ b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile @@ -0,0 +1,58 @@ +FROM ubuntu:22.04 + +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python3 \ + python3-dev \ + libxml2-dev \ + libncurses-dev \ + libedit-dev \ + swig \ + doxygen \ + git \ + cmake \ + sudo \ + gdb \ + libssl-dev \ + pkg-config \ + xz-utils \ + lld \ + clang \ + && rm -rf /var/lib/apt/lists/* + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS 1 +ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 + +# llvm.use-linker conflicts with downloading CI LLVM +ENV NO_DOWNLOAD_CI_LLVM 1 + +ENV RUST_CONFIGURE_ARGS \ + --build=aarch64-unknown-linux-gnu \ + --enable-debug \ + --enable-lld \ + --set llvm.use-linker=lld \ + --set target.aarch64-unknown-linux-gnu.linker=clang \ + --set target.aarch64-unknown-linux-gnu.cc=clang \ + --set target.aarch64-unknown-linux-gnu.cxx=clang++ + +# This job appears to be checking two separate things: +# - That we can build the compiler with `--enable-debug` +# (without necessarily testing the result). +# - That the tests with `//@ needs-force-clang-based-tests` pass, since they +# don't run by default unless RUSTBUILD_FORCE_CLANG_BASED_TESTS is set. +# - FIXME(https://github.com/rust-lang/rust/pull/126155#issuecomment-2156314273): +# Currently we only run the subset of tests with "clang" in their name. +# - See also FIXME(#132034) + +ENV SCRIPT \ + python3 ../x.py --stage 2 build && \ + python3 ../x.py --stage 2 test tests/run-make --test-args clang diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index 410f0f92e60..ece5f174d06 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -56,9 +56,9 @@ ENV \ CFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \ CXX_x86_64_fortanix_unknown_sgx=clang++-11 \ CXXFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \ - AR_i686_unknown_freebsd=i686-unknown-freebsd13-ar \ - CC_i686_unknown_freebsd=i686-unknown-freebsd13-clang \ - CXX_i686_unknown_freebsd=i686-unknown-freebsd13-clang++ \ + AR_i686_unknown_freebsd=i686-unknown-freebsd12-ar \ + CC_i686_unknown_freebsd=i686-unknown-freebsd12-clang \ + CXX_i686_unknown_freebsd=i686-unknown-freebsd12-clang++ \ CC_aarch64_unknown_uefi=clang-11 \ CXX_aarch64_unknown_uefi=clang++-11 \ CC_i686_unknown_uefi=clang-11 \ @@ -118,6 +118,7 @@ ENV TARGETS=$TARGETS,wasm32-wasi ENV TARGETS=$TARGETS,wasm32-wasip1 ENV TARGETS=$TARGETS,wasm32-wasip1-threads ENV TARGETS=$TARGETS,wasm32-wasip2 +ENV TARGETS=$TARGETS,wasm32v1-none ENV TARGETS=$TARGETS,sparcv9-sun-solaris ENV TARGETS=$TARGETS,x86_64-pc-solaris ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile index fd0f5da8c49..f42e6f770eb 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile @@ -29,9 +29,9 @@ COPY scripts/cmake.sh /scripts/ RUN /scripts/cmake.sh ENV \ - AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-ar \ - CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang \ - CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang++ + AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-ar \ + CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang \ + CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang++ ENV HOSTS=x86_64-unknown-freebsd diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile index fa31801269a..292dbfd20a5 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile @@ -49,9 +49,7 @@ ENV RUST_CONFIGURE_ARGS \ # (without necessarily testing the result). # - That the tests with `//@ needs-force-clang-based-tests` pass, since they # don't run by default unless RUSTBUILD_FORCE_CLANG_BASED_TESTS is set. -# - FIXME(https://github.com/rust-lang/rust/pull/126155#issuecomment-2156314273): -# Currently we only run the subset of tests with "clang" in their name. 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/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh index 4826b81d56c..0d02636db91 100755 --- a/src/ci/docker/scripts/freebsd-toolchain.sh +++ b/src/ci/docker/scripts/freebsd-toolchain.sh @@ -5,8 +5,8 @@ set -eux arch=$1 binutils_version=2.40 -freebsd_version=13.2 -triple=$arch-unknown-freebsd13 +freebsd_version=12.3 +triple=$arch-unknown-freebsd12 sysroot=/usr/local/$triple hide_output() { @@ -59,7 +59,7 @@ done # Originally downloaded from: # URL=https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz -URL=https://ci-mirrors.rust-lang.org/rustc/2024-02-18-freebsd-${freebsd_version}-${freebsd_arch}-base.txz +URL=https://ci-mirrors.rust-lang.org/rustc/2022-05-06-freebsd-${freebsd_version}-${freebsd_arch}-base.txz curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}" # Clang can do cross-builds out of the box, if we give it the right @@ -68,7 +68,7 @@ curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}" # there might be other problems.) # # The --target option is last because the cross-build of LLVM uses -# --target without an OS version ("-freebsd" vs. "-freebsd13"). This +# --target without an OS version ("-freebsd" vs. "-freebsd12"). This # makes Clang default to libstdc++ (which no longer exists), and also # controls other features, like GNU-style symbol table hashing and # anything predicated on the version number in the __FreeBSD__ diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index 1aa9a4a1794..77e2741f9ea 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -287,7 +287,7 @@ class TestEnvironment: @property def package_server_log_path(self) -> Path: - return self.tmp_dir().joinpath("package_server_log") + return self.tmp_dir().joinpath(f"repo_{self.TEST_REPO_NAME}.log") @property def emulator_log_path(self) -> Path: @@ -401,6 +401,7 @@ class TestEnvironment: # Set configs configs = { "log.enabled": "true", + "log.dir": self.tmp_dir(), "test.is_isolated": "true", "test.experimental_structured_output": "true", } @@ -575,43 +576,19 @@ class TestEnvironment: stderr_handler=self.subprocess_logger.debug, ) - # Add repository - check_call_with_logging( - [ - ffx_path, - "repository", - "add-from-pm", - "--repository", - self.TEST_REPO_NAME, - self.repo_dir(), - ], - env=ffx_env, - stdout_handler=self.subprocess_logger.debug, - stderr_handler=self.subprocess_logger.debug, - ) - - # Start repository server - # Note that we must first enable the repository server daemon. - check_call_with_logging( - [ - ffx_path, - "config", - "set", - "repository.server.enabled", - "true", - ], - env=ffx_env, - stdout_handler=self.subprocess_logger.debug, - stderr_handler=self.subprocess_logger.debug, - ) check_call_with_logging( [ ffx_path, "repository", "server", "start", + "--background", "--address", "[::]:0", + "--repo-path", + self.repo_dir(), + "--repository", + self.TEST_REPO_NAME ], env=ffx_env, stdout_handler=self.subprocess_logger.debug, @@ -1009,6 +986,21 @@ class TestEnvironment: stderr_handler=self.subprocess_logger.debug, ) + # Stop the package server + self.env_logger.info("Stopping package server...") + check_call_with_logging( + [ + self.tool_path("ffx"), + "repository", + "server", + "stop", + self.TEST_REPO_NAME + ], + env=self.ffx_cmd_env(), + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, + ) + # Stop ffx isolation self.env_logger.info("Stopping ffx isolation...") self.stop_ffx_isolation() diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index 27dbfc6040c..f07515f7784 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -2,7 +2,7 @@ set -euo pipefail -LINUX_VERSION=v6.12-rc2 +LINUX_VERSION=28e848386b92645f93b9f2fdba5882c3ca7fb3e2 # Build rustc, rustdoc, cargo, clippy-driver and rustfmt ../x.py build --stage 2 library rustdoc clippy rustfmt diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 2b636604049..a401092a3a7 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -123,6 +123,9 @@ auto: - image: aarch64-gnu <<: *job-aarch64-linux + - image: aarch64-gnu-debug + <<: *job-aarch64-linux + - image: arm-android <<: *job-linux-4c @@ -253,7 +256,9 @@ auto: <<: *job-linux-4c - image: x86_64-gnu-debug - <<: *job-linux-4c + # This seems to be needed because a full stage 2 build + run-make tests + # overwhelms the storage capacity of the standard 4c runner. + <<: *job-linux-4c-largedisk - image: x86_64-gnu-distcheck <<: *job-linux-8c diff --git a/src/ci/run.sh b/src/ci/run.sh index 3962c354c10..8e2f525db68 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -47,11 +47,6 @@ source "$ci_dir/shared.sh" export CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse -# suppress change-tracker warnings on CI -if [ "$CI" != "" ]; then - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set change-id=99999999" -fi - # If runner uses an incompatible option and `FORCE_CI_RUSTC` is not defined, # switch to in-tree rustc. if [ "$FORCE_CI_RUSTC" == "" ]; then diff --git a/src/doc/edition-guide b/src/doc/edition-guide index c7ebae25cb4..1f07c242f81 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit c7ebae25cb4801a31b6f05353f6d85bfa6feedd1 +Subproject commit 1f07c242f8162a711a5ac5a4ea8fa7ec884ee7a9 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index f40a8b420ec..ddbf1b4e285 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit f40a8b420ec4b4505d9489965e261f1d5c28ba23 +Subproject commit ddbf1b4e2858fedb71b7c42eb15c4576517dc125 diff --git a/src/doc/reference b/src/doc/reference index c64e52a3d30..23ce6199665 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit c64e52a3d306eac0129f3ad6c6d8806ab99ae2e9 +Subproject commit 23ce619966541bf2c80d45fdfeecf3393e360a13 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 07bc9ca9eb1..59d94ea75a0 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 07bc9ca9eb1cd6d9fbbf758c2753b748804a134f +Subproject commit 59d94ea75a0b157e148af14c73c2dd60efb7b60a diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 795908b32c0..18f76ac6fe0 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -66,9 +66,10 @@ - [powerpc-unknown-openbsd](platform-support/powerpc-unknown-openbsd.md) - [powerpc-unknown-linux-muslspe](platform-support/powerpc-unknown-linux-muslspe.md) - [powerpc64-ibm-aix](platform-support/aix.md) + - [riscv32e*-unknown-none-elf](platform-support/riscv32e-unknown-none-elf.md) + - [riscv32i*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md) - [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md) - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) - - [riscv32*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md) - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md) - [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md) - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md) @@ -86,6 +87,7 @@ - [wasm32-wasip2](platform-support/wasm32-wasip2.md) - [wasm32-unknown-emscripten](platform-support/wasm32-unknown-emscripten.md) - [wasm32-unknown-unknown](platform-support/wasm32-unknown-unknown.md) + - [wasm32v1-none](platform-support/wasm32v1-none.md) - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md) - [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md) - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index e9c73ef1c2d..04bb40d750c 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -100,7 +100,7 @@ target | notes [`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) -`x86_64-unknown-freebsd` | 64-bit FreeBSD (version 13.2) +`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 [`x86_64-unknown-netbsd`](platform-support/netbsd.md) | NetBSD/amd64 @@ -166,7 +166,7 @@ target | std | notes `i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, musl 1.2.3 [^x86_32-floats-x87] [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android [^x86_32-floats-return-ABI] [`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+), LLVM ABI [^x86_32-floats-return-ABI] -`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD (version 13.2) [^x86_32-floats-return-ABI] +`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD [^x86_32-floats-return-ABI] `i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 [^x86_32-floats-return-ABI] [`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI) @@ -195,6 +195,7 @@ target | std | notes `wasm32-wasi` | ✓ | WebAssembly with WASI (undergoing a [rename to `wasm32-wasip1`][wasi-rename]) [`wasm32-wasip1`](platform-support/wasm32-wasip1.md) | ✓ | WebAssembly with WASI [`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ | WebAssembly with WASI Preview 1 and threads +[`wasm32v1-none`](platform-support/wasm32v1-none.md) | * | WebAssembly limited to 1.0 features and no imports [`x86_64-apple-ios`](platform-support/apple-ios.md) | ✓ | 64-bit x86 iOS [`x86_64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ | Mac Catalyst on x86_64 [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX @@ -257,7 +258,7 @@ target | std | host | notes [`aarch64-unknown-teeos`](platform-support/aarch64-unknown-teeos.md) | ? | | ARM64 TEEOS | [`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.0 RTOS | [`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS | -`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD (version 13.2) +`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD [`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit `aarch64-unknown-illumos` | ✓ | ✓ | ARM64 illumos `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) @@ -276,14 +277,14 @@ target | std | host | notes `armv4t-unknown-linux-gnueabi` | ? | | Armv4T Linux [`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare Armv5TE `armv5te-unknown-linux-uclibceabi` | ? | | Armv5TE Linux with uClibc -`armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD (version 13.2) +`armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD [`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv6 NetBSD w/hard-float [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? | | Armv6k Nintendo 3DS, Horizon (Requires devkitARM toolchain) [`armv7-rtems-eabihf`](platform-support/armv7-rtems-eabihf.md) | ? | | RTEMS OS for ARM BSPs [`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ✓ | | Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain) [`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | Armv7-A Linux with uClibc, softfloat [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | Armv7-A Linux with uClibc, hardfloat -`armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD (version 13.2) +`armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD [`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv7-A NetBSD w/hard-float [`armv7-unknown-trusty`](platform-support/trusty.md) | ? | | [`armv7-wrs-vxworks-eabihf`](platform-support/vxworks.md) | ✓ | | Armv7-A for VxWorks @@ -342,9 +343,9 @@ target | std | host | notes [`powerpc-unknown-openbsd`](platform-support/powerpc-unknown-openbsd.md) | * | | [`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ | | [`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | -`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2, version 13.2) -`powerpc64le-unknown-freebsd` | | | PPC64LE FreeBSD (version 13.2) -`powerpc-unknown-freebsd` | | | PowerPC FreeBSD (version 13.2) +`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2) +`powerpc64le-unknown-freebsd` | | | PPC64LE FreeBSD +`powerpc-unknown-freebsd` | | | PowerPC FreeBSD `powerpc64-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3 [`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | `powerpc64le-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3, Little Endian @@ -360,7 +361,7 @@ target | std | host | notes [`riscv32imafc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ | | RISC-V Hermit -`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD (version 13.2) +`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD `riscv64gc-unknown-fuchsia` | | | RISC-V Fuchsia [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64 @@ -413,8 +414,8 @@ target | std | host | notes [`riscv32imafc-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 32bit with NuttX [`riscv64imac-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 64bit with NuttX [`riscv64gc-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 64bit with NuttX -[`riscv32e-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32E ISA) -[`riscv32em-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32EM ISA) -[`riscv32emc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32EMC ISA) +[`riscv32e-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * | | Bare RISC-V (RV32E ISA) +[`riscv32em-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * | | Bare RISC-V (RV32EM ISA) +[`riscv32emc-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * | | Bare RISC-V (RV32EMC ISA) [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets diff --git a/src/doc/rustc/src/platform-support/nuttx.md b/src/doc/rustc/src/platform-support/nuttx.md index cbbede45f52..433a092aab2 100644 --- a/src/doc/rustc/src/platform-support/nuttx.md +++ b/src/doc/rustc/src/platform-support/nuttx.md @@ -35,7 +35,7 @@ The following target names are defined: ## Building the target -The target can be built by enabled in the `rustc` build: +The target can be built by enabling it in the `rustc` build: ```toml [build] diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md index 48a8df0c4a8..73264aba858 100644 --- a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md +++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md @@ -132,10 +132,20 @@ As of the time of this writing the proposals that are enabled by default (the If you're compiling WebAssembly code for an engine that does not support a feature in LLVM's default feature set then the feature must be disabled at -compile time. Note, though, that enabled features may be used in the standard -library or precompiled libraries shipped via rustup. This means that not only -does your own code need to be compiled with the correct set of flags but the -Rust standard library additionally must be recompiled. +compile time. There are two approaches to choose from: + + - If you are targeting a feature set no smaller than the W3C WebAssembly Core + 1.0 recommendation -- which is equivalent to the WebAssembly MVP plus the + `mutable-globals` feature -- and you are building `no_std`, then you can + simply use the [`wasm32v1-none` target](./wasm32v1-none.md) instead of + `wasm32-unknown-unknown`, which uses only those minimal features and + includes a core and alloc library built with only those minimal features. + + - Otherwise -- if you need std, or if you need to target the ultra-minimal + "MVP" feature set, excluding `mutable-globals` -- you will need to manually + specify `-Ctarget-cpu=mvp` and also rebuild the stdlib using that target to + ensure no features are used in the stdlib. This in turn requires use of a + nightly compiler. Compiling all code for the initial release of WebAssembly looks like: @@ -150,9 +160,9 @@ then used to recompile the standard library in addition to your own code. This will produce a binary that uses only the original WebAssembly features by default and no proposals since its inception. -To enable individual features it can be done with `-Ctarget-feature=+foo`. -Available features for Rust code itself are documented in the [reference] and -can also be found through: +To enable individual features on either this target or `wasm32v1-none`, pass +arguments of the form `-Ctarget-feature=+foo`. Available features for Rust code +itself are documented in the [reference] and can also be found through: ```sh $ rustc -Ctarget-feature=help --target wasm32-unknown-unknown diff --git a/src/doc/rustc/src/platform-support/wasm32v1-none.md b/src/doc/rustc/src/platform-support/wasm32v1-none.md new file mode 100644 index 00000000000..46f89c20113 --- /dev/null +++ b/src/doc/rustc/src/platform-support/wasm32v1-none.md @@ -0,0 +1,109 @@ +# `wasm32v1-none` + +**Tier: 2** + +The `wasm32v1-none` target is a WebAssembly compilation target that: + +- Imports nothing from its host environment +- Enables no proposals / features past the [W3C WebAssembly Core 1.0 spec] + +[W3C WebAssembly Core 1.0 spec]: https://www.w3.org/TR/wasm-core-1/ + +The target is very similar to [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md) and similarly uses LLVM's `wasm32-unknown-unknown` backend target. It contains only three minor differences: + +* Setting the `target-cpu` to `mvp` rather than the default `generic`. Requesting `mvp` disables _all_ WebAssembly proposals / LLVM target feature flags. +* Enabling the [Import/Export of Mutable Globals] proposal (i.e. the `+mutable-globals` LLVM target feature flag) +* Not compiling the `std` library at all, rather than compiling it with stubs. + +[Import/Export of Mutable Globals]: https://github.com/WebAssembly/mutable-global + +## Target maintainers + +- Alex Crichton, https://github.com/alexcrichton +- Graydon Hoare, https://github.com/graydon + +## Requirements + +This target is cross-compiled. It does not support `std`, only `core` and `alloc`. Since it imports nothing from its environment, any `std` parts that use OS facilities would be stubbed out with functions-that-fail anyways, and the experience of working with the stub `std` in the `wasm32-unknown-unknown` target was deemed not something worth repeating here. + +Everything else about this target's requirements, building, usage and testing is the same as what's described in the [`wasm32-unknown-unknown` document](./wasm32-unknown-unknown.md), just using the target string `wasm32v1-none` in place of `wasm32-unknown-unknown`. + +## Conditionally compiling code + +It's recommended to conditionally compile code for this target with: + +```text +#[cfg(all(target_family = "wasm", target_os = "none"))] +``` + +Note that there is no way to tell via `#[cfg]` whether code will be running on +the web or not. + +## Enabled WebAssembly features + +As noted above, _no WebAssembly proposals past 1.0_ are enabled on this target by default. Indeed, the entire point of this target is to have a way to compile for a stable "no post-1.0 proposals" subset of WebAssembly _on stable Rust_. + +The [W3C WebAssembly Core 1.0 spec] was adopted as a W3C recommendation in December 2019, and includes exactly one "post-MVP" proposal: the [Import/Export of Mutable Globals] proposal. + +All subsequent proposals are _disabled_ on this target by default, though they can be individually enabled by passing LLVM target-feature flags. + +For reference sake, the set of proposals that LLVM supports at the time of writing, that this target _does not enable by default_, are listed here along with their LLVM target-feature flags: + +* Post-1.0 proposals (integrated into the WebAssembly core 2.0 spec): + * [Bulk memory] - `+bulk-memory` + * [Sign-extending operations] - `+sign-ext` + * [Non-trapping fp-to-int operations] - `+nontrapping-fptoint` + * [Multi-value] - `+multivalue` + * [Reference Types] - `+reference-types` + * [Fixed-width SIMD] - `+simd128` +* Post-2.0 proposals: + * [Threads] (supported by atomics) - `+atomics` + * [Exception handling] - `+exception-handling` + * [Extended Constant Expressions] - `+extended-const` + * [Half Precision] - `+half-precision` + * [Multiple memories]- `+multimemory` + * [Relaxed SIMD] - `+relaxed-simd` + * [Tail call] - `+tail-call` + +[Bulk memory]: https://github.com/WebAssembly/spec/blob/main/proposals/bulk-memory-operations/Overview.md +[Sign-extending operations]: https://github.com/WebAssembly/spec/blob/main/proposals/sign-extension-ops/Overview.md +[Non-trapping fp-to-int operations]: https://github.com/WebAssembly/spec/blob/main/proposals/nontrapping-float-to-int-conversion/Overview.md +[Multi-value]: https://github.com/WebAssembly/spec/blob/main/proposals/multi-value/Overview.md +[Reference Types]: https://github.com/WebAssembly/spec/blob/main/proposals/reference-types/Overview.md +[Fixed-width SIMD]: https://github.com/WebAssembly/spec/blob/main/proposals/simd/SIMD.md +[Threads]: https://github.com/webassembly/threads +[Exception handling]: https://github.com/WebAssembly/exception-handling +[Extended Constant Expressions]: https://github.com/WebAssembly/extended-const +[Half Precision]: https://github.com/WebAssembly/half-precision +[Multiple memories]: https://github.com/WebAssembly/multi-memory +[Relaxed SIMD]: https://github.com/WebAssembly/relaxed-simd +[Tail call]: https://github.com/WebAssembly/tail-call + +Additional proposals in the future are, of course, also not enabled by default. + +## Rationale relative to wasm32-unknown-unknown + +As noted in the [`wasm32-unknown-unknown` document](./wasm32-unknown-unknown.md), it is possible to compile with `--target wasm32-unknown-unknown` and disable all WebAssembly proposals "by hand", by passing `-Ctarget-cpu=mvp`. Furthermore one can enable proposals one by one by passing LLVM target feature flags, such as `-Ctarget-feature=+mutable-globals`. + +Is it therefore reasonable to wonder what the difference is between building with this: + +```sh +$ rustc --target wasm32-unknown-unknown -Ctarget-cpu=mvp -Ctarget-feature=+mutable-globals +``` + +and building with this: + +```sh +$ rustc --target wasm32v1-none +``` + +The difference is in how the `core` and `alloc` crates are compiled for distribution with the toolchain, and whether it works on _stable_ Rust toolchains or requires _nightly_ ones. Again referring back to the [`wasm32-unknown-unknown` document](./wasm32-unknown-unknown.md), note that to disable all post-MVP proposals on that target one _actually_ has to compile with this: + +```sh +$ export RUSTFLAGS="-Ctarget-cpu=mvp -Ctarget-feature=+mutable-globals" +$ cargo +nightly build -Zbuild-std=panic_abort,std --target wasm32-unknown-unknown +``` + +Which not only rebuilds `std`, `core` and `alloc` (which is somewhat costly and annoying) but more importantly requires the use of nightly Rust toolchains (for the `-Zbuild-std` flag). This is very undesirable for the target audience, which consists of people targeting WebAssembly implementations that prioritize stability, simplicity and/or security over feature support. + +This `wasm32v1-none` target exists as an alternative option that works on stable Rust toolchains, without rebuilding the stdlib. diff --git a/src/doc/rustc/src/symbol-mangling/v0.md b/src/doc/rustc/src/symbol-mangling/v0.md index 6329e878c5c..109942518fc 100644 --- a/src/doc/rustc/src/symbol-mangling/v0.md +++ b/src/doc/rustc/src/symbol-mangling/v0.md @@ -1208,7 +1208,7 @@ The compiler has some latitude in how an entity is encoded as long as the symbol * Named functions, methods, and statics shall be represented by a *[path]* production. -* Paths should be rooted at the inner-most entity that can act as a path root. +* Paths should be rooted at the innermost entity that can act as a path root. Roots can be crate-ids, inherent impls, trait impls, and (for items within default methods) trait definitions. * The compiler is free to choose disambiguation indices and namespace tags from diff --git a/src/doc/unstable-book/src/compiler-flags/regparm.md b/src/doc/unstable-book/src/compiler-flags/regparm.md new file mode 100644 index 00000000000..8f311f091c0 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/regparm.md @@ -0,0 +1,20 @@ +# `regparm` + +The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/131749. + +------------------------ + +Option -Zregparm=N causes the compiler to pass N arguments +in registers EAX, EDX, and ECX instead of on the stack for "C", "cdecl", and "stdcall" fn. +It is UNSOUND to link together crates that use different values for this flag. +It is only supported on `x86`. + +It is equivalent to [Clang]'s and [GCC]'s `-mregparm`. + +Supported values for this option are 0-3. + +[Clang]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mregparm +[GCC]: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-regparm-function-attribute_002c-x86 + +Implementation details: +For eligible arguments, llvm `inreg` attribute is set. diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index 24940f0d6fb..4679acf0a6a 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -690,7 +690,6 @@ LeakSanitizer is run-time memory leak detector. LeakSanitizer is supported on the following targets: -* `aarch64-apple-darwin` * `aarch64-unknown-linux-gnu` * `x86_64-apple-darwin` * `x86_64-unknown-linux-gnu` diff --git a/src/etc/cat-and-grep.sh b/src/etc/cat-and-grep.sh index 238f7f5b660..68c6993ac15 100755 --- a/src/etc/cat-and-grep.sh +++ b/src/etc/cat-and-grep.sh @@ -33,7 +33,6 @@ while getopts ':vieh' OPTION; do case "$OPTION" in v) INVERT=1 - ERROR_MSG='should not be found' ;; i) GREPFLAGS="i$GREPFLAGS" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 42df0b28381..57b6de67ee8 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -2,6 +2,7 @@ name = "rustdoc" version = "0.0.0" edition = "2021" +build = "build.rs" [lib] path = "lib.rs" @@ -24,13 +25,15 @@ tracing = "0.1" tracing-tree = "0.3.0" threadpool = "1.8.1" unicode-segmentation = "1.9" -sha2 = "0.10.8" [dependencies.tracing-subscriber] version = "0.3.3" default-features = false features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] +[build-dependencies] +sha2 = "0.10.8" + [dev-dependencies] expect-test = "1.4.0" diff --git a/src/librustdoc/build.rs b/src/librustdoc/build.rs new file mode 100644 index 00000000000..69337fb1d25 --- /dev/null +++ b/src/librustdoc/build.rs @@ -0,0 +1,48 @@ +fn main() { + // generate sha256 files + // this avoids having to perform hashing at runtime + let files = &[ + "static/css/rustdoc.css", + "static/css/noscript.css", + "static/css/normalize.css", + "static/js/main.js", + "static/js/search.js", + "static/js/settings.js", + "static/js/src-script.js", + "static/js/storage.js", + "static/js/scrape-examples.js", + "static/COPYRIGHT.txt", + "static/LICENSE-APACHE.txt", + "static/LICENSE-MIT.txt", + "static/images/rust-logo.svg", + "static/images/favicon.svg", + "static/images/favicon-32x32.png", + "static/fonts/FiraSans-Regular.woff2", + "static/fonts/FiraSans-Medium.woff2", + "static/fonts/FiraSans-LICENSE.txt", + "static/fonts/SourceSerif4-Regular.ttf.woff2", + "static/fonts/SourceSerif4-Bold.ttf.woff2", + "static/fonts/SourceSerif4-It.ttf.woff2", + "static/fonts/SourceSerif4-LICENSE.md", + "static/fonts/SourceCodePro-Regular.ttf.woff2", + "static/fonts/SourceCodePro-Semibold.ttf.woff2", + "static/fonts/SourceCodePro-It.ttf.woff2", + "static/fonts/SourceCodePro-LICENSE.txt", + "static/fonts/NanumBarunGothic.ttf.woff2", + "static/fonts/NanumBarunGothic-LICENSE.txt", + ]; + let out_dir = std::env::var("OUT_DIR").expect("standard Cargo environment variable"); + for path in files { + let inpath = format!("html/{path}"); + println!("cargo::rerun-if-changed={inpath}"); + let bytes = std::fs::read(inpath).expect("static path exists"); + use sha2::Digest; + let bytes = sha2::Sha256::digest(bytes); + let mut digest = format!("-{bytes:x}"); + digest.truncate(9); + let outpath = std::path::PathBuf::from(format!("{out_dir}/{path}.sha256")); + std::fs::create_dir_all(outpath.parent().expect("all file paths are in a directory")) + .expect("should be able to write to out_dir"); + std::fs::write(&outpath, digest.as_bytes()).expect("write to out_dir"); + } +} diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index d966f993104..31e4e79c00a 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -156,7 +156,7 @@ fn clean_param_env<'tcx>( .iter() .inspect(|param| { if cfg!(debug_assertions) { - debug_assert!(!param.is_anonymous_lifetime() && !param.is_host_effect()); + debug_assert!(!param.is_anonymous_lifetime()); if let ty::GenericParamDefKind::Type { synthetic, .. } = param.kind { debug_assert!(!synthetic && param.name != kw::SelfUpper); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e7f921eef7f..97529e420e3 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -248,9 +248,7 @@ pub(crate) fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemT // Check to see if it is a macro 2.0 or built-in macro if matches!( CStore::from_tcx(cx.tcx).load_macro_untracked(did, cx.tcx), - LoadedMacro::MacroDef(def, _) - if matches!(&def.kind, ast::ItemKind::MacroDef(ast_def) - if !ast_def.macro_rules) + LoadedMacro::MacroDef { def, .. } if !def.macro_rules ) { once(crate_name).chain(relative).collect() } else { @@ -747,24 +745,12 @@ fn build_macro( is_doc_hidden: bool, ) -> clean::ItemKind { match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) { - LoadedMacro::MacroDef(item_def, _) => match macro_kind { + LoadedMacro::MacroDef { def, .. } => match macro_kind { MacroKind::Bang => { - if let ast::ItemKind::MacroDef(ref def) = item_def.kind { - let vis = - cx.tcx.visibility(import_def_id.map(|d| d.to_def_id()).unwrap_or(def_id)); - clean::MacroItem(clean::Macro { - source: utils::display_macro_source( - cx, - name, - def, - def_id, - vis, - is_doc_hidden, - ), - }) - } else { - unreachable!() - } + let vis = cx.tcx.visibility(import_def_id.map(|d| d.to_def_id()).unwrap_or(def_id)); + clean::MacroItem(clean::Macro { + source: utils::display_macro_source(cx, name, &def, def_id, vis, is_doc_hidden), + }) } MacroKind::Derive | MacroKind::Attr => { clean::ProcMacroItem(clean::ProcMacro { kind: macro_kind, helpers: Vec::new() }) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7d4d8d8941d..ea349f878e0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -216,7 +216,7 @@ fn clean_generic_bound<'tcx>( hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)), hir::GenericBound::Trait(ref t) => { // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op. - if t.modifiers == hir::TraitBoundModifier::MaybeConst + if let hir::BoundConstness::Maybe(_) = t.modifiers.constness && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap()) { return None; @@ -263,7 +263,7 @@ fn clean_poly_trait_ref_with_constraints<'tcx>( trait_: clean_trait_ref_with_constraints(cx, poly_trait_ref, constraints), generic_params: clean_bound_vars(poly_trait_ref.bound_vars()), }, - hir::TraitBoundModifier::None, + hir::TraitBoundModifiers::NONE, ) } @@ -368,7 +368,9 @@ pub(crate) fn clean_predicate<'tcx>( // FIXME(generic_const_exprs): should this do something? ty::ClauseKind::ConstEvaluatable(..) | ty::ClauseKind::WellFormed(..) - | ty::ClauseKind::ConstArgHasType(..) => None, + | ty::ClauseKind::ConstArgHasType(..) + // FIXME(effects): We can probably use this `HostEffect` pred to render `~const`. + | ty::ClauseKind::HostEffect(_) => None, } } @@ -542,7 +544,7 @@ fn clean_generic_param_def( synthetic, }) } - ty::GenericParamDefKind::Const { has_default, synthetic, is_host_effect: _ } => { + ty::GenericParamDefKind::Const { has_default, synthetic } => { (def.name, GenericParamDefKind::Const { ty: Box::new(clean_middle_ty( ty::Binder::dummy( @@ -617,7 +619,7 @@ fn clean_generic_param<'tcx>( synthetic, }) } - hir::GenericParamKind::Const { ty, default, synthetic, is_host_effect: _ } => { + hir::GenericParamKind::Const { ty, default, synthetic } => { (param.name.ident().name, GenericParamDefKind::Const { ty: Box::new(clean_ty(ty, cx)), default: default.map(|ct| { @@ -797,7 +799,7 @@ fn clean_ty_generics<'tcx>( } true } - ty::GenericParamDefKind::Const { is_host_effect, .. } => !is_host_effect, + ty::GenericParamDefKind::Const { .. } => true, }) .map(|param| clean_generic_param_def(param, ParamDefaults::Yes, cx)) .collect(); @@ -1398,7 +1400,6 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo clean_ty_generics(cx, tcx.generics_of(assoc_item.def_id), ty::GenericPredicates { parent: None, predicates, - effects_min_tys: ty::List::empty(), }); simplify::move_bounds_to_generic_parameters(&mut generics); @@ -2189,7 +2190,7 @@ pub(crate) fn clean_middle_ty<'tcx>( } ty::Alias(ty::Weak, data) => { - if cx.tcx.features().lazy_type_alias { + if cx.tcx.features().lazy_type_alias() { // Weak type alias `data` represents the `type X` in `type X = Y`. If we need `Y`, // we need to use `type_of`. let path = clean_middle_path( diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 675507a44c9..c62144be3da 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -8,7 +8,6 @@ use arrayvec::ArrayVec; use rustc_ast::MetaItemInner; use rustc_ast_pretty::pprust; use rustc_attr::{ConstStability, Deprecation, Stability, StableSince}; -use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; @@ -641,12 +640,11 @@ impl Item { asyncness: ty::Asyncness, ) -> hir::FnHeader { let sig = tcx.fn_sig(def_id).skip_binder(); - let constness = - if tcx.is_const_fn(def_id) || is_unstable_const_fn(tcx, def_id).is_some() { - hir::Constness::Const - } else { - hir::Constness::NotConst - }; + let constness = if tcx.is_const_fn(def_id) { + hir::Constness::Const + } else { + hir::Constness::NotConst + }; let asyncness = match asyncness { ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP), ty::Asyncness::No => hir::IsAsync::NotAsync, @@ -664,9 +662,7 @@ impl Item { safety }, abi, - constness: if tcx.is_const_fn(def_id) - || is_unstable_const_fn(tcx, def_id).is_some() - { + constness: if tcx.is_const_fn(def_id) { hir::Constness::Const } else { hir::Constness::NotConst @@ -966,8 +962,8 @@ pub(crate) trait AttributesExt { fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet) -> Option> { let sess = tcx.sess; - let doc_cfg_active = tcx.features().doc_cfg; - let doc_auto_cfg_active = tcx.features().doc_auto_cfg; + let doc_cfg_active = tcx.features().doc_cfg(); + let doc_auto_cfg_active = tcx.features().doc_auto_cfg(); fn single(it: T) -> Option { let mut iter = it.into_iter(); @@ -1257,7 +1253,7 @@ impl Eq for Attributes {} #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) enum GenericBound { - TraitBound(PolyTrait, hir::TraitBoundModifier), + TraitBound(PolyTrait, hir::TraitBoundModifiers), Outlives(Lifetime), /// `use<'a, T>` precise-capturing bound syntax Use(Vec), @@ -1265,19 +1261,22 @@ pub(crate) enum GenericBound { impl GenericBound { pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound { - Self::sized_with(cx, hir::TraitBoundModifier::None) + Self::sized_with(cx, hir::TraitBoundModifiers::NONE) } pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound { - Self::sized_with(cx, hir::TraitBoundModifier::Maybe) + Self::sized_with(cx, hir::TraitBoundModifiers { + polarity: hir::BoundPolarity::Maybe(DUMMY_SP), + constness: hir::BoundConstness::Never, + }) } - fn sized_with(cx: &mut DocContext<'_>, modifier: hir::TraitBoundModifier) -> GenericBound { + fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound { let did = cx.tcx.require_lang_item(LangItem::Sized, None); let empty = ty::Binder::dummy(ty::GenericArgs::empty()); let path = clean_middle_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); - GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifier) + GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers) } pub(crate) fn is_trait_bound(&self) -> bool { @@ -1285,8 +1284,10 @@ impl GenericBound { } pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool { - use rustc_hir::TraitBoundModifier as TBM; - if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self + if let GenericBound::TraitBound( + PolyTrait { ref trait_, .. }, + rustc_hir::TraitBoundModifiers::NONE, + ) = *self && Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait() { return true; @@ -1361,8 +1362,7 @@ impl GenericParamDef { pub(crate) fn is_synthetic_param(&self) -> bool { match self.kind { - GenericParamDefKind::Lifetime { .. } => false, - GenericParamDefKind::Const { synthetic: is_host_effect, .. } => is_host_effect, + GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false, GenericParamDefKind::Type { synthetic, .. } => synthetic, } } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index fdf628b50fb..d3a545fe0b6 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -114,10 +114,6 @@ pub(crate) fn clean_middle_generic_args<'tcx>( // Elide internal host effect args. let param = generics.param_at(index, cx.tcx); - if param.is_host_effect() { - return None; - } - let arg = ty::Binder::bind_with_vars(arg, bound_vars); // Elide arguments that coincide with their default. diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 9bebe1fb4c1..0f7d4d3e8f3 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -8,7 +8,7 @@ use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::emitter::{DynEmitter, HumanEmitter, stderr_destination}; use rustc_errors::json::JsonEmitter; -use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, TerminalUrl}; +use rustc_errors::{ErrorGuaranteed, TerminalUrl}; use rustc_feature::UnstableFeatures; use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId}; @@ -21,8 +21,8 @@ use rustc_middle::ty::{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}; +use rustc_span::source_map; use rustc_span::symbol::sym; -use rustc_span::{Span, source_map}; use tracing::{debug, info}; use crate::clean::inline::build_external_trait; @@ -381,45 +381,10 @@ pub(crate) fn run_global_ctxt( ); } - fn report_deprecated_attr(name: &str, dcx: DiagCtxtHandle<'_>, sp: Span) { - let mut msg = - dcx.struct_span_warn(sp, format!("the `#![doc({name})]` attribute is deprecated")); - msg.note( - "see issue #44136 \ - for more information", - ); - - if name == "no_default_passes" { - msg.help("`#![doc(no_default_passes)]` no longer functions; you may want to use `#![doc(document_private_items)]`"); - } else if name.starts_with("passes") { - msg.help("`#![doc(passes = \"...\")]` no longer functions; you may want to use `#![doc(document_private_items)]`"); - } else if name.starts_with("plugins") { - msg.warn("`#![doc(plugins = \"...\")]` no longer functions; see CVE-2018-1000622 "); - } - - msg.emit(); - } - // Process all of the crate attributes, extracting plugin metadata along // with the passes which we are supposed to run. for attr in krate.module.attrs.lists(sym::doc) { - let dcx = ctxt.sess().dcx(); - let name = attr.name_or_empty(); - // `plugins = "..."`, `no_default_passes`, and `passes = "..."` have no effect - if attr.is_word() && name == sym::no_default_passes { - report_deprecated_attr("no_default_passes", dcx, attr.span()); - } else if attr.value_str().is_some() { - match name { - sym::passes => { - report_deprecated_attr("passes = \"...\"", dcx, attr.span()); - } - sym::plugins => { - report_deprecated_attr("plugins = \"...\"", dcx, attr.span()); - } - _ => (), - } - } if attr.is_word() && name == sym::document_private_items { ctxt.render_options.document_private = true; diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index efbb332d12d..3ae60938749 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -289,7 +289,12 @@ fn parse_source( // Recurse through functions body. It is necessary because the doctest source code is // wrapped in a function to limit the number of AST errors. If we don't recurse into // functions, we would thing all top-level items (so basically nothing). - fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option<&str>) { + fn check_item( + item: &ast::Item, + info: &mut ParseSourceInfo, + crate_name: &Option<&str>, + is_top_level: bool, + ) { if !info.has_global_allocator && item.attrs.iter().any(|attr| attr.name_or_empty() == sym::global_allocator) { @@ -297,13 +302,15 @@ fn parse_source( } match item.kind { ast::ItemKind::Fn(ref fn_item) if !info.has_main_fn => { - if item.ident.name == sym::main { + if item.ident.name == sym::main && is_top_level { info.has_main_fn = true; } if let Some(ref body) = fn_item.body { for stmt in &body.stmts { match stmt.kind { - ast::StmtKind::Item(ref item) => check_item(item, info, crate_name), + ast::StmtKind::Item(ref item) => { + check_item(item, info, crate_name, false) + } ast::StmtKind::MacCall(..) => info.found_macro = true, _ => {} } @@ -329,7 +336,7 @@ fn parse_source( loop { match parser.parse_item(ForceCollect::No) { Ok(Some(item)) => { - check_item(&item, info, crate_name); + check_item(&item, info, crate_name, true); if info.has_main_fn && info.found_extern_crate { break; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 2e70a8c080d..8e8e5c6ade8 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -16,6 +16,7 @@ use itertools::Itertools; use rustc_attr::{ConstStability, StabilityLevel, StableSince}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_metadata::creader::{CStore, LoadedMacro}; @@ -25,7 +26,6 @@ use rustc_span::symbol::kw; use rustc_span::{Symbol, sym}; use rustc_target::spec::abi::Abi; use tracing::{debug, trace}; -use {rustc_ast as ast, rustc_hir as hir}; use super::url_parts_builder::{UrlPartsBuilder, estimate_item_path_byte_length}; use crate::clean::types::ExternalLocation; @@ -399,13 +399,13 @@ impl clean::GenericBound { ) -> impl Display + 'a + Captures<'tcx> { display_fn(move |f| match self { clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()), - clean::GenericBound::TraitBound(ty, modifier) => { - f.write_str(match modifier { - hir::TraitBoundModifier::None => "", - hir::TraitBoundModifier::Maybe => "?", - hir::TraitBoundModifier::Negative => "!", - // `const` and `~const` trait bounds are experimental; don't render them. - hir::TraitBoundModifier::Const | hir::TraitBoundModifier::MaybeConst => "", + clean::GenericBound::TraitBound(ty, modifiers) => { + // `const` and `~const` trait bounds are experimental; don't render them. + let hir::TraitBoundModifiers { polarity, constness: _ } = modifiers; + f.write_str(match polarity { + hir::BoundPolarity::Positive => "", + hir::BoundPolarity::Maybe(_) => "?", + hir::BoundPolarity::Negative(_) => "!", })?; ty.print(cx).fmt(f) } @@ -554,10 +554,8 @@ fn generate_macro_def_id_path( // Check to see if it is a macro 2.0 or built-in macro. // More information in . let is_macro_2 = match cstore.load_macro_untracked(def_id, tcx) { - LoadedMacro::MacroDef(def, _) => { - // If `ast_def.macro_rules` is `true`, then it's not a macro 2.0. - matches!(&def.kind, ast::ItemKind::MacroDef(ast_def) if !ast_def.macro_rules) - } + // If `def.macro_rules` is `true`, then it's not a macro 2.0. + LoadedMacro::MacroDef { def, .. } => !def.macro_rules, _ => false, }; @@ -1368,6 +1366,24 @@ impl clean::Impl { write!(f, " -> ")?; fmt_type(&bare_fn.decl.output, f, use_absolute, cx)?; } + } else if let clean::Type::Path { path } = type_ + && let Some(generics) = path.generics() + && generics.len() == 1 + && self.kind.is_fake_variadic() + { + let ty = generics[0]; + let wrapper = anchor(path.def_id(), path.last(), cx); + if f.alternate() { + write!(f, "{wrapper:#}<")?; + } else { + write!(f, "{wrapper}<")?; + } + self.print_type(ty, f, use_absolute, cx)?; + if f.alternate() { + write!(f, ">")?; + } else { + write!(f, ">")?; + } } else { fmt_type(&type_, f, use_absolute, cx)?; } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 399730a01c8..8446235fb18 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1010,7 +1010,9 @@ fn render_stability_since_raw_with_extra( // don't display const unstable if entirely unstable None } else { - let unstable = if let Some(n) = issue { + let unstable = if let Some(n) = issue + && let Some(feature) = feature + { format!( ", item: &clean::Item, render ); if let Some(link) = src_href { if has_stability { - write!(rightside, " · source") + write!(rightside, " · Source") } else { - write!(rightside, "source") + write!(rightside, "Source") } } if has_stability && has_src_ref { diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index c958458b662..d1939adc1a5 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -759,7 +759,10 @@ pub(crate) fn get_function_type_for_search<'tcx>( } }); let (mut inputs, mut output, where_clause) = match item.kind { - clean::FunctionItem(ref f) | clean::MethodItem(ref f, _) | clean::TyMethodItem(ref f) => { + clean::ForeignFunctionItem(ref f, _) + | clean::FunctionItem(ref f) + | clean::MethodItem(ref f, _) + | clean::TyMethodItem(ref f) => { get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache) } _ => return None, diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 12b63460056..c82f7e9aaf9 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -112,7 +112,7 @@ pub(crate) fn write_shared( md_opts.output = cx.dst.clone(); md_opts.external_html = cx.shared.layout.external_html.clone(); try_err!( - crate::markdown::render(&index_page, md_opts, cx.shared.edition()), + crate::markdown::render_and_write(&index_page, md_opts, cx.shared.edition()), &index_page ); } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 2c17fd54006..97e8b8f5b5f 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -185,7 +185,7 @@ h1, h2, h3, h4 { grid-template-columns: minmax(105px, 1fr) minmax(0, max-content); grid-template-rows: minmax(25px, min-content) min-content min-content; padding-bottom: 6px; - margin-bottom: 11px; + margin-bottom: 15px; } .rustdoc-breadcrumbs { grid-area: main-heading-breadcrumbs; @@ -959,7 +959,7 @@ pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers { background: var(--table-alt-row-background-color); } -.docblock .stab, .docblock-short .stab { +.docblock .stab, .docblock-short .stab, .docblock p code { display: inline-block; } @@ -1004,6 +1004,7 @@ nav.sub { display: flex; height: 34px; flex-grow: 1; + margin-bottom: 4px; } .src nav.sub { margin: 0 0 -10px 0; @@ -2253,7 +2254,12 @@ in src-script.js and main.js /* We don't display this button on mobile devices. */ #copy-path { - display: none; + /* display: none; avoided as a layout hack. + When there's one line, we get an effective line-height of 34px, + because that's how big the image is, but if the header wraps, + they're packed more tightly than that. */ + width: 0; + visibility: hidden; } /* Text label takes up too much space at this size. */ diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index 9e0803f5d3f..a4dc8cd1ed9 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -12,8 +12,8 @@ pub(crate) struct StaticFile { } impl StaticFile { - fn new(filename: &str, bytes: &'static [u8]) -> StaticFile { - Self { filename: static_filename(filename, bytes), bytes } + fn new(filename: &str, bytes: &'static [u8], sha256: &'static str) -> StaticFile { + Self { filename: static_filename(filename, sha256), bytes } } pub(crate) fn minified(&self) -> Vec { @@ -55,17 +55,9 @@ pub(crate) fn suffix_path(filename: &str, suffix: &str) -> PathBuf { filename.into() } -pub(crate) fn static_filename(filename: &str, contents: &[u8]) -> PathBuf { +pub(crate) fn static_filename(filename: &str, sha256: &str) -> PathBuf { let filename = filename.rsplit('/').next().unwrap(); - suffix_path(filename, &static_suffix(contents)) -} - -fn static_suffix(bytes: &[u8]) -> String { - use sha2::Digest; - let bytes = sha2::Sha256::digest(bytes); - let mut digest = format!("-{bytes:x}"); - digest.truncate(9); - digest + suffix_path(filename, &sha256) } macro_rules! static_files { @@ -74,8 +66,9 @@ macro_rules! static_files { $(pub $field: StaticFile,)+ } + // sha256 files are generated in build.rs pub(crate) static STATIC_FILES: std::sync::LazyLock = std::sync::LazyLock::new(|| StaticFiles { - $($field: StaticFile::new($file_path, include_bytes!($file_path)),)+ + $($field: StaticFile::new($file_path, include_bytes!($file_path), include_str!(concat!(env!("OUT_DIR"), "/", $file_path, ".sha256"))),)+ }); pub(crate) fn for_each(f: impl Fn(&StaticFile) -> Result<(), E>) -> Result<(), E> { diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html index f60720b67c6..9fd575b2751 100644 --- a/src/librustdoc/html/templates/print_item.html +++ b/src/librustdoc/html/templates/print_item.html @@ -26,7 +26,7 @@ {% match src_href %} {% when Some with (href) %} {% if !stability_since_raw.is_empty() +%} · {%+ endif %} - source {#+ #} + Source {#+ #} {% else %} {% endmatch %} {# #} diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 0130f2ce517..7270f170780 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -552,20 +552,18 @@ impl FromClean for GenericBound { } pub(crate) fn from_trait_bound_modifier( - modifier: rustc_hir::TraitBoundModifier, + modifiers: rustc_hir::TraitBoundModifiers, ) -> TraitBoundModifier { - use rustc_hir::TraitBoundModifier::*; - match modifier { - None => TraitBoundModifier::None, - Maybe => TraitBoundModifier::Maybe, - MaybeConst => TraitBoundModifier::MaybeConst, - // FIXME(const_trait_impl): Create rjt::TBM::Const and map to it once always-const bounds - // are less experimental. - Const => TraitBoundModifier::None, - // FIXME(negative-bounds): This bound should be rendered negative, but - // since that's experimental, maybe let's not add it to the rustdoc json - // API just now... - Negative => TraitBoundModifier::None, + use rustc_hir as hir; + let hir::TraitBoundModifiers { constness, polarity } = modifiers; + match (constness, polarity) { + (hir::BoundConstness::Never, hir::BoundPolarity::Positive) => TraitBoundModifier::None, + (hir::BoundConstness::Never, hir::BoundPolarity::Maybe(_)) => TraitBoundModifier::Maybe, + (hir::BoundConstness::Maybe(_), hir::BoundPolarity::Positive) => { + TraitBoundModifier::MaybeConst + } + // FIXME: Fill out the rest of this matrix. + _ => TraitBoundModifier::None, } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 10fc0ea9990..7c9dcd41e6a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -37,7 +37,6 @@ extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; -extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; @@ -817,7 +816,7 @@ fn main_args( return wrap_return( dcx, interface::run_compiler(config, |_compiler| { - markdown::render(&md_input, render_options, edition) + markdown::render_and_write(&md_input, render_options, edition) }), ); } diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index bdfdeeabc5a..2afb9e549d9 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -31,9 +31,9 @@ where allowed_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); let lints = || { - lint::builtin::HardwiredLints::get_lints() + lint::builtin::HardwiredLints::lint_vec() .into_iter() - .chain(rustc_lint::SoftLints::get_lints()) + .chain(rustc_lint::SoftLints::lint_vec()) }; let lint_opts = lints() diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 978f96f38be..76eac084907 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -1,3 +1,13 @@ +//! Standalone markdown rendering. +//! +//! For the (much more common) case of rendering markdown in doc-comments, see +//! [crate::html::markdown]. +//! +//! This is used when [rendering a markdown file to an html file][docs], without processing +//! rust source code. +//! +//! [docs]: https://doc.rust-lang.org/stable/rustdoc/#using-standalone-markdown-files + use std::fmt::Write as _; use std::fs::{File, create_dir_all, read_to_string}; use std::io::prelude::*; @@ -33,7 +43,7 @@ fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) { /// (e.g., output = "bar" => "bar/foo.html"). /// /// Requires session globals to be available, for symbol interning. -pub(crate) fn render>( +pub(crate) fn render_and_write>( input: P, options: RenderOptions, edition: Edition, diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index f4579d85531..484bdb5627c 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -116,7 +116,7 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item find_testable_code(dox, &mut tests, ErrorCodes::No, false, None); - if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples { + if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples() { if should_have_doc_example(cx, item) { debug!("reporting error for {item:?} (hir_id={hir_id:?})"); let sp = item.attr_span(cx.tcx); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 2f0ea8d618c..140fda70918 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1419,7 +1419,7 @@ impl LinkCollector<'_, '_> { && key.path_str.contains("::") // We only want to check this if this is an associated item. { - if key.item_id.is_local() && !self.cx.tcx.features().intra_doc_pointers { + if key.item_id.is_local() && !self.cx.tcx.features().intra_doc_pointers() { self.report_rawptr_assoc_feature_gate(diag.dox, &diag.link_range, diag.item); return None; } else { diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 62e1695cbe3..925cbfe09a4 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -161,6 +161,7 @@ static TARGETS: &[&str] = &[ "wasm32-wasip1", "wasm32-wasip1-threads", "wasm32-wasip2", + "wasm32v1-none", "x86_64-apple-darwin", "x86_64-apple-ios", "x86_64-apple-ios-macabi", diff --git a/src/tools/cargo b/src/tools/cargo index cf53cc54bb5..e75214ea493 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit cf53cc54bb593b5ec3dc2be4b1702f50c36d24d5 +Subproject commit e75214ea4936d2f2c909a71a1237042cc0e14b07 diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index 495d8ce3fa7..477435236a5 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -31,6 +31,7 @@ declare_clippy_lint! { pub COGNITIVE_COMPLEXITY, nursery, "functions that should be split up into multiple functions" + @eval_always = true } pub struct CognitiveComplexity { diff --git a/src/tools/clippy/clippy_lints/src/ctfe.rs b/src/tools/clippy/clippy_lints/src/ctfe.rs new file mode 100644 index 00000000000..2fe37a64db6 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/ctfe.rs @@ -0,0 +1,40 @@ +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, FnDecl}; +use rustc_lint::Level::Deny; +use rustc_lint::{LateContext, LateLintPass, Lint}; +use rustc_session::declare_lint_pass; +use rustc_span::Span; + +/// Ensures that Constant-time Function Evaluation is being done (specifically, MIR lint passes). +/// As Clippy deactivates codegen, this lint ensures that CTFE (used in hard errors) is still ran. +pub static CLIPPY_CTFE: &Lint = &Lint { + name: &"clippy::CLIPPY_CTFE", + default_level: Deny, + desc: "Ensure CTFE is being made", + edition_lint_opts: None, + report_in_external_macro: true, + future_incompatible: None, + is_externally_loaded: true, + crate_level_only: false, + eval_always: true, + ..Lint::default_fields_for_macro() +}; + +// No static CLIPPY_CTFE_INFO because we want this lint to be invisible + +declare_lint_pass! { ClippyCtfe => [CLIPPY_CTFE] } + +impl<'tcx> LateLintPass<'tcx> for ClippyCtfe { + fn check_fn( + &mut self, + cx: &LateContext<'_>, + _: FnKind<'tcx>, + _: &'tcx FnDecl<'tcx>, + _: &'tcx Body<'tcx>, + _: Span, + defid: LocalDefId, + ) { + cx.tcx.ensure().mir_drops_elaborated_and_const_checked(defid); // Lint + } +} diff --git a/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs b/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs index b1e39c70baa..a785a9d377c 100644 --- a/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs +++ b/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs @@ -9,6 +9,7 @@ macro_rules! declare_clippy_lint { $desc:literal, $version_expr:expr, $version_lit:literal + $(, $eval_always: literal)? ) => { rustc_session::declare_tool_lint! { $(#[doc = $lit])* @@ -17,6 +18,7 @@ macro_rules! declare_clippy_lint { $category, $desc, report_in_external_macro:true + $(, @eval_always = $eval_always)? } pub(crate) static ${concat($lint_name, _INFO)}: &'static crate::LintInfo = &crate::LintInfo { @@ -33,11 +35,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, restriction, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Allow, crate::LintCategory::Restriction, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; ( @@ -46,12 +49,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, style, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Warn, crate::LintCategory::Style, $desc, - Some($version), $version - + Some($version), $version $(, $eval_always)? } }; ( @@ -60,11 +63,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, correctness, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Deny, crate::LintCategory::Correctness, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; @@ -74,11 +78,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, perf, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Warn, crate::LintCategory::Perf, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; ( @@ -87,11 +92,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, complexity, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Warn, crate::LintCategory::Complexity, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; ( @@ -100,11 +106,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, suspicious, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Warn, crate::LintCategory::Suspicious, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; ( @@ -113,11 +120,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, nursery, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Allow, crate::LintCategory::Nursery, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; ( @@ -126,11 +134,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, pedantic, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Allow, crate::LintCategory::Pedantic, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; ( @@ -139,11 +148,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, cargo, $desc:literal + $(@eval_always = $eval_always: literal)? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Allow, crate::LintCategory::Cargo, $desc, - Some($version), $version + Some($version), $version $(, $eval_always)? } }; diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs index 0066ed64325..77dbe9b78a1 100644 --- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs +++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs @@ -166,7 +166,7 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[ #[clippy::version = ""] ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"), #[clippy::version = ""] - ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"), + ("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"), #[clippy::version = ""] ("clippy::undropped_manually_drops", "undropped_manually_drops"), #[clippy::version = ""] diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 82a66cc9202..e8e21edd494 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -324,7 +324,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h // If the current self type doesn't implement Copy (due to generic constraints), search to see if // there's a Copy impl for any instance of the adt. if !is_copy(cx, ty) { - if ty_subs.non_erasable_generics(cx.tcx, ty_adt.did()).next().is_some() { + if ty_subs.non_erasable_generics().next().is_some() { let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).map_or(false, |impls| { impls.iter().any(|&id| { matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _) diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs index 70eb81fa09c..b0389fd9a2f 100644 --- a/src/tools/clippy/clippy_lints/src/empty_enum.rs +++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs @@ -64,7 +64,7 @@ impl LateLintPass<'_> for EmptyEnum { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if let ItemKind::Enum(..) = item.kind // Only suggest the `never_type` if the feature is enabled - && cx.tcx.features().never_type + && cx.tcx.features().never_type() && let Some(adt) = cx.tcx.type_of(item.owner_id).instantiate_identity().ty_adt_def() && adt.variants().is_empty() { diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index 00f83237224..65fdc93e0ed 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::def_id::DefId; use rustc_hir::{ - AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifier, TyKind, + AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifiers, TyKind, WherePredicate, }; use rustc_hir_analysis::lower_ty; @@ -234,7 +234,7 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds .iter() .filter_map(|bound| { if let GenericBound::Trait(poly_trait) = bound - && let TraitBoundModifier::None = poly_trait.modifiers + && let TraitBoundModifiers::NONE = poly_trait.modifiers && let [.., path] = poly_trait.trait_ref.path.segments && poly_trait.bound_generic_params.is_empty() && let Some(trait_def_id) = path.res.opt_def_id() @@ -300,7 +300,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) { // simply comparing trait `DefId`s won't be enough. We also need to compare the generics. for (index, bound) in bounds.iter().enumerate() { if let GenericBound::Trait(poly_trait) = bound - && let TraitBoundModifier::None = poly_trait.modifiers + && let TraitBoundModifiers::NONE = poly_trait.modifiers && let [.., path] = poly_trait.trait_ref.path.segments && let implied_args = path.args.map_or([].as_slice(), |a| a.args) && let implied_constraints = path.args.map_or([].as_slice(), |a| a.constraints) diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 6e29dde2211..14110539709 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -65,6 +65,7 @@ extern crate clippy_utils; #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))] mod utils; +pub mod ctfe; // Very important lint, do not remove (rust#125116) pub mod declared_lints; pub mod deprecated_lints; @@ -605,6 +606,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { }); } + store.register_late_pass(|_| Box::new(ctfe::ClippyCtfe)); + store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf))); store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir)); store.register_late_pass(|_| Box::new(utils::author::Author)); diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs index 00e02e2a336..4c171e6d890 100644 --- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs +++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs @@ -111,11 +111,7 @@ fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr); match expr_ty.peel_refs().kind() { ty::Uint(_) => true, - ty::Int(_) => cx - .tcx - .features() - .declared_features - .contains(&Symbol::intern("int_roundings")), + ty::Int(_) => cx.tcx.features().enabled(Symbol::intern("int_roundings")), _ => false, } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index f9ffbc5dc0b..20984bc40ca 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -114,7 +114,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect(); for (&(i, arm1), &(j, arm2)) in search_same(&indexed_arms, hash, eq) { if matches!(arm2.pat.kind, PatKind::Wild) { - if !cx.tcx.features().non_exhaustive_omitted_patterns_lint + if !cx.tcx.features().non_exhaustive_omitted_patterns_lint() || is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id) { let arm_span = adjusted_arm_span(cx, arm1.span); diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs index 564c598a334..42d9efe4ff6 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs @@ -251,7 +251,7 @@ fn emit_redundant_guards<'tcx>( fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { for_each_expr_without_closures(expr, |expr| { if match expr.kind { - ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat, + ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat(), ExprKind::Call(c, ..) if let ExprKind::Path(qpath) = c.kind => { // Allow ctors matches!(cx.qpath_res(&qpath, c.hir_id), Res::Def(DefKind::Ctor(..), ..)) diff --git a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs index 68c9af07465..9a1c397b5b2 100644 --- a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs +++ b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::def_id::{DefId, DefIdMap}; -use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifier, WherePredicate}; +use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifiers, BoundPolarity, WherePredicate}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{ClauseKind, PredicatePolarity}; use rustc_session::declare_lint_pass; @@ -118,13 +118,13 @@ impl LateLintPass<'_> for NeedlessMaybeSized { let maybe_sized_params: DefIdMap<_> = type_param_bounds(generics) .filter(|bound| { bound.trait_bound.trait_ref.trait_def_id() == Some(sized_trait) - && bound.trait_bound.modifiers == TraitBoundModifier::Maybe + && matches!(bound.trait_bound.modifiers.polarity, BoundPolarity::Maybe(_)) }) .map(|bound| (bound.param, bound)) .collect(); for bound in type_param_bounds(generics) { - if bound.trait_bound.modifiers == TraitBoundModifier::None + if bound.trait_bound.modifiers == TraitBoundModifiers::NONE && let Some(sized_bound) = maybe_sized_params.get(&bound.param) && let Some(path) = path_to_sized_bound(cx, bound.trait_bound) { diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 7f528b9d17b..3da4bf67558 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -11,7 +11,7 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{ GenericBound, Generics, Item, ItemKind, LangItem, Node, Path, PathSegment, PredicateOrigin, QPath, - TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate, + TraitBoundModifiers, TraitItem, TraitRef, Ty, TyKind, WherePredicate, BoundPolarity, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -233,7 +233,7 @@ impl TraitBounds { fn cannot_combine_maybe_bound(&self, cx: &LateContext<'_>, bound: &GenericBound<'_>) -> bool { if !self.msrv.meets(msrvs::MAYBE_BOUND_IN_WHERE) && let GenericBound::Trait(tr) = bound - && let TraitBoundModifier::Maybe = tr.modifiers + && let BoundPolarity::Maybe(_) = tr.modifiers.polarity { cx.tcx.lang_items().get(LangItem::Sized) == tr.trait_ref.path.res.opt_def_id() } else { @@ -374,12 +374,12 @@ fn check_trait_bound_duplication<'tcx>(cx: &LateContext<'tcx>, generics: &'_ Gen struct ComparableTraitRef<'a, 'tcx> { cx: &'a LateContext<'tcx>, trait_ref: &'tcx TraitRef<'tcx>, - modifier: TraitBoundModifier, + modifiers: TraitBoundModifiers, } impl PartialEq for ComparableTraitRef<'_, '_> { fn eq(&self, other: &Self) -> bool { - self.modifier == other.modifier + SpanlessEq::new(self.cx).eq_modifiers(self.modifiers, other.modifiers) && SpanlessEq::new(self.cx) .paths_by_resolution() .eq_path(self.trait_ref.path, other.trait_ref.path) @@ -390,8 +390,8 @@ impl Hash for ComparableTraitRef<'_, '_> { fn hash(&self, state: &mut H) { let mut s = SpanlessHash::new(self.cx).paths_by_resolution(); s.hash_path(self.trait_ref.path); + s.hash_modifiers(self.modifiers); state.write_u64(s.finish()); - self.modifier.hash(state); } } @@ -400,7 +400,7 @@ fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &' let trait_path = t.trait_ref.path; let trait_span = { let path_span = trait_path.span; - if let TraitBoundModifier::Maybe = t.modifiers { + if let BoundPolarity::Maybe(_) = t.modifiers.polarity { path_span.with_lo(path_span.lo() - BytePos(1)) // include the `?` } else { path_span @@ -427,7 +427,7 @@ fn rollup_traits<'cx, 'tcx>( ComparableTraitRef { cx, trait_ref: &t.trait_ref, - modifier: t.modifiers, + modifiers: t.modifiers, }, t.span, )) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs b/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs index 032cd3ed739..22b2c895f7c 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs @@ -39,7 +39,7 @@ impl From<&Attribute> for IdentIter { struct IdentCollector(Vec); impl Visitor<'_> for IdentCollector { - fn visit_ident(&mut self, ident: Ident) { - self.0.push(ident); + fn visit_ident(&mut self, ident: &Ident) { + self.0.push(*ident); } } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 27c57808ece..181d414cbbd 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -9,7 +9,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ ArrayLen, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, - LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, + LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitBoundModifiers, Ty, + TyKind, }; use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::LateContext; @@ -126,6 +127,11 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub fn eq_path_segments(&mut self, left: &[PathSegment<'_>], right: &[PathSegment<'_>]) -> bool { self.inter_expr().eq_path_segments(left, right) } + + pub fn eq_modifiers(&mut self, left: TraitBoundModifiers, right: TraitBoundModifiers) -> bool { + std::mem::discriminant(&left.constness) == std::mem::discriminant(&right.constness) + && std::mem::discriminant(&left.polarity) == std::mem::discriminant(&right.polarity) + } } pub struct HirEqInterExpr<'a, 'b, 'tcx> { @@ -1143,6 +1149,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } } + pub fn hash_modifiers(&mut self, modifiers: TraitBoundModifiers) { + let TraitBoundModifiers { constness, polarity } = modifiers; + std::mem::discriminant(&polarity).hash(&mut self.s); + std::mem::discriminant(&constness).hash(&mut self.s); + } + pub fn hash_stmt(&mut self, b: &Stmt<'_>) { std::mem::discriminant(&b.kind).hash(&mut self.s); 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 5f12b6bf99e..46739862de6 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 @@ -334,7 +334,7 @@ fn check_terminator<'tcx>( | TerminatorKind::TailCall { func, args, fn_span: _ } => { let fn_ty = func.ty(body, tcx); if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() { - if !is_const_fn(tcx, fn_def_id, msrv) { + if !is_stable_const_fn(tcx, fn_def_id, msrv) { return Err(( span, format!( @@ -377,12 +377,12 @@ fn check_terminator<'tcx>( } } -fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { +fn is_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { tcx.is_const_fn(def_id) - && tcx.lookup_const_stability(def_id).map_or(true, |const_stab| { + && tcx.lookup_const_stability(def_id).is_none_or(|const_stab| { if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level { // Checking MSRV is manually necessary because `rustc` has no such concept. This entire - // function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`. + // function could be removed if `rustc` provided a MSRV-aware version of `is_stable_const_fn`. // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262. let const_stab_rust_version = match since { @@ -393,8 +393,12 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { msrv.meets(const_stab_rust_version) } else { - // Unstable const fn with the feature enabled. - msrv.current().is_none() + // Unstable const fn, check if the feature is enabled. We need both the regular stability + // feature and (if set) the const stability feature to const-call this function. + let stab = tcx.lookup_stability(def_id); + let is_enabled = stab.is_some_and(|s| s.is_stable() || tcx.features().enabled(s.feature)) + && const_stab.feature.is_none_or(|f| tcx.features().enabled(f)); + is_enabled && msrv.current().is_none() } }) } diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs index 91ec120adbf..3021f21df12 100644 --- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs @@ -207,16 +207,7 @@ fn path_segment_certainty( if cx.tcx.res_generics_def_id(path_segment.res).is_some() { let generics = cx.tcx.generics_of(def_id); - let own_count = generics.own_params.len() - - usize::from(generics.host_effect_index.is_some_and(|index| { - // Check that the host index actually belongs to this resolution. - // E.g. for `Add::add`, host_effect_index is `Some(2)`, but it's part of the parent `Add` - // trait's generics. - // Add params: [Self#0, Rhs#1, host#2] parent_count=0, count=3 - // Add::add params: [] parent_count=3, count=3 - // (3..3).contains(&host_effect_index) => false - (generics.parent_count..generics.count()).contains(&index) - })); + let own_count = generics.own_params.len(); let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && own_count == 0 { Certainty::Certain(None) } else { @@ -310,8 +301,7 @@ fn type_is_inferable_from_arguments(cx: &LateContext<'_>, expr: &Expr<'_>) -> bo // Check that all type parameters appear in the functions input types. (0..(generics.parent_count + generics.own_params.len()) as u32).all(|index| { - Some(index as usize) == generics.host_effect_index - || fn_sig + fn_sig .inputs() .iter() .any(|input_ty| contains_param(*input_ty.skip_binder(), index)) diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index 02931306f16..8db6502dbfb 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -346,13 +346,13 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> .cx .qpath_res(p, hir_id) .opt_def_id() - .map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {}, + .map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {}, ExprKind::MethodCall(..) if self .cx .typeck_results() .type_dependent_def_id(e.hir_id) - .map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {}, + .map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {}, ExprKind::Binary(_, lhs, rhs) if self.cx.typeck_results().expr_ty(lhs).peel_refs().is_primitive_ty() && self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {}, diff --git a/src/tools/clippy/tests/ui/author.rs b/src/tools/clippy/tests/ui-internal/author.rs similarity index 72% rename from src/tools/clippy/tests/ui/author.rs rename to src/tools/clippy/tests/ui-internal/author.rs index 0a1be356896..eb1f3e3f870 100644 --- a/src/tools/clippy/tests/ui/author.rs +++ b/src/tools/clippy/tests/ui-internal/author.rs @@ -1,3 +1,5 @@ +#![warn(clippy::author)] + fn main() { #[clippy::author] let x: char = 0x45 as char; diff --git a/src/tools/clippy/tests/ui/author.stdout b/src/tools/clippy/tests/ui-internal/author.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author.stdout rename to src/tools/clippy/tests/ui-internal/author.stdout diff --git a/src/tools/clippy/tests/ui/author/blocks.rs b/src/tools/clippy/tests/ui-internal/author/blocks.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/blocks.rs rename to src/tools/clippy/tests/ui-internal/author/blocks.rs diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui-internal/author/blocks.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/blocks.stdout rename to src/tools/clippy/tests/ui-internal/author/blocks.stdout diff --git a/src/tools/clippy/tests/ui/author/call.rs b/src/tools/clippy/tests/ui-internal/author/call.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/call.rs rename to src/tools/clippy/tests/ui-internal/author/call.rs diff --git a/src/tools/clippy/tests/ui/author/call.stdout b/src/tools/clippy/tests/ui-internal/author/call.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/call.stdout rename to src/tools/clippy/tests/ui-internal/author/call.stdout diff --git a/src/tools/clippy/tests/ui/author/if.rs b/src/tools/clippy/tests/ui-internal/author/if.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/if.rs rename to src/tools/clippy/tests/ui-internal/author/if.rs diff --git a/src/tools/clippy/tests/ui/author/if.stdout b/src/tools/clippy/tests/ui-internal/author/if.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/if.stdout rename to src/tools/clippy/tests/ui-internal/author/if.stdout diff --git a/src/tools/clippy/tests/ui/author/issue_3849.rs b/src/tools/clippy/tests/ui-internal/author/issue_3849.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/issue_3849.rs rename to src/tools/clippy/tests/ui-internal/author/issue_3849.rs diff --git a/src/tools/clippy/tests/ui/author/issue_3849.stdout b/src/tools/clippy/tests/ui-internal/author/issue_3849.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/issue_3849.stdout rename to src/tools/clippy/tests/ui-internal/author/issue_3849.stdout diff --git a/src/tools/clippy/tests/ui/author/loop.rs b/src/tools/clippy/tests/ui-internal/author/loop.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/loop.rs rename to src/tools/clippy/tests/ui-internal/author/loop.rs diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui-internal/author/loop.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/loop.stdout rename to src/tools/clippy/tests/ui-internal/author/loop.stdout diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.rs b/src/tools/clippy/tests/ui-internal/author/macro_in_closure.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/macro_in_closure.rs rename to src/tools/clippy/tests/ui-internal/author/macro_in_closure.rs diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui-internal/author/macro_in_closure.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/macro_in_closure.stdout rename to src/tools/clippy/tests/ui-internal/author/macro_in_closure.stdout diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.rs b/src/tools/clippy/tests/ui-internal/author/macro_in_loop.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/macro_in_loop.rs rename to src/tools/clippy/tests/ui-internal/author/macro_in_loop.rs diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout b/src/tools/clippy/tests/ui-internal/author/macro_in_loop.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/macro_in_loop.stdout rename to src/tools/clippy/tests/ui-internal/author/macro_in_loop.stdout diff --git a/src/tools/clippy/tests/ui/author/matches.rs b/src/tools/clippy/tests/ui-internal/author/matches.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/matches.rs rename to src/tools/clippy/tests/ui-internal/author/matches.rs diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui-internal/author/matches.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/matches.stdout rename to src/tools/clippy/tests/ui-internal/author/matches.stdout diff --git a/src/tools/clippy/tests/ui/author/repeat.rs b/src/tools/clippy/tests/ui-internal/author/repeat.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/repeat.rs rename to src/tools/clippy/tests/ui-internal/author/repeat.rs diff --git a/src/tools/clippy/tests/ui/author/repeat.stdout b/src/tools/clippy/tests/ui-internal/author/repeat.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/repeat.stdout rename to src/tools/clippy/tests/ui-internal/author/repeat.stdout diff --git a/src/tools/clippy/tests/ui/author/struct.rs b/src/tools/clippy/tests/ui-internal/author/struct.rs similarity index 100% rename from src/tools/clippy/tests/ui/author/struct.rs rename to src/tools/clippy/tests/ui-internal/author/struct.rs diff --git a/src/tools/clippy/tests/ui/author/struct.stdout b/src/tools/clippy/tests/ui-internal/author/struct.stdout similarity index 100% rename from src/tools/clippy/tests/ui/author/struct.stdout rename to src/tools/clippy/tests/ui-internal/author/struct.stdout diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs index 146b04ab813..0de53a75c62 100644 --- a/src/tools/clippy/tests/ui/cast.rs +++ b/src/tools/clippy/tests/ui/cast.rs @@ -1,7 +1,6 @@ //@no-rustfix #![feature(repr128)] -#![feature(isqrt)] #![allow(incomplete_features)] #![warn( clippy::cast_precision_loss, diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr index 7824bdfac25..452482fc88e 100644 --- a/src/tools/clippy/tests/ui/cast.stderr +++ b/src/tools/clippy/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:26:5 + --> tests/ui/cast.rs:25:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -8,37 +8,37 @@ LL | x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:30:5 + --> tests/ui/cast.rs:29:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:32:5 + --> tests/ui/cast.rs:31:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:35:5 + --> tests/ui/cast.rs:34:5 | LL | x2 as f32; | ^^^^^^^^^ error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:38:5 + --> tests/ui/cast.rs:37:5 | LL | x3 as f32; | ^^^^^^^^^ error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:40:5 + --> tests/ui/cast.rs:39:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:43:5 + --> tests/ui/cast.rs:42:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | 1f32 as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:45:5 + --> tests/ui/cast.rs:44:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | 1f32 as u32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:45:5 + --> tests/ui/cast.rs:44:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | 1f32 as u32; = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]` error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:49:5 + --> tests/ui/cast.rs:48:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | 1f64 as f32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:51:5 + --> tests/ui/cast.rs:50:5 | LL | 1i32 as i8; | ^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | i8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u8` may truncate the value - --> tests/ui/cast.rs:53:5 + --> tests/ui/cast.rs:52:5 | LL | 1i32 as u8; | ^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | u8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `f64` to `isize` may truncate the value - --> tests/ui/cast.rs:55:5 + --> tests/ui/cast.rs:54:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | 1f64 as isize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may truncate the value - --> tests/ui/cast.rs:57:5 + --> tests/ui/cast.rs:56:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ @@ -113,13 +113,13 @@ LL | 1f64 as usize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:57:5 + --> tests/ui/cast.rs:56:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u32` to `u16` may truncate the value - --> tests/ui/cast.rs:60:5 + --> tests/ui/cast.rs:59:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | u16::try_from(1f32 as u32); | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:60:5 + --> tests/ui/cast.rs:59:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ @@ -139,13 +139,13 @@ LL | 1f32 as u32 as u16; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:60:5 + --> tests/ui/cast.rs:59:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:65:22 + --> tests/ui/cast.rs:64:22 | LL | let _x: i8 = 1i32 as _; | ^^^^^^^^^ @@ -157,7 +157,7 @@ LL | let _x: i8 = 1i32.try_into(); | ~~~~~~~~~~~~~~~ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:67:9 + --> tests/ui/cast.rs:66:9 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | 1f32 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `i32` may truncate the value - --> tests/ui/cast.rs:69:9 + --> tests/ui/cast.rs:68:9 | LL | 1f64 as i32; | ^^^^^^^^^^^ @@ -173,7 +173,7 @@ LL | 1f64 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may truncate the value - --> tests/ui/cast.rs:71:9 + --> tests/ui/cast.rs:70:9 | LL | 1f32 as u8; | ^^^^^^^^^^ @@ -181,13 +181,13 @@ LL | 1f32 as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:71:9 + --> tests/ui/cast.rs:70:9 | LL | 1f32 as u8; | ^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> tests/ui/cast.rs:76:5 + --> tests/ui/cast.rs:75:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -196,31 +196,31 @@ LL | 1u8 as i8; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `u16` to `i16` may wrap around the value - --> tests/ui/cast.rs:79:5 + --> tests/ui/cast.rs:78:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> tests/ui/cast.rs:81:5 + --> tests/ui/cast.rs:80:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> tests/ui/cast.rs:83:5 + --> tests/ui/cast.rs:82:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> tests/ui/cast.rs:85:5 + --> tests/ui/cast.rs:84:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `usize` to `i8` may truncate the value - --> tests/ui/cast.rs:88:5 + --> tests/ui/cast.rs:87:5 | LL | 1usize as i8; | ^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL | i8::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may truncate the value - --> tests/ui/cast.rs:91:5 + --> tests/ui/cast.rs:90:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL | i16::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:91:5 + --> tests/ui/cast.rs:90:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | 1usize as i16; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:96:5 + --> tests/ui/cast.rs:95:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -265,19 +265,19 @@ LL | i32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:96:5 + --> tests/ui/cast.rs:95:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:100:5 + --> tests/ui/cast.rs:99:5 | LL | 1usize as i64; | ^^^^^^^^^^^^^ error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:105:5 + --> tests/ui/cast.rs:104:5 | LL | 1u16 as isize; | ^^^^^^^^^^^^^ @@ -286,13 +286,13 @@ LL | 1u16 as isize; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:109:5 + --> tests/ui/cast.rs:108:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:112:5 + --> tests/ui/cast.rs:111:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -304,55 +304,55 @@ LL | isize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:112:5 + --> tests/ui/cast.rs:111:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:117:5 + --> tests/ui/cast.rs:116:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:120:5 + --> tests/ui/cast.rs:119:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i8` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:131:5 + --> tests/ui/cast.rs:130:5 | LL | (i8::MIN).abs() as u8; | ^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:135:5 + --> tests/ui/cast.rs:134:5 | LL | (-1i64).abs() as u64; | ^^^^^^^^^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:136:5 + --> tests/ui/cast.rs:135:5 | LL | (-1isize).abs() as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:143:5 + --> tests/ui/cast.rs:142:5 | LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:158:5 + --> tests/ui/cast.rs:157:5 | LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> tests/ui/cast.rs:209:5 + --> tests/ui/cast.rs:208:5 | LL | (-99999999999i64).min(1) as i8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +364,7 @@ LL | i8::try_from((-99999999999i64).min(1)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:223:5 + --> tests/ui/cast.rs:222:5 | LL | 999999u64.clamp(0, 256) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> tests/ui/cast.rs:246:21 + --> tests/ui/cast.rs:245:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -388,7 +388,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> tests/ui/cast.rs:248:21 + --> tests/ui/cast.rs:247:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -397,7 +397,7 @@ LL | let _ = Self::B as u8; = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]` error: casting `main::E5` to `i8` may truncate the value - --> tests/ui/cast.rs:290:21 + --> tests/ui/cast.rs:289:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -409,13 +409,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> tests/ui/cast.rs:292:21 + --> tests/ui/cast.rs:291:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> tests/ui/cast.rs:309:21 + --> tests/ui/cast.rs:308:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:328:21 + --> tests/ui/cast.rs:327:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -439,7 +439,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> tests/ui/cast.rs:375:21 + --> tests/ui/cast.rs:374:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -451,7 +451,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:386:13 + --> tests/ui/cast.rs:385:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -463,7 +463,7 @@ LL | let c = u8::try_from(q >> 16); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:390:13 + --> tests/ui/cast.rs:389:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -475,85 +475,85 @@ LL | let c = u8::try_from(q / 1000); | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:402:9 + --> tests/ui/cast.rs:401:9 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:407:32 + --> tests/ui/cast.rs:406:32 | LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 }; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:409:5 + --> tests/ui/cast.rs:408:5 | LL | (2_i32).checked_pow(3).unwrap() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:410:5 + --> tests/ui/cast.rs:409:5 | LL | (-2_i32).pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:415:5 + --> tests/ui/cast.rs:414:5 | LL | (-5_i32 % 2) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:417:5 + --> tests/ui/cast.rs:416:5 | LL | (-5_i32 % -2) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:420:5 + --> tests/ui/cast.rs:419:5 | LL | (-2_i32 >> 1) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:424:5 + --> tests/ui/cast.rs:423:5 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:425:5 + --> tests/ui/cast.rs:424:5 | LL | (x * x * x) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:429:5 + --> tests/ui/cast.rs:428:5 | LL | (y * y * y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:431:5 + --> tests/ui/cast.rs:430:5 | LL | (y * y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:432:5 + --> tests/ui/cast.rs:431:5 | LL | (y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:434:5 + --> tests/ui/cast.rs:433:5 | LL | (y / y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `/` - --> tests/ui/cast.rs:434:6 + --> tests/ui/cast.rs:433:6 | LL | (y / y * y * -2) as u16; | ^^^^^ @@ -561,97 +561,97 @@ LL | (y / y * y * -2) as u16; = note: `#[deny(clippy::eq_op)]` on by default error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:437:5 + --> tests/ui/cast.rs:436:5 | LL | (y + y + y + -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:439:5 + --> tests/ui/cast.rs:438:5 | LL | (y + y + y + 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:443:5 + --> tests/ui/cast.rs:442:5 | LL | (z + -2) as u16; | ^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:445:5 + --> tests/ui/cast.rs:444:5 | LL | (z + z + 2) as u16; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:448:9 + --> tests/ui/cast.rs:447:9 | LL | (a * a * b * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:449:9 + --> tests/ui/cast.rs:448:9 | LL | (a * b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:451:9 + --> tests/ui/cast.rs:450:9 | LL | (a * -b * c) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:453:9 + --> tests/ui/cast.rs:452:9 | LL | (a * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:454:9 + --> tests/ui/cast.rs:453:9 | LL | (a * -2) as u32; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:456:9 + --> tests/ui/cast.rs:455:9 | LL | (a * b * c * -2) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:458:9 + --> tests/ui/cast.rs:457:9 | LL | (a / b) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:459:9 + --> tests/ui/cast.rs:458:9 | LL | (a / b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:461:9 + --> tests/ui/cast.rs:460:9 | LL | (a / b + b * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:463:9 + --> tests/ui/cast.rs:462:9 | LL | a.saturating_pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:465:9 + --> tests/ui/cast.rs:464:9 | LL | (a.abs() * b.pow(2) / c.abs()) as u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:473:21 + --> tests/ui/cast.rs:472:21 | LL | let _ = i32::MIN as u32; // cast_sign_loss | ^^^^^^^^^^^^^^^ @@ -662,7 +662,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:474:21 + --> tests/ui/cast.rs:473:21 | LL | let _ = u32::MAX as u8; // cast_possible_truncation | ^^^^^^^^^^^^^^ @@ -678,7 +678,7 @@ LL | let _ = u8::try_from(u32::MAX); // cast_possible_truncation | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:475:21 + --> tests/ui/cast.rs:474:21 | LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -690,7 +690,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:484:5 + --> tests/ui/cast.rs:483:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -702,13 +702,13 @@ LL | usize::try_from(bar.unwrap().unwrap()) | error: casting `i64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:484:5 + --> tests/ui/cast.rs:483:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:499:5 + --> tests/ui/cast.rs:498:5 | LL | (256 & 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -720,7 +720,7 @@ LL | u8::try_from(256 & 999999u64); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:501:5 + --> tests/ui/cast.rs:500:5 | LL | (255 % 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/no_lints.rs b/src/tools/clippy/tests/ui/no_lints.rs new file mode 100644 index 00000000000..a8467bb6ef7 --- /dev/null +++ b/src/tools/clippy/tests/ui/no_lints.rs @@ -0,0 +1,3 @@ +#![deny(clippy::all)] + +fn main() {} \ No newline at end of file diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index b810fd8224f..0d6e07aa546 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -54,7 +54,7 @@ #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] #![allow(named_arguments_used_positionally)] -#![allow(temporary_cstring_as_ptr)] +#![allow(dangling_pointers_from_temporaries)] #![allow(undropped_manually_drops)] #![allow(unknown_lints)] #![allow(unused_labels)] @@ -120,7 +120,7 @@ #![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os` #![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params` #![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters` -#![warn(temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr` +#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr` #![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops` #![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints` #![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label` diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 46d9f0fac59..b906079d7df 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,11 +1,17 @@ +error: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` + --> tests/ui/rename.rs:57:10 + | +LL | #![allow(temporary_cstring_as_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` + | + = note: `-D renamed-and-removed-lints` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` + error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` --> tests/ui/rename.rs:63:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` - | - = note: `-D renamed-and-removed-lints` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` --> tests/ui/rename.rs:64:9 @@ -361,11 +367,11 @@ error: lint `clippy::positional_named_format_parameters` has been renamed to `na LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` -error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` +error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` --> tests/ui/rename.rs:123:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` --> tests/ui/rename.rs:124:9 @@ -397,5 +403,5 @@ error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_e LL | #![warn(clippy::reverse_range_loop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges` -error: aborting due to 66 previous errors +error: aborting due to 67 previous errors diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index ff059940f7c..69ac4644941 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -376,6 +376,7 @@ pub struct Config { pub only_modified: bool, pub target_cfgs: OnceLock, + pub builtin_cfg_names: OnceLock>, pub nocapture: bool, @@ -387,6 +388,9 @@ pub struct Config { /// True if the profiler runtime is enabled for this target. /// Used by the "needs-profiler-runtime" directive in test files. pub profiler_runtime: bool, + + /// Command for visual diff display, e.g. `diff-tool --color=always`. + pub diff_command: Option, } impl Config { @@ -440,6 +444,11 @@ impl Config { self.target_cfg().panic == PanicStrategy::Unwind } + /// Get the list of builtin, 'well known' cfg names + pub fn builtin_cfg_names(&self) -> &HashSet { + self.builtin_cfg_names.get_or_init(|| builtin_cfg_names(self)) + } + pub fn has_threads(&self) -> bool { // Wasm targets don't have threads unless `-threads` is in the target // name, such as `wasm32-wasip1-threads`. @@ -651,6 +660,18 @@ pub enum Endian { Big, } +fn builtin_cfg_names(config: &Config) -> HashSet { + rustc_output( + config, + &["--print=check-cfg", "-Zunstable-options", "--check-cfg=cfg()"], + Default::default(), + ) + .lines() + .map(|l| if let Some((name, _)) = l.split_once('=') { name.to_string() } else { l.to_string() }) + .chain(std::iter::once(String::from("test"))) + .collect() +} + fn rustc_output(config: &Config, args: &[&str], envs: HashMap) -> String { let mut command = Command::new(&config.rustc_path); add_dylib_path(&mut command, iter::once(&config.compile_lib_path)); diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 099e620ffe0..d75cdefe635 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -57,7 +57,7 @@ impl EarlyProps { &mut poisoned, testfile, rdr, - &mut |DirectiveLine { directive: ln, .. }| { + &mut |DirectiveLine { raw_directive: ln, .. }| { parse_and_update_aux(config, ln, &mut props.aux); config.parse_and_update_revisions(testfile, ln, &mut props.revisions); }, @@ -344,8 +344,8 @@ impl TestProps { &mut poisoned, testfile, file, - &mut |DirectiveLine { header_revision, directive: ln, .. }| { - if header_revision.is_some() && header_revision != test_revision { + &mut |directive @ DirectiveLine { raw_directive: ln, .. }| { + if !directive.applies_to_test_revision(test_revision) { return; } @@ -678,28 +678,35 @@ impl TestProps { } } -/// Extract an `(Option, directive)` directive from a line if comment is present. -/// -/// See [`DirectiveLine`] for a diagram. -pub fn line_directive<'line>( +/// If the given line begins with the appropriate comment prefix for a directive, +/// returns a struct containing various parts of the directive. +fn line_directive<'line>( + line_number: usize, comment: &str, original_line: &'line str, -) -> Option<(Option<&'line str>, &'line str)> { +) -> Option> { // Ignore lines that don't start with the comment prefix. let after_comment = original_line.trim_start().strip_prefix(comment)?.trim_start(); + let revision; + let raw_directive; + if let Some(after_open_bracket) = after_comment.strip_prefix('[') { // A comment like `//@[foo]` only applies to revision `foo`. - let Some((line_revision, directive)) = after_open_bracket.split_once(']') else { + let Some((line_revision, after_close_bracket)) = after_open_bracket.split_once(']') else { panic!( "malformed condition directive: expected `{comment}[foo]`, found `{original_line}`" ) }; - Some((Some(line_revision), directive.trim_start())) + revision = Some(line_revision); + raw_directive = after_close_bracket.trim_start(); } else { - Some((None, after_comment)) - } + revision = None; + raw_directive = after_comment; + }; + + Some(DirectiveLine { line_number, revision, raw_directive }) } // To prevent duplicating the list of commmands between `compiletest`,`htmldocck` and `jsondocck`, @@ -730,28 +737,37 @@ const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[ const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] = &["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"]; -/// The broken-down contents of a line containing a test header directive, +/// The (partly) broken-down contents of a line containing a test directive, /// which [`iter_header`] passes to its callback function. /// /// For example: /// /// ```text /// //@ compile-flags: -O -/// ^^^^^^^^^^^^^^^^^ directive +/// ^^^^^^^^^^^^^^^^^ raw_directive /// /// //@ [foo] compile-flags: -O -/// ^^^ header_revision -/// ^^^^^^^^^^^^^^^^^ directive +/// ^^^ revision +/// ^^^^^^^^^^^^^^^^^ raw_directive /// ``` struct DirectiveLine<'ln> { line_number: usize, - /// Some header directives start with a revision name in square brackets + /// Some test directives start with a revision name in square brackets /// (e.g. `[foo]`), and only apply to that revision of the test. /// If present, this field contains the revision name (e.g. `foo`). - header_revision: Option<&'ln str>, - /// The main part of the header directive, after removing the comment prefix + revision: Option<&'ln str>, + /// The main part of the directive, after removing the comment prefix /// and the optional revision specifier. - directive: &'ln str, + /// + /// This is "raw" because the directive's name and colon-separated value + /// (if present) have not yet been extracted or checked. + raw_directive: &'ln str, +} + +impl<'ln> DirectiveLine<'ln> { + fn applies_to_test_revision(&self, test_revision: Option<&str>) -> bool { + self.revision.is_none() || self.revision == test_revision + } } pub(crate) struct CheckDirectiveResult<'ln> { @@ -819,8 +835,8 @@ fn iter_header( "ignore-cross-compile", ]; // Process the extra implied directives, with a dummy line number of 0. - for directive in extra_directives { - it(DirectiveLine { line_number: 0, header_revision: None, directive }); + for raw_directive in extra_directives { + it(DirectiveLine { line_number: 0, revision: None, raw_directive }); } } @@ -847,24 +863,21 @@ fn iter_header( return; } - let Some((header_revision, non_revisioned_directive_line)) = line_directive(comment, ln) - else { + let Some(directive_line) = line_directive(line_number, comment, ln) else { continue; }; // Perform unknown directive check on Rust files. if testfile.extension().map(|e| e == "rs").unwrap_or(false) { - let directive_ln = non_revisioned_directive_line.trim(); - let CheckDirectiveResult { is_known_directive, trailing_directive } = - check_directive(directive_ln, mode, ln); + check_directive(directive_line.raw_directive, mode, ln); if !is_known_directive { *poisoned = true; eprintln!( "error: detected unknown compiletest test directive `{}` in {}:{}", - directive_ln, + directive_line.raw_directive, testfile.display(), line_number, ); @@ -888,11 +901,7 @@ fn iter_header( } } - it(DirectiveLine { - line_number, - header_revision, - directive: non_revisioned_directive_line, - }); + it(directive_line); } } @@ -1292,8 +1301,8 @@ pub fn make_test_description( &mut local_poisoned, path, src, - &mut |DirectiveLine { header_revision, directive: ln, line_number }| { - if header_revision.is_some() && header_revision != test_revision { + &mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| { + if !directive.applies_to_test_revision(test_revision) { return; } diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 7d6ede9bcda..490df313228 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -175,6 +175,12 @@ pub fn parse_config(args: Vec) -> Config { "git-merge-commit-email", "email address used for finding merge commits", "EMAIL", + ) + .optopt( + "", + "compiletest-diff-tool", + "What custom diff tool to use for displaying compiletest tests.", + "COMMAND", ); let (argv0, args_) = args.split_first().unwrap(); @@ -356,6 +362,7 @@ pub fn parse_config(args: Vec) -> Config { force_rerun: matches.opt_present("force-rerun"), target_cfgs: OnceLock::new(), + builtin_cfg_names: OnceLock::new(), nocapture: matches.opt_present("nocapture"), @@ -364,6 +371,7 @@ pub fn parse_config(args: Vec) -> Config { git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(), profiler_runtime: matches.opt_present("profiler-runtime"), + diff_command: matches.opt_str("compiletest-diff-tool"), } } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 36c5106ddad..a8a71c196fc 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -59,7 +59,7 @@ fn disable_error_reporting R, R>(f: F) -> R { use std::sync::Mutex; use windows::Win32::System::Diagnostics::Debug::{ - SEM_NOGPFAULTERRORBOX, SetErrorMode, THREAD_ERROR_MODE, + SEM_FAILCRITICALERRORS, SEM_NOGPFAULTERRORBOX, SetErrorMode, THREAD_ERROR_MODE, }; static LOCK: Mutex<()> = Mutex::new(()); @@ -67,13 +67,21 @@ fn disable_error_reporting R, R>(f: F) -> R { // Error mode is a global variable, so lock it so only one thread will change it let _lock = LOCK.lock().unwrap(); - // Tell Windows to not show any UI on errors (such as terminating abnormally). - // This is important for running tests, since some of them use abnormal - // termination by design. This mode is inherited by all child processes. + // Tell Windows to not show any UI on errors (such as terminating abnormally). This is important + // for running tests, since some of them use abnormal termination by design. This mode is + // inherited by all child processes. + // + // Note that `run-make` tests require `SEM_FAILCRITICALERRORS` in addition to suppress Windows + // Error Reporting (WER) error dialogues that come from "critical failures" such as missing + // DLLs. + // + // See and + // . unsafe { - let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags + // read inherited flags + let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS); let old_mode = THREAD_ERROR_MODE(old_mode); - SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX); + SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS); let r = f(); SetErrorMode(old_mode); r @@ -478,6 +486,9 @@ impl<'test> TestCx<'test> { "error: redundant cfg argument `{normalized_revision}` is already created by the revision" ); } + if self.config.builtin_cfg_names().contains(&normalized_revision) { + panic!("error: revision `{normalized_revision}` collides with a builtin cfg"); + } cmd.args(cfg_arg); } @@ -1085,6 +1096,10 @@ impl<'test> TestCx<'test> { self.config.target.contains("vxworks") && !self.is_vxworks_pure_static() } + fn has_aux_dir(&self) -> bool { + !self.props.aux.builds.is_empty() || !self.props.aux.crates.is_empty() + } + fn aux_output_dir(&self) -> PathBuf { let aux_dir = self.aux_output_dir_name(); @@ -1638,7 +1653,11 @@ impl<'test> TestCx<'test> { } if let LinkToAux::Yes = link_to_aux { - rustc.arg("-L").arg(self.aux_output_dir_name()); + // if we pass an `-L` argument to a directory that doesn't exist, + // macOS ld emits warnings which disrupt the .stderr files + if self.has_aux_dir() { + rustc.arg("-L").arg(self.aux_output_dir_name()); + } } rustc.args(&self.props.compile_flags); @@ -2459,7 +2478,7 @@ impl<'test> TestCx<'test> { } } - fn compare_output(&self, kind: &str, actual: &str, expected: &str) -> usize { + fn compare_output(&self, stream: &str, actual: &str, expected: &str) -> usize { let are_different = match (self.force_color_svg(), expected.find('\n'), actual.find('\n')) { // FIXME: We ignore the first line of SVG files // because the width parameter is non-deterministic. @@ -2499,56 +2518,66 @@ impl<'test> TestCx<'test> { (expected, actual) }; - if !self.config.bless { - if expected.is_empty() { - println!("normalized {}:\n{}\n", kind, actual); - } else { - println!("diff of {}:\n", kind); - print!("{}", write_diff(expected, actual, 3)); - } - } - - let mode = self.config.compare_mode.as_ref().map_or("", |m| m.to_str()); - let output_file = self + // Write the actual output to a file in build/ + let test_name = self.config.compare_mode.as_ref().map_or("", |m| m.to_str()); + let actual_path = self .output_base_name() .with_extra_extension(self.revision.unwrap_or("")) - .with_extra_extension(mode) - .with_extra_extension(kind); + .with_extra_extension(test_name) + .with_extra_extension(stream); - let mut files = vec![output_file]; - if self.config.bless { + if let Err(err) = fs::write(&actual_path, &actual) { + self.fatal(&format!("failed to write {stream} to `{actual_path:?}`: {err}",)); + } + println!("Saved the actual {stream} to {actual_path:?}"); + + let expected_path = + expected_output_path(self.testpaths, self.revision, &self.config.compare_mode, stream); + + if !self.config.bless { + if expected.is_empty() { + println!("normalized {}:\n{}\n", stream, actual); + } else { + println!("diff of {stream}:\n"); + if let Some(diff_command) = self.config.diff_command.as_deref() { + let mut args = diff_command.split_whitespace(); + let name = args.next().unwrap(); + match Command::new(name) + .args(args) + .args([&expected_path, &actual_path]) + .output() + { + Err(err) => { + self.fatal(&format!( + "failed to call custom diff command `{diff_command}`: {err}" + )); + } + Ok(output) => { + let output = String::from_utf8_lossy(&output.stdout); + print!("{output}"); + } + } + } else { + print!("{}", write_diff(expected, actual, 3)); + } + } + } else { // Delete non-revision .stderr/.stdout file if revisions are used. // Without this, we'd just generate the new files and leave the old files around. if self.revision.is_some() { let old = - expected_output_path(self.testpaths, None, &self.config.compare_mode, kind); + expected_output_path(self.testpaths, None, &self.config.compare_mode, stream); self.delete_file(&old); } - files.push(expected_output_path( - self.testpaths, - self.revision, - &self.config.compare_mode, - kind, - )); - } - for output_file in &files { - if actual.is_empty() { - self.delete_file(output_file); - } else if let Err(err) = fs::write(&output_file, &actual) { - self.fatal(&format!( - "failed to write {} to `{}`: {}", - kind, - output_file.display(), - err, - )); + if let Err(err) = fs::write(&expected_path, &actual) { + self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}")); } + println!("Blessing the {stream} of {test_name} in {expected_path:?}"); } - println!("\nThe actual {0} differed from the expected {0}.", kind); - for output_file in files { - println!("Actual {} saved to {}", kind, output_file.display()); - } + println!("\nThe actual {0} differed from the expected {0}.", stream); + if self.config.bless { 0 } else { 1 } } diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index 985fe6381e8..c15422fb6f6 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -4,7 +4,6 @@ use std::io::{BufRead, BufReader}; use std::path::{Path, PathBuf}; use crate::common::Config; -use crate::header::line_directive; use crate::runtest::ProcRes; /// Representation of information to invoke a debugger and check its output @@ -24,7 +23,6 @@ impl DebuggerCommands { file: &Path, config: &Config, debugger_prefixes: &[&str], - rev: Option<&str>, ) -> Result { let directives = debugger_prefixes .iter() @@ -39,17 +37,16 @@ impl DebuggerCommands { for (line_no, line) in reader.lines().enumerate() { counter += 1; let line = line.map_err(|e| format!("Error while parsing debugger commands: {}", e))?; - let (lnrev, line) = line_directive("//", &line).unwrap_or((None, &line)); - // Skip any revision specific directive that doesn't match the current - // revision being tested - if lnrev.is_some() && lnrev != rev { + // Breakpoints appear on lines with actual code, typically at the end of the line. + if line.contains("#break") { + breakpoint_lines.push(counter); continue; } - if line.contains("#break") { - breakpoint_lines.push(counter); - } + let Some(line) = line.trim_start().strip_prefix("//").map(str::trim_start) else { + continue; + }; for &(ref command_directive, ref check_directive) in &directives { config diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index bd0845b4524..c621c22ac99 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -66,13 +66,8 @@ impl TestCx<'_> { }; // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - prefixes, - self.revision, - ) - .unwrap_or_else(|e| self.fatal(&e)); + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) + .unwrap_or_else(|e| self.fatal(&e)); // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands let mut script_str = String::with_capacity(2048); @@ -142,13 +137,8 @@ impl TestCx<'_> { } fn run_debuginfo_gdb_test_no_opt(&self) { - let dbg_cmds = DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - &["gdb"], - self.revision, - ) - .unwrap_or_else(|e| self.fatal(&e)); + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["gdb"]) + .unwrap_or_else(|e| self.fatal(&e)); let mut cmds = dbg_cmds.commands.join("\n"); // compile test file (it should have 'compile-flags:-g' in the header) @@ -413,13 +403,8 @@ impl TestCx<'_> { } // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - &["lldb"], - self.revision, - ) - .unwrap_or_else(|e| self.fatal(&e)); + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["lldb"]) + .unwrap_or_else(|e| self.fatal(&e)); // Write debugger script: // We don't want to hang when calling `quit` while the process is still running diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index f8ffd0fbe3f..04bc2d7787d 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -2,7 +2,7 @@ use std::path::Path; use std::process::{Command, Output, Stdio}; use std::{env, fs}; -use super::{ProcRes, TestCx}; +use super::{ProcRes, TestCx, disable_error_reporting}; use crate::util::{copy_dir_all, dylib_env_var}; impl TestCx<'_> { @@ -329,6 +329,7 @@ impl TestCx<'_> { .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) .arg("--edition=2021") .arg(&self.testpaths.file.join("rmake.rs")) + .arg("-Cprefer-dynamic") // Provide necessary library search paths for rustc. .env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap()); @@ -514,8 +515,8 @@ impl TestCx<'_> { } } - let (Output { stdout, stderr, status }, truncated) = - self.read2_abbreviated(cmd.spawn().expect("failed to spawn `rmake`")); + let proc = disable_error_reporting(|| cmd.spawn().expect("failed to spawn `rmake`")); + let (Output { stdout, stderr, status }, truncated) = self.read2_abbreviated(proc); if !status.success() { let res = ProcRes { status, diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 8b0916f5111..2e491319822 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -1,11 +1,7 @@ name: CI on: - push: - # Run in PRs and for bors, but not on master. - branches: - - 'auto' - - 'try' + merge_group: pull_request: branches: - 'master' @@ -38,7 +34,7 @@ jobs: # The `style` job only runs on Linux; this makes sure the Windows-host-specific # code is also covered by clippy. - name: Check clippy - if: matrix.os == 'windows-latest' + if: ${{ matrix.os == 'windows-latest' }} run: ./miri clippy -- -D warnings - name: Test Miri @@ -62,27 +58,25 @@ jobs: - name: rustdoc run: RUSTDOCFLAGS="-Dwarnings" ./miri doc --document-private-items - # These jobs doesn't actually test anything, but they're only used to tell - # bors the build completed, as there is no practical way to detect when a - # workflow is successful listening to webhooks only. - # + # Summary job for the merge queue. # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! - end-success: - name: bors build finished - runs-on: ubuntu-latest + # And they should be added below in `cron-fail-notify` as well. + conclusion: needs: [build, style] - if: github.event.pusher.name == 'bors' && success() - steps: - - name: mark the job as a success - run: exit 0 - end-failure: - name: bors build finished + # We need to ensure this job does *not* get skipped if its dependencies fail, + # because a skipped job is considered a success by GitHub. So we have to + # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run + # when the workflow is canceled manually. + if: ${{ !cancelled() }} runs-on: ubuntu-latest - needs: [build, style] - if: github.event.pusher.name == 'bors' && (failure() || cancelled()) steps: - - name: mark the job as a failure - run: exit 1 + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: Conclusion + run: | + # Print the dependent jobs to see them in the CI log + jq -C <<< '${{ toJson(needs) }}' + # Check if all jobs that we depend on (in the needs array) were successful. + jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' cron-fail-notify: name: cronjob failure notification @@ -93,7 +87,7 @@ jobs: # ... and create a PR. pull-requests: write needs: [build, style] - if: github.event_name == 'schedule' && failure() + if: ${{ github.event_name == 'schedule' && failure() }} steps: # Send a Zulip notification - name: Install zulip-send @@ -145,7 +139,7 @@ jobs: git push -u origin $BRANCH - name: Create Pull Request run: | - PR=$(gh pr create -B master --title 'Automatic Rustup' --body '') + PR=$(gh pr create -B master --title 'Automatic Rustup' --body 'Please close and re-open this PR to trigger CI, then enable auto-merge.') ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \ --stream miri --subject "Miri Build Failure ($(date -u +%Y-%m))" \ --message "A PR doing a rustc-pull [has been automatically created]($PR) for your convenience." diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index ad1b2f4d0c3..4e7cbc50ca0 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -154,7 +154,7 @@ case $HOST_TARGET in TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe - TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap pthread --skip threadname + TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap threadname pthread TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 8b9e7efdff9..133edd3191d 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -17a19e684cdf3ca088af8b4da6a6209d128913f4 +814df6e50eaf89b90793e7d9618bb60f1f18377a diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs index 1684abeec6b..5624c4c479e 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs @@ -424,7 +424,11 @@ impl<'history, 'ecx, 'tcx> DiagnosticCx<'history, 'ecx, 'tcx> { } #[inline(never)] // This is only called on fatal code paths - pub(super) fn protector_error(&self, item: &Item, kind: ProtectorKind) -> InterpErrorKind<'tcx> { + pub(super) fn protector_error( + &self, + item: &Item, + kind: ProtectorKind, + ) -> InterpErrorKind<'tcx> { let protected = match kind { ProtectorKind::WeakProtector => "weakly protected", ProtectorKind::StrongProtector => "strongly protected", diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 09ec2cb46b0..776d2561b43 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -145,6 +145,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_bool(branch), dest)?; } + "floorf16" | "ceilf16" | "truncf16" | "roundf16" | "rintf16" => { + let [f] = check_arg_count(args)?; + let f = this.read_scalar(f)?.to_f16()?; + let mode = match intrinsic_name { + "floorf16" => Round::TowardNegative, + "ceilf16" => Round::TowardPositive, + "truncf16" => Round::TowardZero, + "roundf16" => Round::NearestTiesToAway, + "rintf16" => Round::NearestTiesToEven, + _ => bug!(), + }; + let res = f.round_to_integral(mode).value; + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } "floorf32" | "ceilf32" | "truncf32" | "roundf32" | "rintf32" => { let [f] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; @@ -175,6 +190,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; } + "floorf128" | "ceilf128" | "truncf128" | "roundf128" | "rintf128" => { + let [f] = check_arg_count(args)?; + let f = this.read_scalar(f)?.to_f128()?; + let mode = match intrinsic_name { + "floorf128" => Round::TowardNegative, + "ceilf128" => Round::TowardPositive, + "truncf128" => Round::TowardZero, + "roundf128" => Round::NearestTiesToAway, + "rintf128" => Round::NearestTiesToEven, + _ => bug!(), + }; + let res = f.round_to_integral(mode).value; + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } #[rustfmt::skip] | "sinf32" diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index 0799b93dbb0..f15b83a054f 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -1,7 +1,8 @@ use either::Either; use rustc_apfloat::{Float, Round}; +use rustc_middle::ty::FloatTy; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::{mir, ty, ty::FloatTy}; +use rustc_middle::{mir, ty}; use rustc_span::{Symbol, sym}; use rustc_target::abi::{Endian, HasDataLayout}; @@ -630,12 +631,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (right, right_len) = this.project_to_simd(right)?; let (dest, dest_len) = this.project_to_simd(dest)?; - let index = generic_args[2] - .expect_const() - .try_to_valtree() - .unwrap() - .0 - .unwrap_branch(); + let index = + generic_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch(); let index_len = index.len(); assert_eq!(left_len, right_len); diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 660f2e493bc..938d1ca319e 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -147,7 +147,7 @@ pub use crate::range_map::RangeMap; pub use crate::shims::EmulateItemResult; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _}; -pub use crate::shims::io_error::{EvalContextExt as _, LibcError}; +pub use crate::shims::io_error::{EvalContextExt as _, IoError, LibcError}; pub use crate::shims::os_str::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; pub use crate::shims::time::EvalContextExt as _; diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index f6f91e58969..12f8facfd02 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -447,8 +447,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } else { // If this does not fit in an isize, return null and, on Unix, set errno. if this.target_os_is_unix() { - let einval = this.eval_libc("ENOMEM"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("ENOMEM"))?; } this.write_null(dest)?; } @@ -464,8 +463,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } else { // On size overflow, return null and, on Unix, set errno. if this.target_os_is_unix() { - let einval = this.eval_libc("ENOMEM"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("ENOMEM"))?; } this.write_null(dest)?; } @@ -486,8 +484,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } else { // If this does not fit in an isize, return null and, on Unix, set errno. if this.target_os_is_unix() { - let einval = this.eval_libc("ENOMEM"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("ENOMEM"))?; } this.write_null(dest)?; } diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs index 38aa181cb4f..04491f0542b 100644 --- a/src/tools/miri/src/shims/io_error.rs +++ b/src/tools/miri/src/shims/io_error.rs @@ -141,6 +141,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(Scalar::from_i32(-1)) } + /// Sets the last OS error and return `-1` as a `i64`-typed Scalar + fn set_last_error_and_return_i64( + &mut self, + err: impl Into, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + this.set_last_error(err)?; + interp_ok(Scalar::from_i64(-1)) + } + /// Gets the last error variable. fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 12c7679608d..6436823b0fd 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -81,9 +81,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } else if relative_clocks.contains(&clk_id) { this.machine.clock.now().duration_since(this.machine.clock.epoch()) } else { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); }; let tv_sec = duration.as_secs(); @@ -109,9 +107,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Using tz is obsolete and should always be null let tz = this.read_pointer(tz_op)?; if !this.ptr_is_null(tz)? { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); } let duration = system_time_to_duration(&SystemTime::now())?; @@ -323,9 +319,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let duration = match this.read_timespec(&req)? { Some(duration) => duration, None => { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); } }; diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index 583a1f65009..b6f04951fc7 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -1,6 +1,7 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; +use crate::shims::unix::android::thread::prctl; use crate::*; pub fn is_dyn_sym(_name: &str) -> bool { @@ -25,6 +26,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } + // Threading + "prctl" => prctl(this, link_name, abi, args, dest)?, + _ => return interp_ok(EmulateItemResult::NotSupported), } interp_ok(EmulateItemResult::NeedsReturn) diff --git a/src/tools/miri/src/shims/unix/android/mod.rs b/src/tools/miri/src/shims/unix/android/mod.rs index 09c6507b24f..1f2a74bac59 100644 --- a/src/tools/miri/src/shims/unix/android/mod.rs +++ b/src/tools/miri/src/shims/unix/android/mod.rs @@ -1 +1,2 @@ pub mod foreign_items; +pub mod thread; diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs new file mode 100644 index 00000000000..6f5f0f74a22 --- /dev/null +++ b/src/tools/miri/src/shims/unix/android/thread.rs @@ -0,0 +1,57 @@ +use rustc_span::Symbol; +use rustc_target::abi::Size; +use rustc_target::spec::abi::Abi; + +use crate::helpers::check_min_arg_count; +use crate::shims::unix::thread::EvalContextExt as _; +use crate::*; + +const TASK_COMM_LEN: usize = 16; + +pub fn prctl<'tcx>( + this: &mut MiriInterpCx<'tcx>, + link_name: Symbol, + abi: Abi, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx> { + // We do not use `check_shim` here because `prctl` is variadic. The argument + // count is checked bellow. + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; + + // FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch. + let pr_set_name = 15; + let pr_get_name = 16; + + let [op] = check_min_arg_count("prctl", args)?; + let res = match this.read_scalar(op)?.to_i32()? { + op if op == pr_set_name => { + let [_, name] = check_min_arg_count("prctl(PR_SET_NAME, ...)", args)?; + let name = this.read_scalar(name)?; + let thread = this.pthread_self()?; + // The Linux kernel silently truncates long names. + // https://www.man7.org/linux/man-pages/man2/PR_SET_NAME.2const.html + let res = + this.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?; + assert!(res); + Scalar::from_u32(0) + } + op if op == pr_get_name => { + let [_, name] = check_min_arg_count("prctl(PR_GET_NAME, ...)", args)?; + let name = this.read_scalar(name)?; + let thread = this.pthread_self()?; + let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, this); + this.check_ptr_access( + name.to_pointer(this)?, + Size::from_bytes(TASK_COMM_LEN), + CheckInAllocMsg::MemoryAccessTest, + )?; + let res = this.pthread_getname_np(thread, name, len, /* truncate*/ false)?; + assert!(res); + Scalar::from_u32(0) + } + op => throw_unsup_format!("Miri does not support `prctl` syscall with op={}", op), + }; + this.write_scalar(res, dest)?; + interp_ok(()) +} diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index e3914640037..f3db56695fc 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -423,7 +423,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let Some(fd) = this.machine.fds.get(old_fd_num) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; interp_ok(Scalar::from_i32(this.machine.fds.insert(fd))) } @@ -432,7 +432,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let Some(fd) = this.machine.fds.get(old_fd_num) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; if new_fd_num != old_fd_num { // Close new_fd if it is previously opened. @@ -448,7 +448,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn flock(&mut self, fd_num: i32, op: i32) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let Some(fd) = this.machine.fds.get(fd_num) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; // We need to check that there aren't unsupported options in `op`. @@ -498,11 +498,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` // always sets this flag when opening a file. However we still need to check that the // file itself is open. - interp_ok(Scalar::from_i32(if this.machine.fds.is_fd_num(fd_num) { - this.eval_libc_i32("FD_CLOEXEC") + if !this.machine.fds.is_fd_num(fd_num) { + this.set_last_error_and_return_i32(LibcError("EBADF")) } else { - this.fd_not_found()? - })) + interp_ok(this.eval_libc("FD_CLOEXEC")) + } } cmd if cmd == f_dupfd || cmd == f_dupfd_cloexec => { // Note that we always assume the FD_CLOEXEC flag is set for every open file, in part @@ -521,7 +521,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let Some(fd) = this.machine.fds.get(fd_num) { interp_ok(Scalar::from_i32(this.machine.fds.insert_with_min_num(fd, start))) } else { - interp_ok(Scalar::from_i32(this.fd_not_found()?)) + this.set_last_error_and_return_i32(LibcError("EBADF")) } } cmd if this.tcx.sess.target.os == "macos" @@ -547,7 +547,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let fd_num = this.read_scalar(fd_op)?.to_i32()?; let Some(fd) = this.machine.fds.remove(fd_num) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; let result = fd.close(this.machine.communicate(), this)?; // return `0` if close is successful @@ -555,17 +555,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) } - /// Function used when a file descriptor does not exist. It returns `Ok(-1)`and sets - /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses - /// `T: From` instead of `i32` directly because some fs functions return different integer - /// types (like `read`, that returns an `i64`). - fn fd_not_found>(&mut self) -> InterpResult<'tcx, T> { - let this = self.eval_context_mut(); - let ebadf = this.eval_libc("EBADF"); - this.set_last_error(ebadf)?; - interp_ok((-1).into()) - } - /// Read data from `fd` into buffer specified by `buf` and `count`. /// /// If `offset` is `None`, reads data from current cursor position associated with `fd` @@ -599,9 +588,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We temporarily dup the FD to be able to retain mutable access to `this`. let Some(fd) = this.machine.fds.get(fd_num) else { trace!("read: FD not found"); - let res: i32 = this.fd_not_found()?; - this.write_int(res, dest)?; - return interp_ok(()); + return this.set_last_error_and_return(LibcError("EBADF"), dest); }; trace!("read: FD mapped to {fd:?}"); @@ -646,9 +633,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We temporarily dup the FD to be able to retain mutable access to `this`. let Some(fd) = this.machine.fds.get(fd_num) else { - let res: i32 = this.fd_not_found()?; - this.write_int(res, dest)?; - return interp_ok(()); + return this.set_last_error_and_return(LibcError("EBADF"), dest); }; match offset { diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 7ba98981920..355c93c444c 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -362,8 +362,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=reallocarray match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) { None => { - let enmem = this.eval_libc("ENOMEM"); - this.set_last_error(enmem)?; + this.set_last_error(LibcError("ENOMEM"))?; this.write_null(dest)?; } Some(len) => { @@ -653,13 +652,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let chunk_size = CpuAffinityMask::chunk_size(this); if this.ptr_is_null(mask)? { - let efault = this.eval_libc("EFAULT"); - this.set_last_error(efault)?; - this.write_int(-1, dest)?; + this.set_last_error_and_return(LibcError("EFAULT"), dest)?; } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 { // we only copy whole chunks of size_of::() - this.set_last_error(LibcError("EINVAL"))?; - this.write_int(-1, dest)?; + this.set_last_error_and_return(LibcError("EINVAL"), dest)?; } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) { let cpuset = cpuset.clone(); // we only copy whole chunks of size_of::() @@ -668,9 +664,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } else { // The thread whose ID is pid could not be found - let esrch = this.eval_libc("ESRCH"); - this.set_last_error(esrch)?; - this.write_int(-1, dest)?; + this.set_last_error_and_return(LibcError("ESRCH"), dest)?; } } "sched_setaffinity" => { @@ -695,9 +689,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; if this.ptr_is_null(mask)? { - let efault = this.eval_libc("EFAULT"); - this.set_last_error(efault)?; - this.write_int(-1, dest)?; + this.set_last_error_and_return(LibcError("EFAULT"), dest)?; } else { // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`. // Any unspecified bytes are treated as zero here (none of the CPUs are configured). @@ -713,8 +705,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } None => { // The intersection between the mask and the available CPUs was empty. - this.set_last_error(LibcError("EINVAL"))?; - this.write_int(-1, dest)?; + this.set_last_error_and_return(LibcError("EINVAL"), dest)?; } } } @@ -770,9 +761,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // macOS: https://keith.github.io/xcode-man-pages/getentropy.2.html // Solaris/Illumos: https://illumos.org/man/3C/getentropy if bufsize > 256 { - let err = this.eval_libc("EIO"); - this.set_last_error(err)?; - this.write_int(-1, dest)?; + this.set_last_error_and_return(LibcError("EIO"), dest)?; } else { this.gen_random(buf, bufsize)?; this.write_null(dest)?; diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 5204e57705a..71953aca989 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -29,6 +29,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.read_scalar(thread)?, this.read_scalar(name)?, max_len, + /* truncate */ false, )?; } "pthread_get_name_np" => { diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 4b3ae8e0520..f7436d7f089 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -149,6 +149,7 @@ impl FileDescription for FileHandle { // to handle possible errors correctly. let result = self.file.sync_all(); // Now we actually close the file and return the result. + drop(*self); interp_ok(result) } else { // We drop the file, this closes it but ignores any errors @@ -157,6 +158,7 @@ impl FileDescription for FileHandle { // `/dev/urandom` which are read-only. Check // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 // for a deeper discussion. + drop(*self); interp_ok(Ok(())) } } @@ -229,6 +231,8 @@ impl FileDescription for FileHandle { TRUE => Ok(()), FALSE => { let mut err = io::Error::last_os_error(); + // This only runs on Windows hosts so we can use `raw_os_error`. + // We have to be careful not to forward that error code to target code. let code: u32 = err.raw_os_error().unwrap().try_into().unwrap(); if matches!(code, ERROR_IO_PENDING | ERROR_LOCK_VIOLATION) { if lock_nb { @@ -337,15 +341,10 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => interp_ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()), } } - Err(e) => - match e.raw_os_error() { - Some(error) => interp_ok(error), - None => - throw_unsup_format!( - "the error {} couldn't be converted to a return value", - e - ), - }, + Err(_) => { + // Fallback on error + interp_ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()) + } } } } @@ -528,8 +527,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let o_tmpfile = this.eval_libc_i32("O_TMPFILE"); if flag & o_tmpfile == o_tmpfile { // if the flag contains `O_TMPFILE` then we return a graceful error - this.set_last_error(LibcError("EOPNOTSUPP"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EOPNOTSUPP")); } } @@ -548,9 +546,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // O_NOFOLLOW only fails when the trailing component is a symlink; // the entire rest of the path can still contain symlinks. if path.is_symlink() { - let eloop = this.eval_libc("ELOOP"); - this.set_last_error(eloop)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("ELOOP")); } } mirror |= o_nofollow; @@ -565,8 +561,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`open`", reject_with)?; - this.set_last_error(ErrorKind::PermissionDenied)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied); } let fd = options @@ -584,8 +579,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let seek_from = if whence == this.eval_libc_i32("SEEK_SET") { if offset < 0 { // Negative offsets return `EINVAL`. - this.set_last_error(LibcError("EINVAL"))?; - return interp_ok(Scalar::from_i64(-1)); + return this.set_last_error_and_return_i64(LibcError("EINVAL")); } else { SeekFrom::Start(u64::try_from(offset).unwrap()) } @@ -594,14 +588,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } else if whence == this.eval_libc_i32("SEEK_END") { SeekFrom::End(i64::try_from(offset).unwrap()) } else { - this.set_last_error(LibcError("EINVAL"))?; - return interp_ok(Scalar::from_i64(-1)); + return this.set_last_error_and_return_i64(LibcError("EINVAL")); }; let communicate = this.machine.communicate(); let Some(fd) = this.machine.fds.get(fd_num) else { - return interp_ok(Scalar::from_i64(this.fd_not_found()?)); + return this.set_last_error_and_return_i64(LibcError("EBADF")); }; let result = fd.seek(communicate, seek_from)?.map(|offset| i64::try_from(offset).unwrap()); drop(fd); @@ -618,8 +611,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`unlink`", reject_with)?; - this.set_last_error(ErrorKind::PermissionDenied)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied); } let result = remove_file(path).map(|_| 0); @@ -649,8 +641,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`symlink`", reject_with)?; - this.set_last_error(ErrorKind::PermissionDenied)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied); } let result = create_link(&target, &linkpath).map(|_| 0); @@ -674,15 +665,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`stat`", reject_with)?; - let eacc = this.eval_libc("EACCES"); - this.set_last_error(eacc)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EACCES")); } // `stat` always follows symlinks. let metadata = match FileMetadata::from_path(this, &path, true)? { - Some(metadata) => metadata, - None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno + Ok(metadata) => metadata, + Err(err) => return this.set_last_error_and_return_i32(err), }; interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) @@ -706,14 +695,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`lstat`", reject_with)?; - let eacc = this.eval_libc("EACCES"); - this.set_last_error(eacc)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EACCES")); } let metadata = match FileMetadata::from_path(this, &path, false)? { - Some(metadata) => metadata, - None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno + Ok(metadata) => metadata, + Err(err) => return this.set_last_error_and_return_i32(err), }; interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) @@ -736,12 +723,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fstat`", reject_with)?; // Set error code as "EBADF" (bad fd) - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); } let metadata = match FileMetadata::from_fd_num(this, fd)? { - Some(metadata) => metadata, - None => return interp_ok(Scalar::from_i32(-1)), + Ok(metadata) => metadata, + Err(err) => return this.set_last_error_and_return_i32(err), }; interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) } @@ -766,9 +753,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If the statxbuf or pathname pointers are null, the function fails with `EFAULT`. if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? { - let efault = this.eval_libc("EFAULT"); - this.set_last_error(efault)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EFAULT")); } let statxbuf = this.deref_pointer_as(statxbuf_op, this.libc_ty_layout("statx"))?; @@ -801,16 +786,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ecode = if path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD") { // since `path` is provided, either absolute or // relative to CWD, `EACCES` is the most relevant. - this.eval_libc("EACCES") + LibcError("EACCES") } else { // `dirfd` is set to target file, and `path` is empty // (or we would have hit the `throw_unsup_format` // above). `EACCES` would violate the spec. assert!(empty_path_flag); - this.eval_libc("EBADF") + LibcError("EBADF") }; - this.set_last_error(ecode)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ecode); } // the `_mask_op` parameter specifies the file information that the caller requested. @@ -831,8 +815,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { FileMetadata::from_path(this, &path, follow_symlink)? }; let metadata = match metadata { - Some(metadata) => metadata, - None => return interp_ok(Scalar::from_i32(-1)), + Ok(metadata) => metadata, + Err(err) => return this.set_last_error_and_return_i32(err), }; // The `mode` field specifies the type of the file and the permissions over the file for @@ -939,9 +923,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let newpath_ptr = this.read_pointer(newpath_op)?; if this.ptr_is_null(oldpath_ptr)? || this.ptr_is_null(newpath_ptr)? { - let efault = this.eval_libc("EFAULT"); - this.set_last_error(efault)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EFAULT")); } let oldpath = this.read_path_from_c_str(oldpath_ptr)?; @@ -950,8 +932,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`rename`", reject_with)?; - this.set_last_error(ErrorKind::PermissionDenied)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied); } let result = rename(oldpath, newpath).map(|_| 0); @@ -974,8 +955,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`mkdir`", reject_with)?; - this.set_last_error(ErrorKind::PermissionDenied)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied); } #[cfg_attr(not(unix), allow(unused_mut))] @@ -1002,8 +982,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`rmdir`", reject_with)?; - this.set_last_error(ErrorKind::PermissionDenied)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied); } let result = remove_dir(path).map(|_| 0i32); @@ -1019,8 +998,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`opendir`", reject_with)?; - let eacc = this.eval_libc("EACCES"); - this.set_last_error(eacc)?; + this.set_last_error(LibcError("EACCES"))?; return interp_ok(Scalar::null_ptr(this)); } @@ -1052,8 +1030,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readdir`", reject_with)?; - let eacc = this.eval_libc("EBADF"); - this.set_last_error(eacc)?; + this.set_last_error(LibcError("EBADF"))?; return interp_ok(Scalar::null_ptr(this)); } @@ -1152,14 +1129,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readdir_r`", reject_with)?; - // Set error code as "EBADF" (bad fd) - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + // Return error code, do *not* set `errno`. + return interp_ok(this.eval_libc("EBADF")); } let open_dir = this.machine.dirs.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir") })?; - interp_ok(Scalar::from_i32(match open_dir.read_dir.next() { + interp_ok(match open_dir.read_dir.next() { Some(Ok(dir_entry)) => { // Write into entry, write pointer to result, return 0 on success. // The name is written with write_os_str_to_c_str, while the rest of the @@ -1237,25 +1214,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result_place = this.deref_pointer(result_op)?; this.write_scalar(this.read_scalar(entry_op)?, &result_place)?; - 0 + Scalar::from_i32(0) } None => { // end of stream: return 0, assign *result=NULL this.write_null(&this.deref_pointer(result_op)?)?; - 0 + Scalar::from_i32(0) } - Some(Err(e)) => - match e.raw_os_error() { - // return positive error number on error - Some(error) => error, - None => { - throw_unsup_format!( - "the error {} couldn't be converted to a return value", - e - ) - } - }, - })) + Some(Err(e)) => { + // return positive error number on error (do *not* set last error) + this.io_error_to_errnum(e)? + } + }) } fn closedir(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { @@ -1264,20 +1234,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let dirp = this.read_target_usize(dirp_op)?; // Reject if isolation is enabled. - interp_ok(Scalar::from_i32( - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`closedir`", reject_with)?; - this.fd_not_found()? - } else if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) { - if let Some(entry) = open_dir.entry { - this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?; - } - drop(open_dir); - 0 - } else { - this.fd_not_found()? - }, - )) + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`closedir`", reject_with)?; + return this.set_last_error_and_return_i32(LibcError("EBADF")); + } + + let Some(mut open_dir) = this.machine.dirs.streams.remove(&dirp) else { + return this.set_last_error_and_return_i32(LibcError("EBADF")); + }; + if let Some(entry) = open_dir.entry.take() { + this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?; + } + // We drop the `open_dir`, which will close the host dir handle. + drop(open_dir); + + interp_ok(Scalar::from_i32(0)) } fn ftruncate64(&mut self, fd_num: i32, length: i128) -> InterpResult<'tcx, Scalar> { @@ -1287,11 +1258,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`ftruncate64`", reject_with)?; // Set error code as "EBADF" (bad fd) - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); } let Some(fd) = this.machine.fds.get(fd_num) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; // FIXME: Support ftruncate64 for all FDs @@ -1307,14 +1278,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(Scalar::from_i32(result)) } else { drop(fd); - this.set_last_error(LibcError("EINVAL"))?; - interp_ok(Scalar::from_i32(-1)) + this.set_last_error_and_return_i32(LibcError("EINVAL")) } } else { drop(fd); // The file is not writable - this.set_last_error(LibcError("EINVAL"))?; - interp_ok(Scalar::from_i32(-1)) + this.set_last_error_and_return_i32(LibcError("EINVAL")) } } @@ -1332,7 +1301,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fsync`", reject_with)?; // Set error code as "EBADF" (bad fd) - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); } self.ffullsync_fd(fd) @@ -1341,7 +1310,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn ffullsync_fd(&mut self, fd_num: i32) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let Some(fd) = this.machine.fds.get(fd_num) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; // Only regular files support synchronization. let FileHandle { file, writable } = fd.downcast::().ok_or_else(|| { @@ -1361,11 +1330,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fdatasync`", reject_with)?; // Set error code as "EBADF" (bad fd) - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); } let Some(fd) = this.machine.fds.get(fd) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; // Only regular files support synchronization. let FileHandle { file, writable } = fd.downcast::().ok_or_else(|| { @@ -1391,26 +1360,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let flags = this.read_scalar(flags_op)?.to_i32()?; if offset < 0 || nbytes < 0 { - this.set_last_error(LibcError("EINVAL"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); } let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE") | this.eval_libc_i32("SYNC_FILE_RANGE_WRITE") | this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_AFTER"); if flags & allowed_flags != flags { - this.set_last_error(LibcError("EINVAL"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); } // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`sync_file_range`", reject_with)?; // Set error code as "EBADF" (bad fd) - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); } let Some(fd) = this.machine.fds.get(fd) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; // Only regular files support synchronization. let FileHandle { file, writable } = fd.downcast::().ok_or_else(|| { @@ -1436,8 +1403,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readlink`", reject_with)?; - let eacc = this.eval_libc("EACCES"); - this.set_last_error(eacc)?; + this.set_last_error(LibcError("EACCES"))?; return interp_ok(-1); } @@ -1475,11 +1441,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if fd.is_tty(this.machine.communicate()) { return interp_ok(Scalar::from_i32(1)); } else { - this.eval_libc("ENOTTY") + LibcError("ENOTTY") } } else { // FD does not exist - this.eval_libc("EBADF") + LibcError("EBADF") }; this.set_last_error(error)?; interp_ok(Scalar::from_i32(0)) @@ -1499,8 +1465,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`realpath`", reject_with)?; - let eacc = this.eval_libc("EACCES"); - this.set_last_error(eacc)?; + this.set_last_error(LibcError("EACCES"))?; return interp_ok(Scalar::from_target_usize(0, this)); } @@ -1530,8 +1495,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Note that we do not explicitly handle `FILENAME_MAX` // (different from `PATH_MAX` above) as it is Linux-specific and // seems like a bit of a mess anyway: . - let enametoolong = this.eval_libc("ENAMETOOLONG"); - this.set_last_error(enametoolong)?; + this.set_last_error(LibcError("ENAMETOOLONG"))?; return interp_ok(Scalar::from_target_usize(0, this)); } processed_ptr @@ -1574,9 +1538,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`mkstemp`", reject_with)?; - let eacc = this.eval_libc("EACCES"); - this.set_last_error(eacc)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EACCES")); } // Get the bytes of the suffix we expect in _target_ encoding. @@ -1592,8 +1554,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If we don't find the suffix, it is an error. if last_six_char_bytes != suffix_bytes { - this.set_last_error(LibcError("EINVAL"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); } // At this point we know we have 6 ASCII 'X' characters as a suffix. @@ -1658,17 +1619,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => { // "On error, -1 is returned, and errno is set to // indicate the error" - this.set_last_error(e)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(e); } }, } } // We ran out of attempts to create the file, return an error. - let eexist = this.eval_libc("EEXIST"); - this.set_last_error(eexist)?; - interp_ok(Scalar::from_i32(-1)) + this.set_last_error_and_return_i32(LibcError("EEXIST")) } } @@ -1702,7 +1660,7 @@ impl FileMetadata { ecx: &mut MiriInterpCx<'tcx>, path: &Path, follow_symlink: bool, - ) -> InterpResult<'tcx, Option> { + ) -> InterpResult<'tcx, Result> { let metadata = if follow_symlink { std::fs::metadata(path) } else { std::fs::symlink_metadata(path) }; @@ -1712,9 +1670,9 @@ impl FileMetadata { fn from_fd_num<'tcx>( ecx: &mut MiriInterpCx<'tcx>, fd_num: i32, - ) -> InterpResult<'tcx, Option> { + ) -> InterpResult<'tcx, Result> { let Some(fd) = ecx.machine.fds.get(fd_num) else { - return ecx.fd_not_found().map(|_: i32| None); + return interp_ok(Err(LibcError("EBADF"))); }; let file = &fd @@ -1734,12 +1692,11 @@ impl FileMetadata { fn from_meta<'tcx>( ecx: &mut MiriInterpCx<'tcx>, metadata: Result, - ) -> InterpResult<'tcx, Option> { + ) -> InterpResult<'tcx, Result> { let metadata = match metadata { Ok(metadata) => metadata, Err(e) => { - ecx.set_last_error(e)?; - return interp_ok(None); + return interp_ok(Err(e.into())); } }; @@ -1762,6 +1719,6 @@ impl FileMetadata { let modified = extract_sec_and_nsec(metadata.modified())?; // FIXME: Provide more fields using platform specific methods. - interp_ok(Some(FileMetadata { mode, size, created, accessed, modified })) + interp_ok(Ok(FileMetadata { mode, size, created, accessed, modified })) } } diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index cafc7161d26..de108665e9f 100644 --- a/src/tools/miri/src/shims/unix/linux/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -256,23 +256,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let epollhup = this.eval_libc_u32("EPOLLHUP"); let epollerr = this.eval_libc_u32("EPOLLERR"); - // Fail on unsupported operations. - if op & epoll_ctl_add != epoll_ctl_add - && op & epoll_ctl_mod != epoll_ctl_mod - && op & epoll_ctl_del != epoll_ctl_del - { - throw_unsup_format!("epoll_ctl: encountered unknown unsupported operation {:#x}", op); - } - // Throw EINVAL if epfd and fd have the same value. if epfd_value == fd { - this.set_last_error(LibcError("EINVAL"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); } // Check if epfd is a valid epoll file descriptor. let Some(epfd) = this.machine.fds.get(epfd_value) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; let epoll_file_description = epfd .downcast::() @@ -282,7 +273,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ready_list = &epoll_file_description.ready_list; let Some(fd_ref) = this.machine.fds.get(fd) else { - return interp_ok(Scalar::from_i32(this.fd_not_found()?)); + return this.set_last_error_and_return_i32(LibcError("EBADF")); }; let id = fd_ref.get_id(); @@ -332,15 +323,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Check the existence of fd in the interest list. if op == epoll_ctl_add { if interest_list.contains_key(&epoll_key) { - let eexist = this.eval_libc("EEXIST"); - this.set_last_error(eexist)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EEXIST")); } } else { if !interest_list.contains_key(&epoll_key) { - let enoent = this.eval_libc("ENOENT"); - this.set_last_error(enoent)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("ENOENT")); } } @@ -368,15 +355,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Notification will be returned for current epfd if there is event in the file // descriptor we registered. check_and_update_one_event_interest(&fd_ref, interest, id, this)?; - return interp_ok(Scalar::from_i32(0)); + interp_ok(Scalar::from_i32(0)) } else if op == epoll_ctl_del { let epoll_key = (id, fd); // Remove epoll_event_interest from interest_list. let Some(epoll_interest) = interest_list.remove(&epoll_key) else { - let enoent = this.eval_libc("ENOENT"); - this.set_last_error(enoent)?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("ENOENT")); }; // All related Weak will fail to upgrade after the drop. drop(epoll_interest); @@ -394,9 +379,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .unwrap() .retain(|event| event.upgrade().is_some()); - return interp_ok(Scalar::from_i32(0)); + interp_ok(Scalar::from_i32(0)) + } else { + throw_unsup_format!("unsupported epoll_ctl operation: {op}"); } - interp_ok(Scalar::from_i32(-1)) } /// The `epoll_wait()` system call waits for events on the `Epoll` @@ -447,9 +433,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let timeout = this.read_scalar(timeout)?.to_i32()?; if epfd_value <= 0 || maxevents <= 0 { - this.set_last_error(LibcError("EINVAL"))?; - this.write_int(-1, dest)?; - return interp_ok(()); + return this.set_last_error_and_return(LibcError("EINVAL"), dest); } // This needs to come after the maxevents value check, or else maxevents.try_into().unwrap() @@ -460,9 +444,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; let Some(epfd) = this.machine.fds.get(epfd_value) else { - let result_value: i32 = this.fd_not_found()?; - this.write_int(result_value, dest)?; - return interp_ok(()); + return this.set_last_error_and_return(LibcError("EBADF"), dest); }; // Create a weak ref of epfd and pass it to callback so we will make sure that epfd // is not close after the thread unblocks. diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index e73bde1ddb6..6616a9845c0 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -84,6 +84,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.read_scalar(thread)?, this.read_scalar(name)?, TASK_COMM_LEN, + /* truncate */ false, )?; let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") }; this.write_scalar(res, dest)?; diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs index 4f2e17d50c8..d5f9669b360 100644 --- a/src/tools/miri/src/shims/unix/linux/mem.rs +++ b/src/tools/miri/src/shims/unix/linux/mem.rs @@ -24,7 +24,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // old_address must be a multiple of the page size #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero if old_address.addr().bytes() % this.machine.page_size != 0 || new_size == 0 { - this.set_last_error(this.eval_libc("EINVAL"))?; + this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); } @@ -38,7 +38,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if flags & this.eval_libc_i32("MREMAP_MAYMOVE") == 0 { // We only support MREMAP_MAYMOVE, so not passing the flag is just a failure - this.set_last_error(this.eval_libc("EINVAL"))?; + this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); } diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index 941011bfac6..c258be78f76 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -63,8 +63,7 @@ pub fn futex<'tcx>( }; if bitset == 0 { - this.set_last_error(LibcError("EINVAL"))?; - this.write_scalar(Scalar::from_target_isize(-1, this), dest)?; + this.set_last_error_and_return(LibcError("EINVAL"), dest)?; return interp_ok(()); } @@ -75,9 +74,7 @@ pub fn futex<'tcx>( let duration = match this.read_timespec(&timeout)? { Some(duration) => duration, None => { - this.set_last_error(LibcError("EINVAL"))?; - this.write_scalar(Scalar::from_target_isize(-1, this), dest)?; - return interp_ok(()); + return this.set_last_error_and_return(LibcError("EINVAL"), dest); } }; let timeout_clock = if op & futex_realtime == futex_realtime { @@ -153,14 +150,12 @@ pub fn futex<'tcx>( Scalar::from_target_isize(0, this), // retval_succ Scalar::from_target_isize(-1, this), // retval_timeout dest.clone(), - this.eval_libc("ETIMEDOUT"), + this.eval_libc("ETIMEDOUT"), // errno_timeout ); } else { // The futex value doesn't match the expected value, so we return failure // right away without sleeping: -1 and errno set to EAGAIN. - let eagain = this.eval_libc("EAGAIN"); - this.set_last_error(eagain)?; - this.write_scalar(Scalar::from_target_isize(-1, this), dest)?; + return this.set_last_error_and_return(LibcError("EAGAIN"), dest); } } // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val) @@ -180,9 +175,7 @@ pub fn futex<'tcx>( u32::MAX }; if bitset == 0 { - this.set_last_error(LibcError("EINVAL"))?; - this.write_scalar(Scalar::from_target_isize(-1, this), dest)?; - return interp_ok(()); + return this.set_last_error_and_return(LibcError("EINVAL"), dest); } // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait // will see the latest value on addr which could be changed by our caller diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index b199992245c..cd07bc9e013 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -181,6 +181,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { thread, this.read_scalar(name)?, this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?.try_into().unwrap(), + /* truncate */ false, )? { Scalar::from_u32(0) } else { diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs index 9273748ef3b..9371edfc83d 100644 --- a/src/tools/miri/src/shims/unix/mem.rs +++ b/src/tools/miri/src/shims/unix/mem.rs @@ -57,11 +57,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // First, we do some basic argument validation as required by mmap if (flags & (map_private | map_shared)).count_ones() != 1 { - this.set_last_error(this.eval_libc("EINVAL"))?; + this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); } if length == 0 { - this.set_last_error(this.eval_libc("EINVAL"))?; + this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); } @@ -103,11 +103,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let align = this.machine.page_align(); let Some(map_length) = length.checked_next_multiple_of(this.machine.page_size) else { - this.set_last_error(this.eval_libc("EINVAL"))?; + this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); }; if map_length > this.target_usize_max() { - this.set_last_error(this.eval_libc("EINVAL"))?; + this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); } @@ -134,16 +134,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // as a dealloc. #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero if addr.addr().bytes() % this.machine.page_size != 0 { - this.set_last_error(this.eval_libc("EINVAL"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); } let Some(length) = length.checked_next_multiple_of(this.machine.page_size) else { - this.set_last_error(this.eval_libc("EINVAL"))?; - return interp_ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(LibcError("EINVAL")); }; if length > this.target_usize_max() { - this.set_last_error(this.eval_libc("EINVAL"))?; + this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); } diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index 7f3d0f07bdc..c9c1b01b8b1 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -30,6 +30,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.read_scalar(thread)?, this.read_scalar(name)?, max_len, + /* truncate */ false, )?; let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") }; this.write_scalar(res, dest)?; diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs index 7f97afc8e4b..51256d800a4 100644 --- a/src/tools/miri/src/shims/unix/thread.rs +++ b/src/tools/miri/src/shims/unix/thread.rs @@ -64,23 +64,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Set the name of the specified thread. If the name including the null terminator - /// is longer than `name_max_len`, then `false` is returned. + /// is longer or equals to `name_max_len`, then if `truncate` is set the truncated name + /// is used as the thread name, otherwise `false` is returned. fn pthread_setname_np( &mut self, thread: Scalar, name: Scalar, name_max_len: usize, + truncate: bool, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?; let thread = ThreadId::try_from(thread).unwrap(); let name = name.to_pointer(this)?; - let name = this.read_c_str(name)?.to_owned(); + let mut name = this.read_c_str(name)?.to_owned(); // Comparing with `>=` to account for null terminator. if name.len() >= name_max_len { - return interp_ok(false); + if truncate { + name.truncate(name_max_len.saturating_sub(1)); + } else { + return interp_ok(false); + } } this.set_thread_name(thread, name); diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index f8861085fe5..f7566a8112d 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -202,7 +202,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Scalar::from_i32(1), // retval_succ Scalar::from_i32(0), // retval_timeout dest.clone(), - this.eval_windows("c", "ERROR_TIMEOUT"), + this.eval_windows("c", "ERROR_TIMEOUT"), // errno_timeout ); } diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock index 64bfc84ef20..0a5e9f62dd9 100644 --- a/src/tools/miri/test_dependencies/Cargo.lock +++ b/src/tools/miri/test_dependencies/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 = "addr2line" @@ -128,9 +128,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "linux-raw-sys" diff --git a/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs new file mode 100644 index 00000000000..4b731866aca --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs @@ -0,0 +1,10 @@ +//! Ensure we report UB when the buffer is smaller than 16 bytes (even if the thread +//! name would fit in the smaller buffer). +//@only-target: android # Miri supports prctl for Android only + +fn main() { + let mut buf = vec![0u8; 15]; + unsafe { + libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr().cast::()); //~ ERROR: memory access failed: expected a pointer to 16 bytes of memory, but got alloc952 which is only 15 bytes from the end of the allocation + } +} diff --git a/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr new file mode 100644 index 00000000000..275a38e593c --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr @@ -0,0 +1,21 @@ +error: Undefined Behavior: memory access failed: expected a pointer to 16 bytes of memory, but got ALLOC which is only 15 bytes from the end of the allocation + --> tests/fail-dep/libc/prctl-threadname.rs:LL:CC + | +LL | libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr().cast::()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 16 bytes of memory, but got ALLOC which is only 15 bytes from the end of the allocation + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: ALLOC was allocated here: + --> tests/fail-dep/libc/prctl-threadname.rs:LL:CC + | +LL | let mut buf = vec![0u8; 15]; + | ^^^^^^^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail-dep/libc/prctl-threadname.rs:LL:CC + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs index f4c009456d2..55491da9f60 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs @@ -1,7 +1,7 @@ //! This is a regression test for : we had some //! faulty logic around `release_clock` that led to this code not reporting a data race. //@ignore-target: windows # no libc socketpair on Windows -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0 use std::thread; fn main() { diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs index d4479f32e56..c91f4ec158f 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs +++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs @@ -1,4 +1,3 @@ - // Ensure that a `ptr::without_provenance` ptr is truly invalid. fn main() { let x = 42; diff --git a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs new file mode 100644 index 00000000000..b69f7ee9dff --- /dev/null +++ b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs @@ -0,0 +1,16 @@ +#![feature(explicit_tail_calls)] +#![allow(incomplete_features)] + +fn g(x: *const i32) { + let _val = unsafe { *x }; //~ERROR: has been freed, so this pointer is dangling +} + +fn f(_x: *const i32) { + let local = 0; + let ptr = &local as *const i32; + become g(ptr) +} + +fn main() { + f(std::ptr::null()); +} diff --git a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr new file mode 100644 index 00000000000..6acd69ab3f8 --- /dev/null +++ b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr @@ -0,0 +1,30 @@ +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling + --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC + | +LL | let _val = unsafe { *x }; + | ^^ memory access failed: ALLOC has been freed, so this pointer is dangling + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: ALLOC was allocated here: + --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC + | +LL | let local = 0; + | ^^^^^ +help: ALLOC was deallocated here: + --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC + | +LL | } + | ^ + = note: BACKTRACE (of the first span): + = note: inside `g` at tests/fail/tail_calls/dangling-local-var.rs:LL:CC +note: inside `main` + --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC + | +LL | f(std::ptr::null()); + | ^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs b/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs new file mode 100644 index 00000000000..87ae3753fea --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs @@ -0,0 +1,74 @@ +//@only-target: android # Miri supports prctl for Android only +use std::ffi::{CStr, CString}; +use std::thread; + +// The Linux kernel all names 16 bytes long including the null terminator. +const MAX_THREAD_NAME_LEN: usize = 16; + +fn main() { + // The short name should be shorter than 16 bytes which POSIX promises + // for thread names. The length includes a null terminator. + let short_name = "test_named".to_owned(); + let long_name = std::iter::once("test_named_thread_truncation") + .chain(std::iter::repeat(" yada").take(100)) + .collect::(); + + fn set_thread_name(name: &CStr) -> i32 { + unsafe { libc::prctl(libc::PR_SET_NAME, name.as_ptr().cast::()) } + } + + fn get_thread_name(name: &mut [u8]) -> i32 { + assert!(name.len() >= MAX_THREAD_NAME_LEN); + unsafe { libc::prctl(libc::PR_GET_NAME, name.as_mut_ptr().cast::()) } + } + + // Set name via Rust API, get it via prctl. + let long_name2 = long_name.clone(); + thread::Builder::new() + .name(long_name.clone()) + .spawn(move || { + let mut buf = vec![0u8; MAX_THREAD_NAME_LEN]; + assert_eq!(get_thread_name(&mut buf), 0); + let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); + let truncated_name = &long_name2[..long_name2.len().min(MAX_THREAD_NAME_LEN - 1)]; + assert_eq!(cstr.to_bytes(), truncated_name.as_bytes()); + }) + .unwrap() + .join() + .unwrap(); + + // Set name via prctl and get it again (short name). + thread::Builder::new() + .spawn(move || { + // Set short thread name. + let cstr = CString::new(short_name.clone()).unwrap(); + assert!(cstr.to_bytes_with_nul().len() <= MAX_THREAD_NAME_LEN); // this should fit + assert_eq!(set_thread_name(&cstr), 0); + + let mut buf = vec![0u8; MAX_THREAD_NAME_LEN]; + assert_eq!(get_thread_name(&mut buf), 0); + let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); + assert_eq!(cstr.to_bytes(), short_name.as_bytes()); + }) + .unwrap() + .join() + .unwrap(); + + // Set name via prctl and get it again (long name). + thread::Builder::new() + .spawn(move || { + // Set full thread name. + let cstr = CString::new(long_name.clone()).unwrap(); + assert!(cstr.to_bytes_with_nul().len() > MAX_THREAD_NAME_LEN); + // Names are truncated by the Linux kernel. + assert_eq!(set_thread_name(&cstr), 0); + + let mut buf = vec![0u8; MAX_THREAD_NAME_LEN]; + assert_eq!(get_thread_name(&mut buf), 0); + let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); + assert_eq!(cstr.to_bytes(), &long_name.as_bytes()[..(MAX_THREAD_NAME_LEN - 1)]); + }) + .unwrap() + .join() + .unwrap(); +} diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs index 404ef7cc42d..0e5b501bbcc 100644 --- a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs @@ -1,4 +1,5 @@ //@ignore-target: windows # No pthreads on Windows +//@ignore-target: android # No pthread_{get,set}_name on Android use std::ffi::{CStr, CString}; use std::thread; @@ -65,6 +66,22 @@ fn main() { } } + // Set name via Rust API, get it via pthreads. + let long_name2 = long_name.clone(); + thread::Builder::new() + .name(long_name.clone()) + .spawn(move || { + let mut buf = vec![0u8; long_name2.len() + 1]; + assert_eq!(get_thread_name(&mut buf), 0); + let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); + let truncated_name = &long_name2[..long_name2.len().min(MAX_THREAD_NAME_LEN - 1)]; + assert_eq!(cstr.to_bytes(), truncated_name.as_bytes()); + }) + .unwrap() + .join() + .unwrap(); + + // Set name via pthread and get it again (short name). thread::Builder::new() .spawn(move || { // Set short thread name. @@ -130,6 +147,7 @@ fn main() { .join() .unwrap(); + // Set name via pthread and get it again (long name). thread::Builder::new() .spawn(move || { // Set full thread name. diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs index 306e9ab9c67..61410f7c4e0 100644 --- a/src/tools/miri/tests/pass/dyn-upcast.rs +++ b/src/tools/miri/tests/pass/dyn-upcast.rs @@ -433,7 +433,8 @@ fn replace_vptr() { } fn drop_principal() { - use std::{alloc::Layout, any::Any}; + use std::alloc::Layout; + use std::any::Any; const fn yeet_principal(x: Box) -> Box { x diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 853d3e80517..66843ca584b 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -157,13 +157,18 @@ fn basic() { assert_eq(-{ 5.0_f128 }, -5.0_f128); // infinities, NaN - // FIXME(f16_f128): add when constants and `is_infinite` are available + assert!((5.0_f16 / 0.0).is_infinite()); + assert_ne!({ 5.0_f16 / 0.0 }, { -5.0_f16 / 0.0 }); assert!((5.0_f32 / 0.0).is_infinite()); assert_ne!({ 5.0_f32 / 0.0 }, { -5.0_f32 / 0.0 }); assert!((5.0_f64 / 0.0).is_infinite()); assert_ne!({ 5.0_f64 / 0.0 }, { 5.0_f64 / -0.0 }); + assert!((5.0_f128 / 0.0).is_infinite()); + assert_ne!({ 5.0_f128 / 0.0 }, { 5.0_f128 / -0.0 }); + assert_ne!(f16::NAN, f16::NAN); assert_ne!(f32::NAN, f32::NAN); assert_ne!(f64::NAN, f64::NAN); + assert_ne!(f128::NAN, f128::NAN); // negative zero let posz = 0.0f16; @@ -215,9 +220,14 @@ fn basic() { assert!((black_box(-1.0f128) % 1.0).is_sign_negative()); assert!((black_box(-1.0f128) % -1.0).is_sign_negative()); - // FIXME(f16_f128): add when `abs` is available + assert_eq!((-1.0f16).abs(), 1.0f16); + assert_eq!(34.2f16.abs(), 34.2f16); assert_eq!((-1.0f32).abs(), 1.0f32); + assert_eq!(34.2f32.abs(), 34.2f32); + assert_eq!((-1.0f64).abs(), 1.0f64); assert_eq!(34.2f64.abs(), 34.2f64); + assert_eq!((-1.0f128).abs(), 1.0f128); + assert_eq!(34.2f128.abs(), 34.2f128); } /// Test casts from floats to ints and back @@ -654,6 +664,14 @@ fn casts() { } fn ops() { + // f16 min/max + assert_eq((1.0_f16).max(-1.0), 1.0); + assert_eq((1.0_f16).min(-1.0), -1.0); + assert_eq(f16::NAN.min(9.0), 9.0); + assert_eq(f16::NAN.max(-9.0), -9.0); + assert_eq((9.0_f16).min(f16::NAN), 9.0); + assert_eq((-9.0_f16).max(f16::NAN), -9.0); + // f32 min/max assert_eq((1.0 as f32).max(-1.0), 1.0); assert_eq((1.0 as f32).min(-1.0), -1.0); @@ -670,6 +688,21 @@ fn ops() { assert_eq((9.0 as f64).min(f64::NAN), 9.0); assert_eq((-9.0 as f64).max(f64::NAN), -9.0); + // f128 min/max + assert_eq((1.0_f128).max(-1.0), 1.0); + assert_eq((1.0_f128).min(-1.0), -1.0); + assert_eq(f128::NAN.min(9.0), 9.0); + assert_eq(f128::NAN.max(-9.0), -9.0); + assert_eq((9.0_f128).min(f128::NAN), 9.0); + assert_eq((-9.0_f128).max(f128::NAN), -9.0); + + // f16 copysign + assert_eq(3.5_f16.copysign(0.42), 3.5_f16); + assert_eq(3.5_f16.copysign(-0.42), -3.5_f16); + assert_eq((-3.5_f16).copysign(0.42), 3.5_f16); + assert_eq((-3.5_f16).copysign(-0.42), -3.5_f16); + assert!(f16::NAN.copysign(1.0).is_nan()); + // f32 copysign assert_eq(3.5_f32.copysign(0.42), 3.5_f32); assert_eq(3.5_f32.copysign(-0.42), -3.5_f32); @@ -683,6 +716,13 @@ fn ops() { assert_eq((-3.5_f64).copysign(0.42), 3.5_f64); assert_eq((-3.5_f64).copysign(-0.42), -3.5_f64); assert!(f64::NAN.copysign(1.0).is_nan()); + + // f128 copysign + assert_eq(3.5_f128.copysign(0.42), 3.5_f128); + assert_eq(3.5_f128.copysign(-0.42), -3.5_f128); + assert_eq((-3.5_f128).copysign(0.42), 3.5_f128); + assert_eq((-3.5_f128).copysign(-0.42), -3.5_f128); + assert!(f128::NAN.copysign(1.0).is_nan()); } /// Tests taken from rustc test suite. @@ -807,6 +847,18 @@ fn nan_casts() { fn rounding() { // Test cases taken from the library's tests for this feature + // f16 + assert_eq(2.5f16.round_ties_even(), 2.0f16); + assert_eq(1.0f16.round_ties_even(), 1.0f16); + assert_eq(1.3f16.round_ties_even(), 1.0f16); + assert_eq(1.5f16.round_ties_even(), 2.0f16); + assert_eq(1.7f16.round_ties_even(), 2.0f16); + assert_eq(0.0f16.round_ties_even(), 0.0f16); + assert_eq((-0.0f16).round_ties_even(), -0.0f16); + assert_eq((-1.0f16).round_ties_even(), -1.0f16); + assert_eq((-1.3f16).round_ties_even(), -1.0f16); + assert_eq((-1.5f16).round_ties_even(), -2.0f16); + assert_eq((-1.7f16).round_ties_even(), -2.0f16); // f32 assert_eq(2.5f32.round_ties_even(), 2.0f32); assert_eq(1.0f32.round_ties_even(), 1.0f32); @@ -831,23 +883,59 @@ fn rounding() { assert_eq((-1.3f64).round_ties_even(), -1.0f64); assert_eq((-1.5f64).round_ties_even(), -2.0f64); assert_eq((-1.7f64).round_ties_even(), -2.0f64); + // f128 + assert_eq(2.5f128.round_ties_even(), 2.0f128); + assert_eq(1.0f128.round_ties_even(), 1.0f128); + assert_eq(1.3f128.round_ties_even(), 1.0f128); + assert_eq(1.5f128.round_ties_even(), 2.0f128); + assert_eq(1.7f128.round_ties_even(), 2.0f128); + assert_eq(0.0f128.round_ties_even(), 0.0f128); + assert_eq((-0.0f128).round_ties_even(), -0.0f128); + assert_eq((-1.0f128).round_ties_even(), -1.0f128); + assert_eq((-1.3f128).round_ties_even(), -1.0f128); + assert_eq((-1.5f128).round_ties_even(), -2.0f128); + assert_eq((-1.7f128).round_ties_even(), -2.0f128); + assert_eq!(3.8f16.floor(), 3.0f16); + assert_eq!((-1.1f16).floor(), -2.0f16); assert_eq!(3.8f32.floor(), 3.0f32); + assert_eq!((-1.1f32).floor(), -2.0f32); + assert_eq!(3.8f64.floor(), 3.0f64); assert_eq!((-1.1f64).floor(), -2.0f64); + assert_eq!(3.8f128.floor(), 3.0f128); + assert_eq!((-1.1f128).floor(), -2.0f128); + assert_eq!(3.8f16.ceil(), 4.0f16); + assert_eq!((-2.3f16).ceil(), -2.0f16); + assert_eq!(3.8f32.ceil(), 4.0f32); assert_eq!((-2.3f32).ceil(), -2.0f32); assert_eq!(3.8f64.ceil(), 4.0f64); + assert_eq!((-2.3f64).ceil(), -2.0f64); + assert_eq!(3.8f128.ceil(), 4.0f128); + assert_eq!((-2.3f128).ceil(), -2.0f128); + assert_eq!(0.1f16.trunc(), 0.0f16); + assert_eq!((-0.1f16).trunc(), 0.0f16); assert_eq!(0.1f32.trunc(), 0.0f32); + assert_eq!((-0.1f32).trunc(), 0.0f32); + assert_eq!(0.1f64.trunc(), 0.0f64); assert_eq!((-0.1f64).trunc(), 0.0f64); + assert_eq!(0.1f128.trunc(), 0.0f128); + assert_eq!((-0.1f128).trunc(), 0.0f128); + assert_eq!(3.3_f16.round(), 3.0); + assert_eq!(2.5_f16.round(), 3.0); assert_eq!(3.3_f32.round(), 3.0); assert_eq!(2.5_f32.round(), 3.0); assert_eq!(3.9_f64.round(), 4.0); assert_eq!(2.5_f64.round(), 3.0); + assert_eq!(3.9_f128.round(), 4.0); + assert_eq!(2.5_f128.round(), 3.0); } fn mul_add() { + // FIXME(f16_f128): add when supported + assert_eq!(3.0f32.mul_add(2.0f32, 5.0f32), 11.0); assert_eq!(0.0f32.mul_add(-2.0, f32::consts::E), f32::consts::E); assert_eq!(3.0f64.mul_add(2.0, 5.0), 11.0); @@ -983,7 +1071,7 @@ fn test_fast() { use std::intrinsics::{fadd_fast, fdiv_fast, fmul_fast, frem_fast, fsub_fast}; #[inline(never)] - pub fn test_operations_f64(a: f64, b: f64) { + pub fn test_operations_f16(a: f16, b: f16) { // make sure they all map to the correct operation unsafe { assert_eq!(fadd_fast(a, b), a + b); @@ -1006,10 +1094,38 @@ fn test_fast() { } } - test_operations_f64(1., 2.); - test_operations_f64(10., 5.); + #[inline(never)] + pub fn test_operations_f64(a: f64, b: f64) { + // make sure they all map to the correct operation + unsafe { + assert_eq!(fadd_fast(a, b), a + b); + assert_eq!(fsub_fast(a, b), a - b); + assert_eq!(fmul_fast(a, b), a * b); + assert_eq!(fdiv_fast(a, b), a / b); + assert_eq!(frem_fast(a, b), a % b); + } + } + + #[inline(never)] + pub fn test_operations_f128(a: f128, b: f128) { + // make sure they all map to the correct operation + unsafe { + assert_eq!(fadd_fast(a, b), a + b); + assert_eq!(fsub_fast(a, b), a - b); + assert_eq!(fmul_fast(a, b), a * b); + assert_eq!(fdiv_fast(a, b), a / b); + assert_eq!(frem_fast(a, b), a % b); + } + } + + test_operations_f16(11., 2.); + test_operations_f16(10., 15.); test_operations_f32(11., 2.); test_operations_f32(10., 15.); + test_operations_f64(1., 2.); + test_operations_f64(10., 5.); + test_operations_f128(1., 2.); + test_operations_f128(10., 5.); } fn test_algebraic() { @@ -1018,7 +1134,7 @@ fn test_algebraic() { }; #[inline(never)] - pub fn test_operations_f64(a: f64, b: f64) { + pub fn test_operations_f16(a: f16, b: f16) { // make sure they all map to the correct operation assert_eq!(fadd_algebraic(a, b), a + b); assert_eq!(fsub_algebraic(a, b), a - b); @@ -1037,15 +1153,41 @@ fn test_algebraic() { assert_eq!(frem_algebraic(a, b), a % b); } - test_operations_f64(1., 2.); - test_operations_f64(10., 5.); + #[inline(never)] + pub fn test_operations_f64(a: f64, b: f64) { + // make sure they all map to the correct operation + assert_eq!(fadd_algebraic(a, b), a + b); + assert_eq!(fsub_algebraic(a, b), a - b); + assert_eq!(fmul_algebraic(a, b), a * b); + assert_eq!(fdiv_algebraic(a, b), a / b); + assert_eq!(frem_algebraic(a, b), a % b); + } + + #[inline(never)] + pub fn test_operations_f128(a: f128, b: f128) { + // make sure they all map to the correct operation + assert_eq!(fadd_algebraic(a, b), a + b); + assert_eq!(fsub_algebraic(a, b), a - b); + assert_eq!(fmul_algebraic(a, b), a * b); + assert_eq!(fdiv_algebraic(a, b), a / b); + assert_eq!(frem_algebraic(a, b), a % b); + } + + test_operations_f16(11., 2.); + test_operations_f16(10., 15.); test_operations_f32(11., 2.); test_operations_f32(10., 15.); + test_operations_f64(1., 2.); + test_operations_f64(10., 5.); + test_operations_f128(1., 2.); + test_operations_f128(10., 5.); } fn test_fmuladd() { use std::intrinsics::{fmuladdf32, fmuladdf64}; + // FIXME(f16_f128): add when supported + #[inline(never)] pub fn test_operations_f32(a: f32, b: f32, c: f32) { assert_approx_eq!(unsafe { fmuladdf32(a, b, c) }, a * b + c); diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index d3605cd3dce..3affa199fa5 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -13,3 +13,6 @@ gimli = "0.31.0" build_helper = { path = "../build_helper" } serde_json = "1.0" libc = "0.2" + +[lib] +crate-type = ["lib", "dylib"] diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index 6b58173b343..9e09527d6d0 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -222,6 +222,12 @@ pub struct CompletedProcess { } impl CompletedProcess { + #[must_use] + #[track_caller] + pub fn stdout(&self) -> Vec { + self.output.stdout.clone() + } + #[must_use] #[track_caller] pub fn stdout_utf8(&self) -> String { @@ -234,12 +240,24 @@ impl CompletedProcess { String::from_utf8_lossy(&self.output.stdout.clone()).to_string() } + #[must_use] + #[track_caller] + pub fn stderr(&self) -> Vec { + self.output.stderr.clone() + } + #[must_use] #[track_caller] pub fn stderr_utf8(&self) -> String { String::from_utf8(self.output.stderr.clone()).expect("stderr is not valid UTF-8") } + #[must_use] + #[track_caller] + pub fn invalid_stderr_utf8(&self) -> String { + String::from_utf8_lossy(&self.output.stderr.clone()).to_string() + } + #[must_use] pub fn status(&self) -> ExitStatus { self.output.status diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs index 38a9ac923b4..9a6e35da3fe 100644 --- a/src/tools/run-make-support/src/external_deps/llvm.rs +++ b/src/tools/run-make-support/src/external_deps/llvm.rs @@ -60,6 +60,18 @@ pub fn llvm_pdbutil() -> LlvmPdbutil { LlvmPdbutil::new() } +/// Construct a new `llvm-dis` invocation. This assumes that `llvm-dis` is available +/// at `$LLVM_BIN_DIR/llvm-dis`. +pub fn llvm_dis() -> LlvmDis { + LlvmDis::new() +} + +/// Construct a new `llvm-objcopy` invocation. This assumes that `llvm-objcopy` is available +/// at `$LLVM_BIN_DIR/llvm-objcopy`. +pub fn llvm_objcopy() -> LlvmObjcopy { + LlvmObjcopy::new() +} + /// A `llvm-readobj` invocation builder. #[derive(Debug)] #[must_use] @@ -123,6 +135,20 @@ pub struct LlvmPdbutil { cmd: Command, } +/// A `llvm-dis` invocation builder. +#[derive(Debug)] +#[must_use] +pub struct LlvmDis { + cmd: Command, +} + +/// A `llvm-objcopy` invocation builder. +#[derive(Debug)] +#[must_use] +pub struct LlvmObjcopy { + cmd: Command, +} + crate::macros::impl_common_helpers!(LlvmReadobj); crate::macros::impl_common_helpers!(LlvmProfdata); crate::macros::impl_common_helpers!(LlvmFilecheck); @@ -132,6 +158,8 @@ crate::macros::impl_common_helpers!(LlvmNm); crate::macros::impl_common_helpers!(LlvmBcanalyzer); crate::macros::impl_common_helpers!(LlvmDwarfdump); crate::macros::impl_common_helpers!(LlvmPdbutil); +crate::macros::impl_common_helpers!(LlvmDis); +crate::macros::impl_common_helpers!(LlvmObjcopy); /// Generate the path to the bin directory of LLVM. #[must_use] @@ -390,3 +418,41 @@ impl LlvmPdbutil { self } } + +impl LlvmObjcopy { + /// Construct a new `llvm-objcopy` invocation. This assumes that `llvm-objcopy` is available + /// at `$LLVM_BIN_DIR/llvm-objcopy`. + pub fn new() -> Self { + let llvm_objcopy = llvm_bin_dir().join("llvm-objcopy"); + let cmd = Command::new(llvm_objcopy); + Self { cmd } + } + + /// Dump the contents of `section` into the file at `path`. + #[track_caller] + pub fn dump_section, P: AsRef>( + &mut self, + section_name: S, + path: P, + ) -> &mut Self { + self.cmd.arg("--dump-section"); + self.cmd.arg(format!("{}={}", section_name.as_ref(), path.as_ref().to_str().unwrap())); + self + } +} + +impl LlvmDis { + /// Construct a new `llvm-dis` invocation. This assumes that `llvm-dis` is available + /// at `$LLVM_BIN_DIR/llvm-dis`. + pub fn new() -> Self { + let llvm_dis = llvm_bin_dir().join("llvm-dis"); + let cmd = Command::new(llvm_dis); + Self { cmd } + } + + /// Provide an input file. + pub fn input>(&mut self, path: P) -> &mut Self { + self.cmd.arg(path.as_ref()); + self + } +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 15d813ccf53..368b98c9f0d 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -49,14 +49,17 @@ pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rust // These rely on external dependencies. pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc}; -pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_optimized, build_native_static_lib_cxx}; +pub use c_build::{ + build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_cxx, + build_native_static_lib_optimized, +}; pub use cargo::cargo; pub use clang::{clang, Clang}; pub use htmldocck::htmldocck; pub use llvm::{ - llvm_ar, llvm_bcanalyzer, llvm_dwarfdump, llvm_filecheck, llvm_nm, llvm_objdump, llvm_profdata, - llvm_readobj, LlvmAr, LlvmBcanalyzer, LlvmDwarfdump, LlvmFilecheck, LlvmNm, LlvmObjdump, - LlvmProfdata, LlvmReadobj, + llvm_ar, llvm_bcanalyzer, llvm_dis, llvm_dwarfdump, llvm_filecheck, llvm_nm, llvm_objcopy, + llvm_objdump, llvm_profdata, llvm_readobj, LlvmAr, LlvmBcanalyzer, LlvmDis, LlvmDwarfdump, + LlvmFilecheck, LlvmNm, LlvmObjcopy, LlvmObjdump, LlvmProfdata, LlvmReadobj, }; pub use python::python_command; pub use rustc::{aux_build, bare_rustc, rustc, rustc_path, Rustc}; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 80831440720..9f4cc98993e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -6,7 +6,7 @@ use base_db::ra_salsa::Cycle; use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; use hir_def::{ layout::{ - Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutS, + Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutData, Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, WrappingRange, }, LocalFieldId, StructId, @@ -66,7 +66,7 @@ impl rustc_index::Idx for RustcFieldIdx { } } -pub type Layout = LayoutS; +pub type Layout = LayoutData; pub type TagEncoding = hir_def::layout::TagEncoding; pub type Variants = hir_def::layout::Variants; diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 060deb18344..27ccb205b50 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/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 = "adler2" @@ -704,6 +704,7 @@ dependencies = [ "semver", "serde_json", "tempfile", + "walkdir", ] [[package]] diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index 2118af61396..f905b9277ff 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -22,6 +22,11 @@ fn main() { .required(false) .value_parser(clap::value_parser!(String)); + let root_arg = arg!(--"rust-root" +"Path to the root of the rust source tree") + .required(false) + .value_parser(clap::value_parser!(PathBuf)); + let dir_arg = arg!([dir] "Root directory for the book\n\ (Defaults to the current directory when omitted)") .value_parser(clap::value_parser!(PathBuf)); @@ -37,6 +42,7 @@ fn main() { .about("Build the book from the markdown files") .arg(d_arg) .arg(l_arg) + .arg(root_arg) .arg(&dir_arg), ) .subcommand( @@ -96,7 +102,8 @@ pub fn build(args: &ArgMatches) -> Result3<()> { } if book.config.get_preprocessor("spec").is_some() { - book.with_preprocessor(Spec::new()); + let rust_root = args.get_one::("rust-root").cloned(); + book.with_preprocessor(Spec::new(rust_root)?); } book.build()?; diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 7a0f98d59f0..0e156b9d1ac 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -2,7 +2,6 @@ run-make/branch-protection-check-IBT/Makefile run-make/cat-and-grep-sanity-check/Makefile run-make/extern-fn-reachable/Makefile run-make/incr-add-rust-src-component/Makefile -run-make/issue-84395-lto-embed-bitcode/Makefile run-make/jobserver-error/Makefile run-make/libs-through-symlinks/Makefile run-make/split-debuginfo/Makefile diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 97c42752c12..94f8d23c158 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -3720,16 +3720,6 @@ ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.rs ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs ui/rfcs/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs -ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs -ui/rfcs/rfc-2632-const-trait-impl/issue-102156.rs -ui/rfcs/rfc-2632-const-trait-impl/issue-102985.rs -ui/rfcs/rfc-2632-const-trait-impl/issue-103677.rs -ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs -ui/rfcs/rfc-2632-const-trait-impl/issue-88155.rs -ui/rfcs/rfc-2632-const-trait-impl/issue-92111.rs -ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs -ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs -ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs ui/rust-2018/issue-51008-1.rs ui/rust-2018/issue-51008.rs ui/rust-2018/issue-52202-use-suggestions.rs @@ -3983,6 +3973,16 @@ ui/traits/alias/issue-75983.rs ui/traits/alias/issue-83613.rs ui/traits/associated_type_bound/issue-51446.rs ui/traits/auxiliary/issue_89119_intercrate_caching.rs +ui/traits/const-traits/issue-100222.rs +ui/traits/const-traits/issue-102156.rs +ui/traits/const-traits/issue-102985.rs +ui/traits/const-traits/issue-103677.rs +ui/traits/const-traits/issue-79450.rs +ui/traits/const-traits/issue-88155.rs +ui/traits/const-traits/issue-92111.rs +ui/traits/const-traits/issue-92230-wf-super-trait-env.rs +ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs +ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs ui/traits/issue-103563.rs ui/traits/issue-104322.rs ui/traits/issue-105231.rs diff --git a/tests/assembly/riscv-soft-abi-with-float-features.rs b/tests/assembly/riscv-soft-abi-with-float-features.rs new file mode 100644 index 00000000000..733137f5700 --- /dev/null +++ b/tests/assembly/riscv-soft-abi-with-float-features.rs @@ -0,0 +1,46 @@ +//@ assembly-output: emit-asm +//@ compile-flags: --target riscv64imac-unknown-none-elf -Ctarget-feature=+f,+d +//@ needs-llvm-components: riscv + +#![feature(no_core, lang_items, f16)] +#![crate_type = "lib"] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +trait Copy {} + +impl Copy for f16 {} +impl Copy for f32 {} +impl Copy for f64 {} + +// This test checks that the floats are all returned in `a0` as required by the `lp64` ABI. + +// CHECK-LABEL: read_f16 +#[no_mangle] +pub extern "C" fn read_f16(x: &f16) -> f16 { + // CHECK: lh a0, 0(a0) + // CHECK-NEXT: lui a1, 1048560 + // CHECK-NEXT: or a0, a0, a1 + // CHECK-NEXT: ret + *x +} + +// CHECK-LABEL: read_f32 +#[no_mangle] +pub extern "C" fn read_f32(x: &f32) -> f32 { + // CHECK: flw fa5, 0(a0) + // CHECK-NEXT: fmv.x.w a0, fa5 + // CHECK-NEXT: ret + *x +} + +// CHECK-LABEL: read_f64 +#[no_mangle] +pub extern "C" fn read_f64(x: &f64) -> f64 { + // CHECK: ld a0, 0(a0) + // CHECK-NEXT: ret + *x +} diff --git a/tests/assembly/rust-abi-arg-attr.rs b/tests/assembly/rust-abi-arg-attr.rs new file mode 100644 index 00000000000..2a113eed4ba --- /dev/null +++ b/tests/assembly/rust-abi-arg-attr.rs @@ -0,0 +1,108 @@ +//@ assembly-output: emit-asm +//@ revisions: riscv64 riscv64-zbb loongarch64 +//@ compile-flags: -C opt-level=3 +//@ [riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu +//@ [riscv64] needs-llvm-components: riscv +//@ [riscv64-zbb] compile-flags: --target riscv64gc-unknown-linux-gnu +//@ [riscv64-zbb] compile-flags: -C target-feature=+zbb +//@ [riscv64-zbb] needs-llvm-components: riscv +//@ [loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@ [loongarch64] needs-llvm-components: loongarch + +#![feature(no_core, lang_items, intrinsics, rustc_attrs)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +// FIXME: Migrate these code after PR #130693 is landed. +// vvvvv core + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +trait Copy {} + +impl Copy for i8 {} +impl Copy for u32 {} +impl Copy for i32 {} + +#[lang = "neg"] +trait Neg { + type Output; + + fn neg(self) -> Self::Output; +} + +impl Neg for i8 { + type Output = i8; + + fn neg(self) -> Self::Output { + -self + } +} + +#[lang = "Ordering"] +#[repr(i8)] +enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, +} + +extern "rust-intrinsic" { + #[rustc_safe_intrinsic] + fn three_way_compare(lhs: T, rhs: T) -> Ordering; +} + +// ^^^^^ core + +// Reimplementation of function `{integer}::max`. +macro_rules! max { + ($a:expr, $b:expr) => { + match three_way_compare($a, $b) { + Ordering::Less | Ordering::Equal => $b, + Ordering::Greater => $a, + } + }; +} + +#[no_mangle] +// CHECK-LABEL: issue_114508_u32: +pub fn issue_114508_u32(a: u32, b: u32) -> u32 { + // CHECK-NEXT: .cfi_startproc + + // riscv64-NEXT: bltu a1, a0, .[[RET:.+]] + // riscv64-NEXT: mv a0, a1 + // riscv64-NEXT: .[[RET]]: + + // riscv64-zbb-NEXT: maxu a0, a0, a1 + + // loongarch64-NEXT: sltu $a2, $a1, $a0 + // loongarch64-NEXT: masknez $a1, $a1, $a2 + // loongarch64-NEXT: maskeqz $a0, $a0, $a2 + // loongarch64-NEXT: or $a0, $a0, $a1 + + // CHECK-NEXT: ret + max!(a, b) +} + +#[no_mangle] +// CHECK-LABEL: issue_114508_i32: +pub fn issue_114508_i32(a: i32, b: i32) -> i32 { + // CHECK-NEXT: .cfi_startproc + + // riscv64-NEXT: blt a1, a0, .[[RET:.+]] + // riscv64-NEXT: mv a0, a1 + // riscv64-NEXT: .[[RET]]: + + // riscv64-zbb-NEXT: max a0, a0, a1 + + // loongarch64-NEXT: slt $a2, $a1, $a0 + // loongarch64-NEXT: masknez $a1, $a1, $a2 + // loongarch64-NEXT: maskeqz $a0, $a0, $a2 + // loongarch64-NEXT: or $a0, $a0, $a1 + + // CHECK-NEXT: ret + max!(a, b) +} diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index f26d06a0ecb..1857633a8bf 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -522,6 +522,9 @@ //@ revisions: wasm32_unknown_unknown //@ [wasm32_unknown_unknown] compile-flags: --target wasm32-unknown-unknown //@ [wasm32_unknown_unknown] needs-llvm-components: webassembly +//@ revisions: wasm32v1_none +//@ [wasm32v1_none] compile-flags: --target wasm32v1-none +//@ [wasm32v1_none] needs-llvm-components: webassembly //@ revisions: wasm32_wasi //@ [wasm32_wasi] compile-flags: --target wasm32-wasi //@ [wasm32_wasi] needs-llvm-components: webassembly diff --git a/tests/assembly/x86-return-float.rs b/tests/assembly/x86-return-float.rs index 30c5e869633..acd1af8d38a 100644 --- a/tests/assembly/x86-return-float.rs +++ b/tests/assembly/x86-return-float.rs @@ -305,8 +305,10 @@ pub unsafe fn call_other_f64(x: &mut (usize, f64)) { // CHECK-LABEL: return_f16: #[no_mangle] pub fn return_f16(x: f16) -> f16 { - // CHECK: pinsrw $0, {{.*}}(%ebp), %xmm0 - // CHECK-NOT: xmm0 + // CHECK: pushl %ebp + // CHECK: movl %esp, %ebp + // CHECK: movzwl 8(%ebp), %eax + // CHECK: popl %ebp // CHECK: retl x } diff --git a/tests/codegen/avr/avr-func-addrspace.rs b/tests/codegen/avr/avr-func-addrspace.rs index 7f9a7e6e811..a2dcb1c0924 100644 --- a/tests/codegen/avr/avr-func-addrspace.rs +++ b/tests/codegen/avr/avr-func-addrspace.rs @@ -18,8 +18,8 @@ pub trait Sized {} #[lang = "copy"] pub trait Copy {} impl Copy for *const T {} -#[lang = "receiver"] -pub trait Receiver {} +#[lang = "legacy_receiver"] +pub trait LegacyReceiver {} #[lang = "tuple_trait"] pub trait Tuple {} diff --git a/tests/codegen/checked_ilog.rs b/tests/codegen/checked_ilog.rs index 8f3c07119fe..d7dfc7c29e7 100644 --- a/tests/codegen/checked_ilog.rs +++ b/tests/codegen/checked_ilog.rs @@ -5,7 +5,7 @@ // Ensure that when val < base, we do not divide or multiply. // CHECK-LABEL: @checked_ilog -// CHECK-SAME: (i16 noundef %val, i16 noundef %base) +// CHECK-SAME: (i16{{.*}} %val, i16{{.*}} %base) #[no_mangle] pub fn checked_ilog(val: u16, base: u16) -> Option { // CHECK-NOT: udiv diff --git a/tests/codegen/checked_math.rs b/tests/codegen/checked_math.rs index 75df5866d6e..63f5c3d34f7 100644 --- a/tests/codegen/checked_math.rs +++ b/tests/codegen/checked_math.rs @@ -8,7 +8,7 @@ // Thanks to poison semantics, this doesn't even need branches. // CHECK-LABEL: @checked_sub_unsigned -// CHECK-SAME: (i16 noundef %a, i16 noundef %b) +// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b) #[no_mangle] pub fn checked_sub_unsigned(a: u16, b: u16) -> Option { // CHECK-DAG: %[[IS_SOME:.+]] = icmp uge i16 %a, %b @@ -26,7 +26,7 @@ pub fn checked_sub_unsigned(a: u16, b: u16) -> Option { // looking for no-wrap flags, we just need there to not be any masking. // CHECK-LABEL: @checked_shl_unsigned -// CHECK-SAME: (i32 noundef %a, i32 noundef %b) +// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) #[no_mangle] pub fn checked_shl_unsigned(a: u32, b: u32) -> Option { // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 @@ -41,7 +41,7 @@ pub fn checked_shl_unsigned(a: u32, b: u32) -> Option { } // CHECK-LABEL: @checked_shr_unsigned -// CHECK-SAME: (i32 noundef %a, i32 noundef %b) +// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) #[no_mangle] pub fn checked_shr_unsigned(a: u32, b: u32) -> Option { // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 @@ -56,7 +56,7 @@ pub fn checked_shr_unsigned(a: u32, b: u32) -> Option { } // CHECK-LABEL: @checked_shl_signed -// CHECK-SAME: (i32 noundef %a, i32 noundef %b) +// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) #[no_mangle] pub fn checked_shl_signed(a: i32, b: u32) -> Option { // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 @@ -71,7 +71,7 @@ pub fn checked_shl_signed(a: i32, b: u32) -> Option { } // CHECK-LABEL: @checked_shr_signed -// CHECK-SAME: (i32 noundef %a, i32 noundef %b) +// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b) #[no_mangle] pub fn checked_shr_signed(a: i32, b: u32) -> Option { // CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32 @@ -86,7 +86,7 @@ pub fn checked_shr_signed(a: i32, b: u32) -> Option { } // CHECK-LABEL: @checked_add_one_unwrap_unsigned -// CHECK-SAME: (i32 noundef %x) +// CHECK-SAME: (i32{{.*}} %x) #[no_mangle] pub fn checked_add_one_unwrap_unsigned(x: u32) -> u32 { // CHECK: %[[IS_MAX:.+]] = icmp eq i32 %x, -1 diff --git a/tests/codegen/comparison-operators-newtype.rs b/tests/codegen/comparison-operators-newtype.rs index d336c4e6ed3..acce0cb5946 100644 --- a/tests/codegen/comparison-operators-newtype.rs +++ b/tests/codegen/comparison-operators-newtype.rs @@ -12,7 +12,7 @@ use std::cmp::Ordering; pub struct Foo(u16); // CHECK-LABEL: @check_lt -// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]]) +// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) #[no_mangle] pub fn check_lt(a: Foo, b: Foo) -> bool { // CHECK: %[[R:.+]] = icmp ult i16 %[[A]], %[[B]] @@ -21,7 +21,7 @@ pub fn check_lt(a: Foo, b: Foo) -> bool { } // CHECK-LABEL: @check_le -// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]]) +// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) #[no_mangle] pub fn check_le(a: Foo, b: Foo) -> bool { // CHECK: %[[R:.+]] = icmp ule i16 %[[A]], %[[B]] @@ -30,7 +30,7 @@ pub fn check_le(a: Foo, b: Foo) -> bool { } // CHECK-LABEL: @check_gt -// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]]) +// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) #[no_mangle] pub fn check_gt(a: Foo, b: Foo) -> bool { // CHECK: %[[R:.+]] = icmp ugt i16 %[[A]], %[[B]] @@ -39,7 +39,7 @@ pub fn check_gt(a: Foo, b: Foo) -> bool { } // CHECK-LABEL: @check_ge -// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]]) +// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]]) #[no_mangle] pub fn check_ge(a: Foo, b: Foo) -> bool { // CHECK: %[[R:.+]] = icmp uge i16 %[[A]], %[[B]] diff --git a/tests/codegen/fewer-names.rs b/tests/codegen/fewer-names.rs index b14dd30482c..a171629a076 100644 --- a/tests/codegen/fewer-names.rs +++ b/tests/codegen/fewer-names.rs @@ -6,11 +6,11 @@ #[no_mangle] pub fn sum(x: u32, y: u32) -> u32 { - // YES-LABEL: define{{.*}}i32 @sum(i32 noundef %0, i32 noundef %1) + // YES-LABEL: define{{.*}}i32 @sum(i32{{.*}} %0, i32{{.*}} %1) // YES-NEXT: %3 = add i32 %1, %0 // YES-NEXT: ret i32 %3 - // NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y) + // NO-LABEL: define{{.*}}i32 @sum(i32{{.*}} %x, i32{{.*}} %y) // NO-NEXT: start: // NO-NEXT: %z = add i32 %y, %x // NO-NEXT: ret i32 %z diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs index 4af264101de..514d35433e1 100644 --- a/tests/codegen/float/f128.rs +++ b/tests/codegen/float/f128.rs @@ -1,4 +1,4 @@ -// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack. +// 32-bit x86 returns float types differently to avoid the x87 stack. // 32-bit systems will return 128bit values using a return area pointer. //@ revisions: x86 bit32 bit64 //@[x86] only-x86 @@ -152,7 +152,9 @@ pub fn f128_rem_assign(a: &mut f128, b: f128) { /* float to float conversions */ -// CHECK-LABEL: half @f128_as_f16( +// x86-LABEL: i16 @f128_as_f16( +// bits32-LABEL: half @f128_as_f16( +// bits64-LABEL: half @f128_as_f16( #[no_mangle] pub fn f128_as_f16(a: f128) -> f16 { // CHECK: fptrunc fp128 %{{.+}} to half diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs index 80931051f18..5c3a5893b9d 100644 --- a/tests/codegen/float/f16.rs +++ b/tests/codegen/float/f16.rs @@ -1,4 +1,4 @@ -// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack. +// 32-bit x86 returns float types differently to avoid the x87 stack. // 32-bit systems will return 128bit values using a return area pointer. //@ revisions: x86 bit32 bit64 //@[x86] only-x86 @@ -58,42 +58,44 @@ pub fn f16_le(a: f16, b: f16) -> bool { a <= b } -// CHECK-LABEL: half @f16_neg( +// This is where we check the argument and return ABI for f16. +// other-LABEL: half @f16_neg(half +// x86-LABEL: i16 @f16_neg(half #[no_mangle] pub fn f16_neg(a: f16) -> f16 { // CHECK: fneg half %{{.+}} -a } -// CHECK-LABEL: half @f16_add( +// CHECK-LABEL: @f16_add #[no_mangle] pub fn f16_add(a: f16, b: f16) -> f16 { // CHECK: fadd half %{{.+}}, %{{.+}} a + b } -// CHECK-LABEL: half @f16_sub( +// CHECK-LABEL: @f16_sub #[no_mangle] pub fn f16_sub(a: f16, b: f16) -> f16 { // CHECK: fsub half %{{.+}}, %{{.+}} a - b } -// CHECK-LABEL: half @f16_mul( +// CHECK-LABEL: @f16_mul #[no_mangle] pub fn f16_mul(a: f16, b: f16) -> f16 { // CHECK: fmul half %{{.+}}, %{{.+}} a * b } -// CHECK-LABEL: half @f16_div( +// CHECK-LABEL: @f16_div #[no_mangle] pub fn f16_div(a: f16, b: f16) -> f16 { // CHECK: fdiv half %{{.+}}, %{{.+}} a / b } -// CHECK-LABEL: half @f16_rem( +// CHECK-LABEL: @f16_rem #[no_mangle] pub fn f16_rem(a: f16, b: f16) -> f16 { // CHECK: frem half %{{.+}}, %{{.+}} @@ -142,10 +144,13 @@ pub fn f16_rem_assign(a: &mut f16, b: f16) { /* float to float conversions */ -// CHECK-LABEL: half @f16_as_self( +// other-LABEL: half @f16_as_self( +// x86-LABEL: i16 @f16_as_self( #[no_mangle] pub fn f16_as_self(a: f16) -> f16 { - // CHECK: ret half %{{.+}} + // other-CHECK: ret half %{{.+}} + // x86-CHECK: bitcast half + // x86-CHECK: ret i16 a as f16 } @@ -176,21 +181,21 @@ pub fn f16_as_f128(a: f16) -> f128 { a as f128 } -// CHECK-LABEL: half @f32_as_f16( +// CHECK-LABEL: @f32_as_f16 #[no_mangle] pub fn f32_as_f16(a: f32) -> f16 { // CHECK: fptrunc float %{{.+}} to half a as f16 } -// CHECK-LABEL: half @f64_as_f16( +// CHECK-LABEL: @f64_as_f16 #[no_mangle] pub fn f64_as_f16(a: f64) -> f16 { // CHECK: fptrunc double %{{.+}} to half a as f16 } -// CHECK-LABEL: half @f128_as_f16( +// CHECK-LABEL: @f128_as_f16 #[no_mangle] pub fn f128_as_f16(a: f128) -> f16 { // CHECK: fptrunc fp128 %{{.+}} to half @@ -273,70 +278,70 @@ pub fn f16_as_i128(a: f16) -> i128 { /* int to float conversions */ -// CHECK-LABEL: half @u8_as_f16( +// CHECK-LABEL: @u8_as_f16 #[no_mangle] pub fn u8_as_f16(a: u8) -> f16 { // CHECK: uitofp i8 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @u16_as_f16( +// CHECK-LABEL: @u16_as_f16 #[no_mangle] pub fn u16_as_f16(a: u16) -> f16 { // CHECK: uitofp i16 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @u32_as_f16( +// CHECK-LABEL: @u32_as_f16 #[no_mangle] pub fn u32_as_f16(a: u32) -> f16 { // CHECK: uitofp i32 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @u64_as_f16( +// CHECK-LABEL: @u64_as_f16 #[no_mangle] pub fn u64_as_f16(a: u64) -> f16 { // CHECK: uitofp i64 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @u128_as_f16( +// CHECK-LABEL: @u128_as_f16 #[no_mangle] pub fn u128_as_f16(a: u128) -> f16 { // CHECK: uitofp i128 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @i8_as_f16( +// CHECK-LABEL: @i8_as_f16 #[no_mangle] pub fn i8_as_f16(a: i8) -> f16 { // CHECK: sitofp i8 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @i16_as_f16( +// CHECK-LABEL: @i16_as_f16 #[no_mangle] pub fn i16_as_f16(a: i16) -> f16 { // CHECK: sitofp i16 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @i32_as_f16( +// CHECK-LABEL: @i32_as_f16 #[no_mangle] pub fn i32_as_f16(a: i32) -> f16 { // CHECK: sitofp i32 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @i64_as_f16( +// CHECK-LABEL: @i64_as_f16 #[no_mangle] pub fn i64_as_f16(a: i64) -> f16 { // CHECK: sitofp i64 %{{.+}} to half a as f16 } -// CHECK-LABEL: half @i128_as_f16( +// CHECK-LABEL: @i128_as_f16 #[no_mangle] pub fn i128_as_f16(a: i128) -> f16 { // CHECK: sitofp i128 %{{.+}} to half diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs index bf9f405192b..7fa1d659885 100644 --- a/tests/codegen/function-arguments.rs +++ b/tests/codegen/function-arguments.rs @@ -32,7 +32,7 @@ pub fn boolean(x: bool) -> bool { x } -// CHECK: i8 @maybeuninit_boolean(i8 %x) +// CHECK: i8 @maybeuninit_boolean(i8{{.*}} %x) #[no_mangle] pub fn maybeuninit_boolean(x: MaybeUninit) -> MaybeUninit { x @@ -44,19 +44,19 @@ pub fn enum_bool(x: MyBool) -> MyBool { x } -// CHECK: i8 @maybeuninit_enum_bool(i8 %x) +// CHECK: i8 @maybeuninit_enum_bool(i8{{.*}} %x) #[no_mangle] pub fn maybeuninit_enum_bool(x: MaybeUninit) -> MaybeUninit { x } -// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32 noundef{{( range\(i32 0, 1114112\))?}} %x) +// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32{{.*}}{{( range\(i32 0, 1114112\))?}} %x) #[no_mangle] pub fn char(x: char) -> char { x } -// CHECK: i32 @maybeuninit_char(i32 %x) +// CHECK: i32 @maybeuninit_char(i32{{.*}} %x) #[no_mangle] pub fn maybeuninit_char(x: MaybeUninit) -> MaybeUninit { x diff --git a/tests/codegen/intrinsics/three_way_compare.rs b/tests/codegen/intrinsics/three_way_compare.rs index f3b631abc22..9a476abe891 100644 --- a/tests/codegen/intrinsics/three_way_compare.rs +++ b/tests/codegen/intrinsics/three_way_compare.rs @@ -10,8 +10,7 @@ use std::intrinsics::three_way_compare; #[no_mangle] // CHECK-LABEL: @signed_cmp -// DEBUG-SAME: (i16 %a, i16 %b) -// OPTIM-SAME: (i16 noundef %a, i16 noundef %b) +// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b) pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { // DEBUG: %[[GT:.+]] = icmp sgt i16 %a, %b // DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8 @@ -29,8 +28,7 @@ pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { #[no_mangle] // CHECK-LABEL: @unsigned_cmp -// DEBUG-SAME: (i16 %a, i16 %b) -// OPTIM-SAME: (i16 noundef %a, i16 noundef %b) +// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b) pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering { // DEBUG: %[[GT:.+]] = icmp ugt i16 %a, %b // DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8 diff --git a/tests/codegen/mir-aggregate-no-alloca.rs b/tests/codegen/mir-aggregate-no-alloca.rs index 04ffb075538..37b024a55b3 100644 --- a/tests/codegen/mir-aggregate-no-alloca.rs +++ b/tests/codegen/mir-aggregate-no-alloca.rs @@ -9,7 +9,7 @@ #[repr(transparent)] pub struct Transparent32(u32); -// CHECK: i32 @make_transparent(i32 noundef %x) +// CHECK: i32 @make_transparent(i32{{.*}} %x) #[no_mangle] pub fn make_transparent(x: u32) -> Transparent32 { // CHECK-NOT: alloca @@ -18,7 +18,7 @@ pub fn make_transparent(x: u32) -> Transparent32 { a } -// CHECK: i32 @make_closure(i32 noundef %x) +// CHECK: i32 @make_closure(i32{{.*}} %x) #[no_mangle] pub fn make_closure(x: i32) -> impl Fn(i32) -> i32 { // CHECK-NOT: alloca @@ -40,7 +40,7 @@ pub fn make_transparent_pair(x: (u16, u16)) -> TransparentPair { a } -// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32 noundef %x) +// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32{{.*}} %x) #[no_mangle] pub fn make_2_tuple(x: u32) -> (u32, u32) { // CHECK-NOT: alloca @@ -59,7 +59,7 @@ pub fn make_cell_of_bool(b: bool) -> std::cell::Cell { std::cell::Cell::new(b) } -// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16 noundef %s) +// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16{{.*}} %s) #[no_mangle] pub fn make_cell_of_bool_and_short(b: bool, s: u16) -> std::cell::Cell<(bool, u16)> { // CHECK-NOT: alloca @@ -92,7 +92,7 @@ pub fn make_struct_0() -> Struct0 { pub struct Struct1(i32); -// CHECK-LABEL: i32 @make_struct_1(i32 noundef %a) +// CHECK-LABEL: i32 @make_struct_1(i32{{.*}} %a) #[no_mangle] pub fn make_struct_1(a: i32) -> Struct1 { // CHECK: ret i32 %a @@ -104,7 +104,7 @@ pub struct Struct2Asc(i16, i64); // bit32-LABEL: void @make_struct_2_asc({{.*}} sret({{[^,]*}}) {{.*}} %s, // bit64-LABEL: { i64, i16 } @make_struct_2_asc( -// CHECK-SAME: i16 noundef %a, i64 noundef %b) +// CHECK-SAME: i16{{.*}} %a, i64 noundef %b) #[no_mangle] pub fn make_struct_2_asc(a: i16, b: i64) -> Struct2Asc { // CHECK-NOT: alloca @@ -122,7 +122,7 @@ pub struct Struct2Desc(i64, i16); // bit32-LABEL: void @make_struct_2_desc({{.*}} sret({{[^,]*}}) {{.*}} %s, // bit64-LABEL: { i64, i16 } @make_struct_2_desc( -// CHECK-SAME: i64 noundef %a, i16 noundef %b) +// CHECK-SAME: i64 noundef %a, i16{{.*}} %b) #[no_mangle] pub fn make_struct_2_desc(a: i64, b: i16) -> Struct2Desc { // CHECK-NOT: alloca diff --git a/tests/codegen/placement-new.rs b/tests/codegen/placement-new.rs index edb25df5eb4..0ec2b6a6f20 100644 --- a/tests/codegen/placement-new.rs +++ b/tests/codegen/placement-new.rs @@ -1,9 +1,11 @@ //@ compile-flags: -O +//@ compile-flags: -Zmerge-functions=disabled #![crate_type = "lib"] // Test to check that types with "complex" destructors, but trivial `Default` impls // are constructed directly into the allocation in `Box::default` and `Arc::default`. +use std::rc::Rc; use std::sync::Arc; // CHECK-LABEL: @box_default_inplace @@ -16,6 +18,16 @@ pub fn box_default_inplace() -> Box<(String, String)> { Box::default() } +// CHECK-LABEL: @rc_default_inplace +#[no_mangle] +pub fn rc_default_inplace() -> Rc<(String, String)> { + // CHECK-NOT: alloca + // CHECK: [[RC:%.*]] = {{.*}}call {{.*}}__rust_alloc( + // CHECK-NOT: call void @llvm.memcpy + // CHECK: ret ptr [[RC]] + Rc::default() +} + // CHECK-LABEL: @arc_default_inplace #[no_mangle] pub fn arc_default_inplace() -> Arc<(String, String)> { diff --git a/tests/codegen/range-attribute.rs b/tests/codegen/range-attribute.rs index 8972fc76ca2..a44ec1026b1 100644 --- a/tests/codegen/range-attribute.rs +++ b/tests/codegen/range-attribute.rs @@ -24,7 +24,7 @@ pub fn nonzero_int(x: NonZero) -> NonZero { x } -// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8 noundef range(i8 0, 3) %x) +// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8{{.*}} range(i8 0, 3) %x) #[no_mangle] pub fn optional_bool(x: Option) -> Option { x @@ -36,7 +36,7 @@ pub enum Enum0 { C, } -// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8 noundef range(i8 0, 4) %x) +// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8{{.*}} range(i8 0, 4) %x) #[no_mangle] pub fn enum0_value(x: Enum0) -> Enum0 { x diff --git a/tests/codegen/regparm-inreg.rs b/tests/codegen/regparm-inreg.rs new file mode 100644 index 00000000000..c8c647bcc87 --- /dev/null +++ b/tests/codegen/regparm-inreg.rs @@ -0,0 +1,125 @@ +// Checks how `regparm` flag works with different calling conventions: +// marks function arguments as "inreg" like the C/C++ compilers for the platforms. +// x86 only. + +//@ compile-flags: --target i686-unknown-linux-gnu -O -C no-prepopulate-passes +//@ needs-llvm-components: x86 + +//@ revisions:regparm0 regparm1 regparm2 regparm3 +//@[regparm0] compile-flags: -Zregparm=0 +//@[regparm1] compile-flags: -Zregparm=1 +//@[regparm2] compile-flags: -Zregparm=2 +//@[regparm3] compile-flags: -Zregparm=3 + +#![crate_type = "lib"] +#![no_core] +#![feature(no_core, lang_items, repr_simd)] +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +pub mod tests { + // regparm doesn't work for "fastcall" calling conv (only 2 inregs) + // CHECK: @f1(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) + #[no_mangle] + pub extern "fastcall" fn f1(_: i32, _: i32, _: i32) {} + + // regparm0: @f3(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm1: @f3(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm2: @f3(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) + // regparm3: @f3(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + #[no_mangle] + pub extern "C" fn f3(_: i32, _: i32, _: i32) {} + + // regparm0: @f4(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm1: @f4(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm2: @f4(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) + // regparm3: @f4(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + #[no_mangle] + pub extern "cdecl" fn f4(_: i32, _: i32, _: i32) {} + + // regparm0: @f5(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm1: @f5(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3) + // regparm2: @f5(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3) + // regparm3: @f5(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3) + #[no_mangle] + pub extern "stdcall" fn f5(_: i32, _: i32, _: i32) {} + + // regparm doesn't work for thiscall + // CHECK: @f6(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3) + #[no_mangle] + pub extern "thiscall" fn f6(_: i32, _: i32, _: i32) {} + + struct S1 { + x1: i32, + } + // regparm0: @f7(i32 noundef %_1, i32 noundef %_2, i32 noundef %_3, i32 noundef %_4) + // regparm1: @f7(i32 inreg noundef %_1, i32 noundef %_2, i32 noundef %_3, i32 noundef %_4) + // regparm2: @f7(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 noundef %_3, i32 noundef %_4) + // regparm3: @f7(i32 inreg noundef %_1, i32 inreg noundef %_2, i32 inreg noundef %_3, + // regparm3-SAME: i32 noundef %_4) + #[no_mangle] + pub extern "C" fn f7(_: i32, _: i32, _: S1, _: i32) {} + + #[repr(C)] + struct S2 { + x1: i32, + x2: i32, + } + // regparm0: @f8(i32 noundef %_1, i32 noundef %_2, ptr {{.*}} %_3, i32 noundef %_4) + // regparm1: @f8(i32 inreg noundef %_1, i32 noundef %_2, ptr {{.*}} %_3, i32 noundef %_4) + // regparm2: @f8(i32 inreg noundef %_1, i32 inreg noundef %_2, ptr {{.*}} %_3, i32 noundef %_4) + // regparm3: @f8(i32 inreg noundef %_1, i32 inreg noundef %_2, ptr {{.*}} %_3, + // regparm3-SAME: i32 inreg noundef %_4) + #[no_mangle] + pub extern "C" fn f8(_: i32, _: i32, _: S2, _: i32) {} + + // regparm0: @f9(i1 noundef zeroext %_1, i16 noundef signext %_2, i64 noundef %_3, + // regparm0-SAME: i128 noundef %_4) + // regparm1: @f9(i1 inreg noundef zeroext %_1, i16 noundef signext %_2, i64 noundef %_3, + // regparm1-SAME: i128 noundef %_4) + // regparm2: @f9(i1 inreg noundef zeroext %_1, i16 inreg noundef signext %_2, i64 noundef %_3, + // regparm2-SAME: i128 noundef %_4) + // regparm3: @f9(i1 inreg noundef zeroext %_1, i16 inreg noundef signext %_2, i64 noundef %_3, + // regparm3-SAME: i128 noundef %_4) + #[no_mangle] + pub extern "C" fn f9(_: bool, _: i16, _: i64, _: u128) {} + + // regparm0: @f10(float noundef %_1, double noundef %_2, i1 noundef zeroext %_3, + // regparm0-SAME: i16 noundef signext %_4) + // regparm1: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3, + // regparm1-SAME: i16 noundef signext %_4) + // regparm2: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3, + // regparm2-SAME: i16 inreg noundef signext %_4) + // regparm3: @f10(float noundef %_1, double noundef %_2, i1 inreg noundef zeroext %_3, + // regparm3-SAME: i16 inreg noundef signext %_4) + #[no_mangle] + pub extern "C" fn f10(_: f32, _: f64, _: bool, _: i16) {} + + #[allow(non_camel_case_types)] + #[repr(simd)] + pub struct __m128([f32; 4]); + + // regparm0: @f11(i32 noundef %_1, <4 x float> %_2, i32 noundef %_3, i32 noundef %_4) + // regparm1: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 noundef %_3, i32 noundef %_4) + // regparm2: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 inreg noundef %_3, + // regparm2-SAME: i32 noundef %_4) + // regparm3: @f11(i32 inreg noundef %_1, <4 x float> %_2, i32 inreg noundef %_3, + // regparm3-SAME: i32 inreg noundef %_4) + #[no_mangle] + pub extern "C" fn f11(_: i32, _: __m128, _: i32, _: i32) {} + + #[allow(non_camel_case_types)] + #[repr(simd)] + pub struct __m256([f32; 8]); + + // regparm0: @f12(i32 noundef %_1, <8 x float> %_2, i32 noundef %_3, i32 noundef %_4) + // regparm1: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 noundef %_3, i32 noundef %_4) + // regparm2: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 inreg noundef %_3, + // regparm2-SAME: i32 noundef %_4) + // regparm3: @f12(i32 inreg noundef %_1, <8 x float> %_2, i32 inreg noundef %_3, + // regparm3-SAME: i32 inreg noundef %_4) + #[no_mangle] + pub extern "C" fn f12(_: i32, _: __m256, _: i32, _: i32) {} +} diff --git a/tests/codegen/riscv-target-abi.rs b/tests/codegen/riscv-target-abi.rs index 5d545af9c76..88da4ece7ba 100644 --- a/tests/codegen/riscv-target-abi.rs +++ b/tests/codegen/riscv-target-abi.rs @@ -10,7 +10,7 @@ //@[riscv32imac] compile-flags: --target=riscv32imac-unknown-none-elf //@[riscv32imac] needs-llvm-components: riscv -// riscv32imac-NOT: !"target-abi" +// riscv32imac: !{i32 1, !"target-abi", !"ilp32"} #![feature(no_core, lang_items)] #![crate_type = "lib"] diff --git a/tests/codegen/rust-abi-arch-specific-adjustment.rs b/tests/codegen/rust-abi-arch-specific-adjustment.rs new file mode 100644 index 00000000000..9da10f662b0 --- /dev/null +++ b/tests/codegen/rust-abi-arch-specific-adjustment.rs @@ -0,0 +1,111 @@ +//@ compile-flags: -O -C no-prepopulate-passes +//@ revisions: riscv64 loongarch64 + +//@[riscv64] only-riscv64 +//@[riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu +//@[riscv64] needs-llvm-components: riscv + +//@[loongarch64] only-loongarch64 +//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@[loongarch64] needs-llvm-components: loongarch + +#![crate_type = "lib"] + +#[no_mangle] +// riscv64: define noundef i8 @arg_attr_u8(i8 noundef zeroext %x) +// loongarch64: define noundef i8 @arg_attr_u8(i8 noundef zeroext %x) +pub fn arg_attr_u8(x: u8) -> u8 { + x +} + +#[no_mangle] +// riscv64: define noundef i16 @arg_attr_u16(i16 noundef zeroext %x) +// loongarch64: define noundef i16 @arg_attr_u16(i16 noundef zeroext %x) +pub fn arg_attr_u16(x: u16) -> u16 { + x +} + +#[no_mangle] +// riscv64: define noundef i32 @arg_attr_u32(i32 noundef signext %x) +// loongarch64: define noundef i32 @arg_attr_u32(i32 noundef signext %x) +pub fn arg_attr_u32(x: u32) -> u32 { + x +} + +#[no_mangle] +// riscv64: define noundef i64 @arg_attr_u64(i64 noundef %x) +// loongarch64: define noundef i64 @arg_attr_u64(i64 noundef %x) +pub fn arg_attr_u64(x: u64) -> u64 { + x +} + +#[no_mangle] +// riscv64: define noundef i128 @arg_attr_u128(i128 noundef %x) +// loongarch64: define noundef i128 @arg_attr_u128(i128 noundef %x) +pub fn arg_attr_u128(x: u128) -> u128 { + x +} + +#[no_mangle] +// riscv64: define noundef i8 @arg_attr_i8(i8 noundef signext %x) +// loongarch64: define noundef i8 @arg_attr_i8(i8 noundef signext %x) +pub fn arg_attr_i8(x: i8) -> i8 { + x +} + +#[no_mangle] +// riscv64: define noundef i16 @arg_attr_i16(i16 noundef signext %x) +// loongarch64: define noundef i16 @arg_attr_i16(i16 noundef signext %x) +pub fn arg_attr_i16(x: i16) -> i16 { + x +} + +#[no_mangle] +// riscv64: define noundef i32 @arg_attr_i32(i32 noundef signext %x) +// loongarch64: define noundef i32 @arg_attr_i32(i32 noundef signext %x) +pub fn arg_attr_i32(x: i32) -> i32 { + x +} + +#[no_mangle] +// riscv64: define noundef i64 @arg_attr_i64(i64 noundef %x) +// loongarch64: define noundef i64 @arg_attr_i64(i64 noundef %x) +pub fn arg_attr_i64(x: i64) -> i64 { + x +} + +#[no_mangle] +// riscv64: define noundef i128 @arg_attr_i128(i128 noundef %x) +// loongarch64: define noundef i128 @arg_attr_i128(i128 noundef %x) +pub fn arg_attr_i128(x: i128) -> i128 { + x +} + +#[no_mangle] +// riscv64: define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x) +// loongarch64: define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x) +pub fn arg_attr_bool(x: bool) -> bool { + x +} + +#[no_mangle] +// ignore-tidy-linelength +// riscv64: define noundef{{( range\(i32 0, 1114112\))?}} i32 @arg_attr_char(i32 noundef signext{{( range\(i32 0, 1114112\))?}} %x) +// loongarch64: define noundef{{( range\(i32 0, 1114112\))?}} i32 @arg_attr_char(i32 noundef signext{{( range\(i32 0, 1114112\))?}} %x) +pub fn arg_attr_char(x: char) -> char { + x +} + +#[no_mangle] +// riscv64: define noundef float @arg_attr_f32(float noundef %x) +// loongarch64: define noundef float @arg_attr_f32(float noundef %x) +pub fn arg_attr_f32(x: f32) -> f32 { + x +} + +#[no_mangle] +// riscv64: define noundef double @arg_attr_f64(double noundef %x) +// loongarch64: define noundef double @arg_attr_f64(double noundef %x) +pub fn arg_attr_f64(x: f64) -> f64 { + x +} diff --git a/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs b/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs index 259967e8918..71ccdc8ca62 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs @@ -12,7 +12,7 @@ pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { // CHECK: Function Attrs: {{.*}} // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} // CHECK: start: - // CHECK-NEXT: {{%.+}} = call i32 %f(i32 %arg) + // CHECK-NEXT: {{%.+}} = call i32 %f(i32{{.*}} %arg) // CHECK-NEXT: ret i32 {{%.+}} f(arg) } diff --git a/tests/codegen/sanitizer/cfi/emit-type-checks.rs b/tests/codegen/sanitizer/cfi/emit-type-checks.rs index 37edbefee56..ebc66a015df 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-checks.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-checks.rs @@ -11,7 +11,7 @@ pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { // CHECK: [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}") // CHECK-NEXT: br i1 [[TT]], label %type_test.pass, label %type_test.fail // CHECK: type_test.pass: - // CHECK-NEXT: {{%.+}} = call i32 %f(i32 %arg) + // CHECK-NEXT: {{%.+}} = call i32 %f(i32{{.*}} %arg) // CHECK: type_test.fail: // CHECK-NEXT: call void @llvm.trap() // CHECK-NEXT: unreachable diff --git a/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs index c1967e55e75..5ab55a46726 100644 --- a/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs +++ b/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs @@ -16,8 +16,8 @@ trait Sized {} #[lang = "copy"] trait Copy {} impl Copy for &T {} -#[lang = "receiver"] -trait Receiver {} +#[lang = "legacy_receiver"] +trait LegacyReceiver {} #[lang = "dispatch_from_dyn"] trait DispatchFromDyn {} impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index caaa70962d5..43da7c1781e 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -25,7 +25,7 @@ pub fn bool_to_byte(b: bool) -> u8 { unsafe { std::mem::transmute(b) } } -// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8 %byte) +// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte) // CHECK: %_0 = trunc i8 %byte to i1 // CHECK-NEXT: ret i1 %_0 #[no_mangle] diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs index b3c67a59730..2f14682dfa5 100644 --- a/tests/codegen/union-abi.rs +++ b/tests/codegen/union-abi.rs @@ -131,7 +131,7 @@ pub fn test_CUnionU128(_: CUnionU128) { pub union UnionBool { b: bool, } -// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8 %b) +// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8{{.*}} %b) #[no_mangle] pub fn test_UnionBool(b: UnionBool) -> bool { unsafe { b.b } diff --git a/tests/codegen/var-names.rs b/tests/codegen/var-names.rs index fd163a55551..4ea5b3b436d 100644 --- a/tests/codegen/var-names.rs +++ b/tests/codegen/var-names.rs @@ -2,7 +2,7 @@ #![crate_type = "lib"] -// CHECK-LABEL: define{{.*}}i32 @test(i32 noundef %a, i32 noundef %b) +// CHECK-LABEL: define{{.*}}i32 @test(i32{{.*}} %a, i32{{.*}} %b) #[no_mangle] pub fn test(a: u32, b: u32) -> u32 { let c = a + b; diff --git a/tests/crashes/110630.rs b/tests/crashes/110630.rs deleted file mode 100644 index f17f6f0781f..00000000000 --- a/tests/crashes/110630.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ known-bug: #110630 - -#![feature(generic_const_exprs)] - -use std::ops::Mul; - -pub trait Indices { - const NUM_ELEMS: usize = I::NUM_ELEMS * N; -} - -pub trait Concat { - type Output; -} - -pub struct Tensor, const N: usize> -where - [u8; I::NUM_ELEMS]: Sized, {} - -impl, J: Indices, const N: usize> Mul> for Tensor -where - I: Concat, - >::Output: Indices, - [u8; I::NUM_ELEMS]: Sized, - [u8; J::NUM_ELEMS]: Sized, - [u8; >::Output::NUM_ELEMS]: Sized, -{ - type Output = Tensor<>::Output, N>; -} diff --git a/tests/crashes/115808.rs b/tests/crashes/115808.rs deleted file mode 100644 index 79196ac9c65..00000000000 --- a/tests/crashes/115808.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ known-bug: #115808 -#![feature(generic_const_exprs)] - -use std::ops::Mul; - -pub trait Indices { - const NUM_ELEMS: usize; -} - -pub trait Concat { - type Output; -} - -pub struct Tensor, const N: usize> -where - [u8; I::NUM_ELEMS]: Sized, {} - -impl, J: Indices, const N: usize> Mul> for Tensor -where - I: Concat, - >::Output: Indices, - [u8; I::NUM_ELEMS]: Sized, - [u8; J::NUM_ELEMS]: Sized, - [u8; >::Output::NUM_ELEMS]: Sized, -{ - type Output = Tensor<>::Output, N>; -} diff --git a/tests/crashes/118320.rs b/tests/crashes/118320.rs deleted file mode 100644 index 093c58e1c05..00000000000 --- a/tests/crashes/118320.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ known-bug: #118320 -//@ edition:2021 -#![feature(const_trait_impl, effects, const_closures)] - -#[const_trait] -trait Bar { - fn foo(&self); -} - -impl Bar for () {} - -const FOO: () = { - (const || (()).foo())(); -}; diff --git a/tests/crashes/119924-6.rs b/tests/crashes/119924-6.rs deleted file mode 100644 index f1cc9d29159..00000000000 --- a/tests/crashes/119924-6.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: #119924 -//@ compile-flags: -Znext-solver -#![feature(const_trait_impl, effects)] - -struct S; -#[const_trait] -trait Trait {} - -const fn f>(U); // should've gotten rejected during AST validation - //~^ ICE no host param id for call in const yet no errors reported - 0 -}>>() {} - -pub fn main() {} diff --git a/tests/crashes/121052.rs b/tests/crashes/121052.rs deleted file mode 100644 index 5d16b06db23..00000000000 --- a/tests/crashes/121052.rs +++ /dev/null @@ -1,32 +0,0 @@ -//@ known-bug: #121052 -#![feature(generic_const_exprs, with_negative_coherence)] - -use std::ops::Mul; - -pub trait Indices { - const NUM_ELEMS: usize; -} - -impl, J: Indices, const N: usize> Mul for Tensor -where - I: Concat, - >::Output: Indices, - [u8; I::NUM_ELEMS]: Sized, - [u8; J::NUM_ELEMS]: Sized, - [u8; >::Output::NUM_ELEMS]: Sized, -{ -} - -pub trait Concat {} - -pub struct Tensor, const N: usize> {} - -impl, J: Indices, const N: usize> Mul for Tensor -where - I: Concat, - >::Output: Indices, - [u8; I::NUM_ELEMS]: Sized, - [u8; J::NUM_ELEMS]: Sized, - [u8; >::Output::NUM_ELEMS]: Sized, -{ -} diff --git a/tests/crashes/126725.rs b/tests/crashes/126725.rs deleted file mode 100644 index d7a7d21ae42..00000000000 --- a/tests/crashes/126725.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: rust-lang/rust#126725 -trait Foo { - fn foo<'a>(&'a self) -> <&'a impl Sized as Bar>::Output; -} - -trait Bar { - type Output; -} - -struct X(i32); - -impl<'a> Bar for &'a X { - type Output = &'a i32; -} - -impl Foo for X { - fn foo<'a>(&'a self) -> <&'a Self as Bar>::Output { - &self.0 - } -} diff --git a/tests/debuginfo/thread.rs b/tests/debuginfo/thread.rs index 0415f586f5d..dc8cb083219 100644 --- a/tests/debuginfo/thread.rs +++ b/tests/debuginfo/thread.rs @@ -12,15 +12,15 @@ // cdb-check:join_handle,d [Type: std::thread::JoinHandle >] // cdb-check: [...] __0 [Type: std::thread::JoinInner >] // -// cdb-command:dx t,d +// cdb-command:dx -r3 t,d // cdb-check:t,d : [...] [Type: std::thread::Thread *] -// cdb-check:[...] inner [...][Type: core::pin::Pin >] +// cdb-check: [...] __0 : Other [Type: enum2$] +// cdb-check: [...] __0 [Type: core::pin::Pin >] use std::thread; #[allow(unused_variables)] -fn main() -{ +fn main() { let join_handle = thread::spawn(|| { println!("Initialize a thread"); }); diff --git a/tests/run-make/cross-lang-lto-clang/rmake.rs b/tests/run-make/cross-lang-lto-clang/rmake.rs index 1b15a54aacb..3fed6ea2066 100644 --- a/tests/run-make/cross-lang-lto-clang/rmake.rs +++ b/tests/run-make/cross-lang-lto-clang/rmake.rs @@ -9,6 +9,24 @@ use run_make_support::{clang, env_var, llvm_ar, llvm_objdump, rustc, static_lib_name}; +#[cfg(any(target_arch = "aarch64", target_arch = "arm"))] +static RUST_ALWAYS_INLINED_PATTERN: &'static str = "bl.*"; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +static RUST_ALWAYS_INLINED_PATTERN: &'static str = "call.*rust_always_inlined"; +#[cfg(any(target_arch = "aarch64", target_arch = "arm"))] +static C_ALWAYS_INLINED_PATTERN: &'static str = "bl.*"; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +static C_ALWAYS_INLINED_PATTERN: &'static str = "call.*c_always_inlined"; + +#[cfg(any(target_arch = "aarch64", target_arch = "arm"))] +static RUST_NEVER_INLINED_PATTERN: &'static str = "bl.*"; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +static RUST_NEVER_INLINED_PATTERN: &'static str = "call.*rust_never_inlined"; +#[cfg(any(target_arch = "aarch64", target_arch = "arm"))] +static C_NEVER_INLINED_PATTERN: &'static str = "bl.*"; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +static C_NEVER_INLINED_PATTERN: &'static str = "call.*c_never_inlined"; + fn main() { rustc() .linker_plugin_lto("on") @@ -31,14 +49,14 @@ fn main() { .disassemble() .input("cmain") .run() - .assert_stdout_not_contains_regex("call.*rust_always_inlined"); + .assert_stdout_not_contains_regex(RUST_ALWAYS_INLINED_PATTERN); // As a sanity check, make sure we do find a call instruction to a // non-inlined function llvm_objdump() .disassemble() .input("cmain") .run() - .assert_stdout_contains_regex("call.*rust_never_inlined"); + .assert_stdout_contains_regex(RUST_NEVER_INLINED_PATTERN); clang().input("clib.c").lto("thin").arg("-c").out_exe("clib.o").arg("-O2").run(); llvm_ar().obj_to_ar().output_input(static_lib_name("xyz"), "clib.o").run(); rustc() @@ -53,10 +71,10 @@ fn main() { .disassemble() .input("rsmain") .run() - .assert_stdout_not_contains_regex("call.*c_always_inlined"); + .assert_stdout_not_contains_regex(C_ALWAYS_INLINED_PATTERN); llvm_objdump() .disassemble() .input("rsmain") .run() - .assert_stdout_contains_regex("call.*c_never_inlined"); + .assert_stdout_contains_regex(C_NEVER_INLINED_PATTERN); } diff --git a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs index 92573353a74..e595dbea94d 100644 --- a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs +++ b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs @@ -1,21 +1,20 @@ -//! Make sure that cross-language LTO works on riscv targets, -//! which requires extra `target-abi` metadata to be emitted. +//! Make sure that cross-language LTO works on riscv targets, which requires extra `target-abi` +//! metadata to be emitted. //@ needs-force-clang-based-tests -//@ needs-llvm-components riscv +//@ needs-llvm-components: riscv -//@ needs-force-clang-based-tests -// FIXME(#126180): This test can only run on `x86_64-gnu-debug`, because that CI job sets -// RUSTBUILD_FORCE_CLANG_BASED_TESTS and only runs tests which contain "clang" in their -// name. -// However, this test does not run at all as its name does not contain "clang". +// ignore-tidy-linelength -use std::path::PathBuf; -use std::process::{Command, Output}; -use std::{env, str}; +use object::elf; +use object::read::elf as readelf; +use run_make_support::{bin_name, clang, object, rfs, rustc}; -use run_make_support::{bin_name, clang, llvm_readobj, rustc}; - -fn check_target(target: &str, clang_target: &str, carch: &str, is_double_float: bool) { +fn check_target>( + target: &str, + clang_target: &str, + carch: &str, + is_double_float: bool, +) { eprintln!("Checking target {target}"); // Rust part rustc() @@ -39,16 +38,55 @@ fn check_target(target: &str, clang_target: &str, carch: &str, is_double_float: // Check that the built binary has correct float abi let executable = bin_name("riscv-xlto"); - let output = llvm_readobj().input(&executable).file_header().run(); - let stdout = String::from_utf8_lossy(&output.stdout); - eprintln!("obj:\n{}", stdout); - - assert!(!(is_double_float ^ stdout.contains("EF_RISCV_FLOAT_ABI_DOUBLE"))); + let data = rfs::read(&executable); + let header = ::parse(&*data).unwrap(); + let endian = match header.e_ident().data { + elf::ELFDATA2LSB => object::Endianness::Little, + elf::ELFDATA2MSB => object::Endianness::Big, + x => unreachable!("invalid e_ident data: {:#010b}", x), + }; + // Check `(e_flags & EF_RISCV_FLOAT_ABI) == EF_RISCV_FLOAT_ABI_DOUBLE`. + // + // See + // . + if is_double_float { + assert_eq!( + header.e_flags(endian) & elf::EF_RISCV_FLOAT_ABI, + elf::EF_RISCV_FLOAT_ABI_DOUBLE, + "expected {target} to use double ABI, but it did not" + ); + } else { + assert_ne!( + header.e_flags(endian) & elf::EF_RISCV_FLOAT_ABI, + elf::EF_RISCV_FLOAT_ABI_DOUBLE, + "did not expected {target} to use double ABI" + ); + } } fn main() { - check_target("riscv64gc-unknown-linux-gnu", "riscv64-linux-gnu", "rv64gc", true); - check_target("riscv64imac-unknown-none-elf", "riscv64-unknown-elf", "rv64imac", false); - check_target("riscv32imac-unknown-none-elf", "riscv32-unknown-elf", "rv32imac", false); - check_target("riscv32gc-unknown-linux-gnu", "riscv32-linux-gnu", "rv32gc", true); + check_target::>( + "riscv64gc-unknown-linux-gnu", + "riscv64-linux-gnu", + "rv64gc", + true, + ); + check_target::>( + "riscv64imac-unknown-none-elf", + "riscv64-unknown-elf", + "rv64imac", + false, + ); + check_target::>( + "riscv32imac-unknown-none-elf", + "riscv32-unknown-elf", + "rv32imac", + false, + ); + check_target::>( + "riscv32gc-unknown-linux-gnu", + "riscv32-linux-gnu", + "rv32gc", + true, + ); } diff --git a/tests/run-make/import-macro-verbatim/include/include.txt b/tests/run-make/import-macro-verbatim/include/include.txt new file mode 100644 index 00000000000..63d71b14c1d --- /dev/null +++ b/tests/run-make/import-macro-verbatim/include/include.txt @@ -0,0 +1 @@ +static TEST: &str = "Hello World!"; diff --git a/tests/run-make/import-macro-verbatim/rmake.rs b/tests/run-make/import-macro-verbatim/rmake.rs new file mode 100644 index 00000000000..d2bf626e0aa --- /dev/null +++ b/tests/run-make/import-macro-verbatim/rmake.rs @@ -0,0 +1,8 @@ +//@ only-windows other platforms do not have Windows verbatim paths +use run_make_support::rustc; +fn main() { + // Canonicalizing the path ensures that it's verbatim (i.e. starts with `\\?\`) + let mut path = std::fs::canonicalize(file!()).unwrap(); + path.pop(); + rustc().input("verbatim.rs").env("VERBATIM_DIR", path).run(); +} diff --git a/tests/run-make/import-macro-verbatim/verbatim.rs b/tests/run-make/import-macro-verbatim/verbatim.rs new file mode 100644 index 00000000000..56a83673c1f --- /dev/null +++ b/tests/run-make/import-macro-verbatim/verbatim.rs @@ -0,0 +1,12 @@ +//! Include a file by concating the verbatim path using `/` instead of `\` + +include!(concat!(env!("VERBATIM_DIR"), "/include/include.txt")); +fn main() { + assert_eq!(TEST, "Hello World!"); + + let s = include_str!(concat!(env!("VERBATIM_DIR"), "/include/include.txt")); + assert_eq!(s, "static TEST: &str = \"Hello World!\";\n"); + + let b = include_bytes!(concat!(env!("VERBATIM_DIR"), "/include/include.txt")); + assert_eq!(b, b"static TEST: &str = \"Hello World!\";\n"); +} diff --git a/tests/run-make/issue-84395-lto-embed-bitcode/Makefile b/tests/run-make/issue-84395-lto-embed-bitcode/Makefile deleted file mode 100644 index aabe90754a6..00000000000 --- a/tests/run-make/issue-84395-lto-embed-bitcode/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# needs-force-clang-based-tests - -# FIXME(#126180): This test doesn't actually run anywhere, because the only -# CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests. - -# This test makes sure the embed bitcode in elf created with -# lto-embed-bitcode=optimized is valid llvm BC module. - -include ../tools.mk - -all: - $(RUSTC) test.rs --target $(TARGET) -Clink-arg=-fuse-ld=lld -Clinker-plugin-lto -Clinker=$(CLANG) -Clink-arg=-Wl,--plugin-opt=-lto-embed-bitcode=optimized -Zemit-thin-lto=no - $(LLVM_BIN_DIR)/objcopy --dump-section .llvmbc=$(TMPDIR)/test.bc $(TMPDIR)/test - $(LLVM_BIN_DIR)/llvm-dis $(TMPDIR)/test.bc diff --git a/tests/run-make/issue-84395-lto-embed-bitcode/rmake.rs b/tests/run-make/issue-84395-lto-embed-bitcode/rmake.rs new file mode 100644 index 00000000000..450d8a9f099 --- /dev/null +++ b/tests/run-make/issue-84395-lto-embed-bitcode/rmake.rs @@ -0,0 +1,27 @@ +//! Smoke test to make sure the embed bitcode in elf created with +//! `--plugin-opt=-lto-embed-bitcode=optimized` is valid llvm BC module. +//! +//! See where passing +//! `-lto-embed-bitcode=optimized` to lld when linking rust code via `linker-plugin-lto` doesn't +//! produce the expected result. +//! +//! See PR which initially introduced this test. + +//@ needs-force-clang-based-tests + +use run_make_support::{env_var, llvm_dis, llvm_objcopy, rustc}; + +fn main() { + rustc() + .input("test.rs") + .arg("-Clink-arg=-fuse-ld=lld") + .arg("-Clinker-plugin-lto") + .arg(format!("-Clinker={}", env_var("CLANG"))) + .arg("-Clink-arg=-Wl,--plugin-opt=-lto-embed-bitcode=optimized") + .arg("-Zemit-thin-lto=no") + .run(); + + llvm_objcopy().dump_section(".llvmbc", "test.bc").arg("test").run(); + + llvm_dis().arg("test.bc").run(); +} diff --git a/tests/run-make/linkage-attr-framework/main.rs b/tests/run-make/linkage-attr-framework/main.rs new file mode 100644 index 00000000000..8efabc83e62 --- /dev/null +++ b/tests/run-make/linkage-attr-framework/main.rs @@ -0,0 +1,17 @@ +#![cfg_attr(any(weak, both), feature(link_arg_attribute))] + +#[cfg_attr(any(link, both), link(name = "CoreFoundation", kind = "framework"))] +#[cfg_attr( + any(weak, both), + link(name = "-weak_framework", kind = "link-arg", modifiers = "+verbatim"), + link(name = "CoreFoundation", kind = "link-arg", modifiers = "+verbatim") +)] +extern "C" { + fn CFRunLoopGetTypeID() -> core::ffi::c_ulong; +} + +fn main() { + unsafe { + CFRunLoopGetTypeID(); + } +} diff --git a/tests/run-make/linkage-attr-framework/rmake.rs b/tests/run-make/linkage-attr-framework/rmake.rs new file mode 100644 index 00000000000..4450350f96e --- /dev/null +++ b/tests/run-make/linkage-attr-framework/rmake.rs @@ -0,0 +1,26 @@ +//! Check that linking frameworks on Apple platforms works. + +//@ only-apple + +use run_make_support::{Rustc, run, rustc}; + +fn compile(cfg: &str) -> Rustc { + let mut rustc = rustc(); + rustc.cfg(cfg).input("main.rs"); + rustc +} + +fn main() { + for cfg in ["link", "weak", "both"] { + compile(cfg).run(); + run("main"); + } + + let errs = compile("omit").run_fail(); + // The linker's exact error output changes between Xcode versions, depends on + // linker invocation details, and the linker sometimes outputs more warnings. + errs.assert_stderr_contains_regex(r"error: linking with `.*` failed"); + errs.assert_stderr_contains_regex(r"(Undefined symbols|ld: symbol[^\s]* not found)"); + errs.assert_stderr_contains_regex(r".?_CFRunLoopGetTypeID.?, referenced from:"); + errs.assert_stderr_contains("clang: error: linker command failed with exit code 1"); +} 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 new file mode 100644 index 00000000000..cf6e3d86377 --- /dev/null +++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs @@ -0,0 +1,36 @@ +// `-Z branch protection` is an unstable compiler feature which adds pointer-authentication +// code (PAC), a useful hashing measure for verifying that pointers have not been modified. +// This test checks that compilation and execution is successful when this feature is activated, +// with some of its possible extra arguments (bti, pac-ret, leaf) when doing LTO. +// See https://github.com/rust-lang/rust/pull/88354 + +//@ needs-force-clang-based-tests +//@ only-aarch64 +// Reason: branch protection is not supported on other architectures +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{clang, env_var, llvm_ar, run, rustc, static_lib_name}; + +fn main() { + clang() + .arg("-v") + .lto("thin") + .arg("-mbranch-protection=bti+pac-ret+leaf") + .arg("-O2") + .arg("-c") + .out_exe("test.o") + .input("test.c") + .run(); + llvm_ar().obj_to_ar().output_input(static_lib_name("test"), "test.o").run(); + rustc() + .linker_plugin_lto("on") + .opt_level("2") + .linker(&env_var("CLANG")) + .link_arg("-fuse-ld=lld") + .arg("-Zbranch-protection=bti,pac-ret,leaf") + .input("test.rs") + .output("test.bin") + .run(); + run("test.bin"); +} diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/test.c b/tests/run-make/pointer-auth-link-with-c-lto-clang/test.c new file mode 100644 index 00000000000..9fe07f82f9e --- /dev/null +++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/test.c @@ -0,0 +1 @@ +int foo() { return 0; } diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/test.rs b/tests/run-make/pointer-auth-link-with-c-lto-clang/test.rs new file mode 100644 index 00000000000..1a3be80e898 --- /dev/null +++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/test.rs @@ -0,0 +1,10 @@ +#[link(name = "test")] +extern "C" { + fn foo() -> i32; +} + +fn main() { + unsafe { + foo(); + } +} diff --git a/tests/run-make/rust-lld-link-script-provide/main.rs b/tests/run-make/rust-lld-link-script-provide/main.rs new file mode 100644 index 00000000000..5c19e7a4bbf --- /dev/null +++ b/tests/run-make/rust-lld-link-script-provide/main.rs @@ -0,0 +1,7 @@ +#[no_mangle] +fn foo() {} + +#[no_mangle] +fn bar() {} + +fn main() {} diff --git a/tests/run-make/rust-lld-link-script-provide/rmake.rs b/tests/run-make/rust-lld-link-script-provide/rmake.rs new file mode 100644 index 00000000000..e78a411bc15 --- /dev/null +++ b/tests/run-make/rust-lld-link-script-provide/rmake.rs @@ -0,0 +1,18 @@ +// This test ensures that the “symbol not found” error does not occur +// when the symbols in the `PROVIDE` of the link script can be eliminated. +// This is a regression test for #131164. + +//@ needs-rust-lld +//@ only-x86_64-unknown-linux-gnu + +use run_make_support::rustc; + +fn main() { + rustc() + .input("main.rs") + .arg("-Zlinker-features=+lld") + .arg("-Clink-self-contained=+linker") + .arg("-Zunstable-options") + .link_arg("-Tscript.t") + .run(); +} diff --git a/tests/run-make/rust-lld-link-script-provide/script.t b/tests/run-make/rust-lld-link-script-provide/script.t new file mode 100644 index 00000000000..4c4c6ddfc36 --- /dev/null +++ b/tests/run-make/rust-lld-link-script-provide/script.t @@ -0,0 +1 @@ +PROVIDE(foo = bar); diff --git a/tests/rustdoc-gui/check-stab-in-docblock.goml b/tests/rustdoc-gui/check-stab-in-docblock.goml index f25c88690e5..916bea6b069 100644 --- a/tests/rustdoc-gui/check-stab-in-docblock.goml +++ b/tests/rustdoc-gui/check-stab-in-docblock.goml @@ -1,5 +1,5 @@ // This test checks that using `.stab` attributes in `.docblock` elements doesn't -// create scrollable paragraphs. +// create scrollable paragraphs and is correctly displayed (not making weird blocks). go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" // Needs the text to be display to check for scrollable content. show-text: true @@ -31,3 +31,15 @@ assert-property: ( ".top-doc .docblock p:nth-of-type(3)", {"scrollHeight": |clientHeight|, "scrollWidth": |clientWidth|}, ) + +// Ensure that `` elements in code don't make big blocks. +compare-elements-size-near: ( + "#reexport\.TheStdReexport > code", + ".docblock p span[data-span='1']", + {"height": 1}, +) +compare-elements-size-near: ( + "#reexport\.TheStdReexport > code", + ".docblock p span[data-span='2']", + {"height": 1}, +) diff --git a/tests/rustdoc-gui/docblock-big-code-mobile.goml b/tests/rustdoc-gui/docblock-big-code-mobile.goml index 6fc6834768e..71e08e2c7e2 100644 --- a/tests/rustdoc-gui/docblock-big-code-mobile.goml +++ b/tests/rustdoc-gui/docblock-big-code-mobile.goml @@ -1,13 +1,15 @@ // If we have a long ``, we need to ensure that it'll be fully displayed on mobile, meaning // that it'll be on two lines. + emulate: "iPhone 8" // it has the following size: (375, 667) go-to: "file://" + |DOC_PATH| + "/test_docs/long_code_block/index.html" -// We now check that the block is on two lines: show-text: true // We need to enable text draw to be able to have the "real" size + +// We now check that the block is on two lines: // Little explanations for this test: if the text wasn't displayed on two lines, it would take -// around 20px (which is the font size). -assert-property: (".docblock p > code", {"offsetHeight": "44"}) +// around 24px (which is the font size). +assert-size: (".docblock p > code", {"height": 48}) // Same check, but where the long code block is also a link go-to: "file://" + |DOC_PATH| + "/test_docs/long_code_block_link/index.html" -assert-property: (".docblock p > a > code", {"offsetHeight": "44"}) +assert-size: (".docblock p > a > code", {"height": 48}) diff --git a/tests/rustdoc-gui/fields.goml b/tests/rustdoc-gui/fields.goml index b8139a2edac..5d13d7be2f9 100644 --- a/tests/rustdoc-gui/fields.goml +++ b/tests/rustdoc-gui/fields.goml @@ -1,13 +1,36 @@ -// This test checks that fields are displayed as expected (one by line). -go-to: "file://" + |DOC_PATH| + "/test_docs/fields/struct.Struct.html" -store-position: ("#structfield\.a", {"y": a_y}) -store-position: ("#structfield\.b", {"y": b_y}) -assert: |a_y| < |b_y| +// This test checks that fields are displayed as expected (one by line) and they are surrounded +// by margins. -go-to: "file://" + |DOC_PATH| + "/test_docs/fields/union.Union.html" -store-position: ("#structfield\.a", {"y": a_y}) -store-position: ("#structfield\.b", {"y": b_y}) -assert: |a_y| < |b_y| +define-function: ( + "check-fields", + [path, selector_1, selector_2], + block { + go-to: "file://" + |DOC_PATH| + "/test_docs/fields/" + |path| + store-position: (|selector_1|, {"y": a_y}) + store-position: (|selector_2|, {"y": b_y}) + assert: |a_y| < |b_y| + + // Check the margins. + assert-css: (".structfield.section-header", { + "margin-top": "9.6px", + "margin-bottom": "9.6px", + "margin-left": "0px", + "margin-right": "0px", + }, ALL) + } +) + +call-function: ("check-fields", { + "path": "struct.Struct.html", + "selector_1": "#structfield\.a", + "selector_2": "#structfield\.b", +}) + +call-function: ("check-fields", { + "path": "union.Union.html", + "selector_1": "#structfield\.a", + "selector_2": "#structfield\.b", +}) go-to: "file://" + |DOC_PATH| + "/test_docs/fields/enum.Enum.html" store-position: ("#variant\.A\.field\.a", {"y": a_y}) @@ -16,3 +39,11 @@ assert: |a_y| < |b_y| store-position: ("#variant\.B\.field\.a", {"y": a_y}) store-position: ("#variant\.B\.field\.b", {"y": b_y}) assert: |a_y| < |b_y| + +// Check the margins. +assert-css: (".sub-variant-field .section-header", { + "margin-top": "0px", + "margin-bottom": "0px", + "margin-left": "0px", + "margin-right": "0px", +}, ALL) diff --git a/tests/rustdoc-gui/item-info.goml b/tests/rustdoc-gui/item-info.goml index c8aa7b31cad..1636e149692 100644 --- a/tests/rustdoc-gui/item-info.goml +++ b/tests/rustdoc-gui/item-info.goml @@ -20,7 +20,7 @@ store-position: ( {"x": second_line_x, "y": second_line_y}, ) assert: |first_line_x| != |second_line_x| && |first_line_x| == 516 && |second_line_x| == 272 -assert: |first_line_y| != |second_line_y| && |first_line_y| == 714 && |second_line_y| == 737 +assert: |first_line_y| != |second_line_y| && |first_line_y| == 718 && |second_line_y| == 741 // Now we ensure that they're not rendered on the same line. set-window-size: (1100, 800) diff --git a/tests/rustdoc-gui/scrape-examples-layout.goml b/tests/rustdoc-gui/scrape-examples-layout.goml index 96c78bbfe8b..5187ac486b0 100644 --- a/tests/rustdoc-gui/scrape-examples-layout.goml +++ b/tests/rustdoc-gui/scrape-examples-layout.goml @@ -80,8 +80,8 @@ click: ".scraped-example .button-holder .expand" store-value: (offset_y, 4) // First with desktop -assert-position: (".scraped-example", {"y": 252}) -assert-position: (".scraped-example .prev", {"y": 252 + |offset_y|}) +assert-position: (".scraped-example", {"y": 256}) +assert-position: (".scraped-example .prev", {"y": 256 + |offset_y|}) // Gradient background should be at the top of the code block. assert-css: (".scraped-example .example-wrap::before", {"top": "0px"}) @@ -90,8 +90,8 @@ assert-css: (".scraped-example .example-wrap::after", {"bottom": "0px"}) // Then with mobile set-window-size: (600, 600) store-size: (".scraped-example .scraped-example-title", {"height": title_height}) -assert-position: (".scraped-example", {"y": 287}) -assert-position: (".scraped-example .prev", {"y": 287 + |offset_y| + |title_height|}) +assert-position: (".scraped-example", {"y": 291}) +assert-position: (".scraped-example .prev", {"y": 291 + |offset_y| + |title_height|}) define-function: ( "check_title_and_code_position", diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml index 742453c173b..1e77bcc2273 100644 --- a/tests/rustdoc-gui/sidebar-source-code-display.goml +++ b/tests/rustdoc-gui/sidebar-source-code-display.goml @@ -141,7 +141,7 @@ click: "#sidebar-button" wait-for-css: (".src .sidebar > *", {"visibility": "hidden"}) // We scroll to line 117 to change the scroll position. scroll-to: '//*[@id="117"]' -store-value: (y_offset, "2570") +store-value: (y_offset, "2578") assert-window-property: {"pageYOffset": |y_offset|} // Expanding the sidebar... click: "#sidebar-button" diff --git a/tests/rustdoc-gui/source-anchor-scroll.goml b/tests/rustdoc-gui/source-anchor-scroll.goml index f8794645705..4ad65bbbd61 100644 --- a/tests/rustdoc-gui/source-anchor-scroll.goml +++ b/tests/rustdoc-gui/source-anchor-scroll.goml @@ -8,13 +8,13 @@ set-window-size: (600, 800) assert-property: ("html", {"scrollTop": "0"}) click: '//a[text() = "barbar" and @href="#5-7"]' -assert-property: ("html", {"scrollTop": "200"}) +assert-property: ("html", {"scrollTop": "208"}) click: '//a[text() = "bar" and @href="#28-36"]' -assert-property: ("html", {"scrollTop": "231"}) +assert-property: ("html", {"scrollTop": "239"}) click: '//a[normalize-space() = "sub_fn" and @href="#2-4"]' -assert-property: ("html", {"scrollTop": "128"}) +assert-property: ("html", {"scrollTop": "136"}) // We now check that clicking on lines doesn't change the scroll // Extra information: the "sub_fn" function header is on line 1. click: '//*[@id="6"]' -assert-property: ("html", {"scrollTop": "128"}) +assert-property: ("html", {"scrollTop": "136"}) diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml index 095354c2f4c..afb19462521 100644 --- a/tests/rustdoc-gui/source-code-page.goml +++ b/tests/rustdoc-gui/source-code-page.goml @@ -89,7 +89,7 @@ assert-css: (".src-line-numbers", {"text-align": "right"}) // do anything (and certainly not add a `#NaN` to the URL!). go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" // We use this assert-position to know where we will click. -assert-position: ("//*[@id='1']", {"x": 88, "y": 163}) +assert-position: ("//*[@id='1']", {"x": 88, "y": 171}) // We click on the left of the "1" anchor but still in the "src-line-number" `

`.
 click: (163, 77)
 assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
@@ -165,7 +165,7 @@ assert-css: ("nav.sub", {"flex-direction": "row"})
 // offsetTop[nav.sub form] = offsetTop[#main-content] - offsetHeight[nav.sub form] - offsetTop[nav.sub form]
 assert-position: ("nav.sub form", {"y": 15})
 assert-property: ("nav.sub form", {"offsetHeight": 34})
-assert-position: ("h1", {"y": 64})
+assert-position: ("h1", {"y": 68})
 // 15 = 64 - 34 - 15
 
 // Now do the same check on moderately-sized, tablet mobile.
@@ -173,7 +173,7 @@ set-window-size: (700, 700)
 assert-css: ("nav.sub", {"flex-direction": "row"})
 assert-position: ("nav.sub form", {"y": 8})
 assert-property: ("nav.sub form", {"offsetHeight": 34})
-assert-position: ("h1", {"y": 50})
+assert-position: ("h1", {"y": 54})
 // 8 = 50 - 34 - 8
 
 // Check the sidebar directory entries have a marker and spacing (tablet).
diff --git a/tests/rustdoc-gui/struct-fields.goml b/tests/rustdoc-gui/struct-fields.goml
index 3c87a4cd654..302a1a0d80b 100644
--- a/tests/rustdoc-gui/struct-fields.goml
+++ b/tests/rustdoc-gui/struct-fields.goml
@@ -1,4 +1,5 @@
-// This test ensures that each field is on its own line (In other words, they have display: block).
+// This test ensures that each field is on its own line (In other words, they have
+// `display: block`).
 go-to: "file://" + |DOC_PATH| + "/test_docs/struct.StructWithPublicUndocumentedFields.html"
 
 store-property: ("//*[@id='structfield.first']", {"offsetTop": first_top})
diff --git a/tests/rustdoc-js/extern-func.js b/tests/rustdoc-js/extern-func.js
new file mode 100644
index 00000000000..a3fe2d8ea42
--- /dev/null
+++ b/tests/rustdoc-js/extern-func.js
@@ -0,0 +1,8 @@
+const EXPECTED = [
+    {
+        'query': 'c_float -> c_float',
+        'others': [
+            { 'path': 'extern_func', 'name': 'sqrt' }
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/extern-func.rs b/tests/rustdoc-js/extern-func.rs
new file mode 100644
index 00000000000..ab1e3e75da7
--- /dev/null
+++ b/tests/rustdoc-js/extern-func.rs
@@ -0,0 +1,5 @@
+use std::ffi::c_float;
+
+extern "C" {
+    pub fn sqrt(x: c_float) -> c_float;
+}
diff --git a/tests/rustdoc-json/impls/auto.rs b/tests/rustdoc-json/impls/auto.rs
index e14c935b23b..f37dae4c1ed 100644
--- a/tests/rustdoc-json/impls/auto.rs
+++ b/tests/rustdoc-json/impls/auto.rs
@@ -4,8 +4,8 @@
 #[lang = "sized"]
 trait Sized {}
 
-#[lang = "receiver"]
-pub trait Receiver {}
+#[lang = "legacy_receiver"]
+pub trait LegacyReceiver {}
 
 pub auto trait Bar {}
 
diff --git a/tests/rustdoc-ui/deprecated-attrs.rs b/tests/rustdoc-ui/deprecated-attrs.rs
index e4802ee2518..3b59e05a012 100644
--- a/tests/rustdoc-ui/deprecated-attrs.rs
+++ b/tests/rustdoc-ui/deprecated-attrs.rs
@@ -1,16 +1,21 @@
-//@ check-pass
 //@ compile-flags: --passes unknown-pass
 //@ error-pattern: the `passes` flag no longer functions
 
 #![doc(no_default_passes)]
-//~^ WARNING attribute is deprecated
+//~^ ERROR unknown `doc` attribute `no_default_passes`
+//~| NOTE no longer functions
 //~| NOTE see issue #44136
-//~| HELP no longer functions; you may want to use `#![doc(document_private_items)]`
+//~| HELP you may want to use `doc(document_private_items)`
+//~| NOTE `doc(no_default_passes)` is now a no-op
+//~| NOTE `#[deny(invalid_doc_attributes)]` on by default
 #![doc(passes = "collapse-docs unindent-comments")]
-//~^ WARNING attribute is deprecated
+//~^ ERROR unknown `doc` attribute `passes`
+//~| NOTE no longer functions
 //~| NOTE see issue #44136
-//~| HELP no longer functions; you may want to use `#![doc(document_private_items)]`
+//~| HELP you may want to use `doc(document_private_items)`
+//~| NOTE `doc(passes)` is now a no-op
 #![doc(plugins = "xxx")]
-//~^ WARNING attribute is deprecated
+//~^ ERROR unknown `doc` attribute `plugins`
 //~| NOTE see issue #44136
-//~| WARNING no longer functions; see CVE
+//~| NOTE no longer functions
+//~| NOTE `doc(plugins)` is now a no-op
diff --git a/tests/rustdoc-ui/deprecated-attrs.stderr b/tests/rustdoc-ui/deprecated-attrs.stderr
index 45b20ce70ef..a30523e7329 100644
--- a/tests/rustdoc-ui/deprecated-attrs.stderr
+++ b/tests/rustdoc-ui/deprecated-attrs.stderr
@@ -3,32 +3,35 @@ warning: the `passes` flag no longer functions
    = note: see issue #44136  for more information
    = help: you may want to use --document-private-items
 
-warning: the `#![doc(no_default_passes)]` attribute is deprecated
-  --> $DIR/deprecated-attrs.rs:5:8
+error: unknown `doc` attribute `no_default_passes`
+  --> $DIR/deprecated-attrs.rs:4:8
    |
 LL | #![doc(no_default_passes)]
-   |        ^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^ no longer functions
    |
-   = note: see issue #44136  for more information
-   = help: `#![doc(no_default_passes)]` no longer functions; you may want to use `#![doc(document_private_items)]`
+   = note: `doc` attribute `no_default_passes` no longer functions; see issue #44136 
+   = help: you may want to use `doc(document_private_items)`
+   = note: `doc(no_default_passes)` is now a no-op
+   = note: `#[deny(invalid_doc_attributes)]` on by default
 
-warning: the `#![doc(passes = "...")]` attribute is deprecated
-  --> $DIR/deprecated-attrs.rs:9:8
+error: unknown `doc` attribute `passes`
+  --> $DIR/deprecated-attrs.rs:11:8
    |
 LL | #![doc(passes = "collapse-docs unindent-comments")]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no longer functions
    |
-   = note: see issue #44136  for more information
-   = help: `#![doc(passes = "...")]` no longer functions; you may want to use `#![doc(document_private_items)]`
+   = note: `doc` attribute `passes` no longer functions; see issue #44136 
+   = help: you may want to use `doc(document_private_items)`
+   = note: `doc(passes)` is now a no-op
 
-warning: the `#![doc(plugins = "...")]` attribute is deprecated
-  --> $DIR/deprecated-attrs.rs:13:8
+error: unknown `doc` attribute `plugins`
+  --> $DIR/deprecated-attrs.rs:17:8
    |
 LL | #![doc(plugins = "xxx")]
-   |        ^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^ no longer functions
    |
-   = note: see issue #44136  for more information
-   = warning: `#![doc(plugins = "...")]` no longer functions; see CVE-2018-1000622 
+   = note: `doc` attribute `plugins` no longer functions; see issue #44136  and CVE-2018-1000622 
+   = note: `doc(plugins)` is now a no-op
 
-warning: 3 warnings emitted
+error: aborting due to 3 previous errors
 
diff --git a/tests/rustdoc-ui/doctest/nested-main.rs b/tests/rustdoc-ui/doctest/nested-main.rs
new file mode 100644
index 00000000000..e939ba81214
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/nested-main.rs
@@ -0,0 +1,24 @@
+//@ check-pass
+//@ compile-flags:--test --test-args=--test-threads=1
+//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
+//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+// Regression test for .
+// It ensures that if a function called `main` is nested, it will not consider
+// it as the `main` function.
+
+/// ```
+/// fn dox() {
+///     fn main() {}
+/// }
+/// ```
+pub fn foo() {}
+
+// This one ensures that having a nested `main` doesn't prevent the
+// actual `main` function to be detected.
+/// ```
+/// fn main() {
+///     fn main() {}
+/// }
+/// ```
+pub fn foo2() {}
diff --git a/tests/rustdoc-ui/doctest/nested-main.stdout b/tests/rustdoc-ui/doctest/nested-main.stdout
new file mode 100644
index 00000000000..af9a8f5e1d7
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/nested-main.stdout
@@ -0,0 +1,7 @@
+
+running 2 tests
+test $DIR/nested-main.rs - foo (line 10) ... ok
+test $DIR/nested-main.rs - foo2 (line 19) ... ok
+
+test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/tests/rustdoc-ui/rustc-check-passes.stderr b/tests/rustdoc-ui/rustc-check-passes.stderr
index 58d61c0213e..5b20d1128c5 100644
--- a/tests/rustdoc-ui/rustc-check-passes.stderr
+++ b/tests/rustdoc-ui/rustc-check-passes.stderr
@@ -1,4 +1,4 @@
-error[E0636]: the feature `rustdoc_internals` has already been declared
+error[E0636]: the feature `rustdoc_internals` has already been enabled
   --> $DIR/rustc-check-passes.rs:2:12
    |
 LL | #![feature(rustdoc_internals)]
diff --git a/tests/rustdoc/anchors.no_const_anchor.html b/tests/rustdoc/anchors.no_const_anchor.html
index 06673d87406..07a7507fa2e 100644
--- a/tests/rustdoc/anchors.no_const_anchor.html
+++ b/tests/rustdoc/anchors.no_const_anchor.html
@@ -1 +1 @@
-
source

const YOLO: u32

\ No newline at end of file +
Source

const YOLO: u32

\ No newline at end of file diff --git a/tests/rustdoc/anchors.no_const_anchor2.html b/tests/rustdoc/anchors.no_const_anchor2.html index 73c3d0a807b..091dac3e4b2 100644 --- a/tests/rustdoc/anchors.no_const_anchor2.html +++ b/tests/rustdoc/anchors.no_const_anchor2.html @@ -1 +1 @@ -
source

pub const X: i32 = 0i32

\ No newline at end of file +
Source

pub const X: i32 = 0i32

\ No newline at end of file diff --git a/tests/rustdoc/anchors.no_method_anchor.html b/tests/rustdoc/anchors.no_method_anchor.html index e8b61caa1c1..89f9898624c 100644 --- a/tests/rustdoc/anchors.no_method_anchor.html +++ b/tests/rustdoc/anchors.no_method_anchor.html @@ -1 +1 @@ -
source

pub fn new() -> Self

\ No newline at end of file +
Source

pub fn new() -> Self

\ No newline at end of file diff --git a/tests/rustdoc/anchors.no_trait_method_anchor.html b/tests/rustdoc/anchors.no_trait_method_anchor.html index abdb17c27dc..51656a3e58f 100644 --- a/tests/rustdoc/anchors.no_trait_method_anchor.html +++ b/tests/rustdoc/anchors.no_trait_method_anchor.html @@ -1 +1 @@ -
source

fn bar()

\ No newline at end of file +
Source

fn bar()

\ No newline at end of file diff --git a/tests/rustdoc/anchors.no_tymethod_anchor.html b/tests/rustdoc/anchors.no_tymethod_anchor.html index 23f4277c5b5..49ee624bdbc 100644 --- a/tests/rustdoc/anchors.no_tymethod_anchor.html +++ b/tests/rustdoc/anchors.no_tymethod_anchor.html @@ -1 +1 @@ -
source

fn foo()

\ No newline at end of file +
Source

fn foo()

\ No newline at end of file diff --git a/tests/rustdoc/anchors.no_type_anchor.html b/tests/rustdoc/anchors.no_type_anchor.html index 62b9295508f..c5ac3c93818 100644 --- a/tests/rustdoc/anchors.no_type_anchor.html +++ b/tests/rustdoc/anchors.no_type_anchor.html @@ -1 +1 @@ -
source

type T

\ No newline at end of file +
Source

type T

\ No newline at end of file diff --git a/tests/rustdoc/anchors.no_type_anchor2.html b/tests/rustdoc/anchors.no_type_anchor2.html index 9127104ded4..14dd31d87b6 100644 --- a/tests/rustdoc/anchors.no_type_anchor2.html +++ b/tests/rustdoc/anchors.no_type_anchor2.html @@ -1 +1 @@ -
source

pub type Y = u32

\ No newline at end of file +
Source

pub type Y = u32

\ No newline at end of file diff --git a/tests/rustdoc/assoc-type-source-link.rs b/tests/rustdoc/assoc-type-source-link.rs index 34b156b9649..a955a67a457 100644 --- a/tests/rustdoc/assoc-type-source-link.rs +++ b/tests/rustdoc/assoc-type-source-link.rs @@ -8,7 +8,7 @@ pub struct Bar; impl Bar { - //@ has - '//*[@id="implementations-list"]//*[@id="associatedtype.Y"]/a' 'source' + //@ has - '//*[@id="implementations-list"]//*[@id="associatedtype.Y"]/a' 'Source' //@ has - '//*[@id="implementations-list"]//*[@id="associatedtype.Y"]/a/@href' \ // '../src/foo/assoc-type-source-link.rs.html#14' pub type Y = u8; @@ -19,7 +19,7 @@ pub trait Foo { } impl Foo for Bar { - //@ has - '//*[@id="trait-implementations-list"]//*[@id="associatedtype.Z"]/a' 'source' + //@ has - '//*[@id="trait-implementations-list"]//*[@id="associatedtype.Z"]/a' 'Source' //@ has - '//*[@id="trait-implementations-list"]//*[@id="associatedtype.Z"]/a/@href' \ // '../src/foo/assoc-type-source-link.rs.html#25' type Z = u8; diff --git a/tests/rustdoc/const-display.rs b/tests/rustdoc/const-display.rs index a71825d883d..bc4270c421d 100644 --- a/tests/rustdoc/const-display.rs +++ b/tests/rustdoc/const-display.rs @@ -89,10 +89,4 @@ impl Bar { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const2", since = "1.2.0")] pub const fn stable_impl() -> u32 { 42 } - - // Show const-stability even for unstable functions. - //@ matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.3.0$' - #[unstable(feature = "foo2", issue = "none")] - #[rustc_const_stable(feature = "const3", since = "1.3.0")] - pub const fn const_stable_unstable() -> u32 { 42 } } diff --git a/tests/rustdoc/demo-allocator-54478.rs b/tests/rustdoc/demo-allocator-54478.rs index dd98e80f03a..80acfc0ff58 100644 --- a/tests/rustdoc/demo-allocator-54478.rs +++ b/tests/rustdoc/demo-allocator-54478.rs @@ -40,6 +40,7 @@ //! } //! //! fn main() { +//! drop(String::from("An allocation")); //! assert!(unsafe { HIT }); //! } //! ``` diff --git a/tests/rustdoc/ensure-src-link.rs b/tests/rustdoc/ensure-src-link.rs index 4156fdcba59..f70902b1756 100644 --- a/tests/rustdoc/ensure-src-link.rs +++ b/tests/rustdoc/ensure-src-link.rs @@ -2,5 +2,5 @@ // This test ensures that the [src] link is present on traits items. -//@ has foo/trait.Iterator.html '//*[@id="method.zip"]//a[@class="src"]' "source" +//@ has foo/trait.Iterator.html '//*[@id="method.zip"]//a[@class="src"]' "Source" pub use std::iter::Iterator; diff --git a/tests/rustdoc/external-macro-src.rs b/tests/rustdoc/external-macro-src.rs index f723af57fad..998687d93bd 100644 --- a/tests/rustdoc/external-macro-src.rs +++ b/tests/rustdoc/external-macro-src.rs @@ -5,8 +5,8 @@ #[macro_use] extern crate external_macro_src; -//@ has foo/index.html '//a[@href="../src/foo/external-macro-src.rs.html#3-12"]' 'source' +//@ has foo/index.html '//a[@href="../src/foo/external-macro-src.rs.html#3-12"]' 'Source' //@ has foo/struct.Foo.html -//@ has - '//a[@href="../src/foo/external-macro-src.rs.html#12"]' 'source' +//@ has - '//a[@href="../src/foo/external-macro-src.rs.html#12"]' 'Source' make_foo!(); diff --git a/tests/rustdoc/primitive-tuple-variadic.rs b/tests/rustdoc/primitive-tuple-variadic.rs index b15e996f929..d142729d2a8 100644 --- a/tests/rustdoc/primitive-tuple-variadic.rs +++ b/tests/rustdoc/primitive-tuple-variadic.rs @@ -33,3 +33,22 @@ impl Baz<[T; 1]> for (T,) {} //@ has - '//section[@id="impl-Baz%3CT%3E-for-(T,)"]/h3' 'impl Baz for (T₁, T₂, …, Tₙ)' #[doc(fake_variadic)] impl Baz for (T,) {} + +pub trait Qux {} + +pub struct NewType(T); + +//@ has foo/trait.Qux.html +//@ has - '//section[@id="impl-Qux-for-NewType%3C(T,)%3E"]/h3' 'impl Qux for NewType<(T₁, T₂, …, Tₙ)>' +#[doc(fake_variadic)] +impl Qux for NewType<(T,)> {} + +//@ has foo/trait.Qux.html +//@ has - '//section[@id="impl-Qux-for-NewType%3CNewType%3C(T,)%3E%3E"]/h3' 'impl Qux for NewType>' +#[doc(fake_variadic)] +impl Qux for NewType> {} + +//@ has foo/trait.Qux.html +//@ has - '//section[@id="impl-Qux-for-NewType%3Cfn(T)+-%3E+Out%3E"]/h3' 'impl Qux for NewType Out>' +#[doc(fake_variadic)] +impl Qux for NewType Out> {} diff --git a/tests/rustdoc/source-version-separator.rs b/tests/rustdoc/source-version-separator.rs index 9709bbe3c71..78b9d364d21 100644 --- a/tests/rustdoc/source-version-separator.rs +++ b/tests/rustdoc/source-version-separator.rs @@ -3,23 +3,23 @@ #![feature(staged_api)] //@ has foo/trait.Bar.html -//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source' +//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · Source' #[stable(feature = "bar", since = "1.0")] pub trait Bar { - //@ has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0.0 · source' + //@ has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0.0 · Source' #[stable(feature = "foobar", since = "3.0")] fn foo(); } -//@ has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0.0 · source' +//@ has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0.0 · Source' //@ has foo/struct.Foo.html -//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source' +//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · Source' #[stable(feature = "baz", since = "1.0")] pub struct Foo; impl Foo { - //@ has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0.0 · source' + //@ has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0.0 · Source' #[stable(feature = "foobar", since = "3.0")] pub fn foofoo() {} } diff --git a/tests/rustdoc/src-link-external-macro-26606.rs b/tests/rustdoc/src-link-external-macro-26606.rs index b5662be9b2d..0ce829f06f5 100644 --- a/tests/rustdoc/src-link-external-macro-26606.rs +++ b/tests/rustdoc/src-link-external-macro-26606.rs @@ -10,5 +10,5 @@ extern crate issue_26606_macro; //@ has issue_26606/constant.FOO.html -//@ has - '//a[@href="../src/issue_26606/src-link-external-macro-26606.rs.html#14"]' 'source' +//@ has - '//a[@href="../src/issue_26606/src-link-external-macro-26606.rs.html#14"]' 'Source' make_item!(FOO); diff --git a/tests/rustdoc/src-links-auto-impls.rs b/tests/rustdoc/src-links-auto-impls.rs index dd07f85eee7..5a777f59b7e 100644 --- a/tests/rustdoc/src-links-auto-impls.rs +++ b/tests/rustdoc/src-links-auto-impls.rs @@ -2,11 +2,11 @@ //@ has foo/struct.Unsized.html //@ has - '//*[@id="impl-Sized-for-Unsized"]/h3[@class="code-header"]' 'impl !Sized for Unsized' -//@ !has - '//*[@id="impl-Sized-for-Unsized"]//a[@class="src"]' 'source' +//@ !has - '//*[@id="impl-Sized-for-Unsized"]//a[@class="src"]' 'Source' //@ has - '//*[@id="impl-Sync-for-Unsized"]/h3[@class="code-header"]' 'impl Sync for Unsized' -//@ !has - '//*[@id="impl-Sync-for-Unsized"]//a[@class="src"]' 'source' +//@ !has - '//*[@id="impl-Sync-for-Unsized"]//a[@class="src"]' 'Source' //@ has - '//*[@id="impl-Any-for-T"]/h3[@class="code-header"]' 'impl Any for T' -//@ has - '//*[@id="impl-Any-for-T"]//a[@class="src rightside"]' 'source' +//@ has - '//*[@id="impl-Any-for-T"]//a[@class="src rightside"]' 'Source' pub struct Unsized { data: [u8], } diff --git a/tests/rustdoc/thread-local-src.rs b/tests/rustdoc/thread-local-src.rs index b23a9a48654..16509e8514d 100644 --- a/tests/rustdoc/thread-local-src.rs +++ b/tests/rustdoc/thread-local-src.rs @@ -1,6 +1,6 @@ #![crate_name = "foo"] -//@ has foo/index.html '//a[@href="../src/foo/thread-local-src.rs.html#1-6"]' 'source' +//@ has foo/index.html '//a[@href="../src/foo/thread-local-src.rs.html#1-6"]' 'Source' -//@ has foo/constant.FOO.html '//a[@href="../src/foo/thread-local-src.rs.html#6"]' 'source' +//@ has foo/constant.FOO.html '//a[@href="../src/foo/thread-local-src.rs.html#6"]' 'Source' thread_local!(pub static FOO: bool = false); diff --git a/tests/rustdoc/trait-src-link.rs b/tests/rustdoc/trait-src-link.rs index 7c3afb7d7d3..7bf883d52da 100644 --- a/tests/rustdoc/trait-src-link.rs +++ b/tests/rustdoc/trait-src-link.rs @@ -1,26 +1,26 @@ #![crate_name = "quix"] pub trait Foo { - //@ has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#4"]' 'source' + //@ has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#4"]' 'Source' fn required(); - //@ has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'source' + //@ has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'Source' fn provided() {} } pub struct Bar; impl Foo for Bar { - //@ has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#14"]' 'source' + //@ has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#14"]' 'Source' fn required() {} - //@ has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'source' + //@ has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'Source' } pub struct Baz; impl Foo for Baz { - //@ has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#22"]' 'source' + //@ has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#22"]' 'Source' fn required() {} - //@ has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#25"]' 'source' + //@ has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#25"]' 'Source' fn provided() {} } diff --git a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs index c3df917ed12..6eb698c96f6 100644 --- a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs +++ b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs @@ -6,7 +6,7 @@ extern crate rustc_middle; extern crate rustc_session; -use rustc_session::lint::{LintPass, LintVec}; +use rustc_session::lint::{LintPass, LintVec, Lint}; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; declare_lint! { @@ -21,6 +21,10 @@ impl LintPass for Foo { //~ERROR implementing `LintPass` by hand fn name(&self) -> &'static str { "Foo" } + + fn get_lints(&self) -> Vec<&'static Lint> { + vec![TEST_LINT] + } } macro_rules! custom_lint_pass_macro { @@ -31,6 +35,10 @@ macro_rules! custom_lint_pass_macro { fn name(&self) -> &'static str { "Custom" } + + fn get_lints(&self) -> Vec<&'static Lint> { + vec![TEST_LINT] + } } }; } diff --git a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr index ad6e93334cd..824eb35424d 100644 --- a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr +++ b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr @@ -12,7 +12,7 @@ LL | #![deny(rustc::lint_pass_impl_without_macro)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementing `LintPass` by hand - --> $DIR/lint_pass_impl_without_macro.rs:30:14 + --> $DIR/lint_pass_impl_without_macro.rs:34:14 | LL | impl LintPass for Custom { | ^^^^^^^^ diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index ff7af388514..03fca17aa55 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -1,10 +1,10 @@ -error: unsupported type attribute for diagnostic derive enum +error: derive(Diagnostic): unsupported type attribute for diagnostic derive enum --> $DIR/diagnostic-derive.rs:47:1 | LL | #[diag(no_crate_example, code = E0123)] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:50:5 | LL | Foo, @@ -12,7 +12,7 @@ LL | Foo, | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:52:5 | LL | Bar, @@ -20,13 +20,13 @@ LL | Bar, | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: `#[nonsense(...)]` is not a valid attribute +error: derive(Diagnostic): `#[nonsense(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:63:1 | LL | #[nonsense(no_crate_example, code = E0123)] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:63:1 | LL | #[nonsense(no_crate_example, code = E0123)] @@ -34,7 +34,7 @@ LL | #[nonsense(no_crate_example, code = E0123)] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:70:1 | LL | #[diag(code = E0123)] @@ -42,13 +42,13 @@ LL | #[diag(code = E0123)] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: diagnostic slug must be the first argument +error: derive(Diagnostic): diagnostic slug must be the first argument --> $DIR/diagnostic-derive.rs:80:16 | LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:80:1 | LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")] @@ -56,7 +56,7 @@ LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: unknown argument +error: derive(Diagnostic): unknown argument --> $DIR/diagnostic-derive.rs:86:8 | LL | #[diag(nonsense = "...", code = E0123, slug = "foo")] @@ -64,7 +64,7 @@ LL | #[diag(nonsense = "...", code = E0123, slug = "foo")] | = note: only the `code` parameter is valid after the slug -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:86:1 | LL | #[diag(nonsense = "...", code = E0123, slug = "foo")] @@ -72,7 +72,7 @@ LL | #[diag(nonsense = "...", code = E0123, slug = "foo")] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: unknown argument +error: derive(Diagnostic): unknown argument --> $DIR/diagnostic-derive.rs:92:8 | LL | #[diag(nonsense = 4, code = E0123, slug = "foo")] @@ -80,7 +80,7 @@ LL | #[diag(nonsense = 4, code = E0123, slug = "foo")] | = note: only the `code` parameter is valid after the slug -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:92:1 | LL | #[diag(nonsense = 4, code = E0123, slug = "foo")] @@ -88,7 +88,7 @@ LL | #[diag(nonsense = 4, code = E0123, slug = "foo")] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: unknown argument +error: derive(Diagnostic): unknown argument --> $DIR/diagnostic-derive.rs:98:40 | LL | #[diag(no_crate_example, code = E0123, slug = "foo")] @@ -96,13 +96,13 @@ LL | #[diag(no_crate_example, code = E0123, slug = "foo")] | = note: only the `code` parameter is valid after the slug -error: `#[suggestion = ...]` is not a valid attribute +error: derive(Diagnostic): `#[suggestion = ...]` is not a valid attribute --> $DIR/diagnostic-derive.rs:105:5 | LL | #[suggestion = "bar"] | ^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:112:8 | LL | #[diag(no_crate_example, code = E0456)] @@ -114,7 +114,7 @@ note: previously specified here LL | #[diag(no_crate_example, code = E0123)] | ^^^^^^^^^^^^^^^^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:112:26 | LL | #[diag(no_crate_example, code = E0456)] @@ -126,7 +126,7 @@ note: previously specified here LL | #[diag(no_crate_example, code = E0123)] | ^^^^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:118:40 | LL | #[diag(no_crate_example, code = E0123, code = E0456)] @@ -138,13 +138,13 @@ note: previously specified here LL | #[diag(no_crate_example, code = E0123, code = E0456)] | ^^^^ -error: diagnostic slug must be the first argument +error: derive(Diagnostic): diagnostic slug must be the first argument --> $DIR/diagnostic-derive.rs:123:43 | LL | #[diag(no_crate_example, no_crate::example, code = E0123)] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:128:1 | LL | struct KindNotProvided {} @@ -152,7 +152,7 @@ LL | struct KindNotProvided {} | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:131:1 | LL | #[diag(code = E0123)] @@ -160,25 +160,25 @@ LL | #[diag(code = E0123)] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` +error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` --> $DIR/diagnostic-derive.rs:142:5 | LL | #[primary_span] | ^ -error: `#[nonsense]` is not a valid attribute +error: derive(Diagnostic): `#[nonsense]` is not a valid attribute --> $DIR/diagnostic-derive.rs:150:5 | LL | #[nonsense] | ^ -error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` +error: derive(Diagnostic): the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` --> $DIR/diagnostic-derive.rs:167:5 | LL | #[label(no_crate_label)] | ^ -error: `name` doesn't refer to a field on this type +error: derive(Diagnostic): `name` doesn't refer to a field on this type --> $DIR/diagnostic-derive.rs:175:46 | LL | #[suggestion(no_crate_suggestion, code = "{name}")] @@ -202,19 +202,19 @@ LL | #[derive(Diagnostic)] = note: if you intended to print `}`, you can escape it using `}}` = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) -error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` +error: derive(Diagnostic): the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` --> $DIR/diagnostic-derive.rs:210:5 | LL | #[label(no_crate_label)] | ^ -error: suggestion without `code = "..."` +error: derive(Diagnostic): suggestion without `code = "..."` --> $DIR/diagnostic-derive.rs:229:5 | LL | #[suggestion(no_crate_suggestion)] | ^ -error: invalid nested attribute +error: derive(Diagnostic): invalid nested attribute --> $DIR/diagnostic-derive.rs:237:18 | LL | #[suggestion(nonsense = "bar")] @@ -222,13 +222,13 @@ LL | #[suggestion(nonsense = "bar")] | = help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes -error: suggestion without `code = "..."` +error: derive(Diagnostic): suggestion without `code = "..."` --> $DIR/diagnostic-derive.rs:237:5 | LL | #[suggestion(nonsense = "bar")] | ^ -error: invalid nested attribute +error: derive(Diagnostic): invalid nested attribute --> $DIR/diagnostic-derive.rs:246:18 | LL | #[suggestion(msg = "bar")] @@ -236,13 +236,13 @@ LL | #[suggestion(msg = "bar")] | = help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes -error: suggestion without `code = "..."` +error: derive(Diagnostic): suggestion without `code = "..."` --> $DIR/diagnostic-derive.rs:246:5 | LL | #[suggestion(msg = "bar")] | ^ -error: wrong field type for suggestion +error: derive(Diagnostic): wrong field type for suggestion --> $DIR/diagnostic-derive.rs:269:5 | LL | #[suggestion(no_crate_suggestion, code = "This is suggested code")] @@ -250,7 +250,7 @@ LL | #[suggestion(no_crate_suggestion, code = "This is suggested code")] | = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)` -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:285:24 | LL | suggestion: (Span, Span, Applicability), @@ -262,7 +262,7 @@ note: previously specified here LL | suggestion: (Span, Span, Applicability), | ^^^^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:293:33 | LL | suggestion: (Applicability, Applicability, Span), @@ -274,13 +274,13 @@ note: previously specified here LL | suggestion: (Applicability, Applicability, Span), | ^^^^^^^^^^^^^ -error: `#[label = ...]` is not a valid attribute +error: derive(Diagnostic): `#[label = ...]` is not a valid attribute --> $DIR/diagnostic-derive.rs:300:5 | LL | #[label = "bar"] | ^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:451:5 | LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")] @@ -292,37 +292,37 @@ note: previously specified here LL | suggestion: (Span, Applicability), | ^^^^^^^^^^^^^ -error: invalid applicability +error: derive(Diagnostic): invalid applicability --> $DIR/diagnostic-derive.rs:459:69 | LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")] | ^^^^^^^^ -error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()` +error: derive(Diagnostic): the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()` --> $DIR/diagnostic-derive.rs:526:5 | LL | #[help(no_crate_help)] | ^ -error: a diagnostic slug must be the first argument to the attribute +error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute --> $DIR/diagnostic-derive.rs:535:32 | LL | #[label(no_crate_label, foo)] | ^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/diagnostic-derive.rs:543:29 | LL | #[label(no_crate_label, foo = "...")] | ^^^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/diagnostic-derive.rs:551:29 | LL | #[label(no_crate_label, foo("..."))] | ^^^ -error: `#[primary_span]` is not a valid attribute +error: derive(Diagnostic): `#[primary_span]` is not a valid attribute --> $DIR/diagnostic-derive.rs:563:5 | LL | #[primary_span] @@ -330,13 +330,13 @@ LL | #[primary_span] | = help: the `primary_span` field attribute is not valid for lint diagnostics -error: `#[error(...)]` is not a valid attribute +error: derive(Diagnostic): `#[error(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:583:1 | LL | #[error(no_crate_example, code = E0123)] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:583:1 | LL | #[error(no_crate_example, code = E0123)] @@ -344,13 +344,13 @@ LL | #[error(no_crate_example, code = E0123)] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: `#[warn_(...)]` is not a valid attribute +error: derive(Diagnostic): `#[warn_(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:590:1 | LL | #[warn_(no_crate_example, code = E0123)] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:590:1 | LL | #[warn_(no_crate_example, code = E0123)] @@ -358,13 +358,13 @@ LL | #[warn_(no_crate_example, code = E0123)] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: `#[lint(...)]` is not a valid attribute +error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:597:1 | LL | #[lint(no_crate_example, code = E0123)] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:597:1 | LL | #[lint(no_crate_example, code = E0123)] @@ -372,13 +372,13 @@ LL | #[lint(no_crate_example, code = E0123)] | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` -error: `#[lint(...)]` is not a valid attribute +error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:604:1 | LL | #[lint(no_crate_example, code = E0123)] | ^ -error: diagnostic slug not specified +error: derive(Diagnostic): diagnostic slug not specified --> $DIR/diagnostic-derive.rs:604:1 | LL | #[lint(no_crate_example, code = E0123)] @@ -386,7 +386,7 @@ LL | #[lint(no_crate_example, code = E0123)] | = help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest_example)]` -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/diagnostic-derive.rs:613:53 | LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")] @@ -398,7 +398,7 @@ note: previously specified here LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")] | ^^^^ -error: wrong types for suggestion +error: derive(Diagnostic): wrong types for suggestion --> $DIR/diagnostic-derive.rs:622:24 | LL | suggestion: (Span, usize), @@ -406,7 +406,7 @@ LL | suggestion: (Span, usize), | = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` -error: wrong types for suggestion +error: derive(Diagnostic): wrong types for suggestion --> $DIR/diagnostic-derive.rs:630:17 | LL | suggestion: (Span,), @@ -414,13 +414,13 @@ LL | suggestion: (Span,), | = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` -error: suggestion without `code = "..."` +error: derive(Diagnostic): suggestion without `code = "..."` --> $DIR/diagnostic-derive.rs:637:5 | LL | #[suggestion(no_crate_suggestion)] | ^ -error: `#[multipart_suggestion(...)]` is not a valid attribute +error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:644:1 | LL | #[multipart_suggestion(no_crate_suggestion)] @@ -428,7 +428,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)] | = help: consider creating a `Subdiagnostic` instead -error: `#[multipart_suggestion(...)]` is not a valid attribute +error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:647:1 | LL | #[multipart_suggestion()] @@ -436,7 +436,7 @@ LL | #[multipart_suggestion()] | = help: consider creating a `Subdiagnostic` instead -error: `#[multipart_suggestion(...)]` is not a valid attribute +error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:651:5 | LL | #[multipart_suggestion(no_crate_suggestion)] @@ -444,7 +444,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)] | = help: consider creating a `Subdiagnostic` instead -error: `#[suggestion(...)]` is not a valid attribute +error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:659:1 | LL | #[suggestion(no_crate_suggestion, code = "...")] @@ -452,7 +452,7 @@ LL | #[suggestion(no_crate_suggestion, code = "...")] | = help: `#[label]` and `#[suggestion]` can only be applied to fields -error: `#[label]` is not a valid attribute +error: derive(Diagnostic): `#[label]` is not a valid attribute --> $DIR/diagnostic-derive.rs:668:1 | LL | #[label] @@ -460,61 +460,61 @@ LL | #[label] | = help: `#[label]` and `#[suggestion]` can only be applied to fields -error: `#[subdiagnostic(...)]` is not a valid attribute +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:702:5 | LL | #[subdiagnostic(bad)] | ^ -error: `#[subdiagnostic = ...]` is not a valid attribute +error: derive(Diagnostic): `#[subdiagnostic = ...]` is not a valid attribute --> $DIR/diagnostic-derive.rs:710:5 | LL | #[subdiagnostic = "bad"] | ^ -error: `#[subdiagnostic(...)]` is not a valid attribute +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:718:5 | LL | #[subdiagnostic(bad, bad)] | ^ -error: `#[subdiagnostic(...)]` is not a valid attribute +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:726:5 | LL | #[subdiagnostic("bad")] | ^ -error: `#[subdiagnostic(...)]` is not a valid attribute +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:734:5 | LL | #[subdiagnostic(eager)] | ^ -error: `#[subdiagnostic(...)]` is not a valid attribute +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:742:5 | LL | #[subdiagnostic(eager)] | ^ -error: `#[subdiagnostic(...)]` is not a valid attribute +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:763:5 | LL | #[subdiagnostic(eager)] | ^ -error: expected at least one string literal for `code(...)` +error: derive(Diagnostic): expected at least one string literal for `code(...)` --> $DIR/diagnostic-derive.rs:794:23 | LL | #[suggestion(code())] | ^ -error: `code(...)` must contain only string literals +error: derive(Diagnostic): `code(...)` must contain only string literals --> $DIR/diagnostic-derive.rs:802:23 | LL | #[suggestion(code(foo))] | ^^^ -error: `#[suggestion(...)]` is not a valid attribute +error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:826:5 | LL | #[suggestion(no_crate_suggestion, code = "")] diff --git a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr index df1bad3cad0..4f54239f0fa 100644 --- a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr +++ b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr @@ -1,4 +1,4 @@ -error: diagnostic slug and crate name do not match +error: derive(Diagnostic): diagnostic slug and crate name do not match --> $DIR/enforce_slug_naming.rs:22:8 | LL | #[diag(compiletest_example, code = E0123)] diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr index 96f6ef06d1d..0ae7ba4c497 100644 --- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr @@ -1,142 +1,142 @@ -error: label without `#[primary_span]` field +error: derive(Diagnostic): label without `#[primary_span]` field --> $DIR/subdiagnostic-derive.rs:51:1 | LL | #[label(no_crate_example)] | ^ -error: diagnostic slug must be first argument of a `#[label(...)]` attribute +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute --> $DIR/subdiagnostic-derive.rs:58:1 | LL | #[label] | ^ -error: `#[foo]` is not a valid attribute +error: derive(Diagnostic): `#[foo]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:67:1 | LL | #[foo] | ^ -error: `#[label = ...]` is not a valid attribute +error: derive(Diagnostic): `#[label = ...]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:77:1 | LL | #[label = "..."] | ^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/subdiagnostic-derive.rs:86:9 | LL | #[label(bug = "...")] | ^^^ -error: diagnostic slug must be first argument of a `#[label(...)]` attribute +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute --> $DIR/subdiagnostic-derive.rs:86:1 | LL | #[label(bug = "...")] | ^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/subdiagnostic-derive.rs:106:9 | LL | #[label(slug = 4)] | ^^^^ -error: diagnostic slug must be first argument of a `#[label(...)]` attribute +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute --> $DIR/subdiagnostic-derive.rs:106:1 | LL | #[label(slug = 4)] | ^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/subdiagnostic-derive.rs:116:9 | LL | #[label(slug("..."))] | ^^^^ -error: diagnostic slug must be first argument of a `#[label(...)]` attribute +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute --> $DIR/subdiagnostic-derive.rs:116:1 | LL | #[label(slug("..."))] | ^ -error: diagnostic slug must be first argument of a `#[label(...)]` attribute +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute --> $DIR/subdiagnostic-derive.rs:136:1 | LL | #[label()] | ^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/subdiagnostic-derive.rs:145:27 | LL | #[label(no_crate_example, code = "...")] | ^^^^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/subdiagnostic-derive.rs:154:27 | LL | #[label(no_crate_example, applicability = "machine-applicable")] | ^^^^^^^^^^^^^ -error: unsupported type attribute for subdiagnostic enum +error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum --> $DIR/subdiagnostic-derive.rs:163:1 | LL | #[foo] | ^ -error: `#[bar]` is not a valid attribute +error: derive(Diagnostic): `#[bar]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:177:5 | LL | #[bar] | ^ -error: `#[bar = ...]` is not a valid attribute +error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:189:5 | LL | #[bar = "..."] | ^ -error: `#[bar = ...]` is not a valid attribute +error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:201:5 | LL | #[bar = 4] | ^ -error: `#[bar(...)]` is not a valid attribute +error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:213:5 | LL | #[bar("...")] | ^ -error: only `no_span` is a valid nested attribute +error: derive(Diagnostic): only `no_span` is a valid nested attribute --> $DIR/subdiagnostic-derive.rs:225:13 | LL | #[label(code = "...")] | ^^^^ -error: diagnostic slug must be first argument of a `#[label(...)]` attribute +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute --> $DIR/subdiagnostic-derive.rs:225:5 | LL | #[label(code = "...")] | ^ -error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` +error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` --> $DIR/subdiagnostic-derive.rs:254:5 | LL | #[primary_span] | ^ -error: label without `#[primary_span]` field +error: derive(Diagnostic): label without `#[primary_span]` field --> $DIR/subdiagnostic-derive.rs:251:1 | LL | #[label(no_crate_example)] | ^ -error: `#[applicability]` is only valid on suggestions +error: derive(Diagnostic): `#[applicability]` is only valid on suggestions --> $DIR/subdiagnostic-derive.rs:264:5 | LL | #[applicability] | ^ -error: `#[bar]` is not a valid attribute +error: derive(Diagnostic): `#[bar]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:274:5 | LL | #[bar] @@ -144,13 +144,13 @@ LL | #[bar] | = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes -error: `#[bar = ...]` is not a valid attribute +error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:285:5 | LL | #[bar = "..."] | ^ -error: `#[bar(...)]` is not a valid attribute +error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:296:5 | LL | #[bar("...")] @@ -158,13 +158,13 @@ LL | #[bar("...")] | = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes -error: a diagnostic slug must be the first argument to the attribute +error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute --> $DIR/subdiagnostic-derive.rs:328:44 | LL | #[label(no_crate_example, no_crate::example)] | ^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/subdiagnostic-derive.rs:341:5 | LL | #[primary_span] @@ -176,13 +176,13 @@ note: previously specified here LL | #[primary_span] | ^ -error: subdiagnostic kind not specified +error: derive(Diagnostic): subdiagnostic kind not specified --> $DIR/subdiagnostic-derive.rs:347:8 | LL | struct AG { | ^^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/subdiagnostic-derive.rs:384:46 | LL | #[suggestion(no_crate_example, code = "...", code = "...")] @@ -194,7 +194,7 @@ note: previously specified here LL | #[suggestion(no_crate_example, code = "...", code = "...")] | ^^^^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/subdiagnostic-derive.rs:402:5 | LL | #[applicability] @@ -206,49 +206,49 @@ note: previously specified here LL | #[applicability] | ^ -error: the `#[applicability]` attribute can only be applied to fields of type `Applicability` +error: derive(Diagnostic): the `#[applicability]` attribute can only be applied to fields of type `Applicability` --> $DIR/subdiagnostic-derive.rs:412:5 | LL | #[applicability] | ^ -error: suggestion without `code = "..."` +error: derive(Diagnostic): suggestion without `code = "..."` --> $DIR/subdiagnostic-derive.rs:425:1 | LL | #[suggestion(no_crate_example)] | ^ -error: invalid applicability +error: derive(Diagnostic): invalid applicability --> $DIR/subdiagnostic-derive.rs:435:62 | LL | #[suggestion(no_crate_example, code = "...", applicability = "foo")] | ^^^^^ -error: suggestion without `#[primary_span]` field +error: derive(Diagnostic): suggestion without `#[primary_span]` field --> $DIR/subdiagnostic-derive.rs:453:1 | LL | #[suggestion(no_crate_example, code = "...")] | ^ -error: unsupported type attribute for subdiagnostic enum +error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum --> $DIR/subdiagnostic-derive.rs:467:1 | LL | #[label] | ^ -error: `var` doesn't refer to a field on this type +error: derive(Diagnostic): `var` doesn't refer to a field on this type --> $DIR/subdiagnostic-derive.rs:487:39 | LL | #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")] | ^^^^^^^ -error: `var` doesn't refer to a field on this type +error: derive(Diagnostic): `var` doesn't refer to a field on this type --> $DIR/subdiagnostic-derive.rs:506:43 | LL | #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")] | ^^^^^^^ -error: `#[suggestion_part]` is not a valid attribute +error: derive(Diagnostic): `#[suggestion_part]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:529:5 | LL | #[suggestion_part] @@ -256,7 +256,7 @@ LL | #[suggestion_part] | = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead -error: `#[suggestion_part(...)]` is not a valid attribute +error: derive(Diagnostic): `#[suggestion_part(...)]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:532:5 | LL | #[suggestion_part(code = "...")] @@ -264,13 +264,13 @@ LL | #[suggestion_part(code = "...")] | = help: `#[suggestion_part(...)]` is only valid in multipart suggestions -error: suggestion without `#[primary_span]` field +error: derive(Diagnostic): suggestion without `#[primary_span]` field --> $DIR/subdiagnostic-derive.rs:526:1 | LL | #[suggestion(no_crate_example, code = "...")] | ^ -error: invalid nested attribute +error: derive(Diagnostic): invalid nested attribute --> $DIR/subdiagnostic-derive.rs:541:42 | LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")] @@ -278,25 +278,25 @@ LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "mac | = help: only `no_span`, `style` and `applicability` are valid nested attributes -error: multipart suggestion without any `#[suggestion_part(...)]` fields +error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields --> $DIR/subdiagnostic-derive.rs:541:1 | LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")] | ^ -error: `#[suggestion_part(...)]` attribute without `code = "..."` +error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` --> $DIR/subdiagnostic-derive.rs:551:5 | LL | #[suggestion_part] | ^ -error: `#[suggestion_part(...)]` attribute without `code = "..."` +error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` --> $DIR/subdiagnostic-derive.rs:559:5 | LL | #[suggestion_part()] | ^ -error: `#[primary_span]` is not a valid attribute +error: derive(Diagnostic): `#[primary_span]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:568:5 | LL | #[primary_span] @@ -304,43 +304,43 @@ LL | #[primary_span] | = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]` -error: multipart suggestion without any `#[suggestion_part(...)]` fields +error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields --> $DIR/subdiagnostic-derive.rs:565:1 | LL | #[multipart_suggestion(no_crate_example)] | ^ -error: `#[suggestion_part(...)]` attribute without `code = "..."` +error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` --> $DIR/subdiagnostic-derive.rs:576:5 | LL | #[suggestion_part] | ^ -error: `#[suggestion_part(...)]` attribute without `code = "..."` +error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` --> $DIR/subdiagnostic-derive.rs:579:5 | LL | #[suggestion_part()] | ^ -error: `code` is the only valid nested attribute +error: derive(Diagnostic): `code` is the only valid nested attribute --> $DIR/subdiagnostic-derive.rs:582:23 | LL | #[suggestion_part(foo = "bar")] | ^^^ -error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` +error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` --> $DIR/subdiagnostic-derive.rs:587:5 | LL | #[suggestion_part(code = "...")] | ^ -error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` +error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` --> $DIR/subdiagnostic-derive.rs:590:5 | LL | #[suggestion_part()] | ^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/subdiagnostic-derive.rs:598:37 | LL | #[suggestion_part(code = "...", code = ",,,")] @@ -352,37 +352,37 @@ note: previously specified here LL | #[suggestion_part(code = "...", code = ",,,")] | ^^^^ -error: `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."` +error: derive(Diagnostic): `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."` --> $DIR/subdiagnostic-derive.rs:627:5 | LL | #[applicability] | ^ -error: expected exactly one string literal for `code = ...` +error: derive(Diagnostic): expected exactly one string literal for `code = ...` --> $DIR/subdiagnostic-derive.rs:675:34 | LL | #[suggestion_part(code("foo"))] | ^ -error: expected exactly one string literal for `code = ...` +error: derive(Diagnostic): expected exactly one string literal for `code = ...` --> $DIR/subdiagnostic-derive.rs:686:41 | LL | #[suggestion_part(code("foo", "bar"))] | ^ -error: expected exactly one string literal for `code = ...` +error: derive(Diagnostic): expected exactly one string literal for `code = ...` --> $DIR/subdiagnostic-derive.rs:697:30 | LL | #[suggestion_part(code(3))] | ^ -error: expected exactly one string literal for `code = ...` +error: derive(Diagnostic): expected exactly one string literal for `code = ...` --> $DIR/subdiagnostic-derive.rs:708:29 | LL | #[suggestion_part(code())] | ^ -error: specified multiple times +error: derive(Diagnostic): attribute specified multiple times --> $DIR/subdiagnostic-derive.rs:763:1 | LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")] @@ -394,7 +394,7 @@ note: previously specified here LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")] | ^ -error: `#[suggestion_hidden(...)]` is not a valid attribute +error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:772:1 | LL | #[suggestion_hidden(no_crate_example, code = "")] @@ -402,7 +402,7 @@ LL | #[suggestion_hidden(no_crate_example, code = "")] | = help: Use `#[suggestion(..., style = "hidden")]` instead -error: `#[suggestion_hidden(...)]` is not a valid attribute +error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:780:1 | LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")] @@ -410,7 +410,7 @@ LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")] | = help: Use `#[suggestion(..., style = "hidden")]` instead -error: invalid suggestion style +error: derive(Diagnostic): invalid suggestion style --> $DIR/subdiagnostic-derive.rs:788:51 | LL | #[suggestion(no_crate_example, code = "", style = "foo")] @@ -418,25 +418,25 @@ LL | #[suggestion(no_crate_example, code = "", style = "foo")] | = help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only` -error: expected `= "xxx"` +error: derive(Diagnostic): expected `= "xxx"` --> $DIR/subdiagnostic-derive.rs:796:49 | LL | #[suggestion(no_crate_example, code = "", style = 42)] | ^ -error: a diagnostic slug must be the first argument to the attribute +error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute --> $DIR/subdiagnostic-derive.rs:804:48 | LL | #[suggestion(no_crate_example, code = "", style)] | ^ -error: expected `= "xxx"` +error: derive(Diagnostic): expected `= "xxx"` --> $DIR/subdiagnostic-derive.rs:812:48 | LL | #[suggestion(no_crate_example, code = "", style("foo"))] | ^ -error: `#[primary_span]` is not a valid attribute +error: derive(Diagnostic): `#[primary_span]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:825:5 | LL | #[primary_span] @@ -445,7 +445,7 @@ LL | #[primary_span] = note: there must be exactly one primary span = help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead -error: suggestion without `#[primary_span]` field +error: derive(Diagnostic): suggestion without `#[primary_span]` field --> $DIR/subdiagnostic-derive.rs:822:1 | LL | #[suggestion(no_crate_example, code = "")] diff --git a/tests/ui-fulldeps/try-from-u32/errors.rs b/tests/ui-fulldeps/try-from-u32/errors.rs new file mode 100644 index 00000000000..0470063312c --- /dev/null +++ b/tests/ui-fulldeps/try-from-u32/errors.rs @@ -0,0 +1,24 @@ +#![feature(rustc_private)] +//@ edition: 2021 + +// Checks the error messages produced by `#[derive(TryFromU32)]`. + +extern crate rustc_macros; + +use rustc_macros::TryFromU32; + +#[derive(TryFromU32)] +struct MyStruct {} //~ type is not an enum + +#[derive(TryFromU32)] +enum NonTrivial { + A, + B(), + C {}, + D(bool), //~ enum variant cannot have fields + E(bool, bool), //~ enum variant cannot have fields + F { x: bool }, //~ enum variant cannot have fields + G { x: bool, y: bool }, //~ enum variant cannot have fields +} + +fn main() {} diff --git a/tests/ui-fulldeps/try-from-u32/errors.stderr b/tests/ui-fulldeps/try-from-u32/errors.stderr new file mode 100644 index 00000000000..d20567061d7 --- /dev/null +++ b/tests/ui-fulldeps/try-from-u32/errors.stderr @@ -0,0 +1,32 @@ +error: type is not an enum (TryFromU32) + --> $DIR/errors.rs:11:1 + | +LL | struct MyStruct {} + | ^^^^^^ + +error: enum variant cannot have fields (TryFromU32) + --> $DIR/errors.rs:18:7 + | +LL | D(bool), + | ^^^^ + +error: enum variant cannot have fields (TryFromU32) + --> $DIR/errors.rs:19:7 + | +LL | E(bool, bool), + | ^^^^ + +error: enum variant cannot have fields (TryFromU32) + --> $DIR/errors.rs:20:9 + | +LL | F { x: bool }, + | ^ + +error: enum variant cannot have fields (TryFromU32) + --> $DIR/errors.rs:21:9 + | +LL | G { x: bool, y: bool }, + | ^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui-fulldeps/try-from-u32/hygiene.rs b/tests/ui-fulldeps/try-from-u32/hygiene.rs new file mode 100644 index 00000000000..e0655a64a64 --- /dev/null +++ b/tests/ui-fulldeps/try-from-u32/hygiene.rs @@ -0,0 +1,32 @@ +#![feature(rustc_private)] +//@ edition: 2021 +//@ check-pass + +// Checks that the derive macro still works even if the surrounding code has +// shadowed the relevant library types. + +extern crate rustc_macros; + +mod submod { + use rustc_macros::TryFromU32; + + struct Result; + trait TryFrom {} + #[allow(non_camel_case_types)] + struct u32; + struct Ok; + struct Err; + mod core {} + mod std {} + + #[derive(TryFromU32)] + pub(crate) enum MyEnum { + Zero, + One, + } +} + +fn main() { + use submod::MyEnum; + let _: Result = MyEnum::try_from(1u32); +} diff --git a/tests/ui-fulldeps/try-from-u32/values.rs b/tests/ui-fulldeps/try-from-u32/values.rs new file mode 100644 index 00000000000..180a8f2beb7 --- /dev/null +++ b/tests/ui-fulldeps/try-from-u32/values.rs @@ -0,0 +1,36 @@ +#![feature(assert_matches)] +#![feature(rustc_private)] +//@ edition: 2021 +//@ run-pass + +// Checks the values accepted by the `TryFrom` impl produced by `#[derive(TryFromU32)]`. + +extern crate rustc_macros; + +use core::assert_matches::assert_matches; +use rustc_macros::TryFromU32; + +#[derive(TryFromU32, Debug, PartialEq)] +#[repr(u32)] +enum Repr { + Zero, + One(), + Seven = 7, +} + +#[derive(TryFromU32, Debug)] +enum NoRepr { + Zero, + One, +} + +fn main() { + assert_eq!(Repr::try_from(0u32), Ok(Repr::Zero)); + assert_eq!(Repr::try_from(1u32), Ok(Repr::One())); + assert_eq!(Repr::try_from(2u32), Err(2)); + assert_eq!(Repr::try_from(7u32), Ok(Repr::Seven)); + + assert_matches!(NoRepr::try_from(0u32), Ok(NoRepr::Zero)); + assert_matches!(NoRepr::try_from(1u32), Ok(NoRepr::One)); + assert_matches!(NoRepr::try_from(2u32), Err(2)); +} diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 28c8063a923..408dbea4ae8 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -79,10 +79,10 @@ mod prelude { #[lang = "sized"] pub trait Sized {} - #[lang = "receiver"] - pub trait Receiver {} - impl Receiver for &T {} - impl Receiver for &mut T {} + #[lang = "legacy_receiver"] + pub trait LegacyReceiver {} + impl LegacyReceiver for &T {} + impl LegacyReceiver for &mut T {} #[lang = "copy"] pub trait Copy: Sized {} @@ -211,6 +211,15 @@ impl Clone for Zst { } } +enum Either { + Left(T), + Right(U), +} +enum Either2 { + Left(T), + Right(U, ()), +} + #[repr(C)] enum ReprCEnum { Variant1, @@ -328,7 +337,8 @@ mod unsized_ { test_transparent_unsized!(dyn_trait, dyn Any); } -// RFC 3391 . +// RFC 3391 , including the +// extension ratified at . macro_rules! test_nonnull { ($name:ident, $t:ty) => { mod $name { @@ -340,6 +350,12 @@ macro_rules! test_nonnull { test_abi_compatible!(result_ok_zst, Result, $t); test_abi_compatible!(result_err_arr, Result<$t, [i8; 0]>, $t); test_abi_compatible!(result_ok_arr, Result<[i8; 0], $t>, $t); + test_abi_compatible!(result_err_void, Result<$t, Void>, $t); + test_abi_compatible!(result_ok_void, Result, $t); + test_abi_compatible!(either_err_zst, Either<$t, Zst>, $t); + test_abi_compatible!(either_ok_zst, Either, $t); + test_abi_compatible!(either2_err_zst, Either2<$t, Zst>, $t); + test_abi_compatible!(either2_err_arr, Either2<$t, [i8; 0]>, $t); } } } diff --git a/tests/ui/async-await/field-in-sync.rs b/tests/ui/async-await/field-in-sync.rs new file mode 100644 index 00000000000..586980c6e2b --- /dev/null +++ b/tests/ui/async-await/field-in-sync.rs @@ -0,0 +1,13 @@ +//@ edition: 2021 + +struct S { + field: (), +} + +async fn foo() -> S { todo!() } + +fn main() -> Result<(), ()> { + foo().field; + //~^ ERROR no field `field` on type `impl Future` + Ok(()) +} diff --git a/tests/ui/async-await/field-in-sync.stderr b/tests/ui/async-await/field-in-sync.stderr new file mode 100644 index 00000000000..7be30339c27 --- /dev/null +++ b/tests/ui/async-await/field-in-sync.stderr @@ -0,0 +1,17 @@ +error[E0609]: no field `field` on type `impl Future` + --> $DIR/field-in-sync.rs:10:11 + | +LL | foo().field; + | ^^^^^ field not available in `impl Future`, but it is available in its `Output` + | +note: this implements `Future` and its output type has the field, but the future cannot be awaited in a synchronous function + --> $DIR/field-in-sync.rs:10:5 + | +LL | fn main() -> Result<(), ()> { + | --------------------------- this is not `async` +LL | foo().field; + | ^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0609`. diff --git a/tests/ui/async-await/in-trait/unconstrained-impl-region.rs b/tests/ui/async-await/in-trait/unconstrained-impl-region.rs index 95ba1f3f277..9382c232364 100644 --- a/tests/ui/async-await/in-trait/unconstrained-impl-region.rs +++ b/tests/ui/async-await/in-trait/unconstrained-impl-region.rs @@ -14,7 +14,6 @@ impl<'a> Actor for () { //~^ ERROR the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates type Message = &'a (); async fn on_mount(self, _: impl Inbox<&'a ()>) {} - //~^ ERROR the trait bound `impl Inbox<&'a ()>: Inbox<&'a ()>` is not satisfied } fn main() {} diff --git a/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr b/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr index 80dc5fdc747..ef7e4ef0eb8 100644 --- a/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr +++ b/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr @@ -1,22 +1,9 @@ -error[E0277]: the trait bound `impl Inbox<&'a ()>: Inbox<&'a ()>` is not satisfied - --> $DIR/unconstrained-impl-region.rs:16:5 - | -LL | async fn on_mount(self, _: impl Inbox<&'a ()>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Inbox<&'a ()>` is not implemented for `impl Inbox<&'a ()>` - | -note: required by a bound in `<() as Actor>::on_mount` - --> $DIR/unconstrained-impl-region.rs:16:37 - | -LL | async fn on_mount(self, _: impl Inbox<&'a ()>) {} - | ^^^^^^^^^^^^^ required by this bound in `<() as Actor>::on_mount` - error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates --> $DIR/unconstrained-impl-region.rs:13:6 | LL | impl<'a> Actor for () { | ^^ unconstrained lifetime parameter -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0207, E0277. -For more information about an error, try `rustc --explain E0207`. +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/async-await/issue-61076.stderr b/tests/ui/async-await/issue-61076.stderr index 44de282988b..b8478c8d138 100644 --- a/tests/ui/async-await/issue-61076.stderr +++ b/tests/ui/async-await/issue-61076.stderr @@ -28,7 +28,7 @@ error[E0609]: no field `0` on type `impl Future` LL | let _: i32 = tuple().0; | ^ field not available in `impl Future`, but it is available in its `Output` | -help: consider `await`ing on the `Future` and access the field of its `Output` +help: consider `await`ing on the `Future` to access the field | LL | let _: i32 = tuple().await.0; | ++++++ @@ -39,7 +39,7 @@ error[E0609]: no field `a` on type `impl Future` LL | let _: i32 = struct_().a; | ^ field not available in `impl Future`, but it is available in its `Output` | -help: consider `await`ing on the `Future` and access the field of its `Output` +help: consider `await`ing on the `Future` to access the field | LL | let _: i32 = struct_().await.a; | ++++++ diff --git a/tests/ui/async-await/try-in-sync.rs b/tests/ui/async-await/try-in-sync.rs new file mode 100644 index 00000000000..81d72c3fb9a --- /dev/null +++ b/tests/ui/async-await/try-in-sync.rs @@ -0,0 +1,9 @@ +//@ edition: 2021 + +async fn foo() -> Result<(), ()> { todo!() } + +fn main() -> Result<(), ()> { + foo()?; + //~^ ERROR the `?` operator can only be applied to values that implement `Try` + Ok(()) +} diff --git a/tests/ui/async-await/try-in-sync.stderr b/tests/ui/async-await/try-in-sync.stderr new file mode 100644 index 00000000000..bc7a6bd0151 --- /dev/null +++ b/tests/ui/async-await/try-in-sync.stderr @@ -0,0 +1,18 @@ +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/try-in-sync.rs:6:5 + | +LL | foo()?; + | ^^^^^^ the `?` operator cannot be applied to type `impl Future>` + | + = help: the trait `Try` is not implemented for `impl Future>` +note: this implements `Future` and its output type supports `?`, but the future cannot be awaited in a synchronous function + --> $DIR/try-in-sync.rs:6:10 + | +LL | fn main() -> Result<(), ()> { + | --------------------------- this is not `async` +LL | foo()?; + | ^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/borrowck/issue-64453.rs b/tests/ui/borrowck/issue-64453.rs index 33d55be5812..5f1f35d6ca9 100644 --- a/tests/ui/borrowck/issue-64453.rs +++ b/tests/ui/borrowck/issue-64453.rs @@ -3,7 +3,6 @@ struct Value; static settings_dir: String = format!(""); //~^ ERROR cannot call non-const fn -//~| ERROR is not yet stable as a const fn from_string(_: String) -> Value { Value diff --git a/tests/ui/borrowck/issue-64453.stderr b/tests/ui/borrowck/issue-64453.stderr index e671817633b..98b05ead649 100644 --- a/tests/ui/borrowck/issue-64453.stderr +++ b/tests/ui/borrowck/issue-64453.stderr @@ -1,12 +1,3 @@ -error: `Arguments::<'a>::new_const` is not yet stable as a const fn - --> $DIR/issue-64453.rs:4:31 - | -LL | static settings_dir: String = format!(""); - | ^^^^^^^^^^^ - | - = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable - = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0015]: cannot call non-const fn `format` in statics --> $DIR/issue-64453.rs:4:31 | @@ -18,7 +9,7 @@ LL | static settings_dir: String = format!(""); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0507]: cannot move out of static item `settings_dir` - --> $DIR/issue-64453.rs:14:37 + --> $DIR/issue-64453.rs:13:37 | LL | let settings_data = from_string(settings_dir); | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait @@ -28,7 +19,7 @@ help: consider cloning the value if the performance cost is acceptable LL | let settings_data = from_string(settings_dir.clone()); | ++++++++ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0015, E0507. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/cast/ptr-to-trait-obj-drop-principal.rs b/tests/ui/cast/ptr-to-trait-obj-drop-principal.rs new file mode 100644 index 00000000000..01dd91fc77d --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-drop-principal.rs @@ -0,0 +1,21 @@ +//! Test that non-coercion casts aren't allowed to drop the principal, +//! because they cannot modify the pointer metadata. +//! +//! We test this in a const context to guard against UB if this is allowed +//! in the future. + +trait Trait {} +impl Trait for () {} + +struct Wrapper(T); + +const OBJECT: *const (dyn Trait + Send) = &(); + +// coercions are allowed +const _: *const dyn Send = OBJECT as _; + +// casts are **not** allowed +const _: *const Wrapper = OBJECT as _; +//~^ ERROR casting `*const (dyn Trait + Send + 'static)` as `*const Wrapper` is invalid + +fn main() {} diff --git a/tests/ui/cast/ptr-to-trait-obj-drop-principal.stderr b/tests/ui/cast/ptr-to-trait-obj-drop-principal.stderr new file mode 100644 index 00000000000..719e0711f5b --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-drop-principal.stderr @@ -0,0 +1,11 @@ +error[E0606]: casting `*const (dyn Trait + Send + 'static)` as `*const Wrapper` is invalid + --> $DIR/ptr-to-trait-obj-drop-principal.rs:18:37 + | +LL | const _: *const Wrapper = OBJECT as _; + | ^^^^^^^^^^^ + | + = note: the trait objects may have different vtables + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0606`. diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index c21016e9290..7589551a87c 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra` LL | cfg!(target_feature = "zebra"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 245 more + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 246 more = note: see for more information about checking conditional configuration warning: 27 warnings emitted diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index da790bbd528..b0ca09a59ed 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -174,7 +174,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pauth-lr`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/closures/issue-111932.stderr b/tests/ui/closures/issue-111932.stderr index ff46b10d005..93488ad2011 100644 --- a/tests/ui/closures/issue-111932.stderr +++ b/tests/ui/closures/issue-111932.stderr @@ -17,7 +17,7 @@ LL | println!("{:?}", foo); | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `dyn Foo` -note: required by an implicit `Sized` bound in `core::fmt::rt::Argument::<'a>::new_debug` +note: required by an implicit `Sized` bound in `core::fmt::rt::Argument::<'_>::new_debug` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr index bae8249845c..b8d7c94bddc 100644 --- a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr +++ b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr @@ -27,11 +27,13 @@ LL + #[derive(ConstParamTy)] LL | struct Foo(u8); | -error[E0284]: type annotations needed: cannot normalize `foo::{constant#0}` - --> $DIR/unify-op-with-fn-call.rs:20:25 +error[E0015]: cannot call non-const operator in constants + --> $DIR/unify-op-with-fn-call.rs:20:39 | LL | fn foo(a: Evaluatable<{ N + N }>) { - | ^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo::{constant#0}` + | ^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter --> $DIR/unify-op-with-fn-call.rs:20:17 @@ -63,11 +65,21 @@ error[E0284]: type annotations needed: cannot normalize `foo2::{constant#0}` LL | fn foo2(a: Evaluatable2<{ N + N }>) { | ^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2::{constant#0}` -error[E0284]: type annotations needed: cannot normalize `foo::{constant#0}` - --> $DIR/unify-op-with-fn-call.rs:21:11 +error[E0015]: cannot call non-const fn `::add` in constants + --> $DIR/unify-op-with-fn-call.rs:21:13 | LL | bar::<{ std::ops::Add::add(N, N) }>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo::{constant#0}` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + +error[E0015]: cannot call non-const fn `::add` in constants + --> $DIR/unify-op-with-fn-call.rs:30:14 + | +LL | bar2::<{ std::ops::Add::add(N, N) }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants error[E0284]: type annotations needed: cannot normalize `foo2::{constant#0}` --> $DIR/unify-op-with-fn-call.rs:30:12 @@ -75,7 +87,7 @@ error[E0284]: type annotations needed: cannot normalize `foo2::{constant#0}` LL | bar2::<{ std::ops::Add::add(N, N) }>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2::{constant#0}` -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors -Some errors have detailed explanations: E0284, E0741. -For more information about an error, try `rustc --explain E0284`. +Some errors have detailed explanations: E0015, E0284, E0741. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/const-generics/infer/issue-77092.stderr b/tests/ui/const-generics/infer/issue-77092.stderr index 9a6374a2adc..4ab80cec58d 100644 --- a/tests/ui/const-generics/infer/issue-77092.stderr +++ b/tests/ui/const-generics/infer/issue-77092.stderr @@ -25,7 +25,7 @@ LL | println!("{:?}", take_array_from_mut(&mut arr, i)); = note: required for `[i32; _]` to implement `Debug` = note: 1 redundant requirement hidden = note: required for `&mut [i32; _]` to implement `Debug` -note: required by a bound in `core::fmt::rt::Argument::<'a>::new_debug` +note: required by a bound in `core::fmt::rt::Argument::<'_>::new_debug` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL help: consider specifying the generic arguments | diff --git a/tests/ui/const-generics/issue-93647.stderr b/tests/ui/const-generics/issue-93647.stderr index 81f50a1b517..38fb3d79459 100644 --- a/tests/ui/const-generics/issue-93647.stderr +++ b/tests/ui/const-generics/issue-93647.stderr @@ -6,10 +6,6 @@ LL | (||1usize)() | = note: closures need an RFC before allowed to be called in constants = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/issue-88119.stderr b/tests/ui/const-generics/issues/issue-88119.stderr index 98bb8196810..a0ca33e38ef 100644 --- a/tests/ui/const-generics/issues/issue-88119.stderr +++ b/tests/ui/const-generics/issues/issue-88119.stderr @@ -11,30 +11,12 @@ error[E0284]: type annotations needed: cannot normalize `<&T as ConstName>::{con | LL | impl const ConstName for &T | ^^ cannot normalize `<&T as ConstName>::{constant#0}` - | -note: required for `&T` to implement `ConstName` - --> $DIR/issue-88119.rs:19:35 - | -LL | impl const ConstName for &T - | ^^^^^^^^^ ^^ -LL | where -LL | [(); name_len::()]:, - | --------------------- unsatisfied trait bound introduced here error[E0284]: type annotations needed: cannot normalize `<&mut T as ConstName>::{constant#0}` --> $DIR/issue-88119.rs:26:49 | LL | impl const ConstName for &mut T | ^^^^^^ cannot normalize `<&mut T as ConstName>::{constant#0}` - | -note: required for `&mut T` to implement `ConstName` - --> $DIR/issue-88119.rs:26:35 - | -LL | impl const ConstName for &mut T - | ^^^^^^^^^ ^^^^^^ -LL | where -LL | [(); name_len::()]:, - | --------------------- unsatisfied trait bound introduced here error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/issues/issue-90318.stderr b/tests/ui/const-generics/issues/issue-90318.stderr index a534e8f8d44..9c7cb5ceb58 100644 --- a/tests/ui/const-generics/issues/issue-90318.stderr +++ b/tests/ui/const-generics/issues/issue-90318.stderr @@ -29,10 +29,6 @@ LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/any.rs:LL:COL = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0015]: cannot call non-const operator in constants --> $DIR/issue-90318.rs:22:10 @@ -43,10 +39,6 @@ LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/any.rs:LL:COL = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 4 previous errors diff --git a/tests/ui/consts/auxiliary/unstable_but_const_stable.rs b/tests/ui/consts/auxiliary/unstable_but_const_stable.rs deleted file mode 100644 index 88044b0272c..00000000000 --- a/tests/ui/consts/auxiliary/unstable_but_const_stable.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![feature(staged_api, rustc_attrs, intrinsics)] -#![stable(since="1.0.0", feature = "stable")] - -extern "rust-intrinsic" { - #[unstable(feature = "unstable", issue = "42")] - #[rustc_const_stable(feature = "stable", since = "1.0.0")] - #[rustc_nounwind] - pub fn write_bytes(dst: *mut T, val: u8, count: usize); -} - -#[unstable(feature = "unstable", issue = "42")] -#[rustc_const_stable(feature = "stable", since = "1.0.0")] -pub const fn some_unstable_fn() {} diff --git a/tests/ui/consts/auxiliary/unstable_intrinsic.rs b/tests/ui/consts/auxiliary/unstable_intrinsic.rs new file mode 100644 index 00000000000..edef499dbb1 --- /dev/null +++ b/tests/ui/consts/auxiliary/unstable_intrinsic.rs @@ -0,0 +1,26 @@ +#![feature(staged_api, rustc_attrs, intrinsics)] +#![stable(since="1.0.0", feature = "stable")] + +#[stable(since="1.0.0", feature = "stable")] +pub mod old_way { + extern "rust-intrinsic" { + #[unstable(feature = "unstable", issue = "42")] + pub fn size_of_val(x: *const T) -> usize; + + #[unstable(feature = "unstable", issue = "42")] + #[rustc_const_unstable(feature = "unstable", issue = "42")] + pub fn min_align_of_val(x: *const T) -> usize; + } +} + +#[stable(since="1.0.0", feature = "stable")] +pub mod new_way { + #[unstable(feature = "unstable", issue = "42")] + #[rustc_intrinsic] + pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } + + #[unstable(feature = "unstable", issue = "42")] + #[rustc_const_unstable(feature = "unstable", issue = "42")] + #[rustc_intrinsic] + pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } +} diff --git a/tests/ui/consts/closure-in-foreign-crate.rs b/tests/ui/consts/closure-in-foreign-crate.rs index 701cf091045..94e40fcf1e4 100644 --- a/tests/ui/consts/closure-in-foreign-crate.rs +++ b/tests/ui/consts/closure-in-foreign-crate.rs @@ -1,8 +1,8 @@ -//@ aux-build:closure-in-foreign-crate.rs +// FIXME(effects) aux-build:closure-in-foreign-crate.rs //@ build-pass -extern crate closure_in_foreign_crate; +// FIXME(effects) extern crate closure_in_foreign_crate; -const _: () = closure_in_foreign_crate::test(); +// FIXME(effects) const _: () = closure_in_foreign_crate::test(); fn main() {} diff --git a/tests/ui/consts/const-block-const-bound.stderr b/tests/ui/consts/const-block-const-bound.stderr index 42a42ae3938..5e24959146b 100644 --- a/tests/ui/consts/const-block-const-bound.stderr +++ b/tests/ui/consts/const-block-const-bound.stderr @@ -1,8 +1,16 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-block-const-bound.rs:8:22 + --> $DIR/const-block-const-bound.rs:8:15 | LL | const fn f(x: T) {} - | ^^^^^^^^ + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-block-const-bound.rs:8:15 + | +LL | const fn f(x: T) {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-block-const-bound.rs:8:32 @@ -12,6 +20,6 @@ LL | const fn f(x: T) {} | | | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs index 4b3cf70739c..6c93c0e63b6 100644 --- a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs +++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(staged_api)] +#![feature(staged_api, foo)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature="foo", issue = "none")] @@ -11,7 +11,7 @@ const fn foo() -> u32 { 42 } fn meh() -> u32 { 42 } -const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn +const fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]` fn a() { let _: &'static u32 = &foo(); //~ ERROR temporary value dropped while borrowed diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr index 2e697b219c5..1de1c78faf6 100644 --- a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr +++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr @@ -1,10 +1,20 @@ -error: `foo` is not yet stable as a const fn +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]` --> $DIR/dont_promote_unstable_const_fn.rs:14:25 | LL | const fn bar() -> u32 { foo() } | ^^^^^ | - = help: add `#![feature(foo)]` to the crate attributes to enable + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn bar() -> u32 { foo() } + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(foo)] +LL | const fn bar() -> u32 { foo() } + | error[E0716]: temporary value dropped while borrowed --> $DIR/dont_promote_unstable_const_fn.rs:17:28 diff --git a/tests/ui/consts/const-eval/simd/insert_extract.rs b/tests/ui/consts/const-eval/simd/insert_extract.rs index f4f25327aaf..57d4b4888ca 100644 --- a/tests/ui/consts/const-eval/simd/insert_extract.rs +++ b/tests/ui/consts/const-eval/simd/insert_extract.rs @@ -11,8 +11,11 @@ #[repr(simd)] struct f32x4([f32; 4]); extern "rust-intrinsic" { + #[stable(feature = "foo", since = "1.3.37")] #[rustc_const_stable(feature = "foo", since = "1.3.37")] fn simd_insert(x: T, idx: u32, val: U) -> T; + + #[stable(feature = "foo", since = "1.3.37")] #[rustc_const_stable(feature = "foo", since = "1.3.37")] fn simd_extract(x: T, idx: u32) -> U; } diff --git a/tests/ui/consts/const-fn-error.stderr b/tests/ui/consts/const-fn-error.stderr index e886a0b4fe4..42a6f2704c9 100644 --- a/tests/ui/consts/const-fn-error.stderr +++ b/tests/ui/consts/const-fn-error.stderr @@ -22,10 +22,6 @@ LL | for i in 0..x { note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0015]: cannot call non-const fn ` as Iterator>::next` in constant functions --> $DIR/const-fn-error.rs:5:14 @@ -34,10 +30,6 @@ LL | for i in 0..x { | ^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const-for-feature-gate.stderr b/tests/ui/consts/const-for-feature-gate.stderr index 3344611a60c..6e099a3159d 100644 --- a/tests/ui/consts/const-for-feature-gate.stderr +++ b/tests/ui/consts/const-for-feature-gate.stderr @@ -17,10 +17,6 @@ LL | for _ in 0..5 {} note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants --> $DIR/const-for-feature-gate.rs:4:14 @@ -29,10 +25,6 @@ LL | for _ in 0..5 {} | ^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const-for.stderr b/tests/ui/consts/const-for.stderr index 2b817c2d20c..78336dc93e8 100644 --- a/tests/ui/consts/const-for.stderr +++ b/tests/ui/consts/const-for.stderr @@ -7,10 +7,6 @@ LL | for _ in 0..5 {} note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants --> $DIR/const-for.rs:4:14 @@ -19,10 +15,6 @@ LL | for _ in 0..5 {} | ^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-try-feature-gate.stderr b/tests/ui/consts/const-try-feature-gate.stderr index 0c4c16fc56a..dc1dabc2f4f 100644 --- a/tests/ui/consts/const-try-feature-gate.stderr +++ b/tests/ui/consts/const-try-feature-gate.stderr @@ -17,10 +17,6 @@ LL | Some(())?; note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/option.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0015]: `?` cannot convert from residual of `Option<()>` in constant functions --> $DIR/const-try-feature-gate.rs:4:5 @@ -31,10 +27,6 @@ LL | Some(())?; note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/option.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const-try.rs b/tests/ui/consts/const-try.rs index 9089dd70a26..758c4dd1e8c 100644 --- a/tests/ui/consts/const-try.rs +++ b/tests/ui/consts/const-try.rs @@ -1,4 +1,4 @@ -//@ known-bug: #110395 +//@ compile-flags: -Znext-solver // Demonstrates what's needed to make use of `?` in const contexts. @@ -14,12 +14,14 @@ struct TryMe; struct Error; impl const FromResidual for TryMe { + //~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` fn from_residual(residual: Error) -> Self { TryMe } } impl const Try for TryMe { + //~^ ERROR const `impl` for trait `Try` which is not marked with `#[const_trait]` type Output = (); type Residual = Error; fn from_output(output: Self::Output) -> Self { @@ -32,6 +34,8 @@ impl const Try for TryMe { const fn t() -> TryMe { TryMe?; + //~^ ERROR `?` cannot determine the branch of `TryMe` in constant functions + //~| ERROR `?` cannot convert from residual of `TryMe` in constant functions TryMe } diff --git a/tests/ui/consts/const-try.stderr b/tests/ui/consts/const-try.stderr index 8afdd4e0d61..abb1a921cfa 100644 --- a/tests/ui/consts/const-try.stderr +++ b/tests/ui/consts/const-try.stderr @@ -1,8 +1,3 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` --> $DIR/const-try.rs:16:12 | @@ -13,7 +8,7 @@ LL | impl const FromResidual for TryMe { = note: adding a non-const method body in the future would be a breaking change error: const `impl` for trait `Try` which is not marked with `#[const_trait]` - --> $DIR/const-try.rs:22:12 + --> $DIR/const-try.rs:23:12 | LL | impl const Try for TryMe { | ^^^ @@ -21,5 +16,22 @@ LL | impl const Try for TryMe { = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error: aborting due to 3 previous errors +error[E0015]: `?` cannot determine the branch of `TryMe` in constant functions + --> $DIR/const-try.rs:36:5 + | +LL | TryMe?; + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: `?` cannot convert from residual of `TryMe` in constant functions + --> $DIR/const-try.rs:36:5 + | +LL | TryMe?; + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const-unstable-intrinsic.rs b/tests/ui/consts/const-unstable-intrinsic.rs new file mode 100644 index 00000000000..050abc6dd46 --- /dev/null +++ b/tests/ui/consts/const-unstable-intrinsic.rs @@ -0,0 +1,76 @@ +//! Ensure that unstable intrinsics can actually not be called, +//! neither within a crate nor cross-crate. +//@ aux-build:unstable_intrinsic.rs +#![feature(staged_api, rustc_attrs, intrinsics)] +#![stable(since="1.0.0", feature = "stable")] +#![feature(local)] + +extern crate unstable_intrinsic; + +fn main() { + const_main(); +} + +const fn const_main() { + let x = 42; + unsafe { + unstable_intrinsic::old_way::size_of_val(&x); + //~^ERROR: unstable library feature 'unstable' + //~|ERROR: cannot call non-const intrinsic + unstable_intrinsic::old_way::min_align_of_val(&x); + //~^ERROR: unstable library feature 'unstable' + //~|ERROR: not yet stable as a const intrinsic + unstable_intrinsic::new_way::size_of_val(&x); + //~^ERROR: unstable library feature 'unstable' + //~|ERROR: cannot be (indirectly) exposed to stable + unstable_intrinsic::new_way::min_align_of_val(&x); + //~^ERROR: unstable library feature 'unstable' + //~|ERROR: not yet stable as a const intrinsic + + old_way::size_of_val(&x); + //~^ERROR: cannot call non-const intrinsic + old_way::min_align_of_val(&x); + //~^ERROR: cannot use `#[feature(local)]` + new_way::size_of_val(&x); + //~^ERROR: cannot be (indirectly) exposed to stable + new_way::min_align_of_val(&x); + //~^ERROR: cannot use `#[feature(local)]` + } +} + +#[stable(since="1.0.0", feature = "stable")] +pub mod old_way { + extern "rust-intrinsic" { + #[unstable(feature = "local", issue = "42")] + pub fn size_of_val(x: *const T) -> usize; + + #[unstable(feature = "local", issue = "42")] + #[rustc_const_unstable(feature = "local", issue = "42")] + pub fn min_align_of_val(x: *const T) -> usize; + } +} + +#[stable(since="1.0.0", feature = "stable")] +pub mod new_way { + #[unstable(feature = "local", issue = "42")] + #[rustc_intrinsic] + pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } + + #[unstable(feature = "local", issue = "42")] + #[rustc_const_unstable(feature = "local", issue = "42")] + #[rustc_intrinsic] + pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] +#[inline] +pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { + // Const stability attributes are not inherited from parent items. + extern "rust-intrinsic" { + fn copy(src: *const T, dst: *mut T, count: usize); + } + + unsafe { copy(src, dst, count) } + //~^ ERROR cannot call non-const intrinsic +} diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr new file mode 100644 index 00000000000..33a434c503d --- /dev/null +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -0,0 +1,127 @@ +error[E0658]: use of unstable library feature 'unstable' + --> $DIR/const-unstable-intrinsic.rs:17:9 + | +LL | unstable_intrinsic::old_way::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #42 for more information + = help: add `#![feature(unstable)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'unstable' + --> $DIR/const-unstable-intrinsic.rs:20:9 + | +LL | unstable_intrinsic::old_way::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #42 for more information + = help: add `#![feature(unstable)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'unstable' + --> $DIR/const-unstable-intrinsic.rs:23:9 + | +LL | unstable_intrinsic::new_way::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #42 for more information + = help: add `#![feature(unstable)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'unstable' + --> $DIR/const-unstable-intrinsic.rs:26:9 + | +LL | unstable_intrinsic::new_way::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #42 for more information + = help: add `#![feature(unstable)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: cannot call non-const intrinsic `size_of_val` in constant functions + --> $DIR/const-unstable-intrinsic.rs:17:9 + | +LL | unstable_intrinsic::old_way::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `min_align_of_val` is not yet stable as a const intrinsic + --> $DIR/const-unstable-intrinsic.rs:20:9 + | +LL | unstable_intrinsic::old_way::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable)]` to the crate attributes to enable + +error: intrinsic `unstable_intrinsic::new_way::size_of_val` cannot be (indirectly) exposed to stable + --> $DIR/const-unstable-intrinsic.rs:23:9 + | +LL | unstable_intrinsic::new_way::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) + +error: `min_align_of_val` is not yet stable as a const intrinsic + --> $DIR/const-unstable-intrinsic.rs:26:9 + | +LL | unstable_intrinsic::new_way::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable)]` to the crate attributes to enable + +error: cannot call non-const intrinsic `size_of_val` in constant functions + --> $DIR/const-unstable-intrinsic.rs:30:9 + | +LL | old_way::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` + --> $DIR/const-unstable-intrinsic.rs:32:9 + | +LL | old_way::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn const_main() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(local)] +LL | const fn const_main() { + | + +error: intrinsic `new_way::size_of_val` cannot be (indirectly) exposed to stable + --> $DIR/const-unstable-intrinsic.rs:34:9 + | +LL | new_way::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_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:36:9 + | +LL | new_way::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn const_main() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(local)] +LL | const fn const_main() { + | + +error: cannot call non-const intrinsic `copy` in constant functions + --> $DIR/const-unstable-intrinsic.rs:74:14 + | +LL | unsafe { copy(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 13 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs index 77482007be4..3a54764f422 100644 --- a/tests/ui/consts/const_cmp_type_id.rs +++ b/tests/ui/consts/const_cmp_type_id.rs @@ -1,4 +1,3 @@ -//@ check-pass //@ compile-flags: -Znext-solver #![feature(const_type_id, const_trait_impl, effects)] #![allow(incomplete_features)] @@ -7,11 +6,13 @@ use std::any::TypeId; fn main() { const { - // FIXME(effects) this isn't supposed to pass (right now) but it did. - // revisit binops typeck please. assert!(TypeId::of::() == TypeId::of::()); + //~^ ERROR cannot call non-const operator in constants assert!(TypeId::of::<()>() != TypeId::of::()); + //~^ ERROR cannot call non-const operator in constants let _a = TypeId::of::() < TypeId::of::(); + //~^ ERROR cannot call non-const operator in constants // can't assert `_a` because it is not deterministic + // FIXME(effects) make it pass } } diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr new file mode 100644 index 00000000000..12f35361b80 --- /dev/null +++ b/tests/ui/consts/const_cmp_type_id.stderr @@ -0,0 +1,34 @@ +error[E0015]: cannot call non-const operator in constants + --> $DIR/const_cmp_type_id.rs:9:17 + | +LL | assert!(TypeId::of::() == TypeId::of::()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + +error[E0015]: cannot call non-const operator in constants + --> $DIR/const_cmp_type_id.rs:11:17 + | +LL | assert!(TypeId::of::<()>() != TypeId::of::()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + +error[E0015]: cannot call non-const operator in constants + --> $DIR/const_cmp_type_id.rs:13:18 + | +LL | let _a = TypeId::of::() < TypeId::of::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the derive macro `PartialOrd` (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 E0015`. diff --git a/tests/ui/consts/constifconst-call-in-const-position.stderr b/tests/ui/consts/constifconst-call-in-const-position.stderr index 7de10f0287b..2195cab3f4d 100644 --- a/tests/ui/consts/constifconst-call-in-const-position.stderr +++ b/tests/ui/consts/constifconst-call-in-const-position.stderr @@ -3,24 +3,12 @@ error: using `#![feature(effects)]` without enabling next trait solver globally = note: the next trait solver must be enabled globally for the effects feature to work correctly = help: use `-Znext-solver` to enable -error[E0308]: mismatched types +error[E0080]: evaluation of `foo::<()>::{constant#0}` failed --> $DIR/constifconst-call-in-const-position.rs:17:38 | LL | const fn foo() -> [u8; T::a()] { - | ^^^^^^ expected `false`, found `host` - | - = note: expected constant `false` - found constant `host` + | ^^^^^^ calling non-const function `<() as Tr>::a` -error[E0308]: mismatched types - --> $DIR/constifconst-call-in-const-position.rs:18:9 - | -LL | [0; T::a()] - | ^^^^^^ expected `false`, found `host` - | - = note: expected constant `false` - found constant `host` +error: aborting due to 2 previous errors -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/control-flow/loop.stderr b/tests/ui/consts/control-flow/loop.stderr index 13d5d3e0b55..5e43c70e9df 100644 --- a/tests/ui/consts/control-flow/loop.stderr +++ b/tests/ui/consts/control-flow/loop.stderr @@ -35,10 +35,6 @@ LL | for i in 0..4 { note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants --> $DIR/loop.rs:53:14 @@ -47,10 +43,6 @@ LL | for i in 0..4 { | ^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0015]: cannot convert `std::ops::Range` into an iterator in constants --> $DIR/loop.rs:59:14 @@ -61,10 +53,6 @@ LL | for i in 0..4 { note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants --> $DIR/loop.rs:59:14 @@ -73,10 +61,6 @@ LL | for i in 0..4 { | ^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 6 previous errors diff --git a/tests/ui/consts/control-flow/try.stderr b/tests/ui/consts/control-flow/try.stderr index e08f52369fa..5e2c77318e7 100644 --- a/tests/ui/consts/control-flow/try.stderr +++ b/tests/ui/consts/control-flow/try.stderr @@ -17,10 +17,6 @@ LL | x?; note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/option.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0015]: `?` cannot convert from residual of `Option` in constant functions --> $DIR/try.rs:6:5 @@ -31,10 +27,6 @@ LL | x?; note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/option.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 3 previous errors diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs index 805c03da546..62917c0b98b 100644 --- a/tests/ui/consts/copy-intrinsic.rs +++ b/tests/ui/consts/copy-intrinsic.rs @@ -5,9 +5,11 @@ use std::mem; extern "rust-intrinsic" { + #[stable(feature = "dummy", since = "1.0.0")] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); + #[stable(feature = "dummy", since = "1.0.0")] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] fn copy(src: *const T, dst: *mut T, count: usize); } diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr index da8139129c9..29a88f6270b 100644 --- a/tests/ui/consts/copy-intrinsic.stderr +++ b/tests/ui/consts/copy-intrinsic.stderr @@ -1,23 +1,23 @@ error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:28:5 + --> $DIR/copy-intrinsic.rs:30:5 | LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x100[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:37:5 + --> $DIR/copy-intrinsic.rs:39:5 | LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:44:5 + --> $DIR/copy-intrinsic.rs:46:5 | LL | copy(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:50:5 + --> $DIR/copy-intrinsic.rs:52:5 | LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping` diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr index 218c90f89a9..a686bc23c0f 100644 --- a/tests/ui/consts/fn_trait_refs.stderr +++ b/tests/ui/consts/fn_trait_refs.stderr @@ -11,96 +11,168 @@ LL | #![feature(const_cmp)] | ^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:13:15 + --> $DIR/fn_trait_refs.rs:13:8 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:13:31 + --> $DIR/fn_trait_refs.rs:13:24 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:13:15 + --> $DIR/fn_trait_refs.rs:13:8 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:20:15 + --> $DIR/fn_trait_refs.rs:13:8 | -LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:20:34 - | -LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:20:15 - | -LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^^ +LL | T: ~const Fn<()> + ~const Destruct, + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:27:15 + --> $DIR/fn_trait_refs.rs:13:24 + | +LL | T: ~const Fn<()> + ~const Destruct, + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:20:8 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:20:27 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:20:8 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:20:8 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:20:27 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:27:8 | LL | T: ~const FnOnce<()>, - | ^^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:27:15 + --> $DIR/fn_trait_refs.rs:27:8 | LL | T: ~const FnOnce<()>, - | ^^^^^^^^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:34:15 + --> $DIR/fn_trait_refs.rs:27:8 | -LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:34:31 - | -LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:34:15 - | -LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ +LL | T: ~const FnOnce<()>, + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:48:15 + --> $DIR/fn_trait_refs.rs:34:8 | -LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^^ +LL | T: ~const Fn<()> + ~const Destruct, + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:48:34 + --> $DIR/fn_trait_refs.rs:34:24 | -LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^ +LL | T: ~const Fn<()> + ~const Destruct, + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:48:15 + --> $DIR/fn_trait_refs.rs:34:8 + | +LL | T: ~const Fn<()> + ~const Destruct, + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:34:8 + | +LL | T: ~const Fn<()> + ~const Destruct, + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:34:24 + | +LL | T: ~const Fn<()> + ~const Destruct, + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:48:8 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^^^^ + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:48:27 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:48:8 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:48:8 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/fn_trait_refs.rs:48:27 + | +LL | T: ~const FnMut<()> + ~const Destruct, + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -111,10 +183,6 @@ LL | assert!(test_one == (1, 1, 1)); | ^^^^^^^^^^^^^^^^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error[E0015]: cannot call non-const operator in constants --> $DIR/fn_trait_refs.rs:73:17 @@ -123,10 +191,6 @@ LL | assert!(test_two == (2, 2)); | ^^^^^^^^^^^^^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error[E0015]: cannot call non-const closure in constant functions --> $DIR/fn_trait_refs.rs:15:5 @@ -139,10 +203,6 @@ help: consider further restricting this bound | LL | T: ~const Fn<()> + ~const Destruct + ~const Fn(), | +++++++++++++ -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/fn_trait_refs.rs:11:23 @@ -164,10 +224,6 @@ help: consider further restricting this bound | LL | T: ~const FnMut<()> + ~const Destruct + ~const FnMut(), | ++++++++++++++++ -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/fn_trait_refs.rs:18:27 @@ -189,10 +245,6 @@ help: consider further restricting this bound | LL | T: ~const FnOnce<()> + ~const FnOnce(), | +++++++++++++++++ -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/fn_trait_refs.rs:32:21 @@ -212,7 +264,7 @@ LL | const fn test_fn_mut(mut f: T) -> (T::Output, T::Output) LL | } | - value is dropped here -error: aborting due to 25 previous errors +error: aborting due to 34 previous errors Some errors have detailed explanations: E0015, E0493, E0635. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/intrinsic_without_const_stab.rs b/tests/ui/consts/intrinsic_without_const_stab.rs deleted file mode 100644 index 40ec65d51be..00000000000 --- a/tests/ui/consts/intrinsic_without_const_stab.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![feature(intrinsics, staged_api)] -#![stable(feature = "core", since = "1.6.0")] - -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] -#[inline] -pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { - // Const stability attributes are not inherited from parent items. - extern "rust-intrinsic" { - fn copy(src: *const T, dst: *mut T, count: usize); - } - - unsafe { copy(src, dst, count) } - //~^ ERROR cannot call non-const fn -} - -fn main() {} diff --git a/tests/ui/consts/intrinsic_without_const_stab.stderr b/tests/ui/consts/intrinsic_without_const_stab.stderr deleted file mode 100644 index e3143080c5f..00000000000 --- a/tests/ui/consts/intrinsic_without_const_stab.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0015]: cannot call non-const fn `copy::copy::` in constant functions - --> $DIR/intrinsic_without_const_stab.rs:13:14 - | -LL | unsafe { copy(src, dst, count) } - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/intrinsic_without_const_stab_fail.rs b/tests/ui/consts/intrinsic_without_const_stab_fail.rs deleted file mode 100644 index 2b0745b3c11..00000000000 --- a/tests/ui/consts/intrinsic_without_const_stab_fail.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(intrinsics, staged_api)] -#![stable(feature = "core", since = "1.6.0")] - -extern "rust-intrinsic" { - fn copy(src: *const T, dst: *mut T, count: usize); -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] -#[inline] -pub const unsafe fn stuff(src: *const T, dst: *mut T, count: usize) { - unsafe { copy(src, dst, count) } //~ ERROR cannot call non-const fn -} - -fn main() {} diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr index 0e41053a29d..2e48837bdcd 100644 --- a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr +++ b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr @@ -6,10 +6,6 @@ LL | const { (|| {})() } => {} | = note: closures need an RFC before allowed to be called in constants = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: could not evaluate constant pattern --> $DIR/invalid-inline-const-in-match-arm.rs:5:9 diff --git a/tests/ui/consts/issue-28113.stderr b/tests/ui/consts/issue-28113.stderr index c2f53870173..401536c1353 100644 --- a/tests/ui/consts/issue-28113.stderr +++ b/tests/ui/consts/issue-28113.stderr @@ -6,10 +6,6 @@ LL | || -> u8 { 5 }() | = note: closures need an RFC before allowed to be called in constants = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-56164.stderr b/tests/ui/consts/issue-56164.stderr index 6ec4ce0fbd7..de5a53c9ad2 100644 --- a/tests/ui/consts/issue-56164.stderr +++ b/tests/ui/consts/issue-56164.stderr @@ -6,10 +6,6 @@ LL | const fn foo() { (||{})() } | = note: closures need an RFC before allowed to be called in constant functions = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: function pointer calls are not allowed in constant functions --> $DIR/issue-56164.rs:5:5 diff --git a/tests/ui/consts/issue-68542-closure-in-array-len.stderr b/tests/ui/consts/issue-68542-closure-in-array-len.stderr index b414a6e0dba..9f323b2259f 100644 --- a/tests/ui/consts/issue-68542-closure-in-array-len.stderr +++ b/tests/ui/consts/issue-68542-closure-in-array-len.stderr @@ -6,10 +6,6 @@ LL | a: [(); (|| { 0 })()] | = note: closures need an RFC before allowed to be called in constants = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-73976-monomorphic.stderr b/tests/ui/consts/issue-73976-monomorphic.stderr index 79dbed4bea8..ef754b23ff0 100644 --- a/tests/ui/consts/issue-73976-monomorphic.stderr +++ b/tests/ui/consts/issue-73976-monomorphic.stderr @@ -7,10 +7,6 @@ LL | GetTypeId::::VALUE == GetTypeId::::VALUE note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/any.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-90870.rs b/tests/ui/consts/issue-90870.rs index e1929c68c70..b62769a33f8 100644 --- a/tests/ui/consts/issue-90870.rs +++ b/tests/ui/consts/issue-90870.rs @@ -3,9 +3,6 @@ #![allow(dead_code)] const fn f(a: &u8, b: &u8) -> bool { -//~^ HELP: add `#![feature(const_trait_impl)]` -//~| HELP: add `#![feature(const_trait_impl)]` -//~| HELP: add `#![feature(const_trait_impl)]` a == b //~^ ERROR: cannot call non-const operator in constant functions [E0015] //~| HELP: consider dereferencing here diff --git a/tests/ui/consts/issue-90870.stderr b/tests/ui/consts/issue-90870.stderr index df88a0c95cc..ea987920d7d 100644 --- a/tests/ui/consts/issue-90870.stderr +++ b/tests/ui/consts/issue-90870.stderr @@ -1,5 +1,5 @@ error[E0015]: cannot call non-const operator in constant functions - --> $DIR/issue-90870.rs:9:5 + --> $DIR/issue-90870.rs:6:5 | LL | a == b | ^^^^^^ @@ -9,13 +9,9 @@ help: consider dereferencing here | LL | *a == *b | + + -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0015]: cannot call non-const operator in constant functions - --> $DIR/issue-90870.rs:15:5 + --> $DIR/issue-90870.rs:12:5 | LL | a == b | ^^^^^^ @@ -25,13 +21,9 @@ help: consider dereferencing here | LL | ****a == ****b | ++++ ++++ -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0015]: cannot call non-const operator in constant functions - --> $DIR/issue-90870.rs:22:12 + --> $DIR/issue-90870.rs:19:12 | LL | if l == r { | ^^^^^^ @@ -41,10 +33,6 @@ help: consider dereferencing here | LL | if *l == *r { | + + -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 3 previous errors diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr index a85c5e10374..8cad13724f2 100644 --- a/tests/ui/consts/issue-94675.stderr +++ b/tests/ui/consts/issue-94675.stderr @@ -7,10 +7,6 @@ LL | self.bar[0] = baz.len(); note: impl defined here, but it is not `const` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error: aborting due to 1 previous error diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs index 461499e942f..d6f07994e82 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -5,7 +5,7 @@ issue = "none")] #![feature(foo, foo2)] -#![feature(const_async_blocks, staged_api)] +#![feature(const_async_blocks, staged_api, rustc_attrs)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature="foo", issue = "none")] @@ -14,33 +14,55 @@ const fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn +const fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]` #[unstable(feature = "foo2", issue = "none")] +#[rustc_const_unstable(feature = "foo2", issue = "none")] const fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn +const fn bar2() -> u32 { foo2() } //~ ERROR cannot use `#[feature(foo2)]` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // conformity is required const fn bar3() -> u32 { let x = async { 13 }; - //~^ ERROR const-stable function cannot use `#[feature(const_async_blocks)]` + //~^ ERROR cannot use `#[feature(const_async_blocks)]` foo() - //~^ ERROR is not yet stable as a const fn + //~^ ERROR cannot use `#[feature(foo)]` } // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] +#[rustc_const_unstable(feature = "foo2", issue = "none")] const fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn +const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]` + +// Functions without any attribute are checked like stable functions, +// even if they are in a stable module. +mod stable { + #![stable(feature = "rust1", since = "1.0.0")] + + pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]` +} +// And same for const-unstable functions that are marked as "stable_indirect". +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature="foo", issue = "none")] +#[rustc_const_stable_indirect] +const fn stable_indirect() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]` + +// These functiuons *can* be called from fully stable functions. +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +const fn bar2_gated_exposed() -> u32 { + stable::bar2_gated_stable_indirect() + stable_indirect() +} fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index fedc5a4809d..899cec07ac7 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -1,51 +1,127 @@ -error: `foo` is not yet stable as a const fn +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]` --> $DIR/min_const_fn_libstd_stability.rs:17:25 | LL | const fn bar() -> u32 { foo() } | ^^^^^ | - = help: const-stable functions can only call other const-stable functions + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn bar() -> u32 { foo() } + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(foo)] +LL | const fn bar() -> u32 { foo() } + | -error: `foo2` is not yet stable as a const fn - --> $DIR/min_const_fn_libstd_stability.rs:25:26 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_fn_libstd_stability.rs:26:26 | LL | const fn bar2() -> u32 { foo2() } | ^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn bar2() -> u32 { foo2() } + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(foo2)] +LL | const fn bar2() -> u32 { foo2() } + | -error: const-stable function cannot use `#[feature(const_async_blocks)]` - --> $DIR/min_const_fn_libstd_stability.rs:31:13 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_async_blocks)]` + --> $DIR/min_const_fn_libstd_stability.rs:32:13 | LL | let x = async { 13 }; | ^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be stable, make this function unstably const +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) | LL + #[rustc_const_unstable(feature = "...", issue = "...")] LL | const fn bar3() -> u32 { | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval) +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) | LL + #[rustc_allow_const_fn_unstable(const_async_blocks)] LL | const fn bar3() -> u32 { | -error: `foo` is not yet stable as a const fn - --> $DIR/min_const_fn_libstd_stability.rs:33:5 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]` + --> $DIR/min_const_fn_libstd_stability.rs:34:5 | LL | foo() | ^^^^^ | - = help: const-stable functions can only call other const-stable functions + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn bar3() -> u32 { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(foo)] +LL | const fn bar3() -> u32 { + | -error: `foo2_gated` is not yet stable as a const fn - --> $DIR/min_const_fn_libstd_stability.rs:44:32 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_fn_libstd_stability.rs:46:32 | LL | const fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn bar2_gated() -> u32 { foo2_gated() } + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(foo2)] +LL | const fn bar2_gated() -> u32 { foo2_gated() } + | -error: aborting due to 5 previous errors +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_fn_libstd_stability.rs:53:63 + | +LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } + | ^^^^^^^^^^^^^^^^^^^ + | + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(foo2)] +LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_fn_libstd_stability.rs:59:37 + | +LL | const fn stable_indirect() -> u32 { foo2_gated() } + | ^^^^^^^^^^^^ + | + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn stable_indirect() -> u32 { foo2_gated() } + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(foo2)] +LL | const fn stable_indirect() -> u32 { foo2_gated() } + | + +error: aborting due to 7 previous errors diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs index 274b4444799..3e82b9ff924 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -13,24 +13,26 @@ const unsafe fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR not yet stable as a const fn +const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR cannot use `#[feature(foo)]` #[unstable(feature = "foo2", issue = "none")] +#[rustc_const_unstable(feature = "foo2", issue = "none")] const unsafe fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as a const fn +const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR cannot use `#[feature(foo2)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] +#[rustc_const_unstable(feature = "foo2", issue = "none")] const unsafe fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } -//~^ ERROR not yet stable as a const fn +//~^ ERROR cannot use `#[feature(foo2)]` fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index 353b117efbc..442a079020f 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -1,26 +1,56 @@ -error: `foo` is not yet stable as a const fn +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41 | LL | const unsafe fn bar() -> u32 { unsafe { foo() } } | ^^^^^ | - = help: const-stable functions can only call other const-stable functions + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const unsafe fn bar() -> u32 { unsafe { foo() } } + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(foo)] +LL | const unsafe fn bar() -> u32 { unsafe { foo() } } + | -error: `foo2` is not yet stable as a const fn - --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:25:42 | LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | ^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(foo2)] +LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } + | -error: `foo2_gated` is not yet stable as a const fn - --> $DIR/min_const_unsafe_fn_libstd_stability.rs:33:48 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:35:48 | LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } | ^^^^^^^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(foo2)] +LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } + | error: aborting due to 3 previous errors diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs index 94b62071362..cc7eaa51a6f 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs @@ -13,23 +13,25 @@ const fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn +const unsafe fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]` #[unstable(feature = "foo2", issue = "none")] +#[rustc_const_unstable(feature="foo2", issue = "none")] const fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn +const unsafe fn bar2() -> u32 { foo2() } //~ ERROR cannot use `#[feature(foo2)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] +#[rustc_const_unstable(feature="foo2", issue = "none")] const fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn +const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]` fn main() {} diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr index e90ba9b912f..ff37cba7b9a 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr @@ -1,26 +1,56 @@ -error: `foo` is not yet stable as a const fn +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]` --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32 | LL | const unsafe fn bar() -> u32 { foo() } | ^^^^^ | - = help: const-stable functions can only call other const-stable functions + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const unsafe fn bar() -> u32 { foo() } + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(foo)] +LL | const unsafe fn bar() -> u32 { foo() } + | -error: `foo2` is not yet stable as a const fn - --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:25:33 | LL | const unsafe fn bar2() -> u32 { foo2() } | ^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const unsafe fn bar2() -> u32 { foo2() } + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(foo2)] +LL | const unsafe fn bar2() -> u32 { foo2() } + | -error: `foo2_gated` is not yet stable as a const fn - --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39 +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]` + --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:35:39 | LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = help: const-stable functions can only call other const-stable functions + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(foo2)] +LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } + | error: aborting due to 3 previous errors diff --git a/tests/ui/consts/rustc-const-stability-require-const.rs b/tests/ui/consts/rustc-const-stability-require-const.rs index 4fb259b335c..6cc3f0f0da1 100644 --- a/tests/ui/consts/rustc-const-stability-require-const.rs +++ b/tests/ui/consts/rustc-const-stability-require-const.rs @@ -1,16 +1,16 @@ #![crate_type = "lib"] -#![feature(staged_api)] +#![feature(staged_api, rustc_attrs)] #![stable(feature = "foo", since = "1.0.0")] #[stable(feature = "foo", since = "1.0.0")] #[rustc_const_unstable(feature = "const_foo", issue = "none")] pub fn foo() {} -//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +//~^ ERROR require the function or method to be `const` #[stable(feature = "bar", since = "1.0.0")] #[rustc_const_stable(feature = "const_bar", since = "1.0.0")] pub fn bar() {} -//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +//~^ ERROR require the function or method to be `const` #[stable(feature = "potato", since = "1.0.0")] pub struct Potato; @@ -19,23 +19,23 @@ impl Potato { #[stable(feature = "salad", since = "1.0.0")] #[rustc_const_unstable(feature = "const_salad", issue = "none")] pub fn salad(&self) -> &'static str { "mmmmmm" } - //~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + //~^ ERROR require the function or method to be `const` #[stable(feature = "roasted", since = "1.0.0")] #[rustc_const_unstable(feature = "const_roasted", issue = "none")] pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } - //~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` + //~^ ERROR require the function or method to be `const` } #[stable(feature = "bar", since = "1.0.0")] #[rustc_const_stable(feature = "const_bar", since = "1.0.0")] pub extern "C" fn bar_c() {} -//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +//~^ ERROR require the function or method to be `const` #[stable(feature = "foo", since = "1.0.0")] #[rustc_const_unstable(feature = "const_foo", issue = "none")] pub extern "C" fn foo_c() {} -//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +//~^ ERROR require the function or method to be `const` #[stable(feature = "foobar", since = "1.0.0")] @@ -45,3 +45,20 @@ pub const fn foobar() {} #[stable(feature = "barfoo", since = "1.0.0")] #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] pub const fn barfoo() {} + +// `rustc_const_stable` also requires the function to be stable. + +#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] +const fn barfoo_unmarked() {} +//~^ ERROR can only be applied to functions that are declared `#[stable]` + +#[unstable(feature = "unstable", issue = "none")] +#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] +pub const fn barfoo_unstable() {} +//~^ ERROR can only be applied to functions that are declared `#[stable]` + +// `#[rustc_const_stable_indirect]` also requires a const fn +#[rustc_const_stable_indirect] +#[unstable(feature = "unstable", issue = "none")] +pub fn not_a_const_fn() {} +//~^ ERROR require the function or method to be `const` diff --git a/tests/ui/consts/rustc-const-stability-require-const.stderr b/tests/ui/consts/rustc-const-stability-require-const.stderr index 1027b9311b7..d9a7d37cbcd 100644 --- a/tests/ui/consts/rustc-const-stability-require-const.stderr +++ b/tests/ui/consts/rustc-const-stability-require-const.stderr @@ -1,8 +1,6 @@ -error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` --> $DIR/rustc-const-stability-require-const.rs:7:1 | -LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")] - | -------------------------------------------------------------- attribute specified here LL | pub fn foo() {} | ^^^^^^^^^^^^ | @@ -12,11 +10,9 @@ help: make the function or method const LL | pub fn foo() {} | ^^^^^^^^^^^^ -error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` --> $DIR/rustc-const-stability-require-const.rs:12:1 | -LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")] - | ------------------------------------------------------------- attribute specified here LL | pub fn bar() {} | ^^^^^^^^^^^^ | @@ -26,11 +22,9 @@ help: make the function or method const LL | pub fn bar() {} | ^^^^^^^^^^^^ -error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` --> $DIR/rustc-const-stability-require-const.rs:21:5 | -LL | #[rustc_const_unstable(feature = "const_salad", issue = "none")] - | ---------------------------------------------------------------- attribute specified here LL | pub fn salad(&self) -> &'static str { "mmmmmm" } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -40,11 +34,9 @@ help: make the function or method const LL | pub fn salad(&self) -> &'static str { "mmmmmm" } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` --> $DIR/rustc-const-stability-require-const.rs:26:5 | -LL | #[rustc_const_unstable(feature = "const_roasted", issue = "none")] - | ------------------------------------------------------------------ attribute specified here LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -54,11 +46,9 @@ help: make the function or method const LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` --> $DIR/rustc-const-stability-require-const.rs:32:1 | -LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")] - | ------------------------------------------------------------- attribute specified here LL | pub extern "C" fn bar_c() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -68,11 +58,9 @@ help: make the function or method const LL | pub extern "C" fn bar_c() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const` +error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` --> $DIR/rustc-const-stability-require-const.rs:37:1 | -LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")] - | -------------------------------------------------------------- attribute specified here LL | pub extern "C" fn foo_c() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -82,5 +70,33 @@ help: make the function or method const LL | pub extern "C" fn foo_c() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]` + --> $DIR/rustc-const-stability-require-const.rs:52:1 + | +LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] + | ---------------------------------------------------------------- attribute specified here +LL | const fn barfoo_unmarked() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]` + --> $DIR/rustc-const-stability-require-const.rs:57:1 + | +LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")] + | ---------------------------------------------------------------- attribute specified here +LL | pub const fn barfoo_unstable() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const` + --> $DIR/rustc-const-stability-require-const.rs:63:1 + | +LL | pub fn not_a_const_fn() {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function or method const + --> $DIR/rustc-const-stability-require-const.rs:63:1 + | +LL | pub fn not_a_const_fn() {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors diff --git a/tests/ui/consts/try-operator.stderr b/tests/ui/consts/try-operator.stderr index 2c8b4c7fcd9..40d96ed3a10 100644 --- a/tests/ui/consts/try-operator.stderr +++ b/tests/ui/consts/try-operator.stderr @@ -13,10 +13,6 @@ LL | Err(())?; note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/result.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error[E0015]: `?` cannot convert from residual of `Result` in constant functions --> $DIR/try-operator.rs:10:9 @@ -27,10 +23,6 @@ LL | Err(())?; note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/result.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error[E0015]: `?` cannot determine the branch of `Option<()>` in constant functions --> $DIR/try-operator.rs:18:9 @@ -41,10 +33,6 @@ LL | None?; note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/option.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error[E0015]: `?` cannot convert from residual of `Option<()>` in constant functions --> $DIR/try-operator.rs:18:9 @@ -55,10 +43,6 @@ LL | None?; note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/option.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error: aborting due to 5 previous errors diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr index 6c83eff4de0..2bdec1bf41b 100644 --- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr @@ -1,8 +1,16 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/unstable-const-fn-in-libcore.rs:19:39 + --> $DIR/unstable-const-fn-in-libcore.rs:19:32 | LL | const fn unwrap_or_else T>(self, f: F) -> T { - | ^^^^^^^^^^^^^ + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/unstable-const-fn-in-libcore.rs:19:32 + | +LL | const fn unwrap_or_else T>(self, f: F) -> T { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const closure in constant functions --> $DIR/unstable-const-fn-in-libcore.rs:24:26 @@ -15,10 +23,6 @@ help: consider further restricting this bound | LL | const fn unwrap_or_else T + ~const FnOnce()>(self, f: F) -> T { | +++++++++++++++++ -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error[E0493]: destructor of `F` cannot be evaluated at compile-time --> $DIR/unstable-const-fn-in-libcore.rs:19:60 @@ -38,7 +42,7 @@ LL | const fn unwrap_or_else T>(self, f: F) -> T { LL | } | - value is dropped here -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0015, E0493. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/unstable-const-stable.rs b/tests/ui/consts/unstable-const-stable.rs deleted file mode 100644 index f69e8d0efe5..00000000000 --- a/tests/ui/consts/unstable-const-stable.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ aux-build:unstable_but_const_stable.rs - -extern crate unstable_but_const_stable; -use unstable_but_const_stable::*; - -fn main() { - some_unstable_fn(); //~ERROR use of unstable library feature - unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature -} - -const fn const_main() { - some_unstable_fn(); //~ERROR use of unstable library feature - unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature -} diff --git a/tests/ui/consts/unstable-const-stable.stderr b/tests/ui/consts/unstable-const-stable.stderr deleted file mode 100644 index c4ffbbb60db..00000000000 --- a/tests/ui/consts/unstable-const-stable.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0658]: use of unstable library feature 'unstable' - --> $DIR/unstable-const-stable.rs:7:5 - | -LL | some_unstable_fn(); - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #42 for more information - = help: add `#![feature(unstable)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature 'unstable' - --> $DIR/unstable-const-stable.rs:8:14 - | -LL | unsafe { write_bytes(4 as *mut u8, 0, 0) }; - | ^^^^^^^^^^^ - | - = note: see issue #42 for more information - = help: add `#![feature(unstable)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature 'unstable' - --> $DIR/unstable-const-stable.rs:12:5 - | -LL | some_unstable_fn(); - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #42 for more information - = help: add `#![feature(unstable)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature 'unstable' - --> $DIR/unstable-const-stable.rs:13:14 - | -LL | unsafe { write_bytes(4 as *mut u8, 0, 0) }; - | ^^^^^^^^^^^ - | - = note: see issue #42 for more information - = help: add `#![feature(unstable)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/zst_no_llvm_alloc.rs b/tests/ui/consts/zst_no_llvm_alloc.rs index 48ef11e2b58..1e92e3bbd4c 100644 --- a/tests/ui/consts/zst_no_llvm_alloc.rs +++ b/tests/ui/consts/zst_no_llvm_alloc.rs @@ -17,8 +17,11 @@ fn main() { // The exact addresses returned by these library functions are not necessarily stable guarantees // but for now we assert that we're still matching. - assert_eq!(>::new().as_ptr(), <&[i32]>::default().as_ptr()); - assert_eq!(>::default().as_ptr(), (&[]).as_ptr()); + #[allow(dangling_pointers_from_temporaries)] + { + assert_eq!(>::new().as_ptr(), <&[i32]>::default().as_ptr()); + assert_eq!(>::default().as_ptr(), (&[]).as_ptr()); + }; // statics must have a unique address (see https://github.com/rust-lang/rust/issues/18297, not // clear whether this is a stable guarantee) diff --git a/tests/ui/delegation/ice-issue-124347.rs b/tests/ui/delegation/ice-issue-124347.rs index ee2bf9e33eb..b2b3c61a722 100644 --- a/tests/ui/delegation/ice-issue-124347.rs +++ b/tests/ui/delegation/ice-issue-124347.rs @@ -4,7 +4,7 @@ // FIXME(fn_delegation): `recursive delegation` error should be emitted here trait Trait { reuse Trait::foo { &self.0 } - //~^ ERROR cycle detected when computing generics of `Trait::foo` + //~^ ERROR recursive delegation is not supported yet } reuse foo; diff --git a/tests/ui/delegation/ice-issue-124347.stderr b/tests/ui/delegation/ice-issue-124347.stderr index bd0bc970b94..74c4b5cd949 100644 --- a/tests/ui/delegation/ice-issue-124347.stderr +++ b/tests/ui/delegation/ice-issue-124347.stderr @@ -1,16 +1,8 @@ -error[E0391]: cycle detected when computing generics of `Trait::foo` +error: recursive delegation is not supported yet --> $DIR/ice-issue-124347.rs:6:18 | LL | reuse Trait::foo { &self.0 } - | ^^^ - | - = note: ...which immediately requires computing generics of `Trait::foo` again -note: cycle used when inheriting delegation signature - --> $DIR/ice-issue-124347.rs:6:18 - | -LL | reuse Trait::foo { &self.0 } - | ^^^ - = 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 + | ^^^ callee defined here error[E0391]: cycle detected when computing generics of `foo` --> $DIR/ice-issue-124347.rs:10:7 diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs index e57effff48d..56296db85a3 100644 --- a/tests/ui/delegation/unsupported.rs +++ b/tests/ui/delegation/unsupported.rs @@ -51,7 +51,7 @@ mod effects { } reuse Trait::foo; - //~^ ERROR delegation to a function with effect parameter is not supported yet + //~^ ERROR type annotations needed } fn main() {} diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr index 6a627be3b64..1c79a603503 100644 --- a/tests/ui/delegation/unsupported.stderr +++ b/tests/ui/delegation/unsupported.stderr @@ -81,15 +81,15 @@ LL | pub reuse to_reuse2::foo; LL | reuse to_reuse1::foo; | ^^^ -error: delegation to a function with effect parameter is not supported yet +error[E0283]: type annotations needed --> $DIR/unsupported.rs:53:18 | -LL | fn foo(); - | --------- callee defined here -... LL | reuse Trait::foo; - | ^^^ + | ^^^ cannot infer type + | + = note: cannot satisfy `_: effects::Trait` error: aborting due to 5 previous errors; 2 warnings emitted -For more information about this error, try `rustc --explain E0391`. +Some errors have detailed explanations: E0283, E0391. +For more information about an error, try `rustc --explain E0283`. diff --git a/tests/ui/deriving/auxiliary/another-proc-macro.rs b/tests/ui/deriving/auxiliary/another-proc-macro.rs index a05175c9de9..c992cde4066 100644 --- a/tests/ui/deriving/auxiliary/another-proc-macro.rs +++ b/tests/ui/deriving/auxiliary/another-proc-macro.rs @@ -6,7 +6,7 @@ extern crate proc_macro; -use proc_macro::{quote, TokenStream}; +use proc_macro::{TokenStream, quote}; #[proc_macro_derive(AnotherMacro, attributes(pointee))] pub fn derive(_input: TokenStream) -> TokenStream { diff --git a/tests/ui/deriving/built-in-proc-macro-scope.rs b/tests/ui/deriving/built-in-proc-macro-scope.rs index 41c95f63b13..6c473aefc5b 100644 --- a/tests/ui/deriving/built-in-proc-macro-scope.rs +++ b/tests/ui/deriving/built-in-proc-macro-scope.rs @@ -2,14 +2,14 @@ //@ aux-build: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded -#![feature(derive_smart_pointer)] +#![feature(derive_coerce_pointee)] #[macro_use] extern crate another_proc_macro; -use another_proc_macro::{pointee, AnotherMacro}; +use another_proc_macro::{AnotherMacro, pointee}; -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct Ptr<'a, #[pointee] T: ?Sized> { data: &'a mut T, diff --git a/tests/ui/deriving/built-in-proc-macro-scope.stdout b/tests/ui/deriving/built-in-proc-macro-scope.stdout index c649b7a9a57..07767dc229f 100644 --- a/tests/ui/deriving/built-in-proc-macro-scope.stdout +++ b/tests/ui/deriving/built-in-proc-macro-scope.stdout @@ -4,7 +4,7 @@ //@ aux-build: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded -#![feature(derive_smart_pointer)] +#![feature(derive_coerce_pointee)] #[prelude_import] use ::std::prelude::rust_2015::*; #[macro_use] @@ -13,7 +13,7 @@ extern crate std; #[macro_use] extern crate another_proc_macro; -use another_proc_macro::{pointee, AnotherMacro}; +use another_proc_macro::{AnotherMacro, pointee}; #[repr(transparent)] pub struct Ptr<'a, #[pointee] T: ?Sized> { diff --git a/tests/ui/deriving/smart-pointer-bounds-issue-127647.rs b/tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs similarity index 82% rename from tests/ui/deriving/smart-pointer-bounds-issue-127647.rs rename to tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs index 4cae1b32896..a1aabf1cb52 100644 --- a/tests/ui/deriving/smart-pointer-bounds-issue-127647.rs +++ b/tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs @@ -1,8 +1,8 @@ //@ check-pass -#![feature(derive_smart_pointer)] +#![feature(derive_coerce_pointee)] -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct Ptr<'a, #[pointee] T: OnDrop + ?Sized, X> { data: &'a mut T, @@ -13,7 +13,7 @@ pub trait OnDrop { fn on_drop(&mut self); } -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct Ptr2<'a, #[pointee] T: ?Sized, X> where @@ -25,7 +25,7 @@ where pub trait MyTrait {} -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct Ptr3<'a, #[pointee] T: ?Sized, X> where @@ -35,14 +35,14 @@ where x: core::marker::PhantomData, } -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct Ptr4<'a, #[pointee] T: MyTrait + ?Sized, X> { data: &'a mut T, x: core::marker::PhantomData, } -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct Ptr5<'a, #[pointee] T: ?Sized, X> where @@ -56,7 +56,7 @@ where pub struct Ptr5Companion(core::marker::PhantomData); pub struct Ptr5Companion2; -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct Ptr6<'a, #[pointee] T: ?Sized, X: MyTrait = (), const PARAM: usize = 0> { data: &'a mut T, @@ -65,7 +65,7 @@ pub struct Ptr6<'a, #[pointee] T: ?Sized, X: MyTrait = (), const PARAM: usize // a reduced example from https://lore.kernel.org/all/20240402-linked-list-v1-1-b1c59ba7ae3b@google.com/ #[repr(transparent)] -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] pub struct ListArc<#[pointee] T, const ID: u64 = 0> where T: ListArcSafe + ?Sized, diff --git a/tests/ui/deriving/deriving-smart-pointer-expanded.rs b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs similarity index 75% rename from tests/ui/deriving/deriving-smart-pointer-expanded.rs rename to tests/ui/deriving/deriving-coerce-pointee-expanded.rs index e48ad3dd4bc..94be7031fb7 100644 --- a/tests/ui/deriving/deriving-smart-pointer-expanded.rs +++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs @@ -1,17 +1,17 @@ //@ check-pass //@ compile-flags: -Zunpretty=expanded -#![feature(derive_smart_pointer)] -use std::marker::SmartPointer; +#![feature(derive_coerce_pointee)] +use std::marker::CoercePointee; pub trait MyTrait {} -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct MyPointer<'a, #[pointee] T: ?Sized> { ptr: &'a T, } -#[derive(core::marker::SmartPointer)] +#[derive(core::marker::CoercePointee)] #[repr(transparent)] pub struct MyPointer2<'a, Y, Z: MyTrait, #[pointee] T: ?Sized + MyTrait, X: MyTrait = ()> where @@ -21,7 +21,7 @@ where x: core::marker::PhantomData, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct MyPointerWithoutPointee<'a, T: ?Sized> { ptr: &'a T, diff --git a/tests/ui/deriving/deriving-smart-pointer-expanded.stdout b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout similarity index 96% rename from tests/ui/deriving/deriving-smart-pointer-expanded.stdout rename to tests/ui/deriving/deriving-coerce-pointee-expanded.stdout index 68ef17f2b05..d6eaca5cba1 100644 --- a/tests/ui/deriving/deriving-smart-pointer-expanded.stdout +++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout @@ -2,12 +2,12 @@ #![no_std] //@ check-pass //@ compile-flags: -Zunpretty=expanded -#![feature(derive_smart_pointer)] +#![feature(derive_coerce_pointee)] #[prelude_import] use ::std::prelude::rust_2015::*; #[macro_use] extern crate std; -use std::marker::SmartPointer; +use std::marker::CoercePointee; pub trait MyTrait {} diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.rs b/tests/ui/deriving/deriving-coerce-pointee-neg.rs similarity index 50% rename from tests/ui/deriving/deriving-smart-pointer-neg.rs rename to tests/ui/deriving/deriving-coerce-pointee-neg.rs index 41d3039236f..deef35cdf70 100644 --- a/tests/ui/deriving/deriving-smart-pointer-neg.rs +++ b/tests/ui/deriving/deriving-coerce-pointee-neg.rs @@ -1,115 +1,131 @@ -#![feature(derive_smart_pointer, arbitrary_self_types)] +#![feature(derive_coerce_pointee, arbitrary_self_types)] extern crate core; -use std::marker::SmartPointer; +use std::marker::CoercePointee; -#[derive(SmartPointer)] -//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` +#[derive(CoercePointee)] +//~^ ERROR: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` enum NotStruct<'a, T: ?Sized> { Variant(&'a T), } -#[derive(SmartPointer)] -//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field +#[derive(CoercePointee)] +//~^ ERROR: `CoercePointee` can only be derived on `struct`s with at least one field #[repr(transparent)] struct NoField<'a, #[pointee] T: ?Sized> {} //~^ ERROR: lifetime parameter `'a` is never used //~| ERROR: type parameter `T` is never used -#[derive(SmartPointer)] -//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field +#[derive(CoercePointee)] +//~^ ERROR: `CoercePointee` can only be derived on `struct`s with at least one field #[repr(transparent)] struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); //~^ ERROR: lifetime parameter `'a` is never used //~| ERROR: type parameter `T` is never used -#[derive(SmartPointer)] -//~^ ERROR: `SmartPointer` can only be derived on `struct`s that are generic over at least one type +#[derive(CoercePointee)] +//~^ ERROR: `CoercePointee` can only be derived on `struct`s that are generic over at least one type #[repr(transparent)] struct NoGeneric<'a>(&'a u8); -#[derive(SmartPointer)] -//~^ ERROR: exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits +#[derive(CoercePointee)] +//~^ ERROR: exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits #[repr(transparent)] struct AmbiguousPointee<'a, T1: ?Sized, T2: ?Sized> { a: (&'a T1, &'a T2), } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B)); -//~^ ERROR: only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits +//~^ ERROR: only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits -#[derive(SmartPointer)] -//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` +#[derive(CoercePointee)] +//~^ ERROR: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` struct NotTransparent<'a, #[pointee] T: ?Sized> { ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct NoMaybeSized<'a, #[pointee] T> { - //~^ ERROR: `derive(SmartPointer)` requires T to be marked `?Sized` + //~^ ERROR: `derive(CoercePointee)` requires T to be marked `?Sized` ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct PointeeOnField<'a, #[pointee] T: ?Sized> { #[pointee] - //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters - ptr: &'a T -} - -#[derive(SmartPointer)] -#[repr(transparent)] -struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> { //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] +#[repr(transparent)] +struct PointeeInTypeConstBlock< + 'a, + T: ?Sized = [u32; const { + struct UhOh<#[pointee] T>(T); + //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters + 10 + }], +> { + ptr: &'a T, +} + +#[derive(CoercePointee)] #[repr(transparent)] struct PointeeInConstConstBlock< 'a, T: ?Sized, - const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }> - //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters -{ + const V: u32 = { + struct UhOh<#[pointee] T>(T); + //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters + 10 + }, +> { ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct PointeeInAnotherTypeConstBlock<'a, #[pointee] T: ?Sized> { - ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }> - //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters + ptr: PointeeInConstConstBlock< + 'a, + T, + { + struct UhOh<#[pointee] T>(T); + //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters + 0 + }, + >, } // However, reordering attributes should work nevertheless. #[repr(transparent)] -#[derive(SmartPointer)] -struct ThisIsAPossibleSmartPointer<'a, #[pointee] T: ?Sized> { +#[derive(CoercePointee)] +struct ThisIsAPossibleCoercePointee<'a, #[pointee] T: ?Sized> { ptr: &'a T, } // Also, these paths to Sized should work -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct StdSized<'a, #[pointee] T: ?std::marker::Sized> { ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct CoreSized<'a, #[pointee] T: ?core::marker::Sized> { ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct GlobalStdSized<'a, #[pointee] T: ?::std::marker::Sized> { ptr: &'a T, } -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct GlobalCoreSized<'a, #[pointee] T: ?::core::marker::Sized> { ptr: &'a T, diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr new file mode 100644 index 00000000000..e590d636d0e --- /dev/null +++ b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr @@ -0,0 +1,119 @@ +error: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` + --> $DIR/deriving-coerce-pointee-neg.rs:6:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `CoercePointee` can only be derived on `struct`s with at least one field + --> $DIR/deriving-coerce-pointee-neg.rs:12:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `CoercePointee` can only be derived on `struct`s with at least one field + --> $DIR/deriving-coerce-pointee-neg.rs:19:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `CoercePointee` can only be derived on `struct`s that are generic over at least one type + --> $DIR/deriving-coerce-pointee-neg.rs:26:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits + --> $DIR/deriving-coerce-pointee-neg.rs:31:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits + --> $DIR/deriving-coerce-pointee-neg.rs:40:39 + | +LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B)); + | ^ ^ + +error: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]` + --> $DIR/deriving-coerce-pointee-neg.rs:43:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `derive(CoercePointee)` requires T to be marked `?Sized` + --> $DIR/deriving-coerce-pointee-neg.rs:51:36 + | +LL | struct NoMaybeSized<'a, #[pointee] T> { + | ^ + +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-coerce-pointee-neg.rs:59:5 + | +LL | #[pointee] + | ^^^^^^^^^^ + +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-coerce-pointee-neg.rs:69:33 + | +LL | struct UhOh<#[pointee] T>(T); + | ^^^^^^^^^^ + +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-coerce-pointee-neg.rs:83:21 + | +LL | struct UhOh<#[pointee] T>(T); + | ^^^^^^^^^^ + +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-coerce-pointee-neg.rs:98:25 + | +LL | struct UhOh<#[pointee] T>(T); + | ^^^^^^^^^^ + +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/deriving-coerce-pointee-neg.rs:15:16 + | +LL | struct NoField<'a, #[pointee] T: ?Sized> {} + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: type parameter `T` is never used + --> $DIR/deriving-coerce-pointee-neg.rs:15:31 + | +LL | struct NoField<'a, #[pointee] T: ?Sized> {} + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/deriving-coerce-pointee-neg.rs:22:20 + | +LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: type parameter `T` is never used + --> $DIR/deriving-coerce-pointee-neg.rs:22:35 + | +LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 16 previous errors + +For more information about this error, try `rustc --explain E0392`. diff --git a/tests/ui/deriving/deriving-smart-pointer.rs b/tests/ui/deriving/deriving-coerce-pointee.rs similarity index 90% rename from tests/ui/deriving/deriving-smart-pointer.rs rename to tests/ui/deriving/deriving-coerce-pointee.rs index d34a502da68..26762e4d0fa 100644 --- a/tests/ui/deriving/deriving-smart-pointer.rs +++ b/tests/ui/deriving/deriving-coerce-pointee.rs @@ -1,9 +1,9 @@ //@ run-pass -#![feature(derive_smart_pointer, arbitrary_self_types)] +#![feature(derive_coerce_pointee, arbitrary_self_types)] -use std::marker::SmartPointer; +use std::marker::CoercePointee; -#[derive(SmartPointer)] +#[derive(CoercePointee)] #[repr(transparent)] struct MyPointer<'a, #[pointee] T: ?Sized> { ptr: &'a T, diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.stderr b/tests/ui/deriving/deriving-smart-pointer-neg.stderr deleted file mode 100644 index 9ab117698c7..00000000000 --- a/tests/ui/deriving/deriving-smart-pointer-neg.stderr +++ /dev/null @@ -1,119 +0,0 @@ -error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` - --> $DIR/deriving-smart-pointer-neg.rs:6:10 - | -LL | #[derive(SmartPointer)] - | ^^^^^^^^^^^^ - | - = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `SmartPointer` can only be derived on `struct`s with at least one field - --> $DIR/deriving-smart-pointer-neg.rs:12:10 - | -LL | #[derive(SmartPointer)] - | ^^^^^^^^^^^^ - | - = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `SmartPointer` can only be derived on `struct`s with at least one field - --> $DIR/deriving-smart-pointer-neg.rs:19:10 - | -LL | #[derive(SmartPointer)] - | ^^^^^^^^^^^^ - | - = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `SmartPointer` can only be derived on `struct`s that are generic over at least one type - --> $DIR/deriving-smart-pointer-neg.rs:26:10 - | -LL | #[derive(SmartPointer)] - | ^^^^^^^^^^^^ - | - = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits - --> $DIR/deriving-smart-pointer-neg.rs:31:10 - | -LL | #[derive(SmartPointer)] - | ^^^^^^^^^^^^ - | - = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits - --> $DIR/deriving-smart-pointer-neg.rs:40:39 - | -LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B)); - | ^ ^ - -error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` - --> $DIR/deriving-smart-pointer-neg.rs:43:10 - | -LL | #[derive(SmartPointer)] - | ^^^^^^^^^^^^ - | - = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `derive(SmartPointer)` requires T to be marked `?Sized` - --> $DIR/deriving-smart-pointer-neg.rs:51:36 - | -LL | struct NoMaybeSized<'a, #[pointee] T> { - | ^ - -error: the `#[pointee]` attribute may only be used on generic parameters - --> $DIR/deriving-smart-pointer-neg.rs:59:5 - | -LL | #[pointee] - | ^^^^^^^^^^ - -error: the `#[pointee]` attribute may only be used on generic parameters - --> $DIR/deriving-smart-pointer-neg.rs:66:74 - | -LL | struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> { - | ^^^^^^^^^^ - -error: the `#[pointee]` attribute may only be used on generic parameters - --> $DIR/deriving-smart-pointer-neg.rs:76:34 - | -LL | const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }> - | ^^^^^^^^^^ - -error: the `#[pointee]` attribute may only be used on generic parameters - --> $DIR/deriving-smart-pointer-neg.rs:85:56 - | -LL | ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }> - | ^^^^^^^^^^ - -error[E0392]: lifetime parameter `'a` is never used - --> $DIR/deriving-smart-pointer-neg.rs:15:16 - | -LL | struct NoField<'a, #[pointee] T: ?Sized> {} - | ^^ unused lifetime parameter - | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` - -error[E0392]: type parameter `T` is never used - --> $DIR/deriving-smart-pointer-neg.rs:15:31 - | -LL | struct NoField<'a, #[pointee] T: ?Sized> {} - | ^ unused type parameter - | - = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - -error[E0392]: lifetime parameter `'a` is never used - --> $DIR/deriving-smart-pointer-neg.rs:22:20 - | -LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); - | ^^ unused lifetime parameter - | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` - -error[E0392]: type parameter `T` is never used - --> $DIR/deriving-smart-pointer-neg.rs:22:35 - | -LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); - | ^ unused type parameter - | - = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - -error: aborting due to 16 previous errors - -For more information about this error, try `rustc --explain E0392`. diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.rs b/tests/ui/deriving/proc-macro-attribute-mixing.rs index 489665ebeb5..80a0d068ce7 100644 --- a/tests/ui/deriving/proc-macro-attribute-mixing.rs +++ b/tests/ui/deriving/proc-macro-attribute-mixing.rs @@ -1,5 +1,5 @@ // This test certify that we can mix attribute macros from Rust and external proc-macros. -// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(SmartPointer)]` uses +// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(CoercePointee)]` uses // `#[pointee]`. // The scoping rule should allow the use of the said two attributes when external proc-macros // are in scope. @@ -8,7 +8,7 @@ //@ aux-build: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded -#![feature(derive_smart_pointer)] +#![feature(derive_coerce_pointee)] #[macro_use] extern crate another_proc_macro; diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.stdout b/tests/ui/deriving/proc-macro-attribute-mixing.stdout index f314f6efbe2..03128c6c957 100644 --- a/tests/ui/deriving/proc-macro-attribute-mixing.stdout +++ b/tests/ui/deriving/proc-macro-attribute-mixing.stdout @@ -1,7 +1,7 @@ #![feature(prelude_import)] #![no_std] // This test certify that we can mix attribute macros from Rust and external proc-macros. -// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(SmartPointer)]` uses +// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(CoercePointee)]` uses // `#[pointee]`. // The scoping rule should allow the use of the said two attributes when external proc-macros // are in scope. @@ -10,7 +10,7 @@ //@ aux-build: another-proc-macro.rs //@ compile-flags: -Zunpretty=expanded -#![feature(derive_smart_pointer)] +#![feature(derive_coerce_pointee)] #[prelude_import] use ::std::prelude::rust_2015::*; #[macro_use] diff --git a/tests/ui/drop/drop_order.rs b/tests/ui/drop/drop_order.rs index cf062538007..29b68d666fc 100644 --- a/tests/ui/drop/drop_order.rs +++ b/tests/ui/drop/drop_order.rs @@ -105,6 +105,7 @@ impl DropOrderCollector { () => self.print(10), } + #[cfg(edition2021)] match { match self.option_loud_drop(14) { _ => { @@ -115,6 +116,17 @@ impl DropOrderCollector { } { _ => self.print(12), } + #[cfg(edition2024)] + match { + match self.option_loud_drop(12) { + _ => { + self.print(11); + self.option_loud_drop(14) + } + } + } { + _ => self.print(13), + } match { loop { 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 b22e72bcfad..fde542c756f 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order-gated.rs +++ b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs @@ -1,15 +1,11 @@ -// This test ensures that `tail_expr_drop_order` does not activate in case Edition 2024 is not used -// or the feature gate `shorter_tail_lifetimes` is disabled. +// This test is to demonstrate that the lint is gated behind Edition and +// is triggered only for Edition 2021 and before. -//@ revisions: neither no_feature_gate edition_less_than_2024 //@ check-pass -//@ [neither] edition: 2021 -//@ [no_feature_gate] compile-flags: -Z unstable-options -//@ [no_feature_gate] edition: 2024 -//@ [edition_less_than_2024] edition: 2021 +//@ edition: 2024 +//@ compile-flags: -Z unstable-options #![deny(tail_expr_drop_order)] -#![cfg_attr(edition_less_than_2024, feature(shorter_tail_lifetimes))] struct LoudDropper; impl Drop for LoudDropper { diff --git a/tests/ui/drop/lint-tail-expr-drop-order.rs b/tests/ui/drop/lint-tail-expr-drop-order.rs index 0aa0ef02610..d61abae5187 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order.rs +++ b/tests/ui/drop/lint-tail-expr-drop-order.rs @@ -1,12 +1,10 @@ -//@ compile-flags: -Z unstable-options -//@ edition: 2024 +//@ 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 #![deny(tail_expr_drop_order)] -#![feature(shorter_tail_lifetimes)] struct LoudDropper; impl Drop for LoudDropper { diff --git a/tests/ui/drop/lint-tail-expr-drop-order.stderr b/tests/ui/drop/lint-tail-expr-drop-order.stderr index 630f0a80f09..6775c4ce6d1 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order.stderr +++ b/tests/ui/drop/lint-tail-expr-drop-order.stderr @@ -1,5 +1,5 @@ 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:29:15 + --> $DIR/lint-tail-expr-drop-order.rs:27:15 | LL | let x = LoudDropper; | - these values have significant drop implementation and will observe changes in drop order under Edition 2024 @@ -10,13 +10,13 @@ LL | x.get() + LoudDropper.get() = warning: this changes meaning in Rust 2024 = note: for more information, see issue #123739 note: the lint level is defined here - --> $DIR/lint-tail-expr-drop-order.rs:8:9 + --> $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:36:23 + --> $DIR/lint-tail-expr-drop-order.rs:34:23 | LL | let x = LoudDropper; | - these values have significant drop implementation and will observe changes in drop order under Edition 2024 @@ -27,7 +27,7 @@ LL | move || x.get() + LoudDropper.get() = note: for more information, see issue #123739 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:65:19 + --> $DIR/lint-tail-expr-drop-order.rs:63:19 | LL | let x = LoudDropper; | - these values have significant drop implementation and will observe changes in drop order under Edition 2024 diff --git a/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr b/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr index 75fc34e409b..bcce796570e 100644 --- a/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr +++ b/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/tail-expr-drop-order-negative.rs:11:15 + --> $DIR/tail-expr-drop-order-negative.rs:9:15 | LL | x.replace(std::cell::RefCell::new(123).borrow()).is_some() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement diff --git a/tests/ui/drop/tail-expr-drop-order-negative.rs b/tests/ui/drop/tail-expr-drop-order-negative.rs index c570b3a1ee2..5ad04d0a67e 100644 --- a/tests/ui/drop/tail-expr-drop-order-negative.rs +++ b/tests/ui/drop/tail-expr-drop-order-negative.rs @@ -3,8 +3,6 @@ //@ [edition2024] edition: 2024 //@ [edition2021] check-pass -#![feature(shorter_tail_lifetimes)] - fn why_would_you_do_this() -> bool { let mut x = None; // Make a temporary `RefCell` and put a `Ref` that borrows it in `x`. diff --git a/tests/ui/drop/tail-expr-drop-order.rs b/tests/ui/drop/tail-expr-drop-order.rs index 5d87f980b15..80968b823f9 100644 --- a/tests/ui/drop/tail-expr-drop-order.rs +++ b/tests/ui/drop/tail-expr-drop-order.rs @@ -4,7 +4,6 @@ //@ edition: 2024 //@ run-pass -#![feature(shorter_tail_lifetimes)] #![allow(unused_imports)] #![allow(dead_code)] #![allow(unused_variables)] diff --git a/tests/ui/error-codes/E0081.rs b/tests/ui/error-codes/E0081.rs index f53fda864d6..8fdb27c36e3 100644 --- a/tests/ui/error-codes/E0081.rs +++ b/tests/ui/error-codes/E0081.rs @@ -50,5 +50,47 @@ enum MultipleDuplicates { //~^ NOTE `-2` assigned here } -fn main() { +// Test for #131902 +// Ensure that casting an enum with too many variants for its repr +// does not ICE +#[repr(u8)] +enum TooManyVariants { + //~^ ERROR discriminant value `0` assigned more than once + X000, X001, X002, X003, X004, X005, X006, X007, X008, X009, + //~^ NOTE `0` assigned here + //~| NOTE discriminant for `X256` incremented from this startpoint + X010, X011, X012, X013, X014, X015, X016, X017, X018, X019, + X020, X021, X022, X023, X024, X025, X026, X027, X028, X029, + X030, X031, X032, X033, X034, X035, X036, X037, X038, X039, + X040, X041, X042, X043, X044, X045, X046, X047, X048, X049, + X050, X051, X052, X053, X054, X055, X056, X057, X058, X059, + X060, X061, X062, X063, X064, X065, X066, X067, X068, X069, + X070, X071, X072, X073, X074, X075, X076, X077, X078, X079, + X080, X081, X082, X083, X084, X085, X086, X087, X088, X089, + X090, X091, X092, X093, X094, X095, X096, X097, X098, X099, + X100, X101, X102, X103, X104, X105, X106, X107, X108, X109, + X110, X111, X112, X113, X114, X115, X116, X117, X118, X119, + X120, X121, X122, X123, X124, X125, X126, X127, X128, X129, + X130, X131, X132, X133, X134, X135, X136, X137, X138, X139, + X140, X141, X142, X143, X144, X145, X146, X147, X148, X149, + X150, X151, X152, X153, X154, X155, X156, X157, X158, X159, + X160, X161, X162, X163, X164, X165, X166, X167, X168, X169, + X170, X171, X172, X173, X174, X175, X176, X177, X178, X179, + X180, X181, X182, X183, X184, X185, X186, X187, X188, X189, + X190, X191, X192, X193, X194, X195, X196, X197, X198, X199, + X200, X201, X202, X203, X204, X205, X206, X207, X208, X209, + X210, X211, X212, X213, X214, X215, X216, X217, X218, X219, + X220, X221, X222, X223, X224, X225, X226, X227, X228, X229, + X230, X231, X232, X233, X234, X235, X236, X237, X238, X239, + X240, X241, X242, X243, X244, X245, X246, X247, X248, X249, + X250, X251, X252, X253, X254, X255, + X256, + //~^ ERROR enum discriminant overflowed + //~| NOTE overflowed on value after 255 + //~| NOTE explicitly set `X256 = 0` + //~| NOTE `0` assigned here +} + +fn main() { + TooManyVariants::X256 as u8; } diff --git a/tests/ui/error-codes/E0081.stderr b/tests/ui/error-codes/E0081.stderr index d4b21f6893b..91445eedf4d 100644 --- a/tests/ui/error-codes/E0081.stderr +++ b/tests/ui/error-codes/E0081.stderr @@ -73,6 +73,30 @@ LL | LL | V9, | -- `-2` assigned here -error: aborting due to 5 previous errors +error[E0370]: enum discriminant overflowed + --> $DIR/E0081.rs:87:5 + | +LL | X256, + | ^^^^ overflowed on value after 255 + | + = note: explicitly set `X256 = 0` if that is desired outcome -For more information about this error, try `rustc --explain E0081`. +error[E0081]: discriminant value `0` assigned more than once + --> $DIR/E0081.rs:57:1 + | +LL | enum TooManyVariants { + | ^^^^^^^^^^^^^^^^^^^^ +LL | +LL | X000, X001, X002, X003, X004, X005, X006, X007, X008, X009, + | ---- + | | + | `0` assigned here + | discriminant for `X256` incremented from this startpoint (`X000` + 256 variants later => `X256` = 0) +... +LL | X256, + | ---- `0` assigned here + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0081, E0370. +For more information about an error, try `rustc --explain E0081`. diff --git a/tests/ui/feature-gates/duplicate-features.rs b/tests/ui/feature-gates/duplicate-features.rs index d8f7818054a..1fae71c3eb2 100644 --- a/tests/ui/feature-gates/duplicate-features.rs +++ b/tests/ui/feature-gates/duplicate-features.rs @@ -1,9 +1,9 @@ #![allow(stable_features)] #![feature(rust1)] -#![feature(rust1)] //~ ERROR the feature `rust1` has already been declared +#![feature(rust1)] //~ ERROR the feature `rust1` has already been enabled #![feature(if_let)] -#![feature(if_let)] //~ ERROR the feature `if_let` has already been declared +#![feature(if_let)] //~ ERROR the feature `if_let` has already been enabled fn main() {} diff --git a/tests/ui/feature-gates/duplicate-features.stderr b/tests/ui/feature-gates/duplicate-features.stderr index dbde806f6cc..f667a5b9623 100644 --- a/tests/ui/feature-gates/duplicate-features.stderr +++ b/tests/ui/feature-gates/duplicate-features.stderr @@ -1,10 +1,10 @@ -error[E0636]: the feature `if_let` has already been declared +error[E0636]: the feature `if_let` has already been enabled --> $DIR/duplicate-features.rs:7:12 | LL | #![feature(if_let)] | ^^^^^^ -error[E0636]: the feature `rust1` has already been declared +error[E0636]: the feature `rust1` has already been enabled --> $DIR/duplicate-features.rs:4:12 | LL | #![feature(rust1)] diff --git a/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs new file mode 100644 index 00000000000..69bc70e8666 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs @@ -0,0 +1,9 @@ +use std::marker::CoercePointee; //~ ERROR use of unstable library feature 'derive_coerce_pointee' + +#[derive(CoercePointee)] //~ ERROR use of unstable library feature 'derive_coerce_pointee' +#[repr(transparent)] +struct MyPointer<'a, #[pointee] T: ?Sized> { + ptr: &'a T, +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr new file mode 100644 index 00000000000..0b52ceb782a --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr @@ -0,0 +1,23 @@ +error[E0658]: use of unstable library feature 'derive_coerce_pointee' + --> $DIR/feature-gate-derive-coerce-pointee.rs:3:10 + | +LL | #[derive(CoercePointee)] + | ^^^^^^^^^^^^^ + | + = note: see issue #123430 for more information + = help: add `#![feature(derive_coerce_pointee)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'derive_coerce_pointee' + --> $DIR/feature-gate-derive-coerce-pointee.rs:1:5 + | +LL | use std::marker::CoercePointee; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #123430 for more information + = help: add `#![feature(derive_coerce_pointee)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs deleted file mode 100644 index 7b4764ee768..00000000000 --- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs +++ /dev/null @@ -1,9 +0,0 @@ -use std::marker::SmartPointer; //~ ERROR use of unstable library feature 'derive_smart_pointer' - -#[derive(SmartPointer)] //~ ERROR use of unstable library feature 'derive_smart_pointer' -#[repr(transparent)] -struct MyPointer<'a, #[pointee] T: ?Sized> { - ptr: &'a T, -} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr deleted file mode 100644 index ea4d1271b7c..00000000000 --- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0658]: use of unstable library feature 'derive_smart_pointer' - --> $DIR/feature-gate-derive-smart-pointer.rs:3:10 - | -LL | #[derive(SmartPointer)] - | ^^^^^^^^^^^^ - | - = note: see issue #123430 for more information - = help: add `#![feature(derive_smart_pointer)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature 'derive_smart_pointer' - --> $DIR/feature-gate-derive-smart-pointer.rs:1:5 - | -LL | use std::marker::SmartPointer; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #123430 for more information - = help: add `#![feature(derive_smart_pointer)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr index 319056a9c88..d599523c727 100644 --- a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr +++ b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr @@ -1,3 +1,17 @@ +error: can't mark as unstable using an already stable feature + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 + | +LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable +LL | const fn my_fun() {} + | -------------------- the stability attribute annotates this item + | +help: consider removing the attribute + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 + | +LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: can't mark as unstable using an already stable feature --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1 | @@ -13,19 +27,5 @@ help: consider removing the attribute LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: can't mark as unstable using an already stable feature - --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 - | -LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable -LL | const fn my_fun() {} - | -------------------- the stability attribute annotates this item - | -help: consider removing the attribute - --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 - | -LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: aborting due to 2 previous errors diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index a22bba07c02..f83e7c87728 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -17,7 +17,7 @@ LL | format!("{:X}", "3"); i32 and 9 others = note: required for `&str` to implement `UpperHex` -note: required by a bound in `core::fmt::rt::Argument::<'a>::new_upper_hex` +note: required by a bound in `core::fmt::rt::Argument::<'_>::new_upper_hex` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs new file mode 100644 index 00000000000..f1c196a154d --- /dev/null +++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs @@ -0,0 +1,20 @@ +//@ only-linux +//@ compile-flags: --error-format=human --color=always +//@ error-pattern: the trait bound + +trait Foo: Bar {} + +trait Bar {} + +struct Struct; + +impl Foo for T where T: Bar +{} + +impl<'a> Bar<()> for Struct {} + +fn foo() -> impl Foo { + Struct +} + +fn main() {} diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg new file mode 100644 index 00000000000..e09b96e5ff2 --- /dev/null +++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg @@ -0,0 +1,62 @@ + + + + + + + error[E0277]: the trait bound `Struct: Foo<i32>` is not satisfied + + --> $DIR/highlight-difference-between-expected-trait-and-found-trait.rs:16:13 + + | + + LL | fn foo() -> impl Foo<i32> { + + | ^^^^^^^^^^^^^ the trait `Bar<i32>` is not implemented for `Struct`, which is required by `Struct: Foo<i32>` + + | + + = help: the trait `Bar<()>` is implemented for `Struct` + + = help: for that trait implementation, expected `()`, found `i32` + + note: required for `Struct` to implement `Foo<i32>` + + --> $DIR/highlight-difference-between-expected-trait-and-found-trait.rs:11:12 + + | + + LL | impl<T, K> Foo<K> for T where T: Bar<K> + + | ^^^^^^ ^ ------ unsatisfied trait bound introduced here + + + + error: aborting due to 1 previous error + + + + For more information about this error, try `rustc --explain E0277`. + + + + + + diff --git a/tests/ui/impl-trait/impl_trait_projections.rs b/tests/ui/impl-trait/impl_trait_projections.rs index 365ac85e2f6..2c277aee06d 100644 --- a/tests/ui/impl-trait/impl_trait_projections.rs +++ b/tests/ui/impl-trait/impl_trait_projections.rs @@ -10,30 +10,27 @@ fn path_parametrized_type_is_allowed() -> option::Option { } fn projection_is_disallowed(x: impl Iterator) -> ::Item { -//~^ ERROR `impl Trait` is not allowed in path parameters -//~| ERROR `impl Trait` is not allowed in path parameters +//~^ ERROR `impl Trait` is not allowed in paths x.next().unwrap() } fn projection_with_named_trait_is_disallowed(mut x: impl Iterator) -> ::Item -//~^ ERROR `impl Trait` is not allowed in path parameters +//~^ ERROR `impl Trait` is not allowed in paths { x.next().unwrap() } fn projection_with_named_trait_inside_path_is_disallowed() -> <::std::ops::Range as Iterator>::Item -//~^ ERROR `impl Trait` is not allowed in path parameters -//~| ERROR `impl Debug: Step` is not satisfied +//~^ ERROR `impl Trait` is not allowed in paths { - //~^ ERROR `impl Debug: Step` is not satisfied (1i32..100).next().unwrap() } fn projection_from_impl_trait_inside_dyn_trait_is_disallowed() -> as Iterator>::Item -//~^ ERROR `impl Trait` is not allowed in path parameters +//~^ ERROR `impl Trait` is not allowed in paths { panic!() } diff --git a/tests/ui/impl-trait/impl_trait_projections.stderr b/tests/ui/impl-trait/impl_trait_projections.stderr index d62e3ac4183..5e0b80fcd59 100644 --- a/tests/ui/impl-trait/impl_trait_projections.stderr +++ b/tests/ui/impl-trait/impl_trait_projections.stderr @@ -1,73 +1,35 @@ -error[E0667]: `impl Trait` is not allowed in path parameters +error[E0562]: `impl Trait` is not allowed in paths --> $DIR/impl_trait_projections.rs:12:51 | LL | fn projection_is_disallowed(x: impl Iterator) -> ::Item { | ^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:19:9 +error[E0562]: `impl Trait` is not allowed in paths + --> $DIR/impl_trait_projections.rs:18:9 | LL | -> ::Item | ^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:26:27 +error[E0562]: `impl Trait` is not allowed in paths + --> $DIR/impl_trait_projections.rs:25:27 | LL | -> <::std::ops::Range as Iterator>::Item | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:35:29 +error[E0562]: `impl Trait` is not allowed in paths + --> $DIR/impl_trait_projections.rs:32:29 | LL | -> as Iterator>::Item | ^^^^^^^^^^ - -error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:12:51 | -LL | fn projection_is_disallowed(x: impl Iterator) -> ::Item { - | ^^^^^^^^^^^^^ + = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0277]: the trait bound `impl Debug: Step` is not satisfied - --> $DIR/impl_trait_projections.rs:26:8 - | -LL | -> <::std::ops::Range as Iterator>::Item - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range: Iterator` - | - = help: the following other types implement trait `Step`: - Char - Ipv4Addr - Ipv6Addr - char - i128 - i16 - i32 - i64 - and 8 others - = note: required for `std::ops::Range` to implement `Iterator` +error: aborting due to 4 previous errors -error[E0277]: the trait bound `impl Debug: Step` is not satisfied - --> $DIR/impl_trait_projections.rs:29:1 - | -LL | / { -LL | | -LL | | (1i32..100).next().unwrap() -LL | | } - | |_^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range: Iterator` - | - = help: the following other types implement trait `Step`: - Char - Ipv4Addr - Ipv6Addr - char - i128 - i16 - i32 - i64 - and 8 others - = note: required for `std::ops::Range` to implement `Iterator` - -error: aborting due to 7 previous errors - -Some errors have detailed explanations: E0277, E0667. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs new file mode 100644 index 00000000000..c2c22cd1abf --- /dev/null +++ b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs @@ -0,0 +1,22 @@ +// issue: rust-lang/rust#126725 + +trait Foo { + fn foo<'a>() -> <&'a impl Sized as Bar>::Output; + //~^ ERROR `impl Trait` is not allowed in paths +} + +trait Bar { + type Output; +} + +impl<'a> Bar for &'a () { + type Output = &'a i32; +} + +impl Foo for () { + fn foo<'a>() -> <&'a Self as Bar>::Output { + &0 + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr new file mode 100644 index 00000000000..bea7ccd1a18 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr @@ -0,0 +1,11 @@ +error[E0562]: `impl Trait` is not allowed in paths + --> $DIR/bad-projection-from-opaque.rs:4:26 + | +LL | fn foo<'a>() -> <&'a impl Sized as Bar>::Output; + | ^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs index c5ecd1caae1..9466668b1dc 100644 --- a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs +++ b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs @@ -6,7 +6,7 @@ pub trait Bar { } pub trait Quux { type Assoc; } pub fn demo(_: impl Quux<(), Assoc=<() as Quux>::Assoc>) { } -//~^ ERROR `impl Trait` is not allowed in path parameters +//~^ ERROR `impl Trait` is not allowed in paths impl Quux for () { type Assoc = u32; } fn main() { } diff --git a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr index 55f47785f0e..25547dfa66f 100644 --- a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr +++ b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr @@ -1,9 +1,11 @@ -error[E0667]: `impl Trait` is not allowed in path parameters +error[E0562]: `impl Trait` is not allowed in paths --> $DIR/issue-57979-impl-trait-in-path.rs:8:48 | LL | pub fn demo(_: impl Quux<(), Assoc=<() as Quux>::Assoc>) { } | ^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0667`. +For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr index e0d193b5d40..f9142664f1b 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.stderr +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -1,14 +1,30 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/normalize-tait-in-const.rs:26:42 + --> $DIR/normalize-tait-in-const.rs:26:35 | LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/normalize-tait-in-const.rs:26:69 + --> $DIR/normalize-tait-in-const.rs:26:62 | LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^^^^^^ + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/normalize-tait-in-const.rs:26:35 + | +LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/normalize-tait-in-const.rs:26:62 + | +LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const closure in constant functions --> $DIR/normalize-tait-in-const.rs:27:5 @@ -21,10 +37,6 @@ help: consider further restricting this bound | LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct + ~const Fn(&foo::Alias<'_>)>(fun: F) { | ++++++++++++++++++++++++++++ -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error[E0493]: destructor of `F` cannot be evaluated at compile-time --> $DIR/normalize-tait-in-const.rs:26:79 @@ -35,7 +47,7 @@ LL | fun(filter_positive()); LL | } | - value is dropped here -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0015, E0493. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/intrinsics/const-eval-select-stability.rs b/tests/ui/intrinsics/const-eval-select-stability.rs index 575bc0cadda..25cbadaa22d 100644 --- a/tests/ui/intrinsics/const-eval-select-stability.rs +++ b/tests/ui/intrinsics/const-eval-select-stability.rs @@ -15,7 +15,7 @@ const fn nothing(){} #[rustc_const_stable(since = "1.0", feature = "const_hey")] pub const fn hey() { const_eval_select((), nothing, log); - //~^ ERROR `const_eval_select` is not yet stable as a const fn + //~^ ERROR cannot use `#[feature(const_eval_select)]` } fn main() {} diff --git a/tests/ui/intrinsics/const-eval-select-stability.stderr b/tests/ui/intrinsics/const-eval-select-stability.stderr index 335b9877aa0..5f443b1d4ff 100644 --- a/tests/ui/intrinsics/const-eval-select-stability.stderr +++ b/tests/ui/intrinsics/const-eval-select-stability.stderr @@ -1,10 +1,19 @@ -error: `const_eval_select` is not yet stable as a const fn +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_eval_select)]` --> $DIR/const-eval-select-stability.rs:17:5 | LL | const_eval_select((), nothing, log); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: const-stable functions can only call other const-stable functions +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | pub const fn hey() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(const_eval_select)] +LL | pub const fn hey() { + | error: aborting due to 1 previous error diff --git a/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.regparm4.stderr b/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.regparm4.stderr new file mode 100644 index 00000000000..8fc04adf57f --- /dev/null +++ b/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.regparm4.stderr @@ -0,0 +1,4 @@ +error: `-Zregparm=4` is unsupported (valid values 0-3) + +error: aborting due to 1 previous error + diff --git a/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.rs b/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.rs new file mode 100644 index 00000000000..b548d678520 --- /dev/null +++ b/tests/ui/invalid-compile-flags/regparm/regparm-valid-values.rs @@ -0,0 +1,24 @@ +//@ revisions: regparm0 regparm1 regparm2 regparm3 regparm4 + +//@ needs-llvm-components: x86 +//@ compile-flags: --target i686-unknown-linux-gnu + +//@[regparm0] check-pass +//@[regparm0] compile-flags: -Zregparm=0 + +//@[regparm1] check-pass +//@[regparm1] compile-flags: -Zregparm=1 + +//@[regparm2] check-pass +//@[regparm2] compile-flags: -Zregparm=2 + +//@[regparm3] check-pass +//@[regparm3] compile-flags: -Zregparm=3 + +//@[regparm4] check-fail +//@[regparm4] compile-flags: -Zregparm=4 +//@[regparm4] error-pattern: `-Zregparm=4` is unsupported (valid values 0-3) + +#![feature(no_core)] +#![no_core] +#![no_main] diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.aarch64.stderr b/tests/ui/invalid-compile-flags/regparm/requires-x86.aarch64.stderr new file mode 100644 index 00000000000..2433519f803 --- /dev/null +++ b/tests/ui/invalid-compile-flags/regparm/requires-x86.aarch64.stderr @@ -0,0 +1,4 @@ +error: `-Zregparm=N` is only supported on x86 + +error: aborting due to 1 previous error + diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.rs b/tests/ui/invalid-compile-flags/regparm/requires-x86.rs new file mode 100644 index 00000000000..ce6e437fb47 --- /dev/null +++ b/tests/ui/invalid-compile-flags/regparm/requires-x86.rs @@ -0,0 +1,21 @@ +//@ revisions: x86 x86_64 aarch64 + +//@ compile-flags: -Zregparm=3 + +//@[x86] check-pass +//@[x86] needs-llvm-components: x86 +//@[x86] compile-flags: --target i686-unknown-linux-gnu + +//@[x86_64] check-fail +//@[x86_64] needs-llvm-components: x86 +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64] error-pattern: `-Zregparm=N` is only supported on x86 + +//@[aarch64] check-fail +//@[aarch64] needs-llvm-components: aarch64 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] error-pattern: `-Zregparm=N` is only supported on x86 + +#![feature(no_core)] +#![no_core] +#![no_main] diff --git a/tests/ui/invalid-compile-flags/regparm/requires-x86.x86_64.stderr b/tests/ui/invalid-compile-flags/regparm/requires-x86.x86_64.stderr new file mode 100644 index 00000000000..2433519f803 --- /dev/null +++ b/tests/ui/invalid-compile-flags/regparm/requires-x86.x86_64.stderr @@ -0,0 +1,4 @@ +error: `-Zregparm=N` is only supported on x86 + +error: aborting due to 1 previous error + diff --git a/tests/ui/issues/issue-25901.stderr b/tests/ui/issues/issue-25901.stderr index 3fedfd96417..bcbc805908f 100644 --- a/tests/ui/issues/issue-25901.stderr +++ b/tests/ui/issues/issue-25901.stderr @@ -17,10 +17,6 @@ LL | impl Deref for A { | ^^^^^^^^^^^^^^^^ = note: calls in statics are limited to constant functions, tuple structs and tuple variants = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr b/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr index 858be42d540..157a1c5e09b 100644 --- a/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr +++ b/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr @@ -1,5 +1,5 @@ error[E0597]: `cell` does not live long enough - --> $DIR/refcell-in-tail-expr.rs:12:27 + --> $DIR/refcell-in-tail-expr.rs:10:27 | LL | let cell = std::cell::RefCell::new(0u8); | ---- binding `cell` declared here diff --git a/tests/ui/lifetimes/refcell-in-tail-expr.rs b/tests/ui/lifetimes/refcell-in-tail-expr.rs index b1814c1e327..595e951f373 100644 --- a/tests/ui/lifetimes/refcell-in-tail-expr.rs +++ b/tests/ui/lifetimes/refcell-in-tail-expr.rs @@ -4,8 +4,6 @@ //@ [edition2024] compile-flags: -Zunstable-options //@ [edition2024] check-pass -#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))] - fn main() { let cell = std::cell::RefCell::new(0u8); diff --git a/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr b/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr index ad28ae2f80d..3c074c5c3a2 100644 --- a/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr +++ b/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr @@ -1,5 +1,5 @@ error[E0597]: `c` does not live long enough - --> $DIR/shorter-tail-expr-lifetime.rs:10:5 + --> $DIR/shorter-tail-expr-lifetime.rs:8:5 | LL | let c = std::cell::RefCell::new(".."); | - binding `c` declared here diff --git a/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs b/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs index 0392b6c6d9a..4195a8b6c32 100644 --- a/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs +++ b/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs @@ -3,8 +3,6 @@ //@ [edition2024] edition: 2024 //@ [edition2024] run-pass -#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))] - fn f() -> usize { let c = std::cell::RefCell::new(".."); c.borrow().len() //[edition2021]~ ERROR: `c` does not live long enough diff --git a/tests/ui/lifetimes/tail-expr-in-nested-expr.rs b/tests/ui/lifetimes/tail-expr-in-nested-expr.rs index a8989f22f4b..2ac97aff2b0 100644 --- a/tests/ui/lifetimes/tail-expr-in-nested-expr.rs +++ b/tests/ui/lifetimes/tail-expr-in-nested-expr.rs @@ -1,8 +1,6 @@ //@ edition: 2024 //@ compile-flags: -Zunstable-options -#![feature(shorter_tail_lifetimes)] - fn main() { let _ = { String::new().as_str() }.len(); //~^ ERROR temporary value dropped while borrowed diff --git a/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr b/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr index f699d184bdb..96e88eaca92 100644 --- a/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr +++ b/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/tail-expr-in-nested-expr.rs:7:15 + --> $DIR/tail-expr-in-nested-expr.rs:5:15 | LL | let _ = { String::new().as_str() }.len(); | ^^^^^^^^^^^^^--------- diff --git a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs index cdfd35304b4..ec74596a08d 100644 --- a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs +++ b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs @@ -4,7 +4,6 @@ //@ [edition2024] edition: 2024 //@ run-pass //@ needs-unwind -#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))] use std::sync::Mutex; diff --git a/tests/ui/linkage-attr/framework.omit.stderr b/tests/ui/linkage-attr/framework.omit.stderr deleted file mode 100644 index 23e017cb012..00000000000 --- a/tests/ui/linkage-attr/framework.omit.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: linking with `LINKER` failed: exit status: 1 - | - ld: Undefined symbols: - _CFRunLoopGetTypeID, referenced from: - clang: error: linker command failed with exit code 1 (use -v to see invocation) - - -error: aborting due to 1 previous error diff --git a/tests/ui/linkage-attr/framework.rs b/tests/ui/linkage-attr/framework.rs deleted file mode 100644 index 08f4394db21..00000000000 --- a/tests/ui/linkage-attr/framework.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Check that linking frameworks on Apple platforms works. -//@ only-apple -//@ revisions: omit link weak both -//@ [omit]build-fail -//@ [link]run-pass -//@ [weak]run-pass -//@ [both]run-pass - -// The linker's exact error output changes between Xcode versions, depends on -// linker invocation details, and the linker sometimes outputs more warnings. -//@ compare-output-lines-by-subset -//@ normalize-stderr-test: "linking with `.*` failed" -> "linking with `LINKER` failed" -//@ normalize-stderr-test: "Undefined symbols for architecture .*" -> "ld: Undefined symbols:" -//@ normalize-stderr-test: "._CFRunLoopGetTypeID.," -> "_CFRunLoopGetTypeID," - -#![cfg_attr(any(weak, both), feature(link_arg_attribute))] - -#[cfg_attr(any(link, both), link(name = "CoreFoundation", kind = "framework"))] -#[cfg_attr( - any(weak, both), - link(name = "-weak_framework", kind = "link-arg", modifiers = "+verbatim"), - link(name = "CoreFoundation", kind = "link-arg", modifiers = "+verbatim") -)] -extern "C" { - fn CFRunLoopGetTypeID() -> core::ffi::c_ulong; -} - -pub fn main() { - unsafe { - CFRunLoopGetTypeID(); - } -} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs b/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs new file mode 100644 index 00000000000..d892ebdf606 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs @@ -0,0 +1,23 @@ +#![allow(dangling_pointers_from_temporaries)] + +fn main() { + dbg!(String::new().as_ptr()); + // ^ no error + + #[deny(dangling_pointers_from_temporaries)] + { + dbg!(String::new().as_ptr()); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + } + S.foo() +} + +struct S; + +impl S { + #[warn(dangling_pointers_from_temporaries)] + fn foo(self) { + dbg!(String::new().as_ptr()); + //~^ WARNING a dangling pointer will be produced because the temporary `String` will be dropped + } +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr new file mode 100644 index 00000000000..fd434eacf3d --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr @@ -0,0 +1,34 @@ +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/allow.rs:9:28 + | +LL | dbg!(String::new().as_ptr()); + | ------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` 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 `as_ptr` the `String` 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 +note: the lint level is defined here + --> $DIR/allow.rs:7:12 + | +LL | #[deny(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/allow.rs:20:28 + | +LL | dbg!(String::new().as_ptr()); + | ------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` 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 `as_ptr` the `String` 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 +note: the lint level is defined here + --> $DIR/allow.rs:18:12 + | +LL | #[warn(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs b/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs new file mode 100644 index 00000000000..b376582a886 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs @@ -0,0 +1,52 @@ +#![deny(dangling_pointers_from_temporaries)] + +use std::ffi::{c_char, CString}; + +fn cstring() -> CString { + CString::new("hello").unwrap() +} + +fn consume(ptr: *const c_char) { + let c = unsafe { ptr.read() }; + dbg!(c); +} + +// None of these should trigger the lint. +fn ok() { + consume(cstring().as_ptr()); + consume({ cstring() }.as_ptr()); + consume({ cstring().as_ptr() }); + consume(cstring().as_ptr().cast()); + consume({ cstring() }.as_ptr().cast()); + consume({ cstring().as_ptr() }.cast()); +} + +// All of these should trigger the lint. +fn not_ok() { + { + let ptr = cstring().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + consume(ptr); + } + consume({ + let ptr = cstring().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + ptr + }); + consume({ + let s = cstring(); + s.as_ptr() + //^ FIXME: should error + }); + let _ptr: *const u8 = cstring().as_ptr().cast(); + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + let _ptr: *const u8 = { cstring() }.as_ptr().cast(); + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + let _ptr: *const u8 = { cstring().as_ptr() }.cast(); + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped +} + +fn main() { + ok(); + not_ok(); +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr new file mode 100644 index 00000000000..d1615b76d82 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr @@ -0,0 +1,62 @@ +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/calls.rs:27:29 + | +LL | let ptr = cstring().as_ptr(); + | --------- ^^^^^^ this pointer will immediately be invalid + | | + | this `CString` 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 `as_ptr` the `CString` 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 +note: the lint level is defined here + --> $DIR/calls.rs:1:9 + | +LL | #![deny(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/calls.rs:32:29 + | +LL | let ptr = cstring().as_ptr(); + | --------- ^^^^^^ this pointer will immediately be invalid + | | + | this `CString` 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 `as_ptr` the `CString` 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 + +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/calls.rs:41:37 + | +LL | let _ptr: *const u8 = cstring().as_ptr().cast(); + | --------- ^^^^^^ this pointer will immediately be invalid + | | + | this `CString` 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 `as_ptr` the `CString` 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 + +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/calls.rs:43:41 + | +LL | let _ptr: *const u8 = { cstring() }.as_ptr().cast(); + | ------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `CString` 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 `as_ptr` the `CString` 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 + +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/calls.rs:45:39 + | +LL | let _ptr: *const u8 = { cstring().as_ptr() }.cast(); + | --------- ^^^^^^ this pointer will immediately be invalid + | | + | this `CString` 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 `as_ptr` the `CString` 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 + +error: aborting due to 5 previous errors + diff --git a/tests/ui/lint/lint-temporary-cstring-as-param.rs b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.rs similarity index 62% rename from tests/ui/lint/lint-temporary-cstring-as-param.rs rename to tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.rs index 9f5805367e4..fb6ed363272 100644 --- a/tests/ui/lint/lint-temporary-cstring-as-param.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.rs @@ -1,4 +1,7 @@ +//@ check-pass + #![deny(temporary_cstring_as_ptr)] +//~^ WARNING lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` use std::ffi::CString; use std::os::raw::c_char; @@ -7,5 +10,4 @@ fn some_function(data: *const c_char) {} fn main() { some_function(CString::new("").unwrap().as_ptr()); - //~^ ERROR getting the inner pointer of a temporary `CString` } diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr new file mode 100644 index 00000000000..dd54b4971dd --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr @@ -0,0 +1,10 @@ +warning: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` + --> $DIR/cstring-as-param.rs:3:9 + | +LL | #![deny(temporary_cstring_as_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` + | + = note: `#[warn(renamed_and_removed_lints)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/lint/lint-temporary-cstring-as-ptr.rs b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs similarity index 53% rename from tests/ui/lint/lint-temporary-cstring-as-ptr.rs rename to tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs index fab792f1284..a98378794ab 100644 --- a/tests/ui/lint/lint-temporary-cstring-as-ptr.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs @@ -1,17 +1,18 @@ // this program is not technically incorrect, but is an obscure enough style to be worth linting #![deny(temporary_cstring_as_ptr)] +//~^ WARNING lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` use std::ffi::CString; macro_rules! mymacro { () => { let s = CString::new("some text").unwrap().as_ptr(); - //~^ ERROR getting the inner pointer of a temporary `CString` + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped } } fn main() { let s = CString::new("some text").unwrap().as_ptr(); - //~^ ERROR getting the inner pointer of a temporary `CString` + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped mymacro!(); } diff --git a/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr similarity index 57% rename from tests/ui/lint/lint-temporary-cstring-as-ptr.stderr rename to tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr index 4e5c8aa0693..5289fbb8723 100644 --- a/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr @@ -1,24 +1,32 @@ -error: getting the inner pointer of a temporary `CString` - --> $DIR/lint-temporary-cstring-as-ptr.rs:14:48 +warning: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries` + --> $DIR/cstring-as-ptr.rs:2:9 + | +LL | #![deny(temporary_cstring_as_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries` + | + = note: `#[warn(renamed_and_removed_lints)]` on by default + +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/cstring-as-ptr.rs:15:48 | LL | let s = CString::new("some text").unwrap().as_ptr(); - | ---------------------------------- ^^^^^^ this pointer will be invalid + | ---------------------------------- ^^^^^^ this pointer will immediately be invalid | | | this `CString` 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 `as_ptr` the `CString` 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 + = help: for more information, see note: the lint level is defined here - --> $DIR/lint-temporary-cstring-as-ptr.rs:2:9 + --> $DIR/cstring-as-ptr.rs:2:9 | LL | #![deny(temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: getting the inner pointer of a temporary `CString` - --> $DIR/lint-temporary-cstring-as-ptr.rs:8:52 +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/cstring-as-ptr.rs:9:52 | LL | let s = CString::new("some text").unwrap().as_ptr(); - | ---------------------------------- ^^^^^^ this pointer will be invalid + | ---------------------------------- ^^^^^^ this pointer will immediately be invalid | | | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime ... @@ -26,8 +34,8 @@ LL | mymacro!(); | ---------- in this macro invocation | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` 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 + = help: for more information, see = note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs b/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs new file mode 100644 index 00000000000..b9b7bd3ade1 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs @@ -0,0 +1,19 @@ +//@ check-pass + +#![deny(dangling_pointers_from_temporaries)] + +// The original code example comes from bindgen-produced code for emacs. +// Hence the name of the test. +// https://github.com/rust-lang/rust/pull/128985#issuecomment-2338951363 + +use std::ffi::{c_char, CString}; + +fn read(ptr: *const c_char) -> c_char { + unsafe { ptr.read() } +} + +fn main() { + let fnptr: Option c_char> = Some(read); + let x = fnptr.unwrap()(CString::new("foo").unwrap().as_ptr()); + assert_eq!(x as u8, b'f'); +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs new file mode 100644 index 00000000000..0fb07a3f3bc --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs @@ -0,0 +1,13 @@ +#![deny(dangling_pointers_from_temporaries)] + +const MAX_PATH: usize = 260; +fn main() { + let str1 = String::with_capacity(MAX_PATH).as_mut_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + let str2 = String::from("TotototototototototototototototototoT").as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + unsafe { + std::ptr::copy_nonoverlapping(str2, str1, 30); + println!("{:?}", String::from_raw_parts(str1, 30, 30)); + } +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr new file mode 100644 index 00000000000..0de794f6ae2 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr @@ -0,0 +1,29 @@ +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/example-from-issue123613.rs:5:48 + | +LL | let str1 = String::with_capacity(MAX_PATH).as_mut_ptr(); + | ------------------------------- ^^^^^^^^^^ this pointer will immediately be invalid + | | + | this `String` 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 `as_mut_ptr` the `String` 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 +note: the lint level is defined here + --> $DIR/example-from-issue123613.rs:1:9 + | +LL | #![deny(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/example-from-issue123613.rs:7:70 + | +LL | let str2 = String::from("TotototototototototototototototototoT").as_ptr(); + | ----------------------------------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` 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 `as_ptr` the `String` 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 + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs b/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs new file mode 100644 index 00000000000..a5e84d36090 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs @@ -0,0 +1,32 @@ +#![deny(dangling_pointers_from_temporaries)] + +use std::fmt::Debug; + +trait Ext1 { + fn dbg(self) -> Self + where + Self: Sized + Debug, + { + dbg!(&self); + self + } +} + +impl Ext1 for *const T {} + +trait Ext2 { + fn foo(self); +} + +impl Ext2 for *const u32 { + fn foo(self) { + dbg!(unsafe { self.read() }); + } +} + +fn main() { + let _ptr1 = Vec::::new().as_ptr().dbg(); + //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped + let _ptr2 = vec![0].as_ptr().foo(); + //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr new file mode 100644 index 00000000000..5d401c89c0c --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr @@ -0,0 +1,29 @@ +error: a dangling pointer will be produced because the temporary `Vec` will be dropped + --> $DIR/ext.rs:28:35 + | +LL | let _ptr1 = Vec::::new().as_ptr().dbg(); + | ----------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Vec` 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 `as_ptr` the `Vec` 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 +note: the lint level is defined here + --> $DIR/ext.rs:1:9 + | +LL | #![deny(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a dangling pointer will be produced because the temporary `Vec` will be dropped + --> $DIR/ext.rs:30:25 + | +LL | let _ptr2 = vec![0].as_ptr().foo(); + | ------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Vec` 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 `as_ptr` the `Vec` 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 + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs new file mode 100644 index 00000000000..26019b376d3 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs @@ -0,0 +1,8 @@ +#![deny(dangling_pointers_from_temporaries)] + +fn main() { + vec![0u8].as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped + vec![0u8].as_mut_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr new file mode 100644 index 00000000000..11c052c158e --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr @@ -0,0 +1,29 @@ +error: a dangling pointer will be produced because the temporary `Vec` will be dropped + --> $DIR/methods.rs:4:15 + | +LL | vec![0u8].as_ptr(); + | --------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Vec` 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 `as_ptr` the `Vec` 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 +note: the lint level is defined here + --> $DIR/methods.rs:1:9 + | +LL | #![deny(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a dangling pointer will be produced because the temporary `Vec` will be dropped + --> $DIR/methods.rs:6:15 + | +LL | vec![0u8].as_mut_ptr(); + | --------- ^^^^^^^^^^ this pointer will immediately be invalid + | | + | this `Vec` 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 `as_mut_ptr` the `Vec` 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 + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs new file mode 100644 index 00000000000..1f216586ae8 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs @@ -0,0 +1,136 @@ +#![allow(unused)] +#![deny(dangling_pointers_from_temporaries)] + +fn string() -> String { + "hello".into() +} + +struct Wrapper(String); + +fn main() { + // ConstBlock + const { String::new() }.as_ptr(); + + // Array + { + [string()].as_ptr(); // False negative + [true].as_ptr(); + } + + // Call + string().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + + // MethodCall + "hello".to_string().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + + // Tup + // impossible + + // Binary + (string() + "hello").as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + + // Path + { + let x = string(); + x.as_ptr(); + } + + // Unary + { + let x = string(); + let x: &String = &x; + (*x).as_ptr(); + (&[0u8]).as_ptr(); + (&string()).as_ptr(); // False negative + (*&string()).as_ptr(); // False negative + } + + // Lit + "hello".as_ptr(); + + // Cast + // impossible + + // Type + // impossible + + // DropTemps + // impossible + + // Let + // impossible + + // If + { + (if true { String::new() } else { "hello".into() }).as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + } + + // Loop + { + (loop { + break String::new(); + }) + .as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + } + + // Match + { + match string() { + s => s, + } + .as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + } + + // Closure + // impossible + + // Block + { string() }.as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + + // Assign, AssignOp + // impossible + + // Field + { + Wrapper(string()).0.as_ptr(); // False negative + let x = Wrapper(string()); + x.0.as_ptr(); + } + + // Index + { + vec![string()][0].as_ptr(); // False negative + let x = vec![string()]; + x[0].as_ptr(); + } + + // AddrOf, InlineAsm, OffsetOf + // impossible + + // Break, Continue, Ret + // are ! + + // Become, Yield + // unstable, are ! + + // Repeat + [0u8; 100].as_ptr(); + [const { String::new() }; 100].as_ptr(); + + // Struct + // Cannot test this without access to private fields of the linted types. + + // Err + // impossible + + // Macro + vec![0u8].as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr new file mode 100644 index 00000000000..d2e9ac8c4e9 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr @@ -0,0 +1,99 @@ +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/temporaries.rs:21:14 + | +LL | string().as_ptr(); + | -------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` 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 `as_ptr` the `String` 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 +note: the lint level is defined here + --> $DIR/temporaries.rs:2:9 + | +LL | #![deny(dangling_pointers_from_temporaries)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/temporaries.rs:25:25 + | +LL | "hello".to_string().as_ptr(); + | ------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` 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 `as_ptr` the `String` 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 + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/temporaries.rs:32:26 + | +LL | (string() + "hello").as_ptr(); + | -------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` 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 `as_ptr` the `String` 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 + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/temporaries.rs:68:61 + | +LL | (if true { String::new() } else { "hello".into() }).as_ptr(); + | --------------------------------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` 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 `as_ptr` the `String` 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 + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/temporaries.rs:77:10 + | +LL | / (loop { +LL | | break String::new(); +LL | | }) + | |__________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime +LL | .as_ptr(); + | ^^^^^^ this pointer will immediately be invalid + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `String` 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 + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/temporaries.rs:86:10 + | +LL | / match string() { +LL | | s => s, +LL | | } + | |_________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime +LL | .as_ptr(); + | ^^^^^^ this pointer will immediately be invalid + | + = note: pointers do not have a lifetime; when calling `as_ptr` the `String` 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 + +error: a dangling pointer will be produced because the temporary `String` will be dropped + --> $DIR/temporaries.rs:94:18 + | +LL | { string() }.as_ptr(); + | ------------ ^^^^^^ this pointer will immediately be invalid + | | + | this `String` 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 `as_ptr` the `String` 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 + +error: a dangling pointer will be produced because the temporary `Vec` will be dropped + --> $DIR/temporaries.rs:134:15 + | +LL | vec![0u8].as_ptr(); + | --------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Vec` 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 `as_ptr` the `Vec` 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 + +error: aborting due to 8 previous errors + diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs new file mode 100644 index 00000000000..2b515d3e6d5 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs @@ -0,0 +1,52 @@ +#![deny(dangling_pointers_from_temporaries)] + +use std::cell::Cell; +use std::ffi::{CStr, CString}; +use std::mem::MaybeUninit; + +struct AsPtrFake; + +impl AsPtrFake { + fn as_ptr(&self) -> *const () { + std::ptr::null() + } +} + +fn declval() -> T { + loop {} +} + +fn main() { + declval::().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + declval::().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + declval::>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped + declval::>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box` will be dropped + declval::>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped + declval::>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box` will be dropped + declval::>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box` will be dropped + declval::<[u8; 10]>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped + declval::>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped + declval::>>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box>` will be dropped + declval::>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box` will be dropped + declval::>>>>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Box>>>` will be dropped + declval::>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Cell` will be dropped + declval::>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit` will be dropped + declval::>().as_ptr(); + //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped + declval::>().as_ptr(); + declval::().as_ptr(); +} diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr new file mode 100644 index 00000000000..c582a4c6540 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr @@ -0,0 +1,172 @@ +error: a dangling pointer will be produced because the temporary `CString` will be dropped + --> $DIR/types.rs:20:26 + | +LL | declval::().as_ptr(); + | -------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `CString` 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 `as_ptr` the `CString` 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 +note: the lint level is defined here + --> $DIR/types.rs:1:9 + | +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 + | +LL | declval::().as_ptr(); + | ------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `String` 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 `as_ptr` the `String` 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 + +error: a dangling pointer will be produced because the temporary `Vec` will be dropped + --> $DIR/types.rs:24:26 + | +LL | declval::>().as_ptr(); + | -------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Vec` 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 `as_ptr` the `Vec` 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 + +error: a dangling pointer will be produced because the temporary `Box` will be dropped + --> $DIR/types.rs:26:31 + | +LL | declval::>().as_ptr(); + | ------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Box` 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 `as_ptr` the `Box` 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 + +error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped + --> $DIR/types.rs:28:28 + | +LL | declval::>().as_ptr(); + | ---------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Box<[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 `as_ptr` the `Box<[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 + +error: a dangling pointer will be produced because the temporary `Box` will be dropped + --> $DIR/types.rs:30:27 + | +LL | declval::>().as_ptr(); + | --------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Box` 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 `as_ptr` the `Box` 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 + +error: a dangling pointer will be produced because the temporary `Box` will be dropped + --> $DIR/types.rs:32:28 + | +LL | declval::>().as_ptr(); + | ---------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Box` 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 `as_ptr` the `Box` 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 + +error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped + --> $DIR/types.rs:34:27 + | +LL | declval::<[u8; 10]>().as_ptr(); + | --------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `[u8; 10]` 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 `as_ptr` the `[u8; 10]` 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 + +error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped + --> $DIR/types.rs:36:32 + | +LL | declval::>().as_ptr(); + | -------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Box<[u8; 10]>` 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 `as_ptr` the `Box<[u8; 10]>` 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 + +error: a dangling pointer will be produced because the temporary `Box>` will be dropped + --> $DIR/types.rs:38:31 + | +LL | declval::>>().as_ptr(); + | ------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Box>` 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 `as_ptr` the `Box>` 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 + +error: a dangling pointer will be produced because the temporary `Box` will be dropped + --> $DIR/types.rs:40:30 + | +LL | declval::>().as_ptr(); + | ------------------------ ^^^^^^ this pointer will immediately be invalid + | | + | this `Box` 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 `as_ptr` the `Box` 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 + +error: a dangling pointer will be produced because the temporary `Box>>>` will be dropped + --> $DIR/types.rs:42:43 + | +LL | declval::>>>>().as_ptr(); + | ------------------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Box>>>` 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 `as_ptr` the `Box>>>` 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 + +error: a dangling pointer will be produced because the temporary `Cell` will be dropped + --> $DIR/types.rs:44:27 + | +LL | declval::>().as_ptr(); + | --------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Cell` 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 `as_ptr` the `Cell` 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 + +error: a dangling pointer will be produced because the temporary `MaybeUninit` will be dropped + --> $DIR/types.rs:46:34 + | +LL | declval::>().as_ptr(); + | ---------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `MaybeUninit` 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 `as_ptr` the `MaybeUninit` 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 + +error: a dangling pointer will be produced because the temporary `Vec` will be dropped + --> $DIR/types.rs:48:33 + | +LL | declval::>().as_ptr(); + | --------------------------- ^^^^^^ this pointer will immediately be invalid + | | + | this `Vec` 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 `as_ptr` the `Vec` 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 + +error: aborting due to 15 previous errors + diff --git a/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs b/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs new file mode 100644 index 00000000000..08d6733d3e2 --- /dev/null +++ b/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs @@ -0,0 +1,10 @@ +// Submodule file used by test `../multi-file.rs`. + +// Keywords reserved from Rust 2018: +fn async() {} +fn await() {} +fn try() {} +fn dyn() {} + +// Keywords reserved from Rust 2024: +fn gen() {} diff --git a/tests/ui/lint/keyword-idents/multi-file.rs b/tests/ui/lint/keyword-idents/multi-file.rs new file mode 100644 index 00000000000..703e13f9ef6 --- /dev/null +++ b/tests/ui/lint/keyword-idents/multi-file.rs @@ -0,0 +1,14 @@ +#![deny(keyword_idents)] // Should affect the submodule, but doesn't. +//@ edition: 2015 +//@ known-bug: #132218 +//@ check-pass (known bug; should be check-fail) + +// Because `keyword_idents_2018` and `keyword_idents_2024` are pre-expansion +// lints, configuring them via lint attributes doesn't propagate to submodules +// in other files. +// + +#[path = "./auxiliary/multi_file_submod.rs"] +mod multi_file_submod; + +fn main() {} diff --git a/tests/ui/lint/lint-deref-nullptr.rs b/tests/ui/lint/lint-deref-nullptr.rs index d052dbd9b64..f83d88309b9 100644 --- a/tests/ui/lint/lint-deref-nullptr.rs +++ b/tests/ui/lint/lint-deref-nullptr.rs @@ -27,9 +27,9 @@ fn f() { let ub = &*ptr::null_mut::(); //~^ ERROR dereferencing a null pointer ptr::addr_of!(*ptr::null::()); - //~^ ERROR dereferencing a null pointer + // ^^ OKAY ptr::addr_of_mut!(*ptr::null_mut::()); - //~^ ERROR dereferencing a null pointer + // ^^ OKAY let offset = ptr::addr_of!((*ptr::null::()).field); //~^ ERROR dereferencing a null pointer } diff --git a/tests/ui/lint/lint-deref-nullptr.stderr b/tests/ui/lint/lint-deref-nullptr.stderr index c6f432e4e42..175431b2994 100644 --- a/tests/ui/lint/lint-deref-nullptr.stderr +++ b/tests/ui/lint/lint-deref-nullptr.stderr @@ -46,23 +46,11 @@ error: dereferencing a null pointer LL | let ub = &*ptr::null_mut::(); | ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed -error: dereferencing a null pointer - --> $DIR/lint-deref-nullptr.rs:29:23 - | -LL | ptr::addr_of!(*ptr::null::()); - | ^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed - -error: dereferencing a null pointer - --> $DIR/lint-deref-nullptr.rs:31:27 - | -LL | ptr::addr_of_mut!(*ptr::null_mut::()); - | ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed - error: dereferencing a null pointer --> $DIR/lint-deref-nullptr.rs:33:36 | LL | let offset = ptr::addr_of!((*ptr::null::()).field); | ^^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed -error: aborting due to 10 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/lint/lint-missing-doc-expect.rs b/tests/ui/lint/lint-missing-doc-expect.rs index 991f65003dc..b1abf8b6962 100644 --- a/tests/ui/lint/lint-missing-doc-expect.rs +++ b/tests/ui/lint/lint-missing-doc-expect.rs @@ -1,10 +1,10 @@ // Make sure that `#[expect(missing_docs)]` is always correctly fulfilled. //@ check-pass -//@ revisions: lib bin test +//@ revisions: lib bin test_ //@ [lib]compile-flags: --crate-type lib //@ [bin]compile-flags: --crate-type bin -//@ [test]compile-flags: --test +//@ [test_]compile-flags: --test #[expect(missing_docs)] pub fn foo() {} diff --git a/tests/ui/lint/lint-temporary-cstring-as-param.stderr b/tests/ui/lint/lint-temporary-cstring-as-param.stderr deleted file mode 100644 index 7aa21f2560c..00000000000 --- a/tests/ui/lint/lint-temporary-cstring-as-param.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: getting the inner pointer of a temporary `CString` - --> $DIR/lint-temporary-cstring-as-param.rs:9:45 - | -LL | some_function(CString::new("").unwrap().as_ptr()); - | ------------------------- ^^^^^^ this pointer will be invalid - | | - | this `CString` 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 `as_ptr` the `CString` 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 -note: the lint level is defined here - --> $DIR/lint-temporary-cstring-as-param.rs:1:9 - | -LL | #![deny(temporary_cstring_as_ptr)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs b/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs index 131d4166de0..8ca453273cd 100644 --- a/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs +++ b/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs @@ -6,9 +6,9 @@ fn main() { macro_rules! one_nested_count_and_len { ( $( [ $( $l:literal ),* ] ),* ) => { [ - // outer-most repetition + // outermost repetition $( - // inner-most repetition + // innermost repetition $( ${ignore($l)} ${index()}, ${len()}, )* @@ -23,34 +23,34 @@ fn main() { [ // # ["foo"] - // ## inner-most repetition (first iteration) + // ## innermost repetition (first iteration) // - // `index` is 0 because this is the first inner-most iteration. - // `len` is 1 because there is only one inner-most repetition, "foo". + // `index` is 0 because this is the first innermost iteration. + // `len` is 1 because there is only one innermost repetition, "foo". 0, 1, - // ## outer-most repetition (first iteration) + // ## outermost repetition (first iteration) // // `count` is 1 because of "foo", i,e, `$l` has only one repetition, - // `index` is 0 because this is the first outer-most iteration. - // `len` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"] + // `index` is 0 because this is the first outermost iteration. + // `len` is 2 because there are 2 outermost repetitions, ["foo"] and ["bar", "baz"] 1, 0, 2, // # ["bar", "baz"] - // ## inner-most repetition (first iteration) + // ## innermost repetition (first iteration) // - // `index` is 0 because this is the first inner-most iteration + // `index` is 0 because this is the first innermost iteration // `len` is 2 because there are repetitions, "bar" and "baz" 0, 2, - // ## inner-most repetition (second iteration) + // ## innermost repetition (second iteration) // - // `index` is 1 because this is the second inner-most iteration + // `index` is 1 because this is the second innermost iteration // `len` is 2 because there are repetitions, "bar" and "baz" 1, 2, - // ## outer-most repetition (second iteration) + // ## outermost repetition (second iteration) // // `count` is 2 because of "bar" and "baz", i,e, `$l` has two repetitions, - // `index` is 1 because this is the second outer-most iteration - // `len` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"] + // `index` is 1 because this is the second outermost iteration + // `len` is 2 because there are 2 outermost repetitions, ["foo"] and ["bar", "baz"] 2, 1, 2, // # last count @@ -61,7 +61,7 @@ fn main() { // Based on the above explanation, the following macros should be straightforward - // Grouped from the outer-most to the inner-most + // Grouped from the outermost to the innermost macro_rules! three_nested_count { ( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => { &[ @@ -156,7 +156,7 @@ fn main() { ][..] ); - // Grouped from the outer-most to the inner-most + // Grouped from the outermost to the innermost macro_rules! three_nested_len { ( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => { &[ diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs index 1eda5f5bb6b..78cede92526 100644 --- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs +++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs @@ -10,12 +10,12 @@ macro_rules! curly__no_rhs_dollar__round { macro_rules! curly__no_rhs_dollar__no_round { ( $i:ident ) => { ${ count($i) } }; - //~^ ERROR `count` can not be placed inside the inner-most repetition + //~^ ERROR `count` can not be placed inside the innermost repetition } macro_rules! curly__rhs_dollar__no_round { ( $i:ident ) => { ${ count($i) } }; - //~^ ERROR `count` can not be placed inside the inner-most repetition + //~^ ERROR `count` can not be placed inside the innermost repetition } #[rustfmt::skip] // autoformatters can break a few of the error traces diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr index 2c44ad2e0a4..ce7694ecb1d 100644 --- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr +++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr @@ -196,13 +196,13 @@ error: expected identifier or string literal LL | ( $( $i:ident ),* ) => { ${ {} } }; | ^^ -error: `count` can not be placed inside the inner-most repetition +error: `count` can not be placed inside the innermost repetition --> $DIR/syntax-errors.rs:12:24 | LL | ( $i:ident ) => { ${ count($i) } }; | ^^^^^^^^^^^^^ -error: `count` can not be placed inside the inner-most repetition +error: `count` can not be placed inside the innermost repetition --> $DIR/syntax-errors.rs:17:24 | LL | ( $i:ident ) => { ${ count($i) } }; diff --git a/tests/ui/never_type/issue-52443.stderr b/tests/ui/never_type/issue-52443.stderr index adcff6637b0..2207ceb5033 100644 --- a/tests/ui/never_type/issue-52443.stderr +++ b/tests/ui/never_type/issue-52443.stderr @@ -50,10 +50,6 @@ LL | [(); { for _ in 0usize.. {}; 0}]; note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants --> $DIR/issue-52443.rs:9:21 @@ -62,10 +58,6 @@ LL | [(); { for _ in 0usize.. {}; 0}]; | ^^^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 5 previous errors; 1 warning emitted diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr index 66b57c772d5..e34371be3d2 100644 --- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr +++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr @@ -353,10 +353,6 @@ LL | static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); | = note: calls in statics are limited to constant functions, tuple structs and tuple variants = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 40 previous errors diff --git a/tests/ui/privacy/privacy1.rs b/tests/ui/privacy/privacy1.rs index fcb2108ab5f..31f39601003 100644 --- a/tests/ui/privacy/privacy1.rs +++ b/tests/ui/privacy/privacy1.rs @@ -12,14 +12,14 @@ pub trait Deref { type Target; } -#[lang="receiver"] -pub trait Receiver: Deref {} +#[lang="legacy_receiver"] +pub trait LegacyReceiver: Deref {} impl<'a, T> Deref for &'a T { type Target = T; } -impl<'a, T> Receiver for &'a T {} +impl<'a, T> LegacyReceiver for &'a T {} mod bar { // shouldn't bring in too much diff --git a/tests/ui/repr/repr_align_greater_usize.msp430.stderr b/tests/ui/repr/repr_align_greater_usize.msp430.stderr new file mode 100644 index 00000000000..7c85249c009 --- /dev/null +++ b/tests/ui/repr/repr_align_greater_usize.msp430.stderr @@ -0,0 +1,19 @@ +error[E0589]: alignment must not be greater than `isize::MAX` bytes + --> $DIR/repr_align_greater_usize.rs:21:8 + | +LL | #[repr(align(32768))] + | ^^^^^^^^^^^^ + | + = note: `isize::MAX` is 32767 for the current target + +error[E0589]: alignment must not be greater than `isize::MAX` bytes + --> $DIR/repr_align_greater_usize.rs:24:8 + | +LL | #[repr(align(65536))] + | ^^^^^^^^^^^^ + | + = note: `isize::MAX` is 32767 for the current target + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0589`. diff --git a/tests/ui/repr/repr_align_greater_usize.rs b/tests/ui/repr/repr_align_greater_usize.rs new file mode 100644 index 00000000000..b47320b6d9b --- /dev/null +++ b/tests/ui/repr/repr_align_greater_usize.rs @@ -0,0 +1,25 @@ +//@ revisions: msp430 aarch32 +//@[msp430] needs-llvm-components: msp430 +//@[msp430] compile-flags: --target=msp430-none-elf +//@[aarch32] build-pass +//@[aarch32] needs-llvm-components: arm +//@[aarch32] compile-flags: --target=thumbv7m-none-eabi + +// We should fail to compute alignment for types aligned higher than usize::MAX. +// We can't handle alignments that require all 32 bits, so this only affects 16-bit. + +#![feature(lang_items, no_core)] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +#[repr(align(16384))] +struct Kitten; + +#[repr(align(32768))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX` +struct Cat; + +#[repr(align(65536))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX` +struct BigCat; diff --git a/tests/ui/resolve/issue-39559-2.stderr b/tests/ui/resolve/issue-39559-2.stderr index 7f51357a56f..ea27e7bd250 100644 --- a/tests/ui/resolve/issue-39559-2.stderr +++ b/tests/ui/resolve/issue-39559-2.stderr @@ -5,10 +5,6 @@ LL | let array: [usize; Dim3::dim()] | ^^^^^^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0015]: cannot call non-const fn `::dim` in constants --> $DIR/issue-39559-2.rs:16:15 @@ -17,10 +13,6 @@ LL | = [0; Dim3::dim()]; | ^^^^^^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 2 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr deleted file mode 100644 index 8288c660ce7..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error[E0277]: the trait bound `::Assoc: Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-0.rs:13:5 - | -LL | T::Assoc::func() - | ^^^^^^^^ the trait `Trait` is not implemented for `::Assoc` - | -note: required by a bound in `Trait::func` - --> $DIR/assoc-type-const-bound-usage-0.rs:6:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ required by this bound in `Trait::func` -... -LL | fn func() -> i32; - | ---- required by a bound in this associated function -help: consider further restricting the associated type - | -LL | const fn unqualified() -> i32 where ::Assoc: Trait { - | ++++++++++++++++++++++++++++++++ - -error[E0277]: the trait bound `::Assoc: Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-0.rs:17:5 - | -LL | ::Assoc::func() - | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `::Assoc` - | -note: required by a bound in `Trait::func` - --> $DIR/assoc-type-const-bound-usage-0.rs:6:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ required by this bound in `Trait::func` -... -LL | fn func() -> i32; - | ---- required by a bound in this associated function -help: consider further restricting the associated type - | -LL | const fn qualified() -> i32 where ::Assoc: Trait { - | ++++++++++++++++++++++++++++++++ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr deleted file mode 100644 index 0792d090321..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error[E0277]: the trait bound `::Assoc: Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-1.rs:15:44 - | -LL | fn unqualified() -> Type<{ T::Assoc::func() }> { - | ^^^^^^^^ the trait `Trait` is not implemented for `::Assoc` - | -note: required by a bound in `Trait::func` - --> $DIR/assoc-type-const-bound-usage-1.rs:7:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ required by this bound in `Trait::func` -... -LL | fn func() -> i32; - | ---- required by a bound in this associated function -help: consider further restricting the associated type - | -LL | fn unqualified() -> Type<{ T::Assoc::func() }> where ::Assoc: Trait { - | ++++++++++++++++++++++++++++++++ - -error[E0277]: the trait bound `::Assoc: Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-1.rs:19:42 - | -LL | fn qualified() -> Type<{ ::Assoc::func() }> { - | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `::Assoc` - | -note: required by a bound in `Trait::func` - --> $DIR/assoc-type-const-bound-usage-1.rs:7:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ required by this bound in `Trait::func` -... -LL | fn func() -> i32; - | ---- required by a bound in this associated function -help: consider further restricting the associated type - | -LL | fn qualified() -> Type<{ ::Assoc::func() }> where ::Assoc: Trait { - | ++++++++++++++++++++++++++++++++ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr deleted file mode 100644 index 5d2333d94fe..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0277]: the trait bound `u32: ~const Plus` is not satisfied - --> $DIR/call-const-trait-method-fail.rs:27:5 - | -LL | a.plus(b) - | ^ the trait `Plus` is not implemented for `u32` - | -note: required by a bound in `Plus::plus` - --> $DIR/call-const-trait-method-fail.rs:5:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ required by this bound in `Plus::plus` -LL | pub trait Plus { -LL | fn plus(self, rhs: Self) -> Self; - | ---- required by a bound in this associated function -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement - | -LL | pub const fn add_u32(a: u32, b: u32) -> u32 where u32: Plus { - | +++++++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr deleted file mode 100644 index 5cd274c6c5a..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-in-impl.rs:10:16 - | -LL | impl const MyPartialEq for T { - | ^^^^^^^^^ - -error[E0049]: method `eq` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/call-generic-in-impl.rs:5:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait MyPartialEq { -LL | fn eq(&self, other: &Self) -> bool; - | - expected 0 const parameters - -error[E0015]: cannot call non-const fn `::eq` in constant functions - --> $DIR/call-generic-in-impl.rs:12:9 - | -LL | PartialEq::eq(self, other) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0015, E0049. -For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr deleted file mode 100644 index 57d57dfd5b9..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.stderr +++ /dev/null @@ -1,37 +0,0 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/call-generic-method-chain.rs:6:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` - --> $DIR/call-generic-method-chain.rs:10:12 - | -LL | impl const PartialEq for S { - | ^^^^^^^^^ - | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-chain.rs:19:32 - | -LL | const fn equals_self(t: &T) -> bool { - | ^^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-chain.rs:23:40 - | -LL | const fn equals_self_wrapper(t: &T) -> bool { - | ^^^^^^^^^ - -error: aborting due to 4 previous errors; 1 warning emitted - diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr deleted file mode 100644 index 0088ed2eb13..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.stderr +++ /dev/null @@ -1,37 +0,0 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/call-generic-method-dup-bound.rs:4:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` - --> $DIR/call-generic-method-dup-bound.rs:8:12 - | -LL | impl const PartialEq for S { - | ^^^^^^^^^ - | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-dup-bound.rs:19:44 - | -LL | const fn equals_self(t: &T) -> bool { - | ^^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-dup-bound.rs:26:37 - | -LL | const fn equals_self2(t: &T) -> bool { - | ^^^^^^^^^ - -error: aborting due to 4 previous errors; 1 warning emitted - diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr deleted file mode 100644 index 68c9fc40010..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0277]: the trait bound `S: const Foo` is not satisfied - --> $DIR/call-generic-method-nonconst.rs:25:34 - | -LL | pub const EQ: bool = equals_self(&S); - | ----------- ^^ the trait `Foo` is not implemented for `S` - | | - | required by a bound introduced by this call - | -note: required by a bound in `equals_self` - --> $DIR/call-generic-method-nonconst.rs:18:25 - | -LL | const fn equals_self(t: &T) -> bool { - | ^^^^^^^^^^ required by this bound in `equals_self` -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement - | -LL | pub const EQ: bool where S: Foo = equals_self(&S); - | ++++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr deleted file mode 100644 index 4a6100c3c1a..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.stderr +++ /dev/null @@ -1,31 +0,0 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/call-generic-method-pass.rs:6:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` - --> $DIR/call-generic-method-pass.rs:10:12 - | -LL | impl const PartialEq for S { - | ^^^^^^^^^ - | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-pass.rs:19:32 - | -LL | const fn equals_self(t: &T) -> bool { - | ^^^^^^^^^ - -error: aborting due to 3 previous errors; 1 warning emitted - diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr deleted file mode 100644 index 0809d9c1e1d..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied - --> $DIR/const-default-method-bodies.rs:26:18 - | -LL | NonConstImpl.a(); - | ^ the trait `ConstDefaultFn` is not implemented for `NonConstImpl` - | -note: required by a bound in `ConstDefaultFn::a` - --> $DIR/const-default-method-bodies.rs:5:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ required by this bound in `ConstDefaultFn::a` -... -LL | fn a(self) { - | - required by a bound in this associated function -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement - | -LL | const fn test() where NonConstImpl: ConstDefaultFn { - | ++++++++++++++++++++++++++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.stderr deleted file mode 100644 index be197006f02..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-bound.rs:9:68 - | -LL | const fn foo(res: Result) -> Option where E: ~const Destruct { - | ^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-bound.rs:20:15 - | -LL | T: ~const Destruct, - | ^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-bound.rs:21:15 - | -LL | E: ~const Destruct, - | ^^^^^^^^ - -error[E0493]: destructor of `E` cannot be evaluated at compile-time - --> $DIR/const-drop-bound.rs:12:13 - | -LL | Err(_e) => None, - | ^^ the destructor for this type cannot be evaluated in constant functions - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs deleted file mode 100644 index b3087349e4d..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs +++ /dev/null @@ -1,136 +0,0 @@ -//@ known-bug: #110395 -// FIXME(effects) 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) - where - F: const FnOnce<()>, - { - } - - const fn foo() {} - - is_const_fn(foo); -} - -/// ---------------------------------------------------------------------- /// -/// Const fn trait definitions - -#[const_trait] -#[lang = "fn"] -#[rustc_paren_sugar] -trait Fn: ~const FnMut { - extern "rust-call" fn call(&self, args: Args) -> Self::Output; -} - -#[const_trait] -#[lang = "fn_mut"] -#[rustc_paren_sugar] -trait FnMut: ~const FnOnce { - extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; -} - -#[const_trait] -#[lang = "fn_once"] -#[rustc_paren_sugar] -trait FnOnce { - #[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 = "receiver"] -trait Receiver {} - -impl Receiver for &T {} - -impl Receiver for &mut T {} - -#[stable(feature = "minicore", since = "1.0.0")] -pub mod effects { - use super::Sized; - - #[lang = "EffectsNoRuntime"] - #[stable(feature = "minicore", since = "1.0.0")] - pub struct NoRuntime; - #[lang = "EffectsMaybe"] - #[stable(feature = "minicore", since = "1.0.0")] - pub struct Maybe; - #[lang = "EffectsRuntime"] - #[stable(feature = "minicore", since = "1.0.0")] - pub struct Runtime; - - #[lang = "EffectsCompat"] - #[stable(feature = "minicore", since = "1.0.0")] - pub trait Compat<#[rustc_runtime] const RUNTIME: bool> {} - - #[stable(feature = "minicore", since = "1.0.0")] - impl Compat for NoRuntime {} - #[stable(feature = "minicore", since = "1.0.0")] - impl Compat for Runtime {} - #[stable(feature = "minicore", since = "1.0.0")] - impl<#[rustc_runtime] const RUNTIME: bool> Compat for Maybe {} - - #[lang = "EffectsTyCompat"] - #[marker] - #[stable(feature = "minicore", since = "1.0.0")] - pub trait TyCompat {} - - #[stable(feature = "minicore", since = "1.0.0")] - impl TyCompat for T {} - #[stable(feature = "minicore", since = "1.0.0")] - impl TyCompat for Maybe {} - #[stable(feature = "minicore", since = "1.0.0")] - impl TyCompat for T {} - - #[lang = "EffectsIntersection"] - #[stable(feature = "minicore", since = "1.0.0")] - pub trait Intersection { - #[lang = "EffectsIntersectionOutput"] - #[stable(feature = "minicore", since = "1.0.0")] - type Output: ?Sized; - } -} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr deleted file mode 100644 index 9eda9d98ec5..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0277]: the trait bound `fn() {foo}: const FnOnce()` is not satisfied - --> $DIR/const-fns-are-early-bound.rs:31:17 - | -LL | is_const_fn(foo); - | ----------- ^^^ the trait `FnOnce()` is not implemented for fn item `fn() {foo}` - | | - | required by a bound introduced by this call - | -note: required by a bound in `is_const_fn` - --> $DIR/const-fns-are-early-bound.rs:25:12 - | -LL | fn is_const_fn(_: F) - | ----------- required by a bound in this function -LL | where -LL | F: const FnOnce<()>, - | ^^^^^^^^^^^^^^^^ required by this bound in `is_const_fn` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.rs deleted file mode 100644 index bd6f476f879..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #110395 - -#![feature(const_trait_impl, effects)] - -pub trait A {} -// FIXME ~^ HELP: mark `A` as const - -impl const A for () {} -// FIXME ~^ ERROR: const `impl` for trait `A` which is not marked with `#[const_trait]` - -fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr deleted file mode 100644 index 2a030369093..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-requires-const-trait.stderr +++ /dev/null @@ -1,28 +0,0 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/const-impl-requires-const-trait.rs:3:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error: const `impl` for trait `A` which is not marked with `#[const_trait]` - --> $DIR/const-impl-requires-const-trait.rs:8:12 - | -LL | pub trait A {} - | - help: mark `A` as const: `#[const_trait]` -... -LL | impl const A for () {} - | ^ - | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error: aborting due to 2 previous errors; 1 warning emitted - diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr deleted file mode 100644 index 1040af7541c..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr +++ /dev/null @@ -1,249 +0,0 @@ -error[E0635]: unknown feature `const_cmp` - --> $DIR/const-impl-trait.rs:8:5 - | -LL | const_cmp, - | ^^^^^^^^^ - -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:13:30 - | -LL | const fn cmp(a: &impl ~const PartialEq) -> bool { - | ^^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:17:30 - | -LL | const fn wrap(x: impl ~const PartialEq + ~const Destruct) - | ^^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:17:49 - | -LL | const fn wrap(x: impl ~const PartialEq + ~const Destruct) - | ^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:18:20 - | -LL | -> impl ~const PartialEq + ~const Destruct - | ^^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:18:39 - | -LL | -> impl ~const PartialEq + ~const Destruct - | ^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:18:20 - | -LL | -> impl ~const PartialEq + ~const Destruct - | ^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:18:39 - | -LL | -> impl ~const PartialEq + ~const Destruct - | ^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:29 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:48 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:29:29 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { - | ^^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:29:48 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { - | ^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:29:29 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { - | ^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:29:48 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { - | ^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:50:41 - | -LL | const fn apit(_: impl ~const T + ~const Destruct) {} - | ^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:54:73 - | -LL | const fn apit_assoc_bound(_: impl IntoIterator + ~const Destruct) {} - | ^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:29 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:48 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:29 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:48 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:29 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:48 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time - --> $DIR/const-impl-trait.rs:37:26 - | -LL | assert!(wrap(123) == wrap(123)); - | ^^^^^^^^^- value is dropped here - | | - | the destructor for this type cannot be evaluated in constants - -error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time - --> $DIR/const-impl-trait.rs:37:26 - | -LL | assert!(wrap(123) == wrap(123)); - | ^^^^^^^^^- value is dropped here - | | - | the destructor for this type cannot be evaluated in constants - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time - --> $DIR/const-impl-trait.rs:37:13 - | -LL | assert!(wrap(123) == wrap(123)); - | ^^^^^^^^^ - value is dropped here - | | - | the destructor for this type cannot be evaluated in constants - -error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time - --> $DIR/const-impl-trait.rs:37:13 - | -LL | assert!(wrap(123) == wrap(123)); - | ^^^^^^^^^ - value is dropped here - | | - | the destructor for this type cannot be evaluated in constants - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time - --> $DIR/const-impl-trait.rs:38:26 - | -LL | assert!(wrap(123) != wrap(456)); - | ^^^^^^^^^- value is dropped here - | | - | the destructor for this type cannot be evaluated in constants - -error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time - --> $DIR/const-impl-trait.rs:38:26 - | -LL | assert!(wrap(123) != wrap(456)); - | ^^^^^^^^^- value is dropped here - | | - | the destructor for this type cannot be evaluated in constants - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time - --> $DIR/const-impl-trait.rs:38:13 - | -LL | assert!(wrap(123) != wrap(456)); - | ^^^^^^^^^ - value is dropped here - | | - | the destructor for this type cannot be evaluated in constants - -error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time - --> $DIR/const-impl-trait.rs:38:13 - | -LL | assert!(wrap(123) != wrap(456)); - | ^^^^^^^^^ - value is dropped here - | | - | the destructor for this type cannot be evaluated in constants - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0493]: destructor of `impl ~const T + ~const Destruct` cannot be evaluated at compile-time - --> $DIR/const-impl-trait.rs:50:15 - | -LL | const fn apit(_: impl ~const T + ~const Destruct) {} - | ^ - value is dropped here - | | - | the destructor for this type cannot be evaluated in constant functions - -error[E0493]: destructor of `impl IntoIterator + ~const Destruct` cannot be evaluated at compile-time - --> $DIR/const-impl-trait.rs:54:27 - | -LL | const fn apit_assoc_bound(_: impl IntoIterator + ~const Destruct) {} - | ^ - value is dropped here - | | - | the destructor for this type cannot be evaluated in constant functions - -error: aborting due to 33 previous errors - -Some errors have detailed explanations: E0493, E0635. -For more information about an error, try `rustc --explain E0493`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr deleted file mode 100644 index a34bae843c8..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied - --> $DIR/cross-crate.rs:19:14 - | -LL | NonConst.func(); - | ^^^^ the trait `cross_crate::MyTrait` is not implemented for `cross_crate::NonConst` - | -note: required by a bound in `func` - --> $DIR/auxiliary/cross-crate.rs:5:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ required by this bound in `MyTrait::func` -... -LL | fn func(self); - | ---- required by a bound in this associated function -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement - | -LL | const fn const_context() where cross_crate::NonConst: cross_crate::MyTrait { - | +++++++++++++++++++++++++++++++++++++++++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr deleted file mode 100644 index d0f22c0b9b6..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0277]: the trait bound `(): ~const Tr` is not satisfied - --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12 - | -LL | ().a() - | ^ the trait `Tr` is not implemented for `()` - | -note: required by a bound in `Tr::a` - --> $DIR/default-method-body-is-const-same-trait-ck.rs:5:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ required by this bound in `Tr::a` -LL | pub trait Tr { -LL | fn a(&self) {} - | - required by a bound in this associated function -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement - | -LL | pub trait Tr where (): Tr { - | ++++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr deleted file mode 100644 index 823ab69df9c..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: the compiler unexpectedly panicked. this is a bug. - -query stack during panic: -#0 [check_well_formed] checking that `` is well-formed -#1 [check_mod_type_wf] checking that types are well-formed in top-level module -end of query stack - -error: the compiler unexpectedly panicked. this is a bug. - -query stack during panic: -#0 [check_well_formed] checking that `drop` is well-formed -#1 [check_mod_type_wf] checking that types are well-formed in top-level module -end of query stack diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.stderr deleted file mode 100644 index 598129d8694..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.stderr +++ /dev/null @@ -1,27 +0,0 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/hir-const-check.rs:3:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 for more information - = note: `#[warn(incomplete_features)]` on by default - -error[E0658]: `?` is not allowed in a `const fn` - --> $DIR/hir-const-check.rs:12:9 - | -LL | Some(())?; - | ^^^^^^^^^ - | - = note: see issue #74935 for more information - = help: add `#![feature(const_try)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error: aborting due to 2 previous errors; 1 warning emitted - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.stderr deleted file mode 100644 index c937430a1ca..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/ice-123664-unexpected-bound-var.rs:4:34 - | -LL | const fn with_positive() {} - | ^^^^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr deleted file mode 100644 index de4783bdb3f..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/non-const-op-in-closure-in-const.rs:10:51 - | -LL | impl const Convert for A where B: ~const From { - | ^^^^^^^ - -error[E0049]: method `to` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/non-const-op-in-closure-in-const.rs:5:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Convert { -LL | fn to(self) -> T; - | - expected 0 const parameters - -error[E0015]: cannot call non-const fn `>::from` in constant functions - --> $DIR/non-const-op-in-closure-in-const.rs:12:9 - | -LL | B::from(self) - | ^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0015, E0049. -For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr deleted file mode 100644 index 7643697874f..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr +++ /dev/null @@ -1,41 +0,0 @@ -error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-default-bound-non-const-specialized-bound.rs:16:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Bar { -LL | fn bar(); - | - expected 0 const parameters - -error: cannot specialize on const impl with non-const impl - --> $DIR/const-default-bound-non-const-specialized-bound.rs:28:1 - | -LL | / impl Bar for T -LL | | where -LL | | T: Foo, //FIXME ~ ERROR missing `~const` qualifier -LL | | T: Specialize, - | |__________________^ - -error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-default-bound-non-const-specialized-bound.rs:36:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Baz { -LL | fn baz(); - | - expected 0 const parameters - -error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-default-bound-non-const-specialized-bound.rs:36:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Baz { -LL | fn baz(); - | - expected 0 const parameters - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr deleted file mode 100644 index 9b2ae8d739c..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-default-const-specialized.rs:10:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Value { -LL | fn value() -> u32; - | - expected 0 const parameters - -error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-default-const-specialized.rs:10:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Value { -LL | fn value() -> u32; - | - expected 0 const parameters - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0015]: cannot call non-const fn `::value` in constant functions - --> $DIR/const-default-const-specialized.rs:16:5 - | -LL | T::value() - | ^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0015, E0049. -For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr deleted file mode 100644 index 18a25045f4b..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/default-keyword.rs:7:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Foo { -LL | fn foo(); - | - expected 0 const parameters - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr deleted file mode 100644 index ecdc7b930e6..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/issue-95186-specialize-on-tilde-const.rs:14:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Foo { -LL | fn foo(); - | - expected 0 const parameters - -error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/issue-95186-specialize-on-tilde-const.rs:14:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Foo { -LL | fn foo(); - | - expected 0 const parameters - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/issue-95186-specialize-on-tilde-const.rs:30:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Bar { -LL | fn bar() {} - | - expected 0 const parameters - -error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/issue-95186-specialize-on-tilde-const.rs:30:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Bar { -LL | fn bar() {} - | - expected 0 const parameters - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr deleted file mode 100644 index 6679bb46537..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/issue-95187-same-trait-bound-different-constness.rs:18:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Bar { -LL | fn bar(); - | - expected 0 const parameters - -error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/issue-95187-same-trait-bound-different-constness.rs:18:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Bar { -LL | fn bar(); - | - expected 0 const parameters - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/issue-95187-same-trait-bound-different-constness.rs:38:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Baz { -LL | fn baz(); - | - expected 0 const parameters - -error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/issue-95187-same-trait-bound-different-constness.rs:38:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Baz { -LL | fn baz(); - | - expected 0 const parameters - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr deleted file mode 100644 index 7f363922947..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/non-const-default-const-specialized.rs:9:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Value { -LL | fn value() -> u32; - | - expected 0 const parameters - -error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/non-const-default-const-specialized.rs:9:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Value { -LL | fn value() -> u32; - | - expected 0 const parameters - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0015]: cannot call non-const fn `::value` in constant functions - --> $DIR/non-const-default-const-specialized.rs:15:5 - | -LL | T::value() - | ^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0015, E0049. -For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr deleted file mode 100644 index bf273f349b4..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/specializing-constness-2.rs:9:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | pub trait A { -LL | fn a() -> u32; - | - expected 0 const parameters - -error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/specializing-constness-2.rs:9:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | pub trait A { -LL | fn a() -> u32; - | - expected 0 const parameters - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0015]: cannot call non-const fn `::a` in constant functions - --> $DIR/specializing-constness-2.rs:27:5 - | -LL | ::a(); - | ^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0015, E0049. -For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.stable.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.stable.stderr deleted file mode 100644 index 6c07a253f5b..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.stable.stderr +++ /dev/null @@ -1,49 +0,0 @@ -error: trait implementations cannot be const stable yet - --> $DIR/staged-api.rs:21:1 - | -LL | / impl const MyTrait for Foo { -LL | | -LL | | fn func() {} -LL | | } - | |_^ - | - = note: see issue #67792 for more information - -error: function has missing const stability attribute - --> $DIR/staged-api.rs:43:1 - | -LL | / pub const fn const_context_not_const_stable() { -LL | | -LL | | Unstable::func(); -LL | | -... | -LL | | // ^ fails, because the `foo` feature is not active -LL | | } - | |_^ - -error: `::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:34:5 - | -LL | Unstable::func(); - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(unstable)]` to the crate attributes to enable - -error: `::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:45:5 - | -LL | Unstable::func(); - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(unstable)]` to the crate attributes to enable - -error: `::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:55:5 - | -LL | Unstable::func(); - | ^^^^^^^^^^^^^^^^ - | - = help: const-stable functions can only call other const-stable functions - -error: aborting due to 5 previous errors - diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr deleted file mode 100644 index 1c772f13dd5..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.unstable.stderr +++ /dev/null @@ -1,42 +0,0 @@ -error: `::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:36:5 - | -LL | Foo::func(); - | ^^^^^^^^^^^ - | - = help: add `#![feature(foo)]` to the crate attributes to enable - -error: `::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:47:5 - | -LL | Foo::func(); - | ^^^^^^^^^^^ - | - = help: add `#![feature(foo)]` to the crate attributes to enable - -error: `::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:55:5 - | -LL | Unstable::func(); - | ^^^^^^^^^^^^^^^^ - | - = help: const-stable functions can only call other const-stable functions - -error: `::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:57:5 - | -LL | Foo::func(); - | ^^^^^^^^^^^ - | - = help: const-stable functions can only call other const-stable functions - -error: `const_context_not_const_stable` is not yet stable as a const fn - --> $DIR/staged-api.rs:59:5 - | -LL | const_context_not_const_stable() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: const-stable functions can only call other const-stable functions - -error: aborting due to 5 previous errors - diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr deleted file mode 100644 index 029c3b4bde3..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:12:19 - | -LL | trait Bar: ~const Foo {} - | ^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:12:19 - | -LL | trait Bar: ~const Foo {} - | ^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:12:19 - | -LL | trait Bar: ~const Foo {} - | ^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 3 previous errors - diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr deleted file mode 100644 index 873c57ec71f..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error: `~const` is not allowed here - --> $DIR/super-traits-fail-2.rs:12:12 - | -LL | trait Bar: ~const Foo {} - | ^^^^^^ - | -note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds - --> $DIR/super-traits-fail-2.rs:12:1 - | -LL | trait Bar: ~const Foo {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `T: ~const Foo` is not satisfied - --> $DIR/super-traits-fail-2.rs:19:7 - | -LL | x.a(); - | ^ the trait `Foo` is not implemented for `T` - | -note: required by a bound in `Foo::a` - --> $DIR/super-traits-fail-2.rs:6:25 - | -LL | #[cfg_attr(any(yy, yn), const_trait)] - | ^^^^^^^^^^^ required by this bound in `Foo::a` -LL | trait Foo { -LL | fn a(&self); - | - required by a bound in this associated function -help: consider further restricting this bound - | -LL | const fn foo(x: &T) { - | +++++ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr deleted file mode 100644 index bea3aea2f3a..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0277]: the trait bound `T: ~const Foo` is not satisfied - --> $DIR/super-traits-fail-2.rs:19:7 - | -LL | x.a(); - | ^ the trait `Foo` is not implemented for `T` - | -note: required by a bound in `Foo::a` - --> $DIR/super-traits-fail-2.rs:6:25 - | -LL | #[cfg_attr(any(yy, yn), const_trait)] - | ^^^^^^^^^^^ required by this bound in `Foo::a` -LL | trait Foo { -LL | fn a(&self); - | - required by a bound in this associated function -help: consider further restricting this bound - | -LL | const fn foo(x: &T) { - | +++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr deleted file mode 100644 index 3f6dfa7b008..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:14:19 - | -LL | trait Bar: ~const Foo {} - | ^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:14:19 - | -LL | trait Bar: ~const Foo {} - | ^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:14:19 - | -LL | trait Bar: ~const Foo {} - | ^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 3 previous errors - diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr deleted file mode 100644 index bbc95948a59..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr +++ /dev/null @@ -1,40 +0,0 @@ -error: `~const` is not allowed here - --> $DIR/super-traits-fail-3.rs:14:12 - | -LL | trait Bar: ~const Foo {} - | ^^^^^^ - | -note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds - --> $DIR/super-traits-fail-3.rs:14:1 - | -LL | trait Bar: ~const Foo {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:20:24 - | -LL | const fn foo(x: &T) { - | ^^^ - -error[E0277]: the trait bound `T: ~const Foo` is not satisfied - --> $DIR/super-traits-fail-3.rs:22:7 - | -LL | x.a(); - | ^ the trait `Foo` is not implemented for `T` - | -note: required by a bound in `Foo::a` - --> $DIR/super-traits-fail-3.rs:8:25 - | -LL | #[cfg_attr(any(yy, yn), const_trait)] - | ^^^^^^^^^^^ required by this bound in `Foo::a` -LL | trait Foo { -LL | fn a(&self); - | - required by a bound in this associated function -help: consider further restricting this bound - | -LL | const fn foo(x: &T) { - | +++++ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr deleted file mode 100644 index 3870f0f722f..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0277]: the trait bound `Bar::{synthetic#0}: TyCompat` is not satisfied - --> $DIR/super-traits-fail.rs:19:12 - | -LL | impl const Bar for S {} - | ^^^ the trait `TyCompat` is not implemented for `Bar::{synthetic#0}`, which is required by `S: Bar` - | - = help: the trait `Bar` is implemented for `S` -note: required for `S` to implement `Bar` - --> $DIR/super-traits-fail.rs:12:7 - | -LL | trait Bar: ~const Foo {} - | ^^^ - -error[E0277]: the trait bound `Maybe: TyCompat` is not satisfied - | -note: required by a bound in `Bar::{synthetic#0}` - --> $DIR/super-traits-fail.rs:12:12 - | -LL | trait Bar: ~const Foo {} - | ^^^^^^^^^^ required by this bound in `Bar::{synthetic#0}` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr deleted file mode 100644 index eaa981ec744..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr +++ /dev/null @@ -1,52 +0,0 @@ -error[E0277]: the trait bound `T: Foo` is not satisfied - --> $DIR/trait-where-clause-const.rs:22:5 - | -LL | T::b(); - | ^ the trait `Foo` is not implemented for `T` - | -note: required by a bound in `Foo::b` - --> $DIR/trait-where-clause-const.rs:13:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ required by this bound in `Foo::b` -... -LL | fn b() where Self: ~const Bar; - | - required by a bound in this associated function - -error[E0308]: mismatched types - --> $DIR/trait-where-clause-const.rs:22:5 - | -LL | T::b(); - | ^^^^^^ expected `host`, found `true` - | - = note: expected constant `host` - found constant `true` - -error[E0277]: the trait bound `T: Foo` is not satisfied - --> $DIR/trait-where-clause-const.rs:25:5 - | -LL | T::c::(); - | ^ the trait `Foo` is not implemented for `T` - | -note: required by a bound in `Foo::c` - --> $DIR/trait-where-clause-const.rs:13:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ required by this bound in `Foo::c` -... -LL | fn c(); - | - required by a bound in this associated function - -error[E0308]: mismatched types - --> $DIR/trait-where-clause-const.rs:25:5 - | -LL | T::c::(); - | ^^^^^^^^^^^ expected `host`, found `true` - | - = note: expected constant `host` - found constant `true` - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0277, E0308. -For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr deleted file mode 100644 index 848aa68689b..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed - --> $DIR/unsatisfied-const-trait-bound.rs:5:39 - | -LL | #![feature(const_trait_impl, effects, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = help: remove one of these features - -error[E0308]: mismatched types - --> $DIR/unsatisfied-const-trait-bound.rs:29:37 - | -LL | fn accept0(_: Container<{ T::make() }>) {} - | ^^^^^^^^^ expected `false`, found `true` - | - = note: expected constant `false` - found constant `true` - -error[E0308]: mismatched types - --> $DIR/unsatisfied-const-trait-bound.rs:33:50 - | -LL | const fn accept1(_: Container<{ T::make() }>) {} - | ^^^^^^^^^ expected `false`, found `host` - | - = note: expected constant `false` - found constant `host` - -error[E0277]: the trait bound `Ty: const Trait` is not satisfied - --> $DIR/unsatisfied-const-trait-bound.rs:22:15 - | -LL | require::(); - | ^^ the trait `Trait` is not implemented for `Ty` - | -note: required by a bound in `require` - --> $DIR/unsatisfied-const-trait-bound.rs:8:15 - | -LL | fn require() {} - | ^^^^^^^^^^^ required by this bound in `require` -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement - | -LL | fn main() where Ty: Trait { - | +++++++++++++++ - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0277, E0308. -For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr index 505b0a173fa..6ae60e7af47 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr @@ -5,10 +5,6 @@ LL | self.0 | ^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0493]: destructor of `R` cannot be evaluated at compile-time --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:43 diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr index 643f1de3e8d..40ac350980e 100644 --- a/tests/ui/specialization/const_trait_impl.stderr +++ b/tests/ui/specialization/const_trait_impl.stderr @@ -1,69 +1,42 @@ -error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const_trait_impl.rs:6:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | pub unsafe trait Sup { -LL | fn foo() -> u32; - | - expected 0 const parameters - -error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const_trait_impl.rs:6:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | pub unsafe trait Sup { -LL | fn foo() -> u32; - | - expected 0 const parameters - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const_trait_impl.rs:34:16 + --> $DIR/const_trait_impl.rs:34:9 | LL | impl const A for T { - | ^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const_trait_impl.rs:40:16 + --> $DIR/const_trait_impl.rs:40:9 | LL | impl const A for T { - | ^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const_trait_impl.rs:46:16 + --> $DIR/const_trait_impl.rs:46:9 | LL | impl const A for T { - | ^^^^^^^ + | ^^^^^^ -error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const_trait_impl.rs:29:1 +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const_trait_impl.rs:40:9 | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | pub trait A { -LL | fn a() -> u32; - | - expected 0 const parameters - -error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const_trait_impl.rs:29:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | pub trait A { -LL | fn a() -> u32; - | - expected 0 const parameters +LL | impl const A for T { + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const_trait_impl.rs:29:1 +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const_trait_impl.rs:34:9 | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | pub trait A { -LL | fn a() -> u32; - | - expected 0 const parameters +LL | impl const A for T { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const_trait_impl.rs:46:9 + | +LL | impl const A for T { + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -115,7 +88,6 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 12 previous errors +error: aborting due to 10 previous errors -Some errors have detailed explanations: E0015, E0049. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs index 4089ec72885..6d6d793c62b 100644 --- a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs +++ b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs @@ -14,4 +14,3 @@ pub const fn foobar() -> u32 { } const VAR: u32 = foobar(); -//~^ ERROR: `foobar` is not yet stable as a const fn diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr index 918d6ebf992..232de41c769 100644 --- a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr +++ b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr @@ -4,13 +4,5 @@ error: feature `const_bar` implying `const_foobar` does not exist LL | #[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_bar")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `foobar` is not yet stable as a const fn - --> $DIR/const-stability-attribute-implies-missing.rs:16:18 - | -LL | const VAR: u32 = foobar(); - | ^^^^^^^^ - | - = help: add `#![feature(const_foobar)]` to the crate attributes to enable - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/stability-attribute/missing-const-stability.rs b/tests/ui/stability-attribute/missing-const-stability.rs index 82da18cc9ac..f1139652550 100644 --- a/tests/ui/stability-attribute/missing-const-stability.rs +++ b/tests/ui/stability-attribute/missing-const-stability.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Znext-solver #![feature(staged_api)] -#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete +#![feature(const_trait_impl, effects, rustc_attrs, intrinsics)] //~ WARN the feature `effects` is incomplete #![stable(feature = "stable", since = "1.0.0")] #[stable(feature = "stable", since = "1.0.0")] @@ -31,4 +31,15 @@ impl const Bar for Foo { fn fun() {} } +#[stable(feature = "stable", since = "1.0.0")] +#[rustc_intrinsic] +pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } +//~^ ERROR function has missing const stability attribute + +extern "rust-intrinsic" { + #[stable(feature = "stable", since = "1.0.0")] + #[rustc_const_stable_indirect] + pub fn min_align_of_val(x: *const T) -> usize; +} + fn main() {} diff --git a/tests/ui/stability-attribute/missing-const-stability.stderr b/tests/ui/stability-attribute/missing-const-stability.stderr index adf60c38611..e62a8b88261 100644 --- a/tests/ui/stability-attribute/missing-const-stability.stderr +++ b/tests/ui/stability-attribute/missing-const-stability.stderr @@ -1,7 +1,7 @@ warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/missing-const-stability.rs:3:30 | -LL | #![feature(const_trait_impl, effects)] +LL | #![feature(const_trait_impl, effects, rustc_attrs, intrinsics)] | ^^^^^^^ | = note: see issue #102090 for more information @@ -22,11 +22,17 @@ LL | | fn fun() {} LL | | } | |_^ +error: function has missing const stability attribute + --> $DIR/missing-const-stability.rs:36:1 + | +LL | pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: associated function has missing const stability attribute --> $DIR/missing-const-stability.rs:16:5 | LL | pub const fn foo() {} | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 4 previous errors; 1 warning emitted diff --git a/tests/ui/static/raw-ref-deref-with-unsafe.rs b/tests/ui/static/raw-ref-deref-with-unsafe.rs index 0974948b3a0..5beed697179 100644 --- a/tests/ui/static/raw-ref-deref-with-unsafe.rs +++ b/tests/ui/static/raw-ref-deref-with-unsafe.rs @@ -1,13 +1,14 @@ //@ check-pass use std::ptr; -// This code should remain unsafe because of the two unsafe operations here, -// even if in a hypothetical future we deem all &raw (const|mut) *ptr exprs safe. - static mut BYTE: u8 = 0; static mut BYTE_PTR: *mut u8 = ptr::addr_of_mut!(BYTE); + +// This code should remain unsafe because reading from a static mut is *always* unsafe. + // An unsafe static's ident is a place expression in its own right, so despite the above being safe -// (it's fine to create raw refs to places!) the following derefs the ptr before creating its ref +// (it's fine to create raw refs to places!) the following *reads* from the static mut place before +// derefing it explicitly with the `*` below. static mut DEREF_BYTE_PTR: *mut u8 = unsafe { ptr::addr_of_mut!(*BYTE_PTR) }; fn main() { diff --git a/tests/ui/static/raw-ref-deref-without-unsafe.rs b/tests/ui/static/raw-ref-deref-without-unsafe.rs index 289e55b7638..97d08c815bf 100644 --- a/tests/ui/static/raw-ref-deref-without-unsafe.rs +++ b/tests/ui/static/raw-ref-deref-without-unsafe.rs @@ -1,15 +1,14 @@ use std::ptr; -// This code should remain unsafe because of the two unsafe operations here, -// even if in a hypothetical future we deem all &raw (const|mut) *ptr exprs safe. - static mut BYTE: u8 = 0; static mut BYTE_PTR: *mut u8 = ptr::addr_of_mut!(BYTE); + +// This code should remain unsafe because reading from a static mut is *always* unsafe. + // An unsafe static's ident is a place expression in its own right, so despite the above being safe // (it's fine to create raw refs to places!) the following derefs the ptr before creating its ref! static mut DEREF_BYTE_PTR: *mut u8 = ptr::addr_of_mut!(*BYTE_PTR); //~^ ERROR: use of mutable static -//~| ERROR: dereference of raw pointer fn main() { let _ = unsafe { DEREF_BYTE_PTR }; diff --git a/tests/ui/static/raw-ref-deref-without-unsafe.stderr b/tests/ui/static/raw-ref-deref-without-unsafe.stderr index f034499bbb5..b9c294e5c1f 100644 --- a/tests/ui/static/raw-ref-deref-without-unsafe.stderr +++ b/tests/ui/static/raw-ref-deref-without-unsafe.stderr @@ -1,11 +1,3 @@ -error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/raw-ref-deref-without-unsafe.rs:10:56 - | -LL | static mut DEREF_BYTE_PTR: *mut u8 = ptr::addr_of_mut!(*BYTE_PTR); - | ^^^^^^^^^ dereference of raw pointer - | - = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior - error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/raw-ref-deref-without-unsafe.rs:10:57 | @@ -14,6 +6,6 @@ LL | static mut DEREF_BYTE_PTR: *mut u8 = ptr::addr_of_mut!(*BYTE_PTR); | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/statics/check-values-constraints.stderr b/tests/ui/statics/check-values-constraints.stderr index 24763c175fc..b4ee34530d3 100644 --- a/tests/ui/statics/check-values-constraints.stderr +++ b/tests/ui/statics/check-values-constraints.stderr @@ -37,10 +37,6 @@ LL | field2: SafeEnum::Variant4("str".to_string()), | = note: calls in statics are limited to constant functions, tuple structs and tuple variants = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0010]: allocations are not allowed in statics --> $DIR/check-values-constraints.rs:96:5 diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index 3a2d4df3bee..bd0c8cbc3b1 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -141,10 +141,10 @@ hir-stats FnDecl 120 ( 1.3%) 3 40 hir-stats Attribute 128 ( 1.4%) 4 32 hir-stats GenericArgs 144 ( 1.6%) 3 48 hir-stats Variant 144 ( 1.6%) 2 72 -hir-stats GenericBound 192 ( 2.1%) 4 48 -hir-stats - Trait 192 ( 2.1%) 4 hir-stats WherePredicate 192 ( 2.1%) 3 64 hir-stats - BoundPredicate 192 ( 2.1%) 3 +hir-stats GenericBound 256 ( 2.8%) 4 64 +hir-stats - Trait 256 ( 2.8%) 4 hir-stats Block 288 ( 3.2%) 6 48 hir-stats GenericParam 360 ( 4.0%) 5 72 hir-stats Pat 360 ( 4.0%) 5 72 @@ -155,15 +155,15 @@ hir-stats Generics 560 ( 6.2%) 10 56 hir-stats Ty 720 ( 8.0%) 15 48 hir-stats - Ref 48 ( 0.5%) 1 hir-stats - Ptr 48 ( 0.5%) 1 -hir-stats - Path 624 ( 7.0%) 13 -hir-stats Expr 768 ( 8.6%) 12 64 +hir-stats - Path 624 ( 6.9%) 13 +hir-stats Expr 768 ( 8.5%) 12 64 hir-stats - Path 64 ( 0.7%) 1 hir-stats - Match 64 ( 0.7%) 1 hir-stats - Struct 64 ( 0.7%) 1 hir-stats - InlineAsm 64 ( 0.7%) 1 hir-stats - Lit 128 ( 1.4%) 2 hir-stats - Block 384 ( 4.3%) 6 -hir-stats Item 968 (10.8%) 11 88 +hir-stats Item 968 (10.7%) 11 88 hir-stats - Enum 88 ( 1.0%) 1 hir-stats - Trait 88 ( 1.0%) 1 hir-stats - Impl 88 ( 1.0%) 1 @@ -171,8 +171,8 @@ hir-stats - ExternCrate 88 ( 1.0%) 1 hir-stats - ForeignMod 88 ( 1.0%) 1 hir-stats - Fn 176 ( 2.0%) 2 hir-stats - Use 352 ( 3.9%) 4 -hir-stats Path 1_240 (13.8%) 31 40 -hir-stats PathSegment 1_920 (21.4%) 40 48 +hir-stats Path 1_240 (13.7%) 31 40 +hir-stats PathSegment 1_920 (21.3%) 40 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_960 +hir-stats Total 9_024 hir-stats diff --git a/tests/ui/target-feature/feature-hierarchy.rs b/tests/ui/target-feature/feature-hierarchy.rs index 4cf9112810c..7f14d700ecb 100644 --- a/tests/ui/target-feature/feature-hierarchy.rs +++ b/tests/ui/target-feature/feature-hierarchy.rs @@ -19,6 +19,7 @@ trait Copy {} impl Copy for bool {} extern "rust-intrinsic" { + #[stable(feature = "test", since = "1.0.0")] #[rustc_const_stable(feature = "test", since = "1.0.0")] fn unreachable() -> !; } diff --git a/tests/ui/target-feature/no-llvm-leaks.rs b/tests/ui/target-feature/no-llvm-leaks.rs index 9f5dec4447f..f0c887bc1e0 100644 --- a/tests/ui/target-feature/no-llvm-leaks.rs +++ b/tests/ui/target-feature/no-llvm-leaks.rs @@ -17,6 +17,7 @@ trait Copy {} impl Copy for bool {} extern "rust-intrinsic" { + #[stable(feature = "test", since = "1.0.0")] #[rustc_const_stable(feature = "test", since = "1.0.0")] fn unreachable() -> !; } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs similarity index 87% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.rs rename to tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs index 4399ae2d1be..bbf88917905 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.rs +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs @@ -1,4 +1,5 @@ -//@ known-bug: unknown +//@ compile-flags: -Znext-solver +//@ check-pass #![allow(incomplete_features)] #![feature(const_trait_impl, effects)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs similarity index 92% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.rs rename to tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs index 8a1bf75f87e..04ad94556c3 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.rs +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs @@ -1,5 +1,5 @@ +//@ compile-flags: -Znext-solver //@ known-bug: unknown -// FIXME(effects) #![feature(const_trait_impl, effects, generic_const_exprs)] #![allow(incomplete_features)] diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr new file mode 100644 index 00000000000..b8768bd5541 --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr @@ -0,0 +1,35 @@ +error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed + --> $DIR/assoc-type-const-bound-usage-1.rs:4:39 + | +LL | #![feature(const_trait_impl, effects, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: remove one of these features + +error[E0284]: type annotations needed: cannot normalize `unqualified::{constant#0}` + --> $DIR/assoc-type-const-bound-usage-1.rs:15:37 + | +LL | fn unqualified() -> Type<{ T::Assoc::func() }> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `unqualified::{constant#0}` + +error[E0284]: type annotations needed: cannot normalize `qualified::{constant#0}` + --> $DIR/assoc-type-const-bound-usage-1.rs:19:35 + | +LL | fn qualified() -> Type<{ ::Assoc::func() }> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `qualified::{constant#0}` + +error[E0284]: type annotations needed: cannot normalize `unqualified::{constant#0}` + --> $DIR/assoc-type-const-bound-usage-1.rs:16:5 + | +LL | Type + | ^^^^ cannot normalize `unqualified::{constant#0}` + +error[E0284]: type annotations needed: cannot normalize `qualified::{constant#0}` + --> $DIR/assoc-type-const-bound-usage-1.rs:20:5 + | +LL | Type + | ^^^^ cannot normalize `qualified::{constant#0}` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs new file mode 100644 index 00000000000..5e873082781 --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs @@ -0,0 +1,35 @@ +//@ compile-flags: -Znext-solver + +// Check that `~const` item bounds only hold if the where clauses on the +// associated type are also const. +// i.e. check that we validate the const conditions for the associated type +// when considering one of implied const bounds. + +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] + +#[const_trait] +trait Trait { + type Assoc: ~const Trait + where + U: ~const Other; + + fn func(); +} + +#[const_trait] +trait Other {} + +const fn fails() { + T::Assoc::::func(); + //~^ ERROR the trait bound `::Assoc: ~const Trait` is not satisfied + ::Assoc::::func(); + //~^ ERROR the trait bound `::Assoc: ~const Trait` is not satisfied +} + +const fn works() { + T::Assoc::::func(); + ::Assoc::::func(); +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr new file mode 100644 index 00000000000..1f6532c7a57 --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `::Assoc: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail-2.rs:24:5 + | +LL | T::Assoc::::func(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `::Assoc: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail-2.rs:26:5 + | +LL | ::Assoc::::func(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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/assoc-type-const-bound-usage-fail.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs new file mode 100644 index 00000000000..73b3d142f7c --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Znext-solver + +// Check that `~const` item bounds only hold if the parent trait is `~const`. +// i.e. check that we validate the const conditions for the associated type +// when considering one of implied const bounds. + +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] + +#[const_trait] +trait Trait { + type Assoc: ~const Trait; + fn func(); +} + +const fn unqualified() { + T::Assoc::func(); + //~^ ERROR the trait bound `T: ~const Trait` is not satisfied + ::Assoc::func(); + //~^ ERROR the trait bound `T: ~const Trait` is not satisfied +} + +const fn works() { + T::Assoc::func(); + ::Assoc::func(); +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr new file mode 100644 index 00000000000..fb08e74eb7f --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `T: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail.rs:17:5 + | +LL | T::Assoc::func(); + | ^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `T: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail.rs:19:5 + | +LL | ::Assoc::func(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs b/tests/ui/traits/const-traits/assoc-type.rs similarity index 80% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs rename to tests/ui/traits/const-traits/assoc-type.rs index ea3cbabf302..a9394d90ed8 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs +++ b/tests/ui/traits/const-traits/assoc-type.rs @@ -1,4 +1,5 @@ -// FIXME(effects): Replace `Add` with `std::ops::Add` once the latter a `#[const_trait]` again. +//@ compile-flags: -Znext-solver + #![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete #[const_trait] @@ -33,7 +34,7 @@ trait Foo { impl const Foo for NonConstAdd { type Bar = NonConstAdd; - // FIXME(effects) ERROR the trait bound `NonConstAdd: ~const Add` is not satisfied + //~^ ERROR the trait bound `NonConstAdd: ~const Add` is not satisfied } #[const_trait] diff --git a/tests/ui/traits/const-traits/assoc-type.stderr b/tests/ui/traits/const-traits/assoc-type.stderr new file mode 100644 index 00000000000..672eaf26f72 --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type.stderr @@ -0,0 +1,24 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/assoc-type.rs:3:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the trait bound `NonConstAdd: ~const Add` is not satisfied + --> $DIR/assoc-type.rs:36:16 + | +LL | type Bar = NonConstAdd; + | ^^^^^^^^^^^ + | +note: required by a bound in `Foo::Bar` + --> $DIR/assoc-type.rs:32:15 + | +LL | type Bar: ~const Add; + | ^^^^^^ required by this bound in `Foo::Bar` + +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/rfcs/rfc-2632-const-trait-impl/attr-misuse.rs b/tests/ui/traits/const-traits/attr-misuse.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.rs rename to tests/ui/traits/const-traits/attr-misuse.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr b/tests/ui/traits/const-traits/attr-misuse.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/attr-misuse.stderr rename to tests/ui/traits/const-traits/attr-misuse.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs b/tests/ui/traits/const-traits/auxiliary/cross-crate.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs rename to tests/ui/traits/const-traits/auxiliary/cross-crate.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/staged-api.rs b/tests/ui/traits/const-traits/auxiliary/staged-api.rs similarity index 70% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/staged-api.rs rename to tests/ui/traits/const-traits/auxiliary/staged-api.rs index 986165ef91e..bb591321b84 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/auxiliary/staged-api.rs +++ b/tests/ui/traits/const-traits/auxiliary/staged-api.rs @@ -19,3 +19,12 @@ pub struct Unstable; impl const MyTrait for Unstable { fn func() {} } + +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Unstable2; + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "unstable2", issue = "none")] +impl const MyTrait for Unstable2 { + fn func() {} +} diff --git a/tests/ui/traits/const-traits/call-const-closure.rs b/tests/ui/traits/const-traits/call-const-closure.rs new file mode 100644 index 00000000000..cbf3e6c3ac4 --- /dev/null +++ b/tests/ui/traits/const-traits/call-const-closure.rs @@ -0,0 +1,22 @@ +//@ compile-flags: -Znext-solver +//@ edition:2021 + +#![feature(const_trait_impl, effects, const_closures)] +#![allow(incomplete_features)] + +#[const_trait] +trait Bar { + fn foo(&self); +} + +impl Bar for () { + fn foo(&self) {} +} + +const FOO: () = { + (const || ().foo())(); + //~^ ERROR the trait bound `(): ~const Bar` is not satisfied + // FIXME(effects): The constness environment for const closures is wrong. +}; + +fn main() {} diff --git a/tests/ui/traits/const-traits/call-const-closure.stderr b/tests/ui/traits/const-traits/call-const-closure.stderr new file mode 100644 index 00000000000..3fed67f5d08 --- /dev/null +++ b/tests/ui/traits/const-traits/call-const-closure.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `(): ~const Bar` is not satisfied + --> $DIR/call-const-closure.rs:17:15 + | +LL | (const || ().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/call-const-in-tilde-const.rs b/tests/ui/traits/const-traits/call-const-in-tilde-const.rs new file mode 100644 index 00000000000..970ee93fd49 --- /dev/null +++ b/tests/ui/traits/const-traits/call-const-in-tilde-const.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Znext-solver +#![feature(const_trait_impl, effects)] +//~^ WARN the feature `effects` is incomplete + +#[const_trait] trait Foo { + fn foo(); +} + +const fn foo() { + const { T::foo() } + //~^ ERROR the trait bound `T: const Foo` is not satisfied +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr b/tests/ui/traits/const-traits/call-const-in-tilde-const.stderr similarity index 60% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr rename to tests/ui/traits/const-traits/call-const-in-tilde-const.stderr index c20b53c210f..49c310f1f75 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr +++ b/tests/ui/traits/const-traits/call-const-in-tilde-const.stderr @@ -1,5 +1,5 @@ warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/assoc-type.rs:2:30 + --> $DIR/call-const-in-tilde-const.rs:2:30 | LL | #![feature(const_trait_impl, effects)] | ^^^^^^^ @@ -7,10 +7,12 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally +error[E0277]: the trait bound `T: const Foo` is not satisfied + --> $DIR/call-const-in-tilde-const.rs:10:13 | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable +LL | const { T::foo() } + | ^^^^^^^^ 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/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs b/tests/ui/traits/const-traits/call-const-trait-method-fail.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs rename to tests/ui/traits/const-traits/call-const-trait-method-fail.rs diff --git a/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr b/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr new file mode 100644 index 00000000000..40a06af85ed --- /dev/null +++ b/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `u32: ~const Plus` is not satisfied + --> $DIR/call-const-trait-method-fail.rs:27:5 + | +LL | a.plus(b) + | ^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs b/tests/ui/traits/const-traits/call-const-trait-method-pass.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs rename to tests/ui/traits/const-traits/call-const-trait-method-pass.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr b/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr similarity index 76% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr rename to tests/ui/traits/const-traits/call-const-trait-method-pass.stderr index bf455a714a3..32f53137a00 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr +++ b/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr @@ -16,15 +16,6 @@ LL | impl const PartialEq for Int { = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error[E0049]: method `plus` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/call-const-trait-method-pass.rs:24:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | pub trait Plus { -LL | fn plus(self, rhs: Self) -> Self; - | - expected 0 const parameters - error[E0015]: cannot call non-const operator in constants --> $DIR/call-const-trait-method-pass.rs:39:22 | @@ -32,10 +23,6 @@ LL | const ADD_INT: Int = Int(1i32) + Int(2i32); | ^^^^^^^^^^^^^^^^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error[E0015]: cannot call non-const fn `::plus` in constant functions --> $DIR/call-const-trait-method-pass.rs:11:20 @@ -56,10 +43,6 @@ LL | !self.eq(other) | ^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error[E0015]: cannot call non-const fn `::plus` in constant functions --> $DIR/call-const-trait-method-pass.rs:36:7 @@ -73,7 +56,6 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0015, E0049. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.rs b/tests/ui/traits/const-traits/call-generic-in-impl.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-in-impl.rs rename to tests/ui/traits/const-traits/call-generic-in-impl.rs diff --git a/tests/ui/traits/const-traits/call-generic-in-impl.stderr b/tests/ui/traits/const-traits/call-generic-in-impl.stderr new file mode 100644 index 00000000000..52ee04425b2 --- /dev/null +++ b/tests/ui/traits/const-traits/call-generic-in-impl.stderr @@ -0,0 +1,25 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-in-impl.rs:10:9 + | +LL | impl const MyPartialEq for T { + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-in-impl.rs:10:9 + | +LL | impl const MyPartialEq for T { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0015]: cannot call non-const fn `::eq` in constant functions + --> $DIR/call-generic-in-impl.rs:12:9 + | +LL | PartialEq::eq(self, other) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.rs b/tests/ui/traits/const-traits/call-generic-method-chain.rs similarity index 94% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.rs rename to tests/ui/traits/const-traits/call-generic-method-chain.rs index 9df694a02f5..e5baedae818 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-chain.rs +++ b/tests/ui/traits/const-traits/call-generic-method-chain.rs @@ -1,6 +1,7 @@ //! Basic test for calling methods on generic type parameters in `const fn`. //@ known-bug: #110395 +//@ compile-flags: -Znext-solver // FIXME(effects) check-pass #![feature(const_trait_impl, effects)] diff --git a/tests/ui/traits/const-traits/call-generic-method-chain.stderr b/tests/ui/traits/const-traits/call-generic-method-chain.stderr new file mode 100644 index 00000000000..6dbf3ad2526 --- /dev/null +++ b/tests/ui/traits/const-traits/call-generic-method-chain.stderr @@ -0,0 +1,69 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/call-generic-method-chain.rs:7:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/call-generic-method-chain.rs:11:12 + | +LL | impl const PartialEq for S { + | ^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-chain.rs:20:25 + | +LL | const fn equals_self(t: &T) -> bool { + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-chain.rs:20:25 + | +LL | const fn equals_self(t: &T) -> bool { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-chain.rs:24:33 + | +LL | const fn equals_self_wrapper(t: &T) -> bool { + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-chain.rs:24:33 + | +LL | const fn equals_self_wrapper(t: &T) -> bool { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/call-generic-method-chain.rs:21:5 + | +LL | *t == *t + | ^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: consider further restricting this bound + | +LL | const fn equals_self(t: &T) -> bool { + | ++++++++++++++++++++++++++++ + +error[E0015]: cannot call non-const fn `::eq` in constant functions + --> $DIR/call-generic-method-chain.rs:16:15 + | +LL | !self.eq(other) + | ^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 7 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs b/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs similarity index 95% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs rename to tests/ui/traits/const-traits/call-generic-method-dup-bound.rs index f46a34911f1..83a4bb25436 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs +++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Znext-solver //@ known-bug: #110395 // FIXME(effects) check-pass diff --git a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr new file mode 100644 index 00000000000..08877daad79 --- /dev/null +++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr @@ -0,0 +1,81 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/call-generic-method-dup-bound.rs:5:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/call-generic-method-dup-bound.rs:9:12 + | +LL | impl const PartialEq for S { + | ^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-dup-bound.rs:20:37 + | +LL | const fn equals_self(t: &T) -> bool { + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-dup-bound.rs:20:37 + | +LL | const fn equals_self(t: &T) -> bool { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-dup-bound.rs:27:30 + | +LL | const fn equals_self2(t: &T) -> bool { + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-dup-bound.rs:27:30 + | +LL | const fn equals_self2(t: &T) -> bool { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/call-generic-method-dup-bound.rs:21:5 + | +LL | *t == *t + | ^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: consider further restricting this bound + | +LL | const fn equals_self(t: &T) -> bool { + | ++++++++++++++++++++++++++++ + +error[E0015]: cannot call non-const fn `::eq` in constant functions + --> $DIR/call-generic-method-dup-bound.rs:14:15 + | +LL | !self.eq(other) + | ^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/call-generic-method-dup-bound.rs:28:5 + | +LL | *t == *t + | ^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: consider further restricting this bound + | +LL | const fn equals_self2(t: &T) -> bool { + | ++++++++++++++++++++++++++++ + +error: aborting due to 8 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.rs b/tests/ui/traits/const-traits/call-generic-method-fail.rs similarity index 66% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.rs rename to tests/ui/traits/const-traits/call-generic-method-fail.rs index 86e0eae61c9..6bfbbef6f76 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-fail.rs +++ b/tests/ui/traits/const-traits/call-generic-method-fail.rs @@ -1,12 +1,10 @@ -//@ check-pass //@ compile-flags: -Znext-solver #![allow(incomplete_features)] #![feature(const_trait_impl, effects)] pub const fn equals_self(t: &T) -> bool { *t == *t - // FIXME(effects) ~^ ERROR mismatched types - // FIXME(effects): diagnostic + //~^ ERROR cannot call non-const operator in constant functions } fn main() {} diff --git a/tests/ui/traits/const-traits/call-generic-method-fail.stderr b/tests/ui/traits/const-traits/call-generic-method-fail.stderr new file mode 100644 index 00000000000..5cd4216dce1 --- /dev/null +++ b/tests/ui/traits/const-traits/call-generic-method-fail.stderr @@ -0,0 +1,15 @@ +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/call-generic-method-fail.rs:6:5 + | +LL | *t == *t + | ^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: consider further restricting this bound + | +LL | pub const fn equals_self(t: &T) -> bool { + | ++++++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs b/tests/ui/traits/const-traits/call-generic-method-nonconst-bound.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs rename to tests/ui/traits/const-traits/call-generic-method-nonconst-bound.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs b/tests/ui/traits/const-traits/call-generic-method-nonconst.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs rename to tests/ui/traits/const-traits/call-generic-method-nonconst.rs diff --git a/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr b/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr new file mode 100644 index 00000000000..06b99375cda --- /dev/null +++ b/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `S: const Foo` is not satisfied + --> $DIR/call-generic-method-nonconst.rs:25:22 + | +LL | pub const EQ: bool = equals_self(&S); + | ^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.rs b/tests/ui/traits/const-traits/call-generic-method-pass.rs similarity index 93% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.rs rename to tests/ui/traits/const-traits/call-generic-method-pass.rs index 413685d8b34..cbeeb2567dd 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-pass.rs +++ b/tests/ui/traits/const-traits/call-generic-method-pass.rs @@ -1,5 +1,6 @@ //! Basic test for calling methods on generic type parameters in `const fn`. +//@ compile-flags: -Znext-solver //@ known-bug: #110395 // FIXME(effects) check-pass diff --git a/tests/ui/traits/const-traits/call-generic-method-pass.stderr b/tests/ui/traits/const-traits/call-generic-method-pass.stderr new file mode 100644 index 00000000000..ac08c057435 --- /dev/null +++ b/tests/ui/traits/const-traits/call-generic-method-pass.stderr @@ -0,0 +1,55 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/call-generic-method-pass.rs:7:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` + --> $DIR/call-generic-method-pass.rs:11:12 + | +LL | impl const PartialEq for S { + | ^^^^^^^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-pass.rs:20:25 + | +LL | const fn equals_self(t: &T) -> bool { + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/call-generic-method-pass.rs:20:25 + | +LL | const fn equals_self(t: &T) -> bool { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/call-generic-method-pass.rs:21:5 + | +LL | *t == *t + | ^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: consider further restricting this bound + | +LL | const fn equals_self(t: &T) -> bool { + | ++++++++++++++++++++++++++++ + +error[E0015]: cannot call non-const fn `::eq` in constant functions + --> $DIR/call-generic-method-pass.rs:16:15 + | +LL | !self.eq(other) + | ^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 5 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call.rs b/tests/ui/traits/const-traits/call.rs similarity index 68% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/call.rs rename to tests/ui/traits/const-traits/call.rs index af2f7caf88c..f96fb614ac2 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call.rs +++ b/tests/ui/traits/const-traits/call.rs @@ -1,10 +1,11 @@ -//@ check-pass +// FIXME(effects) check-pass //@ compile-flags: -Znext-solver #![feature(const_closures, const_trait_impl, effects)] #![allow(incomplete_features)] pub const _: () = { assert!((const || true)()); + //~^ ERROR cannot call non-const closure in constants }; fn main() {} diff --git a/tests/ui/traits/const-traits/call.stderr b/tests/ui/traits/const-traits/call.stderr new file mode 100644 index 00000000000..e9bf64092f3 --- /dev/null +++ b/tests/ui/traits/const-traits/call.stderr @@ -0,0 +1,12 @@ +error[E0015]: cannot call non-const closure in constants + --> $DIR/call.rs:7:13 + | +LL | assert!((const || true)()); + | ^^^^^^^^^^^^^^^^^ + | + = note: closures need an RFC before allowed to be called in constants + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.rs b/tests/ui/traits/const-traits/const-and-non-const-impl.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.rs rename to tests/ui/traits/const-traits/const-and-non-const-impl.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr b/tests/ui/traits/const-traits/const-and-non-const-impl.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr rename to tests/ui/traits/const-traits/const-and-non-const-impl.stderr diff --git a/tests/ui/traits/const-traits/const-bound-in-host.rs b/tests/ui/traits/const-traits/const-bound-in-host.rs new file mode 100644 index 00000000000..6fbc21074b6 --- /dev/null +++ b/tests/ui/traits/const-traits/const-bound-in-host.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +#![feature(const_trait_impl, effects)] +//~^ WARN the feature `effects` is incomplete + +#[const_trait] trait Foo { + fn foo(); +} + +fn foo() { + const { T::foo() } +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/const-bound-in-host.stderr b/tests/ui/traits/const-traits/const-bound-in-host.stderr new file mode 100644 index 00000000000..b815f745ee8 --- /dev/null +++ b/tests/ui/traits/const-traits/const-bound-in-host.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-bound-in-host.rs:4:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.rs b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.rs similarity index 94% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.rs rename to tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.rs index 099cf0b00d3..7c3e2af1797 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.rs +++ b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.rs @@ -1,3 +1,5 @@ +//@ compile-flags: -Znext-solver + #![allow(incomplete_features)] #![feature(const_trait_impl, effects)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.stderr b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.stderr similarity index 55% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.stderr rename to tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.stderr index b5d9b1fff8a..ae1260ffab7 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bound-on-not-const-associated-fn.stderr +++ b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.stderr @@ -1,31 +1,26 @@ error: `~const` is not allowed here - --> $DIR/const-bound-on-not-const-associated-fn.rs:10:40 + --> $DIR/const-bound-on-not-const-associated-fn.rs:12:40 | LL | fn do_something_else() where Self: ~const MyTrait; | ^^^^^^ | note: this function is not `const`, so it cannot have `~const` trait bounds - --> $DIR/const-bound-on-not-const-associated-fn.rs:10:8 + --> $DIR/const-bound-on-not-const-associated-fn.rs:12:8 | LL | fn do_something_else() where Self: ~const MyTrait; | ^^^^^^^^^^^^^^^^^ error: `~const` is not allowed here - --> $DIR/const-bound-on-not-const-associated-fn.rs:21:32 + --> $DIR/const-bound-on-not-const-associated-fn.rs:23:32 | LL | pub fn foo(&self) where T: ~const MyTrait { | ^^^^^^ | note: this function is not `const`, so it cannot have `~const` trait bounds - --> $DIR/const-bound-on-not-const-associated-fn.rs:21:12 + --> $DIR/const-bound-on-not-const-associated-fn.rs:23:12 | LL | pub fn foo(&self) where T: ~const MyTrait { | ^^^ -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs similarity index 84% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs rename to tests/ui/traits/const-traits/const-bounds-non-const-trait.rs index db446f8bc2e..d51d231b8a9 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs +++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs @@ -5,6 +5,7 @@ trait NonConst {} const fn perform() {} //~^ ERROR `~const` can only be applied to `#[const_trait]` traits +//~| ERROR `~const` can only be applied to `#[const_trait]` traits fn operate() {} //~^ ERROR `const` can only be applied to `#[const_trait]` traits diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr similarity index 63% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr rename to tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr index e1a85fc5414..d27be2a324b 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr +++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr @@ -13,16 +13,24 @@ error: using `#![feature(effects)]` without enabling next trait solver globally = help: use `-Znext-solver` to enable error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-bounds-non-const-trait.rs:6:28 + --> $DIR/const-bounds-non-const-trait.rs:6:21 | LL | const fn perform() {} - | ^^^^^^^^ + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-bounds-non-const-trait.rs:6:21 + | +LL | const fn perform() {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `const` can only be applied to `#[const_trait]` traits - --> $DIR/const-bounds-non-const-trait.rs:9:21 + --> $DIR/const-bounds-non-const-trait.rs:10:15 | LL | fn operate() {} - | ^^^^^^^^ + | ^^^^^ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 4 previous errors; 1 warning emitted diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs b/tests/ui/traits/const-traits/const-check-fns-in-const-impl.rs similarity index 88% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs rename to tests/ui/traits/const-traits/const-check-fns-in-const-impl.rs index a1710e65252..7f9b38b8207 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs +++ b/tests/ui/traits/const-traits/const-check-fns-in-const-impl.rs @@ -1,3 +1,5 @@ +//@ compile-flags: -Znext-solver + #![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete struct S; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr b/tests/ui/traits/const-traits/const-check-fns-in-const-impl.stderr similarity index 63% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr rename to tests/ui/traits/const-traits/const-check-fns-in-const-impl.stderr index 49cd1725c8c..ba12854987e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr +++ b/tests/ui/traits/const-traits/const-check-fns-in-const-impl.stderr @@ -1,5 +1,5 @@ warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/const-check-fns-in-const-impl.rs:1:30 + --> $DIR/const-check-fns-in-const-impl.rs:3:30 | LL | #![feature(const_trait_impl, effects)] | ^^^^^^^ @@ -7,19 +7,14 @@ LL | #![feature(const_trait_impl, effects)] = note: see issue #102090 for more information = note: `#[warn(incomplete_features)]` on by default -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - error[E0015]: cannot call non-const fn `non_const` in constant functions - --> $DIR/const-check-fns-in-const-impl.rs:12:16 + --> $DIR/const-check-fns-in-const-impl.rs:14:16 | LL | fn foo() { non_const() } | ^^^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs b/tests/ui/traits/const-traits/const-closure-parse-not-item.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.rs rename to tests/ui/traits/const-traits/const-closure-parse-not-item.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr similarity index 66% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr rename to tests/ui/traits/const-traits/const-closure-parse-not-item.stderr index 12cc79f5961..25c81ff900f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr +++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr @@ -1,14 +1,14 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-parse-not-item.rs:7:32 + --> $DIR/const-closure-parse-not-item.rs:7:25 | LL | const fn test() -> impl ~const Fn() { - | ^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-parse-not-item.rs:7:32 + --> $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` diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.rs b/tests/ui/traits/const-traits/const-closure-trait-method-fail.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.rs rename to tests/ui/traits/const-traits/const-closure-trait-method-fail.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr similarity index 52% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr rename to tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr index 507ceaae2ea..cb4c994bc2f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr +++ b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr @@ -1,17 +1,16 @@ -error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-closure-trait-method-fail.rs:5:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Tr { -LL | fn a(self) -> i32; - | - expected 0 const parameters - error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-trait-method-fail.rs:14:39 + --> $DIR/const-closure-trait-method-fail.rs:14:32 | LL | const fn need_const_closure i32>(x: T) -> i32 { - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-closure-trait-method-fail.rs:14:32 + | +LL | const fn need_const_closure i32>(x: T) -> i32 { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const closure in constant functions --> $DIR/const-closure-trait-method-fail.rs:15:5 @@ -24,12 +23,7 @@ help: consider further restricting this bound | LL | const fn need_const_closure i32 + ~const FnOnce(())>(x: T) -> i32 { | +++++++++++++++++++ -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error: aborting due to 3 previous errors -Some errors have detailed explanations: E0015, E0049. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.rs b/tests/ui/traits/const-traits/const-closure-trait-method.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.rs rename to tests/ui/traits/const-traits/const-closure-trait-method.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr b/tests/ui/traits/const-traits/const-closure-trait-method.stderr similarity index 52% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr rename to tests/ui/traits/const-traits/const-closure-trait-method.stderr index 2a54cd5d7f6..43af435ae64 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr +++ b/tests/ui/traits/const-traits/const-closure-trait-method.stderr @@ -1,17 +1,16 @@ -error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-closure-trait-method.rs:5:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | trait Tr { -LL | fn a(self) -> i32; - | - expected 0 const parameters - error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-trait-method.rs:14:39 + --> $DIR/const-closure-trait-method.rs:14:32 | LL | const fn need_const_closure i32>(x: T) -> i32 { - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-closure-trait-method.rs:14:32 + | +LL | const fn need_const_closure i32>(x: T) -> i32 { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const closure in constant functions --> $DIR/const-closure-trait-method.rs:15:5 @@ -24,12 +23,7 @@ help: consider further restricting this bound | LL | const fn need_const_closure i32 + ~const FnOnce(())>(x: T) -> i32 { | +++++++++++++++++++ -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error: aborting due to 3 previous errors -Some errors have detailed explanations: E0015, E0049. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.rs b/tests/ui/traits/const-traits/const-closures.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.rs rename to tests/ui/traits/const-traits/const-closures.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr b/tests/ui/traits/const-traits/const-closures.stderr similarity index 58% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr rename to tests/ui/traits/const-traits/const-closures.stderr index a0f05325389..2e9e37ba321 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr +++ b/tests/ui/traits/const-traits/const-closures.stderr @@ -1,26 +1,58 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:8:19 + --> $DIR/const-closures.rs:8:12 | LL | F: ~const FnOnce() -> u8, - | ^^^^^^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:9:19 + --> $DIR/const-closures.rs:9:12 | LL | F: ~const FnMut() -> u8, - | ^^^^^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:10:19 + --> $DIR/const-closures.rs:10:12 | LL | F: ~const Fn() -> u8, - | ^^^^^^^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:23:27 + --> $DIR/const-closures.rs:8:12 + | +LL | F: ~const FnOnce() -> u8, + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-closures.rs:9:12 + | +LL | F: ~const FnMut() -> u8, + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-closures.rs:10:12 + | +LL | F: ~const Fn() -> u8, + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-closures.rs:23:20 | LL | const fn answer u8>(f: &F) -> u8 { - | ^^^^^^^^^^ + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-closures.rs:23:20 + | +LL | const fn answer u8>(f: &F) -> u8 { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const closure in constant functions --> $DIR/const-closures.rs:24:5 @@ -33,10 +65,6 @@ help: consider further restricting this bound | LL | const fn answer u8 + ~const Fn()>(f: &F) -> u8 { | +++++++++++++ -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error[E0015]: cannot call non-const closure in constant functions --> $DIR/const-closures.rs:24:11 @@ -49,10 +77,6 @@ help: consider further restricting this bound | LL | const fn answer u8 + ~const Fn()>(f: &F) -> u8 { | +++++++++++++ -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error[E0015]: cannot call non-const closure in constant functions --> $DIR/const-closures.rs:12:5 @@ -65,11 +89,7 @@ help: consider further restricting this bound | LL | F: ~const FnOnce() -> u8 + ~const Fn(), | +++++++++++++ -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | -error: aborting due to 7 previous errors +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs b/tests/ui/traits/const-traits/const-default-method-bodies.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs rename to tests/ui/traits/const-traits/const-default-method-bodies.rs diff --git a/tests/ui/traits/const-traits/const-default-method-bodies.stderr b/tests/ui/traits/const-traits/const-default-method-bodies.stderr new file mode 100644 index 00000000000..071eaf49541 --- /dev/null +++ b/tests/ui/traits/const-traits/const-default-method-bodies.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied + --> $DIR/const-default-method-bodies.rs:26:5 + | +LL | NonConstImpl.a(); + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.rs b/tests/ui/traits/const-traits/const-drop-bound.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-bound.rs rename to tests/ui/traits/const-traits/const-drop-bound.rs diff --git a/tests/ui/traits/const-traits/const-drop-bound.stderr b/tests/ui/traits/const-traits/const-drop-bound.stderr new file mode 100644 index 00000000000..3f718645433 --- /dev/null +++ b/tests/ui/traits/const-traits/const-drop-bound.stderr @@ -0,0 +1,51 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-bound.rs:9:61 + | +LL | const fn foo(res: Result) -> Option where E: ~const Destruct { + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-bound.rs:9:61 + | +LL | const fn foo(res: Result) -> Option where E: ~const Destruct { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-bound.rs:20:8 + | +LL | T: ~const Destruct, + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-bound.rs:21:8 + | +LL | E: ~const Destruct, + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-bound.rs:20:8 + | +LL | T: ~const Destruct, + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-bound.rs:21:8 + | +LL | E: ~const Destruct, + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0493]: destructor of `E` cannot be evaluated at compile-time + --> $DIR/const-drop-bound.rs:12:13 + | +LL | Err(_e) => None, + | ^^ the destructor for this type cannot be evaluated in constant functions + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr rename to tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs b/tests/ui/traits/const-traits/const-drop-fail-2.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs rename to tests/ui/traits/const-traits/const-drop-fail-2.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.stderr similarity index 78% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr rename to tests/ui/traits/const-traits/const-drop-fail-2.stderr index faf24c6d911..82d6412ded0 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail-2.stderr @@ -8,10 +8,18 @@ LL | impl const Drop for ConstDropImplWithNonConstBounds { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-fail-2.rs:20:26 + --> $DIR/const-drop-fail-2.rs:20:19 | LL | const fn check(_: T) {} - | ^^^^^^^^ + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-fail-2.rs:20:19 + | +LL | const fn check(_: T) {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-drop-fail-2.rs:20:36 @@ -33,7 +41,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0015, E0493. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr rename to tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.precise.stderr similarity index 88% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr rename to tests/ui/traits/const-traits/const-drop-fail.precise.stderr index 3d400bf0158..859fdfae81a 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail.precise.stderr @@ -8,10 +8,18 @@ LL | impl const Drop for ConstImplWithDropGlue { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-fail.rs:23:26 + --> $DIR/const-drop-fail.rs:23:19 | LL | const fn check(_: T) {} - | ^^^^^^^^ + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-fail.rs:23:19 + | +LL | const fn check(_: T) {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-drop-fail.rs:23:36 @@ -71,7 +79,7 @@ LL | | } | |_- in this macro invocation = note: this error originates in the macro `check_all` (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: E0080, E0493. For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs b/tests/ui/traits/const-traits/const-drop-fail.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs rename to tests/ui/traits/const-traits/const-drop-fail.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.stock.stderr similarity index 71% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr rename to tests/ui/traits/const-traits/const-drop-fail.stock.stderr index fd0f6d02684..20dea28922b 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail.stock.stderr @@ -8,10 +8,18 @@ LL | impl const Drop for ConstImplWithDropGlue { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop-fail.rs:23:26 + --> $DIR/const-drop-fail.rs:23:19 | LL | const fn check(_: T) {} - | ^^^^^^^^ + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop-fail.rs:23:19 + | +LL | const fn check(_: T) {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-drop-fail.rs:23:36 @@ -21,6 +29,6 @@ LL | const fn check(_: T) {} | | | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr b/tests/ui/traits/const-traits/const-drop.precise.stderr similarity index 75% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr rename to tests/ui/traits/const-traits/const-drop.precise.stderr index dd3ea5d241d..2b8066e5ee7 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr +++ b/tests/ui/traits/const-traits/const-drop.precise.stderr @@ -35,28 +35,16 @@ LL | impl const Drop for ConstDropWithNonconstBound { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop.rs:18:22 + --> $DIR/const-drop.rs:18:15 | LL | const fn a(_: T) {} - | ^^^^^^^^ + | ^^^^^^ -error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-drop.rs:53:5 +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop.rs:18:15 | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | pub trait SomeTrait { -LL | fn foo(); - | - expected 0 const parameters - -error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-drop.rs:53:5 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | pub trait SomeTrait { -LL | fn foo(); - | - expected 0 const parameters +LL | const fn a(_: T) {} + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -78,7 +66,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 9 previous errors +error: aborting due to 8 previous errors -Some errors have detailed explanations: E0015, E0049, E0493. +Some errors have detailed explanations: E0015, E0493. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs b/tests/ui/traits/const-traits/const-drop.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs rename to tests/ui/traits/const-traits/const-drop.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr b/tests/ui/traits/const-traits/const-drop.stock.stderr similarity index 76% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr rename to tests/ui/traits/const-traits/const-drop.stock.stderr index aa59e1c8dc4..54ed2930b90 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr +++ b/tests/ui/traits/const-traits/const-drop.stock.stderr @@ -35,28 +35,16 @@ LL | impl const Drop for ConstDropWithNonconstBound { = note: adding a non-const method body in the future would be a breaking change error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-drop.rs:18:22 + --> $DIR/const-drop.rs:18:15 | LL | const fn a(_: T) {} - | ^^^^^^^^ + | ^^^^^^ -error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-drop.rs:53:5 +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-drop.rs:18:15 | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | pub trait SomeTrait { -LL | fn foo(); - | - expected 0 const parameters - -error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters - --> $DIR/const-drop.rs:53:5 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ found 1 const parameter -LL | pub trait SomeTrait { -LL | fn foo(); - | - expected 0 const parameters +LL | const fn a(_: T) {} + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -80,7 +68,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 9 previous errors +error: aborting due to 8 previous errors -Some errors have detailed explanations: E0015, E0049, E0493. +Some errors have detailed explanations: E0015, E0493. For more information about an error, try `rustc --explain E0015`. 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 new file mode 100644 index 00000000000..6d08d8bdd91 --- /dev/null +++ b/tests/ui/traits/const-traits/const-fns-are-early-bound.rs @@ -0,0 +1,90 @@ +//@ known-bug: #110395 +//@ failure-status: 101 +//@ dont-check-compiler-stderr +// FIXME(effects) 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) + where + F: const FnOnce<()>, + { + } + + const fn foo() {} + + is_const_fn(foo); +} + +/// ---------------------------------------------------------------------- /// +/// Const fn trait definitions + +#[const_trait] +#[lang = "fn"] +#[rustc_paren_sugar] +trait Fn: ~const FnMut { + extern "rust-call" fn call(&self, args: Args) -> Self::Output; +} + +#[const_trait] +#[lang = "fn_mut"] +#[rustc_paren_sugar] +trait FnMut: ~const FnOnce { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +#[const_trait] +#[lang = "fn_once"] +#[rustc_paren_sugar] +trait FnOnce { + #[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 LegacyReceiver for &T {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-norecover.rs b/tests/ui/traits/const-traits/const-impl-norecover.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-norecover.rs rename to tests/ui/traits/const-traits/const-impl-norecover.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-norecover.stderr b/tests/ui/traits/const-traits/const-impl-norecover.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-norecover.stderr rename to tests/ui/traits/const-traits/const-impl-norecover.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-recovery.rs b/tests/ui/traits/const-traits/const-impl-recovery.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-recovery.rs rename to tests/ui/traits/const-traits/const-impl-recovery.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-recovery.stderr b/tests/ui/traits/const-traits/const-impl-recovery.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-recovery.stderr rename to tests/ui/traits/const-traits/const-impl-recovery.stderr diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs b/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs new file mode 100644 index 00000000000..e49e9090eb4 --- /dev/null +++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs @@ -0,0 +1,10 @@ +//@ compile-flags: -Znext-solver +#![feature(const_trait_impl, effects)] +#![allow(incomplete_features)] + +pub trait A {} + +impl const A for () {} +//~^ ERROR: const `impl` for trait `A` which is not marked with `#[const_trait]` + +fn main() {} diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr new file mode 100644 index 00000000000..828e2174f00 --- /dev/null +++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr @@ -0,0 +1,14 @@ +error: const `impl` for trait `A` which is not marked with `#[const_trait]` + --> $DIR/const-impl-requires-const-trait.rs:7:12 + | +LL | pub trait A {} + | - help: mark `A` as const: `#[const_trait]` +LL | +LL | impl const A for () {} + | ^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: aborting due to 1 previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs b/tests/ui/traits/const-traits/const-impl-trait.rs similarity index 92% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs rename to tests/ui/traits/const-traits/const-impl-trait.rs index 51dfe29b829..61b8c9a5bff 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs +++ b/tests/ui/traits/const-traits/const-impl-trait.rs @@ -1,4 +1,7 @@ +//@ compile-flags: -Znext-solver //@ known-bug: #110395 +//@ failure-status: 101 +//@ dont-check-compiler-stderr // Broken until we have `&T: const Deref` impl in stdlib #![allow(incomplete_features)] diff --git a/tests/ui/traits/const-traits/const-in-closure.rs b/tests/ui/traits/const-traits/const-in-closure.rs new file mode 100644 index 00000000000..51b22c53036 --- /dev/null +++ b/tests/ui/traits/const-traits/const-in-closure.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +#![feature(const_trait_impl, effects)] +//~^ WARN the feature `effects` is incomplete + +#[const_trait] trait Trait { + fn method(); +} + +const fn foo() { + let _ = || { + // Make sure this doesn't enforce `T: ~const Trait` + T::method(); + }; +} + +fn bar() { + let _ = || { + // Make sure unconditionally const bounds propagate from parent. + const { T::method(); }; + }; +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/const-in-closure.stderr b/tests/ui/traits/const-traits/const-in-closure.stderr new file mode 100644 index 00000000000..f4b03b9ed20 --- /dev/null +++ b/tests/ui/traits/const-traits/const-in-closure.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-in-closure.rs:4:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs rename to tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr rename to tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.rs b/tests/ui/traits/const-traits/const-trait-bounds.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.rs rename to tests/ui/traits/const-traits/const-trait-bounds.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr b/tests/ui/traits/const-traits/const-trait-bounds.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr rename to tests/ui/traits/const-traits/const-trait-bounds.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs b/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs rename to tests/ui/traits/const-traits/const_derives/derive-const-gate.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr rename to tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs rename to tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr similarity index 63% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr rename to tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr index 777b3313da6..4bcc17952e6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr @@ -22,5 +22,17 @@ LL | #[derive_const(Default)] = note: adding a non-const method body in the future would be a breaking change = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors; 1 warning emitted +error[E0015]: cannot call non-const fn `::default` in constant functions + --> $DIR/derive-const-non-const-type.rs:11:14 + | +LL | #[derive_const(Default)] + | ------- in this derive macro expansion +LL | pub struct S(A); + | ^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs b/tests/ui/traits/const-traits/const_derives/derive-const-use.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs rename to tests/ui/traits/const-traits/const_derives/derive-const-use.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr similarity index 61% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr rename to tests/ui/traits/const-traits/const_derives/derive-const-use.stderr index ad727fc36cd..d471a8253ba 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-use.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr @@ -62,29 +62,67 @@ LL | #[derive_const(Default, PartialEq)] = note: adding a non-const method body in the future would be a breaking change = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0080]: evaluation of constant value failed - --> $DIR/derive-const-use.rs:16:14 +error[E0015]: cannot call non-const fn `::default` in constants + --> $DIR/derive-const-use.rs:18:35 | -LL | #[derive_const(Default, PartialEq)] - | ------- in this derive macro expansion -LL | pub struct S((), A); - | ^^ calling non-const function `<() as Default>::default` +LL | const _: () = assert!(S((), A) == S::default()); + | ^^^^^^^^^^^^ | -note: inside `::default` + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + +error[E0015]: cannot call non-const operator in constants + --> $DIR/derive-const-use.rs:18:23 + | +LL | const _: () = assert!(S((), A) == S::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + +error[E0015]: cannot call non-const fn `<() as Default>::default` in constant functions --> $DIR/derive-const-use.rs:16:14 | LL | #[derive_const(Default, PartialEq)] | ------- in this derive macro expansion LL | pub struct S((), A); | ^^ -note: inside `_` - --> $DIR/derive-const-use.rs:18:35 | -LL | const _: () = assert!(S((), A) == S::default()); - | ^^^^^^^^^^^^ + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 8 previous errors; 1 warning emitted +error[E0015]: cannot call non-const fn `::default` in constant functions + --> $DIR/derive-const-use.rs:16:18 + | +LL | #[derive_const(Default, PartialEq)] + | ------- in this derive macro expansion +LL | pub struct S((), A); + | ^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) -Some errors have detailed explanations: E0080, E0635. -For more information about an error, try `rustc --explain E0080`. +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/derive-const-use.rs:16:14 + | +LL | #[derive_const(Default, PartialEq)] + | --------- in this derive macro expansion +LL | pub struct S((), A); + | ^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/derive-const-use.rs:16:18 + | +LL | #[derive_const(Default, PartialEq)] + | --------- in this derive macro expansion +LL | pub struct S((), A); + | ^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 13 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0015, E0635. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.rs b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.rs rename to tests/ui/traits/const-traits/const_derives/derive-const-with-params.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr similarity index 65% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr rename to tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr index addce8dcd6c..64285cff0a6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-with-params.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr @@ -23,12 +23,26 @@ LL | #[derive_const(PartialEq)] = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/derive-const-with-params.rs:7:16 + +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/derive-const-with-params.rs:8:23 | LL | #[derive_const(PartialEq)] - | ^^^^^^^^^ + | --------- in this derive macro expansion +LL | pub struct Reverse(T); + | ^ | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors; 1 warning emitted +error[E0015]: cannot call non-const operator in constant functions + --> $DIR/derive-const-with-params.rs:11:5 + | +LL | a == b + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error: aborting due to 5 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs b/tests/ui/traits/const-traits/cross-crate-default-method-body-is-const.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs rename to tests/ui/traits/const-traits/cross-crate-default-method-body-is-const.rs diff --git a/tests/ui/traits/const-traits/cross-crate.gatednc.stderr b/tests/ui/traits/const-traits/cross-crate.gatednc.stderr new file mode 100644 index 00000000000..b6f2434140d --- /dev/null +++ b/tests/ui/traits/const-traits/cross-crate.gatednc.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied + --> $DIR/cross-crate.rs:19:5 + | +LL | NonConst.func(); + | ^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.rs b/tests/ui/traits/const-traits/cross-crate.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.rs rename to tests/ui/traits/const-traits/cross-crate.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stock.stderr b/tests/ui/traits/const-traits/cross-crate.stock.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stock.stderr rename to tests/ui/traits/const-traits/cross-crate.stock.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr rename to tests/ui/traits/const-traits/cross-crate.stocknc.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs b/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs rename to tests/ui/traits/const-traits/default-method-body-is-const-body-checking.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs rename to tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.rs diff --git a/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr new file mode 100644 index 00000000000..7b4d512e391 --- /dev/null +++ b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `(): ~const Tr` is not satisfied + --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:9 + | +LL | ().a() + | ^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs b/tests/ui/traits/const-traits/default-method-body-is-const-with-staged-api.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs rename to tests/ui/traits/const-traits/default-method-body-is-const-with-staged-api.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check-override.rs b/tests/ui/traits/const-traits/do-not-const-check-override.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check-override.rs rename to tests/ui/traits/const-traits/do-not-const-check-override.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check.rs b/tests/ui/traits/const-traits/do-not-const-check.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/do-not-const-check.rs rename to tests/ui/traits/const-traits/do-not-const-check.rs diff --git a/tests/ui/traits/const-traits/dont-observe-host-opaque.rs b/tests/ui/traits/const-traits/dont-observe-host-opaque.rs new file mode 100644 index 00000000000..4a5ae346e39 --- /dev/null +++ b/tests/ui/traits/const-traits/dont-observe-host-opaque.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +#![feature(const_trait_impl, effects)] +//~^ WARN the feature `effects` is incomplete + +const fn opaque() -> impl Sized {} + +fn main() { + let mut x = const { opaque() }; + x = opaque(); +} diff --git a/tests/ui/traits/const-traits/dont-observe-host-opaque.stderr b/tests/ui/traits/const-traits/dont-observe-host-opaque.stderr new file mode 100644 index 00000000000..1b457ab7643 --- /dev/null +++ b/tests/ui/traits/const-traits/dont-observe-host-opaque.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/dont-observe-host-opaque.rs:4:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/const-traits/dont-observe-host.rs b/tests/ui/traits/const-traits/dont-observe-host.rs new file mode 100644 index 00000000000..d027d578c42 --- /dev/null +++ b/tests/ui/traits/const-traits/dont-observe-host.rs @@ -0,0 +1,23 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +#![feature(const_trait_impl, effects)] +//~^ WARN the feature `effects` is incomplete + +#[const_trait] +trait Trait { + fn method() {} +} + +impl const Trait for () {} + +fn main() { + let mut x = const { + let x = <()>::method; + x(); + x + }; + let y = <()>::method; + y(); + x = y; +} diff --git a/tests/ui/traits/const-traits/dont-observe-host.stderr b/tests/ui/traits/const-traits/dont-observe-host.stderr new file mode 100644 index 00000000000..64ef611f011 --- /dev/null +++ b/tests/ui/traits/const-traits/dont-observe-host.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/dont-observe-host.rs:4:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/auxiliary/cross-crate.rs b/tests/ui/traits/const-traits/effects/auxiliary/cross-crate.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/auxiliary/cross-crate.rs rename to tests/ui/traits/const-traits/effects/auxiliary/cross-crate.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.rs similarity index 62% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs rename to tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.rs index 3debc22098a..8f8e9f06584 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs +++ b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.rs @@ -1,5 +1,3 @@ -//@ check-pass -// FIXME(effects) this shouldn't pass //@ compile-flags: -Znext-solver #![feature(const_closures, const_trait_impl, effects)] #![allow(incomplete_features)] @@ -14,5 +12,6 @@ impl Foo for () { fn main() { (const || { (()).foo() })(); - // FIXME(effects) ~^ ERROR: cannot call non-const fn + //~^ ERROR: cannot call non-const fn `<() as Foo>::foo` in constant functions + // FIXME(effects) this should probably say constant closures } diff --git a/tests/ui/consts/intrinsic_without_const_stab_fail.stderr b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.stderr similarity index 51% rename from tests/ui/consts/intrinsic_without_const_stab_fail.stderr rename to tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.stderr index 8ade68eb2a9..243e94087bb 100644 --- a/tests/ui/consts/intrinsic_without_const_stab_fail.stderr +++ b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.stderr @@ -1,8 +1,8 @@ -error[E0015]: cannot call non-const fn `copy::` in constant functions - --> $DIR/intrinsic_without_const_stab_fail.rs:12:14 +error[E0015]: cannot call non-const fn `<() as Foo>::foo` in constant functions + --> $DIR/const_closure-const_trait_impl-ice-113381.rs:14:22 | -LL | unsafe { copy(src, dst, count) } - | ^^^^^^^^^^^^^^^^^^^^^ +LL | (const || { (()).foo() })(); + | ^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/effect-param-infer.rs b/tests/ui/traits/const-traits/effects/effect-param-infer.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/effect-param-infer.rs rename to tests/ui/traits/const-traits/effects/effect-param-infer.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs b/tests/ui/traits/const-traits/effects/fallback.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/fallback.rs rename to tests/ui/traits/const-traits/effects/fallback.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/group-traits.rs b/tests/ui/traits/const-traits/effects/group-traits.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/group-traits.rs rename to tests/ui/traits/const-traits/effects/group-traits.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs b/tests/ui/traits/const-traits/effects/helloworld.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs rename to tests/ui/traits/const-traits/effects/helloworld.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs similarity index 91% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs rename to tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs index 9a9016de3a0..ab530b109e1 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs +++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs @@ -10,6 +10,7 @@ const fn test() -> impl ~const Fn() { [first, remainder @ ..] => { assert_eq!(first, &b'f'); //~^ ERROR cannot call non-const fn + //~| ERROR cannot call non-const operator } [] => panic!(), } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr similarity index 74% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr rename to tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr index 526746eec73..5b0d5a8bb1d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr +++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr @@ -23,19 +23,28 @@ error: using `#![feature(effects)]` without enabling next trait solver globally = help: use `-Znext-solver` to enable error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/ice-112822-expected-type-for-param.rs:3:32 + --> $DIR/ice-112822-expected-type-for-param.rs:3:25 | LL | const fn test() -> impl ~const Fn() { - | ^^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/ice-112822-expected-type-for-param.rs:3:32 + --> $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 + | +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[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 | @@ -45,7 +54,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; 1 warning emitted +error: aborting due to 6 previous errors; 1 warning emitted Some errors have detailed explanations: E0015, E0658. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-113375-index-out-of-bounds-generics.rs b/tests/ui/traits/const-traits/effects/ice-113375-index-out-of-bounds-generics.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-113375-index-out-of-bounds-generics.rs rename to tests/ui/traits/const-traits/effects/ice-113375-index-out-of-bounds-generics.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs b/tests/ui/traits/const-traits/effects/infer-fallback.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/infer-fallback.rs rename to tests/ui/traits/const-traits/effects/infer-fallback.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs b/tests/ui/traits/const-traits/effects/minicore.rs similarity index 90% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs rename to tests/ui/traits/const-traits/effects/minicore.rs index 1c3c66bc3ce..1f0d22eeb38 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs +++ b/tests/ui/traits/const-traits/effects/minicore.rs @@ -137,12 +137,12 @@ macro_rules! impl_fn_mut_tuple { //impl_fn_mut_tuple!(A B C D); //impl_fn_mut_tuple!(A B C D E); -#[lang = "receiver"] -trait Receiver {} +#[lang = "legacy_receiver"] +trait LegacyReceiver {} -impl Receiver for &T {} +impl LegacyReceiver for &T {} -impl Receiver for &mut T {} +impl LegacyReceiver for &mut T {} #[lang = "destruct"] #[const_trait] @@ -454,7 +454,7 @@ impl /* const */ Deref for Option { } } -impl Receiver for Pin

{} +impl LegacyReceiver for Pin

{} impl Clone for RefCell { fn clone(&self) -> RefCell { @@ -515,7 +515,7 @@ trait StructuralPartialEq {} const fn drop(_: T) {} -#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")] +#[rustc_const_stable_indirect] #[rustc_intrinsic_must_be_overridden] #[rustc_intrinsic] const fn const_eval_select( @@ -536,35 +536,3 @@ fn test_const_eval_select() { const_eval_select((), const_fn, rt_fn); } - -mod effects { - use super::Sized; - - #[lang = "EffectsNoRuntime"] - pub struct NoRuntime; - #[lang = "EffectsMaybe"] - pub struct Maybe; - #[lang = "EffectsRuntime"] - pub struct Runtime; - - #[lang = "EffectsCompat"] - pub trait Compat<#[rustc_runtime] const RUNTIME: bool> {} - - impl Compat for NoRuntime {} - impl Compat for Runtime {} - impl<#[rustc_runtime] const RUNTIME: bool> Compat for Maybe {} - - #[lang = "EffectsTyCompat"] - #[marker] - pub trait TyCompat {} - - impl TyCompat for T {} - impl TyCompat for Maybe {} - impl TyCompat for T {} - - #[lang = "EffectsIntersection"] - pub trait Intersection { - #[lang = "EffectsIntersectionOutput"] - type Output: ?Sized; - } -} diff --git a/tests/ui/traits/const-traits/effects/minicore.stderr b/tests/ui/traits/const-traits/effects/minicore.stderr new file mode 100644 index 00000000000..568d98cfe87 --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore.stderr @@ -0,0 +1,13 @@ +error: the compiler unexpectedly panicked. this is a bug. + +query stack during panic: +#0 [typeck] type-checking `Clone::clone_from` +#1 [analysis] running analysis passes on this crate +end of query stack + +error: the compiler unexpectedly panicked. this is a bug. + +query stack during panic: +#0 [typeck] type-checking `test_const_eval_select` +#1 [analysis] running analysis passes on this crate +end of query stack diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs b/tests/ui/traits/const-traits/effects/mismatched_generic_args.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs rename to tests/ui/traits/const-traits/effects/mismatched_generic_args.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr b/tests/ui/traits/const-traits/effects/mismatched_generic_args.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr rename to tests/ui/traits/const-traits/effects/mismatched_generic_args.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.rs b/tests/ui/traits/const-traits/effects/no-explicit-const-params-cross-crate.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.rs rename to tests/ui/traits/const-traits/effects/no-explicit-const-params-cross-crate.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr b/tests/ui/traits/const-traits/effects/no-explicit-const-params-cross-crate.stderr similarity index 82% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr rename to tests/ui/traits/const-traits/effects/no-explicit-const-params-cross-crate.stderr index 8c591edac54..eea6a06c1c8 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr +++ b/tests/ui/traits/const-traits/effects/no-explicit-const-params-cross-crate.stderr @@ -16,17 +16,15 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/no-explicit-const-params-cross-crate.rs:16:12 | LL | <() as Bar>::bar(); - | ^^^ expected 0 generic arguments + | ^^^------- help: remove the unnecessary generics + | | + | expected 0 generic arguments | note: trait defined here, with 0 generic parameters --> $DIR/auxiliary/cross-crate.rs:8:11 | LL | pub trait Bar { | ^^^ -help: replace the generic bound with the associated type - | -LL | <() as Bar< = false>>::bar(); - | + error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied --> $DIR/no-explicit-const-params-cross-crate.rs:7:5 @@ -46,17 +44,15 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/no-explicit-const-params-cross-crate.rs:9:12 | LL | <() as Bar>::bar(); - | ^^^ expected 0 generic arguments + | ^^^------ help: remove the unnecessary generics + | | + | expected 0 generic arguments | note: trait defined here, with 0 generic parameters --> $DIR/auxiliary/cross-crate.rs:8:11 | LL | pub trait Bar { | ^^^ -help: replace the generic bound with the associated type - | -LL | <() as Bar< = true>>::bar(); - | + error: aborting due to 4 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.rs b/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs similarity index 95% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.rs rename to tests/ui/traits/const-traits/effects/no-explicit-const-params.rs index 84f5f2803e1..b08aba9acbc 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.rs +++ b/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs @@ -23,5 +23,4 @@ const FOO: () = { //~^ ERROR: function takes 0 generic arguments but 1 generic argument was supplied <() as Bar>::bar(); //~^ ERROR: trait takes 0 generic arguments but 1 generic argument was supplied - //~| ERROR: mismatched types }; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr b/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr similarity index 72% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr rename to tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr index cc08114ddb5..a3aa970e94d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr +++ b/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr @@ -30,26 +30,15 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/no-explicit-const-params.rs:24:12 | LL | <() as Bar>::bar(); - | ^^^ expected 0 generic arguments + | ^^^------- help: remove the unnecessary generics + | | + | expected 0 generic arguments | note: trait defined here, with 0 generic parameters --> $DIR/no-explicit-const-params.rs:6:7 | LL | trait Bar { | ^^^ -help: replace the generic bound with the associated type - | -LL | <() as Bar< = false>>::bar(); - | + - -error[E0308]: mismatched types - --> $DIR/no-explicit-const-params.rs:24:5 - | -LL | <() as Bar>::bar(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `false`, found `true` - | - = note: expected constant `false` - found constant `true` error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied --> $DIR/no-explicit-const-params.rs:15:5 @@ -69,19 +58,16 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie --> $DIR/no-explicit-const-params.rs:17:12 | LL | <() as Bar>::bar(); - | ^^^ expected 0 generic arguments + | ^^^------ help: remove the unnecessary generics + | | + | expected 0 generic arguments | note: trait defined here, with 0 generic parameters --> $DIR/no-explicit-const-params.rs:6:7 | LL | trait Bar { | ^^^ -help: replace the generic bound with the associated type - | -LL | <() as Bar< = true>>::bar(); - | + -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 5 previous errors; 1 warning emitted -Some errors have detailed explanations: E0107, E0308. -For more information about an error, try `rustc --explain E0107`. +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs b/tests/ui/traits/const-traits/effects/project.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs rename to tests/ui/traits/const-traits/effects/project.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.rs b/tests/ui/traits/const-traits/effects/span-bug-issue-121418.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.rs rename to tests/ui/traits/const-traits/effects/span-bug-issue-121418.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.stderr b/tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/span-bug-issue-121418.stderr rename to tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.rs similarity index 97% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs rename to tests/ui/traits/const-traits/effects/spec-effectvar-ice.rs index 0508b1c5e26..d29cd93d3fb 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs +++ b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.rs @@ -1,4 +1,3 @@ -//@ check-fail // Fixes #119830 #![feature(effects)] //~ WARN the feature `effects` is incomplete diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr similarity index 86% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr rename to tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr index e97a9615ae1..0cb172a2d14 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr +++ b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr @@ -1,5 +1,5 @@ warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/spec-effectvar-ice.rs:4:12 + --> $DIR/spec-effectvar-ice.rs:3:12 | LL | #![feature(effects)] | ^^^^^^^ @@ -13,7 +13,7 @@ error: using `#![feature(effects)]` without enabling next trait solver globally = help: use `-Znext-solver` to enable error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` - --> $DIR/spec-effectvar-ice.rs:12:15 + --> $DIR/spec-effectvar-ice.rs:11:15 | LL | trait Foo {} | - help: mark `Foo` as const: `#[const_trait]` @@ -25,7 +25,7 @@ LL | impl const Foo for T {} = note: adding a non-const method body in the future would be a breaking change error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` - --> $DIR/spec-effectvar-ice.rs:15:15 + --> $DIR/spec-effectvar-ice.rs:14:15 | LL | trait Foo {} | - help: mark `Foo` as const: `#[const_trait]` @@ -37,25 +37,25 @@ LL | impl const Foo for T where T: const Specialize {} = note: adding a non-const method body in the future would be a breaking change error: `const` can only be applied to `#[const_trait]` traits - --> $DIR/spec-effectvar-ice.rs:15:40 + --> $DIR/spec-effectvar-ice.rs:14:34 | LL | impl const Foo for T where T: const Specialize {} - | ^^^^^^^^^^ + | ^^^^^ error: specialization impl does not specialize any associated items - --> $DIR/spec-effectvar-ice.rs:15:1 + --> $DIR/spec-effectvar-ice.rs:14:1 | LL | impl const Foo for T where T: const Specialize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: impl is a specialization of this impl - --> $DIR/spec-effectvar-ice.rs:12:1 + --> $DIR/spec-effectvar-ice.rs:11:1 | LL | impl const Foo for T {} | ^^^^^^^^^^^^^^^^^^^^^^^ error: cannot specialize on trait `Specialize` - --> $DIR/spec-effectvar-ice.rs:15:34 + --> $DIR/spec-effectvar-ice.rs:14:34 | LL | impl const Foo for T where T: const Specialize {} | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs b/tests/ui/traits/const-traits/effects/trait-fn-const.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs rename to tests/ui/traits/const-traits/effects/trait-fn-const.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr b/tests/ui/traits/const-traits/effects/trait-fn-const.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr rename to tests/ui/traits/const-traits/effects/trait-fn-const.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/with-without-next-solver.coherence.stderr b/tests/ui/traits/const-traits/effects/with-without-next-solver.coherence.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/with-without-next-solver.coherence.stderr rename to tests/ui/traits/const-traits/effects/with-without-next-solver.coherence.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/with-without-next-solver.rs b/tests/ui/traits/const-traits/effects/with-without-next-solver.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/with-without-next-solver.rs rename to tests/ui/traits/const-traits/effects/with-without-next-solver.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/with-without-next-solver.stock.stderr b/tests/ui/traits/const-traits/effects/with-without-next-solver.stock.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/effects/with-without-next-solver.stock.stderr rename to tests/ui/traits/const-traits/effects/with-without-next-solver.stock.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr b/tests/ui/traits/const-traits/feature-gate.gated.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr rename to tests/ui/traits/const-traits/feature-gate.gated.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs b/tests/ui/traits/const-traits/feature-gate.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs rename to tests/ui/traits/const-traits/feature-gate.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr b/tests/ui/traits/const-traits/feature-gate.stock.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr rename to tests/ui/traits/const-traits/feature-gate.stock.stderr diff --git a/tests/ui/traits/const-traits/fn-ptr-lub.rs b/tests/ui/traits/const-traits/fn-ptr-lub.rs new file mode 100644 index 00000000000..0fc32678827 --- /dev/null +++ b/tests/ui/traits/const-traits/fn-ptr-lub.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +#![feature(const_trait_impl, effects)] +//~^ WARN the feature `effects` is incomplete + +const fn foo() {} +const fn bar() {} +fn baz() {} + +const fn caller(branch: bool) { + let mut x = if branch { + foo + } else { + bar + }; + x = baz; +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/fn-ptr-lub.stderr b/tests/ui/traits/const-traits/fn-ptr-lub.stderr new file mode 100644 index 00000000000..b333311b660 --- /dev/null +++ b/tests/ui/traits/const-traits/fn-ptr-lub.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/fn-ptr-lub.rs:4:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/function-pointer-does-not-require-const.rs b/tests/ui/traits/const-traits/function-pointer-does-not-require-const.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/function-pointer-does-not-require-const.rs rename to tests/ui/traits/const-traits/function-pointer-does-not-require-const.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/gate.rs b/tests/ui/traits/const-traits/gate.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/gate.rs rename to tests/ui/traits/const-traits/gate.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/gate.stderr b/tests/ui/traits/const-traits/gate.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/gate.stderr rename to tests/ui/traits/const-traits/gate.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.rs b/tests/ui/traits/const-traits/generic-bound.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.rs rename to tests/ui/traits/const-traits/generic-bound.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr b/tests/ui/traits/const-traits/generic-bound.stderr similarity index 87% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr rename to tests/ui/traits/const-traits/generic-bound.stderr index 2baac1d2a16..0444c319577 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr +++ b/tests/ui/traits/const-traits/generic-bound.stderr @@ -14,10 +14,6 @@ LL | arg + arg | ^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error: aborting due to 2 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.rs b/tests/ui/traits/const-traits/hir-const-check.rs similarity index 62% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.rs rename to tests/ui/traits/const-traits/hir-const-check.rs index f5fb0fd516a..0ffd60682b0 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.rs +++ b/tests/ui/traits/const-traits/hir-const-check.rs @@ -1,3 +1,5 @@ +//@ compile-flags: -Znext-solver + // Regression test for #69615. #![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete @@ -10,6 +12,8 @@ pub trait MyTrait { impl const MyTrait for () { fn method(&self) -> Option<()> { Some(())?; //~ ERROR `?` is not allowed in a `const fn` + //~^ ERROR `?` cannot determine the branch of `Option<()>` in constant functions + //~| ERROR `?` cannot convert from residual of `Option<()>` in constant functions None } } diff --git a/tests/ui/traits/const-traits/hir-const-check.stderr b/tests/ui/traits/const-traits/hir-const-check.stderr new file mode 100644 index 00000000000..a22ac2c9739 --- /dev/null +++ b/tests/ui/traits/const-traits/hir-const-check.stderr @@ -0,0 +1,43 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/hir-const-check.rs:5:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0658]: `?` is not allowed in a `const fn` + --> $DIR/hir-const-check.rs:14:9 + | +LL | Some(())?; + | ^^^^^^^^^ + | + = note: see issue #74935 for more information + = help: add `#![feature(const_try)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0015]: `?` cannot determine the branch of `Option<()>` in constant functions + --> $DIR/hir-const-check.rs:14:9 + | +LL | Some(())?; + | ^^^^^^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/option.rs:LL:COL + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error[E0015]: `?` cannot convert from residual of `Option<()>` in constant functions + --> $DIR/hir-const-check.rs:14:9 + | +LL | Some(())?; + | ^^^^^^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/option.rs:LL:COL + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 3 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0015, E0658. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-119717-constant-lifetime.rs b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-119717-constant-lifetime.rs rename to tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-119717-constant-lifetime.stderr b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-119717-constant-lifetime.stderr rename to tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs b/tests/ui/traits/const-traits/ice-120503-async-const-method.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs rename to tests/ui/traits/const-traits/ice-120503-async-const-method.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr b/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr rename to tests/ui/traits/const-traits/ice-120503-async-const-method.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-121536-const-method.rs b/tests/ui/traits/const-traits/ice-121536-const-method.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-121536-const-method.rs rename to tests/ui/traits/const-traits/ice-121536-const-method.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-121536-const-method.stderr b/tests/ui/traits/const-traits/ice-121536-const-method.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-121536-const-method.stderr rename to tests/ui/traits/const-traits/ice-121536-const-method.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.rs b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs similarity index 76% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.rs rename to tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs index 64634e7b7ac..29f40604747 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-123664-unexpected-bound-var.rs +++ b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs @@ -3,5 +3,6 @@ const fn with_positive() {} //~^ ERROR `~const` can only be applied to `#[const_trait]` traits +//~| ERROR `~const` can only be applied to `#[const_trait]` traits pub fn main() {} diff --git a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr new file mode 100644 index 00000000000..dcb7dd7a142 --- /dev/null +++ b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr @@ -0,0 +1,21 @@ +error: using `#![feature(effects)]` without enabling next trait solver globally + | + = note: the next trait solver must be enabled globally for the effects feature to work correctly + = help: use `-Znext-solver` to enable + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/ice-123664-unexpected-bound-var.rs:4:27 + | +LL | const fn with_positive() {} + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/ice-123664-unexpected-bound-var.rs:4:27 + | +LL | const fn with_positive() {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-124857-combine-effect-const-infer-vars.rs b/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-124857-combine-effect-const-infer-vars.rs rename to tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-124857-combine-effect-const-infer-vars.stderr b/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-124857-combine-effect-const-infer-vars.stderr rename to tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.rs b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs similarity index 79% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.rs rename to tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs index 717c0e7c088..da97a0e70ed 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.rs +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs @@ -18,6 +18,8 @@ impl const Try for TryMe { const fn t() -> TryMe { TryMe?; + //~^ ERROR `?` cannot determine the branch of `TryMe` in constant functions + //~| ERROR `?` cannot convert from residual of `TryMe` in constant functions TryMe } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr similarity index 71% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.stderr rename to tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr index e49436c8f0f..0ca16a1be40 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-126148-failed-to-normalize.stderr +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr @@ -38,6 +38,23 @@ LL | impl const Try for TryMe { = help: implement the missing item: `fn from_output(_: ::Output) -> Self { todo!() }` = help: implement the missing item: `fn branch(self) -> ControlFlow<::Residual, ::Output> { todo!() }` -error: aborting due to 5 previous errors +error[E0015]: `?` cannot determine the branch of `TryMe` in constant functions + --> $DIR/ice-126148-failed-to-normalize.rs:20:5 + | +LL | TryMe?; + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -For more information about this error, try `rustc --explain E0046`. +error[E0015]: `?` cannot convert from residual of `TryMe` in constant functions + --> $DIR/ice-126148-failed-to-normalize.rs:20:5 + | +LL | TryMe?; + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0015, E0046. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-tilde-const-trait.rs b/tests/ui/traits/const-traits/impl-tilde-const-trait.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/impl-tilde-const-trait.rs rename to tests/ui/traits/const-traits/impl-tilde-const-trait.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-tilde-const-trait.stderr b/tests/ui/traits/const-traits/impl-tilde-const-trait.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/impl-tilde-const-trait.stderr rename to tests/ui/traits/const-traits/impl-tilde-const-trait.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs b/tests/ui/traits/const-traits/impl-with-default-fn-fail.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs rename to tests/ui/traits/const-traits/impl-with-default-fn-fail.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr b/tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr rename to tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs b/tests/ui/traits/const-traits/impl-with-default-fn-pass.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs rename to tests/ui/traits/const-traits/impl-with-default-fn-pass.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs b/tests/ui/traits/const-traits/inherent-impl-const-bounds.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs rename to tests/ui/traits/const-traits/inherent-impl-const-bounds.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl.rs b/tests/ui/traits/const-traits/inherent-impl.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl.rs rename to tests/ui/traits/const-traits/inherent-impl.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl.stderr b/tests/ui/traits/const-traits/inherent-impl.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/inherent-impl.stderr rename to tests/ui/traits/const-traits/inherent-impl.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/inline-incorrect-early-bound-in-ctfe.rs b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.rs similarity index 91% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/inline-incorrect-early-bound-in-ctfe.rs rename to tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.rs index e3adcce17b4..8638c4bbd7f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/inline-incorrect-early-bound-in-ctfe.rs +++ b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.rs @@ -25,6 +25,7 @@ impl Trait for () { const fn foo() { ().foo(); + //~^ ERROR cannot call non-const fn `<() as Trait>::foo` in constant functions } const UWU: () = foo(); diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/inline-incorrect-early-bound-in-ctfe.stderr b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.stderr similarity index 60% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/inline-incorrect-early-bound-in-ctfe.stderr rename to tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.stderr index 2e7801c0b8a..096b00dd302 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/inline-incorrect-early-bound-in-ctfe.stderr +++ b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.stderr @@ -16,6 +16,15 @@ LL | fn foo(self); LL | fn foo(self) { | ^ found 1 type parameter -error: aborting due to 1 previous error; 1 warning emitted +error[E0015]: cannot call non-const fn `<() as Trait>::foo` in constant functions + --> $DIR/inline-incorrect-early-bound-in-ctfe.rs:27:8 + | +LL | ().foo(); + | ^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -For more information about this error, try `rustc --explain E0049`. +error: aborting due to 2 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0015, E0049. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs b/tests/ui/traits/const-traits/issue-100222.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs rename to tests/ui/traits/const-traits/issue-100222.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102156.rs b/tests/ui/traits/const-traits/issue-102156.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102156.rs rename to tests/ui/traits/const-traits/issue-102156.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102156.stderr b/tests/ui/traits/const-traits/issue-102156.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102156.stderr rename to tests/ui/traits/const-traits/issue-102156.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.rs b/tests/ui/traits/const-traits/issue-102985.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.rs rename to tests/ui/traits/const-traits/issue-102985.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr b/tests/ui/traits/const-traits/issue-102985.stderr similarity index 80% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr rename to tests/ui/traits/const-traits/issue-102985.stderr index 8401d1bd4f6..7c5c5acf207 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-102985.stderr +++ b/tests/ui/traits/const-traits/issue-102985.stderr @@ -6,10 +6,6 @@ LL | n => n(), | = note: closures need an RFC before allowed to be called in constants = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-103677.rs b/tests/ui/traits/const-traits/issue-103677.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-103677.rs rename to tests/ui/traits/const-traits/issue-103677.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs b/tests/ui/traits/const-traits/issue-79450.rs similarity index 90% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs rename to tests/ui/traits/const-traits/issue-79450.rs index b8b9e07b3bd..cdefebc87d6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs +++ b/tests/ui/traits/const-traits/issue-79450.rs @@ -1,6 +1,5 @@ //@ compile-flags: -Znext-solver #![allow(incomplete_features)] -#![feature(const_fmt_arguments_new)] #![feature(const_trait_impl, effects)] #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr b/tests/ui/traits/const-traits/issue-79450.stderr similarity index 93% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr rename to tests/ui/traits/const-traits/issue-79450.stderr index 9e6348d37ed..49f380c1a2b 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr +++ b/tests/ui/traits/const-traits/issue-79450.stderr @@ -1,5 +1,5 @@ error[E0015]: cannot call non-const fn `_print` in constant functions - --> $DIR/issue-79450.rs:11:9 + --> $DIR/issue-79450.rs:10:9 | LL | println!("lul"); | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.rs b/tests/ui/traits/const-traits/issue-88155.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.rs rename to tests/ui/traits/const-traits/issue-88155.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr b/tests/ui/traits/const-traits/issue-88155.stderr similarity index 78% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr rename to tests/ui/traits/const-traits/issue-88155.stderr index afe1ea3b1b7..157b54214fa 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-88155.stderr +++ b/tests/ui/traits/const-traits/issue-88155.stderr @@ -5,10 +5,6 @@ LL | T::assoc() | ^^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.rs b/tests/ui/traits/const-traits/issue-92111.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.rs rename to tests/ui/traits/const-traits/issue-92111.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.stderr b/tests/ui/traits/const-traits/issue-92111.stderr similarity index 60% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.stderr rename to tests/ui/traits/const-traits/issue-92111.stderr index ecc994a3fe6..51c6a22b43b 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92111.stderr +++ b/tests/ui/traits/const-traits/issue-92111.stderr @@ -1,8 +1,16 @@ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/issue-92111.rs:20:22 + --> $DIR/issue-92111.rs:20:15 | LL | const fn a(t: T) {} - | ^^^^^^^^ + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/issue-92111.rs:20:15 + | +LL | const fn a(t: T) {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/issue-92111.rs:20:32 @@ -12,6 +20,6 @@ LL | const fn a(t: T) {} | | | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs b/tests/ui/traits/const-traits/issue-92230-wf-super-trait-env.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs rename to tests/ui/traits/const-traits/issue-92230-wf-super-trait-env.rs diff --git a/tests/ui/traits/const-traits/item-bound-entailment-fails.rs b/tests/ui/traits/const-traits/item-bound-entailment-fails.rs new file mode 100644 index 00000000000..42799e3700c --- /dev/null +++ b/tests/ui/traits/const-traits/item-bound-entailment-fails.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -Znext-solver +#![feature(const_trait_impl, effects)] +//~^ WARN the feature `effects` is incomplete + +#[const_trait] trait Foo { + type Assoc: ~const Bar + where + T: ~const Bar; +} + +#[const_trait] trait Bar {} +struct N(T); +impl Bar for N where T: Bar {} +struct C(T); +impl const Bar for C where T: ~const Bar {} + +impl const Foo for u32 { + type Assoc = N + //~^ ERROR the trait bound `N: ~const Bar` is not satisfied + where + T: ~const Bar; +} + +impl const Foo for i32 { + type Assoc = C + //~^ ERROR the trait bound `T: ~const Bar` is not satisfied + where + T: Bar; +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr new file mode 100644 index 00000000000..054a8ac7577 --- /dev/null +++ b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr @@ -0,0 +1,36 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/item-bound-entailment-fails.rs:2:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the trait bound `N: ~const Bar` is not satisfied + --> $DIR/item-bound-entailment-fails.rs:18:21 + | +LL | type Assoc = N + | ^^^^ + | +note: required by a bound in `Foo::Assoc` + --> $DIR/item-bound-entailment-fails.rs:6:20 + | +LL | type Assoc: ~const Bar + | ^^^^^^ required by this bound in `Foo::Assoc` + +error[E0277]: the trait bound `T: ~const Bar` is not satisfied + --> $DIR/item-bound-entailment-fails.rs:25:21 + | +LL | type Assoc = C + | ^^^^ + | +note: required by a bound in `Foo::Assoc` + --> $DIR/item-bound-entailment-fails.rs:6:20 + | +LL | type Assoc: ~const Bar + | ^^^^^^ required by this bound in `Foo::Assoc` + +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/traits/const-traits/item-bound-entailment.rs b/tests/ui/traits/const-traits/item-bound-entailment.rs new file mode 100644 index 00000000000..3670eabd66c --- /dev/null +++ b/tests/ui/traits/const-traits/item-bound-entailment.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +#![feature(const_trait_impl, effects)] +//~^ WARN the feature `effects` is incomplete + +#[const_trait] trait Foo { + type Assoc: ~const Bar + where + T: ~const Bar; +} + +#[const_trait] trait Bar {} +struct N(T); +impl Bar for N where T: Bar {} +struct C(T); +impl const Bar for C where T: ~const Bar {} + +impl Foo for u32 { + type Assoc = N + where + T: Bar; +} + +impl const Foo for i32 { + type Assoc = C + where + T: ~const Bar; +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/item-bound-entailment.stderr b/tests/ui/traits/const-traits/item-bound-entailment.stderr new file mode 100644 index 00000000000..b4a4ebdbee2 --- /dev/null +++ b/tests/ui/traits/const-traits/item-bound-entailment.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/item-bound-entailment.rs:4:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr b/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr similarity index 83% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr rename to tests/ui/traits/const-traits/match-non-const-eq.gated.stderr index c7d21151661..89e59e5db6e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.gated.stderr +++ b/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr @@ -6,10 +6,6 @@ LL | "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in | = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.rs b/tests/ui/traits/const-traits/match-non-const-eq.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.rs rename to tests/ui/traits/const-traits/match-non-const-eq.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr b/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr similarity index 81% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr rename to tests/ui/traits/const-traits/match-non-const-eq.stock.stderr index 0f5ecac3891..89e59e5db6e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/match-non-const-eq.stock.stderr +++ b/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr @@ -6,10 +6,6 @@ LL | "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in | = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-bare-trait-objects-const-trait-bounds.rs b/tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-bare-trait-objects-const-trait-bounds.rs rename to tests/ui/traits/const-traits/mbe-bare-trait-objects-const-trait-bounds.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs b/tests/ui/traits/const-traits/mbe-const-trait-bound-theoretical-regression.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs rename to tests/ui/traits/const-traits/mbe-const-trait-bound-theoretical-regression.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.stderr b/tests/ui/traits/const-traits/mbe-const-trait-bound-theoretical-regression.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.stderr rename to tests/ui/traits/const-traits/mbe-const-trait-bound-theoretical-regression.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs b/tests/ui/traits/const-traits/mbe-dyn-const-2015.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs rename to tests/ui/traits/const-traits/mbe-dyn-const-2015.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs rename to tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr rename to tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/nested-closure.rs b/tests/ui/traits/const-traits/nested-closure.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/nested-closure.rs rename to tests/ui/traits/const-traits/nested-closure.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.rs b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.rs rename to tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr similarity index 81% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr rename to tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr index c362a1077e3..97ad83130d4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr @@ -5,10 +5,6 @@ LL | (const || { (()).foo() })(); | ^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs rename to tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs diff --git a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr new file mode 100644 index 00000000000..837effb7ca4 --- /dev/null +++ b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr @@ -0,0 +1,25 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/non-const-op-in-closure-in-const.rs:10:44 + | +LL | impl const Convert for A where B: ~const From { + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/non-const-op-in-closure-in-const.rs:10:44 + | +LL | impl const Convert for A where B: ~const From { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0015]: cannot call non-const fn `>::from` in constant functions + --> $DIR/non-const-op-in-closure-in-const.rs:12:9 + | +LL | B::from(self) + | ^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/predicate-entailment-fails.rs b/tests/ui/traits/const-traits/predicate-entailment-fails.rs new file mode 100644 index 00000000000..5d6109bfad3 --- /dev/null +++ b/tests/ui/traits/const-traits/predicate-entailment-fails.rs @@ -0,0 +1,43 @@ +//@ compile-flags: -Znext-solver +#![feature(const_trait_impl, effects)] +//~^ WARN the feature `effects` is incomplete + +#[const_trait] trait Bar {} +impl const Bar for () {} + + +#[const_trait] trait TildeConst { + type Bar where T: ~const Bar; + + fn foo() where T: ~const Bar; +} +impl TildeConst for () { + type Bar = () where T: const Bar; + //~^ ERROR impl has stricter requirements than trait + + fn foo() where T: const Bar {} + //~^ ERROR impl has stricter requirements than trait +} + + +#[const_trait] trait NeverConst { + type Bar where T: Bar; + + fn foo() where T: Bar; +} +impl NeverConst for i32 { + type Bar = () where T: const Bar; + //~^ ERROR impl has stricter requirements than trait + + fn foo() where T: const Bar {} + //~^ ERROR impl has stricter requirements than trait +} +impl const NeverConst for u32 { + type Bar = () where T: ~const Bar; + //~^ ERROR impl has stricter requirements than trait + + fn foo() where T: ~const Bar {} + //~^ ERROR impl has stricter requirements than trait +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/predicate-entailment-fails.stderr b/tests/ui/traits/const-traits/predicate-entailment-fails.stderr new file mode 100644 index 00000000000..c50009e9b8c --- /dev/null +++ b/tests/ui/traits/const-traits/predicate-entailment-fails.stderr @@ -0,0 +1,66 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/predicate-entailment-fails.rs:2:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0276]: impl has stricter requirements than trait + --> $DIR/predicate-entailment-fails.rs:15:31 + | +LL | type Bar where T: ~const Bar; + | ----------- definition of `Bar` from trait +... +LL | type Bar = () where T: const Bar; + | ^^^^^ impl has extra requirement `T: const Bar` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/predicate-entailment-fails.rs:18:26 + | +LL | fn foo() where T: ~const Bar; + | -------------------------------- definition of `foo` from trait +... +LL | fn foo() where T: const Bar {} + | ^^^^^ impl has extra requirement `T: const Bar` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/predicate-entailment-fails.rs:29:31 + | +LL | type Bar where T: Bar; + | ----------- definition of `Bar` from trait +... +LL | type Bar = () where T: const Bar; + | ^^^^^ impl has extra requirement `T: const Bar` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/predicate-entailment-fails.rs:32:26 + | +LL | fn foo() where T: Bar; + | ------------------------- definition of `foo` from trait +... +LL | fn foo() where T: const Bar {} + | ^^^^^ impl has extra requirement `T: const Bar` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/predicate-entailment-fails.rs:36:31 + | +LL | type Bar where T: Bar; + | ----------- definition of `Bar` from trait +... +LL | type Bar = () where T: ~const Bar; + | ^^^^^^ impl has extra requirement `T: ~const Bar` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/predicate-entailment-fails.rs:39:26 + | +LL | fn foo() where T: Bar; + | ------------------------- definition of `foo` from trait +... +LL | fn foo() where T: ~const Bar {} + | ^^^^^^ impl has extra requirement `T: ~const Bar` + +error: aborting due to 6 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0276`. diff --git a/tests/ui/traits/const-traits/predicate-entailment-passes.rs b/tests/ui/traits/const-traits/predicate-entailment-passes.rs new file mode 100644 index 00000000000..b660329151b --- /dev/null +++ b/tests/ui/traits/const-traits/predicate-entailment-passes.rs @@ -0,0 +1,39 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +#![feature(const_trait_impl, effects)] +//~^ WARN the feature `effects` is incomplete + +#[const_trait] trait Bar {} +impl const Bar for () {} + + +#[const_trait] trait TildeConst { + type Bar where T: ~const Bar; + + fn foo() where T: ~const Bar; +} +impl TildeConst for () { + type Bar = () where T: Bar; + + fn foo() where T: Bar {} +} + + +#[const_trait] trait AlwaysConst { + type Bar where T: const Bar; + + fn foo() where T: const Bar; +} +impl AlwaysConst for i32 { + type Bar = () where T: Bar; + + fn foo() where T: Bar {} +} +impl const AlwaysConst for u32 { + type Bar = () where T: ~const Bar; + + fn foo() where T: ~const Bar {} +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/predicate-entailment-passes.stderr b/tests/ui/traits/const-traits/predicate-entailment-passes.stderr new file mode 100644 index 00000000000..dcaeea73b58 --- /dev/null +++ b/tests/ui/traits/const-traits/predicate-entailment-passes.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/predicate-entailment-passes.rs:4:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs rename to tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs diff --git a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr new file mode 100644 index 00000000000..bffc60c65fc --- /dev/null +++ b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr @@ -0,0 +1,11 @@ +error: cannot specialize on const impl with non-const impl + --> $DIR/const-default-bound-non-const-specialized-bound.rs:28:1 + | +LL | / impl Bar for T +LL | | where +LL | | T: Foo, //FIXME ~ ERROR missing `~const` qualifier +LL | | T: Specialize, + | |__________________^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs b/tests/ui/traits/const-traits/specialization/const-default-const-specialized.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.rs rename to tests/ui/traits/const-traits/specialization/const-default-const-specialized.rs diff --git a/tests/ui/traits/const-traits/specialization/const-default-const-specialized.stderr b/tests/ui/traits/const-traits/specialization/const-default-const-specialized.stderr new file mode 100644 index 00000000000..f127268d2a1 --- /dev/null +++ b/tests/ui/traits/const-traits/specialization/const-default-const-specialized.stderr @@ -0,0 +1,15 @@ +error[E0015]: cannot call non-const fn `::value` in constant functions + --> $DIR/const-default-const-specialized.rs:16:5 + | +LL | T::value() + | ^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.rs rename to tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-impl-non-const-specialized-impl.stderr rename to tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.rs b/tests/ui/traits/const-traits/specialization/default-keyword.rs similarity index 80% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.rs rename to tests/ui/traits/const-traits/specialization/default-keyword.rs index d9ffd237dce..bc45a70777c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.rs +++ b/tests/ui/traits/const-traits/specialization/default-keyword.rs @@ -1,5 +1,4 @@ -//@ known-bug: #110395 -// FIXME check-pass +//@ check-pass #![feature(const_trait_impl)] #![feature(min_specialization)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs b/tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs similarity index 93% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs rename to tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs index 219e5f3a600..d80370aee82 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs +++ b/tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs @@ -1,7 +1,6 @@ // Tests that `~const` trait bounds can be used to specialize const trait impls. -//@ known-bug: #110395 -// FIXME check-pass +//@ check-pass #![feature(const_trait_impl)] #![feature(rustc_attrs)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs b/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs similarity index 95% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs rename to tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs index 7514baa2fd5..d97469edaf9 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs +++ b/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs @@ -2,8 +2,7 @@ // `T: Foo` in the default impl for the purposes of specialization (i.e., it // does not think that the user is attempting to specialize on trait `Foo`). -//@ known-bug: #110395 -// FIXME check-pass +//@ check-pass #![feature(rustc_attrs)] #![feature(min_specialization)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs b/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.rs rename to tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.rs diff --git a/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.stderr b/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.stderr new file mode 100644 index 00000000000..a4095d7e8ce --- /dev/null +++ b/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.stderr @@ -0,0 +1,15 @@ +error[E0015]: cannot call non-const fn `::value` in constant functions + --> $DIR/non-const-default-const-specialized.rs:15:5 + | +LL | T::value() + | ^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs b/tests/ui/traits/const-traits/specializing-constness-2.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.rs rename to tests/ui/traits/const-traits/specializing-constness-2.rs diff --git a/tests/ui/traits/const-traits/specializing-constness-2.stderr b/tests/ui/traits/const-traits/specializing-constness-2.stderr new file mode 100644 index 00000000000..8e6f6945a1b --- /dev/null +++ b/tests/ui/traits/const-traits/specializing-constness-2.stderr @@ -0,0 +1,15 @@ +error[E0015]: cannot call non-const fn `::a` in constant functions + --> $DIR/specializing-constness-2.rs:27:5 + | +LL | ::a(); + | ^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs b/tests/ui/traits/const-traits/specializing-constness.rs similarity index 90% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs rename to tests/ui/traits/const-traits/specializing-constness.rs index 4501a218ad7..3aabaf137d5 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.rs +++ b/tests/ui/traits/const-traits/specializing-constness.rs @@ -22,8 +22,6 @@ impl const A for T { impl A for T { //~^ ERROR: cannot specialize -//~| ERROR: cannot specialize -//~| ERROR: cannot specialize //FIXME(effects) ~| ERROR: missing `~const` qualifier fn a() -> u32 { 3 diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr b/tests/ui/traits/const-traits/specializing-constness.stderr similarity index 70% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr rename to tests/ui/traits/const-traits/specializing-constness.stderr index 90721af8e5a..e8c4fb0f0c7 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness.stderr +++ b/tests/ui/traits/const-traits/specializing-constness.stderr @@ -18,17 +18,5 @@ error: cannot specialize on const impl with non-const impl LL | impl A for T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: cannot specialize on trait `Compat` - --> $DIR/specializing-constness.rs:23:16 - | -LL | impl A for T { - | ^^^ - -error: cannot specialize on trait `Compat` - --> $DIR/specializing-constness.rs:23:9 - | -LL | impl A for T { - | ^^^^ - -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api-user-crate.rs b/tests/ui/traits/const-traits/staged-api-user-crate.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api-user-crate.rs rename to tests/ui/traits/const-traits/staged-api-user-crate.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api-user-crate.stderr b/tests/ui/traits/const-traits/staged-api-user-crate.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api-user-crate.stderr rename to tests/ui/traits/const-traits/staged-api-user-crate.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs b/tests/ui/traits/const-traits/staged-api.rs similarity index 51% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs rename to tests/ui/traits/const-traits/staged-api.rs index f87e723472a..59fe6d52d5d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs +++ b/tests/ui/traits/const-traits/staged-api.rs @@ -2,6 +2,7 @@ //@ compile-flags: -Znext-solver #![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file. +#![cfg_attr(unstable, feature(local_feature))] #![feature(const_trait_impl, effects)] #![allow(incomplete_features)] #![feature(staged_api)] @@ -16,8 +17,8 @@ use staged_api::*; pub struct Foo; #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))] -#[cfg_attr(stable, rustc_const_stable(feature = "foo", since = "1.0.0"))] +#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))] +#[cfg_attr(stable, rustc_const_stable(feature = "local_feature", since = "1.0.0"))] impl const MyTrait for Foo { //[stable]~^ ERROR trait implementations cannot be const stable yet fn func() {} @@ -32,32 +33,43 @@ fn non_const_context() { #[unstable(feature = "none", issue = "none")] const fn const_context() { Unstable::func(); - //[stable]~^ ERROR not yet stable as a const fn + //[unstable]~^ ERROR cannot use `#[feature(unstable)]` + //[stable]~^^ ERROR not yet stable as a const fn Foo::func(); - //[unstable]~^ ERROR not yet stable as a const fn - // ^ fails, because the `foo` feature is not active + //[unstable]~^ ERROR cannot use `#[feature(local_feature)]` + //[stable]~^^ cannot be (indirectly) exposed to stable + // We get the error on `stable` since this is a trait function. + Unstable2::func(); + //~^ ERROR not yet stable as a const fn + // ^ fails, because the `unstable2` feature is not active } #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))] +#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))] pub const fn const_context_not_const_stable() { //[stable]~^ ERROR function has missing const stability attribute Unstable::func(); //[stable]~^ ERROR not yet stable as a const fn Foo::func(); - //[unstable]~^ ERROR not yet stable as a const fn - // ^ fails, because the `foo` feature is not active + //[stable]~^ cannot be (indirectly) exposed to stable + // We get the error on `stable` since this is a trait function. + Unstable2::func(); + //~^ ERROR not yet stable as a const fn + // ^ fails, because the `unstable2` feature is not active } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "cheese", since = "1.0.0")] const fn stable_const_context() { Unstable::func(); - //~^ ERROR not yet stable as a const fn + //[unstable]~^ ERROR cannot use `#[feature(unstable)]` + //[stable]~^^ ERROR not yet stable as a const fn Foo::func(); - //[unstable]~^ ERROR not yet stable as a const fn + //[unstable]~^ ERROR cannot use `#[feature(local_feature)]` + //[stable]~^^ cannot be (indirectly) exposed to stable + // We get the error on `stable` since this is a trait function. const_context_not_const_stable() - //[unstable]~^ ERROR not yet stable as a const fn + //[unstable]~^ ERROR cannot use `#[feature(local_feature)]` } fn main() {} diff --git a/tests/ui/traits/const-traits/staged-api.stable.stderr b/tests/ui/traits/const-traits/staged-api.stable.stderr new file mode 100644 index 00000000000..40045081f93 --- /dev/null +++ b/tests/ui/traits/const-traits/staged-api.stable.stderr @@ -0,0 +1,89 @@ +error: trait implementations cannot be const stable yet + --> $DIR/staged-api.rs:22:1 + | +LL | / impl const MyTrait for Foo { +LL | | +LL | | fn func() {} +LL | | } + | |_^ + | + = note: see issue #67792 for more information + +error: function has missing const stability attribute + --> $DIR/staged-api.rs:49:1 + | +LL | / pub const fn const_context_not_const_stable() { +LL | | +LL | | Unstable::func(); +LL | | +... | +LL | | // ^ fails, because the `unstable2` feature is not active +LL | | } + | |_^ + +error: `::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:35:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable)]` to the crate attributes to enable + +error: `::func` cannot be (indirectly) exposed to stable + --> $DIR/staged-api.rs:38:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | + = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` + +error: `::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:42:5 + | +LL | Unstable2::func(); + | ^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable2)]` to the crate attributes to enable + +error: `::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:51:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable)]` to the crate attributes to enable + +error: `::func` cannot be (indirectly) exposed to stable + --> $DIR/staged-api.rs:53:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | + = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` + +error: `::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:56:5 + | +LL | Unstable2::func(); + | ^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable2)]` to the crate attributes to enable + +error: `::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:64:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable)]` to the crate attributes to enable + +error: `::func` cannot be (indirectly) exposed to stable + --> $DIR/staged-api.rs:67:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | + = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` + +error: aborting due to 10 previous errors + diff --git a/tests/ui/traits/const-traits/staged-api.unstable.stderr b/tests/ui/traits/const-traits/staged-api.unstable.stderr new file mode 100644 index 00000000000..64b3a8ab19f --- /dev/null +++ b/tests/ui/traits/const-traits/staged-api.unstable.stderr @@ -0,0 +1,108 @@ +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]` + --> $DIR/staged-api.rs:35:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(unstable)] +LL | const fn const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]` + --> $DIR/staged-api.rs:38:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(local_feature)] +LL | const fn const_context() { + | + +error: `::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:42:5 + | +LL | Unstable2::func(); + | ^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable2)]` to the crate attributes to enable + +error: `::func` is not yet stable as a const fn + --> $DIR/staged-api.rs:56:5 + | +LL | Unstable2::func(); + | ^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable2)]` to the crate attributes to enable + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]` + --> $DIR/staged-api.rs:64:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(unstable)] +LL | const fn stable_const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]` + --> $DIR/staged-api.rs:67:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(local_feature)] +LL | const fn stable_const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]` + --> $DIR/staged-api.rs:71:5 + | +LL | const_context_not_const_stable() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(local_feature)] +LL | const fn stable_const_context() { + | + +error: aborting due to 7 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/static-const-trait-bound.rs b/tests/ui/traits/const-traits/static-const-trait-bound.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/static-const-trait-bound.rs rename to tests/ui/traits/const-traits/static-const-trait-bound.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.gated.stderr b/tests/ui/traits/const-traits/std-impl-gate.gated.stderr similarity index 87% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.gated.stderr rename to tests/ui/traits/const-traits/std-impl-gate.gated.stderr index d761fdce4bf..f3b17130761 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.gated.stderr +++ b/tests/ui/traits/const-traits/std-impl-gate.gated.stderr @@ -11,10 +11,6 @@ LL | Default::default() | ^^^^^^^^^^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(effects)]` to the crate attributes to enable - | -LL + #![feature(effects)] - | error: aborting due to 2 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.rs b/tests/ui/traits/const-traits/std-impl-gate.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.rs rename to tests/ui/traits/const-traits/std-impl-gate.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr b/tests/ui/traits/const-traits/std-impl-gate.stock.stderr similarity index 77% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr rename to tests/ui/traits/const-traits/std-impl-gate.stock.stderr index b63ea695fc2..7240b5f4a94 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr +++ b/tests/ui/traits/const-traits/std-impl-gate.stock.stderr @@ -5,10 +5,6 @@ LL | Default::default() | ^^^^^^^^^^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr similarity index 58% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr rename to tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr index 48bb1907be2..8de1bb07e90 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr @@ -11,26 +11,35 @@ LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:12:19 + --> $DIR/super-traits-fail-2.rs:12:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:12:19 + --> $DIR/super-traits-fail-2.rs:12:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-2.rs:12:19 + --> $DIR/super-traits-fail-2.rs:12:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 4 previous errors +error[E0015]: cannot call non-const fn `::a` in constant functions + --> $DIR/super-traits-fail-2.rs:21:7 + | +LL | x.a(); + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr new file mode 100644 index 00000000000..82b306aeff6 --- /dev/null +++ b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr @@ -0,0 +1,49 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-2.rs:12:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-2.rs:12:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-2.rs:12:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-2.rs:12:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-2.rs:12:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0015]: cannot call non-const fn `::a` in constant functions + --> $DIR/super-traits-fail-2.rs:21:7 + | +LL | x.a(); + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/tests/ui/traits/const-traits/super-traits-fail-2.rs similarity index 68% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs rename to tests/ui/traits/const-traits/super-traits-fail-2.rs index 93a6f385e47..1e41d709d6b 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs +++ b/tests/ui/traits/const-traits/super-traits-fail-2.rs @@ -13,11 +13,14 @@ trait Bar: ~const Foo {} //[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]` //[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]` //[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]` -//[yn,nn]~^^^^ ERROR: `~const` is not allowed here +//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]` +//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]` +//[yn,nn]~^^^^^^ ERROR: `~const` is not allowed here const fn foo(x: &T) { x.a(); //[yy,yn]~^ ERROR the trait bound `T: ~const Foo` + //[nn,ny]~^^ ERROR cannot call non-const fn `::a` in constant functions } fn main() {} diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr new file mode 100644 index 00000000000..ec6ca107289 --- /dev/null +++ b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr @@ -0,0 +1,21 @@ +error: `~const` is not allowed here + --> $DIR/super-traits-fail-2.rs:12:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | +note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds + --> $DIR/super-traits-fail-2.rs:12:1 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `T: ~const Foo` is not satisfied + --> $DIR/super-traits-fail-2.rs:21:5 + | +LL | x.a(); + | ^^^^^ + +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/super-traits-fail-2.yy.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.yy.stderr new file mode 100644 index 00000000000..3fa6256abc3 --- /dev/null +++ b/tests/ui/traits/const-traits/super-traits-fail-2.yy.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `T: ~const Foo` is not satisfied + --> $DIR/super-traits-fail-2.rs:21:5 + | +LL | x.a(); + | ^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr similarity index 50% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr rename to tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr index f40583f0ca5..1dd4a2ed5a5 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr @@ -11,32 +11,49 @@ LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:14:19 + --> $DIR/super-traits-fail-3.rs:14:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:14:19 + --> $DIR/super-traits-fail-3.rs:14:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:14:19 + --> $DIR/super-traits-fail-3.rs:14:12 | LL | trait Bar: ~const Foo {} - | ^^^ + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:20:24 + --> $DIR/super-traits-fail-3.rs:22:17 | LL | const fn foo(x: &T) { - | ^^^ + | ^^^^^^ -error: aborting due to 5 previous errors +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:22:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0015]: cannot call non-const fn `::a` in constant functions + --> $DIR/super-traits-fail-3.rs:25:7 + | +LL | x.a(); + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr new file mode 100644 index 00000000000..e619b8bd6ba --- /dev/null +++ b/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr @@ -0,0 +1,49 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:14:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:14:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:14:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:14:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:14:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0015]: cannot call non-const fn `::a` in constant functions + --> $DIR/super-traits-fail-3.rs:25:7 + | +LL | x.a(); + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs b/tests/ui/traits/const-traits/super-traits-fail-3.rs similarity index 66% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs rename to tests/ui/traits/const-traits/super-traits-fail-3.rs index b5643b11700..414337956e2 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs +++ b/tests/ui/traits/const-traits/super-traits-fail-3.rs @@ -15,12 +15,16 @@ trait Bar: ~const Foo {} //[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]` //[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]` //[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]` -//[yn,nn]~^^^^ ERROR: `~const` is not allowed here +//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]` +//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]` +//[yn,nn]~^^^^^^ ERROR: `~const` is not allowed here const fn foo(x: &T) { //[yn,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]` + //[yn,nn]~| ERROR: `~const` can only be applied to `#[const_trait]` x.a(); //[yn]~^ ERROR: the trait bound `T: ~const Foo` is not satisfied + //[nn,ny]~^^ ERROR: cannot call non-const fn `::a` in constant functions } fn main() {} diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr new file mode 100644 index 00000000000..0a36d40d931 --- /dev/null +++ b/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr @@ -0,0 +1,35 @@ +error: `~const` is not allowed here + --> $DIR/super-traits-fail-3.rs:14:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | +note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds + --> $DIR/super-traits-fail-3.rs:14:1 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:22:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:22:17 + | +LL | const fn foo(x: &T) { + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: the trait bound `T: ~const Foo` is not satisfied + --> $DIR/super-traits-fail-3.rs:25:5 + | +LL | x.a(); + | ^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs b/tests/ui/traits/const-traits/super-traits-fail.rs similarity index 92% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs rename to tests/ui/traits/const-traits/super-traits-fail.rs index da41d7fcc72..c07619fbf62 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs +++ b/tests/ui/traits/const-traits/super-traits-fail.rs @@ -1,4 +1,3 @@ -//~ ERROR the trait bound //@ compile-flags: -Znext-solver #![allow(incomplete_features)] diff --git a/tests/ui/traits/const-traits/super-traits-fail.stderr b/tests/ui/traits/const-traits/super-traits-fail.stderr new file mode 100644 index 00000000000..7a734a6c9f1 --- /dev/null +++ b/tests/ui/traits/const-traits/super-traits-fail.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `S: ~const Foo` is not satisfied + --> $DIR/super-traits-fail.rs:18:20 + | +LL | impl const Bar for S {} + | ^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs b/tests/ui/traits/const-traits/super-traits.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs rename to tests/ui/traits/const-traits/super-traits.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/syntax.rs b/tests/ui/traits/const-traits/syntax.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/syntax.rs rename to tests/ui/traits/const-traits/syntax.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs b/tests/ui/traits/const-traits/tilde-const-and-const-params.rs similarity index 91% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs rename to tests/ui/traits/const-traits/tilde-const-and-const-params.rs index 4b720b534a4..f6a7c7c1746 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs +++ b/tests/ui/traits/const-traits/tilde-const-and-const-params.rs @@ -8,7 +8,6 @@ struct Foo; impl Foo { fn add(self) -> Foo<{ A::add(N) }> { //~^ ERROR `~const` is not allowed here - //~| ERROR mismatched types Foo } } @@ -26,7 +25,6 @@ impl const Add42 for () { fn bar(_: Foo) -> Foo<{ A::add(N) }> { //~^ ERROR `~const` is not allowed here - //~| ERROR mismatched types Foo } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr b/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr similarity index 51% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr rename to tests/ui/traits/const-traits/tilde-const-and-const-params.stderr index 73526a26e08..84a425f6791 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr +++ b/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr @@ -11,13 +11,13 @@ LL | fn add(self) -> Foo<{ A::add(N) }> { | ^^^ error: `~const` is not allowed here - --> $DIR/tilde-const-and-const-params.rs:27:11 + --> $DIR/tilde-const-and-const-params.rs:26:11 | LL | fn bar(_: Foo) -> Foo<{ A::add(N) }> { | ^^^^^^ | note: this function is not `const`, so it cannot have `~const` trait bounds - --> $DIR/tilde-const-and-const-params.rs:27:4 + --> $DIR/tilde-const-and-const-params.rs:26:4 | LL | fn bar(_: Foo) -> Foo<{ A::add(N) }> { | ^^^ @@ -27,24 +27,5 @@ error: using `#![feature(effects)]` without enabling next trait solver globally = note: the next trait solver must be enabled globally for the effects feature to work correctly = help: use `-Znext-solver` to enable -error[E0308]: mismatched types - --> $DIR/tilde-const-and-const-params.rs:27:61 - | -LL | fn bar(_: Foo) -> Foo<{ A::add(N) }> { - | ^^^^^^^^^ expected `false`, found `true` - | - = note: expected constant `false` - found constant `true` +error: aborting due to 3 previous errors -error[E0308]: mismatched types - --> $DIR/tilde-const-and-const-params.rs:9:44 - | -LL | fn add(self) -> Foo<{ A::add(N) }> { - | ^^^^^^^^^ expected `false`, found `true` - | - = note: expected constant `false` - found constant `true` - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-assoc-fn-in-trait-impl.rs b/tests/ui/traits/const-traits/tilde-const-assoc-fn-in-trait-impl.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-assoc-fn-in-trait-impl.rs rename to tests/ui/traits/const-traits/tilde-const-assoc-fn-in-trait-impl.rs diff --git a/tests/ui/traits/const-traits/tilde-const-in-struct-args.rs b/tests/ui/traits/const-traits/tilde-const-in-struct-args.rs new file mode 100644 index 00000000000..4722be955e9 --- /dev/null +++ b/tests/ui/traits/const-traits/tilde-const-in-struct-args.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Znext-solver +//@ known-bug: #132067 +//@ check-pass + +#![feature(const_trait_impl, effects)] + +struct S; +#[const_trait] +trait Trait {} + +const fn f< + T: Trait< + { + struct I>(U); + 0 + }, + >, +>() { +} + +pub fn main() {} diff --git a/tests/ui/traits/const-traits/tilde-const-in-struct-args.stderr b/tests/ui/traits/const-traits/tilde-const-in-struct-args.stderr new file mode 100644 index 00000000000..a9759f10d06 --- /dev/null +++ b/tests/ui/traits/const-traits/tilde-const-in-struct-args.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/tilde-const-in-struct-args.rs:5:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-inherent-assoc-const-fn.rs b/tests/ui/traits/const-traits/tilde-const-inherent-assoc-const-fn.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-inherent-assoc-const-fn.rs rename to tests/ui/traits/const-traits/tilde-const-inherent-assoc-const-fn.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs b/tests/ui/traits/const-traits/tilde-const-invalid-places.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs rename to tests/ui/traits/const-traits/tilde-const-invalid-places.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr b/tests/ui/traits/const-traits/tilde-const-invalid-places.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr rename to tests/ui/traits/const-traits/tilde-const-invalid-places.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs b/tests/ui/traits/const-traits/tilde-const-syntax.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs rename to tests/ui/traits/const-traits/tilde-const-syntax.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-trait-assoc-tys.rs b/tests/ui/traits/const-traits/tilde-const-trait-assoc-tys.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-trait-assoc-tys.rs rename to tests/ui/traits/const-traits/tilde-const-trait-assoc-tys.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-twice.rs b/tests/ui/traits/const-traits/tilde-twice.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-twice.rs rename to tests/ui/traits/const-traits/tilde-twice.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-twice.stderr b/tests/ui/traits/const-traits/tilde-twice.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-twice.stderr rename to tests/ui/traits/const-traits/tilde-twice.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.rs b/tests/ui/traits/const-traits/trait-default-body-stability.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.rs rename to tests/ui/traits/const-traits/trait-default-body-stability.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr b/tests/ui/traits/const-traits/trait-default-body-stability.stderr similarity index 53% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr rename to tests/ui/traits/const-traits/trait-default-body-stability.stderr index 49fbef9aaa2..5806b6d6fd2 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-default-body-stability.stderr +++ b/tests/ui/traits/const-traits/trait-default-body-stability.stderr @@ -16,5 +16,22 @@ LL | impl const FromResidual for T { = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error: aborting due to 2 previous errors +error[E0015]: `?` cannot determine the branch of `T` in constant functions + --> $DIR/trait-default-body-stability.rs:45:9 + | +LL | T? + | ^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error[E0015]: `?` cannot convert from residual of `T` in constant functions + --> $DIR/trait-default-body-stability.rs:45:9 + | +LL | T? + | ^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-method-ptr-in-consts-ice.rs b/tests/ui/traits/const-traits/trait-method-ptr-in-consts-ice.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-method-ptr-in-consts-ice.rs rename to tests/ui/traits/const-traits/trait-method-ptr-in-consts-ice.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs b/tests/ui/traits/const-traits/trait-where-clause-const.rs similarity index 84% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs rename to tests/ui/traits/const-traits/trait-where-clause-const.rs index 8ca9b7cc7aa..61e2bc38426 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.rs +++ b/tests/ui/traits/const-traits/trait-where-clause-const.rs @@ -20,11 +20,9 @@ trait Foo { const fn test1() { T::a(); T::b(); - //~^ ERROR mismatched types - //~| ERROR the trait bound + //~^ ERROR the trait bound T::c::(); - //~^ ERROR mismatched types - //~| ERROR the trait bound + //~^ ERROR the trait bound } const fn test2() { diff --git a/tests/ui/traits/const-traits/trait-where-clause-const.stderr b/tests/ui/traits/const-traits/trait-where-clause-const.stderr new file mode 100644 index 00000000000..30a7ef1fd0d --- /dev/null +++ b/tests/ui/traits/const-traits/trait-where-clause-const.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `T: ~const Bar` is not satisfied + --> $DIR/trait-where-clause-const.rs:22:5 + | +LL | T::b(); + | ^^^^^^ + +error[E0277]: the trait bound `T: ~const Bar` is not satisfied + --> $DIR/trait-where-clause-const.rs:24:5 + | +LL | T::c::(); + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs b/tests/ui/traits/const-traits/trait-where-clause-run.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-run.rs rename to tests/ui/traits/const-traits/trait-where-clause-run.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs b/tests/ui/traits/const-traits/trait-where-clause-self-referential.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs rename to tests/ui/traits/const-traits/trait-where-clause-self-referential.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause.rs b/tests/ui/traits/const-traits/trait-where-clause.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause.rs rename to tests/ui/traits/const-traits/trait-where-clause.rs diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause.stderr b/tests/ui/traits/const-traits/trait-where-clause.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause.stderr rename to tests/ui/traits/const-traits/trait-where-clause.stderr diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.rs similarity index 100% rename from tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs rename to tests/ui/traits/const-traits/unsatisfied-const-trait-bound.rs diff --git a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr new file mode 100644 index 00000000000..35f3019b6ee --- /dev/null +++ b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr @@ -0,0 +1,35 @@ +error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed + --> $DIR/unsatisfied-const-trait-bound.rs:5:39 + | +LL | #![feature(const_trait_impl, effects, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: remove one of these features + +error[E0277]: the trait bound `T: const Trait` is not satisfied + --> $DIR/unsatisfied-const-trait-bound.rs:29:37 + | +LL | fn accept0(_: Container<{ T::make() }>) {} + | ^^^^^^^^^ + +error[E0277]: the trait bound `T: const Trait` is not satisfied + --> $DIR/unsatisfied-const-trait-bound.rs:33:50 + | +LL | const fn accept1(_: Container<{ T::make() }>) {} + | ^^^^^^^^^ + +error[E0277]: the trait bound `Ty: const Trait` is not satisfied + --> $DIR/unsatisfied-const-trait-bound.rs:22:5 + | +LL | require::(); + | ^^^^^^^^^^^^^^^ + | +note: required by a bound in `require` + --> $DIR/unsatisfied-const-trait-bound.rs:8:15 + | +LL | fn require() {} + | ^^^^^ required by this bound in `require` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/error-reporting/apit-with-bad-path.rs b/tests/ui/traits/error-reporting/apit-with-bad-path.rs new file mode 100644 index 00000000000..57184b9d0a9 --- /dev/null +++ b/tests/ui/traits/error-reporting/apit-with-bad-path.rs @@ -0,0 +1,10 @@ +// Ensure that we don't emit an E0270 for "`impl AsRef: AsRef` not satisfied". + +fn foo(filename: impl AsRef) { + //~^ ERROR cannot find type `Path` in this scope + std::fs::write(filename, "hello").unwrap(); +} + +fn main() { + foo("/tmp/hello"); +} diff --git a/tests/ui/traits/error-reporting/apit-with-bad-path.stderr b/tests/ui/traits/error-reporting/apit-with-bad-path.stderr new file mode 100644 index 00000000000..19bd5e78b47 --- /dev/null +++ b/tests/ui/traits/error-reporting/apit-with-bad-path.stderr @@ -0,0 +1,14 @@ +error[E0412]: cannot find type `Path` in this scope + --> $DIR/apit-with-bad-path.rs:3:29 + | +LL | fn foo(filename: impl AsRef) { + | ^^^^ not found in this scope + | +help: consider importing this struct + | +LL + use std::path::Path; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/traits/error-reporting/where-clause-with-bad-path.rs b/tests/ui/traits/error-reporting/where-clause-with-bad-path.rs new file mode 100644 index 00000000000..cbe14887de4 --- /dev/null +++ b/tests/ui/traits/error-reporting/where-clause-with-bad-path.rs @@ -0,0 +1,10 @@ +// Ensure that we don't emit an E0270 for "`impl AsRef: AsRef` not satisfied". + +fn foo>(filename: T) { + //~^ ERROR cannot find type `Path` in this scope + std::fs::write(filename, "hello").unwrap(); +} + +fn main() { + foo("/tmp/hello"); +} diff --git a/tests/ui/traits/error-reporting/where-clause-with-bad-path.stderr b/tests/ui/traits/error-reporting/where-clause-with-bad-path.stderr new file mode 100644 index 00000000000..1137178f611 --- /dev/null +++ b/tests/ui/traits/error-reporting/where-clause-with-bad-path.stderr @@ -0,0 +1,14 @@ +error[E0412]: cannot find type `Path` in this scope + --> $DIR/where-clause-with-bad-path.rs:3:17 + | +LL | fn foo>(filename: T) { + | ^^^^ not found in this scope + | +help: consider importing this struct + | +LL + use std::path::Path; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.rs b/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.rs new file mode 100644 index 00000000000..5c53b745933 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Znext-solver + +// Make sure we try to mention a deeply normalized type in a type mismatch error. + +trait Mirror { + type Assoc; +} +impl Mirror for T { + type Assoc = T; +} + +fn needs(_: ::Assoc) {} + +fn main() { + needs::(()); + //~^ ERROR mismatched types +} diff --git a/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.stderr b/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.stderr new file mode 100644 index 00000000000..88643945863 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/deeply-normalize-type-expectation.rs:15:18 + | +LL | needs::(()); + | ------------ ^^ expected `i32`, found `()` + | | + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/deeply-normalize-type-expectation.rs:12:4 + | +LL | fn needs(_: ::Assoc) {} + | ^^^^^ ----------------------- + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr index 8a765c21624..5e32d5c429e 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr @@ -675,10 +675,6 @@ LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); | ^^^^^^^^^^^^^^^^^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error[E0015]: cannot call non-const fn `, {closure@$DIR/typeck_type_placeholder_item.rs:230:29: 230:32}> as Iterator>::map::` in constants --> $DIR/typeck_type_placeholder_item.rs:230:45 @@ -687,10 +683,6 @@ LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); | ^^^^^^^^^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | error: aborting due to 74 previous errors diff --git a/tests/ui/unpretty/extern-static.rs b/tests/ui/unpretty/extern-static.rs new file mode 100644 index 00000000000..fbd605b12ca --- /dev/null +++ b/tests/ui/unpretty/extern-static.rs @@ -0,0 +1,6 @@ +//@ compile-flags: -Zunpretty=normal +//@ check-pass + +unsafe extern "C" { + pub unsafe static STATIC: (); +} diff --git a/tests/ui/unpretty/extern-static.stdout b/tests/ui/unpretty/extern-static.stdout new file mode 100644 index 00000000000..fbd605b12ca --- /dev/null +++ b/tests/ui/unpretty/extern-static.stdout @@ -0,0 +1,6 @@ +//@ compile-flags: -Zunpretty=normal +//@ check-pass + +unsafe extern "C" { + pub unsafe static STATIC: (); +} diff --git a/tests/ui/unpretty/unsafe-attr.rs b/tests/ui/unpretty/unsafe-attr.rs new file mode 100644 index 00000000000..8734ea86b6d --- /dev/null +++ b/tests/ui/unpretty/unsafe-attr.rs @@ -0,0 +1,11 @@ +//@ compile-flags: -Zunpretty=normal +//@ check-pass + +#[no_mangle] +extern "C" fn foo() {} + +#[unsafe(no_mangle)] +extern "C" fn bar() {} + +#[cfg_attr(FALSE, unsafe(no_mangle))] +extern "C" fn zoo() {} diff --git a/tests/ui/unpretty/unsafe-attr.stdout b/tests/ui/unpretty/unsafe-attr.stdout new file mode 100644 index 00000000000..8734ea86b6d --- /dev/null +++ b/tests/ui/unpretty/unsafe-attr.stdout @@ -0,0 +1,11 @@ +//@ compile-flags: -Zunpretty=normal +//@ check-pass + +#[no_mangle] +extern "C" fn foo() {} + +#[unsafe(no_mangle)] +extern "C" fn bar() {} + +#[cfg_attr(FALSE, unsafe(no_mangle))] +extern "C" fn zoo() {} diff --git a/tests/ui/unsafe/place-expr-safe.rs b/tests/ui/unsafe/place-expr-safe.rs new file mode 100644 index 00000000000..2590ea74046 --- /dev/null +++ b/tests/ui/unsafe/place-expr-safe.rs @@ -0,0 +1,14 @@ +//@ check-pass + +fn main() { + let ptr = std::ptr::null_mut::(); + let addr = &raw const *ptr; + + let local = 1; + let ptr = &local as *const i32; + let addr = &raw const *ptr; + + let boxed = Box::new(1); + let ptr = &*boxed as *const i32; + let addr = &raw const *ptr; +} diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs index 07e90538b85..6eba6b7abec 100644 --- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs +++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs @@ -22,8 +22,8 @@ fn main() { Some(()) => &S, None => &R, //~ ERROR E0308 } - let t: &dyn Trait = match opt() { //~ ERROR E0038 + let t: &dyn Trait = match opt() { Some(()) => &S, //~ ERROR E0038 - None => &R, + None => &R, //~ ERROR E0038 }; } diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr index d7366e12256..6cd4ebf8412 100644 --- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr +++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr @@ -31,14 +31,10 @@ LL | trait Trait: Sized {} = note: required for the cast from `&S` to `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/wf-dyn-incompat-trait-obj-match.rs:25:25 + --> $DIR/wf-dyn-incompat-trait-obj-match.rs:27:17 | -LL | let t: &dyn Trait = match opt() { - | _________________________^ -LL | | Some(()) => &S, -LL | | None => &R, -LL | | }; - | |_____^ `Trait` cannot be made into an object +LL | None => &R, + | ^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14 diff --git a/triagebot.toml b/triagebot.toml index 74caa036ae6..2e8851e7ec2 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -135,6 +135,43 @@ In case it's useful, here are some [instructions] for tackling these sorts of is """ label = "O-rfl" +[ping.wasm] +alias = ["webassembly"] +message = """\ +Hey WASM notification group! This issue or PR could use some WebAssembly-specific +guidance. Could one of you weigh in? Thanks <3 + +(In case it's useful, here are some [instructions] for tackling these sorts of +issues). + +[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/wasm.html +""" +label = "O-wasm" + +[ping.wasi] +message = """\ +Hey WASI notification group! This issue or PR could use some WASI-specific guidance. +Could one of you weigh in? Thanks <3 + +(In case it's useful, here are some [instructions] for tackling these sorts of +issues). + +[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/wasi.html +""" +label = "O-wasi" + +[ping.emscripten] +message = """\ +Hey Emscripten notification group! This issue or PR could use some Emscripten-specific +guidance. Could one of you weigh in? Thanks <3 + +(In case it's useful, here are some [instructions] for tackling these sorts of +issues). + +[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/emscripten.html +""" +label = "O-emscripten" + [prioritize] label = "I-prioritize" @@ -1081,7 +1118,7 @@ project-const-traits = [ project-stable-mir = [ "@celinval", "@oli-obk", - "@ouz-a", + "@scottmcm", ] project-exploit-mitigations = [