mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-16 14:07:04 +00:00
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:
commit
79b43dfde9
@ -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
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -4,6 +4,7 @@ members = [
|
||||
"std",
|
||||
"sysroot",
|
||||
"coretests",
|
||||
"alloctests",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
|
@ -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"]
|
||||
|
@ -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")]
|
||||
|
@ -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,
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {}
|
||||
|
@ -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>,
|
||||
|
@ -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>) {
|
||||
|
@ -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 {
|
||||
|
@ -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>.
|
||||
///
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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({
|
||||
|
@ -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};
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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`].
|
||||
|
@ -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,
|
||||
|
@ -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")]
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
}
|
47
library/alloctests/Cargo.toml
Normal file
47
library/alloctests/Cargo.toml
Normal 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
93
library/alloctests/lib.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -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;
|
@ -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]
|
@ -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
|
||||
///
|
||||
/// ```
|
||||
|
@ -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
|
||||
|
@ -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(())
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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<'_>) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
{
|
||||
|
@ -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>
|
||||
|
@ -4,7 +4,7 @@ error[E0765]: unterminated double quote string
|
||||
LL | """;
|
||||
| ___________________^
|
||||
LL | | }
|
||||
| |_^
|
||||
| |__^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
18
tests/ui/diagnostic-width/long-span.long.stderr
Normal file
18
tests/ui/diagnostic-width/long-span.long.stderr
Normal 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`.
|
18
tests/ui/diagnostic-width/long-span.longest.stderr
Normal file
18
tests/ui/diagnostic-width/long-span.longest.stderr
Normal 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`.
|
11
tests/ui/diagnostic-width/long-span.rs
Normal file
11
tests/ui/diagnostic-width/long-span.rs
Normal file
File diff suppressed because one or more lines are too long
18
tests/ui/diagnostic-width/long-span.short.stderr
Normal file
18
tests/ui/diagnostic-width/long-span.short.stderr
Normal 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`.
|
18
tests/ui/diagnostic-width/long-span.shortest.stderr
Normal file
18
tests/ui/diagnostic-width/long-span.shortest.stderr
Normal 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`.
|
@ -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`.
|
||||
|
@ -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`
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user