diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 014c240f11ee7..8daeef0cbd95f 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -26,44 +26,43 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> { } impl ItemLowerer<'_, '_, '_> { - fn with_trait_impl_ref(&mut self, impl_ref: &Option, f: impl FnOnce(&mut Self)) { + fn with_trait_impl_ref( + &mut self, + impl_ref: &Option, + f: impl FnOnce(&mut Self) -> T, + ) -> T { let old = self.lctx.is_in_trait_impl; self.lctx.is_in_trait_impl = impl_ref.is_some(); - f(self); + let ret = f(self); self.lctx.is_in_trait_impl = old; + ret } } impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { fn visit_item(&mut self, item: &'a Item) { - let mut item_hir_id = None; - self.lctx.with_hir_id_owner(item.id, |lctx| { + let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| { lctx.without_in_scope_lifetime_defs(|lctx| { - if let Some(hir_item) = lctx.lower_item(item) { - let id = lctx.insert_item(hir_item); - item_hir_id = Some(id); - } + let hir_item = lctx.lower_item(item); + lctx.insert_item(hir_item) }) }); - if let Some(hir_id) = item_hir_id { - self.lctx.with_parent_item_lifetime_defs(hir_id, |this| { - let this = &mut ItemLowerer { lctx: this }; - match item.kind { - ItemKind::Mod(..) => { - let def_id = this.lctx.lower_node_id(item.id).expect_owner(); - let old_current_module = - mem::replace(&mut this.lctx.current_module, def_id); - visit::walk_item(this, item); - this.lctx.current_module = old_current_module; - } - ItemKind::Impl(box ImplKind { ref of_trait, .. }) => { - this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item)); - } - _ => visit::walk_item(this, item), + self.lctx.with_parent_item_lifetime_defs(hir_id, |this| { + let this = &mut ItemLowerer { lctx: this }; + match item.kind { + ItemKind::Mod(..) => { + let def_id = this.lctx.lower_node_id(item.id).expect_owner(); + let old_current_module = mem::replace(&mut this.lctx.current_module, def_id); + visit::walk_item(this, item); + this.lctx.current_module = old_current_module; } - }); - } + ItemKind::Impl(box ImplKind { ref of_trait, .. }) => { + this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item)); + } + _ => visit::walk_item(this, item), + } + }); } fn visit_fn(&mut self, fk: FnKind<'a>, sp: Span, _: NodeId) { @@ -113,7 +112,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn with_parent_item_lifetime_defs( &mut self, parent_hir_id: hir::ItemId, - f: impl FnOnce(&mut LoweringContext<'_, '_>) -> T, + f: impl FnOnce(&mut Self) -> T, ) -> T { let old_len = self.in_scope_lifetimes.len(); @@ -137,10 +136,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Clears (and restores) the `in_scope_lifetimes` field. Used when // visiting nested items, which never inherit in-scope lifetimes // from their surrounding environment. - fn without_in_scope_lifetime_defs( - &mut self, - f: impl FnOnce(&mut LoweringContext<'_, '_>) -> T, - ) -> T { + fn without_in_scope_lifetime_defs(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]); // this vector is only used when walking over impl headers, @@ -208,19 +204,19 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - pub fn lower_item(&mut self, i: &Item) -> Option> { + pub fn lower_item(&mut self, i: &Item) -> hir::Item<'hir> { let mut ident = i.ident; let mut vis = self.lower_visibility(&i.vis, None); let hir_id = self.lower_node_id(i.id); let attrs = self.lower_attrs(hir_id, &i.attrs); let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, &mut vis, &i.kind); - Some(hir::Item { + hir::Item { def_id: hir_id.expect_owner(), ident: self.lower_ident(ident), kind, vis, span: self.lower_span(i.span), - }) + } } fn lower_item_kind( diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 73abd2bb83b9e..a243300edd9d2 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1442,7 +1442,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if !self.is_tilde_const_allowed { self.err_handler() .struct_span_err(bound.span(), "`~const` is not allowed here") - .note("only allowed on bounds on traits' associated types, const fns, const impls and its associated functions") + .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions") .emit(); } } @@ -1616,7 +1616,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(self, visit_ty, ty); } AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body)) - if self.in_const_trait_impl => + if self.in_const_trait_impl || ctxt == AssocCtxt::Trait => { self.visit_vis(&item.vis); self.visit_ident(item.ident); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 8e2917ee5b47c..346a9e8021731 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -426,6 +426,11 @@ impl<'tcx> Body<'tcx> { (arg_count + 1..local_count).map(Local::new) } + #[inline] + pub fn drain_vars_and_temps<'a>(&'a mut self) -> impl Iterator> + 'a { + self.local_decls.drain(self.arg_count + 1..) + } + /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. pub fn make_statement_nop(&mut self, location: Location) { diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index c333667b3ad13..8e9da31eba11f 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -607,13 +607,7 @@ impl Inliner<'tcx> { } // Insert all of the (mapped) parts of the callee body into the caller. - caller_body.local_decls.extend( - // FIXME(eddyb) make `Range` iterable so that we can use - // `callee_body.local_decls.drain(callee_body.vars_and_temps())` - callee_body - .vars_and_temps_iter() - .map(|local| callee_body.local_decls[local].clone()), - ); + caller_body.local_decls.extend(callee_body.drain_vars_and_temps()); caller_body.source_scopes.extend(&mut callee_body.source_scopes.drain(..)); caller_body.var_debug_info.append(&mut callee_body.var_debug_info); caller_body.basic_blocks_mut().extend(callee_body.basic_blocks_mut().drain(..)); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 89e032b222fec..10e9bde0d972b 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -597,6 +597,14 @@ impl Span { if !expn_data.is_root() { Some(expn_data.call_site) } else { None } } + /// Walk down the expansion ancestors to find a span that's contained within `outer`. + pub fn find_ancestor_inside(mut self, outer: Span) -> Option { + while !outer.contains(self) { + self = self.parent()?; + } + Some(self) + } + /// Edition of the crate from which this span came. pub fn edition(self) -> edition::Edition { self.ctxt().edition() diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 911956859b861..4d0cad80764e9 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1501,7 +1501,8 @@ impl Target { | Cdecl | EfiApi => true, X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]), - Aapcs | CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]), + Aapcs => "arm" == self.arch, + CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]), Win64 | SysV64 => self.arch == "x86_64", PtxKernel => self.arch == "nvptx64", Msp430Interrupt => self.arch == "msp430", diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs index 1347f56258ea1..5c8056b244242 100644 --- a/compiler/rustc_typeck/src/check/method/prelude2021.rs +++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs @@ -156,15 +156,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { segment.ident.name )); - let (self_adjusted, precise) = self.adjust_expr(pick, self_expr); + let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp); if precise { let args = args .iter() .skip(1) .map(|arg| { + let span = arg.span.find_ancestor_inside(sp).unwrap_or_default(); format!( ", {}", - self.sess().source_map().span_to_snippet(arg.span).unwrap() + self.sess().source_map().span_to_snippet(span).unwrap() ) }) .collect::(); @@ -173,8 +174,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp, "disambiguate the associated function", format!( - "{}::{}({}{})", - trait_name, segment.ident.name, self_adjusted, args + "{}::{}{}({}{})", + trait_name, + segment.ident.name, + if let Some(args) = segment.args.as_ref().and_then(|args| self + .sess() + .source_map() + .span_to_snippet(args.span_ext) + .ok()) + { + // Keep turbofish. + format!("::{}", args) + } else { + String::new() + }, + self_adjusted, + args, ), Applicability::MachineApplicable, ); @@ -272,11 +287,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { method_name.name )); - let mut self_ty_name = self - .sess() - .source_map() - .span_to_snippet(self_ty_span) - .unwrap_or_else(|_| self_ty.to_string()); + let mut self_ty_name = self_ty_span + .find_ancestor_inside(span) + .and_then(|span| self.sess().source_map().span_to_snippet(span).ok()) + .unwrap_or_else(|| self_ty.to_string()); // Get the number of generics the self type has (if an Adt) unless we can determine that // the user has written the self type with generics already which we (naively) do by looking @@ -370,7 +384,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Creates a string version of the `expr` that includes explicit adjustments. /// Returns the string and also a bool indicating whther this is a *precise* /// suggestion. - fn adjust_expr(&self, pick: &Pick<'tcx>, expr: &hir::Expr<'tcx>) -> (String, bool) { + fn adjust_expr( + &self, + pick: &Pick<'tcx>, + expr: &hir::Expr<'tcx>, + outer: Span, + ) -> (String, bool) { let derefs = "*".repeat(pick.autoderefs); let autoref = match pick.autoref_or_ptr_adjustment { @@ -379,12 +398,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", }; - let (expr_text, precise) = - if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { - (expr_text, true) - } else { - ("(..)".to_string(), false) - }; + let (expr_text, precise) = if let Some(expr_text) = expr + .span + .find_ancestor_inside(outer) + .and_then(|span| self.sess().source_map().span_to_snippet(span).ok()) + { + (expr_text, true) + } else { + ("(..)".to_string(), false) + }; let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = pick.autoref_or_ptr_adjustment diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 75fd545060c4a..a25d0f8064404 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -680,15 +680,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { migrated_variables_concat ); - let mut closure_body_span = self.tcx.hir().span(body_id.hir_id); - // If the body was entirely expanded from a macro // invocation, i.e. the body is not contained inside the // closure span, then we walk up the expansion until we // find the span before the expansion. - while !closure_body_span.is_dummy() && !closure_span.contains(closure_body_span) { - closure_body_span = closure_body_span.parent().unwrap_or(DUMMY_SP); - } + let closure_body_span = self.tcx.hir().span(body_id.hir_id) + .find_ancestor_inside(closure_span) + .unwrap_or(DUMMY_SP); if let Ok(s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) { let mut lines = s.lines(); diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 1a6d1aed2fd1e..d667fff4b81ee 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -76,6 +76,7 @@ #![feature(const_alloc_layout)] #![feature(const_arguments_as_str)] #![feature(const_assert_type)] +#![feature(const_bigint_helper_methods)] #![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_discriminant)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 2c866812937e9..1a310917fdfc4 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1341,6 +1341,33 @@ macro_rules! int_impl { (a as Self, b) } + /// Calculates `self + rhs + carry` without the ability to overflow. + /// + /// Performs "ternary addition" which takes in an extra bit to add, and may return an + /// additional bit of overflow. This allows for chaining together multiple additions + /// to create "big integers" which represent larger values. + /// + /// # Examples + /// + /// Basic usage + /// + /// ``` + /// #![feature(bigint_helper_methods)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (", stringify!($SelfT), "::MIN, false));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (", stringify!($SelfT), "::MIN + 1, false));")] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) { + let (sum, carry) = (self as $UnsignedT).carrying_add(rhs as $UnsignedT, carry); + (sum as $SelfT, carry) + } + /// Calculates `self` - `rhs` /// /// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow @@ -1365,6 +1392,33 @@ macro_rules! int_impl { (a as Self, b) } + /// Calculates `self - rhs - borrow` without the ability to overflow. + /// + /// Performs "ternary subtraction" which takes in an extra bit to subtract, and may return + /// an additional bit of overflow. This allows for chaining together multiple subtractions + /// to create "big integers" which represent larger values. + /// + /// # Examples + /// + /// Basic usage + /// + /// ``` + /// #![feature(bigint_helper_methods)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.borrowing_sub(1, false), (", stringify!($SelfT), "::MAX, false));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, false));")] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) { + let (sum, borrow) = (self as $UnsignedT).borrowing_sub(rhs as $UnsignedT, borrow); + (sum as $SelfT, borrow) + } + /// Calculates the multiplication of `self` and `rhs`. /// /// Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 09b7418bec0d9..59b68cbe9c0ce 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -93,20 +93,96 @@ depending on the target pointer size. }; } +macro_rules! widening_impl { + ($SelfT:ty, $WideT:ty, $BITS:literal) => { + /// Calculates the complete product `self * rhs` without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5u32.widening_mul(2), (10, 0)); + /// assert_eq!(1_000_000_000u32.widening_mul(10), (1410065408, 2)); + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn widening_mul(self, rhs: Self) -> (Self, Self) { + // note: longer-term this should be done via an intrinsic, + // but for now we can deal without an impl for u128/i128 + // SAFETY: overflow will be contained within the wider types + let wide = unsafe { (self as $WideT).unchecked_mul(rhs as $WideT) }; + (wide as $SelfT, (wide >> $BITS) as $SelfT) + } + + /// Calculates the "full multiplication" `self * rhs + carry` + /// without the possibility to overflow. + /// + /// This returns the low-order (wrapping) bits and the high-order (overflow) bits + /// of the result as two separate values, in that order. + /// + /// Performs "long multiplication" which takes in an extra amount to add, and may return an + /// additional amount of overflow. This allows for chaining together multiple + /// multiplications to create "big integers" which represent larger values. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u32` is used here. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// assert_eq!(5u32.carrying_mul(2, 0), (10, 0)); + /// assert_eq!(5u32.carrying_mul(2, 10), (20, 0)); + /// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2)); + /// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2)); + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) { + // note: longer-term this should be done via an intrinsic, + // but for now we can deal without an impl for u128/i128 + // SAFETY: overflow will be contained within the wider types + let wide = unsafe { + (self as $WideT).unchecked_mul(rhs as $WideT).unchecked_add(carry as $WideT) + }; + (wide as $SelfT, (wide >> $BITS) as $SelfT) + } + }; +} + #[lang = "i8"] impl i8 { + widening_impl! { i8, i16, 8 } int_impl! { i8, i8, u8, 8, 7, -128, 127, 2, "-0x7e", "0xa", "0x12", "0x12", "0x48", "[0x12]", "[0x12]", "", "" } } #[lang = "i16"] impl i16 { + widening_impl! { i16, i32, 16 } int_impl! { i16, i16, u16, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } } #[lang = "i32"] impl i32 { + widening_impl! { i32, i64, 32 } int_impl! { i32, i32, u32, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" } @@ -114,6 +190,7 @@ impl i32 { #[lang = "i64"] impl i64 { + widening_impl! { i64, i128, 64 } int_impl! { i64, i64, u64, 64, 63, -9223372036854775808, 9223372036854775807, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", @@ -135,6 +212,7 @@ impl i128 { #[cfg(target_pointer_width = "16")] #[lang = "isize"] impl isize { + widening_impl! { isize, i32, 16 } int_impl! { isize, i16, usize, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } @@ -143,6 +221,7 @@ impl isize { #[cfg(target_pointer_width = "32")] #[lang = "isize"] impl isize { + widening_impl! { isize, i64, 32 } int_impl! { isize, i32, usize, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", @@ -152,6 +231,7 @@ impl isize { #[cfg(target_pointer_width = "64")] #[lang = "isize"] impl isize { + widening_impl! { isize, i128, 64 } int_impl! { isize, i64, usize, 64, 63, -9223372036854775808, 9223372036854775807, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", @@ -164,6 +244,7 @@ const ASCII_CASE_MASK: u8 = 0b0010_0000; #[lang = "u8"] impl u8 { + widening_impl! { u8, u16, 8 } uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", "[0x12]", "", "" } @@ -697,18 +778,21 @@ impl u8 { #[lang = "u16"] impl u16 { + widening_impl! { u16, u32, 16 } uint_impl! { u16, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } } #[lang = "u32"] impl u32 { + widening_impl! { u32, u64, 32 } uint_impl! { u32, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" } } #[lang = "u64"] impl u64 { + widening_impl! { u64, u128, 64 } uint_impl! { u64, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", @@ -731,6 +815,7 @@ impl u128 { #[cfg(target_pointer_width = "16")] #[lang = "usize"] impl usize { + widening_impl! { usize, u32, 16 } uint_impl! { usize, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } @@ -738,6 +823,7 @@ impl usize { #[cfg(target_pointer_width = "32")] #[lang = "usize"] impl usize { + widening_impl! { usize, u64, 32 } uint_impl! { usize, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } @@ -746,6 +832,7 @@ impl usize { #[cfg(target_pointer_width = "64")] #[lang = "usize"] impl usize { + widening_impl! { usize, u128, 64 } uint_impl! { usize, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index d6bd3115a0254..9366efb32bcf9 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1408,6 +1408,36 @@ macro_rules! uint_impl { (a as Self, b) } + /// Calculates `self + rhs + carry` without the ability to overflow. + /// + /// Performs "ternary addition" which takes in an extra bit to add, and may return an + /// additional bit of overflow. This allows for chaining together multiple additions + /// to create "big integers" which represent larger values. + /// + /// # Examples + /// + /// Basic usage + /// + /// ``` + /// #![feature(bigint_helper_methods)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (0, true));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (1, true));")] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) { + // note: longer-term this should be done via an intrinsic, but this has been shown + // to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic + let (a, b) = self.overflowing_add(rhs); + let (c, d) = a.overflowing_add(carry as $SelfT); + (c, b | d) + } + /// Calculates `self` - `rhs` /// /// Returns a tuple of the subtraction along with a boolean indicating @@ -1433,6 +1463,36 @@ macro_rules! uint_impl { (a as Self, b) } + /// Calculates `self - rhs - borrow` without the ability to overflow. + /// + /// Performs "ternary subtraction" which takes in an extra bit to subtract, and may return + /// an additional bit of overflow. This allows for chaining together multiple subtractions + /// to create "big integers" which represent larger values. + /// + /// # Examples + /// + /// Basic usage + /// + /// ``` + /// #![feature(bigint_helper_methods)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, false), (", stringify!($SelfT), "::MAX, true));")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, true));")] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) { + // note: longer-term this should be done via an intrinsic, but this has been shown + // to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic + let (a, b) = self.overflowing_sub(rhs); + let (c, d) = a.overflowing_sub(borrow as $SelfT); + (c, b | d) + } + /// Calculates the multiplication of `self` and `rhs`. /// /// Returns a tuple of the multiplication along with a boolean diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 336891ec1eb94..5b4a9fa7979de 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -401,6 +401,53 @@ impl TcpStream { self.0.peek(buf) } + /// Sets the value of the `SO_LINGER` option on this socket. + /// + /// This value controls how the socket is closed when data remains + /// to be sent. If `SO_LINGER` is set, the socket will remain open + /// for the specified duration as the system attempts to send pending data. + /// Otherwise, the system may close the socket immediately, or wait for a + /// default timeout. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(tcp_linger)] + /// + /// use std::net::TcpStream; + /// use std::time::Duration; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_linger(Some(Duration::from_secs(0))).expect("set_linger call failed"); + /// ``` + #[unstable(feature = "tcp_linger", issue = "88494")] + pub fn set_linger(&self, linger: Option) -> io::Result<()> { + self.0.set_linger(linger) + } + + /// Gets the value of the `SO_LINGER` option on this socket. + /// + /// For more information about this option, see [`TcpStream::set_linger`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(tcp_linger)] + /// + /// use std::net::TcpStream; + /// use std::time::Duration; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_linger(Some(Duration::from_secs(0))).expect("set_linger call failed"); + /// assert_eq!(stream.linger().unwrap(), Some(Duration::from_secs(0))); + /// ``` + #[unstable(feature = "tcp_linger", issue = "88494")] + pub fn linger(&self) -> io::Result> { + self.0.linger() + } + /// Sets the value of the `TCP_NODELAY` option on this socket. /// /// If set, this option disables the Nagle algorithm. This means that diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 387a3617e5e9a..c2061c1351262 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -767,6 +767,21 @@ fn test_timeout_zero_duration() { drop(listener); } +#[test] +#[cfg_attr(target_env = "sgx", ignore)] +fn linger() { + let addr = next_test_ip4(); + let _listener = t!(TcpListener::bind(&addr)); + + let stream = t!(TcpStream::connect(&("localhost", addr.port()))); + + assert_eq!(None, t!(stream.linger())); + t!(stream.set_linger(Some(Duration::from_secs(1)))); + assert_eq!(Some(Duration::from_secs(1)), t!(stream.linger())); + t!(stream.set_linger(None)); + assert_eq!(None, t!(stream.linger())); +} + #[test] #[cfg_attr(target_env = "sgx", ignore)] fn nodelay() { diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 871505843af23..6354752e64e76 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -39,7 +39,7 @@ use crate::time::Duration; /// /// fn main() -> std::io::Result<()> { /// { -/// let mut socket = UdpSocket::bind("127.0.0.1:34254")?; +/// let socket = UdpSocket::bind("127.0.0.1:34254")?; /// /// // Receives a single datagram message on the socket. If `buf` is too small to hold /// // the message, it will be cut off. diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs index 3f0c99cf74289..880ef678a4f7a 100644 --- a/library/std/src/sys/hermit/net.rs +++ b/library/std/src/sys/hermit/net.rs @@ -182,6 +182,14 @@ impl TcpStream { Ok(self.clone()) } + pub fn set_linger(&self, linger: Option) -> io::Result<()> { + unsupported() + } + + pub fn linger(&self) -> io::Result> { + unsupported() + } + pub fn set_nodelay(&self, mode: bool) -> io::Result<()> { abi::tcpstream::set_nodelay(*self.0.as_inner(), mode) .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"set_nodelay failed")) diff --git a/library/std/src/sys/sgx/net.rs b/library/std/src/sys/sgx/net.rs index 3a69aa039ef2e..89c5af6124f20 100644 --- a/library/std/src/sys/sgx/net.rs +++ b/library/std/src/sys/sgx/net.rs @@ -183,6 +183,14 @@ impl TcpStream { Ok(self.clone()) } + pub fn set_linger(&self, _: Option) -> io::Result<()> { + sgx_ineffective(()) + } + + pub fn linger(&self) -> io::Result> { + sgx_ineffective(None) + } + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { sgx_ineffective(()) } diff --git a/library/std/src/sys/unix/l4re.rs b/library/std/src/sys/unix/l4re.rs index 3cf637c82285a..ba63b41534c1a 100644 --- a/library/std/src/sys/unix/l4re.rs +++ b/library/std/src/sys/unix/l4re.rs @@ -98,6 +98,14 @@ pub mod net { unimpl!(); } + pub fn set_linger(&self, _: Option) -> io::Result<()> { + unimpl!(); + } + + pub fn linger(&self) -> io::Result> { + unimpl!(); + } + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { unimpl!(); } @@ -214,6 +222,14 @@ pub mod net { unimpl!(); } + pub fn set_linger(&self, _: Option) -> io::Result<()> { + unimpl!(); + } + + pub fn linger(&self) -> io::Result> { + unimpl!(); + } + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { unimpl!(); } diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index c2f5da1dbbb11..9ae6d12dcb95c 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -12,6 +12,14 @@ use crate::time::{Duration, Instant}; use libc::{c_int, c_void, size_t, sockaddr, socklen_t, MSG_PEEK}; +cfg_if::cfg_if! { + if #[cfg(target_vendor = "apple")] { + use libc::SO_LINGER_SEC as SO_LINGER; + } else { + use libc::SO_LINGER; + } +} + pub use crate::sys::{cvt, cvt_r}; #[allow(unused_extern_crates)] @@ -376,6 +384,21 @@ impl Socket { Ok(()) } + pub fn set_linger(&self, linger: Option) -> io::Result<()> { + let linger = libc::linger { + l_onoff: linger.is_some() as libc::c_int, + l_linger: linger.unwrap_or_default().as_secs() as libc::c_int, + }; + + setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger) + } + + pub fn linger(&self) -> io::Result> { + let val: libc::linger = getsockopt(self, libc::SOL_SOCKET, SO_LINGER)?; + + Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) + } + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) } diff --git a/library/std/src/sys/unsupported/net.rs b/library/std/src/sys/unsupported/net.rs index 96203c74b576c..dbb6ce22c22de 100644 --- a/library/std/src/sys/unsupported/net.rs +++ b/library/std/src/sys/unsupported/net.rs @@ -76,6 +76,14 @@ impl TcpStream { self.0 } + pub fn set_linger(&self, _: Option) -> io::Result<()> { + self.0 + } + + pub fn linger(&self) -> io::Result> { + self.0 + } + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { self.0 } diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs index c7c4a9f6efdfb..a4dbb225376ee 100644 --- a/library/std/src/sys/wasi/net.rs +++ b/library/std/src/sys/wasi/net.rs @@ -127,6 +127,14 @@ impl TcpStream { unsupported() } + pub fn set_linger(&self, _: Option) -> io::Result<()> { + unsupported() + } + + pub fn linger(&self) -> io::Result> { + unsupported() + } + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { unsupported() } diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 63f9be7b7e350..cedf389fbf503 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -197,6 +197,7 @@ pub const SOCK_DGRAM: c_int = 2; pub const SOCK_STREAM: c_int = 1; pub const SOCKET_ERROR: c_int = -1; pub const SOL_SOCKET: c_int = 0xffff; +pub const SO_LINGER: c_int = 0x0080; pub const SO_RCVTIMEO: c_int = 0x1006; pub const SO_SNDTIMEO: c_int = 0x1005; pub const IPPROTO_IP: c_int = 0; @@ -216,6 +217,13 @@ pub const IPV6_ADD_MEMBERSHIP: c_int = 12; pub const IPV6_DROP_MEMBERSHIP: c_int = 13; pub const MSG_PEEK: c_int = 0x2; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct linger { + pub l_onoff: c_ushort, + pub l_linger: c_ushort, +} + #[repr(C)] pub struct ip_mreq { pub imr_multiaddr: in_addr, diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 55aacb38c6f78..33152cc97abc0 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -15,7 +15,7 @@ use crate::sys_common::net; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; -use libc::{c_int, c_long, c_ulong}; +use libc::{c_int, c_long, c_ulong, c_ushort}; pub type wrlen_t = i32; @@ -446,6 +446,21 @@ impl Socket { cvt(result).map(drop) } + pub fn set_linger(&self, linger: Option) -> io::Result<()> { + let linger = c::linger { + l_onoff: linger.is_some() as c_ushort, + l_linger: linger.unwrap_or_default().as_secs() as c_ushort, + }; + + net::setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger) + } + + pub fn linger(&self) -> io::Result> { + let val: c::linger = net::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?; + + Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) + } + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BYTE) } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 0ffa5c01dd33b..c5c3df361f34b 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -297,6 +297,14 @@ impl TcpStream { self.inner.duplicate().map(|s| TcpStream { inner: s }) } + pub fn set_linger(&self, linger: Option) -> io::Result<()> { + self.inner.set_linger(linger) + } + + pub fn linger(&self) -> io::Result> { + self.inner.linger() + } + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { self.inner.set_nodelay(nodelay) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 640acffb114d9..b566239423e04 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1702,12 +1702,28 @@ impl Clean for rustc_hir::VariantData<'_> { } } +impl Clean> for hir::VariantData<'_> { + fn clean(&self, cx: &mut DocContext<'_>) -> Vec { + self.fields().iter().map(|x| x.clean(cx)).collect() + } +} + impl Clean for ty::VariantDef { fn clean(&self, cx: &mut DocContext<'_>) -> Item { let kind = match self.ctor_kind { CtorKind::Const => Variant::CLike, CtorKind::Fn => Variant::Tuple( - self.fields.iter().map(|f| cx.tcx.type_of(f.did).clean(cx)).collect(), + self.fields + .iter() + .map(|field| { + let name = Some(field.ident.name); + let kind = StructFieldItem(cx.tcx.type_of(field.did).clean(cx)); + let what_rustc_thinks = + Item::from_def_id_and_parts(field.did, name, kind, cx); + // don't show `pub` for fields, which are always public + Item { visibility: Visibility::Inherited, ..what_rustc_thinks } + }) + .collect(), ), CtorKind::Fictive => Variant::Struct(VariantStruct { struct_type: CtorKind::Fictive, @@ -1737,13 +1753,7 @@ impl Clean for hir::VariantData<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> Variant { match self { hir::VariantData::Struct(..) => Variant::Struct(self.clean(cx)), - // Important note here: `Variant::Tuple` is used on tuple structs which are not in an - // enum (so where converting from `ty::VariantDef`). In case we are in an enum, the kind - // is provided by the `Variant` wrapper directly, and since we need the fields' name - // (even for a tuple struct variant!), it's simpler to just store it as a - // `Variant::Struct` instead of a `Variant::Tuple` (otherwise it would force us to make - // a lot of changes when rendering them to generate the name as well). - hir::VariantData::Tuple(..) => Variant::Struct(self.clean(cx)), + hir::VariantData::Tuple(..) => Variant::Tuple(self.clean(cx)), hir::VariantData::Unit(..) => Variant::CLike, } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 7025574914331..4194c99c0ba70 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -715,6 +715,7 @@ impl ItemKind { StructItem(s) => s.fields.iter(), UnionItem(u) => u.fields.iter(), VariantItem(Variant::Struct(v)) => v.fields.iter(), + VariantItem(Variant::Tuple(v)) => v.iter(), EnumItem(e) => e.variants.iter(), TraitItem(t) => t.items.iter(), ImplItem(i) => i.items.iter(), @@ -1937,7 +1938,7 @@ crate struct Enum { #[derive(Clone, Debug)] crate enum Variant { CLike, - Tuple(Vec), + Tuple(Vec), Struct(VariantStruct), } diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 45aae71d2dc57..b4859e4c9c7fe 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -56,6 +56,10 @@ crate trait DocFolder: Sized { || j.fields.iter().any(|f| f.is_stripped()); VariantItem(Variant::Struct(j)) } + Variant::Tuple(fields) => { + let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + VariantItem(Variant::Tuple(fields)) + } _ => VariantItem(i2), } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 8f4857a693928..722cfc97a8d89 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -937,6 +937,19 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni document_type_layout(w, cx, def_id); } +fn print_tuple_struct_fields(w: &mut Buffer, cx: &Context<'_>, s: &[clean::Item]) { + for (i, ty) in s + .iter() + .map(|f| if let clean::StructFieldItem(ref ty) = *f.kind { ty } else { unreachable!() }) + .enumerate() + { + if i > 0 { + w.write_str(", "); + } + write!(w, "{}", ty.print(cx)); + } +} + fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) { wrap_into_docblock(w, |w| { wrap_item(w, "enum", |w| { @@ -964,14 +977,9 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum match *v.kind { clean::VariantItem(ref var) => match var { clean::Variant::CLike => write!(w, "{}", name), - clean::Variant::Tuple(ref tys) => { + clean::Variant::Tuple(ref s) => { write!(w, "{}(", name); - for (i, ty) in tys.iter().enumerate() { - if i > 0 { - w.write_str(", ") - } - write!(w, "{}", ty.print(cx)); - } + print_tuple_struct_fields(w, cx, s); w.write_str(")"); } clean::Variant::Struct(ref s) => { @@ -1024,14 +1032,9 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum id = id, name = variant.name.as_ref().unwrap() ); - if let clean::VariantItem(clean::Variant::Tuple(ref tys)) = *variant.kind { + if let clean::VariantItem(clean::Variant::Tuple(ref s)) = *variant.kind { w.write_str("("); - for (i, ty) in tys.iter().enumerate() { - if i > 0 { - w.write_str(", "); - } - write!(w, "{}", ty.print(cx)); - } + print_tuple_struct_fields(w, cx, s); w.write_str(")"); } w.write_str(""); @@ -1041,7 +1044,11 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum document_non_exhaustive(w, variant); use crate::clean::Variant; - if let clean::VariantItem(Variant::Struct(ref s)) = *variant.kind { + if let Some((extra, fields)) = match *variant.kind { + clean::VariantItem(Variant::Struct(ref s)) => Some(("", &s.fields)), + clean::VariantItem(Variant::Tuple(ref fields)) => Some(("Tuple ", fields)), + _ => None, + } { let variant_id = cx.derive_id(format!( "{}.{}.fields", ItemType::Variant, @@ -1051,10 +1058,10 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum write!( w, "

{extra}Fields of {name}

", - extra = if s.struct_type == CtorKind::Fn { "Tuple " } else { "" }, + extra = extra, name = variant.name.as_ref().unwrap(), ); - for field in &s.fields { + for field in fields { use crate::clean::StructFieldItem; if let StructFieldItem(ref ty) = *field.kind { let id = cx.derive_id(format!( diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index f3eeea6c6ae0b..9453e6d35ee67 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -569,7 +569,18 @@ impl FromWithTcx for Variant { use clean::Variant::*; match variant { CLike => Variant::Plain, - Tuple(t) => Variant::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()), + Tuple(fields) => Variant::Tuple( + fields + .into_iter() + .map(|f| { + if let clean::StructFieldItem(ty) = *f.kind { + ty.into_tcx(tcx) + } else { + unreachable!() + } + }) + .collect(), + ), Struct(s) => Variant::Struct(ids(s.fields)), } } diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 819d7d323fd7a..a93880453ba27 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -94,8 +94,8 @@ impl<'a> DocFolder for Stripper<'a> { // implementations of traits are always public. clean::ImplItem(ref imp) if imp.trait_.is_some() => true, - // Struct variant fields have inherited visibility - clean::VariantItem(clean::Variant::Struct(..)) => true, + // Variant fields have inherited visibility + clean::VariantItem(clean::Variant::Struct(..) | clean::Variant::Tuple(..)) => true, _ => false, }; diff --git a/src/test/rustdoc-json/enums/variant_struct.rs b/src/test/rustdoc-json/enums/variant_struct.rs new file mode 100644 index 0000000000000..246e6a09007b3 --- /dev/null +++ b/src/test/rustdoc-json/enums/variant_struct.rs @@ -0,0 +1,11 @@ +// @has variant_struct.json "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\" +pub enum EnumStruct { + // @has - "$.index[*][?(@.name=='VariantS')].inner.variant_kind" \"struct\" + // @has - "$.index[*][?(@.name=='x')]" + // @has - "$.index[*][?(@.name=='y')]" + VariantS { + x: u32, + y: String, + }, +} diff --git a/src/test/rustdoc-json/enums/variant_tuple_struct.rs b/src/test/rustdoc-json/enums/variant_tuple_struct.rs new file mode 100644 index 0000000000000..d948dc552cdbc --- /dev/null +++ b/src/test/rustdoc-json/enums/variant_tuple_struct.rs @@ -0,0 +1,6 @@ +// @has variant_tuple_struct.json "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\" +pub enum EnumTupleStruct { + // @has - "$.index[*][?(@.name=='VariantA')].inner.variant_kind" \"tuple\" + VariantA(u32, String), +} diff --git a/src/test/ui/abi/unsupported.aarch64.stderr b/src/test/ui/abi/unsupported.aarch64.stderr index fdeb79f93e9f2..225d49e05a3fa 100644 --- a/src/test/ui/abi/unsupported.aarch64.stderr +++ b/src/test/ui/abi/unsupported.aarch64.stderr @@ -1,41 +1,47 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:24:1 + --> $DIR/unsupported.rs:26:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:26:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "amdgpu-kernel" fn amdgpu() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:28:1 + --> $DIR/unsupported.rs:30:1 | LL | extern "wasm" fn wasm() {} | ^^^^^^^^^^^^^^^^^^^^^^^ +error[E0570]: `"aapcs"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:32:1 + | +LL | extern "aapcs" fn aapcs() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:33:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:35:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:37:1 + --> $DIR/unsupported.rs:40:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:39:1 + --> $DIR/unsupported.rs:43:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +51,7 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:44:1 + --> $DIR/unsupported.rs:50:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,6 +59,6 @@ LL | extern "thiscall" fn thiscall() {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #87678 -error: aborting due to 6 previous errors; 2 warnings emitted +error: aborting due to 7 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/src/test/ui/abi/unsupported.arm.stderr b/src/test/ui/abi/unsupported.arm.stderr new file mode 100644 index 0000000000000..b050ee0aa3148 --- /dev/null +++ b/src/test/ui/abi/unsupported.arm.stderr @@ -0,0 +1,58 @@ +error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:26:1 + | +LL | extern "ptx-kernel" fn ptx() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:28:1 + | +LL | extern "amdgpu-kernel" fn amdgpu() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"wasm"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:30:1 + | +LL | extern "wasm" fn wasm() {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:36:1 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:38:1 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target + --> $DIR/unsupported.rs:40:1 + | +LL | extern "x86-interrupt" fn x86() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of calling convention not supported on this target + --> $DIR/unsupported.rs:43:1 + | +LL | extern "stdcall" fn stdcall() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unsupported_calling_conventions)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #87678 + +warning: use of calling convention not supported on this target + --> $DIR/unsupported.rs:50:1 + | +LL | extern "thiscall" fn thiscall() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #87678 + +error: aborting due to 6 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0570`. diff --git a/src/test/ui/abi/unsupported.i686.stderr b/src/test/ui/abi/unsupported.i686.stderr index 81b12653d2ee8..7ca93516db989 100644 --- a/src/test/ui/abi/unsupported.i686.stderr +++ b/src/test/ui/abi/unsupported.i686.stderr @@ -1,35 +1,35 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:24:1 + --> $DIR/unsupported.rs:26:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:26:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "amdgpu-kernel" fn amdgpu() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:28:1 + --> $DIR/unsupported.rs:30:1 | LL | extern "wasm" fn wasm() {} | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:32:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:33:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:35:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/abi/unsupported.rs b/src/test/ui/abi/unsupported.rs index f0debdcf621e2..9319eac8d30d8 100644 --- a/src/test/ui/abi/unsupported.rs +++ b/src/test/ui/abi/unsupported.rs @@ -1,11 +1,13 @@ -// revisions: x64 i686 aarch64 +// revisions: x64 i686 aarch64 arm // // [x64] needs-llvm-components: x86 -// [x64]compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib +// [x64] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib // [i686] needs-llvm-components: x86 -// [i686]compile-flags: --target=i686-unknown-linux-gnu --crate-type=rlib +// [i686] compile-flags: --target=i686-unknown-linux-gnu --crate-type=rlib // [aarch64] needs-llvm-components: aarch64 -// [aarch64]compile-flags: --target=aarch64-unknown-linux-gnu --crate-type=rlib +// [aarch64] compile-flags: --target=aarch64-unknown-linux-gnu --crate-type=rlib +// [arm] needs-llvm-components: arm +// [arm] compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib #![no_core] #![feature( no_core, @@ -30,19 +32,25 @@ extern "wasm" fn wasm() {} extern "aapcs" fn aapcs() {} //[x64]~^ ERROR is not a supported ABI //[i686]~^^ ERROR is not a supported ABI +//[aarch64]~^^^ ERROR is not a supported ABI extern "msp430-interrupt" fn msp430() {} //~^ ERROR is not a supported ABI extern "avr-interrupt" fn avr() {} //~^ ERROR is not a supported ABI extern "x86-interrupt" fn x86() {} //[aarch64]~^ ERROR is not a supported ABI +//[arm]~^^ ERROR is not a supported ABI extern "stdcall" fn stdcall() {} //[x64]~^ WARN use of calling convention not supported //[x64]~^^ WARN this was previously accepted //[aarch64]~^^^ WARN use of calling convention not supported //[aarch64]~^^^^ WARN this was previously accepted +//[arm]~^^^^^ WARN use of calling convention not supported +//[arm]~^^^^^^ WARN this was previously accepted extern "thiscall" fn thiscall() {} //[x64]~^ WARN use of calling convention not supported //[x64]~^^ WARN this was previously accepted //[aarch64]~^^^ WARN use of calling convention not supported //[aarch64]~^^^^ WARN this was previously accepted +//[arm]~^^^^^ WARN use of calling convention not supported +//[arm]~^^^^^^ WARN this was previously accepted diff --git a/src/test/ui/abi/unsupported.x64.stderr b/src/test/ui/abi/unsupported.x64.stderr index 60d067acf174f..f2f52683324db 100644 --- a/src/test/ui/abi/unsupported.x64.stderr +++ b/src/test/ui/abi/unsupported.x64.stderr @@ -1,41 +1,41 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:24:1 + --> $DIR/unsupported.rs:26:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:26:1 + --> $DIR/unsupported.rs:28:1 | LL | extern "amdgpu-kernel" fn amdgpu() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:28:1 + --> $DIR/unsupported.rs:30:1 | LL | extern "wasm" fn wasm() {} | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:32:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:33:1 + --> $DIR/unsupported.rs:36:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:35:1 + --> $DIR/unsupported.rs:38:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:39:1 + --> $DIR/unsupported.rs:43:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #87678 warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:44:1 + --> $DIR/unsupported.rs:50:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr index b026099f6829b..033ec21ba8408 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr @@ -4,7 +4,7 @@ error: `~const` is not allowed here LL | fn rpit() -> impl ~const T { S } | ^^^^^^^^ | - = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions + = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions error: `~const` is not allowed here --> $DIR/tilde-const-invalid-places.rs:11:17 @@ -12,7 +12,7 @@ error: `~const` is not allowed here LL | fn apit(_: impl ~const T) {} | ^^^^^^^^ | - = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions + = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions error: `~const` is not allowed here --> $DIR/tilde-const-invalid-places.rs:14:50 @@ -20,7 +20,7 @@ error: `~const` is not allowed here LL | fn rpit_assoc_bound() -> impl IntoIterator { Some(S) } | ^^^^^^^^ | - = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions + = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions error: `~const` is not allowed here --> $DIR/tilde-const-invalid-places.rs:17:48 @@ -28,7 +28,7 @@ error: `~const` is not allowed here LL | fn apit_assoc_bound(_: impl IntoIterator) {} | ^^^^^^^^ | - = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions + = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions error: `~const` is not allowed here --> $DIR/tilde-const-invalid-places.rs:20:15 @@ -36,7 +36,7 @@ error: `~const` is not allowed here LL | fn generic() {} | ^^^^^^^^ | - = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions + = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions error: `~const` is not allowed here --> $DIR/tilde-const-invalid-places.rs:23:31 @@ -44,7 +44,7 @@ error: `~const` is not allowed here LL | fn where_clause

() where P: ~const T {} | ^^^^^^^^ | - = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions + = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions error: `~const` and `?` are mutually exclusive --> $DIR/tilde-const-invalid-places.rs:26:25 diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs new file mode 100644 index 0000000000000..0cde5b6f84218 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs @@ -0,0 +1,41 @@ +// run-pass + +#![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] + +trait Bar { + fn bar() -> u8; +} + +trait Foo { + #[default_method_body_is_const] + fn foo() -> u8 where Self: ~const Bar { + ::bar() * 6 + } +} + +struct NonConst; +struct Const; + +impl Bar for NonConst { + fn bar() -> u8 { + 3 + } +} + +impl Foo for NonConst {} + +impl const Bar for Const { + fn bar() -> u8 { + 4 + } +} + +impl const Foo for Const {} + +fn main() { + const ANS1: u8 = Const::foo(); + let ans2 = NonConst::foo(); + + assert_eq!(ANS1 + ans2, 42); +} diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs new file mode 100644 index 0000000000000..ae9ab26cdc04a --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs @@ -0,0 +1,24 @@ +// check-pass + +#![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] + +trait Foo { + fn bar() where Self: ~const Foo; +} + +struct S; + +impl Foo for S { + fn bar() {} +} + +fn baz() { + T::bar(); +} + +const fn qux() { + T::bar(); +} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs new file mode 100644 index 0000000000000..d64822d7ce8af --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs @@ -0,0 +1,40 @@ +#![feature(const_fn_trait_bound)] +#![feature(const_trait_impl)] + +trait Bar {} + +trait Foo { + fn a(); + fn b() where Self: ~const Bar; + fn c(); +} + +const fn test1() { + T::a(); + T::b(); + //~^ ERROR the trait bound + T::c::(); + //~^ ERROR the trait bound +} + +const fn test2() { + T::a(); + T::b(); + T::c::(); +} + +fn test3() { + T::a(); + T::b(); + //~^ ERROR the trait bound + T::c::(); + //~^ ERROR the trait bound +} + +fn test4() { + T::a(); + T::b(); + T::c::(); +} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr new file mode 100644 index 0000000000000..fffb91f98700b --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr @@ -0,0 +1,67 @@ +error[E0277]: the trait bound `T: Bar` is not satisfied + --> $DIR/trait-where-clause.rs:14:5 + | +LL | T::b(); + | ^^^^ the trait `Bar` is not implemented for `T` + | +note: required by `Foo::b` + --> $DIR/trait-where-clause.rs:8:5 + | +LL | fn b() where Self: ~const Bar; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider further restricting this bound + | +LL | const fn test1() { + | +++++ + +error[E0277]: the trait bound `T: Bar` is not satisfied + --> $DIR/trait-where-clause.rs:16:5 + | +LL | T::c::(); + | ^^^^^^^^^ the trait `Bar` is not implemented for `T` + | +note: required by `Foo::c` + --> $DIR/trait-where-clause.rs:9:5 + | +LL | fn c(); + | ^^^^^^^^^^^^^^^^^^^^^^ +help: consider further restricting this bound + | +LL | const fn test1() { + | +++++ + +error[E0277]: the trait bound `T: Bar` is not satisfied + --> $DIR/trait-where-clause.rs:28:5 + | +LL | T::b(); + | ^^^^ the trait `Bar` is not implemented for `T` + | +note: required by `Foo::b` + --> $DIR/trait-where-clause.rs:8:5 + | +LL | fn b() where Self: ~const Bar; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider further restricting this bound + | +LL | fn test3() { + | +++++ + +error[E0277]: the trait bound `T: Bar` is not satisfied + --> $DIR/trait-where-clause.rs:30:5 + | +LL | T::c::(); + | ^^^^^^^^^ the trait `Bar` is not implemented for `T` + | +note: required by `Foo::c` + --> $DIR/trait-where-clause.rs:9:5 + | +LL | fn c(); + | ^^^^^^^^^^^^^^^^^^^^^^ +help: consider further restricting this bound + | +LL | fn test3() { + | +++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/rust-2021/future-prelude-collision-macros.fixed b/src/test/ui/rust-2021/future-prelude-collision-macros.fixed new file mode 100644 index 0000000000000..a97dc176e1b8b --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-macros.fixed @@ -0,0 +1,45 @@ +// run-rustfix +// edition:2018 +// check-pass +#![warn(rust_2021_prelude_collisions)] +#![allow(unreachable_code)] + +macro_rules! foo { + () => {{ + 123; + S + }}; +} + +trait MyTry { + fn try_into(self, _: u8); +} + +struct S; + +impl MyTry for S { + fn try_into(self, _: u8) {} +} + +trait TryFromU8: Sized { + fn try_from(_: u8); +} + +impl TryFromU8 for u32 { + fn try_from(_: u8) {} +} + +macro_rules! bar { + () => { + u32 + }; +} + +fn main() { + MyTry::try_into(foo!(), todo!()); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~| WARNING this is accepted in the current edition + ::try_from(0); + //~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021 + //~| WARNING this is accepted in the current edition +} diff --git a/src/test/ui/rust-2021/future-prelude-collision-macros.rs b/src/test/ui/rust-2021/future-prelude-collision-macros.rs new file mode 100644 index 0000000000000..82484b5b3688d --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-macros.rs @@ -0,0 +1,45 @@ +// run-rustfix +// edition:2018 +// check-pass +#![warn(rust_2021_prelude_collisions)] +#![allow(unreachable_code)] + +macro_rules! foo { + () => {{ + 123; + S + }}; +} + +trait MyTry { + fn try_into(self, _: u8); +} + +struct S; + +impl MyTry for S { + fn try_into(self, _: u8) {} +} + +trait TryFromU8: Sized { + fn try_from(_: u8); +} + +impl TryFromU8 for u32 { + fn try_from(_: u8) {} +} + +macro_rules! bar { + () => { + u32 + }; +} + +fn main() { + foo!().try_into(todo!()); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~| WARNING this is accepted in the current edition + ::try_from(0); + //~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021 + //~| WARNING this is accepted in the current edition +} diff --git a/src/test/ui/rust-2021/future-prelude-collision-macros.stderr b/src/test/ui/rust-2021/future-prelude-collision-macros.stderr new file mode 100644 index 0000000000000..4c3543ca782e8 --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-macros.stderr @@ -0,0 +1,25 @@ +warning: trait method `try_into` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision-macros.rs:39:5 + | +LL | foo!().try_into(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `MyTry::try_into(foo!(), todo!())` + | +note: the lint level is defined here + --> $DIR/future-prelude-collision-macros.rs:4:9 + | +LL | #![warn(rust_2021_prelude_collisions)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! + = note: for more information, see + +warning: trait-associated function `try_from` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision-macros.rs:42:5 + | +LL | ::try_from(0); + | ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `::try_from` + | + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! + = note: for more information, see + +warning: 2 warnings emitted + diff --git a/src/test/ui/rust-2021/future-prelude-collision-turbofish.fixed b/src/test/ui/rust-2021/future-prelude-collision-turbofish.fixed new file mode 100644 index 0000000000000..3e76fced774db --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-turbofish.fixed @@ -0,0 +1,28 @@ +// See https://github.com/rust-lang/rust/issues/88442 +// run-rustfix +// edition:2018 +// check-pass +#![allow(unused)] +#![warn(rust_2021_prelude_collisions)] + +trait AnnotatableTryInto { + fn try_into(self) -> Result + where Self: std::convert::TryInto { + std::convert::TryInto::try_into(self) + } +} + +impl AnnotatableTryInto for T where T: From {} + +fn main() -> Result<(), &'static str> { + let x: u64 = 1; + AnnotatableTryInto::try_into::(x).or(Err("foo"))?.checked_sub(1); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! + + AnnotatableTryInto::try_into::(x).or(Err("foo"))?; + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! + + Ok(()) +} diff --git a/src/test/ui/rust-2021/future-prelude-collision-turbofish.rs b/src/test/ui/rust-2021/future-prelude-collision-turbofish.rs new file mode 100644 index 0000000000000..abb292ef99284 --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-turbofish.rs @@ -0,0 +1,28 @@ +// See https://github.com/rust-lang/rust/issues/88442 +// run-rustfix +// edition:2018 +// check-pass +#![allow(unused)] +#![warn(rust_2021_prelude_collisions)] + +trait AnnotatableTryInto { + fn try_into(self) -> Result + where Self: std::convert::TryInto { + std::convert::TryInto::try_into(self) + } +} + +impl AnnotatableTryInto for T where T: From {} + +fn main() -> Result<(), &'static str> { + let x: u64 = 1; + x.try_into::().or(Err("foo"))?.checked_sub(1); + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! + + x.try_into::().or(Err("foo"))?; + //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021 + //~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! + + Ok(()) +} diff --git a/src/test/ui/rust-2021/future-prelude-collision-turbofish.stderr b/src/test/ui/rust-2021/future-prelude-collision-turbofish.stderr new file mode 100644 index 0000000000000..2de9020bce7ac --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-turbofish.stderr @@ -0,0 +1,25 @@ +warning: trait method `try_into` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision-turbofish.rs:19:5 + | +LL | x.try_into::().or(Err("foo"))?.checked_sub(1); + | ^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `AnnotatableTryInto::try_into::(x)` + | +note: the lint level is defined here + --> $DIR/future-prelude-collision-turbofish.rs:6:9 + | +LL | #![warn(rust_2021_prelude_collisions)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! + = note: for more information, see + +warning: trait method `try_into` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision-turbofish.rs:23:5 + | +LL | x.try_into::().or(Err("foo"))?; + | ^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `AnnotatableTryInto::try_into::(x)` + | + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! + = note: for more information, see + +warning: 2 warnings emitted +