Skip to content

Rollup of 10 pull requests #88535

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
Aug 31, 2021
Merged
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
cc15047
Add carrying_add, borrowing_sub, widening_mul, carrying_mul methods t…
clarfonthey May 7, 2021
523490e
Allow `~const` bounds on trait assoc functions
fee1-dead Aug 28, 2021
ee02c8e
Add test cases
fee1-dead Aug 28, 2021
ed30993
Use the correct type for Enum variant tuples
GuillaumeGomez Aug 27, 2021
a521388
Add rustdonc-json tests for enum variants
GuillaumeGomez Aug 27, 2021
147f74a
Clean up the lowering of AST items
inquisitivecrystal Aug 28, 2021
748a089
Disallow the aapcs CC on Aarch64
nagisa Aug 27, 2021
3b6777f
add `TcpStream::set_linger` and `TcpStream::linger`
ibraheemdev Aug 30, 2021
dafc147
clean up `c::linger` conversion
ibraheemdev Aug 30, 2021
4986bbf
Keep turbofish in prelude collision lint.
m-ou-se Aug 30, 2021
532be28
Test that turbofish does not swim away in prelude collusion suggestion.
m-ou-se Aug 30, 2021
4027629
Remove unnecessary `mut` from udp doctests
soenkehahn Aug 31, 2021
7bcc9ae
Avoid cloning LocalDecls
ptrojahn Jun 3, 2021
2a06daa
Pull Span::find_ancestor_inside loop into its own function.
m-ou-se Aug 30, 2021
a15dab9
Use right span in prelude collision suggestions with macros.
m-ou-se Aug 30, 2021
fc0fb38
Add macro test for prelude collision suggestions.
m-ou-se Aug 30, 2021
7c0479b
Use and_then instead of unwrap_or_default.
m-ou-se Aug 31, 2021
072e8c9
disable `tcp_linger` feature in `std`
ibraheemdev Aug 31, 2021
e7a247d
Rollup merge of #85017 - clarfonthey:carrying_widening, r=m-ou-se
m-ou-se Aug 31, 2021
175c8cb
Rollup merge of #86362 - ptrojahn:insert_vars_and_temps, r=jackh726
m-ou-se Aug 31, 2021
f4f5dd5
Rollup merge of #88391 - GuillaumeGomez:fix-json-enum-variant, r=came…
m-ou-se Aug 31, 2021
4d08908
Rollup merge of #88399 - nagisa:nagisa/aapcs-on-aarch, r=petrochenkov
m-ou-se Aug 31, 2021
ab37e49
Rollup merge of #88418 - fee1-dead:trait-assoc-tilde-const, r=oli-obk
m-ou-se Aug 31, 2021
41249ca
Rollup merge of #88445 - inquisitivecrystal:ast-lowering, r=cjgillot
m-ou-se Aug 31, 2021
c5a34d8
Rollup merge of #88495 - ibraheemdev:tcp-linger, r=joshtriplett
m-ou-se Aug 31, 2021
91c4fee
Rollup merge of #88501 - m-ou-se:prelude-collusion-oh-no-macros-help,…
m-ou-se Aug 31, 2021
13f6d7e
Rollup merge of #88504 - m-ou-se:turbofish-please-stay, r=oli-obk
m-ou-se Aug 31, 2021
f5cf967
Rollup merge of #88524 - soenkehahn:master, r=jyn514
m-ou-se Aug 31, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 29 additions & 33 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
@@ -26,44 +26,43 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
}

