Auto merge of #138208 - jhpratt:rollup-hlqyu51, r=jhpratt

Rollup of 5 pull requests

Successful merges:

 - #136642 (Put the alloc unit tests in a separate alloctests package)
 - #137528 (Windows: Fix error in `fs::rename` on Windows 1607)
 - #137685 (self-contained linker: conservatively default to `-znostart-stop-gc` on x64 linux)
 - #137757 (On long spans, trim the middle of them to make them fit in the terminal width)
 - #138189 (Mention `env` and `option_env` macros in `std::env::var` docs)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-03-08 12:30:31 +00:00
commit 79b43dfde9
109 changed files with 1046 additions and 865 deletions

View File

@ -12,15 +12,15 @@ index 7165c3e48af..968552ad435 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -11,7 +11,7 @@ test = { path = "../test" }
edition = "2021"
bench = false
[dependencies]
core = { path = "../core", public = true }
-compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std', 'no-f16-f128'] }
[dev-dependencies]
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
[features]
compiler-builtins-mem = ['compiler_builtins/mem']
--
2.34.1

View File

@ -3382,6 +3382,35 @@ fn add_lld_args(
// this, `wasm-component-ld`, which is overridden if this option is passed.
if !sess.target.is_like_wasm {
cmd.cc_arg("-fuse-ld=lld");
// On ELF platforms like at least x64 linux, GNU ld and LLD have opposite defaults on some
// section garbage-collection features. For example, the somewhat popular `linkme` crate and
// its dependents rely in practice on this difference: when using lld, they need `-z
// nostart-stop-gc` to prevent encapsulation symbols and sections from being
// garbage-collected.
//
// More information about all this can be found in:
// - https://maskray.me/blog/2021-01-31-metadata-sections-comdat-and-shf-link-order
// - https://lld.llvm.org/ELF/start-stop-gc
//
// So when using lld, we restore, for now, the traditional behavior to help migration, but
// will remove it in the future.
// Since this only disables an optimization, it shouldn't create issues, but is in theory
// slightly suboptimal. However, it:
// - doesn't have any visible impact on our benchmarks
// - reduces the need to disable lld for the crates that depend on this
//
// Note that lld can detect some cases where this difference is relied on, and emits a
// dedicated error to add this link arg. We could make use of this error to emit an FCW. As
// of writing this, we don't do it, because lld is already enabled by default on nightly
// without this mitigation: no working project would see the FCW, so we do this to help
// stabilization.
//
// FIXME: emit an FCW if linking fails due its absence, and then remove this link-arg in the
// future.
if sess.target.llvm_target == "x86_64-unknown-linux-gnu" {
cmd.link_arg("-znostart-stop-gc");
}
}
if !flavor.is_gnu() {

View File

@ -113,24 +113,11 @@ impl Margin {
self.computed_left > 0
}
fn was_cut_right(&self, line_len: usize) -> bool {
let right =
if self.computed_right == self.span_right || self.computed_right == self.label_right {
// FIXME: This comment refers to the only callsite of this method.
// Rephrase it or refactor it, so it can stand on its own.
// Account for the "..." padding given above. Otherwise we end up with code lines
// that do fit but end in "..." as if they were trimmed.
// FIXME: Don't hard-code this offset. Is this meant to represent
// `2 * str_width(self.margin())`?
self.computed_right - 6
} else {
self.computed_right
};
right < line_len && self.computed_left + self.column_width < line_len
}
fn compute(&mut self, max_line_len: usize) {
// When there's a lot of whitespace (>20), we want to trim it as it is useless.
// FIXME: this doesn't account for '\t', but to do so correctly we need to perform that
// calculation later, right before printing in order to be accurate with both unicode
// handling and trimming of long lines.
self.computed_left = if self.whitespace_left > 20 {
self.whitespace_left - 16 // We want some padding.
} else {
@ -616,7 +603,6 @@ pub struct HumanEmitter {
#[setters(skip)]
fallback_bundle: LazyFallbackBundle,
short_message: bool,
teach: bool,
ui_testing: bool,
ignored_directories_in_source_blocks: Vec<String>,
diagnostic_width: Option<usize>,
@ -642,7 +628,6 @@ impl HumanEmitter {
fluent_bundle: None,
fallback_bundle,
short_message: false,
teach: false,
ui_testing: false,
ignored_directories_in_source_blocks: Vec::new(),
diagnostic_width: None,
@ -670,43 +655,43 @@ impl HumanEmitter {
width_offset: usize,
code_offset: usize,
margin: Margin,
) {
// Tabs are assumed to have been replaced by spaces in calling code.
debug_assert!(!source_string.contains('\t'));
) -> usize {
let line_len = source_string.len();
// Create the source line we will highlight.
let left = margin.left(line_len);
let right = margin.right(line_len);
// FIXME: The following code looks fishy. See #132860.
// On long lines, we strip the source line, accounting for unicode.
let mut taken = 0;
let code: String = source_string
.chars()
.skip(left)
.take_while(|ch| {
// Make sure that the trimming on the right will fall within the terminal width.
let next = char_width(*ch);
if taken + next > right - left {
return false;
}
taken += next;
true
})
.enumerate()
.skip_while(|(i, _)| *i < left)
.take_while(|(i, _)| *i < right)
.map(|(_, c)| c)
.collect();
let code = normalize_whitespace(&code);
let was_cut_right =
source_string.chars().enumerate().skip_while(|(i, _)| *i < right).next().is_some();
buffer.puts(line_offset, code_offset, &code, Style::Quotation);
let placeholder = self.margin();
if margin.was_cut_left() {
// We have stripped some code/whitespace from the beginning, make it clear.
buffer.puts(line_offset, code_offset, placeholder, Style::LineNumber);
}
if margin.was_cut_right(line_len) {
if was_cut_right {
let padding = str_width(placeholder);
// We have stripped some code after the rightmost span end, make it clear we did so.
buffer.puts(line_offset, code_offset + taken - padding, placeholder, Style::LineNumber);
buffer.puts(
line_offset,
code_offset + str_width(&code) - padding,
placeholder,
Style::LineNumber,
);
}
buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber);
self.draw_col_separator_no_space(buffer, line_offset, width_offset - 2);
left
}
#[instrument(level = "trace", skip(self), ret)]
@ -738,22 +723,16 @@ impl HumanEmitter {
return Vec::new();
}
let source_string = match file.get_line(line.line_index - 1) {
Some(s) => normalize_whitespace(&s),
None => return Vec::new(),
let Some(source_string) = file.get_line(line.line_index - 1) else {
return Vec::new();
};
trace!(?source_string);
let line_offset = buffer.num_lines();
// Left trim
let left = margin.left(source_string.len());
// Left trim.
// FIXME: This looks fishy. See #132860.
// Account for unicode characters of width !=0 that were removed.
let left = source_string.chars().take(left).map(|ch| char_width(ch)).sum();
self.draw_line(
let left = self.draw_line(
buffer,
&source_string,
line.line_index,
@ -784,7 +763,7 @@ impl HumanEmitter {
let mut short_start = true;
for ann in &line.annotations {
if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
if source_string.chars().take(ann.start_col.display).all(|c| c.is_whitespace()) {
if source_string.chars().take(ann.start_col.file).all(|c| c.is_whitespace()) {
let uline = self.underline(ann.is_primary);
let chr = uline.multiline_whole_line;
annotations.push((depth, uline.style));
@ -903,11 +882,16 @@ impl HumanEmitter {
// | x_span
// <EMPTY LINE>
//
let mut overlap = vec![false; annotations.len()];
let mut annotations_position = vec![];
let mut line_len: usize = 0;
let mut p = 0;
for (i, annotation) in annotations.iter().enumerate() {
for (j, next) in annotations.iter().enumerate() {
if overlaps(next, annotation, 0) && j > i {
overlap[i] = true;
overlap[j] = true;
}
if overlaps(next, annotation, 0) // This label overlaps with another one and both
&& annotation.has_label() // take space (they have text and are not
&& j > i // multiline lines).
@ -1035,24 +1019,21 @@ impl HumanEmitter {
let pos = pos + 1;
match annotation.annotation_type {
AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => {
let pre: usize = source_string
.chars()
.take(annotation.start_col.file)
.skip(left)
.map(|c| char_width(c))
.sum();
self.draw_range(
buffer,
underline.multiline_horizontal,
line_offset + pos,
width_offset + depth,
(code_offset + annotation.start_col.display).saturating_sub(left),
code_offset + pre,
underline.style,
);
}
_ if self.teach => {
buffer.set_style_range(
line_offset,
(code_offset + annotation.start_col.display).saturating_sub(left),
(code_offset + annotation.end_col.display).saturating_sub(left),
underline.style,
annotation.is_primary,
);
}
_ => {}
}
}
@ -1072,11 +1053,18 @@ impl HumanEmitter {
let underline = self.underline(annotation.is_primary);
let pos = pos + 1;
let code_offset = code_offset
+ source_string
.chars()
.take(annotation.start_col.file)
.skip(left)
.map(|c| char_width(c))
.sum::<usize>();
if pos > 1 && (annotation.has_label() || annotation.takes_space()) {
for p in line_offset + 1..=line_offset + pos {
buffer.putc(
p,
(code_offset + annotation.start_col.display).saturating_sub(left),
code_offset,
match annotation.annotation_type {
AnnotationType::MultilineLine(_) => underline.multiline_vertical,
_ => underline.vertical_text_line,
@ -1087,7 +1075,7 @@ impl HumanEmitter {
if let AnnotationType::MultilineStart(_) = annotation.annotation_type {
buffer.putc(
line_offset + pos,
(code_offset + annotation.start_col.display).saturating_sub(left),
code_offset,
underline.bottom_right,
underline.style,
);
@ -1097,7 +1085,7 @@ impl HumanEmitter {
{
buffer.putc(
line_offset + pos,
(code_offset + annotation.start_col.display).saturating_sub(left),
code_offset,
underline.multiline_bottom_right_with_text,
underline.style,
);
@ -1155,13 +1143,30 @@ impl HumanEmitter {
let style =
if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary };
let (pos, col) = if pos == 0 {
if annotation.end_col.display == 0 {
(pos + 1, (annotation.end_col.display + 2).saturating_sub(left))
let pre: usize = source_string
.chars()
.take(annotation.end_col.file)
.skip(left)
.map(|c| char_width(c))
.sum();
if annotation.end_col.file == 0 {
(pos + 1, (pre + 2))
} else {
(pos + 1, (annotation.end_col.display + 1).saturating_sub(left))
let pad = if annotation.end_col.file - annotation.start_col.file == 0 {
2
} else {
1
};
(pos + 1, (pre + pad))
}
} else {
(pos + 2, annotation.start_col.display.saturating_sub(left))
let pre: usize = source_string
.chars()
.take(annotation.start_col.file)
.skip(left)
.map(|c| char_width(c))
.sum();
(pos + 2, pre)
};
if let Some(ref label) = annotation.label {
buffer.puts(line_offset + pos, code_offset + col, label, style);
@ -1194,14 +1199,35 @@ impl HumanEmitter {
// | _^ test
for &(pos, annotation) in &annotations_position {
let uline = self.underline(annotation.is_primary);
for p in annotation.start_col.display..annotation.end_col.display {
let width = annotation.end_col.file - annotation.start_col.file;
let previous: String =
source_string.chars().take(annotation.start_col.file).skip(left).collect();
let underlined: String =
source_string.chars().skip(annotation.start_col.file).take(width).collect();
debug!(?previous, ?underlined);
let code_offset = code_offset
+ source_string
.chars()
.take(annotation.start_col.file)
.skip(left)
.map(|c| char_width(c))
.sum::<usize>();
let ann_width: usize = source_string
.chars()
.skip(annotation.start_col.file)
.take(width)
.map(|c| char_width(c))
.sum();
let ann_width = if ann_width == 0
&& matches!(annotation.annotation_type, AnnotationType::Singleline)
{
1
} else {
ann_width
};
for p in 0..ann_width {
// The default span label underline.
buffer.putc(
line_offset + 1,
(code_offset + p).saturating_sub(left),
uline.underline,
uline.style,
);
buffer.putc(line_offset + 1, code_offset + p, uline.underline, uline.style);
}
if pos == 0
@ -1213,7 +1239,7 @@ impl HumanEmitter {
// The beginning of a multiline span with its leftward moving line on the same line.
buffer.putc(
line_offset + 1,
(code_offset + annotation.start_col.display).saturating_sub(left),
code_offset,
match annotation.annotation_type {
AnnotationType::MultilineStart(_) => uline.top_right_flat,
AnnotationType::MultilineEnd(_) => uline.multiline_end_same_line,
@ -1231,7 +1257,7 @@ impl HumanEmitter {
// so we start going down first.
buffer.putc(
line_offset + 1,
(code_offset + annotation.start_col.display).saturating_sub(left),
code_offset,
match annotation.annotation_type {
AnnotationType::MultilineStart(_) => uline.multiline_start_down,
AnnotationType::MultilineEnd(_) => uline.multiline_end_up,
@ -1241,11 +1267,37 @@ impl HumanEmitter {
);
} else if pos != 0 && annotation.has_label() {
// The beginning of a span label with an actual label, we'll point down.
buffer.putc(
buffer.putc(line_offset + 1, code_offset, uline.label_start, uline.style);
}
}
// We look for individual *long* spans, and we trim the *middle*, so that we render
// LL | ...= [0, 0, 0, ..., 0, 0];
// | ^^^^^^^^^^...^^^^^^^ expected `&[u8]`, found `[{integer}; 1680]`
for (i, (_pos, annotation)) in annotations_position.iter().enumerate() {
// Skip cases where multiple spans overlap each other.
if overlap[i] {
continue;
};
let AnnotationType::Singleline = annotation.annotation_type else { continue };
let width = annotation.end_col.display - annotation.start_col.display;
if width > margin.column_width * 2 && width > 10 {
// If the terminal is *too* small, we keep at least a tiny bit of the span for
// display.
let pad = max(margin.column_width / 3, 5);
// Code line
buffer.replace(
line_offset,
annotation.start_col.file + pad,
annotation.end_col.file - pad,
self.margin(),
);
// Underline line
buffer.replace(
line_offset + 1,
(code_offset + annotation.start_col.display).saturating_sub(left),
uline.label_start,
uline.style,
annotation.start_col.file + pad,
annotation.end_col.file - pad,
self.margin(),
);
}
}
@ -1702,17 +1754,11 @@ impl HumanEmitter {
// non-rustc_lexer::is_whitespace() chars are reported as an
// error (ex. no-break-spaces \u{a0}), and thus can't be considered
// for removal during error reporting.
// FIXME: doesn't account for '\t' properly.
let leading_whitespace = source_string
.chars()
.take_while(|c| rustc_lexer::is_whitespace(*c))
.map(|c| {
match c {
// Tabs are displayed as 4 spaces
'\t' => 4,
_ => 1,
}
})
.sum();
.count();
if source_string.chars().any(|c| !rustc_lexer::is_whitespace(c)) {
whitespace_margin = min(whitespace_margin, leading_whitespace);
}
@ -1726,8 +1772,8 @@ impl HumanEmitter {
let mut span_left_margin = usize::MAX;
for line in &annotated_file.lines {
for ann in &line.annotations {
span_left_margin = min(span_left_margin, ann.start_col.display);
span_left_margin = min(span_left_margin, ann.end_col.display);
span_left_margin = min(span_left_margin, ann.start_col.file);
span_left_margin = min(span_left_margin, ann.end_col.file);
}
}
if span_left_margin == usize::MAX {
@ -1747,12 +1793,12 @@ impl HumanEmitter {
.map_or(0, |s| s.len()),
);
for ann in &line.annotations {
span_right_margin = max(span_right_margin, ann.start_col.display);
span_right_margin = max(span_right_margin, ann.end_col.display);
span_right_margin = max(span_right_margin, ann.start_col.file);
span_right_margin = max(span_right_margin, ann.end_col.file);
// FIXME: account for labels not in the same line
let label_right = ann.label.as_ref().map_or(0, |l| l.len() + 1);
label_right_margin =
max(label_right_margin, ann.end_col.display + label_right);
max(label_right_margin, ann.end_col.file + label_right);
}
}
@ -1763,15 +1809,7 @@ impl HumanEmitter {
width_offset + annotated_file.multiline_depth + 1
};
let column_width = if let Some(width) = self.diagnostic_width {
width.saturating_sub(code_offset)
} else if self.ui_testing || cfg!(miri) {
DEFAULT_COLUMN_WIDTH
} else {
termize::dimensions()
.map(|(w, _)| w.saturating_sub(code_offset))
.unwrap_or(DEFAULT_COLUMN_WIDTH)
};
let column_width = self.column_width(code_offset);
let margin = Margin::new(
whitespace_margin,
@ -1928,6 +1966,18 @@ impl HumanEmitter {
Ok(())
}
fn column_width(&self, code_offset: usize) -> usize {
if let Some(width) = self.diagnostic_width {
width.saturating_sub(code_offset)
} else if self.ui_testing || cfg!(miri) {
DEFAULT_COLUMN_WIDTH
} else {
termize::dimensions()
.map(|(w, _)| w.saturating_sub(code_offset))
.unwrap_or(DEFAULT_COLUMN_WIDTH)
}
}
fn emit_suggestion_default(
&mut self,
span: &MultiSpan,

View File

@ -89,6 +89,19 @@ impl StyledBuffer {
}
}
pub(crate) fn replace(&mut self, line: usize, start: usize, end: usize, string: &str) {
if start == end {
return;
}
if start > self.lines[line].len() || end > self.lines[line].len() {
return;
}
let _ = self.lines[line].drain(start..(end - string.chars().count()));
for (i, c) in string.chars().enumerate() {
self.lines[line][start + i] = StyledChar::new(c, Style::LineNumber);
}
}
/// For given `line` inserts `string` with `style` before old content of that line,
/// adding lines if needed
pub(crate) fn prepend(&mut self, line: usize, string: &str, style: Style) {

View File

@ -930,7 +930,6 @@ fn default_emitter(
.fluent_bundle(bundle)
.sm(source_map)
.short_message(short)
.teach(sopts.unstable_opts.teach)
.diagnostic_width(sopts.diagnostic_width)
.macro_backtrace(macro_backtrace)
.track_diagnostics(track_diagnostics)

View File

@ -30,8 +30,6 @@ version = "0.0.0"
dependencies = [
"compiler_builtins",
"core",
"rand",
"rand_xorshift",
]
[[package]]
@ -40,6 +38,14 @@ version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "alloctests"
version = "0.0.0"
dependencies = [
"rand",
"rand_xorshift",
]
[[package]]
name = "cc"
version = "1.2.0"

View File

@ -4,6 +4,7 @@ members = [
"std",
"sysroot",
"coretests",
"alloctests",
]
exclude = [

View File

@ -10,32 +10,14 @@ autotests = false
autobenches = false
edition = "2021"
[lib]
test = false
bench = false
[dependencies]
core = { path = "../core", public = true }
compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] }
[dev-dependencies]
rand = { version = "0.9.0", default-features = false, features = ["alloc"] }
rand_xorshift = "0.4.0"
[[test]]
name = "alloctests"
path = "tests/lib.rs"
[[test]]
name = "vec_deque_alloc_error"
path = "tests/vec_deque_alloc_error.rs"
[[bench]]
name = "allocbenches"
path = "benches/lib.rs"
test = true
[[bench]]
name = "vec_deque_append_bench"
path = "benches/vec_deque_append.rs"
harness = false
[features]
compiler-builtins-mem = ['compiler_builtins/mem']
compiler-builtins-c = ["compiler_builtins/c"]

View File

@ -5,9 +5,7 @@
#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use core::alloc::*;
#[cfg(not(test))]
use core::hint;
#[cfg(not(test))]
use core::ptr::{self, NonNull};
unsafe extern "Rust" {
@ -44,14 +42,10 @@ unsafe extern "Rust" {
/// accessed through the [free functions in `alloc`](self#functions).
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Copy, Clone, Default, Debug)]
#[cfg(not(test))]
// the compiler needs to know when a Box uses the global allocator vs a custom one
#[lang = "global_alloc_ty"]
pub struct Global;
#[cfg(test)]
pub use std::alloc::Global;
/// Allocates memory with the global allocator.
///
/// This function forwards calls to the [`GlobalAlloc::alloc`] method
@ -180,7 +174,6 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
}
}
#[cfg(not(test))]
impl Global {
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@ -246,7 +239,6 @@ impl Global {
}
#[unstable(feature = "allocator_api", issue = "32838")]
#[cfg(not(test))]
unsafe impl Allocator for Global {
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@ -346,7 +338,7 @@ unsafe impl Allocator for Global {
}
/// The allocator for `Box`.
#[cfg(all(not(no_global_oom_handling), not(test)))]
#[cfg(not(no_global_oom_handling))]
#[lang = "exchange_malloc"]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@ -395,7 +387,7 @@ unsafe extern "Rust" {
/// [no_std]: https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute
#[stable(feature = "global_alloc", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
#[cfg(all(not(no_global_oom_handling), not(test)))]
#[cfg(not(no_global_oom_handling))]
#[cold]
#[optimize(size)]
pub const fn handle_alloc_error(layout: Layout) -> ! {
@ -419,11 +411,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
ct_error(layout)
}
// For alloc test `std::alloc::handle_alloc_error` can be used directly.
#[cfg(all(not(no_global_oom_handling), test))]
pub use std::alloc::handle_alloc_error;
#[cfg(all(not(no_global_oom_handling), not(test)))]
#[cfg(not(no_global_oom_handling))]
#[doc(hidden)]
#[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "none")]

View File

@ -32,7 +32,7 @@ where
/// implementing the `Clone` trait. But `Clone` works only for going from `&T`
/// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data
/// from any borrow of a given type.
#[cfg_attr(not(test), rustc_diagnostic_item = "ToOwned")]
#[rustc_diagnostic_item = "ToOwned"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ToOwned {
/// The resulting type after obtaining ownership.
@ -54,7 +54,7 @@ pub trait ToOwned {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use = "cloning is often expensive and is not expected to have side effects"]
#[cfg_attr(not(test), rustc_diagnostic_item = "to_owned_method")]
#[rustc_diagnostic_item = "to_owned_method"]
fn to_owned(&self) -> Self::Owned;
/// Uses borrowed data to replace owned data, usually by cloning.
@ -175,7 +175,7 @@ where
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "Cow")]
#[rustc_diagnostic_item = "Cow"]
pub enum Cow<'a, B: ?Sized + 'a>
where
B: ToOwned,

View File

@ -12,13 +12,10 @@ use core::ops::{
Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive,
RangeTo, RangeToInclusive,
};
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
use core::str::FromStr;
use core::{fmt, hash};
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
use crate::borrow::{Cow, ToOwned};
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
use crate::boxed::Box;
#[cfg(not(no_rc))]
use crate::rc::Rc;
@ -181,7 +178,6 @@ impl Default for ByteString {
// Omitted due to inference failures
//
// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
// #[unstable(feature = "bstr", issue = "134915")]
// impl<'a, const N: usize> From<&'a [u8; N]> for ByteString {
// #[inline]
@ -190,7 +186,6 @@ impl Default for ByteString {
// }
// }
//
// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
// #[unstable(feature = "bstr", issue = "134915")]
// impl<const N: usize> From<[u8; N]> for ByteString {
// #[inline]
@ -199,7 +194,6 @@ impl Default for ByteString {
// }
// }
//
// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
// #[unstable(feature = "bstr", issue = "134915")]
// impl<'a> From<&'a [u8]> for ByteString {
// #[inline]
@ -226,7 +220,6 @@ impl From<ByteString> for Vec<u8> {
// Omitted due to inference failures
//
// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
// #[unstable(feature = "bstr", issue = "134915")]
// impl<'a> From<&'a str> for ByteString {
// #[inline]
@ -243,7 +236,6 @@ impl From<ByteString> for Vec<u8> {
// }
// }
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
#[unstable(feature = "bstr", issue = "134915")]
impl<'a> From<&'a ByteStr> for ByteString {
#[inline]
@ -252,7 +244,6 @@ impl<'a> From<&'a ByteStr> for ByteString {
}
}
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
#[unstable(feature = "bstr", issue = "134915")]
impl<'a> From<ByteString> for Cow<'a, ByteStr> {
#[inline]
@ -261,7 +252,6 @@ impl<'a> From<ByteString> for Cow<'a, ByteStr> {
}
}
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
#[unstable(feature = "bstr", issue = "134915")]
impl<'a> From<&'a ByteString> for Cow<'a, ByteStr> {
#[inline]
@ -330,7 +320,6 @@ impl FromIterator<ByteString> for ByteString {
}
}
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
#[unstable(feature = "bstr", issue = "134915")]
impl FromStr for ByteString {
type Err = core::convert::Infallible;
@ -488,7 +477,6 @@ impl PartialEq for ByteString {
macro_rules! impl_partial_eq_ord_cow {
($lhs:ty, $rhs:ty) => {
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
#[allow(unused_lifetimes)]
#[unstable(feature = "bstr", issue = "134915")]
impl<'a> PartialEq<$rhs> for $lhs {
@ -499,7 +487,6 @@ macro_rules! impl_partial_eq_ord_cow {
}
}
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
#[allow(unused_lifetimes)]
#[unstable(feature = "bstr", issue = "134915")]
impl<'a> PartialEq<$lhs> for $rhs {
@ -510,7 +497,6 @@ macro_rules! impl_partial_eq_ord_cow {
}
}
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
#[allow(unused_lifetimes)]
#[unstable(feature = "bstr", issue = "134915")]
impl<'a> PartialOrd<$rhs> for $lhs {
@ -521,7 +507,6 @@ macro_rules! impl_partial_eq_ord_cow {
}
}
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
#[allow(unused_lifetimes)]
#[unstable(feature = "bstr", issue = "134915")]
impl<'a> PartialOrd<$lhs> for $rhs {
@ -572,7 +557,6 @@ impl PartialOrd for ByteString {
}
}
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
#[unstable(feature = "bstr", issue = "134915")]
impl ToOwned for ByteStr {
type Owned = ByteString;
@ -605,7 +589,6 @@ impl<'a> TryFrom<&'a ByteString> for &'a str {
// Additional impls for `ByteStr` that require types from `alloc`:
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
#[unstable(feature = "bstr", issue = "134915")]
impl Clone for Box<ByteStr> {
#[inline]
@ -614,7 +597,6 @@ impl Clone for Box<ByteStr> {
}
}
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
#[unstable(feature = "bstr", issue = "134915")]
impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> {
#[inline]
@ -623,7 +605,6 @@ impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> {
}
}
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
#[unstable(feature = "bstr", issue = "134915")]
impl From<Box<[u8]>> for Box<ByteStr> {
#[inline]
@ -633,7 +614,6 @@ impl From<Box<[u8]>> for Box<ByteStr> {
}
}
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
#[unstable(feature = "bstr", issue = "134915")]
impl From<Box<ByteStr>> for Box<[u8]> {
#[inline]

View File

@ -153,7 +153,9 @@ use core::{fmt, ptr};
use crate::alloc::Global;
use crate::collections::TryReserveError;
use crate::slice;
use crate::vec::{self, AsVecIntoIter, Vec};
#[cfg(not(test))]
use crate::vec::AsVecIntoIter;
use crate::vec::{self, Vec};
/// A priority queue implemented with a binary heap.
///
@ -1600,6 +1602,7 @@ unsafe impl<I, A: Allocator> InPlaceIterable for IntoIter<I, A> {
const MERGE_BY: Option<NonZero<usize>> = NonZero::new(1);
}
#[cfg(not(test))]
unsafe impl<I> AsVecIntoIter for IntoIter<I> {
type Item = I;

View File

@ -1,5 +1,8 @@
//! Collection types.
// Note: This module is also included in the alloctests crate using #[path] to
// run the tests. See the comment there for an explanation why this is the case.
#![stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(no_global_oom_handling))]
@ -24,41 +27,54 @@ pub mod btree_map {
pub mod btree_set {
//! An ordered set based on a B-Tree.
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(test))]
pub use super::btree::set::*;
}
#[cfg(not(test))]
use core::fmt::Display;
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
#[cfg(not(test))]
pub use binary_heap::BinaryHeap;
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
#[cfg(not(test))]
pub use btree_map::BTreeMap;
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
#[cfg(not(test))]
pub use btree_set::BTreeSet;
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
#[cfg(not(test))]
pub use linked_list::LinkedList;
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
#[cfg(not(test))]
pub use vec_deque::VecDeque;
#[cfg(not(test))]
use crate::alloc::{Layout, LayoutError};
/// The error type for `try_reserve` methods.
#[derive(Clone, PartialEq, Eq, Debug)]
#[stable(feature = "try_reserve", since = "1.57.0")]
#[cfg(not(test))]
pub struct TryReserveError {
kind: TryReserveErrorKind,
}
#[cfg(test)]
pub use realalloc::collections::TryReserveError;
#[cfg(not(test))]
impl TryReserveError {
/// Details about the allocation that caused the error
#[inline]
@ -80,6 +96,7 @@ impl TryReserveError {
reason = "Uncertain how much info should be exposed",
issue = "48043"
)]
#[cfg(not(test))]
pub enum TryReserveErrorKind {
/// Error due to the computed capacity exceeding the collection's maximum
/// (usually `isize::MAX` bytes).
@ -103,11 +120,15 @@ pub enum TryReserveErrorKind {
},
}
#[cfg(test)]
pub use realalloc::collections::TryReserveErrorKind;
#[unstable(
feature = "try_reserve_kind",
reason = "Uncertain how much info should be exposed",
issue = "48043"
)]
#[cfg(not(test))]
impl From<TryReserveErrorKind> for TryReserveError {
#[inline]
fn from(kind: TryReserveErrorKind) -> Self {
@ -116,6 +137,7 @@ impl From<TryReserveErrorKind> for TryReserveError {
}
#[unstable(feature = "try_reserve_kind", reason = "new API", issue = "48043")]
#[cfg(not(test))]
impl From<LayoutError> for TryReserveErrorKind {
/// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`].
#[inline]
@ -125,6 +147,7 @@ impl From<LayoutError> for TryReserveErrorKind {
}
#[stable(feature = "try_reserve", since = "1.57.0")]
#[cfg(not(test))]
impl Display for TryReserveError {
fn fmt(
&self,
@ -152,4 +175,5 @@ trait SpecExtend<I: IntoIterator> {
}
#[stable(feature = "try_reserve", since = "1.57.0")]
#[cfg(not(test))]
impl core::error::Error for TryReserveError {}

View File

@ -645,6 +645,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
/// initialized rather than only supporting `0..len`. Requires that
/// `initialized.start` ≤ `initialized.end` ≤ `capacity`.
#[inline]
#[cfg(not(test))]
pub(crate) unsafe fn from_contiguous_raw_parts_in(
ptr: *mut T,
initialized: Range<usize>,

View File

@ -3,6 +3,7 @@ use core::slice;
use super::VecDeque;
use crate::alloc::Allocator;
#[cfg(not(test))]
use crate::vec;
// Specialization trait used for VecDeque::extend
@ -78,6 +79,7 @@ where
}
}
#[cfg(not(test))]
impl<T, A: Allocator> SpecExtend<T, vec::IntoIter<T>> for VecDeque<T, A> {
#[track_caller]
fn spec_extend(&mut self, mut iterator: vec::IntoIter<T>) {

View File

@ -19,6 +19,7 @@ where
}
}
#[cfg(not(test))]
impl<T> SpecFromIter<T, crate::vec::IntoIter<T>> for VecDeque<T> {
#[inline]
fn spec_from_iter(iterator: crate::vec::IntoIter<T>) -> Self {

View File

@ -10,7 +10,6 @@ use core::{fmt, mem, ops, ptr, slice};
use crate::borrow::{Cow, ToOwned};
use crate::boxed::Box;
use crate::rc::Rc;
use crate::slice::hack::into_vec;
use crate::string::String;
#[cfg(target_has_atomic = "ptr")]
use crate::sync::Arc;
@ -103,7 +102,7 @@ use crate::vec::Vec;
/// of `CString` instances can lead to invalid memory accesses, memory leaks,
/// and other memory errors.
#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)]
#[cfg_attr(not(test), rustc_diagnostic_item = "cstring_type")]
#[rustc_diagnostic_item = "cstring_type"]
#[stable(feature = "alloc_c_string", since = "1.64.0")]
pub struct CString {
// Invariant 1: the slice ends with a zero byte and has a length of at least one.
@ -491,7 +490,7 @@ impl CString {
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "cstring_into", since = "1.7.0")]
pub fn into_bytes(self) -> Vec<u8> {
let mut vec = into_vec(self.into_inner());
let mut vec = self.into_inner().into_vec();
let _nul = vec.pop();
debug_assert_eq!(_nul, Some(0u8));
vec
@ -512,7 +511,7 @@ impl CString {
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "cstring_into", since = "1.7.0")]
pub fn into_bytes_with_nul(self) -> Vec<u8> {
into_vec(self.into_inner())
self.into_inner().into_vec()
}
/// Returns the contents of this `CString` as a slice of bytes.
@ -573,7 +572,7 @@ impl CString {
#[inline]
#[must_use]
#[stable(feature = "as_c_str", since = "1.20.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "cstring_as_c_str")]
#[rustc_diagnostic_item = "cstring_as_c_str"]
pub fn as_c_str(&self) -> &CStr {
&*self
}
@ -755,7 +754,6 @@ impl<'a> From<Cow<'a, CStr>> for CString {
}
}
#[cfg(not(test))]
#[stable(feature = "box_from_c_str", since = "1.17.0")]
impl From<&CStr> for Box<CStr> {
/// Converts a `&CStr` into a `Box<CStr>`,
@ -766,7 +764,6 @@ impl From<&CStr> for Box<CStr> {
}
}
#[cfg(not(test))]
#[stable(feature = "box_from_mut_slice", since = "1.84.0")]
impl From<&mut CStr> for Box<CStr> {
/// Converts a `&mut CStr` into a `Box<CStr>`,
@ -845,7 +842,6 @@ impl TryFrom<CString> for String {
}
}
#[cfg(not(test))]
#[stable(feature = "more_box_slice_clone", since = "1.29.0")]
impl Clone for Box<CStr> {
#[inline]
@ -971,7 +967,6 @@ impl Default for Rc<CStr> {
}
}
#[cfg(not(test))]
#[stable(feature = "default_box_extra", since = "1.17.0")]
impl Default for Box<CStr> {
fn default() -> Box<CStr> {
@ -1080,7 +1075,7 @@ impl ToOwned for CStr {
}
fn clone_into(&self, target: &mut CString) {
let mut b = into_vec(mem::take(&mut target.inner));
let mut b = mem::take(&mut target.inner).into_vec();
self.to_bytes_with_nul().clone_into(&mut b);
target.inner = b.into_boxed_slice();
}
@ -1113,7 +1108,6 @@ impl AsRef<CStr> for CString {
}
}
#[cfg(not(test))]
impl CStr {
/// Converts a `CStr` into a <code>[Cow]<[str]></code>.
///

View File

@ -93,7 +93,6 @@
//
// Library features:
// tidy-alphabetical-start
#![cfg_attr(test, feature(str_as_str))]
#![feature(alloc_layout_extra)]
#![feature(allocator_api)]
#![feature(array_chunks)]
@ -161,13 +160,11 @@
//
// Language features:
// tidy-alphabetical-start
#![cfg_attr(not(test), feature(coroutine_trait))]
#![cfg_attr(test, feature(panic_update_hook))]
#![cfg_attr(test, feature(test))]
#![feature(allocator_internals)]
#![feature(allow_internal_unstable)]
#![feature(cfg_sanitize)]
#![feature(const_precise_live_drops)]
#![feature(coroutine_trait)]
#![feature(decl_macro)]
#![feature(dropck_eyepatch)]
#![feature(fundamental)]
@ -200,15 +197,6 @@
// from other crates, but since this can only appear for lang items, it doesn't seem worth fixing.
#![feature(intra_doc_pointers)]
// Allow testing this library
#[cfg(test)]
#[macro_use]
extern crate std;
#[cfg(test)]
extern crate test;
#[cfg(test)]
mod testing;
// Module with internal macros used by other modules (needs to be included before other modules).
#[macro_use]
mod macros;
@ -216,7 +204,6 @@ mod macros;
mod raw_vec;
// Heaps provided for low-level allocation strategies
pub mod alloc;
// Primitive types using the heaps above
@ -224,13 +211,8 @@ pub mod alloc;
// Need to conditionally define the mod from `boxed.rs` to avoid
// duplicating the lang-items when building in test cfg; but also need
// to allow code to have `use boxed::Box;` declarations.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed {
pub(crate) use std::boxed::Box;
}
pub mod borrow;
pub mod boxed;
#[unstable(feature = "bstr", issue = "134915")]
pub mod bstr;
pub mod collections;
@ -254,20 +236,3 @@ pub mod __export {
pub use core::format_args;
pub use core::hint::must_use;
}
#[cfg(test)]
#[allow(dead_code)] // Not used in all configurations
pub(crate) mod test_helpers {
/// Copied from `std::test_helpers::test_rng`, since these tests rely on the
/// seed not being the same for every RNG invocation too.
pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
use std::hash::{BuildHasher, Hash, Hasher};
let mut hasher = std::hash::RandomState::new().build_hasher();
std::panic::Location::caller().hash(&mut hasher);
let hc64 = hasher.finish();
let seed_vec =
hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<crate::vec::Vec<u8>>();
let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
rand::SeedableRng::from_seed(seed)
}
}

View File

@ -34,7 +34,7 @@
/// be mindful of side effects.
///
/// [`Vec`]: crate::vec::Vec
#[cfg(all(not(no_global_oom_handling), not(test)))]
#[cfg(not(no_global_oom_handling))]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "vec_macro"]
@ -55,25 +55,6 @@ macro_rules! vec {
);
}
// HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is
// required for this macro definition, is not available. Instead use the
// `slice::into_vec` function which is only available with cfg(test)
// NB see the slice::hack module in slice.rs for more information
#[cfg(all(not(no_global_oom_handling), test))]
#[allow(unused_macro_rules)]
macro_rules! vec {
() => (
$crate::vec::Vec::new()
);
($elem:expr; $n:expr) => (
$crate::vec::from_elem($elem, $n)
);
($($x:expr),*) => (
$crate::slice::into_vec($crate::boxed::Box::new([$($x),*]))
);
($($x:expr,)*) => (vec![$($x),*])
}
/// Creates a `String` using interpolation of runtime expressions.
///
/// The first argument `format!` receives is a format string. This must be a string
@ -120,7 +101,7 @@ macro_rules! vec {
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(hint_must_use, liballoc_internals)]
#[cfg_attr(not(test), rustc_diagnostic_item = "format_macro")]
#[rustc_diagnostic_item = "format_macro"]
macro_rules! format {
($($arg:tt)*) => {
$crate::__export::must_use({

View File

@ -1,4 +1,8 @@
#![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")]
#![cfg_attr(test, allow(dead_code))]
// Note: This module is also included in the alloctests crate using #[path] to
// run the tests. See the comment there for an explanation why this is the case.
use core::marker::PhantomData;
use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties};

View File

@ -263,23 +263,17 @@ use core::ptr::{self, NonNull, drop_in_place};
#[cfg(not(no_global_oom_handling))]
use core::slice::from_raw_parts_mut;
use core::{borrow, fmt, hint};
#[cfg(test)]
use std::boxed::Box;
#[cfg(not(no_global_oom_handling))]
use crate::alloc::handle_alloc_error;
use crate::alloc::{AllocError, Allocator, Global, Layout};
use crate::borrow::{Cow, ToOwned};
#[cfg(not(test))]
use crate::boxed::Box;
#[cfg(not(no_global_oom_handling))]
use crate::string::String;
#[cfg(not(no_global_oom_handling))]
use crate::vec::Vec;
#[cfg(test)]
mod tests;
// This is repr(C) to future-proof against possible field-reordering, which
// would interfere with otherwise safe [into|from]_raw() of transmutable
// inner types.
@ -310,7 +304,7 @@ fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout {
///
/// [get_mut]: Rc::get_mut
#[doc(search_unbox)]
#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")]
#[rustc_diagnostic_item = "Rc"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_insignificant_dtor]
pub struct Rc<
@ -2988,7 +2982,7 @@ impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> for I {
///
/// [`upgrade`]: Weak::upgrade
#[stable(feature = "rc_weak", since = "1.4.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "RcWeak")]
#[rustc_diagnostic_item = "RcWeak"]
pub struct Weak<
T: ?Sized,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,

View File

@ -8,9 +8,6 @@
//! A few functions are provided to create a slice from a value reference
//! or from a raw pointer.
#![stable(feature = "rust1", since = "1.0.0")]
// Many of the usings in this module are only used in the test configuration.
// It's cleaner to just turn off the unused_imports warning than to fix them.
#![cfg_attr(test, allow(unused_imports, dead_code))]
use core::borrow::{Borrow, BorrowMut};
#[cfg(not(no_global_oom_handling))]
@ -63,16 +60,6 @@ pub use core::slice::{range, try_range};
////////////////////////////////////////////////////////////////////////////////
// Basic slice extension methods
////////////////////////////////////////////////////////////////////////////////
// HACK(japaric) needed for the implementation of `vec!` macro during testing
// N.B., see the `hack` module in this file for more details.
#[cfg(test)]
pub use hack::into_vec;
// HACK(japaric) needed for the implementation of `Vec::clone` during testing
// N.B., see the `hack` module in this file for more details.
#[cfg(test)]
pub use hack::to_vec;
use crate::alloc::Allocator;
#[cfg(not(no_global_oom_handling))]
use crate::alloc::Global;
@ -81,98 +68,6 @@ use crate::borrow::ToOwned;
use crate::boxed::Box;
use crate::vec::Vec;
// HACK(japaric): With cfg(test) `impl [T]` is not available, these three
// functions are actually methods that are in `impl [T]` but not in
// `core::slice::SliceExt` - we need to supply these functions for the
// `test_permutations` test
#[allow(unreachable_pub)] // cfg(test) pub above
pub(crate) mod hack {
use core::alloc::Allocator;
use crate::boxed::Box;
use crate::vec::Vec;
// We shouldn't add inline attribute to this since this is used in
// `vec!` macro mostly and causes perf regression. See #71204 for
// discussion and perf results.
#[allow(missing_docs)]
pub fn into_vec<T, A: Allocator>(b: Box<[T], A>) -> Vec<T, A> {
unsafe {
let len = b.len();
let (b, alloc) = Box::into_raw_with_allocator(b);
Vec::from_raw_parts_in(b as *mut T, len, len, alloc)
}
}
#[cfg(not(no_global_oom_handling))]
#[allow(missing_docs)]
#[inline]
pub fn to_vec<T: ConvertVec, A: Allocator>(s: &[T], alloc: A) -> Vec<T, A> {
T::to_vec(s, alloc)
}
#[cfg(not(no_global_oom_handling))]
pub trait ConvertVec {
fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A>
where
Self: Sized;
}
#[cfg(not(no_global_oom_handling))]
impl<T: Clone> ConvertVec for T {
#[inline]
default fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
struct DropGuard<'a, T, A: Allocator> {
vec: &'a mut Vec<T, A>,
num_init: usize,
}
impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> {
#[inline]
fn drop(&mut self) {
// SAFETY:
// items were marked initialized in the loop below
unsafe {
self.vec.set_len(self.num_init);
}
}
}
let mut vec = Vec::with_capacity_in(s.len(), alloc);
let mut guard = DropGuard { vec: &mut vec, num_init: 0 };
let slots = guard.vec.spare_capacity_mut();
// .take(slots.len()) is necessary for LLVM to remove bounds checks
// and has better codegen than zip.
for (i, b) in s.iter().enumerate().take(slots.len()) {
guard.num_init = i;
slots[i].write(b.clone());
}
core::mem::forget(guard);
// SAFETY:
// the vec was allocated and initialized above to at least this length.
unsafe {
vec.set_len(s.len());
}
vec
}
}
#[cfg(not(no_global_oom_handling))]
impl<T: Copy> ConvertVec for T {
#[inline]
fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
let mut v = Vec::with_capacity_in(s.len(), alloc);
// SAFETY:
// allocated above with the capacity of `s`, and initialize to `s.len()` in
// ptr::copy_to_non_overlapping below.
unsafe {
s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len());
v.set_len(s.len());
}
v
}
}
}
#[cfg(not(test))]
impl<T> [T] {
/// Sorts the slice, preserving initial order of equal elements.
///
@ -501,8 +396,64 @@ impl<T> [T] {
where
T: Clone,
{
// N.B., see the `hack` module in this file for more details.
hack::to_vec(self, alloc)
return T::to_vec(self, alloc);
trait ConvertVec {
fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A>
where
Self: Sized;
}
impl<T: Clone> ConvertVec for T {
#[inline]
default fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
struct DropGuard<'a, T, A: Allocator> {
vec: &'a mut Vec<T, A>,
num_init: usize,
}
impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> {
#[inline]
fn drop(&mut self) {
// SAFETY:
// items were marked initialized in the loop below
unsafe {
self.vec.set_len(self.num_init);
}
}
}
let mut vec = Vec::with_capacity_in(s.len(), alloc);
let mut guard = DropGuard { vec: &mut vec, num_init: 0 };
let slots = guard.vec.spare_capacity_mut();
// .take(slots.len()) is necessary for LLVM to remove bounds checks
// and has better codegen than zip.
for (i, b) in s.iter().enumerate().take(slots.len()) {
guard.num_init = i;
slots[i].write(b.clone());
}
core::mem::forget(guard);
// SAFETY:
// the vec was allocated and initialized above to at least this length.
unsafe {
vec.set_len(s.len());
}
vec
}
}
impl<T: Copy> ConvertVec for T {
#[inline]
fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
let mut v = Vec::with_capacity_in(s.len(), alloc);
// SAFETY:
// allocated above with the capacity of `s`, and initialize to `s.len()` in
// ptr::copy_to_non_overlapping below.
unsafe {
s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len());
v.set_len(s.len());
}
v
}
}
}
/// Converts `self` into a vector without clones or allocation.
@ -522,10 +473,13 @@ impl<T> [T] {
#[rustc_allow_incoherent_impl]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[cfg_attr(not(test), rustc_diagnostic_item = "slice_into_vec")]
#[rustc_diagnostic_item = "slice_into_vec"]
pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {
// N.B., see the `hack` module in this file for more details.
hack::into_vec(self)
unsafe {
let len = self.len();
let (b, alloc) = Box::into_raw_with_allocator(self);
Vec::from_raw_parts_in(b as *mut T, len, len, alloc)
}
}
/// Creates a vector by copying a slice `n` times.
@ -666,7 +620,6 @@ impl<T> [T] {
}
}
#[cfg(not(test))]
impl [u8] {
/// Returns a vector containing a copy of this slice where each byte
/// is mapped to its ASCII upper case equivalent.
@ -883,16 +836,11 @@ impl<T: Copy, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Clone> ToOwned for [T] {
type Owned = Vec<T>;
#[cfg(not(test))]
fn to_owned(&self) -> Vec<T> {
self.to_vec()
}
#[cfg(test)]
fn to_owned(&self) -> Vec<T> {
hack::to_vec(self, Global)
}
fn clone_into(&self, target: &mut Vec<T>) {
SpecCloneIntoVec::clone_into(self, target);
}

View File

@ -219,7 +219,6 @@ impl ToOwned for str {
}
/// Methods for string slices.
#[cfg(not(test))]
impl str {
/// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating.
///
@ -631,7 +630,6 @@ pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
#[unstable(feature = "str_internals", issue = "none")]
#[doc(hidden)]
#[inline]
#[cfg(not(test))]
#[cfg(not(no_global_oom_handling))]
pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) {
// Process the input in chunks of 16 bytes to enable auto-vectorization.
@ -704,7 +702,6 @@ pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) {
}
}
#[inline]
#[cfg(not(test))]
#[cfg(not(no_global_oom_handling))]
#[allow(dead_code)]
/// Faster implementation of string replacement for ASCII to ASCII cases.

View File

@ -356,7 +356,7 @@ use crate::vec::{self, Vec};
/// [`as_str()`]: String::as_str
#[derive(PartialEq, PartialOrd, Eq, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), lang = "String")]
#[lang = "String"]
pub struct String {
vec: Vec<u8>,
}
@ -438,7 +438,7 @@ impl String {
/// ```
#[inline]
#[rustc_const_stable(feature = "const_string_new", since = "1.39.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "string_new")]
#[rustc_diagnostic_item = "string_new"]
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
pub const fn new() -> String {
@ -501,17 +501,6 @@ impl String {
Ok(String { vec: Vec::try_with_capacity(capacity)? })
}
// HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
// required for this method definition, is not available. Since we don't
// require this method for testing purposes, I'll just stub it
// NB see the slice::hack module in slice.rs for more information
#[inline]
#[cfg(test)]
#[allow(missing_docs)]
pub fn from_str(_: &str) -> String {
panic!("not available with cfg(test)");
}
/// Converts a vector of bytes to a `String`.
///
/// A string ([`String`]) is made of bytes ([`u8`]), and a vector of bytes
@ -570,7 +559,7 @@ impl String {
/// [`into_bytes`]: String::into_bytes
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "string_from_utf8")]
#[rustc_diagnostic_item = "string_from_utf8"]
pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
match str::from_utf8(&vec) {
Ok(..) => Ok(String { vec }),
@ -1071,7 +1060,7 @@ impl String {
#[inline]
#[must_use]
#[stable(feature = "string_as_str", since = "1.7.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "string_as_str")]
#[rustc_diagnostic_item = "string_as_str"]
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn as_str(&self) -> &str {
// SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error
@ -1094,7 +1083,7 @@ impl String {
#[inline]
#[must_use]
#[stable(feature = "string_as_str", since = "1.7.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "string_as_mut_str")]
#[rustc_diagnostic_item = "string_as_mut_str"]
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn as_mut_str(&mut self) -> &mut str {
// SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error
@ -1117,7 +1106,7 @@ impl String {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_confusables("append", "push")]
#[cfg_attr(not(test), rustc_diagnostic_item = "string_push_str")]
#[rustc_diagnostic_item = "string_push_str"]
pub fn push_str(&mut self, string: &str) {
self.vec.extend_from_slice(string.as_bytes())
}
@ -1755,7 +1744,7 @@ impl String {
#[cfg(not(no_global_oom_handling))]
#[inline]
#[stable(feature = "insert_str", since = "1.16.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "string_insert_str")]
#[rustc_diagnostic_item = "string_insert_str"]
pub fn insert_str(&mut self, idx: usize, string: &str) {
assert!(self.is_char_boundary(idx));
@ -2724,7 +2713,7 @@ impl FromStr for String {
/// implementation for free.
///
/// [`Display`]: fmt::Display
#[cfg_attr(not(test), rustc_diagnostic_item = "ToString")]
#[rustc_diagnostic_item = "ToString"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ToString {
/// Converts the given value to a `String`.
@ -2739,7 +2728,7 @@ pub trait ToString {
/// ```
#[rustc_conversion_suggestion]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "to_string_method")]
#[rustc_diagnostic_item = "to_string_method"]
fn to_string(&self) -> String;
}
@ -2979,7 +2968,6 @@ impl From<&String> for String {
}
// note: test pulls in std, which causes errors here
#[cfg(not(test))]
#[stable(feature = "string_from_box", since = "1.18.0")]
impl From<Box<str>> for String {
/// Converts the given boxed `str` slice to a [`String`].

View File

@ -235,7 +235,7 @@ macro_rules! acquire {
///
/// [rc_examples]: crate::rc#examples
#[doc(search_unbox)]
#[cfg_attr(not(test), rustc_diagnostic_item = "Arc")]
#[rustc_diagnostic_item = "Arc"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_insignificant_dtor]
pub struct Arc<
@ -312,7 +312,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
///
/// [`upgrade`]: Weak::upgrade
#[stable(feature = "arc_weak", since = "1.4.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "ArcWeak")]
#[rustc_diagnostic_item = "ArcWeak"]
pub struct Weak<
T: ?Sized,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,

View File

@ -472,14 +472,9 @@ where
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> {
#[cfg(not(test))]
fn clone(&self) -> Self {
self.as_slice().to_vec_in(self.alloc.deref().clone()).into_iter()
}
#[cfg(test)]
fn clone(&self) -> Self {
crate::slice::to_vec(self.as_slice(), self.alloc.deref().clone()).into_iter()
}
}
#[stable(feature = "rust1", since = "1.0.0")]

View File

@ -404,7 +404,7 @@ mod spec_extend;
/// [owned slice]: Box
/// [`into_boxed_slice`]: Vec::into_boxed_slice
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "Vec")]
#[rustc_diagnostic_item = "Vec"]
#[rustc_insignificant_dtor]
pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
buf: RawVec<T, A>,
@ -428,7 +428,7 @@ impl<T> Vec<T> {
/// ```
#[inline]
#[rustc_const_stable(feature = "const_vec_new", since = "1.39.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_new")]
#[rustc_diagnostic_item = "vec_new"]
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
pub const fn new() -> Self {
@ -489,7 +489,7 @@ impl<T> Vec<T> {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_with_capacity")]
#[rustc_diagnostic_item = "vec_with_capacity"]
#[track_caller]
pub fn with_capacity(capacity: usize) -> Self {
Self::with_capacity_in(capacity, Global)
@ -1279,7 +1279,7 @@ impl<T, A: Allocator> Vec<T, A> {
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[track_caller]
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_reserve")]
#[rustc_diagnostic_item = "vec_reserve"]
pub fn reserve(&mut self, additional: usize) {
self.buf.reserve(self.len, additional);
}
@ -1568,7 +1568,7 @@ impl<T, A: Allocator> Vec<T, A> {
/// ```
#[inline]
#[stable(feature = "vec_as_slice", since = "1.7.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_slice")]
#[rustc_diagnostic_item = "vec_as_slice"]
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn as_slice(&self) -> &[T] {
// SAFETY: `slice::from_raw_parts` requires pointee is a contiguous, aligned buffer of size
@ -1600,7 +1600,7 @@ impl<T, A: Allocator> Vec<T, A> {
/// ```
#[inline]
#[stable(feature = "vec_as_slice", since = "1.7.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_mut_slice")]
#[rustc_diagnostic_item = "vec_as_mut_slice"]
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn as_mut_slice(&mut self) -> &mut [T] {
// SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of
@ -2511,7 +2511,7 @@ impl<T, A: Allocator> Vec<T, A> {
/// Takes *O*(1) time.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_pop")]
#[rustc_diagnostic_item = "vec_pop"]
pub fn pop(&mut self) -> Option<T> {
if self.len == 0 {
None
@ -2712,7 +2712,7 @@ impl<T, A: Allocator> Vec<T, A> {
/// assert!(!v.is_empty());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_is_empty")]
#[rustc_diagnostic_item = "vec_is_empty"]
#[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
pub const fn is_empty(&self) -> bool {
self.len() == 0
@ -3193,7 +3193,7 @@ impl<T: PartialEq, A: Allocator> Vec<T, A> {
#[doc(hidden)]
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "vec_from_elem")]
#[rustc_diagnostic_item = "vec_from_elem"]
#[track_caller]
pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
<T as SpecFromElem>::from_elem(elem, n, Global)
@ -3293,23 +3293,12 @@ unsafe impl<T, A: Allocator> ops::DerefPure for Vec<T, A> {}
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
#[cfg(not(test))]
#[track_caller]
fn clone(&self) -> Self {
let alloc = self.allocator().clone();
<[T]>::to_vec_in(&**self, alloc)
}
// HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
// required for this method definition, is not available. Instead use the
// `slice::to_vec` function which is only available with cfg(test)
// NB see the slice::hack module in slice.rs for more information
#[cfg(test)]
fn clone(&self) -> Self {
let alloc = self.allocator().clone();
crate::slice::to_vec(&**self, alloc)
}
/// Overwrites the contents of `self` with a clone of the contents of `source`.
///
/// This method is preferred over simply assigning `source.clone()` to `self`,
@ -3854,15 +3843,10 @@ impl<T: Clone> From<&[T]> for Vec<T> {
/// ```
/// assert_eq!(Vec::from(&[1, 2, 3][..]), vec![1, 2, 3]);
/// ```
#[cfg(not(test))]
#[track_caller]
fn from(s: &[T]) -> Vec<T> {
s.to_vec()
}
#[cfg(test)]
fn from(s: &[T]) -> Vec<T> {
crate::slice::to_vec(s, Global)
}
}
#[cfg(not(no_global_oom_handling))]
@ -3875,15 +3859,10 @@ impl<T: Clone> From<&mut [T]> for Vec<T> {
/// ```
/// assert_eq!(Vec::from(&mut [1, 2, 3][..]), vec![1, 2, 3]);
/// ```
#[cfg(not(test))]
#[track_caller]
fn from(s: &mut [T]) -> Vec<T> {
s.to_vec()
}
#[cfg(test)]
fn from(s: &mut [T]) -> Vec<T> {
crate::slice::to_vec(s, Global)
}
}
#[cfg(not(no_global_oom_handling))]
@ -3928,16 +3907,10 @@ impl<T, const N: usize> From<[T; N]> for Vec<T> {
/// ```
/// assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]);
/// ```
#[cfg(not(test))]
#[track_caller]
fn from(s: [T; N]) -> Vec<T> {
<[T]>::into_vec(Box::new(s))
}
#[cfg(test)]
fn from(s: [T; N]) -> Vec<T> {
crate::slice::into_vec(Box::new(s))
}
}
#[stable(feature = "vec_from_cow_slice", since = "1.14.0")]
@ -3966,7 +3939,6 @@ where
}
// note: test pulls in std, which causes errors here
#[cfg(not(test))]
#[stable(feature = "vec_from_box", since = "1.18.0")]
impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
/// Converts a boxed slice into a vector by transferring ownership of
@ -3985,7 +3957,6 @@ impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
// note: test pulls in std, which causes errors here
#[cfg(not(no_global_oom_handling))]
#[cfg(not(test))]
#[stable(feature = "box_from_vec", since = "1.20.0")]
impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> {
/// Converts a vector into a boxed slice.

View File

@ -1,259 +0,0 @@
use std::any::Any;
use std::cell::{Cell, RefCell};
use std::iter::TrustedLen;
use std::rc::{Rc, Weak};
#[test]
fn uninhabited() {
enum Void {}
let mut a = Weak::<Void>::new();
a = a.clone();
assert!(a.upgrade().is_none());
let mut a: Weak<dyn Any> = a; // Unsizing
a = a.clone();
assert!(a.upgrade().is_none());
}
#[test]
fn slice() {
let a: Rc<[u32; 3]> = Rc::new([3, 2, 1]);
let a: Rc<[u32]> = a; // Unsizing
let b: Rc<[u32]> = Rc::from(&[3, 2, 1][..]); // Conversion
assert_eq!(a, b);
// Exercise is_dangling() with a DST
let mut a = Rc::downgrade(&a);
a = a.clone();
assert!(a.upgrade().is_some());
}
#[test]
fn trait_object() {
let a: Rc<u32> = Rc::new(4);
let a: Rc<dyn Any> = a; // Unsizing
// Exercise is_dangling() with a DST
let mut a = Rc::downgrade(&a);
a = a.clone();
assert!(a.upgrade().is_some());
let mut b = Weak::<u32>::new();
b = b.clone();
assert!(b.upgrade().is_none());
let mut b: Weak<dyn Any> = b; // Unsizing
b = b.clone();
assert!(b.upgrade().is_none());
}
#[test]
fn float_nan_ne() {
let x = Rc::new(f32::NAN);
assert!(x != x);
assert!(!(x == x));
}
#[test]
fn partial_eq() {
struct TestPEq(RefCell<usize>);
impl PartialEq for TestPEq {
fn eq(&self, other: &TestPEq) -> bool {
*self.0.borrow_mut() += 1;
*other.0.borrow_mut() += 1;
true
}
}
let x = Rc::new(TestPEq(RefCell::new(0)));
assert!(x == x);
assert!(!(x != x));
assert_eq!(*x.0.borrow(), 4);
}
#[test]
fn eq() {
#[derive(Eq)]
struct TestEq(RefCell<usize>);
impl PartialEq for TestEq {
fn eq(&self, other: &TestEq) -> bool {
*self.0.borrow_mut() += 1;
*other.0.borrow_mut() += 1;
true
}
}
let x = Rc::new(TestEq(RefCell::new(0)));
assert!(x == x);
assert!(!(x != x));
assert_eq!(*x.0.borrow(), 0);
}
const SHARED_ITER_MAX: u16 = 100;
fn assert_trusted_len<I: TrustedLen>(_: &I) {}
#[test]
fn shared_from_iter_normal() {
// Exercise the base implementation for non-`TrustedLen` iterators.
{
// `Filter` is never `TrustedLen` since we don't
// know statically how many elements will be kept:
let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new);
// Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference:
let vec = iter.clone().collect::<Vec<_>>();
let rc = iter.collect::<Rc<[_]>>();
assert_eq!(&*vec, &*rc);
// Clone a bit and let these get dropped.
{
let _rc_2 = rc.clone();
let _rc_3 = rc.clone();
let _rc_4 = Rc::downgrade(&_rc_3);
}
} // Drop what hasn't been here.
}
#[test]
fn shared_from_iter_trustedlen_normal() {
// Exercise the `TrustedLen` implementation under normal circumstances
// where `size_hint()` matches `(_, Some(exact_len))`.
{
let iter = (0..SHARED_ITER_MAX).map(Box::new);
assert_trusted_len(&iter);
// Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference:
let vec = iter.clone().collect::<Vec<_>>();
let rc = iter.collect::<Rc<[_]>>();
assert_eq!(&*vec, &*rc);
assert_eq!(size_of::<Box<u16>>() * SHARED_ITER_MAX as usize, size_of_val(&*rc));
// Clone a bit and let these get dropped.
{
let _rc_2 = rc.clone();
let _rc_3 = rc.clone();
let _rc_4 = Rc::downgrade(&_rc_3);
}
} // Drop what hasn't been here.
// Try a ZST to make sure it is handled well.
{
let iter = (0..SHARED_ITER_MAX).map(drop);
let vec = iter.clone().collect::<Vec<_>>();
let rc = iter.collect::<Rc<[_]>>();
assert_eq!(&*vec, &*rc);
assert_eq!(0, size_of_val(&*rc));
{
let _rc_2 = rc.clone();
let _rc_3 = rc.clone();
let _rc_4 = Rc::downgrade(&_rc_3);
}
}
}
#[test]
#[should_panic = "I've almost got 99 problems."]
fn shared_from_iter_trustedlen_panic() {
// Exercise the `TrustedLen` implementation when `size_hint()` matches
// `(_, Some(exact_len))` but where `.next()` drops before the last iteration.
let iter = (0..SHARED_ITER_MAX).map(|val| match val {
98 => panic!("I've almost got 99 problems."),
_ => Box::new(val),
});
assert_trusted_len(&iter);
let _ = iter.collect::<Rc<[_]>>();
panic!("I am unreachable.");
}
#[test]
fn shared_from_iter_trustedlen_no_fuse() {
// Exercise the `TrustedLen` implementation when `size_hint()` matches
// `(_, Some(exact_len))` but where the iterator does not behave in a fused manner.
struct Iter(std::vec::IntoIter<Option<Box<u8>>>);
unsafe impl TrustedLen for Iter {}
impl Iterator for Iter {
fn size_hint(&self) -> (usize, Option<usize>) {
(2, Some(2))
}
type Item = Box<u8>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().flatten()
}
}
let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))];
let iter = Iter(vec.into_iter());
assert_trusted_len(&iter);
assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
}
#[test]
fn weak_may_dangle() {
fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
val.clone()
}
// Without #[may_dangle] we get:
let mut val = Weak::new();
hmm(&mut val);
// ~~~~~~~~ borrowed value does not live long enough
//
// `val` dropped here while still borrowed
// borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak`
}
/// Test that a panic from a destructor does not leak the allocation.
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn panic_no_leak() {
use std::alloc::{AllocError, Allocator, Global, Layout};
use std::panic::{AssertUnwindSafe, catch_unwind};
use std::ptr::NonNull;
struct AllocCount(Cell<i32>);
unsafe impl Allocator for AllocCount {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
self.0.set(self.0.get() + 1);
Global.allocate(layout)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
self.0.set(self.0.get() - 1);
unsafe { Global.deallocate(ptr, layout) }
}
}
struct PanicOnDrop;
impl Drop for PanicOnDrop {
fn drop(&mut self) {
panic!("PanicOnDrop");
}
}
let alloc = AllocCount(Cell::new(0));
let rc = Rc::new_in(PanicOnDrop, &alloc);
assert_eq!(alloc.0.get(), 1);
let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err();
assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop");
assert_eq!(alloc.0.get(), 0);
}
#[allow(unused)]
mod pin_coerce_unsized {
use alloc::rc::{Rc, UniqueRc};
use core::pin::Pin;
pub trait MyTrait {}
impl MyTrait for String {}
// Pin coercion should work for Rc
pub fn pin_rc(arg: Pin<Rc<String>>) -> Pin<Rc<dyn MyTrait>> {
arg
}
pub fn pin_unique_rc(arg: Pin<UniqueRc<String>>) -> Pin<UniqueRc<dyn MyTrait>> {
arg
}
}

View File

@ -0,0 +1,47 @@
[package]
name = "alloctests"
version = "0.0.0"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
description = "Tests for the Rust Allocation Library"
autotests = false
autobenches = false
edition = "2021"
[lib]
path = "lib.rs"
test = true
bench = true
doc = false
[dev-dependencies]
rand = { version = "0.9.0", default-features = false, features = ["alloc"] }
rand_xorshift = "0.4.0"
[[test]]
name = "alloctests"
path = "tests/lib.rs"
[[test]]
name = "vec_deque_alloc_error"
path = "tests/vec_deque_alloc_error.rs"
[[bench]]
name = "allocbenches"
path = "benches/lib.rs"
test = true
[[bench]]
name = "vec_deque_append_bench"
path = "benches/vec_deque_append.rs"
harness = false
[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = [
'cfg(bootstrap)',
'cfg(no_global_oom_handling)',
'cfg(no_rc)',
'cfg(no_sync)',
'cfg(randomized_layouts)',
]

93
library/alloctests/lib.rs Normal file
View File

@ -0,0 +1,93 @@
#![cfg(test)]
#![allow(unused_attributes)]
#![unstable(feature = "alloctests", issue = "none")]
#![no_std]
// Lints:
#![deny(unsafe_op_in_unsafe_fn)]
#![warn(deprecated_in_future)]
#![warn(missing_debug_implementations)]
#![allow(explicit_outlives_requirements)]
#![allow(internal_features)]
#![allow(rustdoc::redundant_explicit_links)]
#![warn(rustdoc::unescaped_backticks)]
#![deny(ffi_unwind_calls)]
//
// Library features:
// tidy-alphabetical-start
#![feature(alloc_layout_extra)]
#![feature(allocator_api)]
#![feature(array_into_iter_constructors)]
#![feature(assert_matches)]
#![feature(core_intrinsics)]
#![feature(exact_size_is_empty)]
#![feature(extend_one)]
#![feature(extend_one_unchecked)]
#![feature(hasher_prefixfree_extras)]
#![feature(inplace_iteration)]
#![feature(iter_advance_by)]
#![feature(iter_next_chunk)]
#![feature(maybe_uninit_slice)]
#![feature(maybe_uninit_uninit_array_transpose)]
#![feature(ptr_internals)]
#![feature(sized_type_properties)]
#![feature(slice_iter_mut_as_mut_slice)]
#![feature(slice_ptr_get)]
#![feature(slice_range)]
#![feature(std_internals)]
#![feature(temporary_niche_types)]
#![feature(trusted_fused)]
#![feature(trusted_len)]
#![feature(trusted_random_access)]
#![feature(try_reserve_kind)]
#![feature(try_trait_v2)]
// tidy-alphabetical-end
//
// Language features:
// tidy-alphabetical-start
#![feature(cfg_sanitize)]
#![feature(dropck_eyepatch)]
#![feature(lang_items)]
#![feature(min_specialization)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(optimize_attribute)]
#![feature(rustc_allow_const_fn_unstable)]
#![feature(rustc_attrs)]
#![feature(staged_api)]
#![feature(test)]
#![rustc_preserve_ub_checks]
// tidy-alphabetical-end
// Allow testing this library
extern crate alloc as realalloc;
#[macro_use]
extern crate std;
#[cfg(test)]
extern crate test;
mod testing;
use realalloc::*;
// We are directly including collections and raw_vec here as both use non-public
// methods and fields in tests and as such need to have the types to test in the
// same crate as the tests themself.
#[path = "../alloc/src/collections/mod.rs"]
mod collections;
#[path = "../alloc/src/raw_vec/mod.rs"]
mod raw_vec;
#[allow(dead_code)] // Not used in all configurations
pub(crate) mod test_helpers {
/// Copied from `std::test_helpers::test_rng`, since these tests rely on the
/// seed not being the same for every RNG invocation too.
pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
use std::hash::{BuildHasher, Hash, Hasher};
let mut hasher = std::hash::RandomState::new().build_hasher();
std::panic::Location::caller().hash(&mut hasher);
let hc64 = hasher.finish();
let seed_vec =
hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<crate::vec::Vec<u8>>();
let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
rand::SeedableRng::from_seed(seed)
}
}

View File

@ -43,11 +43,12 @@
#![deny(fuzzy_provenance_casts)]
#![deny(unsafe_op_in_unsafe_fn)]
extern crate alloc;
extern crate test;
use std::hash::{DefaultHasher, Hash, Hasher};
mod alloc;
mod alloc_test;
mod arc;
mod autotraits;
mod borrow;

View File

@ -1,7 +1,263 @@
use std::cell::RefCell;
use std::clone::Clone;
use std::any::Any;
use std::cell::{Cell, RefCell};
use std::iter::TrustedLen;
use std::mem;
use std::rc::{Rc, UniqueRc, Weak};
use super::*;
#[test]
fn uninhabited() {
enum Void {}
let mut a = Weak::<Void>::new();
a = a.clone();
assert!(a.upgrade().is_none());
let mut a: Weak<dyn Any> = a; // Unsizing
a = a.clone();
assert!(a.upgrade().is_none());
}
#[test]
fn slice() {
let a: Rc<[u32; 3]> = Rc::new([3, 2, 1]);
let a: Rc<[u32]> = a; // Unsizing
let b: Rc<[u32]> = Rc::from(&[3, 2, 1][..]); // Conversion
assert_eq!(a, b);
// Exercise is_dangling() with a DST
let mut a = Rc::downgrade(&a);
a = a.clone();
assert!(a.upgrade().is_some());
}
#[test]
fn trait_object() {
let a: Rc<u32> = Rc::new(4);
let a: Rc<dyn Any> = a; // Unsizing
// Exercise is_dangling() with a DST
let mut a = Rc::downgrade(&a);
a = a.clone();
assert!(a.upgrade().is_some());
let mut b = Weak::<u32>::new();
b = b.clone();
assert!(b.upgrade().is_none());
let mut b: Weak<dyn Any> = b; // Unsizing
b = b.clone();
assert!(b.upgrade().is_none());
}
#[test]
fn float_nan_ne() {
let x = Rc::new(f32::NAN);
assert!(x != x);
assert!(!(x == x));
}
#[test]
fn partial_eq() {
struct TestPEq(RefCell<usize>);
impl PartialEq for TestPEq {
fn eq(&self, other: &TestPEq) -> bool {
*self.0.borrow_mut() += 1;
*other.0.borrow_mut() += 1;
true
}
}
let x = Rc::new(TestPEq(RefCell::new(0)));
assert!(x == x);
assert!(!(x != x));
assert_eq!(*x.0.borrow(), 4);
}
#[test]
fn eq() {
#[derive(Eq)]
struct TestEq(RefCell<usize>);
impl PartialEq for TestEq {
fn eq(&self, other: &TestEq) -> bool {
*self.0.borrow_mut() += 1;
*other.0.borrow_mut() += 1;
true
}
}
let x = Rc::new(TestEq(RefCell::new(0)));
assert!(x == x);
assert!(!(x != x));
assert_eq!(*x.0.borrow(), 0);
}
const SHARED_ITER_MAX: u16 = 100;
fn assert_trusted_len<I: TrustedLen>(_: &I) {}
#[test]
fn shared_from_iter_normal() {
// Exercise the base implementation for non-`TrustedLen` iterators.
{
// `Filter` is never `TrustedLen` since we don't
// know statically how many elements will be kept:
let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new);
// Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference:
let vec = iter.clone().collect::<Vec<_>>();
let rc = iter.collect::<Rc<[_]>>();
assert_eq!(&*vec, &*rc);
// Clone a bit and let these get dropped.
{
let _rc_2 = rc.clone();
let _rc_3 = rc.clone();
let _rc_4 = Rc::downgrade(&_rc_3);
}
} // Drop what hasn't been here.
}
#[test]
fn shared_from_iter_trustedlen_normal() {
// Exercise the `TrustedLen` implementation under normal circumstances
// where `size_hint()` matches `(_, Some(exact_len))`.
{
let iter = (0..SHARED_ITER_MAX).map(Box::new);
assert_trusted_len(&iter);
// Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference:
let vec = iter.clone().collect::<Vec<_>>();
let rc = iter.collect::<Rc<[_]>>();
assert_eq!(&*vec, &*rc);
assert_eq!(size_of::<Box<u16>>() * SHARED_ITER_MAX as usize, size_of_val(&*rc));
// Clone a bit and let these get dropped.
{
let _rc_2 = rc.clone();
let _rc_3 = rc.clone();
let _rc_4 = Rc::downgrade(&_rc_3);
}
} // Drop what hasn't been here.
// Try a ZST to make sure it is handled well.
{
let iter = (0..SHARED_ITER_MAX).map(drop);
let vec = iter.clone().collect::<Vec<_>>();
let rc = iter.collect::<Rc<[_]>>();
assert_eq!(&*vec, &*rc);
assert_eq!(0, size_of_val(&*rc));
{
let _rc_2 = rc.clone();
let _rc_3 = rc.clone();
let _rc_4 = Rc::downgrade(&_rc_3);
}
}
}
#[test]
#[should_panic = "I've almost got 99 problems."]
fn shared_from_iter_trustedlen_panic() {
// Exercise the `TrustedLen` implementation when `size_hint()` matches
// `(_, Some(exact_len))` but where `.next()` drops before the last iteration.
let iter = (0..SHARED_ITER_MAX).map(|val| match val {
98 => panic!("I've almost got 99 problems."),
_ => Box::new(val),
});
assert_trusted_len(&iter);
let _ = iter.collect::<Rc<[_]>>();
panic!("I am unreachable.");
}
#[test]
fn shared_from_iter_trustedlen_no_fuse() {
// Exercise the `TrustedLen` implementation when `size_hint()` matches
// `(_, Some(exact_len))` but where the iterator does not behave in a fused manner.
struct Iter(std::vec::IntoIter<Option<Box<u8>>>);
unsafe impl TrustedLen for Iter {}
impl Iterator for Iter {
fn size_hint(&self) -> (usize, Option<usize>) {
(2, Some(2))
}
type Item = Box<u8>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().flatten()
}
}
let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))];
let iter = Iter(vec.into_iter());
assert_trusted_len(&iter);
assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
}
#[test]
fn weak_may_dangle() {
fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
val.clone()
}
// Without #[may_dangle] we get:
let mut val = Weak::new();
hmm(&mut val);
// ~~~~~~~~ borrowed value does not live long enough
//
// `val` dropped here while still borrowed
// borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak`
}
/// Test that a panic from a destructor does not leak the allocation.
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn panic_no_leak() {
use std::alloc::{AllocError, Allocator, Global, Layout};
use std::panic::{AssertUnwindSafe, catch_unwind};
use std::ptr::NonNull;
struct AllocCount(Cell<i32>);
unsafe impl Allocator for AllocCount {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
self.0.set(self.0.get() + 1);
Global.allocate(layout)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
self.0.set(self.0.get() - 1);
unsafe { Global.deallocate(ptr, layout) }
}
}
struct PanicOnDrop;
impl Drop for PanicOnDrop {
fn drop(&mut self) {
panic!("PanicOnDrop");
}
}
let alloc = AllocCount(Cell::new(0));
let rc = Rc::new_in(PanicOnDrop, &alloc);
assert_eq!(alloc.0.get(), 1);
let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err();
assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop");
assert_eq!(alloc.0.get(), 0);
}
#[allow(unused)]
mod pin_coerce_unsized {
use alloc::rc::{Rc, UniqueRc};
use core::pin::Pin;
pub trait MyTrait {}
impl MyTrait for String {}
// Pin coercion should work for Rc
pub fn pin_rc(arg: Pin<Rc<String>>) -> Pin<Rc<dyn MyTrait>> {
arg
}
pub fn pin_unique_rc(arg: Pin<UniqueRc<String>>) -> Pin<UniqueRc<dyn MyTrait>> {
arg
}
}
#[test]
fn test_clone() {
@ -61,16 +317,20 @@ fn weak_self_cyclic() {
#[test]
fn is_unique() {
fn is_unique<T>(this: &Rc<T>) -> bool {
Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1
}
let x = Rc::new(3);
assert!(Rc::is_unique(&x));
assert!(is_unique(&x));
let y = x.clone();
assert!(!Rc::is_unique(&x));
assert!(!is_unique(&x));
drop(y);
assert!(Rc::is_unique(&x));
assert!(is_unique(&x));
let w = Rc::downgrade(&x);
assert!(!Rc::is_unique(&x));
assert!(!is_unique(&x));
drop(w);
assert!(Rc::is_unique(&x));
assert!(is_unique(&x));
}
#[test]

View File

@ -202,6 +202,9 @@ impl fmt::Debug for VarsOs {
/// Returns [`VarError::NotUnicode`] if the variable's value is not valid
/// Unicode. If this is not desired, consider using [`var_os`].
///
/// Use [`env!`] or [`option_env!`] instead if you want to check environment
/// variables at compile time.
///
/// # Examples
///
/// ```

View File

@ -2446,7 +2446,7 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
/// # Platform-specific behavior
///
/// This function currently corresponds to the `rename` function on Unix
/// and the `SetFileInformationByHandle` function on Windows.
/// and the `MoveFileExW` or `SetFileInformationByHandle` function on Windows.
///
/// Because of this, the behavior when both `from` and `to` exist differs. On
/// Unix, if `from` is a directory, `to` must also be an (empty) directory. If

View File

@ -1,10 +1,10 @@
use super::api::{self, WinError, set_file_information_by_handle};
use super::{IoResult, to_u16s};
use crate::alloc::{alloc, handle_alloc_error};
use crate::alloc::{Layout, alloc, dealloc};
use crate::borrow::Cow;
use crate::ffi::{OsStr, OsString, c_void};
use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
use crate::mem::{self, MaybeUninit};
use crate::mem::{self, MaybeUninit, offset_of};
use crate::os::windows::io::{AsHandle, BorrowedHandle};
use crate::os::windows::prelude::*;
use crate::path::{Path, PathBuf};
@ -1241,139 +1241,72 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
let old = maybe_verbatim(old)?;
let new = maybe_verbatim(new)?;
let new_len_without_nul_in_bytes = (new.len() - 1).try_into().unwrap();
if unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) } == 0 {
let err = api::get_last_error();
// if `MoveFileExW` fails with ERROR_ACCESS_DENIED then try to move
// the file while ignoring the readonly attribute.
// This is accomplished by calling `SetFileInformationByHandle` with `FileRenameInfoEx`.
if err == WinError::ACCESS_DENIED {
let mut opts = OpenOptions::new();
opts.access_mode(c::DELETE);
opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS);
let Ok(f) = File::open_native(&old, &opts) else { return Err(err).io_result() };
// The last field of FILE_RENAME_INFO, the file name, is unsized,
// and FILE_RENAME_INFO has two padding bytes.
// Therefore we need to make sure to not allocate less than
// size_of::<c::FILE_RENAME_INFO>() bytes, which would be the case with
// 0 or 1 character paths + a null byte.
let struct_size = size_of::<c::FILE_RENAME_INFO>()
.max(mem::offset_of!(c::FILE_RENAME_INFO, FileName) + new.len() * size_of::<u16>());
// Calculate the layout of the `FILE_RENAME_INFO` we pass to `SetFileInformation`
// This is a dynamically sized struct so we need to get the position of the last field to calculate the actual size.
let Ok(new_len_without_nul_in_bytes): Result<u32, _> = ((new.len() - 1) * 2).try_into()
else {
return Err(err).io_result();
};
let offset: u32 = offset_of!(c::FILE_RENAME_INFO, FileName).try_into().unwrap();
let struct_size = offset + new_len_without_nul_in_bytes + 2;
let layout =
Layout::from_size_align(struct_size as usize, align_of::<c::FILE_RENAME_INFO>())
.unwrap();
let struct_size: u32 = struct_size.try_into().unwrap();
// SAFETY: We allocate enough memory for a full FILE_RENAME_INFO struct and a filename.
let file_rename_info;
unsafe {
file_rename_info = alloc(layout).cast::<c::FILE_RENAME_INFO>();
if file_rename_info.is_null() {
return Err(io::ErrorKind::OutOfMemory.into());
}
let create_file = |extra_access, extra_flags| {
let handle = unsafe {
HandleOrInvalid::from_raw_handle(c::CreateFileW(
old.as_ptr(),
c::SYNCHRONIZE | c::DELETE | extra_access,
c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE,
ptr::null(),
c::OPEN_EXISTING,
c::FILE_ATTRIBUTE_NORMAL | c::FILE_FLAG_BACKUP_SEMANTICS | extra_flags,
ptr::null_mut(),
))
};
(&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 {
Flags: c::FILE_RENAME_FLAG_REPLACE_IF_EXISTS
| c::FILE_RENAME_FLAG_POSIX_SEMANTICS,
});
OwnedHandle::try_from(handle).map_err(|_| io::Error::last_os_error())
};
(&raw mut (*file_rename_info).RootDirectory).write(ptr::null_mut());
// Don't include the NULL in the size
(&raw mut (*file_rename_info).FileNameLength).write(new_len_without_nul_in_bytes);
// The following code replicates `MoveFileEx`'s behavior as reverse-engineered from its disassembly.
// If `old` refers to a mount point, we move it instead of the target.
let handle = match create_file(c::FILE_READ_ATTRIBUTES, c::FILE_FLAG_OPEN_REPARSE_POINT) {
Ok(handle) => {
let mut file_attribute_tag_info: MaybeUninit<c::FILE_ATTRIBUTE_TAG_INFO> =
MaybeUninit::uninit();
new.as_ptr().copy_to_nonoverlapping(
(&raw mut (*file_rename_info).FileName).cast::<u16>(),
new.len(),
);
}
let result = unsafe {
cvt(c::GetFileInformationByHandleEx(
handle.as_raw_handle(),
c::FileAttributeTagInfo,
file_attribute_tag_info.as_mut_ptr().cast(),
size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
))
};
if let Err(err) = result {
if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _)
|| err.raw_os_error() == Some(c::ERROR_INVALID_FUNCTION as _)
{
// `GetFileInformationByHandleEx` documents that not all underlying drivers support all file information classes.
// Since we know we passed the correct arguments, this means the underlying driver didn't understand our request;
// `MoveFileEx` proceeds by reopening the file without inhibiting reparse point behavior.
None
} else {
Some(Err(err))
}
} else {
// SAFETY: The struct has been initialized by GetFileInformationByHandleEx
let file_attribute_tag_info = unsafe { file_attribute_tag_info.assume_init() };
let file_type = FileType::new(
file_attribute_tag_info.FileAttributes,
file_attribute_tag_info.ReparseTag,
);
if file_type.is_symlink() {
// The file is a mount point, junction point or symlink so
// don't reopen the file so that the link gets renamed.
Some(Ok(handle))
} else {
// Otherwise reopen the file without inhibiting reparse point behavior.
None
}
}
}
// The underlying driver may not support `FILE_FLAG_OPEN_REPARSE_POINT`: Retry without it.
Err(err) if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) => None,
Err(err) => Some(Err(err)),
}
.unwrap_or_else(|| create_file(0, 0))?;
let layout =
core::alloc::Layout::from_size_align(struct_size as _, align_of::<c::FILE_RENAME_INFO>())
.unwrap();
let file_rename_info = unsafe { alloc(layout) } as *mut c::FILE_RENAME_INFO;
if file_rename_info.is_null() {
handle_alloc_error(layout);
}
// SAFETY: file_rename_info is a non-null pointer pointing to memory allocated by the global allocator.
let mut file_rename_info = unsafe { Box::from_raw(file_rename_info) };
// SAFETY: We have allocated enough memory for a full FILE_RENAME_INFO struct and a filename.
unsafe {
(&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 {
Flags: c::FILE_RENAME_FLAG_REPLACE_IF_EXISTS | c::FILE_RENAME_FLAG_POSIX_SEMANTICS,
});
(&raw mut (*file_rename_info).RootDirectory).write(ptr::null_mut());
(&raw mut (*file_rename_info).FileNameLength).write(new_len_without_nul_in_bytes);
new.as_ptr()
.copy_to_nonoverlapping((&raw mut (*file_rename_info).FileName) as *mut u16, new.len());
}
// We don't use `set_file_information_by_handle` here as `FILE_RENAME_INFO` is used for both `FileRenameInfo` and `FileRenameInfoEx`.
let result = unsafe {
cvt(c::SetFileInformationByHandle(
handle.as_raw_handle(),
c::FileRenameInfoEx,
(&raw const *file_rename_info).cast::<c_void>(),
struct_size,
))
};
if let Err(err) = result {
if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) {
// FileRenameInfoEx and FILE_RENAME_FLAG_POSIX_SEMANTICS were added in Windows 10 1607; retry with FileRenameInfo.
file_rename_info.Anonymous.ReplaceIfExists = true;
cvt(unsafe {
c::SetFileInformationByHandle(
handle.as_raw_handle(),
c::FileRenameInfo,
(&raw const *file_rename_info).cast::<c_void>(),
f.as_raw_handle(),
c::FileRenameInfoEx,
file_rename_info.cast::<c_void>(),
struct_size,
)
})?;
};
unsafe { dealloc(file_rename_info.cast::<u8>(), layout) };
if result == 0 {
if api::get_last_error() == WinError::DIR_NOT_EMPTY {
return Err(WinError::DIR_NOT_EMPTY).io_result();
} else {
return Err(err).io_result();
}
}
} else {
return Err(err);
return Err(err).io_result();
}
}
Ok(())
}

View File

@ -56,6 +56,7 @@ check-aux:
# Run standard library tests in Miri.
$(Q)$(BOOTSTRAP) miri --stage 2 \
library/coretests \
library/alloctests \
library/alloc \
$(BOOTSTRAP_ARGS) \
--no-doc
@ -63,6 +64,7 @@ check-aux:
$(Q)MIRIFLAGS="-Zmiri-disable-isolation" \
$(BOOTSTRAP) miri --stage 2 \
library/coretests \
library/alloctests \
library/alloc \
$(BOOTSTRAP_ARGS) \
--doc

View File

@ -45,7 +45,10 @@ impl Step for Std {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.crate_or_deps("sysroot").crate_or_deps("coretests").path("library")
run.crate_or_deps("sysroot")
.crate_or_deps("coretests")
.crate_or_deps("alloctests")
.path("library")
}
fn make_run(run: RunConfig<'_>) {

View File

@ -2609,7 +2609,7 @@ impl Step for Crate {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.crate_or_deps("sysroot").crate_or_deps("coretests")
run.crate_or_deps("sysroot").crate_or_deps("coretests").crate_or_deps("alloctests")
}
fn make_run(run: RunConfig<'_>) {
@ -2724,12 +2724,16 @@ impl Step for Crate {
};
let mut crates = self.crates.clone();
// The core crate can't directly be tested. We could silently
// ignore it, but adding it's own test crate is less confusing
// for users. We still keep core itself for doctests.
// The core and alloc crates can't directly be tested. We
// could silently ignore them, but adding their own test
// crates is less confusing for users. We still keep core and
// alloc themself for doctests
if crates.iter().any(|crate_| crate_ == "core") {
crates.push("coretests".to_owned());
}
if crates.iter().any(|crate_| crate_ == "alloc") {
crates.push("alloctests".to_owned());
}
run_cargo_test(cargo, &[], &crates, &*crate_description(&self.crates), target, builder);
}

View File

@ -160,7 +160,6 @@ pub(crate) fn new_dcx(
HumanEmitter::new(stderr_destination(color_config), fallback_bundle)
.sm(source_map.map(|sm| sm as _))
.short_message(short)
.teach(unstable_opts.teach)
.diagnostic_width(diagnostic_width)
.track_diagnostics(unstable_opts.track_diagnostics)
.theme(if let HumanReadableErrorType::Unicode = kind {

View File

@ -475,7 +475,7 @@ pub fn check(path: &Path, bad: &mut bool) {
&& !trimmed.starts_with("//")
&& !file.ancestors().any(|a| {
(a.ends_with("tests") && a.join("COMPILER_TESTS.md").exists())
|| a.ends_with("library/alloc/tests")
|| a.ends_with("library/alloctests")
})
&& filename != "tests.rs"
{

View File

@ -8,8 +8,8 @@ LL | ... a http://link.com
note: the lint level is defined here
--> $DIR/diagnostic-width.rs:2:9
|
LL | ...ny(rustdoc::bare_url...
| ^^^^^^^^^^^^^^^^^^
LL | ...ny(ru...are_urls)]
| ^^...^^^^^^^^
help: use an automatic link instead
|
LL | /// This is a long line that contains a <http://link.com>

View File

@ -4,7 +4,7 @@ error[E0765]: unterminated double quote string
LL | """;
| ___________________^
LL | | }
| |_^
| |__^
error: aborting due to 1 previous error

View File

@ -0,0 +1,18 @@
error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]`
╭▸ $DIR/long-span.rs:7:5056
LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0] + [0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0];
│ ┬───────────────────────────…────────────────────── ━ ────────────────────────────…────────────────────── [{integer}; 1680]
│ │
╰╴ [{integer}; 1680]
error[E0308]: mismatched types
╭▸ $DIR/long-span.rs:9:15
LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0];
╰╴ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━…━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.

View File

@ -0,0 +1,18 @@
error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]`
--> $DIR/long-span.rs:7:5056
|
LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
| -----------------------------------------...----------------------------------- ^ -----------------------------------------...----------------------------------- [{integer}; 1680]
| |
| [{integer}; 1680]
error[E0308]: mismatched types
--> $DIR/long-span.rs:9:15
|
LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,18 @@
error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]`
╭▸ $DIR/long-span.rs:7:5056
LL │ …u8 = [0, 0, 0…0] + [0, 0, 0…0];
│ ┬───────…── ━ ────────…── [{integer}; 1680]
│ │
╰╴ [{integer}; 1680]
error[E0308]: mismatched types
╭▸ $DIR/long-span.rs:9:15
LL │ …u8 = [0, 0, 0…0];
╰╴ ━━━━━━━━…━━ expected `u8`, found `[{integer}; 1680]`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.

View File

@ -0,0 +1,18 @@
error[E0369]: cannot add `[{integer}; 1680]` to `[{integer}; 1680]`
--> $DIR/long-span.rs:7:5056
|
LL | ... = [0, 0, 0...0] + [0, 0, 0...0];
| --------...-- ^ --------...-- [{integer}; 1680]
| |
| [{integer}; 1680]
error[E0308]: mismatched types
--> $DIR/long-span.rs:9:15
|
LL | ... = [0, 0, 0...0];
| ^^^^^^^^...^^ expected `u8`, found `[{integer}; 1680]`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.

View File

@ -1,11 +1,41 @@
error[E0369]: cannot add `&str` to `&str`
--> $DIR/non-1-width-unicode-multiline-label.rs:7:260
--> $DIR/non-1-width-unicode-multiline-label.rs:7:237
|
LL | ...ཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇...࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";
| -------------- ^ -------------- &str
| | |
| | `+` cannot be used to concatenate two `&str` strings
| &str
LL | ...👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!";
| -------------- ^ -------------- &str
| | |
| | `+` cannot be used to concatenate two `&str` strings
| &str
|
= note: string concatenation requires an owned `String` on the left
help: create an owned `String` from a string reference
|
LL | let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!";
| +++++++++++
error[E0369]: cannot add `&str` to `&str`
--> $DIR/non-1-width-unicode-multiline-label.rs:9:384
|
LL | ...👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!";
| -------------- ^ -------------- &str
| | |
| | `+` cannot be used to concatenate two `&str` strings
| &str
|
= note: string concatenation requires an owned `String` on the left
help: create an owned `String` from a string reference
|
LL | let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!";
| +++++++++++
error[E0369]: cannot add `&str` to `&str`
--> $DIR/non-1-width-unicode-multiline-label.rs:11:260
|
LL | ...࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";
| -------------- ^ -------------- &str
| | |
| | `+` cannot be used to concatenate two `&str` strings
| &str
|
= note: string concatenation requires an owned `String` on the left
help: create an owned `String` from a string reference
@ -13,6 +43,21 @@ help: create an owned `String` from a string reference
LL | let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!";
| +++++++++++
error: aborting due to 1 previous error
error[E0369]: cannot add `&str` to `&str`
--> $DIR/non-1-width-unicode-multiline-label.rs:13:219
|
LL | ...xxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun + " really fun!";
| -------------- ^ -------------- &str
| | |
| | `+` cannot be used to concatenate two `&str` strings
| &str
|
= note: string concatenation requires an owned `String` on the left
help: create an owned `String` from a string reference
|
LL | let _ = "xxxxxxx👨👩👧👦xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx👨xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun.to_owned() + " really fun!";
| +++++++++++
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0369`.

View File

@ -4,6 +4,12 @@
fn main() {
let unicode_is_fun = "؁‱ஹ௸௵꧄.ဪ꧅⸻𒈙𒐫﷽𒌄𒈟𒍼𒁎𒀱𒌧𒅃 𒈓𒍙𒊎𒄡𒅌𒁏𒀰𒐪𒐩𒈙𒐫𪚥";
let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!";
//[ascii]~^ ERROR cannot add `&str` to `&str`
let _ = "👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦"; let _a = unicode_is_fun + " really fun!";
//[ascii]~^ ERROR cannot add `&str` to `&str`
let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";
//[ascii]~^ ERROR cannot add `&str` to `&str`
let _ = "xxxxxxx👨👩👧👦xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx👨xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun + " really fun!";
//[ascii]~^ ERROR cannot add `&str` to `&str`
}

View File

@ -1,11 +1,41 @@
error[E0369]: cannot add `&str` to `&str`
╭▸ $DIR/non-1-width-unicode-multiline-label.rs:7:260
╭▸ $DIR/non-1-width-unicode-multiline-label.rs:7:237
LL │ …ཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉…࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";
│ ┬───────────── ┯ ────────────── &str
│ │ │
│ │ `+` cannot be used to concatenate two `&str` strings
│ &str
LL │ …👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!";
│ ┬───────────── ┯ ────────────── &str
│ │ │
│ │ `+` cannot be used to concatenate two `&str` strings
│ &str
╰ note: string concatenation requires an owned `String` on the left
help: create an owned `String` from a string reference
╭╴
LL │ let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!";
╰╴ +++++++++++
error[E0369]: cannot add `&str` to `&str`
╭▸ $DIR/non-1-width-unicode-multiline-label.rs:9:384
LL │ …👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun + " really fun!";
│ ┬───────────── ┯ ────────────── &str
│ │ │
│ │ `+` cannot be used to concatenate two `&str` strings
│ &str
╰ note: string concatenation requires an owned `String` on the left
help: create an owned `String` from a string reference
╭╴
LL │ let _ = "👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦👨👩👧👦"; let _a = unicode_is_fun.to_owned() + " really fun!";
╰╴ +++++++++++
error[E0369]: cannot add `&str` to `&str`
╭▸ $DIR/non-1-width-unicode-multiline-label.rs:11:260
LL │ …࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";
│ ┬───────────── ┯ ────────────── &str
│ │ │
│ │ `+` cannot be used to concatenate two `&str` strings
│ &str
╰ note: string concatenation requires an owned `String` on the left
help: create an owned `String` from a string reference
@ -13,6 +43,21 @@ help: create an owned `String` from a string reference
LL │ let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!";
╰╴ +++++++++++
error: aborting due to 1 previous error
error[E0369]: cannot add `&str` to `&str`
╭▸ $DIR/non-1-width-unicode-multiline-label.rs:13:219
LL │ …xxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun + " really fun!";
│ ┬───────────── ┯ ────────────── &str
│ │ │
│ │ `+` cannot be used to concatenate two `&str` strings
│ &str
╰ note: string concatenation requires an owned `String` on the left
help: create an owned `String` from a string reference
╭╴
LL │ let _ = "xxxxxxx👨👩👧👦xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx👨xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; let _a = unicode_is_fun.to_owned() + " really fun!";
╰╴ +++++++++++
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0369`.

View File

@ -1,10 +1,10 @@
error[E0308]: mismatched types
--> $DIR/non-whitespace-trimming-unicode.rs:4:415
|
LL | ...♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄...
| -- ^^ expected `()`, found integer
| |
| expected due to this
LL | ...♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼...
| -- ^^ expected `()`, found integer
| |
| expected due to this
error: aborting due to 1 previous error

Some files were not shown because too many files have changed in this diff Show More