Auto merge of #75388 - JohnTitor:rollup-9tgkxnl, r=JohnTitor

Rollup of 10 pull requests

Successful merges:

 - #74744 (Update RELEASES.md for 1.46.0)
 - #75085 (Transmute big endian `s6_addr` and `[u16; 8]`)
 - #75226 (Miri: Renamed "undef" to "uninit")
 - #75333 (polymorphize: constrain unevaluated const handling)
 - #75338 (move stack size check to const_eval machine)
 - #75347 (Rustdoc: Fix natural ordering to look at all numbers.)
 - #75352 (Tweak conditions for E0026 and E0769)
 - #75353 (Tiny cleanup, remove unnecessary `unwrap`)
 - #75359 (unused_delims: trim expr)
 - #75360 (Add sample fix for E0749)

Failed merges:

r? @ghost
This commit is contained in:
bors 2020-08-11 12:31:56 +00:00
commit 4b9ac51617
30 changed files with 319 additions and 140 deletions

View File

@ -1,3 +1,104 @@
Version 1.46.0 (2020-08-27)
==========================
Language
--------
- [`if`, `match`, and `loop` expressions can now be used in const functions.][72437]
- [Additionally you are now also able to coerce and cast to slices (`&[T]`) in
const functions.][73862]
- [The `#[track_caller]` attribute can now be added to functions to use the
function's caller's location information for panic messages.][72445]
- [Recursively indexing into tuples no longer needs parentheses.][71322] E.g.
`x.0.0` over `(x.0).0`.
- [`mem::transmute` can now be used in static and constants.][72920] **Note**
You currently can't use `mem::transmute` in constant functions.
Compiler
--------
- [You can now use the `cdylib` target on Apple iOS and tvOS platforms.][73516]
- [Enabled static "Position Independent Executables" by default
for `x86_64-unknown-linux-musl`.][70740]
Libraries
---------
- [`mem::forget` is now a `const fn`.][73887]
- [`String` now implements `From<char>`.][73466]
- [The `leading_ones`, and `trailing_ones` methods have been stabilised for all
integer types.][73032]
- [`vec::IntoIter<T>` now implements `AsRef<[T]>`.][72583]
- [All non-zero integer types (`NonZeroU8`) now implement `TryFrom` for their
zero-able equivalent (e.g. `TryFrom<u8>`).][72717]
- [`&[T]` and `&mut [T]` now implement `PartialEq<Vec<T>>`.][71660]
- [`(String, u16)` now implements `ToSocketAddrs`.][73007]
- [`vec::Drain<'_, T>` now implements `AsRef<[T]>`.][72584]
Stabilized APIs
---------------
- [`Option::zip`]
- [`vec::Drain::as_slice`]
Cargo
-----
Added a number of new environment variables that are now available when
compiling your crate.
- [`CARGO_BIN_NAME` and `CARGO_CRATE_NAME`][cargo/8270] Providing the name of
the specific binary being compiled and the name of the crate.
- [`CARGO_PKG_LICENSE`][cargo/8325] The license from the manifest of the package.
- [`CARGO_PKG_LICENSE_FILE`][cargo/8387] The path to the license file.
Compatibility Notes
-------------------
- [The target configuration option `abi_blacklist` has been renamed
to `unsupported_abis`.][74150] The old name will still continue to work.
- [Rustc will now warn if you have a C-like enum that implements `Drop`.][72331]
This was previously accepted but will become a hard error in a future release.
- [Rustc will fail to compile if you have a struct with
`#[repr(i128)]` or `#[repr(u128)]`.][74109] This representation is currently only
allowed on `enum`s.
- [Tokens passed to `macro_rules!` are now always captured.][73293] This helps
ensure that spans have the correct information, and may cause breakage if you
were relying on receiving spans with dummy information.
- [The InnoSetup installer for Windows is no longer available.][72569] This was
a legacy installer that was replaced by a MSI installer a few years ago but
was still being built.
- [`{f32, f64}::asinh` now returns the correct values for negative numbers.][72486]
- [Rustc will no longer accept overlapping trait implementations that only
differ in how the lifetime was bound.][72493]
- [Rustc now correctly relates the lifetime of an existential associated
type.][71896] This fixes some edge cases where `rustc` would erroneously allow
you to pass a shorter lifetime than expected.
[74109]: https://github.com/rust-lang/rust/pull/74109/
[74150]: https://github.com/rust-lang/rust/pull/74150/
[73862]: https://github.com/rust-lang/rust/pull/73862/
[73887]: https://github.com/rust-lang/rust/pull/73887/
[73466]: https://github.com/rust-lang/rust/pull/73466/
[73516]: https://github.com/rust-lang/rust/pull/73516/
[73293]: https://github.com/rust-lang/rust/pull/73293/
[73007]: https://github.com/rust-lang/rust/pull/73007/
[73032]: https://github.com/rust-lang/rust/pull/73032/
[72920]: https://github.com/rust-lang/rust/pull/72920/
[72569]: https://github.com/rust-lang/rust/pull/72569/
[72583]: https://github.com/rust-lang/rust/pull/72583/
[72584]: https://github.com/rust-lang/rust/pull/72584/
[72717]: https://github.com/rust-lang/rust/pull/72717/
[72437]: https://github.com/rust-lang/rust/pull/72437/
[72445]: https://github.com/rust-lang/rust/pull/72445/
[72486]: https://github.com/rust-lang/rust/pull/72486/
[72493]: https://github.com/rust-lang/rust/pull/72493/
[72331]: https://github.com/rust-lang/rust/pull/72331/
[71896]: https://github.com/rust-lang/rust/pull/71896/
[71660]: https://github.com/rust-lang/rust/pull/71660/
[71322]: https://github.com/rust-lang/rust/pull/71322/
[70740]: https://github.com/rust-lang/rust/pull/70740/
[cargo/8270]: https://github.com/rust-lang/cargo/pull/8270/
[cargo/8325]: https://github.com/rust-lang/cargo/pull/8325/
[cargo/8387]: https://github.com/rust-lang/cargo/pull/8387/
[`Option::zip`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.zip
[`vec::Drain::as_slice`]: https://doc.rust-lang.org/stable/std/vec/struct.Drain.html#method.as_slice
Version 1.45.2 (2020-08-03)
==========================
@ -7,6 +108,7 @@ Version 1.45.2 (2020-08-03)
[74954]: https://github.com/rust-lang/rust/issues/74954
[74784]: https://github.com/rust-lang/rust/issues/74784
Version 1.45.1 (2020-07-30)
==========================
@ -20,6 +122,7 @@ Version 1.45.1 (2020-07-30)
[74509]: https://github.com/rust-lang/rust/pull/74509
[74457]: https://github.com/rust-lang/rust/pull/74457
Version 1.45.0 (2020-07-16)
==========================

View File

@ -249,6 +249,7 @@
#![feature(clamp)]
#![feature(concat_idents)]
#![feature(const_cstr_unchecked)]
#![feature(const_fn_transmute)]
#![feature(const_raw_ptr_deref)]
#![feature(container_error_extra)]
#![feature(core_intrinsics)]

View File

@ -10,6 +10,7 @@ use crate::cmp::Ordering;
use crate::fmt::{self, Write as FmtWrite};
use crate::hash;
use crate::io::Write as IoWrite;
use crate::mem::transmute;
use crate::sys::net::netc as c;
use crate::sys_common::{AsInner, FromInner};
@ -1045,27 +1046,23 @@ impl Ipv6Addr {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")]
#[allow_internal_unstable(const_fn_transmute)]
pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
let addr16 = [
a.to_be(),
b.to_be(),
c.to_be(),
d.to_be(),
e.to_be(),
f.to_be(),
g.to_be(),
h.to_be(),
];
Ipv6Addr {
inner: c::in6_addr {
s6_addr: [
(a >> 8) as u8,
a as u8,
(b >> 8) as u8,
b as u8,
(c >> 8) as u8,
c as u8,
(d >> 8) as u8,
d as u8,
(e >> 8) as u8,
e as u8,
(f >> 8) as u8,
f as u8,
(g >> 8) as u8,
g as u8,
(h >> 8) as u8,
h as u8,
],
// All elements in `addr16` are big endian.
// SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`.
s6_addr: unsafe { transmute::<_, [u8; 16]>(addr16) },
},
}
}
@ -1108,16 +1105,19 @@ impl Ipv6Addr {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn segments(&self) -> [u16; 8] {
let arr = &self.inner.s6_addr;
// All elements in `s6_addr` must be big endian.
// SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`.
let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) };
// We want native endian u16
[
u16::from_be_bytes([arr[0], arr[1]]),
u16::from_be_bytes([arr[2], arr[3]]),
u16::from_be_bytes([arr[4], arr[5]]),
u16::from_be_bytes([arr[6], arr[7]]),
u16::from_be_bytes([arr[8], arr[9]]),
u16::from_be_bytes([arr[10], arr[11]]),
u16::from_be_bytes([arr[12], arr[13]]),
u16::from_be_bytes([arr[14], arr[15]]),
u16::from_be(a),
u16::from_be(b),
u16::from_be(c),
u16::from_be(d),
u16::from_be(e),
u16::from_be(f),
u16::from_be(g),
u16::from_be(h),
]
}

