Auto merge of #77470 - jonas-schievink:rollup-9a2hulp, r=jonas-schievink
Rollup of 8 pull requests Successful merges: - #75377 (Fix Debug implementations of some of the HashMap and BTreeMap iterator types) - #76107 (Write manifest for MAJOR.MINOR channel to enable rustup convenience) - #76745 (Move Wrapping<T> ui tests into library) - #77182 (Add missing examples for Fd traits) - #77251 (Bypass const_item_mutation if const's type has Drop impl) - #77264 (Only use LOCAL_{STDOUT,STDERR} when set_{print/panic} is used. ) - #77421 (Revert "resolve: Avoid "self-confirming" import resolutions in one more case") - #77452 (Permit ty::Bool in const generics for v0 mangling) Failed merges: r? `@ghost`
This commit is contained in:
commit
6ebad43c25
16 changed files with 398 additions and 145 deletions
|
@ -31,6 +31,35 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn is_const_item_without_destructor(&self, local: Local) -> Option<DefId> {
|
||||
let def_id = self.is_const_item(local)?;
|
||||
let mut any_dtor = |_tcx, _def_id| Ok(());
|
||||
|
||||
// We avoid linting mutation of a const item if the const's type has a
|
||||
// Drop impl. The Drop logic observes the mutation which was performed.
|
||||
//
|
||||
// pub struct Log { msg: &'static str }
|
||||
// pub const LOG: Log = Log { msg: "" };
|
||||
// impl Drop for Log {
|
||||
// fn drop(&mut self) { println!("{}", self.msg); }
|
||||
// }
|
||||
//
|
||||
// LOG.msg = "wow"; // prints "wow"
|
||||
//
|
||||
// FIXME(https://github.com/rust-lang/rust/issues/77425):
|
||||
// Drop this exception once there is a stable attribute to suppress the
|
||||
// const item mutation lint for a single specific const only. Something
|
||||
// equivalent to:
|
||||
//
|
||||
// #[const_mutation_allowed]
|
||||
// pub const LOG: Log = Log { msg: "" };
|
||||
match self.tcx.calculate_dtor(def_id, &mut any_dtor) {
|
||||
Some(_) => None,
|
||||
None => Some(def_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn lint_const_item_usage(
|
||||
&self,
|
||||
const_item: DefId,
|
||||
|
@ -59,7 +88,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> {
|
|||
// Assigning directly to a constant (e.g. `FOO = true;`) is a hard error,
|
||||
// so emitting a lint would be redundant.
|
||||
if !lhs.projection.is_empty() {
|
||||
if let Some(def_id) = self.is_const_item(lhs.local) {
|
||||
if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
|
||||
// Don't lint on writes through a pointer
|
||||
// (e.g. `unsafe { *FOO = 0; *BAR.field = 1; }`)
|
||||
if !matches!(lhs.projection.last(), Some(PlaceElem::Deref)) {
|
||||
|
|
|
@ -875,12 +875,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
/// consolidate multiple unresolved import errors into a single diagnostic.
|
||||
fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImportError> {
|
||||
let orig_vis = import.vis.replace(ty::Visibility::Invisible);
|
||||
let orig_unusable_binding = match &import.kind {
|
||||
ImportKind::Single { target_bindings, .. } => {
|
||||
Some(mem::replace(&mut self.r.unusable_binding, target_bindings[TypeNS].get()))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let prev_ambiguity_errors_len = self.r.ambiguity_errors.len();
|
||||
let path_res = self.r.resolve_path(
|
||||
&import.module_path,
|
||||
|
@ -891,9 +885,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
import.crate_lint(),
|
||||
);
|
||||
let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
|
||||
if let Some(orig_unusable_binding) = orig_unusable_binding {
|
||||
self.r.unusable_binding = orig_unusable_binding;
|
||||
}
|
||||
import.vis.set(orig_vis);
|
||||
if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res {
|
||||
// Consider erroneous imports used to avoid duplicate diagnostics.
|
||||
|
@ -904,7 +895,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
// Consistency checks, analogous to `finalize_macro_resolutions`.
|
||||
if let Some(initial_module) = import.imported_module.get() {
|
||||
if !ModuleOrUniformRoot::same_def(module, initial_module) && no_ambiguity {
|
||||
span_bug!(import.span, "inconsistent resolution for an import");
|
||||
let msg = "inconsistent resolution for an import";
|
||||
self.r.session.span_err(import.span, msg);
|
||||
}
|
||||
} else {
|
||||
if self.r.privacy_errors.is_empty() {
|
||||
|
@ -926,7 +918,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
}
|
||||
PathResult::Failed { is_error_from_last_segment: true, span, label, suggestion } => {
|
||||
if no_ambiguity {
|
||||
assert!(import.imported_module.get().is_none());
|
||||
let err = match self.make_path_suggestion(
|
||||
span,
|
||||
import.module_path.clone(),
|
||||
|
|
|
@ -504,6 +504,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
|
|||
|
||||
match ct.ty.kind() {
|
||||
ty::Uint(_) => {}
|
||||
ty::Bool => {}
|
||||
_ => {
|
||||
bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct);
|
||||
}
|
||||
|
|
|
@ -297,14 +297,23 @@ pub struct IntoIter<K, V> {
|
|||
length: usize,
|
||||
}
|
||||
|
||||
#[stable(feature = "collection_debug", since = "1.17.0")]
|
||||
impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IntoIter<K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
impl<K, V> IntoIter<K, V> {
|
||||
/// Returns an iterator of references over the remaining items.
|
||||
#[inline]
|
||||
pub(super) fn iter(&self) -> Iter<'_, K, V> {
|
||||
let range = Range {
|
||||
front: self.front.as_ref().map(|f| f.reborrow()),
|
||||
back: self.back.as_ref().map(|b| b.reborrow()),
|
||||
};
|
||||
f.debug_list().entries(range).finish()
|
||||
|
||||
Iter { range: range, length: self.length }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "collection_debug", since = "1.17.0")]
|
||||
impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IntoIter<K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_list().entries(self.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -351,11 +360,17 @@ impl<K, V: fmt::Debug> fmt::Debug for Values<'_, K, V> {
|
|||
///
|
||||
/// [`values_mut`]: BTreeMap::values_mut
|
||||
#[stable(feature = "map_values_mut", since = "1.10.0")]
|
||||
#[derive(Debug)]
|
||||
pub struct ValuesMut<'a, K: 'a, V: 'a> {
|
||||
inner: IterMut<'a, K, V>,
|
||||
}
|
||||
|
||||
#[stable(feature = "map_values_mut", since = "1.10.0")]
|
||||
impl<K, V: fmt::Debug> fmt::Debug for ValuesMut<'_, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// An owning iterator over the keys of a `BTreeMap`.
|
||||
///
|
||||
/// This `struct` is created by the [`into_keys`] method on [`BTreeMap`].
|
||||
|
@ -363,11 +378,17 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
|
|||
///
|
||||
/// [`into_keys`]: BTreeMap::into_keys
|
||||
#[unstable(feature = "map_into_keys_values", issue = "75294")]
|
||||
#[derive(Debug)]
|
||||
pub struct IntoKeys<K, V> {
|
||||
inner: IntoIter<K, V>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "map_into_keys_values", issue = "75294")]
|
||||
impl<K: fmt::Debug, V> fmt::Debug for IntoKeys<K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_list().entries(self.inner.iter().map(|(key, _)| key)).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// An owning iterator over the values of a `BTreeMap`.
|
||||
///
|
||||
/// This `struct` is created by the [`into_values`] method on [`BTreeMap`].
|
||||
|
@ -375,11 +396,17 @@ pub struct IntoKeys<K, V> {
|
|||
///
|
||||
/// [`into_values`]: BTreeMap::into_values
|
||||
#[unstable(feature = "map_into_keys_values", issue = "75294")]
|
||||
#[derive(Debug)]
|
||||
pub struct IntoValues<K, V> {
|
||||
inner: IntoIter<K, V>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "map_into_keys_values", issue = "75294")]
|
||||
impl<K, V: fmt::Debug> fmt::Debug for IntoValues<K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over a sub-range of entries in a `BTreeMap`.
|
||||
///
|
||||
/// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its
|
||||
|
@ -1465,6 +1492,14 @@ impl<K, V> ExactSizeIterator for IterMut<'_, K, V> {
|
|||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
impl<K, V> FusedIterator for IterMut<'_, K, V> {}
|
||||
|
||||
impl<'a, K, V> IterMut<'a, K, V> {
|
||||
/// Returns an iterator of references over the remaining items.
|
||||
#[inline]
|
||||
pub(super) fn iter(&self) -> Iter<'_, K, V> {
|
||||
Iter { range: self.range.iter(), length: self.length }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K, V> IntoIterator for BTreeMap<K, V> {
|
||||
type Item = (K, V);
|
||||
|
@ -1949,6 +1984,15 @@ impl<'a, K, V> RangeMut<'a, K, V> {
|
|||
unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) {
|
||||
unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() }
|
||||
}
|
||||
|
||||
/// Returns an iterator of references over the remaining items.
|
||||
#[inline]
|
||||
pub(super) fn iter(&self) -> Range<'_, K, V> {
|
||||
Range {
|
||||
front: self.front.as_ref().map(|f| f.reborrow()),
|
||||
back: self.back.as_ref().map(|b| b.reborrow()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "btree_range", since = "1.17.0")]
|
||||
|
|
76
library/core/tests/num/wrapping.rs
Normal file
76
library/core/tests/num/wrapping.rs
Normal file
|
@ -0,0 +1,76 @@
|
|||
use core::num::Wrapping;
|
||||
|
||||
macro_rules! wrapping_operation {
|
||||
($result:expr, $lhs:ident $op:tt $rhs:expr) => {
|
||||
assert_eq!($result, $lhs $op $rhs);
|
||||
assert_eq!($result, &$lhs $op $rhs);
|
||||
assert_eq!($result, $lhs $op &$rhs);
|
||||
assert_eq!($result, &$lhs $op &$rhs);
|
||||
};
|
||||
($result:expr, $op:tt $expr:expr) => {
|
||||
assert_eq!($result, $op $expr);
|
||||
assert_eq!($result, $op &$expr);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! wrapping_assignment {
|
||||
($result:expr, $lhs:ident $op:tt $rhs:expr) => {
|
||||
let mut lhs1 = $lhs;
|
||||
lhs1 $op $rhs;
|
||||
assert_eq!($result, lhs1);
|
||||
|
||||
let mut lhs2 = $lhs;
|
||||
lhs2 $op &$rhs;
|
||||
assert_eq!($result, lhs2);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! wrapping_test {
|
||||
($type:ty, $min:expr, $max:expr) => {
|
||||
#[test]
|
||||
fn wrapping_$type() {
|
||||
let zero: Wrapping<$type> = Wrapping(0);
|
||||
let one: Wrapping<$type> = Wrapping(1);
|
||||
let min: Wrapping<$type> = Wrapping($min);
|
||||
let max: Wrapping<$type> = Wrapping($max);
|
||||
|
||||
wrapping_operation!(min, max + one);
|
||||
wrapping_assignment!(min, max += one);
|
||||
wrapping_operation!(max, min - one);
|
||||
wrapping_assignment!(max, min -= one);
|
||||
wrapping_operation!(max, max * one);
|
||||
wrapping_assignment!(max, max *= one);
|
||||
wrapping_operation!(max, max / one);
|
||||
wrapping_assignment!(max, max /= one);
|
||||
wrapping_operation!(zero, max % one);
|
||||
wrapping_assignment!(zero, max %= one);
|
||||
wrapping_operation!(zero, zero & max);
|
||||
wrapping_assignment!(zero, zero &= max);
|
||||
wrapping_operation!(max, zero | max);
|
||||
wrapping_assignment!(max, zero |= max);
|
||||
wrapping_operation!(zero, max ^ max);
|
||||
wrapping_assignment!(zero, max ^= max);
|
||||
wrapping_operation!(zero, zero << 1usize);
|
||||
wrapping_assignment!(zero, zero <<= 1usize);
|
||||
wrapping_operation!(zero, zero >> 1usize);
|
||||
wrapping_assignment!(zero, zero >>= 1usize);
|
||||
wrapping_operation!(zero, -zero);
|
||||
wrapping_operation!(max, !min);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
wrapping_test!(i8, i8::MIN, i8::MAX);
|
||||
wrapping_test!(i16, i16::MIN, i16::MAX);
|
||||
wrapping_test!(i32, i32::MIN, i32::MAX);
|
||||
wrapping_test!(i64, i64::MIN, i64::MAX);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
wrapping_test!(i128, i128::MIN, i128::MAX);
|
||||
wrapping_test!(isize, isize::MIN, isize::MAX);
|
||||
wrapping_test!(u8, u8::MIN, u8::MAX);
|
||||
wrapping_test!(u16, u16::MIN, u16::MAX);
|
||||
wrapping_test!(u32, u32::MIN, u32::MAX);
|
||||
wrapping_test!(u64, u64::MIN, u64::MAX);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
wrapping_test!(u128, u128::MIN, u128::MAX);
|
||||
wrapping_test!(usize, usize::MIN, usize::MAX);
|
|
@ -2042,13 +2042,9 @@ impl<K, V> ExactSizeIterator for ValuesMut<'_, K, V> {
|
|||
impl<K, V> FusedIterator for ValuesMut<'_, K, V> {}
|
||||
|
||||
#[stable(feature = "std_debug", since = "1.16.0")]
|
||||
impl<K, V> fmt::Debug for ValuesMut<'_, K, V>
|
||||
where
|
||||
K: fmt::Debug,
|
||||
V: fmt::Debug,
|
||||
{
|
||||
impl<K, V: fmt::Debug> fmt::Debug for ValuesMut<'_, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_list().entries(self.inner.iter()).finish()
|
||||
f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2076,7 +2072,7 @@ impl<K, V> ExactSizeIterator for IntoKeys<K, V> {
|
|||
impl<K, V> FusedIterator for IntoKeys<K, V> {}
|
||||
|
||||
#[unstable(feature = "map_into_keys_values", issue = "75294")]
|
||||
impl<K: Debug, V: Debug> fmt::Debug for IntoKeys<K, V> {
|
||||
impl<K: Debug, V> fmt::Debug for IntoKeys<K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish()
|
||||
}
|
||||
|
@ -2106,7 +2102,7 @@ impl<K, V> ExactSizeIterator for IntoValues<K, V> {
|
|||
impl<K, V> FusedIterator for IntoValues<K, V> {}
|
||||
|
||||
#[unstable(feature = "map_into_keys_values", issue = "75294")]
|
||||
impl<K: Debug, V: Debug> fmt::Debug for IntoValues<K, V> {
|
||||
impl<K, V: Debug> fmt::Debug for IntoValues<K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish()
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use crate::cell::RefCell;
|
|||
use crate::fmt;
|
||||
use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter};
|
||||
use crate::lazy::SyncOnceCell;
|
||||
use crate::sync::atomic::{AtomicBool, Ordering};
|
||||
use crate::sync::{Mutex, MutexGuard};
|
||||
use crate::sys::stdio;
|
||||
use crate::sys_common;
|
||||
|
@ -16,19 +17,33 @@ use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
|
|||
use crate::thread::LocalKey;
|
||||
|
||||
thread_local! {
|
||||
/// Stdout used by print! and println! macros
|
||||
/// Used by the test crate to capture the output of the print! and println! macros.
|
||||
static LOCAL_STDOUT: RefCell<Option<Box<dyn Write + Send>>> = {
|
||||
RefCell::new(None)
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
/// Stderr used by eprint! and eprintln! macros, and panics
|
||||
/// Used by the test crate to capture the output of the eprint! and eprintln! macros, and panics.
|
||||
static LOCAL_STDERR: RefCell<Option<Box<dyn Write + Send>>> = {
|
||||
RefCell::new(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Flag to indicate LOCAL_STDOUT and/or LOCAL_STDERR is used.
|
||||
///
|
||||
/// If both are None and were never set on any thread, this flag is set to
|
||||
/// false, and both LOCAL_STDOUT and LOCAL_STDOUT can be safely ignored on all
|
||||
/// threads, saving some time and memory registering an unused thread local.
|
||||
///
|
||||
/// Note about memory ordering: This contains information about whether two
|
||||
/// thread local variables might be in use. Although this is a global flag, the
|
||||
/// memory ordering between threads does not matter: we only want this flag to
|
||||
/// have a consistent order between set_print/set_panic and print_to *within
|
||||
/// the same thread*. Within the same thread, things always have a perfectly
|
||||
/// consistent order. So Ordering::Relaxed is fine.
|
||||
static LOCAL_STREAMS: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
/// A handle to a raw instance of the standard input stream of this process.
|
||||
///
|
||||
/// This handle is not synchronized or buffered in any fashion. Constructed via
|
||||
|
@ -890,10 +905,18 @@ impl fmt::Debug for StderrLock<'_> {
|
|||
#[doc(hidden)]
|
||||
pub fn set_panic(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
|
||||
use crate::mem;
|
||||
LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|mut s| {
|
||||
let _ = s.flush();
|
||||
Some(s)
|
||||
})
|
||||
if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
|
||||
// LOCAL_STDERR is definitely None since LOCAL_STREAMS is false.
|
||||
return None;
|
||||
}
|
||||
let s = LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(
|
||||
|mut s| {
|
||||
let _ = s.flush();
|
||||
Some(s)
|
||||
},
|
||||
);
|
||||
LOCAL_STREAMS.store(true, Ordering::Relaxed);
|
||||
s
|
||||
}
|
||||
|
||||
/// Resets the thread-local stdout handle to the specified writer
|
||||
|
@ -913,10 +936,18 @@ pub fn set_panic(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write +
|
|||
#[doc(hidden)]
|
||||
pub fn set_print(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
|
||||
use crate::mem;
|
||||
LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|mut s| {
|
||||
let _ = s.flush();
|
||||
Some(s)
|
||||
})
|
||||
if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
|
||||
// LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false.
|
||||
return None;
|
||||
}
|
||||
let s = LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(
|
||||
|mut s| {
|
||||
let _ = s.flush();
|
||||
Some(s)
|
||||
},
|
||||
);
|
||||
LOCAL_STREAMS.store(true, Ordering::Relaxed);
|
||||
s
|
||||
}
|
||||
|
||||
/// Write `args` to output stream `local_s` if possible, `global_s`
|
||||
|
@ -937,20 +968,26 @@ fn print_to<T>(
|
|||
) where
|
||||
T: Write,
|
||||
{
|
||||
let result = local_s
|
||||
.try_with(|s| {
|
||||
// Note that we completely remove a local sink to write to in case
|
||||
// our printing recursively panics/prints, so the recursive
|
||||
// panic/print goes to the global sink instead of our local sink.
|
||||
let prev = s.borrow_mut().take();
|
||||
if let Some(mut w) = prev {
|
||||
let result = w.write_fmt(args);
|
||||
*s.borrow_mut() = Some(w);
|
||||
return result;
|
||||
}
|
||||
global_s().write_fmt(args)
|
||||
let result = LOCAL_STREAMS
|
||||
.load(Ordering::Relaxed)
|
||||
.then(|| {
|
||||
local_s
|
||||
.try_with(|s| {
|
||||
// Note that we completely remove a local sink to write to in case
|
||||
// our printing recursively panics/prints, so the recursive
|
||||
// panic/print goes to the global sink instead of our local sink.
|
||||
let prev = s.borrow_mut().take();
|
||||
if let Some(mut w) = prev {
|
||||
let result = w.write_fmt(args);
|
||||
*s.borrow_mut() = Some(w);
|
||||
return result;
|
||||
}
|
||||
global_s().write_fmt(args)
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
.unwrap_or_else(|_| global_s().write_fmt(args));
|
||||
.flatten()
|
||||
.unwrap_or_else(|| global_s().write_fmt(args));
|
||||
|
||||
if let Err(e) = result {
|
||||
panic!("failed printing to {}: {}", label, e);
|
||||
|
|
|
@ -226,6 +226,7 @@
|
|||
#![feature(asm)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(atomic_mut_ptr)]
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(c_variadic)]
|
||||
#![feature(cfg_accessible)]
|
||||
|
|
|
@ -25,6 +25,19 @@ pub trait AsRawFd {
|
|||
/// This method does **not** pass ownership of the raw file descriptor
|
||||
/// to the caller. The descriptor is only guaranteed to be valid while
|
||||
/// the original object has not yet been destroyed.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs::File;
|
||||
/// # use std::io;
|
||||
/// use std::os::unix::io::{AsRawFd, RawFd};
|
||||
///
|
||||
/// let mut f = File::open("foo.txt")?;
|
||||
/// // Note that `raw_fd` is only valid as long as `f` exists.
|
||||
/// let raw_fd: RawFd = f.as_raw_fd();
|
||||
/// # Ok::<(), io::Error>(())
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn as_raw_fd(&self) -> RawFd;
|
||||
}
|
||||
|
@ -45,6 +58,21 @@ pub trait FromRawFd {
|
|||
/// descriptor they are wrapping. Usage of this function could
|
||||
/// accidentally allow violating this contract which can cause memory
|
||||
/// unsafety in code that relies on it being true.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs::File;
|
||||
/// # use std::io;
|
||||
/// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
|
||||
///
|
||||
/// let f = File::open("foo.txt")?;
|
||||
/// let raw_fd: RawFd = f.into_raw_fd();
|
||||
/// // SAFETY: no other functions should call `from_raw_fd`, so there
|
||||
/// // is only one owner for the file descriptor.
|
||||
/// let f = unsafe { File::from_raw_fd(raw_fd) };
|
||||
/// # Ok::<(), io::Error>(())
|
||||
/// ```
|
||||
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self;
|
||||
}
|
||||
|
@ -58,6 +86,18 @@ pub trait IntoRawFd {
|
|||
/// This function **transfers ownership** of the underlying file descriptor
|
||||
/// to the caller. Callers are then the unique owners of the file descriptor
|
||||
/// and must close the descriptor once it's no longer needed.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs::File;
|
||||
/// # use std::io;
|
||||
/// use std::os::unix::io::{IntoRawFd, RawFd};
|
||||
///
|
||||
/// let f = File::open("foo.txt")?;
|
||||
/// let raw_fd: RawFd = f.into_raw_fd();
|
||||
/// # Ok::<(), io::Error>(())
|
||||
/// ```
|
||||
#[stable(feature = "into_raw_os", since = "1.4.0")]
|
||||
fn into_raw_fd(self) -> RawFd;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// check-pass
|
||||
|
||||
// Minimized case from #62767.
|
||||
mod m {
|
||||
pub enum Same {
|
||||
Same,
|
||||
|
@ -8,8 +7,22 @@ mod m {
|
|||
|
||||
use m::*;
|
||||
|
||||
// The variant `Same` introduced by this import is not considered when resolving the prefix
|
||||
// `Same::` during import validation (issue #62767).
|
||||
use Same::Same;
|
||||
// The variant `Same` introduced by this import is also considered when resolving the prefix
|
||||
// `Same::` during import validation to avoid effects similar to time travel (#74556).
|
||||
use Same::Same; //~ ERROR unresolved import `Same`
|
||||
|
||||
// Case from #74556.
|
||||
mod foo {
|
||||
pub mod bar {
|
||||
pub mod bar {
|
||||
pub fn foobar() {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use foo::*;
|
||||
use bar::bar; //~ ERROR unresolved import `bar::bar`
|
||||
//~| ERROR inconsistent resolution for an import
|
||||
use bar::foobar;
|
||||
|
||||
fn main() {}
|
||||
|
|
21
src/test/ui/imports/issue-62767.stderr
Normal file
21
src/test/ui/imports/issue-62767.stderr
Normal file
|
@ -0,0 +1,21 @@
|
|||
error: inconsistent resolution for an import
|
||||
--> $DIR/issue-62767.rs:24:5
|
||||
|
|
||||
LL | use bar::bar;
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0432]: unresolved import `Same`
|
||||
--> $DIR/issue-62767.rs:12:5
|
||||
|
|
||||
LL | use Same::Same;
|
||||
| ^^^^ `Same` is a variant, not a module
|
||||
|
||||
error[E0432]: unresolved import `bar::bar`
|
||||
--> $DIR/issue-62767.rs:24:5
|
||||
|
|
||||
LL | use bar::bar;
|
||||
| ^^^^^^^^ no `bar` in `foo::bar::bar`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0432`.
|
|
@ -9,9 +9,26 @@ impl MyStruct {
|
|||
fn use_mut(&mut self) {}
|
||||
}
|
||||
|
||||
struct Mutable {
|
||||
msg: &'static str,
|
||||
}
|
||||
impl Drop for Mutable {
|
||||
fn drop(&mut self) {
|
||||
println!("{}", self.msg);
|
||||
}
|
||||
}
|
||||
|
||||
struct Mutable2 { // this one has drop glue but not a Drop impl
|
||||
msg: &'static str,
|
||||
other: String,
|
||||
}
|
||||
|
||||
const ARRAY: [u8; 1] = [25];
|
||||
const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
|
||||
const RAW_PTR: *mut u8 = 1 as *mut u8;
|
||||
const MUTABLE: Mutable = Mutable { msg: "" };
|
||||
const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() };
|
||||
const VEC: Vec<i32> = Vec::new();
|
||||
|
||||
fn main() {
|
||||
ARRAY[0] = 5; //~ WARN attempting to modify
|
||||
|
@ -29,4 +46,8 @@ fn main() {
|
|||
*RAW_PTR = 0;
|
||||
*MY_STRUCT.raw_ptr = 0;
|
||||
}
|
||||
|
||||
MUTABLE.msg = "wow"; // no warning, because Drop observes the mutation
|
||||
MUTABLE2.msg = "wow"; //~ WARN attempting to modify
|
||||
VEC.push(0); //~ WARN taking a mutable reference to a `const` item
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
warning: attempting to modify a `const` item
|
||||
--> $DIR/lint-const-item-mutation.rs:17:5
|
||||
--> $DIR/lint-const-item-mutation.rs:34:5
|
||||
|
|
||||
LL | ARRAY[0] = 5;
|
||||
| ^^^^^^^^^^^^
|
||||
|
@ -7,39 +7,39 @@ LL | ARRAY[0] = 5;
|
|||
= note: `#[warn(const_item_mutation)]` on by default
|
||||
= note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
|
||||
note: `const` item defined here
|
||||
--> $DIR/lint-const-item-mutation.rs:12:1
|
||||
--> $DIR/lint-const-item-mutation.rs:26:1
|
||||
|
|
||||
LL | const ARRAY: [u8; 1] = [25];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: attempting to modify a `const` item
|
||||
--> $DIR/lint-const-item-mutation.rs:18:5
|
||||
--> $DIR/lint-const-item-mutation.rs:35:5
|
||||
|
|
||||
LL | MY_STRUCT.field = false;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
|
||||
note: `const` item defined here
|
||||
--> $DIR/lint-const-item-mutation.rs:13:1
|
||||
--> $DIR/lint-const-item-mutation.rs:27:1
|
||||
|
|
||||
LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: attempting to modify a `const` item
|
||||
--> $DIR/lint-const-item-mutation.rs:19:5
|
||||
--> $DIR/lint-const-item-mutation.rs:36:5
|
||||
|
|
||||
LL | MY_STRUCT.inner_array[0] = 'b';
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
|
||||
note: `const` item defined here
|
||||
--> $DIR/lint-const-item-mutation.rs:13:1
|
||||
--> $DIR/lint-const-item-mutation.rs:27:1
|
||||
|
|
||||
LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: taking a mutable reference to a `const` item
|
||||
--> $DIR/lint-const-item-mutation.rs:20:5
|
||||
--> $DIR/lint-const-item-mutation.rs:37:5
|
||||
|
|
||||
LL | MY_STRUCT.use_mut();
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -52,13 +52,13 @@ note: mutable reference created due to call to this method
|
|||
LL | fn use_mut(&mut self) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
note: `const` item defined here
|
||||
--> $DIR/lint-const-item-mutation.rs:13:1
|
||||
--> $DIR/lint-const-item-mutation.rs:27:1
|
||||
|
|
||||
LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: taking a mutable reference to a `const` item
|
||||
--> $DIR/lint-const-item-mutation.rs:21:5
|
||||
--> $DIR/lint-const-item-mutation.rs:38:5
|
||||
|
|
||||
LL | &mut MY_STRUCT;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
@ -66,13 +66,13 @@ LL | &mut MY_STRUCT;
|
|||
= note: each usage of a `const` item creates a new temporary
|
||||
= note: the mutable reference will refer to this temporary, not the original `const` item
|
||||
note: `const` item defined here
|
||||
--> $DIR/lint-const-item-mutation.rs:13:1
|
||||
--> $DIR/lint-const-item-mutation.rs:27:1
|
||||
|
|
||||
LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: taking a mutable reference to a `const` item
|
||||
--> $DIR/lint-const-item-mutation.rs:22:5
|
||||
--> $DIR/lint-const-item-mutation.rs:39:5
|
||||
|
|
||||
LL | (&mut MY_STRUCT).use_mut();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
@ -80,10 +80,48 @@ LL | (&mut MY_STRUCT).use_mut();
|
|||
= note: each usage of a `const` item creates a new temporary
|
||||
= note: the mutable reference will refer to this temporary, not the original `const` item
|
||||
note: `const` item defined here
|
||||
--> $DIR/lint-const-item-mutation.rs:13:1
|
||||
--> $DIR/lint-const-item-mutation.rs:27:1
|
||||
|
|
||||
LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: 6 warnings emitted
|
||||
warning: attempting to modify a `const` item
|
||||
--> $DIR/lint-const-item-mutation.rs:51:5
|
||||
|
|
||||
LL | MUTABLE2.msg = "wow";
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
|
||||
note: `const` item defined here
|
||||
--> $DIR/lint-const-item-mutation.rs:30:1
|
||||
|
|
||||
LL | const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: taking a mutable reference to a `const` item
|
||||
--> $DIR/lint-const-item-mutation.rs:52:5
|
||||
|
|
||||
LL | VEC.push(0);
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: each usage of a `const` item creates a new temporary
|
||||
= note: the mutable reference will refer to this temporary, not the original `const` item
|
||||
note: mutable reference created due to call to this method
|
||||
--> $SRC_DIR/alloc/src/vec.rs:LL:COL
|
||||
|
|
||||
LL | / pub fn push(&mut self, value: T) {
|
||||
LL | | // This will panic or abort if we would allocate > isize::MAX bytes
|
||||
LL | | // or if the length increment would overflow for zero-sized types.
|
||||
LL | | if self.len == self.buf.capacity() {
|
||||
... |
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_____^
|
||||
note: `const` item defined here
|
||||
--> $DIR/lint-const-item-mutation.rs:31:1
|
||||
|
|
||||
LL | const VEC: Vec<i32> = Vec::new();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: 8 warnings emitted
|
||||
|
||||
|
|
18
src/test/ui/symbol-names/issue-76365.rs
Normal file
18
src/test/ui/symbol-names/issue-76365.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
// check-pass
|
||||
// revisions: legacy v0
|
||||
//[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib
|
||||
//[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib
|
||||
|
||||
#![feature(min_const_generics)]
|
||||
|
||||
pub struct Bar<const F: bool>;
|
||||
|
||||
impl Bar<true> {
|
||||
pub fn foo() {}
|
||||
}
|
||||
|
||||
impl<const F: bool> Bar<F> {
|
||||
pub fn bar() {}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,77 +0,0 @@
|
|||
// run-pass
|
||||
|
||||
use std::num::Wrapping;
|
||||
|
||||
macro_rules! wrapping_operation {
|
||||
($result:expr, $lhs:ident $op:tt $rhs:expr) => {
|
||||
assert_eq!($result, $lhs $op $rhs);
|
||||
assert_eq!($result, &$lhs $op $rhs);
|
||||
assert_eq!($result, $lhs $op &$rhs);
|
||||
assert_eq!($result, &$lhs $op &$rhs);
|
||||
};
|
||||
($result:expr, $op:tt $expr:expr) => {
|
||||
assert_eq!($result, $op $expr);
|
||||
assert_eq!($result, $op &$expr);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! wrapping_assignment {
|
||||
($result:expr, $lhs:ident $op:tt $rhs:expr) => {
|
||||
let mut lhs1 = $lhs;
|
||||
lhs1 $op $rhs;
|
||||
assert_eq!($result, lhs1);
|
||||
|
||||
let mut lhs2 = $lhs;
|
||||
lhs2 $op &$rhs;
|
||||
assert_eq!($result, lhs2);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! wrapping_test {
|
||||
($type:ty, $min:expr, $max:expr) => {
|
||||
let zero: Wrapping<$type> = Wrapping(0);
|
||||
let one: Wrapping<$type> = Wrapping(1);
|
||||
let min: Wrapping<$type> = Wrapping($min);
|
||||
let max: Wrapping<$type> = Wrapping($max);
|
||||
|
||||
wrapping_operation!(min, max + one);
|
||||
wrapping_assignment!(min, max += one);
|
||||
wrapping_operation!(max, min - one);
|
||||
wrapping_assignment!(max, min -= one);
|
||||
wrapping_operation!(max, max * one);
|
||||
wrapping_assignment!(max, max *= one);
|
||||
wrapping_operation!(max, max / one);
|
||||
wrapping_assignment!(max, max /= one);
|
||||
wrapping_operation!(zero, max % one);
|
||||
wrapping_assignment!(zero, max %= one);
|
||||
wrapping_operation!(zero, zero & max);
|
||||
wrapping_assignment!(zero, zero &= max);
|
||||
wrapping_operation!(max, zero | max);
|
||||
wrapping_assignment!(max, zero |= max);
|
||||
wrapping_operation!(zero, max ^ max);
|
||||
wrapping_assignment!(zero, max ^= max);
|
||||
wrapping_operation!(zero, zero << 1usize);
|
||||
wrapping_assignment!(zero, zero <<= 1usize);
|
||||
wrapping_operation!(zero, zero >> 1usize);
|
||||
wrapping_assignment!(zero, zero >>= 1usize);
|
||||
wrapping_operation!(zero, -zero);
|
||||
wrapping_operation!(max, !min);
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
wrapping_test!(i8, std::i8::MIN, std::i8::MAX);
|
||||
wrapping_test!(i16, std::i16::MIN, std::i16::MAX);
|
||||
wrapping_test!(i32, std::i32::MIN, std::i32::MAX);
|
||||
wrapping_test!(i64, std::i64::MIN, std::i64::MAX);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
wrapping_test!(i128, std::i128::MIN, std::i128::MAX);
|
||||
wrapping_test!(isize, std::isize::MIN, std::isize::MAX);
|
||||
wrapping_test!(u8, std::u8::MIN, std::u8::MAX);
|
||||
wrapping_test!(u16, std::u16::MIN, std::u16::MAX);
|
||||
wrapping_test!(u32, std::u32::MIN, std::u32::MAX);
|
||||
wrapping_test!(u64, std::u64::MIN, std::u64::MAX);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
wrapping_test!(u128, std::u128::MIN, std::u128::MAX);
|
||||
wrapping_test!(usize, std::usize::MIN, std::usize::MAX);
|
||||
}
|
|
@ -294,6 +294,10 @@ impl Builder {
|
|||
if self.versions.channel() != rust_version {
|
||||
self.write_channel_files(&rust_version, &manifest);
|
||||
}
|
||||
if self.versions.channel() == "stable" {
|
||||
let major_minor = rust_version.split('.').take(2).collect::<Vec<_>>().join(".");
|
||||
self.write_channel_files(&major_minor, &manifest);
|
||||
}
|
||||
}
|
||||
|
||||
/// If a tool does not pass its tests, don't ship it.
|
||||
|
|
Loading…
Add table
Reference in a new issue