Auto merge of #88535 - m-ou-se:rollup-jeusxbo, r=m-ou-se
Rollup of 10 pull requests Successful merges: - #85017 (Add carrying_add, borrowing_sub, widening_mul, carrying_mul methods to integers) - #86362 (Avoid cloning LocalDecls) - #88391 (Fix json tuple struct enum variant ) - #88399 (Disallow the aapcs CC on Aarch64) - #88418 (Allow `~const` bounds on trait assoc functions) - #88445 (Clean up the lowering of AST items) - #88495 (Add `TcpStream::set_linger` and `TcpStream::linger`) - #88501 (Use right span in prelude collision suggestions with macros. ) - #88504 (Keep turbofish in prelude collision lint.) - #88524 (Remove unnecessary `mut` from udp doctests) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
0a84708edc
48 changed files with 1008 additions and 128 deletions
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(..));
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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!();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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("</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!(
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
src/test/rustdoc-json/enums/variant_struct.rs
Normal file
11
src/test/rustdoc-json/enums/variant_struct.rs
Normal file
|
@ -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
src/test/rustdoc-json/enums/variant_tuple_struct.rs
Normal file
6
src/test/rustdoc-json/enums/variant_tuple_struct.rs
Normal file
|
@ -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),
|
||||
}
|
|
@ -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 <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() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -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 <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
src/test/ui/abi/unsupported.arm.stderr
Normal file
58
src/test/ui/abi/unsupported.arm.stderr
Normal file
|
@ -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`.
|
|
@ -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() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -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<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
|
||||
|
@ -28,7 +28,7 @@ error: `~const` is not allowed here
|
|||
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
|
||||
|
@ -36,7 +36,7 @@ error: `~const` is not allowed here
|
|||
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
|
||||
|
@ -44,7 +44,7 @@ error: `~const` is not allowed here
|
|||
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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs
Normal file
40
src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs
Normal file
|
@ -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() {}
|
|
@ -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
src/test/ui/rust-2021/future-prelude-collision-macros.fixed
Normal file
45
src/test/ui/rust-2021/future-prelude-collision-macros.fixed
Normal file
|
@ -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
src/test/ui/rust-2021/future-prelude-collision-macros.rs
Normal file
45
src/test/ui/rust-2021/future-prelude-collision-macros.rs
Normal file
|
@ -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
src/test/ui/rust-2021/future-prelude-collision-macros.stderr
Normal file
25
src/test/ui/rust-2021/future-prelude-collision-macros.stderr
Normal file
|
@ -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
|
||||
|
|
@ -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
src/test/ui/rust-2021/future-prelude-collision-turbofish.rs
Normal file
28
src/test/ui/rust-2021/future-prelude-collision-turbofish.rs
Normal file
|
@ -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(())
|
||||
}
|
|
@ -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
|
||||
|
Loading…
Add table
Reference in a new issue