View File

@ -41,7 +41,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
// some arbitrary byte value.
//
// FIXME: relay undef bytes to codegen as undef const bytes
let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(next_offset..offset);
let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(next_offset..offset);
llvals.push(cx.const_bytes(bytes));
}
let ptr_offset = read_target_uint(
@ -49,7 +49,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
// This `inspect` is okay since it is within the bounds of the allocation, it doesn't
// affect interpreter execution (we inspect the result after interpreter execution),
// and we properly interpret the relocation as a relocation pointer offset.
alloc.inspect_with_undef_and_ptr_outside_interpreter(offset..(offset + pointer_size)),
alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)),
)
.expect("const_alloc_to_llvm: could not read relocation pointer")
as u64;
@ -74,7 +74,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
// arbitrary byte value.
//
// FIXME: relay undef bytes to codegen as undef const bytes
let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(range);
let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(range);
llvals.push(cx.const_bytes(bytes));
}
@ -452,7 +452,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
// BSS.
let all_bytes_are_zero = alloc.relocations().is_empty()
&& alloc
.inspect_with_undef_and_ptr_outside_interpreter(0..alloc.len())
.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len())
.iter()
.all(|&byte| byte == 0);
@ -480,7 +480,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
// because we are doing this access to inspect the final interpreter state (not
// as part of the interpreter execution).
let bytes =
alloc.inspect_with_undef_and_ptr_outside_interpreter(0..alloc.len());
alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len());
let alloc = llvm::LLVMMDStringInContext(
self.llcx,
bytes.as_ptr().cast(),

View File

@ -11,9 +11,19 @@ trait MyTrait {
impl !MyTrait for u32 {
type Foo = i32; // error!
}
# fn main() {}
```
Negative impls are not allowed to have any items. Negative impls declare that a
trait is **not** implemented (and never will be) and hence there is no need to
specify the values for trait methods or other items.
One way to fix this is to remove the items in negative impls:
```
# #![feature(negative_impls)]
trait MyTrait {
type Foo;
}
impl !MyTrait for u32 {}
```

View File

@ -481,25 +481,27 @@ trait UnusedDelimLint {
let mut err = lint.build(&span_msg);
let mut ate_left_paren = false;
let mut ate_right_paren = false;
let parens_removed = pattern.trim_matches(|c| match c {
'(' | '{' => {
if ate_left_paren {
false
} else {
ate_left_paren = true;
true
let parens_removed = pattern
.trim_matches(|c| match c {
'(' | '{' => {
if ate_left_paren {
false
} else {
ate_left_paren = true;
true
}
}
}
')' | '}' => {
if ate_right_paren {
false
} else {
ate_right_paren = true;
true
')' | '}' => {
if ate_right_paren {
false
} else {
ate_right_paren = true;
true
}
}
}
_ => false,
});
_ => false,
})
.trim();
let replace = {
let mut replace = if keep_space.0 {

View File

@ -154,10 +154,10 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
}
/// Looks at a slice which may describe uninitialized bytes or describe a relocation. This differs
/// from `get_bytes_with_undef_and_ptr` in that it does no relocation checks (even on the
/// from `get_bytes_with_uninit_and_ptr` in that it does no relocation checks (even on the
/// edges) at all. It further ignores `AllocationExtra` callbacks.
/// This must not be used for reads affecting the interpreter execution.
pub fn inspect_with_undef_and_ptr_outside_interpreter(&self, range: Range<usize>) -> &[u8] {
pub fn inspect_with_uninit_and_ptr_outside_interpreter(&self, range: Range<usize>) -> &[u8] {
&self.bytes[range]
}
@ -194,7 +194,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
/// The last argument controls whether we error out when there are uninitialized
/// or pointer bytes. You should never call this, call `get_bytes` or
/// `get_bytes_with_undef_and_ptr` instead,
/// `get_bytes_with_uninit_and_ptr` instead,
///
/// This function also guarantees that the resulting pointer will remain stable
/// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
@ -244,7 +244,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
///
/// It is the caller's responsibility to check bounds and alignment beforehand.
#[inline]
pub fn get_bytes_with_undef_and_ptr(
pub fn get_bytes_with_uninit_and_ptr(
&self,
cx: &impl HasDataLayout,
ptr: Pointer<Tag>,
@ -302,19 +302,19 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
}
/// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
/// relocation. If `allow_ptr_and_undef` is `false`, also enforces that the memory in the
/// relocation. If `allow_uninit_and_ptr` is `false`, also enforces that the memory in the
/// given range contains neither relocations nor uninitialized bytes.
pub fn check_bytes(
&self,
cx: &impl HasDataLayout,
ptr: Pointer<Tag>,
size: Size,
allow_ptr_and_undef: bool,
allow_uninit_and_ptr: bool,
) -> InterpResult<'tcx> {
// Check bounds and relocations on the edges.
self.get_bytes_with_undef_and_ptr(cx, ptr, size)?;
self.get_bytes_with_uninit_and_ptr(cx, ptr, size)?;
// Check uninit and ptr.
if !allow_ptr_and_undef {
if !allow_uninit_and_ptr {
self.check_init(ptr, size)?;
self.check_relocations(cx, ptr, size)?;
}
@ -361,7 +361,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
size: Size,
) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
// `get_bytes_unchecked` tests relocation edges.
let bytes = self.get_bytes_with_undef_and_ptr(cx, ptr, size)?;
let bytes = self.get_bytes_with_uninit_and_ptr(cx, ptr, size)?;
// Uninit check happens *after* we established that the alignment is correct.
// We must not return `Ok()` for unaligned pointers!
if self.is_init(ptr, size).is_err() {
@ -594,7 +594,7 @@ impl InitMaskCompressed {
/// Transferring the initialization mask to other allocations.
impl<Tag, Extra> Allocation<Tag, Extra> {
/// Creates a run-length encoding of the initialization mask.
pub fn compress_undef_range(&self, src: Pointer<Tag>, size: Size) -> InitMaskCompressed {
pub fn compress_uninit_range(&self, src: Pointer<Tag>, size: Size) -> InitMaskCompressed {
// Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`),
// a naive initialization mask copying algorithm would repeatedly have to read the initialization mask from
// the source and write it to the destination. Even if we optimized the memory accesses,
@ -636,8 +636,8 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
size: Size,
repeat: u64,
) {
// An optimization where we can just overwrite an entire range of definedness bits if
// they are going to be uniformly `1` or `0`.
// An optimization where we can just overwrite an entire range of initialization
// bits if they are going to be uniformly `1` or `0`.
if defined.ranges.len() <= 1 {
self.init_mask.set_range_inbounds(
dest.offset,

View File

@ -58,7 +58,7 @@ impl<'tcx> ConstValue<'tcx> {
pub fn try_to_str_slice(&self) -> Option<&'tcx str> {
if let ConstValue::Slice { data, start, end } = *self {
::std::str::from_utf8(data.inspect_with_undef_and_ptr_outside_interpreter(start..end))
::std::str::from_utf8(data.inspect_with_uninit_and_ptr_outside_interpreter(start..end))
.ok()
} else {
None

View File

@ -1107,7 +1107,7 @@ pub trait PrettyPrinter<'tcx>:
// The `inspect` here is okay since we checked the bounds, and there are
// no relocations (we have an active slice reference here). We don't use
// this result to affect interpreter execution.
let byte_str = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
let byte_str = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
self.pretty_print_byte_str(byte_str)
}
(
@ -1117,7 +1117,7 @@ pub trait PrettyPrinter<'tcx>:
// The `inspect` here is okay since we checked the bounds, and there are no
// relocations (we have an active `str` reference here). We don't use this
// result to affect interpreter execution.
let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
let slice = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
p!(write("{:?}", s));
Ok(self)

View File

@ -301,6 +301,15 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
Ok(())
}
fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
// Enforce stack size limit.
if !ecx.tcx.sess.recursion_limit().value_within_limit(ecx.stack().len()) {
throw_exhaust!(StackFrameLimitReached)
} else {
Ok(())
}
}
#[inline(always)]
fn stack(
ecx: &'a InterpCx<'mir, 'tcx, Self>,

View File

@ -687,11 +687,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
M::after_stack_push(self)?;
info!("ENTERING({}) {}", self.frame_idx(), self.frame().instance);
if !self.tcx.sess.recursion_limit().value_within_limit(self.stack().len()) {
throw_exhaust!(StackFrameLimitReached)
} else {
Ok(())
}
Ok(())
}
/// Jump to the given block.

View File

@ -926,7 +926,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
// first copy the relocations to a temporary buffer, because
// `get_bytes_mut` will clear the relocations, which is correct,
// since we don't want to keep any relocations at the target.
// (`get_bytes_with_undef_and_ptr` below checks that there are no
// (`get_bytes_with_uninit_and_ptr` below checks that there are no
// relocations overlapping the edges; those would not be handled correctly).
let relocations =
self.get_raw(src.alloc_id)?.prepare_relocation_copy(self, src, size, dest, length);
@ -935,7 +935,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
// This checks relocation edges on the src.
let src_bytes =
self.get_raw(src.alloc_id)?.get_bytes_with_undef_and_ptr(&tcx, src, size)?.as_ptr();
self.get_raw(src.alloc_id)?.get_bytes_with_uninit_and_ptr(&tcx, src, size)?.as_ptr();
let dest_bytes =
self.get_raw_mut(dest.alloc_id)?.get_bytes_mut(&tcx, dest, size * length)?; // `Size` multiplication
@ -948,7 +948,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
let dest_bytes = dest_bytes.as_mut_ptr();
// Prepare a copy of the initialization mask.
let compressed = self.get_raw(src.alloc_id)?.compress_undef_range(src, size);
let compressed = self.get_raw(src.alloc_id)?.compress_uninit_range(src, size);
if compressed.no_bytes_init() {
// Fast path: If all bytes are `uninit` then there is nothing to copy. The target range

View File

@ -106,7 +106,7 @@ impl<Tag: Copy> std::fmt::Display for ImmTy<'tcx, Tag> {
}
ScalarMaybeUninit::Uninit => cx.typed_value(
|mut this| {
this.write_str("{undef ")?;
this.write_str("{uninit ")?;
Ok(this)
},
|this| this.print_type(ty),

View File

@ -61,7 +61,7 @@ impl<Tag> MemPlaceMeta<Tag> {
pub struct MemPlace<Tag = ()> {
/// A place may have an integral pointer for ZSTs, and since it might
/// be turned back into a reference before ever being dereferenced.
/// However, it may never be undef.
/// However, it may never be uninit.
pub ptr: Scalar<Tag>,
pub align: Align,
/// Metadata for unsized places. Interpretation is up to the type.
@ -729,7 +729,7 @@ where
"Size mismatch when writing bits"
)
}
Immediate::Scalar(ScalarMaybeUninit::Uninit) => {} // undef can have any size
Immediate::Scalar(ScalarMaybeUninit::Uninit) => {} // uninit can have any size
Immediate::ScalarPair(_, _) => {
// FIXME: Can we check anything here?
}

View File

@ -508,12 +508,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
}
} else {
// At run-time, for now, we accept *anything* for these types, including
// undef. We should fix that, but let's start low.
// uninit. We should fix that, but let's start low.
}
Ok(true)
}
ty::RawPtr(..) => {
// We are conservative with undef for integers, but try to
// We are conservative with uninit for integers, but try to
// actually enforce the strict rules for raw pointers (mostly because
// that lets us re-use `ref_to_mplace`).
let place = try_validation!(
@ -807,12 +807,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
// reject it. However, that's good: We don't inherently want
// to reject those pointers, we just do not have the machinery to
// talk about parts of a pointer.
// We also accept undef, for consistency with the slow path.
// We also accept uninit, for consistency with the slow path.
match self.ecx.memory.get_raw(ptr.alloc_id)?.check_bytes(
self.ecx,
ptr,
size,
/*allow_ptr_and_undef*/ self.ref_tracking_for_consts.is_none(),
/*allow_uninit_and_ptr*/ self.ref_tracking_for_consts.is_none(),
) {
// In the happy case, we needn't check anything else.
Ok(()) => {}

View File

@ -269,15 +269,21 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
self.unused_parameters.clear(param.index);
false
}
ty::ConstKind::Unevaluated(_, _, Some(p)) => {
ty::ConstKind::Unevaluated(def, _, Some(p))
// Avoid considering `T` unused when constants are of the form:
// `<Self as Foo<T>>::foo::promoted[p]`
if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self =>
{
// If there is a promoted, don't look at the substs - since it will always contain
// the generic parameters, instead, traverse the promoted MIR.
let promoted = self.tcx.promoted_mir(self.def_id);
let promoted = self.tcx.promoted_mir(def.did);
self.visit_body(&promoted[p]);
false
}
ty::ConstKind::Unevaluated(def_id, unevaluated_substs, None) => {
self.visit_child_body(def_id.did, unevaluated_substs);
ty::ConstKind::Unevaluated(def, unevaluated_substs, None)
if self.tcx.def_kind(def.did) == DefKind::AnonConst =>
{
self.visit_child_body(def.did, unevaluated_substs);
false
}
_ => c.super_visit_with(self),

View File

@ -1076,7 +1076,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
// ```rust
// let mut x = 42;
// x = SOME_MUTABLE_STATIC;
// // x must now be undefined
// // x must now be uninit
// ```
// FIXME: we overzealously erase the entire local, because that's easier to
// implement.

View File

@ -743,8 +743,8 @@ fn write_allocation_bytes<Tag: Copy + Debug, Extra>(
if let Some(&(tag, target_id)) = alloc.relocations().get(&i) {
// Memory with a relocation must be defined
let j = i.bytes_usize();
let offset =
alloc.inspect_with_undef_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize());
let offset = alloc
.inspect_with_uninit_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize());
let offset = read_target_uint(tcx.data_layout.endian, offset).unwrap();
let offset = Size::from_bytes(offset);
let relocation_width = |bytes| bytes * 3;
@ -803,7 +803,7 @@ fn write_allocation_bytes<Tag: Copy + Debug, Extra>(
// Checked definedness (and thus range) and relocations. This access also doesn't
// influence interpreter execution but is only for debugging.
let c = alloc.inspect_with_undef_and_ptr_outside_interpreter(j..j + 1)[0];
let c = alloc.inspect_with_uninit_and_ptr_outside_interpreter(j..j + 1)[0];
write!(w, "{:02x}", c)?;
if c.is_ascii_control() || c >= 0x80 {
ascii.push('.');

View File

@ -392,15 +392,15 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
/// return the span of whole call and the span for all arguments expect the first one (`self`).
fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
let mut has_self_arg = None;
if let PathSource::Expr(parent) = source {
match &parent?.kind {
if let PathSource::Expr(Some(parent)) = source {
match &parent.kind {
ExprKind::Call(_, args) if !args.is_empty() => {
let mut expr_kind = &args[0].kind;
loop {
match expr_kind {
ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
if arg_name.segments[0].ident.name == kw::SelfLower {
let call_span = parent.unwrap().span;
let call_span = parent.span;
let tail_args_span = if args.len() > 1 {
Some(Span::new(
args[1].span.lo(),

View File

@ -1229,8 +1229,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MaybeIncorrect,
);
// we don't want to throw `E0027` in case we have thrown `E0026` for them
unmentioned_fields.retain(|&x| x.name != suggested_name);
// When we have a tuple struct used with struct we don't want to suggest using
// the (valid) struct syntax with numeric field names. Instead we want to
// suggest the expected syntax. We infer that this is the case by parsing the
// `Ident` into an unsized integer. The suggestion will be emitted elsewhere in
// `smart_resolve_context_dependent_help`.
if suggested_name.to_ident_string().parse::<usize>().is_err() {
// We don't want to throw `E0027` in case we have thrown `E0026` for them.
unmentioned_fields.retain(|&x| x.name != suggested_name);
}
}
}
}

View File

@ -1903,23 +1903,41 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) {
}
}
fn name_key(name: &str) -> (&str, u64, usize) {
let end = name.bytes().rposition(|b| b.is_ascii_digit()).map_or(name.len(), |i| i + 1);
// find number at end
let split = name[0..end].bytes().rposition(|b| !b.is_ascii_digit()).map_or(0, |i| i + 1);
// count leading zeroes
let after_zeroes =
name[split..end].bytes().position(|b| b != b'0').map_or(name.len(), |extra| split + extra);
// sort leading zeroes last
let num_zeroes = after_zeroes - split;
match name[split..end].parse() {
Ok(n) => (&name[..split], n, num_zeroes),
Err(_) => (name, 0, num_zeroes),
/// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order).
pub fn compare_names(mut lhs: &str, mut rhs: &str) -> Ordering {
/// Takes a non-numeric and a numeric part from the given &str.
fn take_parts<'a>(s: &mut &'a str) -> (&'a str, &'a str) {
let i = s.find(|c: char| c.is_ascii_digit());
let (a, b) = s.split_at(i.unwrap_or(s.len()));
let i = b.find(|c: char| !c.is_ascii_digit());
let (b, c) = b.split_at(i.unwrap_or(b.len()));
*s = c;
(a, b)
}
while !lhs.is_empty() || !rhs.is_empty() {
let (la, lb) = take_parts(&mut lhs);
let (ra, rb) = take_parts(&mut rhs);
// First process the non-numeric part.
match la.cmp(ra) {
Ordering::Equal => (),
x => return x,
}
// Then process the numeric part, if both sides have one (and they fit in a u64).
if let (Ok(ln), Ok(rn)) = (lb.parse::<u64>(), rb.parse::<u64>()) {
match ln.cmp(&rn) {
Ordering::Equal => (),
x => return x,
}
}
// Then process the numeric part again, but this time as strings.
match lb.cmp(rb) {
Ordering::Equal => (),
x => return x,
}
}
Ordering::Equal
}
fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean::Item]) {
@ -1962,7 +1980,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean:
}
let lhs = i1.name.as_ref().map_or("", |s| &**s);
let rhs = i2.name.as_ref().map_or("", |s| &**s);
name_key(lhs).cmp(&name_key(rhs))
compare_names(lhs, rhs)
}
if cx.shared.sort_modules_alphabetically {
@ -2395,7 +2413,7 @@ fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl) -> Ordering {
let rhs = format!("{}", rhs.inner_impl().print());
// lhs and rhs are formatted as HTML, which may be unnecessary
name_key(&lhs).cmp(&name_key(&rhs))
compare_names(&lhs, &rhs)
}
fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, cache: &Cache) {

View File

@ -1,24 +1,40 @@
use super::*;
#[test]
fn test_name_key() {
assert_eq!(name_key("0"), ("", 0, 1));
assert_eq!(name_key("123"), ("", 123, 0));
assert_eq!(name_key("Fruit"), ("Fruit", 0, 0));
assert_eq!(name_key("Fruit0"), ("Fruit", 0, 1));
assert_eq!(name_key("Fruit0000"), ("Fruit", 0, 4));
assert_eq!(name_key("Fruit01"), ("Fruit", 1, 1));
assert_eq!(name_key("Fruit10"), ("Fruit", 10, 0));
assert_eq!(name_key("Fruit123"), ("Fruit", 123, 0));
fn test_compare_names() {
for &(a, b) in &[
("hello", "world"),
("", "world"),
("123", "hello"),
("123", ""),
("123test", "123"),
("hello", ""),
("hello", "hello"),
("hello123", "hello123"),
("hello123", "hello12"),
("hello12", "hello123"),
("hello01abc", "hello01xyz"),
("hello0abc", "hello0"),
("hello0", "hello0abc"),
("01", "1"),
] {
assert_eq!(compare_names(a, b), a.cmp(b), "{:?} - {:?}", a, b);
}
assert_eq!(compare_names("u8", "u16"), Ordering::Less);
assert_eq!(compare_names("u32", "u16"), Ordering::Greater);
assert_eq!(compare_names("u8_to_f64", "u16_to_f64"), Ordering::Less);
assert_eq!(compare_names("u32_to_f64", "u16_to_f64"), Ordering::Greater);
assert_eq!(compare_names("u16_to_f64", "u16_to_f64"), Ordering::Equal);
assert_eq!(compare_names("u16_to_f32", "u16_to_f64"), Ordering::Less);
}
#[test]
fn test_name_sorting() {
let names = [
"Apple", "Banana", "Fruit", "Fruit0", "Fruit00", "Fruit1", "Fruit01", "Fruit2", "Fruit02",
"Apple", "Banana", "Fruit", "Fruit0", "Fruit00", "Fruit01", "Fruit1", "Fruit02", "Fruit2",
"Fruit20", "Fruit30x", "Fruit100", "Pear",
];
let mut sorted = names.to_owned();
sorted.sort_by_key(|&s| name_key(s));
sorted.sort_by(|&l, r| compare_names(l, r));
assert_eq!(names, sorted);
}

View File

@ -10,6 +10,6 @@ struct A<const N: usize>;
fn main() {
let _: A<7>; // ok
let _: A< 7 >; //~ WARN unnecessary braces
let _: A<7>; //~ WARN unnecessary braces
let _: A<{ 3 + 5 }>; // ok
}

View File

@ -6,7 +6,7 @@ enum MyOption<T> {
fn main() {
match MyOption::MySome(42) {
MyOption::MySome { x: 42 } => (),
//~^ ERROR variant `MyOption::MySome` does not have a field named `x`
//~^ ERROR tuple variant `MyOption::MySome` written as struct variant
_ => (),
}
}

View File

@ -1,12 +1,9 @@
error[E0026]: variant `MyOption::MySome` does not have a field named `x`
--> $DIR/issue-17800.rs:8:28
error[E0769]: tuple variant `MyOption::MySome` written as struct variant
--> $DIR/issue-17800.rs:8:9
|
LL | MyOption::MySome { x: 42 } => (),
| ^
| |
| variant `MyOption::MySome` does not have this field
| help: a field with a similar name exists: `0`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `MyOption::MySome(42)`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0026`.
For more information about this error, try `rustc --explain E0769`.

View File

@ -23,18 +23,18 @@ fn main() {
}
}
if true {
if true {
//~^ WARN unnecessary braces
}
while false {
while false {
//~^ WARN unnecessary braces
}
let _: [u8; 3 ];
let _: [u8; 3];
//~^ WARN unnecessary braces
consume( 7 );
consume(7);
//~^ WARN unnecessary braces
// Do not emit lint for multiline blocks.

View File

@ -21,6 +21,6 @@ fn main() {
};
consume(&{ a.b });
consume( a.b );
consume(a.b);
//~^ WARN unnecessary braces
}

View File

@ -0,0 +1,14 @@
// run-pass
// compile-flags: -Zpolymorphize=on -Zmir-opt-level=3
fn caller<T, U>() -> &'static usize {
callee::<U>()
}
fn callee<T>() -> &'static usize {
&std::mem::size_of::<T>()
}
fn main() {
assert_eq!(caller::<(), ()>(), &0);
}

View File

@ -11,7 +11,7 @@ fn main() {
consume(try {});
//~^ WARN unnecessary parentheses
consume( try {} );
consume(try {});
//~^ WARN unnecessary braces
match try {} {

View File

@ -517,7 +517,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind {
ty::Ref(_, tam, _) => match tam.kind {
ty::Str => String::from_utf8(
data.inspect_with_undef_and_ptr_outside_interpreter(start..end)
data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)
.to_owned(),
)
.ok()
@ -530,7 +530,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
ty::Array(sub_type, len) => match sub_type.kind {
ty::Float(FloatTy::F32) => match miri_to_const(len) {
Some(Constant::Int(len)) => alloc
.inspect_with_undef_and_ptr_outside_interpreter(0..(4 * len as usize))
.inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
.to_owned()
.chunks(4)
.map(|chunk| {
@ -544,7 +544,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
},
ty::Float(FloatTy::F64) => match miri_to_const(len) {
Some(Constant::Int(len)) => alloc
.inspect_with_undef_and_ptr_outside_interpreter(0..(8 * len as usize))
.inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize))
.to_owned()
.chunks(8)
.map(|chunk| {