impl ItemLowerer<'_, '_, '_> {
fn with_trait_impl_ref(&mut self, impl_ref: &Option<TraitRef>, f: impl FnOnce(&mut Self)) {
fn with_trait_impl_ref<T>(
&mut self,
impl_ref: &Option<TraitRef>,
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<T>(
&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<T>(
&mut self,
f: impl FnOnce(&mut LoweringContext<'_, '_>) -> T,
) -> T {
fn without_in_scope_lifetime_defs<T>(&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<hir::Item<'hir>> {
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(
4 changes: 2 additions & 2 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
@@ -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);
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -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<Item = LocalDecl<'tcx>> + '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) {
8 changes: 1 addition & 7 deletions compiler/rustc_mir/src/transform/inline.rs
Original file line number Diff line number Diff line change
@@ -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<Local>` 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(..));
8 changes: 8 additions & 0 deletions compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<Span> {
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()
3 changes: 2 additions & 1 deletion compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
@@ -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",
54 changes: 38 additions & 16 deletions compiler/rustc_typeck/src/check/method/prelude2021.rs
Original file line number Diff line number Diff line change
@@ -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::<String>();
@@ -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
8 changes: 3 additions & 5 deletions compiler/rustc_typeck/src/check/upvar.rs
Original file line number Diff line number Diff line change
@@ -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();
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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)]
54 changes: 54 additions & 0 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
@@ -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
87 changes: 87 additions & 0 deletions library/core/src/num/mod.rs
Original file line number Diff line number Diff line change
@@ -93,27 +93,104 @@ 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]", "", "" }
}

#[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,13 +815,15 @@ 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!() }
}
#[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]",
60 changes: 60 additions & 0 deletions library/core/src/num/uint_macros.rs
Original file line number Diff line number Diff line change
@@ -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
47 changes: 47 additions & 0 deletions library/std/src/net/tcp.rs
Original file line number Diff line number Diff line change
@@ -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<Duration>) -> 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<Option<Duration>> {
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
15 changes: 15 additions & 0 deletions library/std/src/net/tcp/tests.rs
Original file line number Diff line number Diff line change
@@ -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() {
2 changes: 1 addition & 1 deletion library/std/src/net/udp.rs
Original file line number Diff line number Diff line change
@@ -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.
8 changes: 8 additions & 0 deletions library/std/src/sys/hermit/net.rs
Original file line number Diff line number Diff line change
@@ -182,6 +182,14 @@ impl TcpStream {
Ok(self.clone())
}

pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
unsupported()
}

pub fn linger(&self) -> io::Result<Option<Duration>> {
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"))
8 changes: 8 additions & 0 deletions library/std/src/sys/sgx/net.rs
Original file line number Diff line number Diff line change
@@ -183,6 +183,14 @@ impl TcpStream {
Ok(self.clone())
}

pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
sgx_ineffective(())
}

pub fn linger(&self) -> io::Result<Option<Duration>> {
sgx_ineffective(None)
}

pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
sgx_ineffective(())
}
16 changes: 16 additions & 0 deletions library/std/src/sys/unix/l4re.rs
Original file line number Diff line number Diff line change
@@ -98,6 +98,14 @@ pub mod net {
unimpl!();
}

pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
unimpl!();
}

pub fn linger(&self) -> io::Result<Option<Duration>> {
unimpl!();
}

pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
unimpl!();
}
@@ -214,6 +222,14 @@ pub mod net {
unimpl!();
}

pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
unimpl!();
}

pub fn linger(&self) -> io::Result<Option<Duration>> {
unimpl!();
}

pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
unimpl!();
}
23 changes: 23 additions & 0 deletions library/std/src/sys/unix/net.rs
Original file line number Diff line number Diff line change
@@ -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<Duration>) -> 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<Option<Duration>> {
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)
}
8 changes: 8 additions & 0 deletions library/std/src/sys/unsupported/net.rs
Original file line number Diff line number Diff line change
@@ -76,6 +76,14 @@ impl TcpStream {
self.0
}

pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
self.0
}

pub fn linger(&self) -> io::Result<Option<Duration>> {
self.0
}

pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
self.0
}
8 changes: 8 additions & 0 deletions library/std/src/sys/wasi/net.rs
Original file line number Diff line number Diff line change
@@ -127,6 +127,14 @@ impl TcpStream {
unsupported()
}

pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
unsupported()
}

pub fn linger(&self) -> io::Result<Option<Duration>> {
unsupported()
}

pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
unsupported()
}
8 changes: 8 additions & 0 deletions library/std/src/sys/windows/c.rs
Original file line number Diff line number Diff line change
@@ -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,
17 changes: 16 additions & 1 deletion library/std/src/sys/windows/net.rs
Original file line number Diff line number Diff line change
@@ -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<Duration>) -> 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<Option<Duration>> {
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)
}
8 changes: 8 additions & 0 deletions library/std/src/sys_common/net.rs
Original file line number Diff line number Diff line change
@@ -297,6 +297,14 @@ impl TcpStream {
self.inner.duplicate().map(|s| TcpStream { inner: s })
}

pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
self.inner.set_linger(linger)
}

pub fn linger(&self) -> io::Result<Option<Duration>> {
self.inner.linger()
}

pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
self.inner.set_nodelay(nodelay)
}
26 changes: 18 additions & 8 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
@@ -1702,12 +1702,28 @@ impl Clean<VariantStruct> for rustc_hir::VariantData<'_> {
}
}

impl Clean<Vec<Item>> for hir::VariantData<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> Vec<Item> {
self.fields().iter().map(|x| x.clean(cx)).collect()
}
}

impl Clean<Item> 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<Variant> 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,
}
}
3 changes: 2 additions & 1 deletion src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
@@ -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<Type>),
Tuple(Vec<Item>),
Struct(VariantStruct),
}

4 changes: 4 additions & 0 deletions src/librustdoc/fold.rs
Original file line number Diff line number Diff line change
@@ -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),
}
}
41 changes: 24 additions & 17 deletions src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
@@ -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(",&nbsp;");
}
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(",&nbsp;")
}
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(",&nbsp;");
}
write!(w, "{}", ty.print(cx));
}
print_tuple_struct_fields(w, cx, s);
w.write_str(")");
}
w.write_str("</code>");
@@ -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,
"<h3>{extra}Fields of <b>{name}</b></h3><div>",
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!(
13 changes: 12 additions & 1 deletion src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
@@ -569,7 +569,18 @@ impl FromWithTcx<clean::Variant> 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)),
}
}
4 changes: 2 additions & 2 deletions src/librustdoc/passes/stripper.rs
Original file line number Diff line number Diff line change
@@ -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,
};

11 changes: 11 additions & 0 deletions src/test/rustdoc-json/enums/variant_struct.rs
Original file line number Diff line number Diff line change
@@ -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,
},
}
6 changes: 6 additions & 0 deletions src/test/rustdoc-json/enums/variant_tuple_struct.rs
Original file line number Diff line number Diff line change
@@ -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),
}
24 changes: 15 additions & 9 deletions src/test/ui/abi/unsupported.aarch64.stderr
Original file line number Diff line number Diff line change
@@ -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,14 +51,14 @@ LL | extern "stdcall" fn stdcall() {}
= note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/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() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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 <https://github.com/rust-lang/rust/issues/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`.
58 changes: 58 additions & 0 deletions src/test/ui/abi/unsupported.arm.stderr
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/87678>

error: aborting due to 6 previous errors; 2 warnings emitted

For more information about this error, try `rustc --explain E0570`.
12 changes: 6 additions & 6 deletions src/test/ui/abi/unsupported.i686.stderr
Original file line number Diff line number Diff line change
@@ -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() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16 changes: 12 additions & 4 deletions src/test/ui/abi/unsupported.rs
Original file line number Diff line number Diff line change
@@ -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
16 changes: 8 additions & 8 deletions src/test/ui/abi/unsupported.x64.stderr
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/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() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Original file line number Diff line number Diff line change
@@ -4,47 +4,47 @@ 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
|
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
|
LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { 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
|
LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ~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:20:15
|
LL | fn generic<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` is not allowed here
--> $DIR/tilde-const-invalid-places.rs:23:31
|
LL | fn where_clause<P>() 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
41 changes: 41 additions & 0 deletions src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs
Original file line number Diff line number Diff line change
@@ -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 {
<Self as 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);
}
Original file line number Diff line number Diff line change
@@ -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: Foo>() {
T::bar();
}

const fn qux<T: ~const Foo>() {
T::bar();
}

fn main() {}
40 changes: 40 additions & 0 deletions src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs
Original file line number Diff line number Diff line change
@@ -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<T: ~const Bar>();
}

const fn test1<T: ~const Foo + Bar>() {
T::a();
T::b();
//~^ ERROR the trait bound
T::c::<T>();
//~^ ERROR the trait bound
}

const fn test2<T: ~const Foo + ~const Bar>() {
T::a();
T::b();
T::c::<T>();
}

fn test3<T: Foo>() {
T::a();
T::b();
//~^ ERROR the trait bound
T::c::<T>();
//~^ ERROR the trait bound
}

fn test4<T: Foo + Bar>() {
T::a();
T::b();
T::c::<T>();
}

fn main() {}
67 changes: 67 additions & 0 deletions src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr
Original file line number Diff line number Diff line change
@@ -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<T: ~const Foo + Bar + Bar>() {
| +++++

error[E0277]: the trait bound `T: Bar` is not satisfied
--> $DIR/trait-where-clause.rs:16:5
|
LL | T::c::<T>();
| ^^^^^^^^^ the trait `Bar` is not implemented for `T`
|
note: required by `Foo::c`
--> $DIR/trait-where-clause.rs:9:5
|
LL | fn c<T: ~const Bar>();
| ^^^^^^^^^^^^^^^^^^^^^^
help: consider further restricting this bound
|
LL | const fn test1<T: ~const Foo + Bar + Bar>() {
| +++++

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<T: Foo + Bar>() {
| +++++

error[E0277]: the trait bound `T: Bar` is not satisfied
--> $DIR/trait-where-clause.rs:30:5
|
LL | T::c::<T>();
| ^^^^^^^^^ the trait `Bar` is not implemented for `T`
|
note: required by `Foo::c`
--> $DIR/trait-where-clause.rs:9:5
|
LL | fn c<T: ~const Bar>();
| ^^^^^^^^^^^^^^^^^^^^^^
help: consider further restricting this bound
|
LL | fn test3<T: Foo + Bar>() {
| +++++

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0277`.
45 changes: 45 additions & 0 deletions src/test/ui/rust-2021/future-prelude-collision-macros.fixed
Original file line number Diff line number Diff line change
@@ -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<T> {
fn try_into(self, _: u8);
}

struct S;

impl MyTry<i32> 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
<bar!() as TryFromU8>::try_from(0);
//~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021
//~| WARNING this is accepted in the current edition
}
45 changes: 45 additions & 0 deletions src/test/ui/rust-2021/future-prelude-collision-macros.rs
Original file line number Diff line number Diff line change
@@ -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<T> {
fn try_into(self, _: u8);
}

struct S;

impl MyTry<i32> 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
<bar!()>::try_from(0);
//~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021
//~| WARNING this is accepted in the current edition
}
25 changes: 25 additions & 0 deletions src/test/ui/rust-2021/future-prelude-collision-macros.stderr
Original file line number Diff line number Diff line change
@@ -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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>

warning: trait-associated function `try_from` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision-macros.rs:42:5
|
LL | <bar!()>::try_from(0);
| ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<bar!() as TryFromU8>::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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>

warning: 2 warnings emitted

28 changes: 28 additions & 0 deletions src/test/ui/rust-2021/future-prelude-collision-turbofish.fixed
Original file line number Diff line number Diff line change
@@ -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<T>(self) -> Result<T, Self::Error>
where Self: std::convert::TryInto<T> {
std::convert::TryInto::try_into(self)
}
}

impl<T> AnnotatableTryInto for T where T: From<u8> {}

fn main() -> Result<(), &'static str> {
let x: u64 = 1;
AnnotatableTryInto::try_into::<usize>(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::<usize>(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(())
}
28 changes: 28 additions & 0 deletions src/test/ui/rust-2021/future-prelude-collision-turbofish.rs
Original file line number Diff line number Diff line change
@@ -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<T>(self) -> Result<T, Self::Error>
where Self: std::convert::TryInto<T> {
std::convert::TryInto::try_into(self)
}
}

impl<T> AnnotatableTryInto for T where T: From<u8> {}

fn main() -> Result<(), &'static str> {
let x: u64 = 1;
x.try_into::<usize>().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::<usize>().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(())
}
25 changes: 25 additions & 0 deletions src/test/ui/rust-2021/future-prelude-collision-turbofish.stderr
Original file line number Diff line number Diff line change
@@ -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::<usize>().or(Err("foo"))?.checked_sub(1);
| ^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `AnnotatableTryInto::try_into::<usize>(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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>

warning: trait method `try_into` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision-turbofish.rs:23:5
|
LL | x.try_into::<usize>().or(Err("foo"))?;
| ^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `AnnotatableTryInto::try_into::<usize>(x)`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>

warning: 2 warnings emitted