-name: Internal Compiler Error (Structured form)
+name: Internal Compiler Error (for use by automated tooling)
description: For now, you'll want to use the other ICE template, as GitHub forms have strict limits on the size of fields so backtraces cannot be pasted directly.
labels: ["C-bug", "I-ICE", "T-compiler"]
title: "[ICE]: "
env: {}
- name: x86_64-gnu-tools
tidy: false
- env:
- CI_ONLY_WHEN_SUBMODULES_CHANGED: 1
os: ubuntu-20.04-xl
+ env: {}
timeout-minutes: 600
runs-on: "${{ matrix.os }}"
steps:
"unicode-xid",
"url",
"walkdir",
- "winapi",
+ "windows-sys 0.45.0",
]
[[package]]
version = "0.2.0"
dependencies = [
"cargo-credential",
- "winapi",
+ "windows-sys 0.45.0",
]
[[package]]
"time 0.3.17",
"toml_edit",
"url",
- "winapi",
+ "windows-sys 0.45.0",
]
[[package]]
"shell-escape",
"tempfile",
"walkdir",
- "winapi",
+ "windows-sys 0.45.0",
]
[[package]]
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
dependencies = [
"libc",
- "windows-sys",
+ "windows-sys 0.42.0",
]
[[package]]
"hermit-abi 0.2.6",
"io-lifetimes",
"rustix",
- "windows-sys",
+ "windows-sys 0.42.0",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123"
dependencies = [
- "windows-sys",
+ "windows-sys 0.42.0",
]
[[package]]
"libc",
"redox_syscall",
"smallvec",
- "windows-sys",
+ "windows-sys 0.42.0",
]
[[package]]
"io-lifetimes",
"libc",
"linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.42.0",
]
[[package]]
checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
dependencies = [
"rustix",
- "windows-sys",
+ "windows-sys 0.42.0",
]
[[package]]
"windows_x86_64_msvc",
]
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_msvc"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_i686_gnu"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_msvc"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "writeable"
predicates
.iter()
.map(|(param, constraint)| (param.name.as_str(), &**constraint, None)),
+ None,
);
}
}
}
self.constraints.member_constraints = tmp;
- for (predicate, constraint_category) in outlives {
- // At the moment, we never generate any "higher-ranked"
- // region constraints like `for<'a> 'a: 'b`. At some point
- // when we move to universes, we will, and this assertion
- // will start to fail.
- let predicate = predicate.no_bound_vars().unwrap_or_else(|| {
- bug!("query_constraint {:?} contained bound vars", predicate,);
- });
-
- self.convert(predicate, *constraint_category);
+ for &(predicate, constraint_category) in outlives {
+ self.convert(predicate, constraint_category);
}
}
let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?;
let vtable = Scalar::from_maybe_pointer(vtable, self);
let data = self.read_immediate(src)?.to_scalar();
- let _assert_pointer_sized = data.to_pointer(self)?;
+ let _assert_pointer_like = data.to_pointer(self)?;
let val = Immediate::ScalarPair(data, vtable);
self.write_immediate(val, dest)?;
} else {
col: u32,
) -> MPlaceTy<'tcx, M::Provenance> {
let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail;
+ // This can fail if rustc runs out of memory right here. Trying to emit an error would be
+ // pointless, since that would require allocating more memory than these short strings.
let file = if loc_details.file {
self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
+ .unwrap()
} else {
// FIXME: This creates a new allocation each time. It might be preferable to
// perform this allocation only once, and re-use the `MPlaceTy`.
// See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
- self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not)
+ self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not).unwrap()
};
let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
.bound_type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None))
.subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter()));
let loc_layout = self.layout_of(loc_ty).unwrap();
- // This can fail if rustc runs out of memory right here. Trying to emit an error would be
- // pointless, since that would require allocating more memory than a Location.
let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
// Initialize fields.
fn adjust_alloc_base_pointer(
ecx: &InterpCx<'mir, 'tcx, Self>,
ptr: Pointer,
- ) -> Pointer<Self::Provenance>;
+ ) -> InterpResult<'tcx, Pointer<Self::Provenance>>;
/// "Int-to-pointer cast"
fn ptr_from_addr_cast(
fn adjust_alloc_base_pointer(
_ecx: &InterpCx<$mir, $tcx, Self>,
ptr: Pointer<AllocId>,
- ) -> Pointer<AllocId> {
- ptr
+ ) -> InterpResult<$tcx, Pointer<AllocId>> {
+ Ok(ptr)
}
#[inline(always)]
_ => {}
}
// And we need to get the provenance.
- Ok(M::adjust_alloc_base_pointer(self, ptr))
+ M::adjust_alloc_base_pointer(self, ptr)
}
pub fn create_fn_alloc_ptr(
kind: MemoryKind<M::MemoryKind>,
) -> InterpResult<'tcx, Pointer<M::Provenance>> {
let alloc = Allocation::uninit(size, align, M::PANIC_ON_ALLOC_FAIL)?;
- // We can `unwrap` since `alloc` contains no pointers.
- Ok(self.allocate_raw_ptr(alloc, kind).unwrap())
+ self.allocate_raw_ptr(alloc, kind)
}
pub fn allocate_bytes_ptr(
align: Align,
kind: MemoryKind<M::MemoryKind>,
mutability: Mutability,
- ) -> Pointer<M::Provenance> {
+ ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
let alloc = Allocation::from_bytes(bytes, align, mutability);
- // We can `unwrap` since `alloc` contains no pointers.
- self.allocate_raw_ptr(alloc, kind).unwrap()
+ self.allocate_raw_ptr(alloc, kind)
}
/// This can fail only of `alloc` contains provenance.
);
let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?;
self.memory.alloc_map.insert(id, (kind, alloc.into_owned()));
- Ok(M::adjust_alloc_base_pointer(self, Pointer::from(id)))
+ M::adjust_alloc_base_pointer(self, Pointer::from(id))
}
pub fn reallocate_ptr(
str: &str,
kind: MemoryKind<M::MemoryKind>,
mutbl: Mutability,
- ) -> MPlaceTy<'tcx, M::Provenance> {
- let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl);
+ ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
+ let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?;
let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self);
let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) };
ty::TypeAndMut { ty: self.tcx.types.str_, mutbl },
);
let layout = self.layout_of(ty).unwrap();
- MPlaceTy { mplace, layout, align: layout.align.abi }
+ Ok(MPlaceTy { mplace, layout, align: layout.align.abi })
}
/// Writes the aggregate to the destination.
¶m_ty.name.as_str(),
&constraint,
None,
+ None,
);
}
}
#![feature(associated_type_bounds)]
#![feature(auto_traits)]
#![feature(cell_leak)]
+#![feature(core_intrinsics)]
#![feature(extend_one)]
#![feature(hash_raw_entry)]
#![feature(hasher_prefixfree_extras)]
use std::collections::hash_map::Entry;
use std::error::Error;
use std::fs;
+use std::intrinsics::unlikely;
use std::path::Path;
use std::process;
use std::sync::Arc;
/// Record a query in-memory cache hit.
#[inline(always)]
pub fn query_cache_hit(&self, query_invocation_id: QueryInvocationId) {
- self.instant_query_event(
- |profiler| profiler.query_cache_hit_event_kind,
- query_invocation_id,
- EventFilter::QUERY_CACHE_HITS,
- );
+ #[inline(never)]
+ #[cold]
+ fn cold_call(profiler_ref: &SelfProfilerRef, query_invocation_id: QueryInvocationId) {
+ profiler_ref.instant_query_event(
+ |profiler| profiler.query_cache_hit_event_kind,
+ query_invocation_id,
+ );
+ }
+
+ if unlikely(self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS)) {
+ cold_call(self, query_invocation_id);
+ }
}
/// Start profiling a query being blocked on a concurrent execution.
&self,
event_kind: fn(&SelfProfiler) -> StringId,
query_invocation_id: QueryInvocationId,
- event_filter: EventFilter,
) {
- drop(self.exec(event_filter, |profiler| {
- let event_id = StringId::new_virtual(query_invocation_id.0);
- let thread_id = get_thread_id();
-
- profiler.profiler.record_instant_event(
- event_kind(profiler),
- EventId::from_virtual(event_id),
- thread_id,
- );
-
- TimingGuard::none()
- }));
+ let event_id = StringId::new_virtual(query_invocation_id.0);
+ let thread_id = get_thread_id();
+ let profiler = self.profiler.as_ref().unwrap();
+ profiler.profiler.record_instant_event(
+ event_kind(profiler),
+ EventId::from_virtual(event_id),
+ thread_id,
+ );
}
pub fn with_profiler(&self, f: impl FnOnce(&SelfProfiler)) {
}
}
- let mut gctxt = queries.global_ctxt()?;
+ // Make sure name resolution and macro expansion is run.
+ queries.global_ctxt()?;
+
if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
return early_exit();
}
// Make sure the `output_filenames` query is run for its side
// effects of writing the dep-info and reporting errors.
- gctxt.enter(|tcx| tcx.output_filenames(()));
+ queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(()));
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
&& sess.opts.output_types.len() == 1
return early_exit();
}
- gctxt.enter(|tcx| {
+ queries.global_ctxt()?.enter(|tcx| {
let result = tcx.analysis(());
if sess.opts.unstable_opts.save_analysis {
let crate_name = tcx.crate_name(LOCAL_CRATE);
result
})?;
- drop(gctxt);
-
if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
return early_exit();
}
if !info.payload().is::<rustc_errors::ExplicitBug>()
&& !info.payload().is::<rustc_errors::DelayedBugPanic>()
{
- let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
- handler.emit_diagnostic(&mut d);
+ handler.emit_err(session_diagnostics::Ice);
}
- handler.emit_note(session_diagnostics::Ice);
handler.emit_note(session_diagnostics::IceBugReport { bug_report_url });
handler.emit_note(session_diagnostics::IceVersion {
version: util::version_str!().unwrap_or("unknown_version"),
E0520: include_str!("./error_codes/E0520.md"),
E0521: include_str!("./error_codes/E0521.md"),
E0522: include_str!("./error_codes/E0522.md"),
+E0523: include_str!("./error_codes/E0523.md"),
E0524: include_str!("./error_codes/E0524.md"),
E0525: include_str!("./error_codes/E0525.md"),
E0527: include_str!("./error_codes/E0527.md"),
// E0488, // lifetime of variable does not enclose its declaration
// E0489, // type/lifetime parameter not in scope here
// E0490, // removed: unreachable
- E0523, // two dependencies have same (crate-name, disambiguator) but different SVH
// E0526, // shuffle indices are not constant
// E0540, // multiple rustc_deprecated attributes
// E0548, // replaced with a generic attribute input check
The compiler found multiple library files with the requested crate name.
+```compile_fail
+// aux-build:crateresolve-1.rs
+// aux-build:crateresolve-2.rs
+// aux-build:crateresolve-3.rs
+
+extern crate crateresolve;
+//~^ ERROR multiple candidates for `rlib` dependency `crateresolve` found
+
+fn main() {}
+```
+
This error can occur in several different cases -- for example, when using
`extern crate` or passing `--extern` options without crate paths. It can also be
caused by caching issues with the build directory, in which case `cargo clean`
may help.
+
+In the above example, there are three different library files, all of which
+define the same crate name. Without providing a full path, there is no way for
+the compiler to know which crate it should use.
--- /dev/null
+#### Note: this error code is no longer emitted by the compiler.
+
+The compiler found multiple library files with the requested crate name.
+
+```compile_fail
+// aux-build:crateresolve-1.rs
+// aux-build:crateresolve-2.rs
+// aux-build:crateresolve-3.rs
+
+extern crate crateresolve;
+//~^ ERROR multiple candidates for `rlib` dependency `crateresolve` found
+
+fn main() {}
+```
+
+This error can occur in several different cases -- for example, when using
+`extern crate` or passing `--extern` options without crate paths. It can also be
+caused by caching issues with the build directory, in which case `cargo clean`
+may help.
+
+In the above example, there are three different library files, all of which
+define the same crate name. Without providing a full path, there is no way for
+the compiler to know which crate it should use.
+
+*Note that E0523 has been merged into E0464.*
&mut buffer,
&mut row_num,
&Vec::new(),
- p,
+ p + line_start,
l,
- line_start,
show_code_change,
max_line_num_len,
&file_lines,
&mut buffer,
&mut row_num,
&Vec::new(),
- p,
+ p + line_start,
l,
- line_start,
show_code_change,
max_line_num_len,
&file_lines,
&mut buffer,
&mut row_num,
&Vec::new(),
- p,
+ p + line_start,
l,
- line_start,
show_code_change,
max_line_num_len,
&file_lines,
&mut buffer,
&mut row_num,
highlight_parts,
- line_pos,
+ line_pos + line_start,
line,
- line_start,
show_code_change,
max_line_num_len,
&file_lines,
buffer: &mut StyledBuffer,
row_num: &mut usize,
highlight_parts: &Vec<SubstitutionHighlight>,
- line_pos: usize,
- line: &str,
- line_start: usize,
+ line_num: usize,
+ line_to_add: &str,
show_code_change: DisplaySuggestion,
max_line_num_len: usize,
file_lines: &FileLines,
is_multiline: bool,
) {
- // Print the span column to avoid confusion
- buffer.puts(*row_num, 0, &self.maybe_anonymized(line_start + line_pos), Style::LineNumber);
if let DisplaySuggestion::Diff = show_code_change {
- // Add the line number for both addition and removal to drive the point home.
- //
- // N - fn foo<A: T>(bar: A) {
- // N + fn foo(bar: impl T) {
- buffer.puts(
- *row_num - 1,
- 0,
- &self.maybe_anonymized(line_start + line_pos),
- Style::LineNumber,
- );
- buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
- buffer.puts(
- *row_num - 1,
- max_line_num_len + 3,
- &normalize_whitespace(
- &file_lines.file.get_line(file_lines.lines[line_pos].line_index).unwrap(),
- ),
- Style::NoStyle,
- );
- buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
+ // We need to print more than one line if the span we need to remove is multiline.
+ // For more info: https://github.com/rust-lang/rust/issues/92741
+ let lines_to_remove = file_lines.lines.iter().take(file_lines.lines.len() - 1);
+ for (index, line_to_remove) in lines_to_remove.enumerate() {
+ buffer.puts(
+ *row_num - 1,
+ 0,
+ &self.maybe_anonymized(line_num + index),
+ Style::LineNumber,
+ );
+ buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
+ let line = normalize_whitespace(
+ &file_lines.file.get_line(line_to_remove.line_index).unwrap(),
+ );
+ buffer.puts(*row_num - 1, max_line_num_len + 3, &line, Style::NoStyle);
+ *row_num += 1;
+ }
+ // If the last line is exactly equal to the line we need to add, we can skip both of them.
+ // This allows us to avoid output like the following:
+ // 2 - &
+ // 2 + if true { true } else { false }
+ // 3 - if true { true } else { false }
+ // If those lines aren't equal, we print their diff
+ let last_line_index = file_lines.lines[file_lines.lines.len() - 1].line_index;
+ let last_line = &file_lines.file.get_line(last_line_index).unwrap();
+ if last_line != line_to_add {
+ buffer.puts(
+ *row_num - 1,
+ 0,
+ &self.maybe_anonymized(line_num + file_lines.lines.len() - 1),
+ Style::LineNumber,
+ );
+ buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
+ buffer.puts(
+ *row_num - 1,
+ max_line_num_len + 3,
+ &normalize_whitespace(last_line),
+ Style::NoStyle,
+ );
+ buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
+ buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
+ buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
+ } else {
+ *row_num -= 2;
+ }
} else if is_multiline {
+ buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
match &highlight_parts[..] {
- [SubstitutionHighlight { start: 0, end }] if *end == line.len() => {
+ [SubstitutionHighlight { start: 0, end }] if *end == line_to_add.len() => {
buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
}
[] => {
buffer.puts(*row_num, max_line_num_len + 1, "~ ", Style::Addition);
}
}
+ buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
} else {
+ buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
draw_col_separator(buffer, *row_num, max_line_num_len + 1);
+ buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
}
- // print the suggestion
- buffer.append(*row_num, &normalize_whitespace(line), Style::NoStyle);
-
// Colorize addition/replacements with green.
for &SubstitutionHighlight { start, end } in highlight_parts {
// Account for tabs when highlighting (#87972).
- let tabs: usize = line
+ let tabs: usize = line_to_add
.chars()
.take(start)
.map(|ch| match ch {
TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
TryTraitFromYeet, sym::from_yeet, from_yeet_fn, Target::Fn, GenericRequirement::None;
- PointerSized, sym::pointer_sized, pointer_sized, Target::Trait, GenericRequirement::Exact(0);
+ PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0);
Poll, sym::Poll, poll, Target::Enum, GenericRequirement::None;
PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None;
bounds.iter().map(|(param, constraint, def_id)| {
(param.as_str(), constraint.as_str(), *def_id)
}),
+ None,
);
err.emit();
}
self.cause.clone(),
self.param_env,
ty::Binder::dummy(
- self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerSized, [a]),
+ self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerLike, [a]),
),
));
use crate::FnCtxt;
use rustc_hir as hir;
use rustc_hir::def::Res;
-use rustc_middle::ty::{self, DefIdTree, Ty};
+use rustc_hir::def_id::DefId;
+use rustc_infer::traits::ObligationCauseCode;
+use rustc_middle::ty::{self, DefIdTree, Ty, TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_span::{self, Span};
use rustc_trait_selection::traits;
+use std::ops::ControlFlow;
+
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+ pub fn adjust_fulfillment_error_for_expr_obligation(
+ &self,
+ error: &mut traits::FulfillmentError<'tcx>,
+ ) -> bool {
+ let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx))
+ = *error.obligation.cause.code().peel_derives() else { return false; };
+ let hir = self.tcx.hir();
+ let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; };
+
+ let Some(unsubstituted_pred) =
+ self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx)
+ else { return false; };
+
+ let generics = self.tcx.generics_of(def_id);
+ let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs,
+ ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs,
+ _ => ty::List::empty(),
+ };
+
+ let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| {
+ predicate_substs.types().find_map(|ty| {
+ ty.walk().find_map(|arg| {
+ if let ty::GenericArgKind::Type(ty) = arg.unpack()
+ && let ty::Param(param_ty) = ty.kind()
+ && matches(param_ty)
+ {
+ Some(arg)
+ } else {
+ None
+ }
+ })
+ })
+ };
+
+ // Prefer generics that are local to the fn item, since these are likely
+ // to be the cause of the unsatisfied predicate.
+ let mut param_to_point_at = find_param_matching(&|param_ty| {
+ self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id
+ });
+ // Fall back to generic that isn't local to the fn item. This will come
+ // from a trait or impl, for example.
+ let mut fallback_param_to_point_at = find_param_matching(&|param_ty| {
+ self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id
+ && param_ty.name != rustc_span::symbol::kw::SelfUpper
+ });
+ // Finally, the `Self` parameter is possibly the reason that the predicate
+ // is unsatisfied. This is less likely to be true for methods, because
+ // method probe means that we already kinda check that the predicates due
+ // to the `Self` type are true.
+ let mut self_param_to_point_at =
+ find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper);
+
+ // Finally, for ambiguity-related errors, we actually want to look
+ // for a parameter that is the source of the inference type left
+ // over in this predicate.
+ if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code {
+ fallback_param_to_point_at = None;
+ self_param_to_point_at = None;
+ param_to_point_at =
+ self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
+ }
+
+ if self.closure_span_overlaps_error(error, expr.span) {
+ return false;
+ }
+
+ match &expr.kind {
+ hir::ExprKind::Path(qpath) => {
+ if let hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Call(callee, args),
+ hir_id: call_hir_id,
+ span: call_span,
+ ..
+ }) = hir.get_parent(expr.hir_id)
+ && callee.hir_id == expr.hir_id
+ {
+ if self.closure_span_overlaps_error(error, *call_span) {
+ return false;
+ }
+
+ for param in
+ [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
+ .into_iter()
+ .flatten()
+ {
+ if self.blame_specific_arg_if_possible(
+ error,
+ def_id,
+ param,
+ *call_hir_id,
+ callee.span,
+ None,
+ args,
+ )
+ {
+ return true;
+ }
+ }
+ }
+ // Notably, we only point to params that are local to the
+ // item we're checking, since those are the ones we are able
+ // to look in the final `hir::PathSegment` for. Everything else
+ // would require a deeper search into the `qpath` than I think
+ // is worthwhile.
+ if let Some(param_to_point_at) = param_to_point_at
+ && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
+ {
+ return true;
+ }
+ }
+ hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
+ for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
+ .into_iter()
+ .flatten()
+ {
+ if self.blame_specific_arg_if_possible(
+ error,
+ def_id,
+ param,
+ hir_id,
+ segment.ident.span,
+ Some(receiver),
+ args,
+ ) {
+ return true;
+ }
+ }
+ if let Some(param_to_point_at) = param_to_point_at
+ && self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment)
+ {
+ return true;
+ }
+ }
+ hir::ExprKind::Struct(qpath, fields, ..) => {
+ if let Res::Def(
+ hir::def::DefKind::Struct | hir::def::DefKind::Variant,
+ variant_def_id,
+ ) = self.typeck_results.borrow().qpath_res(qpath, hir_id)
+ {
+ for param in
+ [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
+ {
+ if let Some(param) = param {
+ let refined_expr = self.point_at_field_if_possible(
+ def_id,
+ param,
+ variant_def_id,
+ fields,
+ );
+
+ match refined_expr {
+ None => {}
+ Some((refined_expr, _)) => {
+ error.obligation.cause.span = refined_expr
+ .span
+ .find_ancestor_in_same_ctxt(error.obligation.cause.span)
+ .unwrap_or(refined_expr.span);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ if let Some(param_to_point_at) = param_to_point_at
+ && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
+ {
+ return true;
+ }
+ }
+ _ => {}
+ }
+
+ false
+ }
+
+ fn point_at_path_if_possible(
+ &self,
+ error: &mut traits::FulfillmentError<'tcx>,
+ def_id: DefId,
+ param: ty::GenericArg<'tcx>,
+ qpath: &hir::QPath<'tcx>,
+ ) -> bool {
+ match qpath {
+ hir::QPath::Resolved(_, path) => {
+ if let Some(segment) = path.segments.last()
+ && self.point_at_generic_if_possible(error, def_id, param, segment)
+ {
+ return true;
+ }
+ }
+ hir::QPath::TypeRelative(_, segment) => {
+ if self.point_at_generic_if_possible(error, def_id, param, segment) {
+ return true;
+ }
+ }
+ _ => {}
+ }
+
+ false
+ }
+
+ fn point_at_generic_if_possible(
+ &self,
+ error: &mut traits::FulfillmentError<'tcx>,
+ def_id: DefId,
+ param_to_point_at: ty::GenericArg<'tcx>,
+ segment: &hir::PathSegment<'tcx>,
+ ) -> bool {
+ let own_substs = self
+ .tcx
+ .generics_of(def_id)
+ .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id));
+ let Some((index, _)) = own_substs
+ .iter()
+ .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
+ .enumerate()
+ .find(|(_, arg)| **arg == param_to_point_at) else { return false };
+ let Some(arg) = segment
+ .args()
+ .args
+ .iter()
+ .filter(|arg| matches!(arg, hir::GenericArg::Type(_)))
+ .nth(index) else { return false; };
+ error.obligation.cause.span = arg
+ .span()
+ .find_ancestor_in_same_ctxt(error.obligation.cause.span)
+ .unwrap_or(arg.span());
+ true
+ }
+
+ fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>(
+ &self,
+ item_def_id: DefId,
+ t: T,
+ ) -> Option<ty::GenericArg<'tcx>> {
+ struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId);
+ impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> {
+ type BreakTy = ty::GenericArg<'tcx>;
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
+ if let Some(origin) = self.0.type_var_origin(ty)
+ && let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) =
+ origin.kind
+ && let generics = self.0.tcx.generics_of(self.1)
+ && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
+ && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1)
+ .get(index as usize)
+ {
+ ControlFlow::Break(*subst)
+ } else {
+ ty.super_visit_with(self)
+ }
+ }
+ }
+ t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value()
+ }
+
+ fn closure_span_overlaps_error(
+ &self,
+ error: &traits::FulfillmentError<'tcx>,
+ span: Span,
+ ) -> bool {
+ if let traits::FulfillmentErrorCode::CodeSelectionError(
+ traits::SelectionError::OutputTypeParameterMismatch(_, expected, _),
+ ) = error.code
+ && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind()
+ && span.overlaps(self.tcx.def_span(*def_id))
+ {
+ true
+ } else {
+ false
+ }
+ }
+
+ fn point_at_field_if_possible(
+ &self,
+ def_id: DefId,
+ param_to_point_at: ty::GenericArg<'tcx>,
+ variant_def_id: DefId,
+ expr_fields: &[hir::ExprField<'tcx>],
+ ) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> {
+ let def = self.tcx.adt_def(def_id);
+
+ let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id);
+ let fields_referencing_param: Vec<_> = def
+ .variant_with_id(variant_def_id)
+ .fields
+ .iter()
+ .filter(|field| {
+ let field_ty = field.ty(self.tcx, identity_substs);
+ Self::find_param_in_ty(field_ty.into(), param_to_point_at)
+ })
+ .collect();
+
+ if let [field] = fields_referencing_param.as_slice() {
+ for expr_field in expr_fields {
+ // Look for the ExprField that matches the field, using the
+ // same rules that check_expr_struct uses for macro hygiene.
+ if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
+ {
+ return Some((expr_field.expr, self.tcx.type_of(field.did)));
+ }
+ }
+ }
+
+ None
+ }
+
+ /// - `blame_specific_*` means that the function will recursively traverse the expression,
+ /// looking for the most-specific-possible span to blame.
+ ///
+ /// - `point_at_*` means that the function will only go "one level", pointing at the specific
+ /// expression mentioned.
+ ///
+ /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside
+ /// the provided function call expression, and mark it as responsible for the fullfillment
+ /// error.
+ fn blame_specific_arg_if_possible(
+ &self,
+ error: &mut traits::FulfillmentError<'tcx>,
+ def_id: DefId,
+ param_to_point_at: ty::GenericArg<'tcx>,
+ call_hir_id: hir::HirId,
+ callee_span: Span,
+ receiver: Option<&'tcx hir::Expr<'tcx>>,
+ args: &'tcx [hir::Expr<'tcx>],
+ ) -> bool {
+ let ty = self.tcx.type_of(def_id);
+ if !ty.is_fn() {
+ return false;
+ }
+ let sig = ty.fn_sig(self.tcx).skip_binder();
+ let args_referencing_param: Vec<_> = sig
+ .inputs()
+ .iter()
+ .enumerate()
+ .filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at))
+ .collect();
+ // If there's one field that references the given generic, great!
+ if let [(idx, _)] = args_referencing_param.as_slice()
+ && let Some(arg) = receiver
+ .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
+
+ error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
+
+ if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) {
+ // This is more specific than pointing at the entire argument.
+ self.blame_specific_expr_if_possible(error, arg_expr)
+ }
+
+ error.obligation.cause.map_code(|parent_code| {
+ ObligationCauseCode::FunctionArgumentObligation {
+ arg_hir_id: arg.hir_id,
+ call_hir_id,
+ parent_code,
+ }
+ });
+ return true;
+ } else if args_referencing_param.len() > 0 {
+ // If more than one argument applies, then point to the callee span at least...
+ // We have chance to fix this up further in `point_at_generics_if_possible`
+ error.obligation.cause.span = callee_span;
+ }
+
+ false
+ }
+
/**
* Recursively searches for the most-specific blamable expression.
* For example, if you have a chain of constraints like:
use rustc_infer::infer::TypeTrace;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor};
+use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty};
use rustc_session::Session;
use rustc_span::symbol::{kw, Ident};
use rustc_span::{self, sym, Span};
use std::mem;
use std::slice;
-use std::ops::ControlFlow;
-
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(in super::super) fn check_casts(&mut self) {
// don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors
}
}
- fn adjust_fulfillment_error_for_expr_obligation(
- &self,
- error: &mut traits::FulfillmentError<'tcx>,
- ) -> bool {
- let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx))
- = *error.obligation.cause.code().peel_derives() else { return false; };
- let hir = self.tcx.hir();
- let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; };
-
- let Some(unsubstituted_pred) =
- self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx)
- else { return false; };
-
- let generics = self.tcx.generics_of(def_id);
- let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs,
- ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs,
- _ => ty::List::empty(),
- };
-
- let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| {
- predicate_substs.types().find_map(|ty| {
- ty.walk().find_map(|arg| {
- if let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Param(param_ty) = ty.kind()
- && matches(param_ty)
- {
- Some(arg)
- } else {
- None
- }
- })
- })
- };
-
- // Prefer generics that are local to the fn item, since these are likely
- // to be the cause of the unsatisfied predicate.
- let mut param_to_point_at = find_param_matching(&|param_ty| {
- self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id
- });
- // Fall back to generic that isn't local to the fn item. This will come
- // from a trait or impl, for example.
- let mut fallback_param_to_point_at = find_param_matching(&|param_ty| {
- self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id
- && param_ty.name != rustc_span::symbol::kw::SelfUpper
- });
- // Finally, the `Self` parameter is possibly the reason that the predicate
- // is unsatisfied. This is less likely to be true for methods, because
- // method probe means that we already kinda check that the predicates due
- // to the `Self` type are true.
- let mut self_param_to_point_at =
- find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper);
-
- // Finally, for ambiguity-related errors, we actually want to look
- // for a parameter that is the source of the inference type left
- // over in this predicate.
- if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code {
- fallback_param_to_point_at = None;
- self_param_to_point_at = None;
- param_to_point_at =
- self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
- }
-
- if self.closure_span_overlaps_error(error, expr.span) {
- return false;
- }
-
- match &expr.kind {
- hir::ExprKind::Path(qpath) => {
- if let hir::Node::Expr(hir::Expr {
- kind: hir::ExprKind::Call(callee, args),
- hir_id: call_hir_id,
- span: call_span,
- ..
- }) = hir.get_parent(expr.hir_id)
- && callee.hir_id == expr.hir_id
- {
- if self.closure_span_overlaps_error(error, *call_span) {
- return false;
- }
-
- for param in
- [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
- .into_iter()
- .flatten()
- {
- if self.blame_specific_arg_if_possible(
- error,
- def_id,
- param,
- *call_hir_id,
- callee.span,
- None,
- args,
- )
- {
- return true;
- }
- }
- }
- // Notably, we only point to params that are local to the
- // item we're checking, since those are the ones we are able
- // to look in the final `hir::PathSegment` for. Everything else
- // would require a deeper search into the `qpath` than I think
- // is worthwhile.
- if let Some(param_to_point_at) = param_to_point_at
- && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
- {
- return true;
- }
- }
- hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
- for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
- .into_iter()
- .flatten()
- {
- if self.blame_specific_arg_if_possible(
- error,
- def_id,
- param,
- hir_id,
- segment.ident.span,
- Some(receiver),
- args,
- ) {
- return true;
- }
- }
- if let Some(param_to_point_at) = param_to_point_at
- && self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment)
- {
- return true;
- }
- }
- hir::ExprKind::Struct(qpath, fields, ..) => {
- if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) =
- self.typeck_results.borrow().qpath_res(qpath, hir_id)
- {
- for param in
- [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
- {
- if let Some(param) = param {
- let refined_expr = self.point_at_field_if_possible(
- def_id,
- param,
- variant_def_id,
- fields,
- );
-
- match refined_expr {
- None => {}
- Some((refined_expr, _)) => {
- error.obligation.cause.span = refined_expr
- .span
- .find_ancestor_in_same_ctxt(error.obligation.cause.span)
- .unwrap_or(refined_expr.span);
- return true;
- }
- }
- }
- }
- }
- if let Some(param_to_point_at) = param_to_point_at
- && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
- {
- return true;
- }
- }
- _ => {}
- }
-
- false
- }
-
- fn closure_span_overlaps_error(
- &self,
- error: &traits::FulfillmentError<'tcx>,
- span: Span,
- ) -> bool {
- if let traits::FulfillmentErrorCode::CodeSelectionError(
- traits::SelectionError::OutputTypeParameterMismatch(_, expected, _),
- ) = error.code
- && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind()
- && span.overlaps(self.tcx.def_span(*def_id))
- {
- true
- } else {
- false
- }
- }
-
- /// - `blame_specific_*` means that the function will recursively traverse the expression,
- /// looking for the most-specific-possible span to blame.
- ///
- /// - `point_at_*` means that the function will only go "one level", pointing at the specific
- /// expression mentioned.
- ///
- /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside
- /// the provided function call expression, and mark it as responsible for the fullfillment
- /// error.
- fn blame_specific_arg_if_possible(
- &self,
- error: &mut traits::FulfillmentError<'tcx>,
- def_id: DefId,
- param_to_point_at: ty::GenericArg<'tcx>,
- call_hir_id: hir::HirId,
- callee_span: Span,
- receiver: Option<&'tcx hir::Expr<'tcx>>,
- args: &'tcx [hir::Expr<'tcx>],
- ) -> bool {
- let ty = self.tcx.type_of(def_id);
- if !ty.is_fn() {
- return false;
- }
- let sig = ty.fn_sig(self.tcx).skip_binder();
- let args_referencing_param: Vec<_> = sig
- .inputs()
- .iter()
- .enumerate()
- .filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at))
- .collect();
- // If there's one field that references the given generic, great!
- if let [(idx, _)] = args_referencing_param.as_slice()
- && let Some(arg) = receiver
- .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
-
- error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
-
- if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) {
- // This is more specific than pointing at the entire argument.
- self.blame_specific_expr_if_possible(error, arg_expr)
- }
-
- error.obligation.cause.map_code(|parent_code| {
- ObligationCauseCode::FunctionArgumentObligation {
- arg_hir_id: arg.hir_id,
- call_hir_id,
- parent_code,
- }
- });
- return true;
- } else if args_referencing_param.len() > 0 {
- // If more than one argument applies, then point to the callee span at least...
- // We have chance to fix this up further in `point_at_generics_if_possible`
- error.obligation.cause.span = callee_span;
- }
-
- false
- }
-
- // FIXME: Make this private and move to mod adjust_fulfillment_errors
- pub fn point_at_field_if_possible(
- &self,
- def_id: DefId,
- param_to_point_at: ty::GenericArg<'tcx>,
- variant_def_id: DefId,
- expr_fields: &[hir::ExprField<'tcx>],
- ) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> {
- let def = self.tcx.adt_def(def_id);
-
- let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id);
- let fields_referencing_param: Vec<_> = def
- .variant_with_id(variant_def_id)
- .fields
- .iter()
- .filter(|field| {
- let field_ty = field.ty(self.tcx, identity_substs);
- Self::find_param_in_ty(field_ty.into(), param_to_point_at)
- })
- .collect();
-
- if let [field] = fields_referencing_param.as_slice() {
- for expr_field in expr_fields {
- // Look for the ExprField that matches the field, using the
- // same rules that check_expr_struct uses for macro hygiene.
- if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
- {
- return Some((expr_field.expr, self.tcx.type_of(field.did)));
- }
- }
- }
-
- None
- }
-
- fn point_at_path_if_possible(
- &self,
- error: &mut traits::FulfillmentError<'tcx>,
- def_id: DefId,
- param: ty::GenericArg<'tcx>,
- qpath: &QPath<'tcx>,
- ) -> bool {
- match qpath {
- hir::QPath::Resolved(_, path) => {
- if let Some(segment) = path.segments.last()
- && self.point_at_generic_if_possible(error, def_id, param, segment)
- {
- return true;
- }
- }
- hir::QPath::TypeRelative(_, segment) => {
- if self.point_at_generic_if_possible(error, def_id, param, segment) {
- return true;
- }
- }
- _ => {}
- }
-
- false
- }
-
- fn point_at_generic_if_possible(
- &self,
- error: &mut traits::FulfillmentError<'tcx>,
- def_id: DefId,
- param_to_point_at: ty::GenericArg<'tcx>,
- segment: &hir::PathSegment<'tcx>,
- ) -> bool {
- let own_substs = self
- .tcx
- .generics_of(def_id)
- .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id));
- let Some((index, _)) = own_substs
- .iter()
- .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
- .enumerate()
- .find(|(_, arg)| **arg == param_to_point_at) else { return false };
- let Some(arg) = segment
- .args()
- .args
- .iter()
- .filter(|arg| matches!(arg, hir::GenericArg::Type(_)))
- .nth(index) else { return false; };
- error.obligation.cause.span = arg
- .span()
- .find_ancestor_in_same_ctxt(error.obligation.cause.span)
- .unwrap_or(arg.span());
- true
- }
-
- fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>(
- &self,
- item_def_id: DefId,
- t: T,
- ) -> Option<ty::GenericArg<'tcx>> {
- struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId);
- impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> {
- type BreakTy = ty::GenericArg<'tcx>;
- fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
- if let Some(origin) = self.0.type_var_origin(ty)
- && let TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) =
- origin.kind
- && let generics = self.0.tcx.generics_of(self.1)
- && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
- && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1)
- .get(index as usize)
- {
- ControlFlow::Break(*subst)
- } else {
- ty.super_visit_with(self)
- }
- }
- }
- t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value()
- }
-
fn label_fn_like(
&self,
err: &mut Diagnostic,
hir::Path { segments: [segment], .. },
))
| hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) => {
- let self_ty = self.astconv().ast_ty_to_ty(ty);
- if let Ok(pick) = self.probe_for_name(
- Mode::Path,
- Ident::new(capitalized_name, segment.ident.span),
- Some(expected_ty),
- IsSuggestion(true),
- self_ty,
- expr.hir_id,
- ProbeScope::TraitsInScope,
- ) {
+ if let Some(self_ty) = self.typeck_results.borrow().node_type_opt(ty.hir_id)
+ && let Ok(pick) = self.probe_for_name(
+ Mode::Path,
+ Ident::new(capitalized_name, segment.ident.span),
+ Some(expected_ty),
+ IsSuggestion(true),
+ self_ty,
+ expr.hir_id,
+ ProbeScope::TraitsInScope,
+ )
+ {
(pick.item, segment)
} else {
return false;
generics,
diag,
vec![(param.name.as_str(), "Clone", Some(clone_trait_did))].into_iter(),
+ None,
);
} else {
self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]);
(GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => {
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
if v_o != v_r {
- output_query_region_constraints.outlives.push((
- ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)),
- constraint_category,
- ));
- output_query_region_constraints.outlives.push((
- ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)),
- constraint_category,
- ));
+ output_query_region_constraints
+ .outlives
+ .push((ty::OutlivesPredicate(v_o.into(), v_r), constraint_category));
+ output_query_region_constraints
+ .outlives
+ .push((ty::OutlivesPredicate(v_r.into(), v_o), constraint_category));
}
}
query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| {
let r_c = substitute_value(self.tcx, &result_subst, r_c);
- // Screen out `'a: 'a` cases -- we skip the binder here but
- // only compare the inner values to one another, so they are still at
- // consistent binding levels.
- let ty::OutlivesPredicate(k1, r2) = r_c.0.skip_binder();
+ // Screen out `'a: 'a` cases.
+ let ty::OutlivesPredicate(k1, r2) = r_c.0;
if k1 != r2.into() { Some(r_c) } else { None }
}),
);
pub fn query_outlives_constraint_to_obligation(
&self,
- predicate: QueryOutlivesConstraint<'tcx>,
+ (predicate, _): QueryOutlivesConstraint<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Obligation<'tcx, ty::Predicate<'tcx>> {
- let ty::OutlivesPredicate(k1, r2) = predicate.0.skip_binder();
+ let ty::OutlivesPredicate(k1, r2) = predicate;
let atom = match k1.unpack() {
GenericArgKind::Lifetime(r1) => {
span_bug!(cause.span, "unexpected const outlives {:?}", predicate);
}
};
- let predicate = predicate.0.rebind(atom);
+ let predicate = ty::Binder::dummy(atom);
Obligation::new(self.tcx, cause, param_env, predicate)
}
let outlives: Vec<_> = constraints
.iter()
.map(|(k, origin)| {
- // no bound vars in the code above
- let constraint = ty::Binder::dummy(match *k {
+ let constraint = match *k {
// Swap regions because we are going from sub (<=) to outlives
// (>=).
Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
}
Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
- });
+ };
(constraint, origin.to_constraint_category())
})
- .chain(
- outlives_obligations
- // no bound vars in the code above
- .map(|(ty, r, constraint_category)| {
- (ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), r)), constraint_category)
- }),
- )
+ .chain(outlives_obligations.map(|(ty, r, constraint_category)| {
+ (ty::OutlivesPredicate(ty.into(), r), constraint_category)
+ }))
.collect();
QueryRegionConstraints { outlives, member_constraints: member_constraints.clone() }
(ty::Uint(ty::UintTy::U8), ty::Char) => {
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
&& let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
- && code.chars().next().map_or(false, |c| c.is_ascii())
+ && !code.starts_with("\\u") // forbid all Unicode escapes
+ && code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
{
err.span_suggestion(
span,
(ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
if tcx.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder =>
{
- let generics = tcx.generics_of(body_owner_def_id);
- let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
+ let p_def_id = tcx
+ .generics_of(body_owner_def_id)
+ .type_param(p, tcx)
+ .def_id;
+ let p_span = tcx.def_span(p_def_id);
if !sp.contains(p_span) {
diag.span_label(p_span, "this type parameter");
}
let hir = tcx.hir();
let mut note = true;
- if let Some(generics) = generics
- .type_param(p, tcx)
- .def_id
+ let parent = p_def_id
.as_local()
- .map(|id| hir.local_def_id_to_hir_id(id))
- .and_then(|id| tcx.hir().find_parent(id))
- .as_ref()
- .and_then(|node| node.generics())
+ .and_then(|id| {
+ let local_id = hir.local_def_id_to_hir_id(id);
+ let generics = tcx.hir().find_parent(local_id)?.generics()?;
+ Some((id, generics))
+ });
+ if let Some((local_id, generics)) = parent
{
// Synthesize the associated type restriction `Add<Output = Expected>`.
// FIXME: extract this logic for use in other diagnostics.
let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(tcx);
- let path =
- tcx.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
let item_name = tcx.item_name(proj.def_id);
let item_args = self.format_generic_args(assoc_substs);
- let path = if path.ends_with('>') {
- format!(
- "{}, {}{} = {}>",
- &path[..path.len() - 1],
- item_name,
- item_args,
- p
- )
+ // Here, we try to see if there's an existing
+ // trait implementation that matches the one that
+ // we're suggesting to restrict. If so, find the
+ // "end", whether it be at the end of the trait
+ // or the end of the generic arguments.
+ let mut matching_span = None;
+ let mut matched_end_of_args = false;
+ for bound in generics.bounds_for_param(local_id) {
+ let potential_spans = bound
+ .bounds
+ .iter()
+ .find_map(|bound| {
+ let bound_trait_path = bound.trait_ref()?.path;
+ let def_id = bound_trait_path.res.opt_def_id()?;
+ let generic_args = bound_trait_path.segments.iter().last().map(|path| path.args());
+ (def_id == trait_ref.def_id).then_some((bound_trait_path.span, generic_args))
+ });
+
+ if let Some((end_of_trait, end_of_args)) = potential_spans {
+ let args_span = end_of_args.and_then(|args| args.span());
+ matched_end_of_args = args_span.is_some();
+ matching_span = args_span
+ .or_else(|| Some(end_of_trait))
+ .map(|span| span.shrink_to_hi());
+ break;
+ }
+ }
+
+ if matched_end_of_args {
+ // Append suggestion to the end of our args
+ let path = format!(", {}{} = {}",item_name, item_args, p);
+ note = !suggest_constraining_type_param(
+ tcx,
+ generics,
+ diag,
+ &format!("{}", proj.self_ty()),
+ &path,
+ None,
+ matching_span,
+ );
} else {
- format!("{}<{}{} = {}>", path, item_name, item_args, p)
- };
- note = !suggest_constraining_type_param(
- tcx,
- generics,
- diag,
- &format!("{}", proj.self_ty()),
- &path,
- None,
- );
+ // Suggest adding a bound to an existing trait
+ // or if the trait doesn't exist, add the trait
+ // and the suggested bounds.
+ let path = format!("<{}{} = {}>", item_name, item_args, p);
+ note = !suggest_constraining_type_param(
+ tcx,
+ generics,
+ diag,
+ &format!("{}", proj.self_ty()),
+ &path,
+ None,
+ matching_span,
+ );
+ }
}
if note {
diag.note("you might be missing a type parameter or trait bound");
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/Lint.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/Linker/Linker.h"
+#if LLVM_VERSION_GE(16, 0)
+#include "llvm/TargetParser/Triple.h"
+#else
+#include "llvm/ADT/Triple.h"
+#endif
+
extern "C" void LLVMRustSetLastError(const char *);
enum class LLVMRustResult { Success, Failure };
for (_, other) in self.cstore.iter_crate_data() {
// Same stable crate id but different SVH
if other.stable_crate_id() == root.stable_crate_id() && other.hash() != root.hash() {
- return Err(CrateError::SymbolConflictsOthers(root.name()));
+ bug!(
+ "Previously returned E0523 here. \
+ See https://github.com/rust-lang/rust/pull/100599 for additional discussion.\
+ root.name() = {}.",
+ root.name()
+ );
}
}
pub crate_name: Symbol,
}
-#[derive(Diagnostic)]
-#[diag(metadata_symbol_conflicts_others, code = "E0523")]
-pub struct SymbolConflictsOthers {
- #[primary_span]
- pub span: Span,
- pub crate_name: Symbol,
-}
-
#[derive(Diagnostic)]
#[diag(metadata_stable_crate_id_collision)]
pub struct StableCrateIdCollision {
ExternLocationNotFile(Symbol, PathBuf),
MultipleCandidates(Symbol, CrateFlavor, Vec<PathBuf>),
SymbolConflictsCurrent(Symbol),
- SymbolConflictsOthers(Symbol),
StableCrateIdCollision(Symbol, Symbol),
DlOpen(String),
DlSym(String),
CrateError::SymbolConflictsCurrent(root_name) => {
sess.emit_err(errors::SymbolConflictsCurrent { span, crate_name: root_name });
}
- CrateError::SymbolConflictsOthers(root_name) => {
- sess.emit_err(errors::SymbolConflictsOthers { span, crate_name: root_name });
- }
CrateError::StableCrateIdCollision(crate_name0, crate_name1) => {
sess.emit_err(errors::StableCrateIdCollision { span, crate_name0, crate_name1 });
}
}
}
-pub type QueryOutlivesConstraint<'tcx> = (
- ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>,
- ConstraintCategory<'tcx>,
-);
+pub type QueryOutlivesConstraint<'tcx> =
+ (ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
TrivialTypeTraversalAndLiftImpls! {
for <'tcx> {
///
/// The exact limit is set by the `const_eval_limit` attribute.
StepLimitReached,
- /// There is not enough memory to perform an allocation.
+ /// There is not enough memory (on the host) to perform an allocation.
MemoryExhausted,
+ /// The address space (of the target) is full.
+ AddressSpaceFull,
}
impl fmt::Display for ResourceExhaustionInfo {
MemoryExhausted => {
write!(f, "tried to allocate more memory than available to compiler")
}
+ AddressSpaceFull => {
+ write!(f, "there are no more free addresses in the address space")
+ }
}
}
}
query upstream_monomorphizations_for(def_id: DefId)
-> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>>
{
- arena_cache
desc { |tcx|
"collecting available upstream monomorphizations for `{}`",
tcx.def_path_str(def_id),
}
/// Suggest restricting a type param with a new bound.
+///
+/// If `span_to_replace` is provided, then that span will be replaced with the
+/// `constraint`. If one wasn't provided, then the full bound will be suggested.
pub fn suggest_constraining_type_param(
tcx: TyCtxt<'_>,
generics: &hir::Generics<'_>,
param_name: &str,
constraint: &str,
def_id: Option<DefId>,
+ span_to_replace: Option<Span>,
) -> bool {
suggest_constraining_type_params(
tcx,
generics,
err,
[(param_name, constraint, def_id)].into_iter(),
+ span_to_replace,
)
}
generics: &hir::Generics<'_>,
err: &mut Diagnostic,
param_names_and_constraints: impl Iterator<Item = (&'a str, &'a str, Option<DefId>)>,
+ span_to_replace: Option<Span>,
) -> bool {
let mut grouped = FxHashMap::default();
param_names_and_constraints.for_each(|(param_name, constraint, def_id)| {
let mut suggest_restrict = |span, bound_list_non_empty| {
suggestions.push((
span,
- if bound_list_non_empty {
+ if span_to_replace.is_some() {
+ constraint.clone()
+ } else if bound_list_non_empty {
format!(" + {}", constraint)
} else {
format!(" {}", constraint)
))
};
+ if let Some(span) = span_to_replace {
+ suggest_restrict(span, true);
+ continue;
+ }
+
// When the type parameter has been provided bounds
//
// Message:
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
if let Operand::Move(place) = *operand
- && let Some(local) = place.as_local()
- && !self.fully_moved.contains(local)
+ // A move out of a projection of a copy is equivalent to a copy of the original projection.
+ && !place.has_deref()
+ && !self.fully_moved.contains(place.local)
{
*operand = Operand::Copy(place);
}
}
impl From<DepNodeIndex> for QueryInvocationId {
- #[inline]
+ #[inline(always)]
fn from(dep_node_index: DepNodeIndex) -> Self {
QueryInvocationId(dep_node_index.as_u32())
}
{
match cache.lookup(&key) {
Some((value, index)) => {
- if std::intrinsics::unlikely(tcx.profiler().enabled()) {
- tcx.profiler().query_cache_hit(index.into());
- }
+ tcx.profiler().query_cache_hit(index.into());
tcx.dep_graph().read_index(index);
Some(value)
}
panic!("value must be in cache after waiting")
};
- if std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) {
- qcx.dep_context().profiler().query_cache_hit(index.into());
- }
+ qcx.dep_context().profiler().query_cache_hit(index.into());
query_blocked_prof_timer.finish_with_query_invocation_id(index.into());
(v, Some(index))
// Ensure that only one of them runs the query.
let cache = Q::query_cache(qcx);
if let Some((_, index)) = cache.lookup(&key) {
- if std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) {
- qcx.dep_context().profiler().query_cache_hit(index.into());
- }
+ qcx.dep_context().profiler().query_cache_hit(index.into());
return;
}
plugins,
pointee_trait,
pointer,
- pointer_sized,
+ pointer_like,
poll,
position,
post_dash_lto: "post-lto",
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
- // A type is `PointerSized` if we can compute its layout, and that layout
+ // A type is `PointerLike` if we can compute its layout, and that layout
// matches the layout of `usize`.
- fn consider_builtin_pointer_sized_candidate(
+ fn consider_builtin_pointer_like_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
|| lang_items.clone_trait() == Some(trait_def_id)
{
G::consider_builtin_copy_clone_candidate(self, goal)
- } else if lang_items.pointer_sized() == Some(trait_def_id) {
- G::consider_builtin_pointer_sized_candidate(self, goal)
+ } else if lang_items.pointer_like() == Some(trait_def_id) {
+ G::consider_builtin_pointer_like_candidate(self, goal)
} else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) {
G::consider_builtin_fn_trait_candidates(self, goal, kind)
} else if lang_items.tuple_trait() == Some(trait_def_id) {
bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
}
- fn consider_builtin_pointer_sized_candidate(
+ fn consider_builtin_pointer_like_candidate(
_ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
- bug!("`PointerSized` does not have an associated type: {:?}", goal);
+ bug!("`PointerLike` does not have an associated type: {:?}", goal);
}
fn consider_builtin_fn_trait_candidates(
)
}
- fn consider_builtin_pointer_sized_candidate(
+ fn consider_builtin_pointer_like_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
¶m_name,
&constraint,
Some(trait_pred.def_id()),
+ None,
) {
return;
}
param.name.as_str(),
"Clone",
Some(clone_trait),
+ None,
);
}
err.span_suggestion_verbose(
self.assemble_candidates_for_transmutability(obligation, &mut candidates);
} else if lang_items.tuple_trait() == Some(def_id) {
self.assemble_candidate_for_tuple(obligation, &mut candidates);
- } else if lang_items.pointer_sized() == Some(def_id) {
+ } else if lang_items.pointer_like() == Some(def_id) {
self.assemble_candidate_for_ptr_sized(obligation, &mut candidates);
} else {
if lang_items.clone_trait() == Some(def_id) {
// which is different from how types/const are freshened.
| TypeFlags::HAS_TY_FRESH.bits
| TypeFlags::HAS_CT_FRESH.bits
- | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
+ | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits
+ | TypeFlags::HAS_RE_ERASED.bits;
/// Does this have `Projection`?
const HAS_TY_PROJECTION = 1 << 10;
/// Copies elements from `src` range to the end of the string.
///
- /// ## Panics
+ /// # Panics
///
/// Panics if the starting point or end point do not lie on a [`char`]
/// boundary, or if they're out of bounds.
///
- /// ## Examples
+ /// # Examples
///
/// ```
/// #![feature(string_extend_from_within)]
pub trait Tuple {}
/// A marker for things
-#[unstable(feature = "pointer_sized_trait", issue = "none")]
-#[lang = "pointer_sized"]
+#[unstable(feature = "pointer_like_trait", issue = "none")]
+#[cfg_attr(bootstrap, lang = "pointer_sized")]
+#[cfg_attr(not(bootstrap), lang = "pointer_like")]
#[rustc_on_unimplemented(
- message = "`{Self}` needs to be a pointer-sized type",
- label = "`{Self}` needs to be a pointer-sized type"
+ message = "`{Self}` needs to have the same alignment and size as a pointer",
+ label = "`{Self}` needs to be a pointer-like type"
)]
-pub trait PointerSized {}
+pub trait PointerLike {}
/// Implementations of `Copy` for primitive types.
///
/// ```
#[inline]
#[unstable(feature = "atomic_mut_ptr", reason = "recently added", issue = "66893")]
- pub fn as_mut_ptr(&self) -> *mut bool {
- self.v.get() as *mut bool
+ pub const fn as_mut_ptr(&self) -> *mut bool {
+ self.v.get().cast()
}
/// Fetches the value, and applies a function to it that returns an optional
///
/// ```ignore (extern-declaration)
/// #![feature(atomic_mut_ptr)]
- //// use std::sync::atomic::AtomicPtr;
+ /// use std::sync::atomic::AtomicPtr;
///
/// extern "C" {
/// fn my_atomic_op(arg: *mut *mut u32);
/// ```
#[inline]
#[unstable(feature = "atomic_mut_ptr", reason = "recently added", issue = "66893")]
- pub fn as_mut_ptr(&self) -> *mut *mut T {
+ pub const fn as_mut_ptr(&self) -> *mut *mut T {
self.p.get()
}
}
#[unstable(feature = "atomic_mut_ptr",
reason = "recently added",
issue = "66893")]
- pub fn as_mut_ptr(&self) -> *mut $int_type {
+ pub const fn as_mut_ptr(&self) -> *mut $int_type {
self.v.get()
}
}
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::Config;
use crate::{t, VERSION};
+use sha2::Digest;
use std::env::consts::EXE_SUFFIX;
use std::fmt::Write as _;
use std::fs::File;
use std::str::FromStr;
use std::{fmt, fs, io};
+#[cfg(test)]
+mod tests;
+
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum Profile {
Compiler,
User,
}
+/// A list of historical hashes of `src/etc/vscode_settings.json`.
+/// New entries should be appended whenever this is updated so we can detected
+/// outdated vs. user-modified settings files.
+static SETTINGS_HASHES: &[&str] =
+ &["ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8"];
+static VSCODE_SETTINGS: &str = include_str!("../etc/vscode_settings.json");
+
impl Profile {
fn include_path(&self, src_path: &Path) -> PathBuf {
PathBuf::from(format!("{}/src/bootstrap/defaults/config.{}.toml", src_path.display(), self))
if !config.dry_run() {
t!(install_git_hook_maybe(&config));
+ t!(create_vscode_settings_maybe(&config));
}
println!();
Ok(template)
}
+#[derive(PartialEq)]
+enum PromptResult {
+ Yes, // y/Y/yes
+ No, // n/N/no
+ Print, // p/P/print
+}
+
+/// Prompt a user for a answer, looping until they enter an accepted input or nothing
+fn prompt_user(prompt: &str) -> io::Result<Option<PromptResult>> {
+ let mut input = String::new();
+ loop {
+ print!("{prompt} ");
+ io::stdout().flush()?;
+ input.clear();
+ io::stdin().read_line(&mut input)?;
+ match input.trim().to_lowercase().as_str() {
+ "y" | "yes" => return Ok(Some(PromptResult::Yes)),
+ "n" | "no" => return Ok(Some(PromptResult::No)),
+ "p" | "print" => return Ok(Some(PromptResult::Print)),
+ "" => return Ok(None),
+ _ => {
+ eprintln!("error: unrecognized option '{}'", input.trim());
+ eprintln!("note: press Ctrl+C to exit");
+ }
+ };
+ }
+}
+
// install a git hook to automatically run tidy, if they want
fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
let git = t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
return Ok(());
}
- let mut input = String::new();
- println!();
println!(
- "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
+ "\nRust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
If you'd like, x.py can install a git hook for you that will automatically run `test tidy` before
pushing your code to ensure your code is up to par. If you decide later that this behavior is
undesirable, simply delete the `pre-push` file from .git/hooks."
);
- let should_install = loop {
- print!("Would you like to install the git hook?: [y/N] ");
- io::stdout().flush()?;
- input.clear();
- io::stdin().read_line(&mut input)?;
- break match input.trim().to_lowercase().as_str() {
- "y" | "yes" => true,
- "n" | "no" | "" => false,
- _ => {
- eprintln!("error: unrecognized option '{}'", input.trim());
- eprintln!("note: press Ctrl+C to exit");
- continue;
- }
- };
- };
-
- if should_install {
- let src = config.src.join("src").join("etc").join("pre-push.sh");
- match fs::hard_link(src, &dst) {
- Err(e) => eprintln!(
+ if prompt_user("Would you like to install the git hook?: [y/N]")? != Some(PromptResult::Yes) {
+ println!("Ok, skipping installation!");
+ return Ok(());
+ }
+ let src = config.src.join("src").join("etc").join("pre-push.sh");
+ match fs::hard_link(src, &dst) {
+ Err(e) => {
+ eprintln!(
"error: could not create hook {}: do you already have the git hook installed?\n{}",
dst.display(),
e
- ),
- Ok(_) => println!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"),
+ );
+ return Err(e);
+ }
+ Ok(_) => println!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"),
+ };
+ Ok(())
+}
+
+/// Create a `.vscode/settings.json` file for rustc development, or just print it
+fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> {
+ let (current_hash, historical_hashes) = SETTINGS_HASHES.split_last().unwrap();
+ let vscode_settings = config.src.join(".vscode").join("settings.json");
+ // If None, no settings.json exists
+ // If Some(true), is a previous version of settings.json
+ // If Some(false), is not a previous version (i.e. user modified)
+ // If it's up to date we can just skip this
+ let mut mismatched_settings = None;
+ if let Ok(current) = fs::read_to_string(&vscode_settings) {
+ let mut hasher = sha2::Sha256::new();
+ hasher.update(¤t);
+ let hash = hex::encode(hasher.finalize().as_slice());
+ if hash == *current_hash {
+ return Ok(());
+ } else if historical_hashes.contains(&hash.as_str()) {
+ mismatched_settings = Some(true);
+ } else {
+ mismatched_settings = Some(false);
+ }
+ }
+ println!(
+ "\nx.py can automatically install the recommended `.vscode/settings.json` file for rustc development"
+ );
+ match mismatched_settings {
+ Some(true) => eprintln!(
+ "warning: existing `.vscode/settings.json` is out of date, x.py will update it"
+ ),
+ Some(false) => eprintln!(
+ "warning: existing `.vscode/settings.json` has been modified by user, x.py will back it up and replace it"
+ ),
+ _ => (),
+ }
+ let should_create = match prompt_user(
+ "Would you like to create/update `settings.json`, or only print suggested settings?: [y/p/N]",
+ )? {
+ Some(PromptResult::Yes) => true,
+ Some(PromptResult::Print) => false,
+ _ => {
+ println!("Ok, skipping settings!");
+ return Ok(());
+ }
+ };
+ if should_create {
+ let path = config.src.join(".vscode");
+ if !path.exists() {
+ fs::create_dir(&path)?;
+ }
+ let verb = match mismatched_settings {
+ // exists but outdated, we can replace this
+ Some(true) => "Updated",
+ // exists but user modified, back it up
+ Some(false) => {
+ // exists and is not current version or outdated, so back it up
+ let mut backup = vscode_settings.clone();
+ backup.set_extension("bak");
+ eprintln!("warning: copying `settings.json` to `settings.json.bak`");
+ fs::copy(&vscode_settings, &backup)?;
+ "Updated"
+ }
+ _ => "Created",
};
+ fs::write(&vscode_settings, &VSCODE_SETTINGS)?;
+ println!("{verb} `.vscode/settings.json`");
} else {
- println!("Ok, skipping installation!");
+ println!("\n{VSCODE_SETTINGS}");
}
Ok(())
}
--- /dev/null
+use super::{SETTINGS_HASHES, VSCODE_SETTINGS};
+use sha2::Digest;
+
+#[test]
+fn check_matching_settings_hash() {
+ let mut hasher = sha2::Sha256::new();
+ hasher.update(&VSCODE_SETTINGS);
+ let hash = hex::encode(hasher.finalize().as_slice());
+ assert_eq!(
+ &hash,
+ SETTINGS_HASHES.last().unwrap(),
+ "Update `SETTINGS_HASHES` with the new hash of `src/etc/vscode_settings.json`"
+ );
+}
- name: x86_64-gnu-tools
<<: *job-linux-xl
tidy: false
- env:
- CI_ONLY_WHEN_SUBMODULES_CHANGED: 1
auto:
permissions:
#!/bin/bash
-# Set the SKIP_JOB environment variable if this job is supposed to only run
-# when submodules are updated and they were not. The following time consuming
-# tasks will be skipped when the environment variable is present.
+# Set the SKIP_JOB environment variable if this job is not supposed to run on the current builder.
set -euo pipefail
IFS=$'\n\t'
source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
-if [[ -n "${CI_ONLY_WHEN_SUBMODULES_CHANGED-}" ]]; then
- git fetch "https://github.com/$GITHUB_REPOSITORY" "$GITHUB_BASE_REF"
- BASE_COMMIT="$(git merge-base FETCH_HEAD HEAD)"
-
- echo "Searching for toolstate changes between $BASE_COMMIT and $(git rev-parse HEAD)"
-
- if git diff "$BASE_COMMIT" | grep --quiet "^index .* 160000"; then
- # Submodules pseudo-files inside git have the 160000 permissions, so when
- # those files are present in the diff a submodule was updated.
- echo "Submodules were updated"
- elif ! (git diff --quiet "$BASE_COMMIT" -- \
- src/tools/clippy src/tools/rustfmt src/tools/miri \
- library/std/src/sys); then
- # There is not an easy blanket search for subtrees. For now, manually list
- # the subtrees.
- # Also run this when the platform-specific parts of std change, in case
- # that breaks Miri.
- echo "Tool subtrees were updated"
- elif ! (git diff --quiet "$BASE_COMMIT" -- \
- tests/rustdoc-gui \
- src/librustdoc \
- src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile \
- src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version \
- src/tools/rustdoc-gui); then
- # There was a change in either rustdoc or in its GUI tests.
- echo "Rustdoc was updated"
- else
- echo "Not executing this job since no submodules nor subtrees were updated"
- ciCommandSetEnv SKIP_JOB 1
- exit 0
- fi
-fi
-
if [[ -n "${CI_ONLY_WHEN_CHANNEL-}" ]]; then
if [[ "${CI_ONLY_WHEN_CHANNEL}" = "$(cat src/ci/channel)" ]]; then
echo "The channel is the expected one"
[output.html]
git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustc"
+edit-url-template = "https://github.com/rust-lang/rust/edit/master/src/doc/rustc/{path}"
* `v0` — The "v0" mangling scheme. The specific format is not specified at
this time.
-The default if not specified will use a compiler-chosen default which may
+The default, if not specified, will use a compiler-chosen default which may
change in the future.
[name mangling]: https://en.wikipedia.org/wiki/Name_mangling
--- /dev/null
+{
+ "rust-analyzer.checkOnSave.overrideCommand": [
+ "python3",
+ "x.py",
+ "check",
+ "--json-output"
+ ],
+ "rust-analyzer.linkedProjects": ["src/bootstrap/Cargo.toml", "Cargo.toml"],
+ "rust-analyzer.rustfmt.overrideCommand": [
+ "./build/host/rustfmt/bin/rustfmt",
+ "--edition=2021"
+ ],
+ "rust-analyzer.procMacro.server": "./build/host/stage0/libexec/rust-analyzer-proc-macro-srv",
+ "rust-analyzer.procMacro.enable": true,
+ "rust-analyzer.cargo.buildScripts.enable": true,
+ "rust-analyzer.cargo.buildScripts.invocationLocation": "root",
+ "rust-analyzer.cargo.buildScripts.invocationStrategy": "once",
+ "rust-analyzer.cargo.buildScripts.overrideCommand": [
+ "python3",
+ "x.py",
+ "check",
+ "--json-output"
+ ],
+ "rust-analyzer.cargo.sysroot": "./build/host/stage0-sysroot",
+ "rust-analyzer.rustc.source": "./Cargo.toml"
+}
if f.alternate() {
f.write_str(" ")?;
} else {
- f.write_str("<br>")?;
+ f.write_str("\n")?;
}
match pred {
}
} else {
let mut br_with_padding = String::with_capacity(6 * indent + 28);
- br_with_padding.push_str("<br>");
+ br_with_padding.push_str("\n");
let padding_amout =
if ending == Ending::Newline { indent + 4 } else { indent + "fn where ".len() };
for _ in 0..padding_amout {
br_with_padding.push_str(" ");
}
- let where_preds = where_preds.to_string().replace("<br>", &br_with_padding);
+ let where_preds = where_preds.to_string().replace("\n", &br_with_padding);
if ending == Ending::Newline {
let mut clause = " ".repeat(indent.saturating_sub(1));
write!(clause, "<span class=\"where fmt-newline\">where{where_preds},</span>")?;
clause
} else {
- // insert a <br> tag after a single space but before multiple spaces at the start
+ // insert a newline after a single space but before multiple spaces at the start
if indent == 0 {
- format!("<br><span class=\"where\">where{where_preds}</span>")
+ format!("\n<span class=\"where\">where{where_preds}</span>")
} else {
// put the first one on the same line as the 'where' keyword
let where_preds = where_preds.replacen(&br_with_padding, " ", 1);
/// * `header_len`: The length of the function header and name. In other words, the number of
/// characters in the function declaration up to but not including the parentheses.
- /// <br>Used to determine line-wrapping.
+ /// This is expected to go into a `<pre>`/`code-header` block, so indentation and newlines
+ /// are preserved.
/// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is
/// necessary.
pub(crate) fn full_print<'a, 'tcx: 'a>(
}
} else {
if i > 0 {
- args.push_str("<br>");
+ args.push_str("\n");
}
if input.is_const {
args.push_str("const ");
let mut args = args.into_inner();
if self.c_variadic {
- args.push_str(",<br> ...");
+ args.push_str(",\n ...");
args_plain.push_str(", ...");
}
let declaration_len = header_len + args_plain.len() + arrow_plain.len();
let output = if declaration_len > 80 {
- let full_pad = format!("<br>{}", " ".repeat(indent + 4));
- let close_pad = format!("<br>{}", " ".repeat(indent));
+ let full_pad = format!("\n{}", " ".repeat(indent + 4));
+ let close_pad = format!("\n{}", " ".repeat(indent));
format!(
"({pad}{args}{close}){arrow}",
pad = if self.inputs.values.is_empty() { "" } else { &full_pad },
- args = args.replace("<br>", &full_pad),
+ args = args.replace("\n", &full_pad),
close = close_pad,
arrow = arrow
)
} else {
- format!("({args}){arrow}", args = args.replace("<br>", " "), arrow = arrow)
+ format!("({args}){arrow}", args = args.replace("\n", " "), arrow = arrow)
};
- if f.alternate() {
- write!(f, "{}", output.replace("<br>", "\n"))
- } else {
- write!(f, "{}", output)
- }
+ write!(f, "{}", output)
}
}
{%- for theme in themes -%}
<link rel="stylesheet" disabled href="{{page.root_path|safe}}{{theme}}{{page.resource_suffix}}.css"> {#- -#}
{%- endfor -%}
+ {%- if !layout.default_settings.is_empty() -%}
<script id="default-settings" {# -#}
{% for (k, v) in layout.default_settings %}
data-{{k}}="{{v}}"
{%- endfor -%}
></script> {#- -#}
+ {%- endif -%}
<script src="{{static_root_path|safe}}{{files.storage_js}}"></script> {#- -#}
{%- if page.css_class.contains("crate") -%}
<script defer src="{{page.root_path|safe}}crates{{page.resource_suffix}}.js"></script> {#- -#}
-Subproject commit e84a7928d93a31f284b497c214a2ece69b4d7719
+Subproject commit 82c3bb79e3a19a5164e33819ef81bfc2c984bc56
Ok(Pointer::new(Some(Provenance::Wildcard), Size::from_bytes(addr)))
}
- fn alloc_base_addr(ecx: &MiriInterpCx<'mir, 'tcx>, alloc_id: AllocId) -> u64 {
+ fn alloc_base_addr(
+ ecx: &MiriInterpCx<'mir, 'tcx>,
+ alloc_id: AllocId,
+ ) -> InterpResult<'tcx, u64> {
let mut global_state = ecx.machine.intptrcast.borrow_mut();
let global_state = &mut *global_state;
- match global_state.base_addr.entry(alloc_id) {
+ Ok(match global_state.base_addr.entry(alloc_id) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
// There is nothing wrong with a raw pointer being cast to an integer only after
rng.gen_range(0..16)
};
// From next_base_addr + slack, round up to adjust for alignment.
- let base_addr = global_state.next_base_addr.checked_add(slack).unwrap();
+ let base_addr = global_state
+ .next_base_addr
+ .checked_add(slack)
+ .ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
let base_addr = Self::align_addr(base_addr, align.bytes());
entry.insert(base_addr);
trace!(
// of at least 1 to avoid two allocations having the same base address.
// (The logic in `alloc_id_from_addr` assumes unique addresses, and different
// function/vtable pointers need to be distinguishable!)
- global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap();
+ global_state.next_base_addr = base_addr
+ .checked_add(max(size.bytes(), 1))
+ .ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
+ // Even if `Size` didn't overflow, we might still have filled up the address space.
+ if global_state.next_base_addr > ecx.machine_usize_max() {
+ throw_exhaust!(AddressSpaceFull);
+ }
// Given that `next_base_addr` increases in each allocation, pushing the
// corresponding tuple keeps `int_to_ptr_map` sorted
global_state.int_to_ptr_map.push((base_addr, alloc_id));
base_addr
}
- }
+ })
}
/// Convert a relative (tcx) pointer to an absolute address.
- pub fn rel_ptr_to_addr(ecx: &MiriInterpCx<'mir, 'tcx>, ptr: Pointer<AllocId>) -> u64 {
+ pub fn rel_ptr_to_addr(
+ ecx: &MiriInterpCx<'mir, 'tcx>,
+ ptr: Pointer<AllocId>,
+ ) -> InterpResult<'tcx, u64> {
let (alloc_id, offset) = ptr.into_parts(); // offset is relative (AllocId provenance)
- let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id);
+ let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id)?;
// Add offset with the right kind of pointer-overflowing arithmetic.
let dl = ecx.data_layout();
- dl.overflowing_offset(base_addr, offset.bytes()).0
+ Ok(dl.overflowing_offset(base_addr, offset.bytes()).0)
}
/// When a pointer is used for a memory access, this computes where in which allocation the
GlobalStateInner::alloc_id_from_addr(ecx, addr.bytes())?
};
- let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id);
+ // This cannot fail: since we already have a pointer with that provenance, rel_ptr_to_addr
+ // must have been called in the past.
+ let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id).unwrap();
// Wrapping "addr - base_addr"
let dl = ecx.data_layout();
fn adjust_alloc_base_pointer(
ecx: &MiriInterpCx<'mir, 'tcx>,
ptr: Pointer<AllocId>,
- ) -> Pointer<Provenance> {
+ ) -> InterpResult<'tcx, Pointer<Provenance>> {
if cfg!(debug_assertions) {
// The machine promises to never call us on thread-local or extern statics.
let alloc_id = ptr.provenance;
_ => {}
}
}
- let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr);
+ let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr)?;
let tag = if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
borrow_tracker.borrow_mut().base_ptr_tag(ptr.provenance, &ecx.machine)
} else {
// Value does not matter, SB is disabled
BorTag::default()
};
- Pointer::new(
+ Ok(Pointer::new(
Provenance::Concrete { alloc_id: ptr.provenance, tag },
Size::from_bytes(absolute_addr),
- )
+ ))
}
#[inline(always)]
0 => {
// These are "mutable" allocations as we consider them to be owned by the callee.
let name_alloc =
- this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut);
+ this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
let filename_alloc =
- this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut);
+ this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
this.write_immediate(
name_alloc.to_ref(this),
let this = self.eval_context_mut();
// First arg: message.
- let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not);
+ let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not)?;
// Call the lang item.
let panic = this.tcx.lang_items().panic_fn().unwrap();
-Subproject commit 5b2eee7eed72b4894909c5eecbf014ea0b5ad995
+Subproject commit 9981e4d1ea6ac0992ff21be5514d4230dc77548b
// Error codes that don't yet have a UI test. This list will eventually be removed.
const IGNORE_UI_TEST_CHECK: &[&str] =
- &["E0461", "E0465", "E0476", "E0514", "E0523", "E0554", "E0640", "E0717", "E0729"];
+ &["E0461", "E0465", "E0476", "E0514", "E0554", "E0640", "E0717", "E0729"];
macro_rules! verbose_print {
($verbose:expr, $($fmt:tt)*) => {
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
const ROOT_ENTRY_LIMIT: usize = 939;
-const ISSUES_ENTRY_LIMIT: usize = 1998;
+const ISSUES_ENTRY_LIMIT: usize = 2001;
fn check_entries(path: &Path, bad: &mut bool) {
for dir in Walk::new(&path.join("ui")) {
--- /dev/null
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+
+ fn f(_1: Foo) -> bool {
+ let mut _0: bool; // return place in scope 0 at $DIR/move_projection.rs:+0:17: +0:21
+ let mut _2: Foo; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ let mut _3: u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+ bb0: {
+- _2 = _1; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+- _3 = move (_2.0: u8); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+- _0 = opaque::<Foo>(move _1) -> bb1; // scope 0 at $DIR/move_projection.rs:+6:13: +6:44
++ _3 = (_1.0: u8); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
++ _0 = opaque::<Foo>(_1) -> bb1; // scope 0 at $DIR/move_projection.rs:+6:13: +6:44
+ // mir::Constant
+ // + span: $DIR/move_projection.rs:19:28: 19:34
+ // + literal: Const { ty: fn(Foo) -> bool {opaque::<Foo>}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ _0 = opaque::<u8>(move _3) -> bb2; // scope 0 at $DIR/move_projection.rs:+9:13: +9:44
+ // mir::Constant
+ // + span: $DIR/move_projection.rs:22:28: 22:34
+ // + literal: Const { ty: fn(u8) -> bool {opaque::<u8>}, val: Value(<ZST>) }
+ }
+
+ bb2: {
+ return; // scope 0 at $DIR/move_projection.rs:+12:13: +12:21
+ }
+ }
+
--- /dev/null
+// unit-test: CopyProp
+
+#![feature(custom_mir, core_intrinsics)]
+#![allow(unused_assignments)]
+extern crate core;
+use core::intrinsics::mir::*;
+
+fn opaque(_: impl Sized) -> bool { true }
+
+struct Foo(u8);
+
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn f(a: Foo) -> bool {
+ mir!(
+ {
+ let b = a;
+ // This is a move out of a copy, so must become a copy of `a.0`.
+ let c = Move(b.0);
+ Call(RET, bb1, opaque(Move(a)))
+ }
+ bb1 = {
+ Call(RET, ret, opaque(Move(c)))
+ }
+ ret = {
+ Return()
+ }
+ )
+}
+
+fn main() {
+ assert!(f(Foo(0)));
+}
+
+// EMIT_MIR move_projection.f.CopyProp.diff
}
bb3: {
- _4 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+ _4 = ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
StorageLive(_5); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
_5 = Add(_4, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
_0 = Option::<i32>::Some(move _5); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
impl Foo {
// @has async_fn/struct.Foo.html
- // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+ // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar ) -> impl Iterator<Item = &usize>'
pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
// taken from `tokio` as an example of a method that was particularly bad before
// @has - '//*[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
impl<const N: usize> Trait<N> for [u8; N] {}
// @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \
-// 'pub struct Foo<const N: usize>where u8: Trait<N>'
+// 'pub struct Foo<const N: usize> where u8: Trait<N>'
pub struct Foo<const N: usize> where u8: Trait<N>;
// @has foo/struct.Bar.html '//pre[@class="rust item-decl"]' 'pub struct Bar<T, const N: usize>(_)'
pub struct Bar<T, const N: usize>([T; N]);
<code>pub trait Write {
// Required methods
- fn <a href="#tymethod.poll_write" class="fn">poll_write</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        buf: &mut [<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>;
-<span class="item-spacer" /> fn <a href="#tymethod.poll_flush" class="fn">poll_flush</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>><br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>;
-<span class="item-spacer" /> fn <a href="#tymethod.poll_close" class="fn">poll_close</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>><br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>;
+ fn <a href="#tymethod.poll_write" class="fn">poll_write</a>(
+ self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,
+ cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,
+ buf: &mut [<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]
+ ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>;
+<span class="item-spacer" /> fn <a href="#tymethod.poll_flush" class="fn">poll_flush</a>(
+ self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,
+ cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>
+ ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>;
+<span class="item-spacer" /> fn <a href="#tymethod.poll_close" class="fn">poll_close</a>(
+ self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,
+ cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>
+ ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>;
// Provided method
- fn <a href="#method.poll_write_vectored" class="fn">poll_write_vectored</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        bufs: &[<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>> { ... }
-}</code>
+ fn <a href="#method.poll_write_vectored" class="fn">poll_write_vectored</a>(
+ self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,
+ cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,
+ bufs: &[<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]
+ ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>> { ... }
+}</code>
\ No newline at end of file
// @has foo/trait.LendingIterator.html
pub trait LendingIterator {
- // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a>where Self: 'a"
+ // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a"
type Item<'a> where Self: 'a;
// @has - '//*[@id="tymethod.next"]//h4[@class="code-header"]' \
pub struct Infinite<T>(T);
// @has foo/trait.LendingIterator.html
-// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a>where Self: 'a = &'a T"
+// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a = &'a T"
impl<T> LendingIterator for Infinite<T> {
type Item<'a> where Self: 'a = &'a T;
// @has impl_trait/fn.func2.html
// @has - '//pre[@class="rust item-decl"]' "func2<T>("
// @has - '//pre[@class="rust item-decl"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>,"
-// @has - '//pre[@class="rust item-decl"]' "_y: impl Iterator<Item = u8>)"
+// @has - '//pre[@class="rust item-decl"]' "_y: impl Iterator<Item = u8> )"
// @!has - '//pre[@class="rust item-decl"]' 'where'
pub use impl_trait_aux::func2;
pub trait Bar {}
-// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T)where T: Bar;'
+// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T) where T: Bar;'
pub struct Foo<T>(pub T) where T: Bar;
pub use reexports::foo;
// @has 'foo/outer/inner/fn.foo_crate.html' '//pre[@class="rust item-decl"]' 'pub(crate) fn foo_crate()'
pub(crate) use reexports::foo_crate;
- // @has 'foo/outer/inner/fn.foo_super.html' '//pre[@class="rust item-decl"]' 'pub(in outer) fn foo_super()'
+ // @has 'foo/outer/inner/fn.foo_super.html' '//pre[@class="rust item-decl"]' 'pub(in outer) fn foo_super( )'
pub(super) use::reexports::foo_super;
// @!has 'foo/outer/inner/fn.foo_self.html'
pub(self) use reexports::foo_self;
-<pre class="rust item-decl"><code>pub struct Simd<T>(_)<br /><span class="where">where<br />    T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre>
\ No newline at end of file
+<pre class="rust item-decl"><code>pub struct Simd<T>(_)
+<span class="where">where
+ T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre>
\ No newline at end of file
<pre class="rust item-decl"><code>pub trait TraitWhere {
- type <a href="#associatedtype.Item" class="associatedtype">Item</a><'a><br />       <span class="where">where Self: 'a</span>;
+ type <a href="#associatedtype.Item" class="associatedtype">Item</a><'a>
+ <span class="where">where Self: 'a</span>;
// Provided methods
- fn <a href="#method.func" class="fn">func</a>(self)<br />       <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
-<span class="item-spacer" /> fn <a href="#method.lines" class="fn">lines</a>(self) -> <a class="struct" href="{{channel}}/std/io/struct.Lines.html" title="struct std::io::Lines">Lines</a><Self><br />       <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
-<span class="item-spacer" /> fn <a href="#method.merge" class="fn">merge</a><T>(self, a: T)<br />       <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,<br />             T: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
+ fn <a href="#method.func" class="fn">func</a>(self)
+ <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
+<span class="item-spacer" /> fn <a href="#method.lines" class="fn">lines</a>(self) -> <a class="struct" href="{{channel}}/std/io/struct.Lines.html" title="struct std::io::Lines">Lines</a><Self>
+ <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
+<span class="item-spacer" /> fn <a href="#method.merge" class="fn">merge</a><T>(self, a: T)
+ <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,
+ T: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
}</code></pre>
\ No newline at end of file
pub trait MyTrait { fn dummy(&self) { } }
-// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_)where A: MyTrait"
+// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_) where A: MyTrait"
pub struct Alpha<A>(A) where A: MyTrait;
// @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B>where B: MyTrait"
pub trait Bravo<B> where B: MyTrait { fn get(&self, B: B); }
-<pre class="rust item-decl"><code>pub enum Cow<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub enum Cow<'a, B><span class="where fmt-newline">where
+ B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a B</a>),
Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
}</code></pre>
\ No newline at end of file
-<pre class="rust item-decl"><code>pub struct Struct<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub struct Struct<'a, B><span class="where fmt-newline">where
+ B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a B</a>,
pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
}</code></pre>
\ No newline at end of file
-<pre class="rust item-decl"><code>pub trait ToOwned<T><span class="where fmt-newline">where<br />    T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</span>{
+<pre class="rust item-decl"><code>pub trait ToOwned<T><span class="where fmt-newline">where
+ T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</span>{
type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>;
// Required methods
-<pre class="rust item-decl"><code>pub union Union<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub union Union<'a, B><span class="where fmt-newline">where
+ B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
/* private fields */
}</code></pre>
\ No newline at end of file
| ^^^^^^^^^^ required by this bound in `UnsafeCopy`
help: consider further restricting this bound
|
-LL | impl<T: Copy + std::ops::Deref + Deref<Target = T>> UnsafeCopy<'_, T> for T {
- | +++++++++++++++++++
+LL | impl<T: Copy + std::ops::Deref<Target = T>> UnsafeCopy<'_, T> for T {
+ | ++++++++++++
error: aborting due to previous error
--- /dev/null
+// compile-flags: -Z print-type-sizes --crate-type lib
+// edition:2021
+// build-pass
+// ignore-pass
+
+async fn wait() {}
+
+async fn big_fut(arg: [u8; 1024]) {}
+
+async fn calls_fut(fut: impl std::future::Future<Output = ()>) {
+ loop {
+ wait().await;
+ if true {
+ return fut.await;
+ } else {
+ wait().await;
+ }
+ }
+}
+
+pub async fn test() {
+ let fut = big_fut([0u8; 1024]);
+ calls_fut(fut).await;
+}
--- /dev/null
+print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:21:21: 24:2]`: 3078 bytes, alignment: 1 bytes
+print-type-size discriminant: 1 bytes
+print-type-size variant `Unresumed`: 0 bytes
+print-type-size variant `Suspend0`: 3077 bytes
+print-type-size local `.__awaitee`: 3077 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size variant `Returned`: 0 bytes
+print-type-size variant `Panicked`: 0 bytes
+print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]`: 3077 bytes, alignment: 1 bytes
+print-type-size discriminant: 1 bytes
+print-type-size variant `Unresumed`: 2051 bytes
+print-type-size padding: 1026 bytes
+print-type-size upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size variant `Suspend0`: 2052 bytes
+print-type-size local `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size local `..generator_field4`: 1 bytes
+print-type-size padding: 1 bytes
+print-type-size upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size local `.__awaitee`: 1 bytes
+print-type-size variant `Suspend1`: 3076 bytes
+print-type-size padding: 1024 bytes
+print-type-size local `..generator_field4`: 1 bytes, alignment: 1 bytes
+print-type-size padding: 1 bytes
+print-type-size upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size local `.__awaitee`: 1025 bytes
+print-type-size variant `Suspend2`: 2052 bytes
+print-type-size local `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size local `..generator_field4`: 1 bytes
+print-type-size padding: 1 bytes
+print-type-size upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size local `.__awaitee`: 1 bytes
+print-type-size variant `Returned`: 2051 bytes
+print-type-size padding: 1026 bytes
+print-type-size upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size variant `Panicked`: 2051 bytes
+print-type-size padding: 1026 bytes
+print-type-size upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]>`: 3077 bytes, alignment: 1 bytes
+print-type-size field `.value`: 3077 bytes
+print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]>`: 3077 bytes, alignment: 1 bytes
+print-type-size variant `MaybeUninit`: 3077 bytes
+print-type-size field `.uninit`: 0 bytes
+print-type-size field `.value`: 3077 bytes
+print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]`: 1025 bytes, alignment: 1 bytes
+print-type-size discriminant: 1 bytes
+print-type-size variant `Unresumed`: 1024 bytes
+print-type-size upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size variant `Returned`: 1024 bytes
+print-type-size upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size variant `Panicked`: 1024 bytes
+print-type-size upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]>`: 1025 bytes, alignment: 1 bytes
+print-type-size field `.value`: 1025 bytes
+print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]>`: 1025 bytes, alignment: 1 bytes
+print-type-size variant `MaybeUninit`: 1025 bytes
+print-type-size field `.uninit`: 0 bytes
+print-type-size field `.value`: 1025 bytes
+print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19]`: 1 bytes, alignment: 1 bytes
+print-type-size discriminant: 1 bytes
+print-type-size variant `Unresumed`: 0 bytes
+print-type-size variant `Returned`: 0 bytes
+print-type-size variant `Panicked`: 0 bytes
+print-type-size type: `std::mem::ManuallyDrop<bool>`: 1 bytes, alignment: 1 bytes
+print-type-size field `.value`: 1 bytes
+print-type-size type: `std::mem::MaybeUninit<bool>`: 1 bytes, alignment: 1 bytes
+print-type-size variant `MaybeUninit`: 1 bytes
+print-type-size field `.uninit`: 0 bytes
+print-type-size field `.value`: 1 bytes
+print-type-size type: `std::task::Poll<()>`: 1 bytes, alignment: 1 bytes
+print-type-size discriminant: 1 bytes
+print-type-size variant `Ready`: 0 bytes
+print-type-size field `.0`: 0 bytes
+print-type-size variant `Pending`: 0 bytes
// compile-flags: -Ztreat-err-as-bug=1
// failure-status: 101
// rustc-env:RUST_BACKTRACE=1
-// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
-// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "\nerror: .*unexpectedly panicked.*\n\n" -> ""
// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
error[E0080]: evaluation of constant value failed
- --> $DIR/const-eval-query-stack.rs:17:16
+ --> $DIR/const-eval-query-stack.rs:16:16
|
LL | const X: i32 = 1 / 0;
| ^^^^^ attempt to divide `1_i32` by zero
= note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
-error[E0277]: `AlignedUsize` needs to be a pointer-sized type
+error[E0277]: `AlignedUsize` needs to have the same alignment and size as a pointer
--> $DIR/align.rs:15:13
|
LL | let x = AlignedUsize(12) as dyn* Debug;
- | ^^^^^^^^^^^^^^^^ `AlignedUsize` needs to be a pointer-sized type
+ | ^^^^^^^^^^^^^^^^ `AlignedUsize` needs to be a pointer-like type
|
- = help: the trait `PointerSized` is not implemented for `AlignedUsize`
+ = help: the trait `PointerLike` is not implemented for `AlignedUsize`
error: aborting due to previous error; 1 warning emitted
fn main() {
let x = AlignedUsize(12) as dyn* Debug;
- //[over_aligned]~^ ERROR `AlignedUsize` needs to be a pointer-sized type
+ //[over_aligned]~^ ERROR `AlignedUsize` needs to have the same alignment and size as a pointer
}
fn polymorphic<T: Debug + ?Sized>(t: &T) {
dyn_debug(t);
- //~^ ERROR `&T` needs to be a pointer-sized type
+ //~^ ERROR `&T` needs to have the same alignment and size as a pointer
}
fn main() {}
-error[E0277]: `&T` needs to be a pointer-sized type
+error[E0277]: `&T` needs to have the same alignment and size as a pointer
--> $DIR/check-size-at-cast-polymorphic-bad.rs:11:15
|
LL | dyn_debug(t);
- | ^ `&T` needs to be a pointer-sized type
+ | ^ `&T` needs to be a pointer-like type
|
- = help: the trait `PointerSized` is not implemented for `&T`
+ = help: the trait `PointerLike` is not implemented for `&T`
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
|
-LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerSized {
- | ++++++++++++++++++++++
+LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike {
+ | +++++++++++++++++++++
error: aborting due to previous error
fn main() {
let i = [1, 2, 3, 4] as dyn* Debug;
- //~^ ERROR `[i32; 4]` needs to be a pointer-sized type
+ //~^ ERROR `[i32; 4]` needs to have the same alignment and size as a pointer
dbg!(i);
}
-error[E0277]: `[i32; 4]` needs to be a pointer-sized type
+error[E0277]: `[i32; 4]` needs to have the same alignment and size as a pointer
--> $DIR/check-size-at-cast.rs:7:13
|
LL | let i = [1, 2, 3, 4] as dyn* Debug;
- | ^^^^^^^^^^^^ `[i32; 4]` needs to be a pointer-sized type
+ | ^^^^^^^^^^^^ `[i32; 4]` needs to be a pointer-like type
|
- = help: the trait `PointerSized` is not implemented for `[i32; 4]`
+ = help: the trait `PointerLike` is not implemented for `[i32; 4]`
error: aborting due to previous error
= note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
-error[E0277]: `dyn* Foo` needs to be a pointer-sized type
+error[E0277]: `dyn* Foo` needs to have the same alignment and size as a pointer
--> $DIR/upcast.rs:30:23
|
LL | let w: dyn* Bar = w;
- | ^ `dyn* Foo` needs to be a pointer-sized type
+ | ^ `dyn* Foo` needs to be a pointer-like type
|
- = help: the trait `PointerSized` is not implemented for `dyn* Foo`
+ = help: the trait `PointerLike` is not implemented for `dyn* Foo`
error: aborting due to previous error; 1 warning emitted
--- /dev/null
+// aux-build:crateresolve1-1.rs
+// aux-build:crateresolve1-2.rs
+// aux-build:crateresolve1-3.rs
+
+// normalize-stderr-test: "\.nll/" -> "/"
+// normalize-stderr-test: "\\\?\\" -> ""
+// normalize-stderr-test: "(lib)?crateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$2.somelib"
+
+// NOTE: This test is duplicated from `tests/ui/crate-loading/crateresolve1.rs`.
+
+extern crate crateresolve1;
+//~^ ERROR multiple candidates for `rlib` dependency `crateresolve1` found
+
+fn main() {}
--- /dev/null
+error[E0464]: multiple candidates for `rlib` dependency `crateresolve1` found
+ --> $DIR/E0523.rs:11:1
+ |
+LL | extern crate crateresolve1;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: candidate #1: $TEST_BUILD_DIR/error-codes/E0523/auxiliary/libcrateresolve1-1.somelib
+ = note: candidate #2: $TEST_BUILD_DIR/error-codes/E0523/auxiliary/libcrateresolve1-2.somelib
+ = note: candidate #3: $TEST_BUILD_DIR/error-codes/E0523/auxiliary/libcrateresolve1-3.somelib
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0464`.
// known-bug: #106191
// unset-rustc-env:RUST_BACKTRACE
// had to be reverted
-// error-pattern:internal compiler error
+// error-pattern:unexpectedly panicked
// failure-status:101
// dont-check-compiler-stderr
| ^^^^^^^^^^ required by this bound in `UnsafeCopy::Item`
help: consider further restricting this bound
|
-LL | impl<T: Copy + std::ops::Deref + Deref<Target = T>> UnsafeCopy<T> for T {
- | +++++++++++++++++++
+LL | impl<T: Copy + std::ops::Deref<Target = T>> UnsafeCopy<T> for T {
+ | ++++++++++++
error: aborting due to previous error
struct A<B>(B);
-impl<B> Add for A<B> where B: Add + Add<Output = B> {
+impl<B> Add for A<B> where B: Add<Output = B> {
type Output = Self;
fn add(self, rhs: Self) -> Self {
struct C<B>(B);
-impl<B: Add + Add<Output = B>> Add for C<B> {
+impl<B: Add<Output = B>> Add for C<B> {
type Output = Self;
fn add(self, rhs: Self) -> Self {
struct E<B>(B);
-impl<B: Add + Add<Output = B>> Add for E<B> where B: Add<Output = B> {
+impl<B: Add<Output = B>> Add for E<B> where B: Add<Output = B> {
//~^ ERROR equality constraints are not yet supported in `where` clauses
type Output = Self;
| ^
help: consider further restricting this bound
|
-LL | impl<B> Add for A<B> where B: Add + Add<Output = B> {
- | +++++++++++++++++
+LL | impl<B> Add for A<B> where B: Add<Output = B> {
+ | ++++++++++++
error[E0308]: mismatched types
--> $DIR/missing-bounds.rs:21:14
| ^
help: consider further restricting this bound
|
-LL | impl<B: Add + Add<Output = B>> Add for C<B> {
- | +++++++++++++++++
+LL | impl<B: Add<Output = B>> Add for C<B> {
+ | ++++++++++++
error[E0369]: cannot add `B` to `B`
--> $DIR/missing-bounds.rs:31:21
| ^
help: consider further restricting this bound
|
-LL | impl<B: Add + Add<Output = B>> Add for E<B> where <B as Add>::Output = B {
- | +++++++++++++++++
+LL | impl<B: Add<Output = B>> Add for E<B> where <B as Add>::Output = B {
+ | ++++++++++++
error: aborting due to 5 previous errors
stack backtrace:
-error: internal compiler error: unexpected panic
-
-
+error: the compiler unexpectedly panicked. this is a bug.
--- /dev/null
+// run-rustfix
+fn main() {}
+fn _foo() -> bool {
+ if true { true } else { false }
+}
+
+fn _bar() -> bool {
+ if true { true } else { false }
+}
+
+fn _baz() -> bool {
+ if true { true } else { false }
+}
--- /dev/null
+// run-rustfix
+fn main() {}
+fn _foo() -> bool {
+ & //~ ERROR 4:5: 6:36: mismatched types [E0308]
+ mut
+ if true { true } else { false }
+}
+
+fn _bar() -> bool {
+ & //~ ERROR 10:5: 11:40: mismatched types [E0308]
+ mut if true { true } else { false }
+}
+
+fn _baz() -> bool {
+ & mut //~ ERROR 15:5: 16:36: mismatched types [E0308]
+ if true { true } else { false }
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-92741.rs:4:5
+ |
+LL | fn _foo() -> bool {
+ | ---- expected `bool` because of return type
+LL | / &
+LL | | mut
+LL | | if true { true } else { false }
+ | |___________________________________^ expected `bool`, found `&mut bool`
+ |
+help: consider removing the borrow
+ |
+LL - &
+LL - mut
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/issue-92741.rs:10:5
+ |
+LL | fn _bar() -> bool {
+ | ---- expected `bool` because of return type
+LL | / &
+LL | | mut if true { true } else { false }
+ | |_______________________________________^ expected `bool`, found `&mut bool`
+ |
+help: consider removing the borrow
+ |
+LL - &
+LL - mut if true { true } else { false }
+LL + if true { true } else { false }
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/issue-92741.rs:15:5
+ |
+LL | fn _baz() -> bool {
+ | ---- expected `bool` because of return type
+LL | / & mut
+LL | | if true { true } else { false }
+ | |___________________________________^ expected `bool`, found `&mut bool`
+ |
+help: consider removing the borrow
+ |
+LL - & mut
+ |
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
-error: internal compiler error: unexpected panic
+error: the compiler unexpectedly panicked. this is a bug.
query stack during panic:
#0 [layout_of] computing layout of `Foo`
--- /dev/null
+// build-pass
+
+#![crate_type = "lib"]
+
+pub trait StreamOnce {
+ type Error;
+}
+
+pub trait ResetStream: StreamOnce {
+ fn reset(&mut self) -> Result<(), Self::Error>;
+}
+
+impl<'a> ResetStream for &'a str
+ where Self: StreamOnce
+{
+ #[inline]
+ fn reset(&mut self) -> Result<(), Self::Error> {
+ Ok(())
+ }
+}
--- /dev/null
+// build-pass
+// compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+
+pub trait Archive {
+ type Archived;
+ type Resolver;
+
+ fn resolve(resolver: Self::Resolver, out: *mut Self::Archived);
+}
+
+pub type Archived<T> = <T as Archive>::Archived;
+pub type Resolver<T> = <T as Archive>::Resolver;
+
+pub struct Record<'a> {
+ _payload: &'a [u8],
+}
+
+pub struct ArchivedRecord<'a>
+where
+ &'a [u8]: Archive,
+{
+ _payload: Archived<&'a [u8]>,
+}
+
+pub struct RecordResolver<'a>
+where
+ &'a [u8]: Archive,
+{
+ _payload: Resolver<&'a [u8]>,
+}
+
+impl<'a> Archive for Record<'a>
+where
+ &'a [u8]: Archive,
+{
+ type Archived = ArchivedRecord<'a>;
+ type Resolver = RecordResolver<'a>;
+
+ fn resolve(_resolver: Self::Resolver, _out: *mut Self::Archived) {}
+}
stack backtrace:
-error: internal compiler error: unexpected panic
-
-
+error: the compiler unexpectedly panicked. this is a bug.
= help: a `loop` may express intention better if this is on purpose
= note: `#[warn(unconditional_recursion)]` on by default
-error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<..., ...>, ...>, ...>, ...>: Iterator`
+error[E0275]: overflow evaluating the requirement `Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:12:24: 12:27]>: Iterator`
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`)
+ = note: required for `&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:12:24: 12:27]>` to implement `Iterator`
+ = note: 65 redundant requirements hidden
= note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<..., ...>, ...>, ...>, ...>, ...>, ...>, ...>` to implement `Iterator`
= note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-83150/issue-83150.long-type-hash.txt'
--- /dev/null
+pub trait TryAdd<Rhs = Self> {
+ type Error;
+ type Output;
+
+ fn try_add(self, rhs: Rhs) -> Result<Self::Output, Self::Error>;
+}
+
+impl<T: TryAdd> TryAdd for Option<T> {
+ type Error = <T as TryAdd>::Error;
+ type Output = Option<<T as TryAdd>::Output>;
+
+ fn try_add(self, rhs: Self) -> Result<Self::Output, Self::Error> {
+ Ok(self) //~ ERROR mismatched types
+ }
+}
+
+struct Other<A>(A);
+
+struct X;
+
+impl<T: TryAdd<Error = X>> TryAdd for Other<T> {
+ type Error = <T as TryAdd>::Error;
+ type Output = Other<<T as TryAdd>::Output>;
+
+ fn try_add(self, rhs: Self) -> Result<Self::Output, Self::Error> {
+ Ok(self) //~ ERROR mismatched types
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/restrict-existing-type-bounds.rs:13:12
+ |
+LL | impl<T: TryAdd> TryAdd for Option<T> {
+ | - this type parameter
+...
+LL | Ok(self)
+ | -- ^^^^ expected `Option<<T as TryAdd>::Output>`, found `Option<T>`
+ | |
+ | arguments to this enum variant are incorrect
+ |
+ = note: expected enum `Option<<T as TryAdd>::Output>`
+ found enum `Option<T>`
+help: the type constructed contains `Option<T>` due to the type of the argument passed
+ --> $DIR/restrict-existing-type-bounds.rs:13:9
+ |
+LL | Ok(self)
+ | ^^^----^
+ | |
+ | this argument influences the type of `Ok`
+note: tuple variant defined here
+ --> $SRC_DIR/core/src/result.rs:LL:COL
+help: consider further restricting this bound
+ |
+LL | impl<T: TryAdd<Output = T>> TryAdd for Option<T> {
+ | ++++++++++++
+
+error[E0308]: mismatched types
+ --> $DIR/restrict-existing-type-bounds.rs:26:12
+ |
+LL | impl<T: TryAdd<Error = X>> TryAdd for Other<T> {
+ | - this type parameter
+...
+LL | Ok(self)
+ | -- ^^^^ expected `Other<<T as TryAdd>::Output>`, found `Other<T>`
+ | |
+ | arguments to this enum variant are incorrect
+ |
+ = note: expected struct `Other<<T as TryAdd>::Output>`
+ found struct `Other<T>`
+help: the type constructed contains `Other<T>` due to the type of the argument passed
+ --> $DIR/restrict-existing-type-bounds.rs:26:9
+ |
+LL | Ok(self)
+ | ^^^----^
+ | |
+ | this argument influences the type of `Ok`
+note: tuple variant defined here
+ --> $SRC_DIR/core/src/result.rs:LL:COL
+help: consider further restricting this bound
+ |
+LL | impl<T: TryAdd<Error = X, Output = T>> TryAdd for Other<T> {
+ | ++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
//~^ ERROR: mismatched types [E0308]
//~| HELP: if you meant to write a byte literal, prefix with `b`
+ let _a: u8 = '\x20';
+ //~^ ERROR: mismatched types [E0308]
+ //~| HELP: if you meant to write a byte literal, prefix with `b`
+
+ // Do not issue the suggestion if the char literal is a Unicode escape
+ foo('\u{0080}');
+ //~^ ERROR: mismatched types [E0308]
+
// Do not issue the suggestion if the char literal isn't ASCII
let _t: u8 = '€';
//~^ ERROR: mismatched types [E0308]
+
+ // Do not issue the suggestion if the char literal isn't ASCII
+ foo('\u{1f980}');
+ //~^ ERROR: mismatched types [E0308]
}
| ~~~~
error[E0308]: mismatched types
- --> $DIR/type-mismatch-byte-literal.rs:16:18
+ --> $DIR/type-mismatch-byte-literal.rs:15:18
+ |
+LL | let _a: u8 = '\x20';
+ | -- ^^^^^^ expected `u8`, found `char`
+ | |
+ | expected due to this
+ |
+help: if you meant to write a byte literal, prefix with `b`
+ |
+LL | let _a: u8 = b'\x20';
+ | ~~~~~~~
+
+error[E0308]: mismatched types
+ --> $DIR/type-mismatch-byte-literal.rs:20:9
+ |
+LL | foo('\u{0080}');
+ | --- ^^^^^^^^^^ expected `u8`, found `char`
+ | |
+ | arguments to this function are incorrect
+ |
+note: function defined here
+ --> $DIR/type-mismatch-byte-literal.rs:4:4
+ |
+LL | fn foo(_t: u8) {}
+ | ^^^ ------
+
+error[E0308]: mismatched types
+ --> $DIR/type-mismatch-byte-literal.rs:24:18
|
LL | let _t: u8 = '€';
| -- ^^^ expected `u8`, found `char`
| |
| expected due to this
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+ --> $DIR/type-mismatch-byte-literal.rs:28:9
+ |
+LL | foo('\u{1f980}');
+ | --- ^^^^^^^^^^^ expected `u8`, found `char`
+ | |
+ | arguments to this function are incorrect
+ |
+note: function defined here
+ --> $DIR/type-mismatch-byte-literal.rs:4:4
+ |
+LL | fn foo(_t: u8) {}
+ | ^^^ ------
+
+error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// compile-flags: -Ztrait-solver=next
+
+#![feature(pointer_like_trait)]
+
+use std::marker::PointerLike;
+
+fn require_(_: impl PointerLike) {}
+
+fn main() {
+ require_(1usize);
+ require_(1u16);
+ //~^ ERROR `u16` needs to have the same alignment and size as a pointer
+ require_(&1i16);
+}
--- /dev/null
+error[E0277]: `u16` needs to have the same alignment and size as a pointer
+ --> $DIR/pointer-like.rs:11:14
+ |
+LL | require_(1u16);
+ | -------- ^^^^ the trait `PointerLike` is not implemented for `u16`
+ | |
+ | required by a bound introduced by this call
+ |
+ = note: the trait bound `u16: PointerLike` is not satisfied
+note: required by a bound in `require_`
+ --> $DIR/pointer-like.rs:7:21
+ |
+LL | fn require_(_: impl PointerLike) {}
+ | ^^^^^^^^^^^ required by this bound in `require_`
+help: consider borrowing here
+ |
+LL | require_(&1u16);
+ | +
+LL | require_(&mut 1u16);
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-#![feature(pointer_sized_trait)]
-
-use std::marker::PointerSized;
-
-fn require_pointer_sized(_: impl PointerSized) {}
-
-fn main() {
- require_pointer_sized(1usize);
- require_pointer_sized(1u16);
- //~^ ERROR `u16` needs to be a pointer-sized type
- require_pointer_sized(&1i16);
-}
+++ /dev/null
-error[E0277]: `u16` needs to be a pointer-sized type
- --> $DIR/pointer-sized.rs:9:27
- |
-LL | require_pointer_sized(1u16);
- | --------------------- ^^^^ the trait `PointerSized` is not implemented for `u16`
- | |
- | required by a bound introduced by this call
- |
- = note: the trait bound `u16: PointerSized` is not satisfied
-note: required by a bound in `require_pointer_sized`
- --> $DIR/pointer-sized.rs:5:34
- |
-LL | fn require_pointer_sized(_: impl PointerSized) {}
- | ^^^^^^^^^^^^ required by this bound in `require_pointer_sized`
-help: consider borrowing here
- |
-LL | require_pointer_sized(&1u16);
- | +
-LL | require_pointer_sized(&mut 1u16);
- | ++++
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
LL | fn main() {}
| ^^^^^^^^^
-error: internal compiler error: unexpected panic
+error: the compiler unexpectedly panicked. this is a bug.
query stack during panic:
#0 [trigger_delay_span_bug] triggering a delay span bug
LL | pub static C: u32 = 0 - 1;
| ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
-error: internal compiler error: unexpected panic
+error: the compiler unexpectedly panicked. this is a bug.
query stack during panic:
#0 [eval_to_allocation_raw] const-evaluating + checking `C`
--- /dev/null
+// edition: 2021
+
+use std::collections::HashMap;
+use std::future::Future;
+use std::pin::Pin;
+
+pub trait Trait {
+ fn do_something<'async_trait>(byte: u8)
+ ->
+ Pin<Box<dyn Future<Output = ()> +
+ Send + 'async_trait>>;
+}
+
+pub struct Struct;
+
+impl Trait for Struct {
+ fn do_something<'async_trait>(byte: u8)
+ ->
+ Pin<Box<dyn Future<Output = ()> +
+ Send + 'async_trait>> {
+ Box::pin(
+
+ async move { let byte = byte; let _: () = {}; })
+ }
+}
+
+pub struct Map {
+ map: HashMap<u16, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
+}
+
+impl Map {
+ pub fn new() -> Self {
+ let mut map = HashMap::new();
+ map.insert(1, Struct::do_something);
+ Self { map }
+ //~^ ERROR mismatched types
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-107775.rs:35:16
+ |
+LL | map.insert(1, Struct::do_something);
+ | - -------------------- this is of type `fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}`, which causes `map` to be inferred as `HashMap<{integer}, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
+ | |
+ | this is of type `{integer}`, which causes `map` to be inferred as `HashMap<{integer}, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
+LL | Self { map }
+ | ^^^ expected `HashMap<u16, fn(u8) -> Pin<...>>`, found `HashMap<{integer}, ...>`
+ |
+ = note: expected struct `HashMap<u16, fn(_) -> Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>>`
+ found struct `HashMap<{integer}, fn(_) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.