- name: dist-x86_64-apple
env:
SCRIPT: "./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin"
- RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin"
+ RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
MACOSX_DEPLOYMENT_TARGET: 10.7
SELECT_XCODE: /Applications/Xcode_13.4.1.app
+Version 1.66.0 (2022-12-15)
+==========================
+
+Language
+--------
+- [Permit specifying explicit discriminants on all `repr(Int)` enums](https://github.com/rust-lang/rust/pull/95710/)
+ ```rust
+ #[repr(u8)]
+ enum Foo {
+ A(u8) = 0,
+ B(i8) = 1,
+ C(bool) = 42,
+ }
+ ```
+- [Allow transmutes between the same type differing only in lifetimes](https://github.com/rust-lang/rust/pull/101520/)
+- [Change constant evaluation errors from a deny-by-default lint to a hard error](https://github.com/rust-lang/rust/pull/102091/)
+- [Trigger `must_use` on `impl Trait` for supertraits](https://github.com/rust-lang/rust/pull/102287/)
+ This makes `impl ExactSizeIterator` respect the existing `#[must_use]` annotation on `Iterator`.
+- [Allow `..=X` in patterns](https://github.com/rust-lang/rust/pull/102275/)
+- [Uplift `clippy::for_loops_over_fallibles` lint into rustc](https://github.com/rust-lang/rust/pull/99696/)
+- [Stabilize `sym` operands in inline assembly](https://github.com/rust-lang/rust/pull/103168/)
+- [Update to Unicode 15](https://github.com/rust-lang/rust/pull/101912/)
+- [Opaque types no longer imply lifetime bounds](https://github.com/rust-lang/rust/pull/95474/)
+ This is a soundness fix which may break code that was erroneously relying on this behavior.
+
+Compiler
+--------
+- [Add armv5te-none-eabi and thumbv5te-none-eabi tier 3 targets](https://github.com/rust-lang/rust/pull/101329/)
+ - Refer to Rust's [platform support page][platform-support-doc] for more
+ information on Rust's tiered platform support.
+- [Add support for linking against macOS universal libraries](https://github.com/rust-lang/rust/pull/98736)
+
+Libraries
+---------
+- [Fix `#[derive(Default)]` on a generic `#[default]` enum adding unnecessary `Default` bounds](https://github.com/rust-lang/rust/pull/101040/)
+- [Update to Unicode 15](https://github.com/rust-lang/rust/pull/101821/)
+
+Stabilized APIs
+---------------
+
+- [`proc_macro::Span::source_text`](https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.source_text)
+- [`uX::{checked_add_signed, overflowing_add_signed, saturating_add_signed, wrapping_add_signed}`](https://doc.rust-lang.org/stable/std/primitive.u8.html#method.checked_add_signed)
+- [`iX::{checked_add_unsigned, overflowing_add_unsigned, saturating_add_unsigned, wrapping_add_unsigned}`](https://doc.rust-lang.org/stable/std/primitive.i8.html#method.checked_add_unsigned)
+- [`iX::{checked_sub_unsigned, overflowing_sub_unsigned, saturating_sub_unsigned, wrapping_sub_unsigned}`](https://doc.rust-lang.org/stable/std/primitive.i8.html#method.checked_sub_unsigned)
+- [`BTreeSet::{first, last, pop_first, pop_last}`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeSet.html#method.first)
+- [`BTreeMap::{first_key_value, last_key_value, first_entry, last_entry, pop_first, pop_last}`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html#method.first_key_value)
+- [Add `AsFd` implementations for stdio lock types on WASI.](https://github.com/rust-lang/rust/pull/101768/)
+- [`impl TryFrom<Vec<T>> for Box<[T; N]>`](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#impl-TryFrom%3CVec%3CT%2C%20Global%3E%3E-for-Box%3C%5BT%3B%20N%5D%2C%20Global%3E)
+- [`core::hint::black_box`](https://doc.rust-lang.org/stable/std/hint/fn.black_box.html)
+- [`Duration::try_from_secs_{f32,f64}`](https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.try_from_secs_f32)
+- [`Option::unzip`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.unzip)
+- [`std::os::fd`](https://doc.rust-lang.org/stable/std/os/fd/index.html)
+
+
+Rustdoc
+-------
+
+- [Add Rustdoc warning for invalid HTML tags in the documentation](https://github.com/rust-lang/rust/pull/101720/)
+
+Cargo
+-----
+
+- [Added `cargo remove` to remove dependencies from Cargo.toml](https://doc.rust-lang.org/nightly/cargo/commands/cargo-remove.html)
+- [`cargo publish` now waits for the new version to be downloadable before exiting](https://github.com/rust-lang/cargo/pull/11062)
+
+See [detailed release notes](https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-166-2022-12-15) for more.
+
+Compatibility Notes
+-------------------
+
+- [Only apply `ProceduralMasquerade` hack to older versions of `rental`](https://github.com/rust-lang/rust/pull/94063/)
+- [Don't export `__heap_base` and `__data_end` on wasm32-wasi.](https://github.com/rust-lang/rust/pull/102385/)
+- [Don't export `__wasm_init_memory` on WebAssembly.](https://github.com/rust-lang/rust/pull/102426/)
+- [Only export `__tls_*` on wasm32-unknown-unknown.](https://github.com/rust-lang/rust/pull/102440/)
+- [Don't link to `libresolv` in libstd on Darwin](https://github.com/rust-lang/rust/pull/102766/)
+- [Update libstd's libc to 0.2.135 (to make `libstd` no longer pull in `libiconv.dylib` on Darwin)](https://github.com/rust-lang/rust/pull/103277/)
+- [Opaque types no longer imply lifetime bounds](https://github.com/rust-lang/rust/pull/95474/)
+ This is a soundness fix which may break code that was erroneously relying on this behavior.
+- [Make `order_dependent_trait_objects` show up in future-breakage reports](https://github.com/rust-lang/rust/pull/102635/)
+- [Change std::process::Command spawning to default to inheriting the parent's signal mask](https://github.com/rust-lang/rust/pull/101077/)
+
+Internal Changes
+----------------
+
+These changes do not affect any public interfaces of Rust, but they represent
+significant improvements to the performance or internals of rustc and related
+tools.
+
+- [Enable BOLT for LLVM compilation](https://github.com/rust-lang/rust/pull/94381/)
+- [Enable LTO for rustc_driver.so](https://github.com/rust-lang/rust/pull/101403/)
+
Version 1.65.0 (2022-11-03)
==========================
pub fn for_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Option<Integer> {
let dl = cx.data_layout();
- for candidate in [I8, I16, I32, I64, I128] {
- if wanted == candidate.align(dl).abi && wanted.bytes() == candidate.size().bytes() {
- return Some(candidate);
- }
- }
- None
+ [I8, I16, I32, I64, I128].into_iter().find(|&candidate| {
+ wanted == candidate.align(dl).abi && wanted.bytes() == candidate.size().bytes()
+ })
}
/// Find the largest integer with the given alignment or less.
Unloaded,
}
-#[derive(Copy, Clone, Encodable, Decodable, Debug)]
+#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
pub struct ModSpans {
/// `inner_span` covers the body of the module; for a file module, its the whole file.
/// For an inline module, its the span inside the `{ ... }`, not including the curly braces.
pub inject_use_span: Span,
}
-impl Default for ModSpans {
- fn default() -> ModSpans {
- ModSpans { inner_span: Default::default(), inject_use_span: Default::default() }
- }
-}
-
/// Foreign module declaration.
///
/// E.g., `extern { .. }` or `extern "C" { .. }`.
if let NtExpr(expr) | NtLiteral(expr) = &**nt
&& let ast::ExprKind::Lit(token_lit) = expr.kind =>
{
- Some(token_lit.clone())
+ Some(token_lit)
}
_ => None,
}
pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
ensure_sufficient_stack(|| {
+ match &e.kind {
+ // Paranthesis expression does not have a HirId and is handled specially.
+ ExprKind::Paren(ex) => {
+ let mut ex = self.lower_expr_mut(ex);
+ // Include parens in span, but only if it is a super-span.
+ if e.span.contains(ex.span) {
+ ex.span = self.lower_span(e.span);
+ }
+ // Merge attributes into the inner expression.
+ if !e.attrs.is_empty() {
+ let old_attrs =
+ self.attrs.get(&ex.hir_id.local_id).map(|la| *la).unwrap_or(&[]);
+ self.attrs.insert(
+ ex.hir_id.local_id,
+ &*self.arena.alloc_from_iter(
+ e.attrs
+ .iter()
+ .map(|a| self.lower_attr(a))
+ .chain(old_attrs.iter().cloned()),
+ ),
+ );
+ }
+ return ex;
+ }
+ // Desugar `ExprForLoop`
+ // from: `[opt_ident]: for <pat> in <head> <body>`
+ //
+ // This also needs special handling because the HirId of the returned `hir::Expr` will not
+ // correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself.
+ ExprKind::ForLoop(pat, head, body, opt_label) => {
+ return self.lower_expr_for(e, pat, head, body, *opt_label);
+ }
+ _ => (),
+ }
+
+ let hir_id = self.lower_node_id(e.id);
+ self.lower_attrs(hir_id, &e.attrs);
+
let kind = match &e.kind {
ExprKind::Box(inner) => hir::ExprKind::Box(self.lower_expr(inner)),
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
if e.attrs.get(0).map_or(false, |a| a.has_name(sym::rustc_box)) {
if let [inner] = &args[..] && e.attrs.len() == 1 {
let kind = hir::ExprKind::Box(self.lower_expr(&inner));
- let hir_id = self.lower_node_id(e.id);
return hir::Expr { hir_id, kind, span: self.lower_span(e.span) };
} else {
self.tcx.sess.emit_err(RustcBoxAttributeError { span: e.span });
),
ExprKind::Async(capture_clause, closure_node_id, block) => self.make_async_expr(
*capture_clause,
- None,
+ hir_id,
*closure_node_id,
None,
e.span,
binder,
*capture_clause,
e.id,
+ hir_id,
*closure_id,
fn_decl,
body,
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
ExprKind::Err => hir::ExprKind::Err,
ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
- ExprKind::Paren(ex) => {
- let mut ex = self.lower_expr_mut(ex);
- // Include parens in span, but only if it is a super-span.
- if e.span.contains(ex.span) {
- ex.span = self.lower_span(e.span);
- }
- // Merge attributes into the inner expression.
- if !e.attrs.is_empty() {
- let old_attrs =
- self.attrs.get(&ex.hir_id.local_id).map(|la| *la).unwrap_or(&[]);
- self.attrs.insert(
- ex.hir_id.local_id,
- &*self.arena.alloc_from_iter(
- e.attrs
- .iter()
- .map(|a| self.lower_attr(a))
- .chain(old_attrs.iter().cloned()),
- ),
- );
- }
- return ex;
- }
- // Desugar `ExprForLoop`
- // from: `[opt_ident]: for <pat> in <head> <body>`
- ExprKind::ForLoop(pat, head, body, opt_label) => {
- return self.lower_expr_for(e, pat, head, body, *opt_label);
- }
+ ExprKind::Paren(_) | ExprKind::ForLoop(..) => unreachable!("already handled"),
+
ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
};
- let hir_id = self.lower_node_id(e.id);
- self.lower_attrs(hir_id, &e.attrs);
hir::Expr { hir_id, kind, span: self.lower_span(e.span) }
})
}
pub(super) fn make_async_expr(
&mut self,
capture_clause: CaptureBy,
- outer_hir_id: Option<hir::HirId>,
+ outer_hir_id: hir::HirId,
closure_node_id: NodeId,
ret_ty: Option<hir::FnRetTy<'hir>>,
span: Span,
hir::ExprKind::Closure(c)
};
- let track_caller = outer_hir_id
- .and_then(|id| self.attrs.get(&id.local_id))
+ let track_caller = self
+ .attrs
+ .get(&outer_hir_id.local_id)
.map_or(false, |attrs| attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)));
let hir_id = self.lower_node_id(closure_node_id);
binder: &ClosureBinder,
capture_clause: CaptureBy,
closure_id: NodeId,
+ closure_hir_id: hir::HirId,
inner_closure_id: NodeId,
decl: &FnDecl,
body: &Expr,
let async_body = this.make_async_expr(
capture_clause,
- // FIXME(nbdd0121): This should also use a proper HIR id so `#[track_caller]`
- // can be applied on async closures as well.
- None,
+ closure_hir_id,
inner_closure_id,
async_ret_ty,
body.span,
let async_expr = this.make_async_expr(
CaptureBy::Value,
- Some(fn_id),
+ fn_id,
closure_id,
None,
body.span,
{
let spans = vec![f1_span, f2_span];
sess.struct_span_err(
- spans.clone(),
+ spans,
&format!(
"features `{}` and `{}` are incompatible, using them at the same time \
is not allowed",
.map_bound(|p| p.predicates),
None,
),
- ty::Opaque(did, substs) => {
- find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*did), Some(*substs))
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
+ find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*def_id), Some(*substs))
}
ty::Closure(_, substs) => match substs.as_closure().kind() {
ty::ClosureKind::Fn => Some(hir::Mutability::Not),
err.span_suggestion_verbose(
span.shrink_to_hi(),
"consider cloning the value if the performance cost is acceptable",
- ".clone()".to_string(),
+ ".clone()",
Applicability::MachineApplicable,
);
}
);
if self.fn_self_span_reported.insert(fn_span) {
err.span_note(
- // Check whether the source is accessible
- if self.infcx.tcx.sess.source_map().is_span_accessible(self_arg.span) {
- self_arg.span
- } else {
- fn_call_span
- },
+ self_arg.span,
"calling this operator moves the left-hand side",
);
}
}
- CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
+ CallKind::Normal { self_arg, desugaring, method_did } => {
let self_arg = self_arg.unwrap();
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
),
);
}
+ let tcx = self.infcx.tcx;
// Avoid pointing to the same function in multiple different
// error messages.
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
+ let func = tcx.def_path_str(method_did);
err.span_note(
self_arg.span,
- &format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
+ &format!("`{func}` takes ownership of the receiver `self`, which moves {place_name}")
);
}
+ let parent_did = tcx.parent(method_did);
+ let parent_self_ty = (tcx.def_kind(parent_did)
+ == rustc_hir::def::DefKind::Impl)
+ .then_some(parent_did)
+ .and_then(|did| match tcx.type_of(did).kind() {
+ ty::Adt(def, ..) => Some(def.did()),
+ _ => None,
+ });
+ let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
+ matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
+ });
if is_option_or_result && maybe_reinitialized_locations_is_empty {
err.span_label(
var_span,
use rustc_mir_dataflow::move_paths::{
IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
};
-use rustc_span::Span;
+use rustc_span::{BytePos, Span};
use crate::diagnostics::{DescribePlaceOpt, UseSpans};
use crate::prefixes::PrefixSet;
match_span: Span,
statement_span: Span,
) {
- debug!("append_binding_error(match_place={:?}, match_span={:?})", match_place, match_span);
+ debug!(?match_place, ?match_span, "append_binding_error");
let from_simple_let = match_place.is_none();
let match_place = match_place.unwrap_or(move_from);
if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge
&& match_span == *span
{
- debug!("appending local({:?}) to list", bind_to);
+ debug!("appending local({bind_to:?}) to list");
if !binds_to.is_empty() {
binds_to.push(bind_to);
}
} = ge
{
if match_span == *span && mpi == *other_mpi {
- debug!("appending local({:?}) to list", bind_to);
+ debug!("appending local({bind_to:?}) to list");
binds_to.push(bind_to);
return;
}
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diagnostic, span: Span) {
match error {
GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
- if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
- err.span_suggestion(
- span,
- "consider borrowing here",
- format!("&{snippet}"),
- Applicability::Unspecified,
- );
- }
-
+ self.add_borrow_suggestions(err, span);
if binds_to.is_empty() {
let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
let place_desc = match self.describe_place(move_from.as_ref()) {
}
}
+ fn add_borrow_suggestions(&self, err: &mut Diagnostic, span: Span) {
+ match self.infcx.tcx.sess.source_map().span_to_snippet(span) {
+ Ok(snippet) if snippet.starts_with('*') => {
+ err.span_suggestion_verbose(
+ span.with_hi(span.lo() + BytePos(1)),
+ "consider removing the dereference here",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ "consider borrowing here",
+ "&".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+
fn add_move_error_suggestions(&self, err: &mut Diagnostic, binds_to: &[Local]) {
- let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
+ let mut suggestions: Vec<(Span, String, String)> = Vec::new();
for local in binds_to {
let bind_to = &self.body.local_decls[*local];
if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
VarBindingForm { pat_span, .. },
)))) = bind_to.local_info
{
- if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span)
+ let Ok(pat_snippet) =
+ self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) else { continue; };
+ let Some(stripped) = pat_snippet.strip_prefix('&') else {
+ suggestions.push((
+ bind_to.source_info.span.shrink_to_lo(),
+ "consider borrowing the pattern binding".to_string(),
+ "ref ".to_string(),
+ ));
+ continue;
+ };
+ let inner_pat_snippet = stripped.trim_start();
+ let (pat_span, suggestion, to_remove) = if inner_pat_snippet.starts_with("mut")
+ && inner_pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
{
- if let Some(stripped) = pat_snippet.strip_prefix('&') {
- let pat_snippet = stripped.trim_start();
- let (suggestion, to_remove) = if pat_snippet.starts_with("mut")
- && pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
- {
- (pat_snippet["mut".len()..].trim_start(), "&mut")
- } else {
- (pat_snippet, "&")
- };
- suggestions.push((pat_span, to_remove, suggestion.to_owned()));
- }
- }
+ let inner_pat_snippet = inner_pat_snippet["mut".len()..].trim_start();
+ let pat_span = pat_span.with_hi(
+ pat_span.lo()
+ + BytePos((pat_snippet.len() - inner_pat_snippet.len()) as u32),
+ );
+ (pat_span, String::new(), "mutable borrow")
+ } else {
+ let pat_span = pat_span.with_hi(
+ pat_span.lo()
+ + BytePos(
+ (pat_snippet.len() - inner_pat_snippet.trim_start().len()) as u32,
+ ),
+ );
+ (pat_span, String::new(), "borrow")
+ };
+ suggestions.push((
+ pat_span,
+ format!("consider removing the {to_remove}"),
+ suggestion.to_string(),
+ ));
}
}
suggestions.sort_unstable_by_key(|&(span, _, _)| span);
suggestions.dedup_by_key(|&mut (span, _, _)| span);
- for (span, to_remove, suggestion) in suggestions {
- err.span_suggestion(
- span,
- &format!("consider removing the `{to_remove}`"),
- suggestion,
- Applicability::MachineApplicable,
- );
+ for (span, msg, suggestion) in suggestions {
+ err.span_suggestion_verbose(span, &msg, suggestion, Applicability::MachineApplicable);
}
}
if binds_to.len() > 1 {
err.note(
- "move occurs because these variables have types that \
- don't implement the `Copy` trait",
+ "move occurs because these variables have types that don't implement the `Copy` \
+ trait",
);
}
}
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
- if let ty::Opaque(def_id, _) = *output_ty.kind() {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *output_ty.kind() {
output_ty = self.infcx.tcx.type_of(def_id)
};
// Otherwise, we need to find the minimum remaining choice, if
// any, and take that.
debug!("choice_regions remaining are {:#?}", choice_regions);
- let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option<ty::RegionVid> {
- let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2);
- let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1);
- match (r1_outlives_r2, r2_outlives_r1) {
- (true, true) => Some(r1.min(r2)),
- (true, false) => Some(r2),
- (false, true) => Some(r1),
- (false, false) => None,
- }
+ let Some(&min_choice) = choice_regions.iter().find(|&r1| {
+ choice_regions.iter().all(|&r2| {
+ self.universal_region_relations.outlives(r2, *r1)
+ })
+ }) else {
+ debug!("no choice region outlived by all others");
+ return false;
};
- let mut min_choice = choice_regions[0];
- for &other_option in &choice_regions[1..] {
- debug!(?min_choice, ?other_option,);
- match min(min_choice, other_option) {
- Some(m) => min_choice = m,
- None => {
- debug!(?min_choice, ?other_option, "incomparable; no min choice",);
- return false;
- }
- }
- }
let min_choice_scc = self.constraint_sccs.scc(min_choice);
debug!(?min_choice, ?min_choice_scc);
(item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
} else {
ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "alloc_error_handler must be a function");
- return vec![orig_item.clone()];
+ return vec![orig_item];
};
// Generate a bunch of new items using the AllocFnFactory
}
}
if !missing_literals.is_empty() {
- let mut err = cx.struct_span_err(missing_literals.clone(), "expected a byte literal");
+ let mut err = cx.struct_span_err(missing_literals, "expected a byte literal");
err.note("only byte literals (like `b\"foo\"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`");
err.emit();
return base::MacEager::expr(DummyResult::raw_expr(sp, true));
folder: target
prepare_script:
- . $HOME/.cargo/env
- - git config --global user.email "user@example.com"
- - git config --global user.name "User"
- ./y.rs prepare
test_script:
- . $HOME/.cargo/env
- name: Rustfmt
run: |
cargo fmt --check
+ rustfmt --check build_system/mod.rs
build:
runs-on: ${{ matrix.os }}
fail-fast: false
matrix:
include:
- - os: ubuntu-latest
+ - os: ubuntu-20.04 # FIXME switch to ubuntu-22.04 once #1303 is fixed
env:
TARGET_TRIPLE: x86_64-unknown-linux-gnu
- os: macos-latest
- os: ubuntu-latest
env:
TARGET_TRIPLE: aarch64-unknown-linux-gnu
+ # s390x requires QEMU 6.1 or greater, we could build it from source, but ubuntu 22.04 comes with 6.2 by default
+ - os: ubuntu-latest
+ env:
+ TARGET_TRIPLE: s390x-unknown-linux-gnu
steps:
- uses: actions/checkout@v3
- name: Cache cargo installed crates
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: ${{ runner.os }}-cargo-installed-crates
- name: Cache cargo registry and index
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: |
~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo target dir
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
- path: target
+ path: build/cg_clif
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
- name: Install MinGW toolchain and wine
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu qemu-user
- - name: Prepare dependencies
+ - name: Install s390x toolchain and qemu
+ if: matrix.env.TARGET_TRIPLE == 's390x-unknown-linux-gnu'
run: |
- git config --global user.email "user@example.com"
- git config --global user.name "User"
- ./y.rs prepare
+ sudo apt-get update
+ sudo apt-get install -y gcc-s390x-linux-gnu qemu-user
+
+ - name: Prepare dependencies
+ run: ./y.rs prepare
- name: Build without unstable features
env:
./y.rs test
- name: Package prebuilt cg_clif
- run: tar cvfJ cg_clif.tar.xz build
+ run: tar cvfJ cg_clif.tar.xz dist
- name: Upload prebuilt cg_clif
if: matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
- name: Upload prebuilt cg_clif (cross compile)
if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
path: cg_clif.tar.xz
- uses: actions/checkout@v3
- name: Cache cargo installed crates
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-installed-crates
- name: Cache cargo registry and index
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: |
~/.cargo/registry
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo target dir
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
- path: target
+ path: build/cg_clif
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
- name: Set MinGW as the default toolchain
- name: Prepare dependencies
run: |
- git config --global user.email "user@example.com"
- git config --global user.name "User"
git config --global core.autocrlf false
rustc y.rs -o y.exe -g
./y.exe prepare
# Enable extra checks
$Env:CG_CLIF_ENABLE_VERIFIER=1
-
+
# WIP Disable some tests
-
+
# This fails due to some weird argument handling by hyperfine, not an actual regression
# more of a build system issue
(Get-Content config.txt) -replace '(bench.simple-raytracer)', '# $1' | Out-File config.txt
-
- # This fails with a different output than expected
+
+ # This fails with a different output than expected
(Get-Content config.txt) -replace '(test.regex-shootout-regex-dna)', '# $1' | Out-File config.txt
./y.exe test
- name: Package prebuilt cg_clif
# don't use compression as xzip isn't supported by tar on windows and bzip2 hangs
- run: tar cvf cg_clif.tar build
+ run: tar cvf cg_clif.tar dist
- name: Upload prebuilt cg_clif
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
path: cg_clif.tar
- uses: actions/checkout@v3
- name: Cache cargo installed crates
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: ubuntu-latest-cargo-installed-crates
- uses: actions/checkout@v3
- name: Cache cargo installed crates
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: ${{ runner.os }}-cargo-installed-crates
- name: Cache cargo registry and index
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: |
~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo target dir
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
- path: target
+ path: build/cg_clif
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
- name: Prepare dependencies
- uses: actions/checkout@v3
- name: Cache cargo installed crates
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: ${{ runner.os }}-cargo-installed-crates
- name: Cache cargo registry and index
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: |
~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo target dir
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
- path: target
+ path: build/cg_clif
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
- name: Prepare dependencies
/build_sysroot/sysroot_src
/build_sysroot/compiler-builtins
/build_sysroot/rustc_version
+/dist
/rust
/download
"rust-analyzer.imports.granularity.enforce": true,
"rust-analyzer.imports.granularity.group": "module",
"rust-analyzer.imports.prefix": "crate",
- "rust-analyzer.cargo.features": ["unstable-features"],
+ "rust-analyzer.cargo.features": ["unstable-features", "__check_build_system_using_ra"],
"rust-analyzer.linkedProjects": [
"./Cargo.toml",
- //"./build_sysroot/sysroot_src/library/std/Cargo.toml",
{
- "roots": [
- "./example/mini_core.rs",
- "./example/mini_core_hello_world.rs",
- "./example/mod_bench.rs"
- ],
"crates": [
{
"root_module": "./example/mini_core.rs",
]
},
{
- "roots": ["./example/std_example.rs"],
+ "sysroot_src": "./build_sysroot/sysroot_src/library",
"crates": [
{
"root_module": "./example/std_example.rs",
- "edition": "2018",
- "deps": [{ "crate": 1, "name": "std" }],
- "cfg": [],
- },
- {
- "root_module": "./build_sysroot/sysroot_src/library/std/src/lib.rs",
- "edition": "2018",
- "deps": [],
- "cfg": [],
- },
- ]
- },
- {
- "roots": ["./y.rs"],
- "crates": [
- {
- "root_module": "./y.rs",
- "edition": "2018",
- "deps": [{ "crate": 1, "name": "std" }],
- "cfg": [],
- },
- {
- "root_module": "./build_sysroot/sysroot_src/library/std/src/lib.rs",
- "edition": "2018",
+ "edition": "2015",
"deps": [],
"cfg": [],
},
[[package]]
name = "anyhow"
-version = "1.0.60"
+version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
+checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
[[package]]
name = "arrayvec"
[[package]]
name = "bumpalo"
-version = "3.11.0"
+version = "3.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
+checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
[[package]]
name = "byteorder"
[[package]]
name = "cranelift-bforest"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44409ccf2d0f663920cab563d2b79fcd6b2e9a2bcc6e929fef76c8f82ad6c17a"
+checksum = "b62c772976416112fa4484cbd688cb6fb35fd430005c1c586224fc014018abad"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98de2018ad96eb97f621f7d6b900a0cc661aec8d02ea4a50e56ecb48e5a2fcaf"
+checksum = "9b40ed2dd13c2ac7e24f88a3090c68ad3414eb1d066a95f8f1f7b3b819cb4e46"
dependencies = [
"arrayvec",
"bumpalo",
"cranelift-bforest",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
+ "cranelift-egraph",
"cranelift-entity",
"cranelift-isle",
"gimli",
[[package]]
name = "cranelift-codegen-meta"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5287ce36e6c4758fbaf298bd1a8697ad97a4f2375a3d1b61142ea538db4877e5"
+checksum = "bb927a8f1c27c34ee3759b6b0ffa528d2330405d5cc4511f0cab33fe2279f4b5"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2855c24219e2f08827f3f4ffb2da92e134ae8d8ecc185b11ec8f9878cf5f588e"
+checksum = "43dfa417b884a9ab488d95fd6b93b25e959321fe7bfd7a0a960ba5d7fb7ab927"
+
+[[package]]
+name = "cranelift-egraph"
+version = "0.90.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0a66b39785efd8513d2cca967ede56d6cc57c8d7986a595c7c47d0c78de8dce"
+dependencies = [
+ "cranelift-entity",
+ "fxhash",
+ "hashbrown",
+ "indexmap",
+ "log",
+ "smallvec",
+]
[[package]]
name = "cranelift-entity"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b65673279d75d34bf11af9660ae2dbd1c22e6d28f163f5c72f4e1dc56d56103"
+checksum = "0637ffde963cb5d759bc4d454cfa364b6509e6c74cdaa21298add0ed9276f346"
[[package]]
name = "cranelift-frontend"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ed2b3d7a4751163f6c4a349205ab1b7d9c00eecf19dcea48592ef1f7688eefc"
+checksum = "fb72b8342685e850cb037350418f62cc4fc55d6c2eb9c7ca01b82f9f1a6f3d56"
dependencies = [
"cranelift-codegen",
"log",
[[package]]
name = "cranelift-isle"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3be64cecea9d90105fc6a2ba2d003e98c867c1d6c4c86cc878f97ad9fb916293"
+checksum = "850579cb9e4b448f7c301f1e6e6cbad99abe3f1f1d878a4994cb66e33c6db8cd"
[[package]]
name = "cranelift-jit"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f98ed42a70a0c9c388e34ec9477f57fc7300f541b1e5136a0e2ea02b1fac6015"
+checksum = "9add822ad66dcbe152b5ab57de10240a2df4505099f2f6c27159acb711890bd4"
dependencies = [
"anyhow",
"cranelift-codegen",
"log",
"region",
"target-lexicon",
+ "wasmtime-jit-icache-coherence",
"windows-sys",
]
[[package]]
name = "cranelift-module"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d658ac7f156708bfccb647216cc8b9387469f50d352ba4ad80150541e4ae2d49"
+checksum = "406b772626fc2664864cf947f3895a23b619895c7fff635f3622e2d857f4492f"
dependencies = [
"anyhow",
"cranelift-codegen",
[[package]]
name = "cranelift-native"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4a03a6ac1b063e416ca4b93f6247978c991475e8271465340caa6f92f3c16a4"
+checksum = "2d0a279e5bcba3e0466c734d8d8eb6bfc1ad29e95c37f3e4955b492b5616335e"
dependencies = [
"cranelift-codegen",
"libc",
[[package]]
name = "cranelift-object"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eef0b4119b645b870a43a036d76c0ada3a076b1f82e8b8487659304c8b09049b"
+checksum = "39793c550f0c1d7db96c2fc1324583670c8143befe6edbfbaf1c68aba53be983"
dependencies = [
"anyhow",
"cranelift-codegen",
"cfg-if",
]
+[[package]]
+name = "fallible-iterator"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+
[[package]]
name = "fxhash"
version = "0.2.1"
[[package]]
name = "getrandom"
-version = "0.2.7"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
+checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if",
"libc",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
dependencies = [
+ "fallible-iterator",
"indexmap",
+ "stable_deref_trait",
]
[[package]]
[[package]]
name = "indexmap"
-version = "1.9.1"
+version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
+checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
[[package]]
name = "libc"
-version = "0.2.127"
+version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b"
+checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
[[package]]
name = "libloading"
-version = "0.7.3"
+version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
[[package]]
name = "once_cell"
-version = "1.13.0"
+version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "regalloc2"
-version = "0.3.2"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d43a209257d978ef079f3d446331d0f1794f5e0fc19b306a199983857833a779"
+checksum = "91b2eab54204ea0117fe9a060537e0b07a4e72f7c7d182361ecc346cab2240e5"
dependencies = [
"fxhash",
"log",
[[package]]
name = "smallvec"
-version = "1.9.0"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "target-lexicon"
-version = "0.12.4"
+version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1"
+checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d"
[[package]]
name = "version_check"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+[[package]]
+name = "wasmtime-jit-icache-coherence"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6bbabb309c06cc238ee91b1455b748c45f0bdcab0dda2c2db85b0a1e69fcb66"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "windows-sys",
+]
+
[[package]]
name = "winapi"
version = "0.3.9"
version = "0.1.0"
edition = "2021"
+[[bin]]
+# This is used just to teach rust-analyzer how to check the build system. required-features is used
+# to disable it for regular builds.
+name = "y"
+path = "./y.rs"
+required-features = ["__check_build_system_using_ra"]
+
[lib]
crate-type = ["dylib"]
[dependencies]
# These have to be in sync with each other
-cranelift-codegen = { version = "0.88.1", features = ["unwind", "all-arch"] }
-cranelift-frontend = "0.88.1"
-cranelift-module = "0.88.1"
-cranelift-native = "0.88.1"
-cranelift-jit = { version = "0.88.1", optional = true }
-cranelift-object = "0.88.1"
+cranelift-codegen = { version = "0.90.1", features = ["unwind", "all-arch"] }
+cranelift-frontend = "0.90.1"
+cranelift-module = "0.90.1"
+cranelift-native = "0.90.1"
+cranelift-jit = { version = "0.90.1", optional = true }
+cranelift-object = "0.90.1"
target-lexicon = "0.12.0"
gimli = { version = "0.26.0", default-features = false, features = ["write"]}
object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
unstable-features = ["jit", "inline_asm"]
jit = ["cranelift-jit", "libloading"]
inline_asm = []
+__check_build_system_using_ra = []
[package.metadata.rust-analyzer]
rustc_private = true
In the directory with your project (where you can do the usual `cargo build`), run:
```bash
-$ $cg_clif_dir/build/cargo-clif build
+$ $cg_clif_dir/dist/cargo-clif build
```
This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend.
[[package]]
name = "addr2line"
-version = "0.16.0"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
+checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
dependencies = [
"compiler_builtins",
"gimli",
"core",
]
-[[package]]
-name = "autocfg"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-
[[package]]
name = "cc"
-version = "1.0.73"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
-
-[[package]]
-name = "cfg-if"
-version = "0.1.10"
+version = "1.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
+checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
[[package]]
name = "cfg-if"
[[package]]
name = "compiler_builtins"
-version = "0.1.82"
+version = "0.1.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18cd7635fea7bb481ea543b392789844c1ad581299da70184c7175ce3af76603"
+checksum = "13e81c6cd7ab79f51a0c927d22858d61ad12bd0b3865f0b13ece02a4486aeabb"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "gimli"
-version = "0.25.0"
+version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
+checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
[[package]]
name = "libc"
-version = "0.2.135"
+version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
+checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "miniz_oxide"
-version = "0.4.4"
+version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
+checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
dependencies = [
"adler",
- "autocfg",
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
[[package]]
name = "object"
-version = "0.26.2"
+version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
+checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
dependencies = [
"compiler_builtins",
"memchr",
version = "0.0.0"
dependencies = [
"alloc",
- "cfg-if 0.1.10",
+ "cfg-if",
"compiler_builtins",
"core",
"libc",
version = "0.0.0"
dependencies = [
"alloc",
- "cfg-if 0.1.10",
+ "cfg-if",
"compiler_builtins",
"core",
"libc",
dependencies = [
"addr2line",
"alloc",
- "cfg-if 1.0.0",
+ "cfg-if",
"compiler_builtins",
"core",
"dlmalloc",
name = "std_detect"
version = "0.1.5"
dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
"compiler_builtins",
"libc",
"rustc-std-workspace-alloc",
name = "test"
version = "0.0.0"
dependencies = [
- "cfg-if 0.1.10",
+ "cfg-if",
"core",
"getopts",
"libc",
version = "0.0.0"
dependencies = [
"cc",
- "cfg-if 0.1.10",
+ "cfg-if",
"compiler_builtins",
"core",
"libc",
-use std::env;
use std::path::Path;
use super::build_sysroot;
use super::config;
-use super::prepare;
-use super::utils::{cargo_command, spawn_and_wait};
+use super::path::Dirs;
+use super::prepare::GitRepo;
+use super::utils::{spawn_and_wait, CargoProject, Compiler};
use super::SysrootKind;
+pub(crate) static ABI_CAFE_REPO: GitRepo =
+ GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe");
+
+static ABI_CAFE: CargoProject = CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe");
+
pub(crate) fn run(
channel: &str,
sysroot_kind: SysrootKind,
- target_dir: &Path,
+ dirs: &Dirs,
cg_clif_dylib: &Path,
host_triple: &str,
target_triple: &str,
eprintln!("Building sysroot for abi-cafe");
build_sysroot::build_sysroot(
+ dirs,
channel,
sysroot_kind,
- target_dir,
cg_clif_dylib,
host_triple,
target_triple,
);
eprintln!("Running abi-cafe");
- let abi_cafe_path = prepare::ABI_CAFE.source_dir();
- env::set_current_dir(abi_cafe_path.clone()).unwrap();
let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"];
- let mut cmd = cargo_command("cargo", "run", Some(target_triple), &abi_cafe_path);
+ let mut cmd = ABI_CAFE.run(&Compiler::host(), dirs);
cmd.arg("--");
cmd.arg("--pairs");
cmd.args(pairs);
cmd.arg("--add-rustc-codegen-backend");
cmd.arg(format!("cgclif:{}", cg_clif_dylib.display()));
+ cmd.current_dir(ABI_CAFE.source_dir(dirs));
spawn_and_wait(cmd);
}
use std::env;
use std::path::PathBuf;
+use super::path::{Dirs, RelPath};
use super::rustc_info::get_file_name;
-use super::utils::{cargo_command, is_ci};
+use super::utils::{is_ci, CargoProject, Compiler};
+
+static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif");
pub(crate) fn build_backend(
+ dirs: &Dirs,
channel: &str,
host_triple: &str,
use_unstable_features: bool,
) -> PathBuf {
- let source_dir = std::env::current_dir().unwrap();
- let mut cmd = cargo_command("cargo", "build", Some(host_triple), &source_dir);
+ let mut cmd = CG_CLIF.build(&Compiler::host(), dirs);
cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode
eprintln!("[BUILD] rustc_codegen_cranelift");
super::utils::spawn_and_wait(cmd);
- source_dir
- .join("target")
+ CG_CLIF
+ .target_dir(dirs)
.join(host_triple)
.join(channel)
.join(get_file_name("rustc_codegen_cranelift", "dylib"))
use std::fs;
-use std::path::{Path, PathBuf};
+use std::path::Path;
use std::process::{self, Command};
+use super::path::{Dirs, RelPath};
use super::rustc_info::{get_file_name, get_rustc_version, get_wrapper_file_name};
-use super::utils::{cargo_command, spawn_and_wait, try_hard_link};
+use super::utils::{spawn_and_wait, try_hard_link, CargoProject, Compiler};
use super::SysrootKind;
+static DIST_DIR: RelPath = RelPath::DIST;
+static BIN_DIR: RelPath = RelPath::DIST.join("bin");
+static LIB_DIR: RelPath = RelPath::DIST.join("lib");
+static RUSTLIB_DIR: RelPath = LIB_DIR.join("rustlib");
+
pub(crate) fn build_sysroot(
+ dirs: &Dirs,
channel: &str,
sysroot_kind: SysrootKind,
- target_dir: &Path,
cg_clif_dylib_src: &Path,
host_triple: &str,
target_triple: &str,
) {
eprintln!("[BUILD] sysroot {:?}", sysroot_kind);
- if target_dir.exists() {
- fs::remove_dir_all(target_dir).unwrap();
- }
- fs::create_dir_all(target_dir.join("bin")).unwrap();
- fs::create_dir_all(target_dir.join("lib")).unwrap();
+ DIST_DIR.ensure_fresh(dirs);
+ BIN_DIR.ensure_exists(dirs);
+ LIB_DIR.ensure_exists(dirs);
// Copy the backend
- let cg_clif_dylib_path = target_dir
- .join(if cfg!(windows) {
- // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
- // binaries.
- "bin"
- } else {
- "lib"
- })
- .join(get_file_name("rustc_codegen_cranelift", "dylib"));
+ let cg_clif_dylib_path = if cfg!(windows) {
+ // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
+ // binaries.
+ BIN_DIR
+ } else {
+ LIB_DIR
+ }
+ .to_path(dirs)
+ .join(get_file_name("rustc_codegen_cranelift", "dylib"));
try_hard_link(cg_clif_dylib_src, &cg_clif_dylib_path);
// Build and copy rustc and cargo wrappers
- for wrapper in ["rustc-clif", "cargo-clif"] {
+ for wrapper in ["rustc-clif", "rustdoc-clif", "cargo-clif"] {
let wrapper_name = get_wrapper_file_name(wrapper, "bin");
let mut build_cargo_wrapper_cmd = Command::new("rustc");
build_cargo_wrapper_cmd
- .arg(PathBuf::from("scripts").join(format!("{wrapper}.rs")))
+ .arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs")))
.arg("-o")
- .arg(target_dir.join(wrapper_name))
+ .arg(DIST_DIR.to_path(dirs).join(wrapper_name))
.arg("-g");
spawn_and_wait(build_cargo_wrapper_cmd);
}
let default_sysroot = super::rustc_info::get_default_sysroot();
- let rustlib = target_dir.join("lib").join("rustlib");
- let host_rustlib_lib = rustlib.join(host_triple).join("lib");
- let target_rustlib_lib = rustlib.join(target_triple).join("lib");
+ let host_rustlib_lib = RUSTLIB_DIR.to_path(dirs).join(host_triple).join("lib");
+ let target_rustlib_lib = RUSTLIB_DIR.to_path(dirs).join(target_triple).join("lib");
fs::create_dir_all(&host_rustlib_lib).unwrap();
fs::create_dir_all(&target_rustlib_lib).unwrap();
}
}
SysrootKind::Clif => {
- build_clif_sysroot_for_triple(
- channel,
- target_dir,
- host_triple,
- &cg_clif_dylib_path,
- None,
- );
+ build_clif_sysroot_for_triple(dirs, channel, host_triple, &cg_clif_dylib_path, None);
if host_triple != target_triple {
// When cross-compiling it is often necessary to manually pick the right linker
- let linker = if target_triple == "aarch64-unknown-linux-gnu" {
- Some("aarch64-linux-gnu-gcc")
- } else {
- None
+ let linker = match target_triple {
+ "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu-gcc"),
+ "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu-gcc"),
+ _ => None,
};
build_clif_sysroot_for_triple(
+ dirs,
channel,
- target_dir,
target_triple,
&cg_clif_dylib_path,
linker,
let file = file.unwrap().path();
let filename = file.file_name().unwrap().to_str().unwrap();
if filename.contains("std-") && !filename.contains(".rlib") {
- try_hard_link(&file, target_dir.join("lib").join(file.file_name().unwrap()));
+ try_hard_link(&file, LIB_DIR.to_path(dirs).join(file.file_name().unwrap()));
}
}
}
}
}
+// FIXME move to download/ or dist/
+pub(crate) static SYSROOT_RUSTC_VERSION: RelPath = RelPath::BUILD_SYSROOT.join("rustc_version");
+pub(crate) static SYSROOT_SRC: RelPath = RelPath::BUILD_SYSROOT.join("sysroot_src");
+static STANDARD_LIBRARY: CargoProject = CargoProject::new(&RelPath::BUILD_SYSROOT, "build_sysroot");
+
fn build_clif_sysroot_for_triple(
+ dirs: &Dirs,
channel: &str,
- target_dir: &Path,
triple: &str,
cg_clif_dylib_path: &Path,
linker: Option<&str>,
) {
- match fs::read_to_string(Path::new("build_sysroot").join("rustc_version")) {
+ match fs::read_to_string(SYSROOT_RUSTC_VERSION.to_path(dirs)) {
Err(e) => {
eprintln!("Failed to get rustc version for patched sysroot source: {}", e);
eprintln!("Hint: Try `./y.rs prepare` to patch the sysroot source");
}
}
- let build_dir = Path::new("build_sysroot").join("target").join(triple).join(channel);
+ let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(triple).join(channel);
if !super::config::get_bool("keep_sysroot") {
// Cleanup the deps dir, but keep build scripts and the incremental cache for faster
}
// Build sysroot
- let mut build_cmd = cargo_command("cargo", "build", Some(triple), Path::new("build_sysroot"));
let mut rustflags = "-Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
rustflags.push_str(&format!(" -Zcodegen-backend={}", cg_clif_dylib_path.to_str().unwrap()));
- rustflags.push_str(&format!(" --sysroot={}", target_dir.to_str().unwrap()));
+ rustflags.push_str(&format!(" --sysroot={}", DIST_DIR.to_path(dirs).to_str().unwrap()));
if channel == "release" {
- build_cmd.arg("--release");
rustflags.push_str(" -Zmir-opt-level=3");
}
if let Some(linker) = linker {
use std::fmt::Write;
write!(rustflags, " -Clinker={}", linker).unwrap();
}
- build_cmd.env("RUSTFLAGS", rustflags);
+ let mut compiler = Compiler::with_triple(triple.to_owned());
+ compiler.rustflags = rustflags;
+ let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
+ if channel == "release" {
+ build_cmd.arg("--release");
+ }
build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
spawn_and_wait(build_cmd);
// Copy all relevant files to the sysroot
- for entry in
- fs::read_dir(Path::new("build_sysroot/target").join(triple).join(channel).join("deps"))
- .unwrap()
- {
+ for entry in fs::read_dir(build_dir.join("deps")).unwrap() {
let entry = entry.unwrap();
if let Some(ext) = entry.path().extension() {
if ext == "rmeta" || ext == "d" || ext == "dSYM" || ext == "clif" {
};
try_hard_link(
entry.path(),
- target_dir.join("lib").join("rustlib").join(triple).join("lib").join(entry.file_name()),
+ RUSTLIB_DIR.to_path(dirs).join(triple).join("lib").join(entry.file_name()),
);
}
}
mod build_backend;
mod build_sysroot;
mod config;
+mod path;
mod prepare;
mod rustc_info;
mod tests;
mod utils;
+const USAGE: &str = r#"The build system of cg_clif.
+
+USAGE:
+ ./y.rs prepare [--out-dir DIR]
+ ./y.rs build [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
+ ./y.rs test [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
+
+OPTIONS:
+ --sysroot none|clif|llvm
+ Which sysroot libraries to use:
+ `none` will not include any standard library in the sysroot.
+ `clif` will build the standard library using Cranelift.
+ `llvm` will use the pre-compiled standard library of rustc which is compiled with LLVM.
+
+ --out-dir DIR
+ Specify the directory in which the download, build and dist directories are stored.
+ By default this is the working directory.
+
+ --no-unstable-features
+ fSome features are not yet ready for production usage. This option will disable these
+ features. This includes the JIT mode and inline assembly support.
+"#;
+
fn usage() {
- eprintln!("Usage:");
- eprintln!(" ./y.rs prepare");
- eprintln!(
- " ./y.rs build [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--no-unstable-features]"
- );
- eprintln!(
- " ./y.rs test [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--no-unstable-features]"
- );
+ eprintln!("{USAGE}");
}
macro_rules! arg_error {
#[derive(PartialEq, Debug)]
enum Command {
+ Prepare,
Build,
Test,
}
pub fn main() {
env::set_var("CG_CLIF_DISPLAY_CG_TIME", "1");
env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1");
- // The target dir is expected in the default location. Guard against the user changing it.
- env::set_var("CARGO_TARGET_DIR", "target");
if is_ci() {
// Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
let mut args = env::args().skip(1);
let command = match args.next().as_deref() {
- Some("prepare") => {
- if args.next().is_some() {
- arg_error!("./y.rs prepare doesn't expect arguments");
- }
- prepare::prepare();
- process::exit(0);
- }
+ Some("prepare") => Command::Prepare,
Some("build") => Command::Build,
Some("test") => Command::Test,
Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
}
};
- let mut target_dir = PathBuf::from("build");
+ let mut out_dir = PathBuf::from(".");
let mut channel = "release";
let mut sysroot_kind = SysrootKind::Clif;
let mut use_unstable_features = true;
while let Some(arg) = args.next().as_deref() {
match arg {
- "--target-dir" => {
- target_dir = PathBuf::from(args.next().unwrap_or_else(|| {
- arg_error!("--target-dir requires argument");
+ "--out-dir" => {
+ out_dir = PathBuf::from(args.next().unwrap_or_else(|| {
+ arg_error!("--out-dir requires argument");
}))
}
"--debug" => channel = "debug",
arg => arg_error!("Unexpected argument {}", arg),
}
}
- target_dir = std::env::current_dir().unwrap().join(target_dir);
let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") {
host_triple
host_triple.clone()
};
- let cg_clif_dylib = build_backend::build_backend(channel, &host_triple, use_unstable_features);
+ // FIXME allow changing the location of these dirs using cli arguments
+ let current_dir = std::env::current_dir().unwrap();
+ out_dir = current_dir.join(out_dir);
+ let dirs = path::Dirs {
+ source_dir: current_dir.clone(),
+ download_dir: out_dir.join("download"),
+ build_dir: out_dir.join("build"),
+ dist_dir: out_dir.join("dist"),
+ };
+
+ path::RelPath::BUILD.ensure_exists(&dirs);
+
+ {
+ // Make sure we always explicitly specify the target dir
+ let target =
+ path::RelPath::BUILD.join("target_dir_should_be_set_explicitly").to_path(&dirs);
+ env::set_var("CARGO_TARGET_DIR", &target);
+ let _ = std::fs::remove_file(&target);
+ std::fs::File::create(target).unwrap();
+ }
+
+ if command == Command::Prepare {
+ prepare::prepare(&dirs);
+ process::exit(0);
+ }
+
+ let cg_clif_dylib =
+ build_backend::build_backend(&dirs, channel, &host_triple, use_unstable_features);
match command {
+ Command::Prepare => {
+ // Handled above
+ }
Command::Test => {
tests::run_tests(
+ &dirs,
channel,
sysroot_kind,
- &target_dir,
&cg_clif_dylib,
&host_triple,
&target_triple,
abi_cafe::run(
channel,
sysroot_kind,
- &target_dir,
+ &dirs,
&cg_clif_dylib,
&host_triple,
&target_triple,
}
Command::Build => {
build_sysroot::build_sysroot(
+ &dirs,
channel,
sysroot_kind,
- &target_dir,
&cg_clif_dylib,
&host_triple,
&target_triple,
--- /dev/null
+use std::fs;
+use std::path::PathBuf;
+
+#[derive(Debug, Clone)]
+pub(crate) struct Dirs {
+ pub(crate) source_dir: PathBuf,
+ pub(crate) download_dir: PathBuf,
+ pub(crate) build_dir: PathBuf,
+ pub(crate) dist_dir: PathBuf,
+}
+
+#[doc(hidden)]
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum PathBase {
+ Source,
+ Download,
+ Build,
+ Dist,
+}
+
+impl PathBase {
+ fn to_path(self, dirs: &Dirs) -> PathBuf {
+ match self {
+ PathBase::Source => dirs.source_dir.clone(),
+ PathBase::Download => dirs.download_dir.clone(),
+ PathBase::Build => dirs.build_dir.clone(),
+ PathBase::Dist => dirs.dist_dir.clone(),
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum RelPath {
+ Base(PathBase),
+ Join(&'static RelPath, &'static str),
+}
+
+impl RelPath {
+ pub(crate) const SOURCE: RelPath = RelPath::Base(PathBase::Source);
+ pub(crate) const DOWNLOAD: RelPath = RelPath::Base(PathBase::Download);
+ pub(crate) const BUILD: RelPath = RelPath::Base(PathBase::Build);
+ pub(crate) const DIST: RelPath = RelPath::Base(PathBase::Dist);
+
+ pub(crate) const SCRIPTS: RelPath = RelPath::SOURCE.join("scripts");
+ pub(crate) const BUILD_SYSROOT: RelPath = RelPath::SOURCE.join("build_sysroot");
+ pub(crate) const PATCHES: RelPath = RelPath::SOURCE.join("patches");
+
+ pub(crate) const fn join(&'static self, suffix: &'static str) -> RelPath {
+ RelPath::Join(self, suffix)
+ }
+
+ pub(crate) fn to_path(&self, dirs: &Dirs) -> PathBuf {
+ match self {
+ RelPath::Base(base) => base.to_path(dirs),
+ RelPath::Join(base, suffix) => base.to_path(dirs).join(suffix),
+ }
+ }
+
+ pub(crate) fn ensure_exists(&self, dirs: &Dirs) {
+ fs::create_dir_all(self.to_path(dirs)).unwrap();
+ }
+
+ pub(crate) fn ensure_fresh(&self, dirs: &Dirs) {
+ let path = self.to_path(dirs);
+ if path.exists() {
+ fs::remove_dir_all(&path).unwrap();
+ }
+ fs::create_dir_all(path).unwrap();
+ }
+}
-use std::env;
use std::ffi::OsStr;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
+use super::build_sysroot::{SYSROOT_RUSTC_VERSION, SYSROOT_SRC};
+use super::path::{Dirs, RelPath};
use super::rustc_info::{get_file_name, get_rustc_path, get_rustc_version};
-use super::utils::{cargo_command, copy_dir_recursively, spawn_and_wait};
-
-pub(crate) const ABI_CAFE: GitRepo =
- GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe");
-
-pub(crate) const RAND: GitRepo =
- GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand");
-
-pub(crate) const REGEX: GitRepo =
- GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
-
-pub(crate) const PORTABLE_SIMD: GitRepo = GitRepo::github(
- "rust-lang",
- "portable-simd",
- "d5cd4a8112d958bd3a252327e0d069a6363249bd",
- "portable-simd",
-);
-
-pub(crate) const SIMPLE_RAYTRACER: GitRepo = GitRepo::github(
- "ebobby",
- "simple-raytracer",
- "804a7a21b9e673a482797aa289a18ed480e4d813",
- "<none>",
-);
-
-pub(crate) fn prepare() {
- if Path::new("download").exists() {
- std::fs::remove_dir_all(Path::new("download")).unwrap();
+use super::utils::{copy_dir_recursively, spawn_and_wait, Compiler};
+
+pub(crate) fn prepare(dirs: &Dirs) {
+ if RelPath::DOWNLOAD.to_path(dirs).exists() {
+ std::fs::remove_dir_all(RelPath::DOWNLOAD.to_path(dirs)).unwrap();
}
- std::fs::create_dir_all(Path::new("download")).unwrap();
+ std::fs::create_dir_all(RelPath::DOWNLOAD.to_path(dirs)).unwrap();
- prepare_sysroot();
+ prepare_sysroot(dirs);
// FIXME maybe install this only locally?
eprintln!("[INSTALL] hyperfine");
- Command::new("cargo").arg("install").arg("hyperfine").spawn().unwrap().wait().unwrap();
+ Command::new("cargo")
+ .arg("install")
+ .arg("hyperfine")
+ .env_remove("CARGO_TARGET_DIR")
+ .spawn()
+ .unwrap()
+ .wait()
+ .unwrap();
- ABI_CAFE.fetch();
- RAND.fetch();
- REGEX.fetch();
- PORTABLE_SIMD.fetch();
- SIMPLE_RAYTRACER.fetch();
+ super::abi_cafe::ABI_CAFE_REPO.fetch(dirs);
+ super::tests::RAND_REPO.fetch(dirs);
+ super::tests::REGEX_REPO.fetch(dirs);
+ super::tests::PORTABLE_SIMD_REPO.fetch(dirs);
+ super::tests::SIMPLE_RAYTRACER_REPO.fetch(dirs);
eprintln!("[LLVM BUILD] simple-raytracer");
- let build_cmd = cargo_command("cargo", "build", None, &SIMPLE_RAYTRACER.source_dir());
+ let host_compiler = Compiler::host();
+ let build_cmd = super::tests::SIMPLE_RAYTRACER.build(&host_compiler, dirs);
spawn_and_wait(build_cmd);
fs::copy(
- SIMPLE_RAYTRACER
- .source_dir()
- .join("target")
+ super::tests::SIMPLE_RAYTRACER
+ .target_dir(dirs)
+ .join(&host_compiler.triple)
.join("debug")
.join(get_file_name("main", "bin")),
- SIMPLE_RAYTRACER.source_dir().join(get_file_name("raytracer_cg_llvm", "bin")),
+ RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_llvm", "bin")),
)
.unwrap();
}
-fn prepare_sysroot() {
+fn prepare_sysroot(dirs: &Dirs) {
let rustc_path = get_rustc_path();
let sysroot_src_orig = rustc_path.parent().unwrap().join("../lib/rustlib/src/rust");
- let sysroot_src = env::current_dir().unwrap().join("build_sysroot").join("sysroot_src");
+ let sysroot_src = SYSROOT_SRC;
assert!(sysroot_src_orig.exists());
- if sysroot_src.exists() {
- fs::remove_dir_all(&sysroot_src).unwrap();
- }
- fs::create_dir_all(sysroot_src.join("library")).unwrap();
+ sysroot_src.ensure_fresh(dirs);
+ fs::create_dir_all(sysroot_src.to_path(dirs).join("library")).unwrap();
eprintln!("[COPY] sysroot src");
- copy_dir_recursively(&sysroot_src_orig.join("library"), &sysroot_src.join("library"));
+ copy_dir_recursively(
+ &sysroot_src_orig.join("library"),
+ &sysroot_src.to_path(dirs).join("library"),
+ );
let rustc_version = get_rustc_version();
- fs::write(Path::new("build_sysroot").join("rustc_version"), &rustc_version).unwrap();
+ fs::write(SYSROOT_RUSTC_VERSION.to_path(dirs), &rustc_version).unwrap();
eprintln!("[GIT] init");
- let mut git_init_cmd = Command::new("git");
- git_init_cmd.arg("init").arg("-q").current_dir(&sysroot_src);
- spawn_and_wait(git_init_cmd);
-
- init_git_repo(&sysroot_src);
+ init_git_repo(&sysroot_src.to_path(dirs));
- apply_patches("sysroot", &sysroot_src);
+ apply_patches(dirs, "sysroot", &sysroot_src.to_path(dirs));
}
pub(crate) struct GitRepo {
}
impl GitRepo {
- const fn github(
+ pub(crate) const fn github(
user: &'static str,
repo: &'static str,
rev: &'static str,
GitRepo { url: GitRepoUrl::Github { user, repo }, rev, patch_name }
}
- pub(crate) fn source_dir(&self) -> PathBuf {
+ pub(crate) const fn source_dir(&self) -> RelPath {
match self.url {
- GitRepoUrl::Github { user: _, repo } => {
- std::env::current_dir().unwrap().join("download").join(repo)
- }
+ GitRepoUrl::Github { user: _, repo } => RelPath::DOWNLOAD.join(repo),
}
}
- fn fetch(&self) {
+ fn fetch(&self, dirs: &Dirs) {
match self.url {
GitRepoUrl::Github { user, repo } => {
- clone_repo_shallow_github(&self.source_dir(), user, repo, self.rev);
+ clone_repo_shallow_github(
+ dirs,
+ &self.source_dir().to_path(dirs),
+ user,
+ repo,
+ self.rev,
+ );
}
}
- apply_patches(self.patch_name, &self.source_dir());
+ apply_patches(dirs, self.patch_name, &self.source_dir().to_path(dirs));
}
}
spawn_and_wait(checkout_cmd);
}
-fn clone_repo_shallow_github(download_dir: &Path, user: &str, repo: &str, rev: &str) {
+fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo: &str, rev: &str) {
if cfg!(windows) {
// Older windows doesn't have tar or curl by default. Fall back to using git.
clone_repo(download_dir, &format!("https://github.com/{}/{}.git", user, repo), rev);
return;
}
- let downloads_dir = std::env::current_dir().unwrap().join("download");
-
let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", user, repo, rev);
- let archive_file = downloads_dir.join(format!("{}.tar.gz", rev));
- let archive_dir = downloads_dir.join(format!("{}-{}", repo, rev));
+ let archive_file = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}.tar.gz", rev));
+ let archive_dir = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}-{}", repo, rev));
eprintln!("[DOWNLOAD] {}/{} from {}", user, repo, archive_url);
// Unpack tar archive
let mut unpack_cmd = Command::new("tar");
- unpack_cmd.arg("xf").arg(&archive_file).current_dir(downloads_dir);
+ unpack_cmd.arg("xf").arg(&archive_file).current_dir(RelPath::DOWNLOAD.to_path(dirs));
spawn_and_wait(unpack_cmd);
// Rename unpacked dir to the expected name
spawn_and_wait(git_add_cmd);
let mut git_commit_cmd = Command::new("git");
- git_commit_cmd.arg("commit").arg("-m").arg("Initial commit").arg("-q").current_dir(repo_dir);
+ git_commit_cmd
+ .arg("-c")
+ .arg("user.name=Dummy")
+ .arg("-c")
+ .arg("user.email=dummy@example.com")
+ .arg("commit")
+ .arg("-m")
+ .arg("Initial commit")
+ .arg("-q")
+ .current_dir(repo_dir);
spawn_and_wait(git_commit_cmd);
}
-fn get_patches(source_dir: &Path, crate_name: &str) -> Vec<PathBuf> {
- let mut patches: Vec<_> = fs::read_dir(source_dir.join("patches"))
+fn get_patches(dirs: &Dirs, crate_name: &str) -> Vec<PathBuf> {
+ let mut patches: Vec<_> = fs::read_dir(RelPath::PATCHES.to_path(dirs))
.unwrap()
.map(|entry| entry.unwrap().path())
.filter(|path| path.extension() == Some(OsStr::new("patch")))
patches
}
-fn apply_patches(crate_name: &str, target_dir: &Path) {
+fn apply_patches(dirs: &Dirs, crate_name: &str, target_dir: &Path) {
if crate_name == "<none>" {
return;
}
- for patch in get_patches(&std::env::current_dir().unwrap(), crate_name) {
+ for patch in get_patches(dirs, crate_name) {
eprintln!(
"[PATCH] {:?} <- {:?}",
target_dir.file_name().unwrap(),
patch.file_name().unwrap()
);
let mut apply_patch_cmd = Command::new("git");
- apply_patch_cmd.arg("am").arg(patch).arg("-q").current_dir(target_dir);
+ apply_patch_cmd
+ .arg("-c")
+ .arg("user.name=Dummy")
+ .arg("-c")
+ .arg("user.email=dummy@example.com")
+ .arg("am")
+ .arg(patch)
+ .arg("-q")
+ .current_dir(target_dir);
spawn_and_wait(apply_patch_cmd);
}
}
.to_owned()
}
+pub(crate) fn get_cargo_path() -> PathBuf {
+ let cargo_path = Command::new("rustup")
+ .stderr(Stdio::inherit())
+ .args(&["which", "cargo"])
+ .output()
+ .unwrap()
+ .stdout;
+ Path::new(String::from_utf8(cargo_path).unwrap().trim()).to_owned()
+}
+
pub(crate) fn get_rustc_path() -> PathBuf {
let rustc_path = Command::new("rustup")
.stderr(Stdio::inherit())
Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned()
}
+pub(crate) fn get_rustdoc_path() -> PathBuf {
+ let rustc_path = Command::new("rustup")
+ .stderr(Stdio::inherit())
+ .args(&["which", "rustdoc"])
+ .output()
+ .unwrap()
+ .stdout;
+ Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned()
+}
+
pub(crate) fn get_default_sysroot() -> PathBuf {
let default_sysroot = Command::new("rustc")
.stderr(Stdio::inherit())
use super::build_sysroot;
use super::config;
-use super::prepare;
-use super::rustc_info::get_wrapper_file_name;
-use super::utils::{cargo_command, hyperfine_command, spawn_and_wait, spawn_and_wait_with_input};
-use build_system::SysrootKind;
+use super::path::{Dirs, RelPath};
+use super::prepare::GitRepo;
+use super::rustc_info::{get_cargo_path, get_wrapper_file_name};
+use super::utils::{
+ hyperfine_command, spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler,
+};
+use super::SysrootKind;
use std::env;
use std::ffi::OsStr;
use std::fs;
-use std::path::{Path, PathBuf};
+use std::path::Path;
use std::process::Command;
+static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example");
+
struct TestCase {
config: &'static str,
func: &'static dyn Fn(&TestRunner),
"--crate-type",
"lib,dylib",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
}),
TestCase::new("build.example", &|runner| {
"--crate-type",
"lib",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
}),
TestCase::new("jit.mini_core_hello_world", &|runner| {
"--cfg",
"jit",
"--target",
- &runner.host_triple,
+ &runner.target_compiler.triple,
]);
jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
spawn_and_wait(jit_cmd);
"--cfg",
"jit",
"--target",
- &runner.host_triple,
+ &runner.target_compiler.triple,
]);
jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
spawn_and_wait(jit_cmd);
"bin",
"-g",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("mini_core_hello_world", ["abc", "bcd"]);
}),
"--crate-type",
"bin",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("arbitrary_self_types_pointers_and_wrappers", []);
}),
"--crate-type",
"bin",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("issue_91827_extern_types", []);
}),
"--crate-type",
"lib",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
}),
TestCase::new("aot.alloc_example", &|runner| {
"--crate-type",
"bin",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("alloc_example", []);
}),
"-Cprefer-dynamic",
"example/std_example.rs",
"--target",
- &runner.host_triple,
+ &runner.target_compiler.triple,
]);
eprintln!("[JIT-lazy] std_example");
"-Cprefer-dynamic",
"example/std_example.rs",
"--target",
- &runner.host_triple,
+ &runner.target_compiler.triple,
]);
}),
TestCase::new("aot.std_example", &|runner| {
"--crate-type",
"bin",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("std_example", ["arg"]);
}),
"--crate-type",
"bin",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("dst_field_align", []);
}),
"bin",
"-Cpanic=abort",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("subslice-patterns-const-eval", []);
}),
"bin",
"-Cpanic=abort",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("track-caller-attribute", []);
}),
"bin",
"-Cpanic=abort",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("float-minmax-pass", []);
}),
"--crate-type",
"bin",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("mod_bench", []);
}),
+ TestCase::new("aot.issue-72793", &|runner| {
+ runner.run_rustc([
+ "example/issue-72793.rs",
+ "--crate-type",
+ "bin",
+ "--target",
+ &runner.target_compiler.triple,
+ ]);
+ runner.run_out_command("issue-72793", []);
+ }),
];
+pub(crate) static RAND_REPO: GitRepo =
+ GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand");
+
+static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand");
+
+pub(crate) static REGEX_REPO: GitRepo =
+ GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
+
+static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex");
+
+pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
+ "rust-lang",
+ "portable-simd",
+ "d5cd4a8112d958bd3a252327e0d069a6363249bd",
+ "portable-simd",
+);
+
+static PORTABLE_SIMD: CargoProject =
+ CargoProject::new(&PORTABLE_SIMD_REPO.source_dir(), "portable_simd");
+
+pub(crate) static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github(
+ "ebobby",
+ "simple-raytracer",
+ "804a7a21b9e673a482797aa289a18ed480e4d813",
+ "<none>",
+);
+
+pub(crate) static SIMPLE_RAYTRACER: CargoProject =
+ CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer");
+
+static LIBCORE_TESTS: CargoProject =
+ CargoProject::new(&RelPath::BUILD_SYSROOT.join("sysroot_src/library/core/tests"), "core_tests");
+
const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
TestCase::new("test.rust-random/rand", &|runner| {
- runner.in_dir(prepare::RAND.source_dir(), |runner| {
- runner.run_cargo("clean", []);
-
- if runner.host_triple == runner.target_triple {
- eprintln!("[TEST] rust-random/rand");
- runner.run_cargo("test", ["--workspace"]);
- } else {
- eprintln!("[AOT] rust-random/rand");
- runner.run_cargo("build", ["--workspace", "--tests"]);
- }
- });
+ spawn_and_wait(RAND.clean(&runner.target_compiler.cargo, &runner.dirs));
+
+ if runner.is_native {
+ eprintln!("[TEST] rust-random/rand");
+ let mut test_cmd = RAND.test(&runner.target_compiler, &runner.dirs);
+ test_cmd.arg("--workspace");
+ spawn_and_wait(test_cmd);
+ } else {
+ eprintln!("[AOT] rust-random/rand");
+ let mut build_cmd = RAND.build(&runner.target_compiler, &runner.dirs);
+ build_cmd.arg("--workspace").arg("--tests");
+ spawn_and_wait(build_cmd);
+ }
}),
TestCase::new("bench.simple-raytracer", &|runner| {
- runner.in_dir(prepare::SIMPLE_RAYTRACER.source_dir(), |runner| {
- let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()).parse().unwrap();
-
- if runner.host_triple == runner.target_triple {
- eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
- let prepare = runner.cargo_command("clean", []);
-
- let llvm_build_cmd = cargo_command("cargo", "build", None, Path::new("."));
-
- let cargo_clif = runner
- .root_dir
- .clone()
- .join("build")
- .join(get_wrapper_file_name("cargo-clif", "bin"));
- let clif_build_cmd = cargo_command(cargo_clif, "build", None, Path::new("."));
-
- let bench_compile =
- hyperfine_command(1, run_runs, Some(prepare), llvm_build_cmd, clif_build_cmd);
-
- spawn_and_wait(bench_compile);
-
- eprintln!("[BENCH RUN] ebobby/simple-raytracer");
- fs::copy(PathBuf::from("./target/debug/main"), PathBuf::from("raytracer_cg_clif"))
- .unwrap();
-
- let bench_run = hyperfine_command(
- 0,
- run_runs,
- None,
- Command::new("./raytracer_cg_llvm"),
- Command::new("./raytracer_cg_clif"),
- );
- spawn_and_wait(bench_run);
- } else {
- runner.run_cargo("clean", []);
- eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)");
- eprintln!("[COMPILE] ebobby/simple-raytracer");
- runner.run_cargo("build", []);
- eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)");
- }
- });
+ let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()).parse().unwrap();
+
+ if runner.is_native {
+ eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
+ let cargo_clif = RelPath::DIST
+ .to_path(&runner.dirs)
+ .join(get_wrapper_file_name("cargo-clif", "bin"));
+ let manifest_path = SIMPLE_RAYTRACER.manifest_path(&runner.dirs);
+ let target_dir = SIMPLE_RAYTRACER.target_dir(&runner.dirs);
+
+ let clean_cmd = format!(
+ "cargo clean --manifest-path {manifest_path} --target-dir {target_dir}",
+ manifest_path = manifest_path.display(),
+ target_dir = target_dir.display(),
+ );
+ let llvm_build_cmd = format!(
+ "cargo build --manifest-path {manifest_path} --target-dir {target_dir}",
+ manifest_path = manifest_path.display(),
+ target_dir = target_dir.display(),
+ );
+ let clif_build_cmd = format!(
+ "{cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir}",
+ cargo_clif = cargo_clif.display(),
+ manifest_path = manifest_path.display(),
+ target_dir = target_dir.display(),
+ );
+
+ let bench_compile =
+ hyperfine_command(1, run_runs, Some(&clean_cmd), &llvm_build_cmd, &clif_build_cmd);
+
+ spawn_and_wait(bench_compile);
+
+ eprintln!("[BENCH RUN] ebobby/simple-raytracer");
+ fs::copy(
+ target_dir.join("debug").join("main"),
+ RelPath::BUILD.to_path(&runner.dirs).join("raytracer_cg_clif"),
+ )
+ .unwrap();
+
+ let mut bench_run =
+ hyperfine_command(0, run_runs, None, "./raytracer_cg_llvm", "./raytracer_cg_clif");
+ bench_run.current_dir(RelPath::BUILD.to_path(&runner.dirs));
+ spawn_and_wait(bench_run);
+ } else {
+ spawn_and_wait(SIMPLE_RAYTRACER.clean(&runner.target_compiler.cargo, &runner.dirs));
+ eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)");
+ eprintln!("[COMPILE] ebobby/simple-raytracer");
+ spawn_and_wait(SIMPLE_RAYTRACER.build(&runner.target_compiler, &runner.dirs));
+ eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)");
+ }
}),
TestCase::new("test.libcore", &|runner| {
- runner.in_dir(
- std::env::current_dir()
- .unwrap()
- .join("build_sysroot")
- .join("sysroot_src")
- .join("library")
- .join("core")
- .join("tests"),
- |runner| {
- runner.run_cargo("clean", []);
-
- if runner.host_triple == runner.target_triple {
- runner.run_cargo("test", []);
- } else {
- eprintln!("Cross-Compiling: Not running tests");
- runner.run_cargo("build", ["--tests"]);
- }
- },
- );
+ spawn_and_wait(LIBCORE_TESTS.clean(&runner.host_compiler.cargo, &runner.dirs));
+
+ if runner.is_native {
+ spawn_and_wait(LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs));
+ } else {
+ eprintln!("Cross-Compiling: Not running tests");
+ let mut build_cmd = LIBCORE_TESTS.build(&runner.target_compiler, &runner.dirs);
+ build_cmd.arg("--tests");
+ spawn_and_wait(build_cmd);
+ }
}),
TestCase::new("test.regex-shootout-regex-dna", &|runner| {
- runner.in_dir(prepare::REGEX.source_dir(), |runner| {
- runner.run_cargo("clean", []);
-
- // newer aho_corasick versions throw a deprecation warning
- let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
-
- let mut build_cmd = runner.cargo_command("build", ["--example", "shootout-regex-dna"]);
- build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
- spawn_and_wait(build_cmd);
-
- if runner.host_triple == runner.target_triple {
- let mut run_cmd = runner.cargo_command("run", ["--example", "shootout-regex-dna"]);
- run_cmd.env("RUSTFLAGS", lint_rust_flags);
-
- let input =
- fs::read_to_string(PathBuf::from("examples/regexdna-input.txt")).unwrap();
- let expected_path = PathBuf::from("examples/regexdna-output.txt");
- let expected = fs::read_to_string(&expected_path).unwrap();
-
- let output = spawn_and_wait_with_input(run_cmd, input);
- // Make sure `[codegen mono items] start` doesn't poison the diff
- let output = output
- .lines()
- .filter(|line| !line.contains("codegen mono items"))
- .chain(Some("")) // This just adds the trailing newline
- .collect::<Vec<&str>>()
- .join("\r\n");
-
- let output_matches = expected.lines().eq(output.lines());
- if !output_matches {
- let res_path = PathBuf::from("res.txt");
- fs::write(&res_path, &output).unwrap();
-
- if cfg!(windows) {
- println!("Output files don't match!");
- println!("Expected Output:\n{}", expected);
- println!("Actual Output:\n{}", output);
- } else {
- let mut diff = Command::new("diff");
- diff.arg("-u");
- diff.arg(res_path);
- diff.arg(expected_path);
- spawn_and_wait(diff);
- }
-
- std::process::exit(1);
+ spawn_and_wait(REGEX.clean(&runner.target_compiler.cargo, &runner.dirs));
+
+ // newer aho_corasick versions throw a deprecation warning
+ let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
+
+ let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
+ build_cmd.arg("--example").arg("shootout-regex-dna");
+ build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
+ spawn_and_wait(build_cmd);
+
+ if runner.is_native {
+ let mut run_cmd = REGEX.run(&runner.target_compiler, &runner.dirs);
+ run_cmd.arg("--example").arg("shootout-regex-dna");
+ run_cmd.env("RUSTFLAGS", lint_rust_flags);
+
+ let input = fs::read_to_string(
+ REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-input.txt"),
+ )
+ .unwrap();
+ let expected_path =
+ REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-output.txt");
+ let expected = fs::read_to_string(&expected_path).unwrap();
+
+ let output = spawn_and_wait_with_input(run_cmd, input);
+ // Make sure `[codegen mono items] start` doesn't poison the diff
+ let output = output
+ .lines()
+ .filter(|line| !line.contains("codegen mono items"))
+ .chain(Some("")) // This just adds the trailing newline
+ .collect::<Vec<&str>>()
+ .join("\r\n");
+
+ let output_matches = expected.lines().eq(output.lines());
+ if !output_matches {
+ let res_path = REGEX.source_dir(&runner.dirs).join("res.txt");
+ fs::write(&res_path, &output).unwrap();
+
+ if cfg!(windows) {
+ println!("Output files don't match!");
+ println!("Expected Output:\n{}", expected);
+ println!("Actual Output:\n{}", output);
+ } else {
+ let mut diff = Command::new("diff");
+ diff.arg("-u");
+ diff.arg(res_path);
+ diff.arg(expected_path);
+ spawn_and_wait(diff);
}
+
+ std::process::exit(1);
}
- });
+ }
}),
TestCase::new("test.regex", &|runner| {
- runner.in_dir(prepare::REGEX.source_dir(), |runner| {
- runner.run_cargo("clean", []);
-
- // newer aho_corasick versions throw a deprecation warning
- let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
-
- if runner.host_triple == runner.target_triple {
- let mut run_cmd = runner.cargo_command(
- "test",
- [
- "--tests",
- "--",
- "--exclude-should-panic",
- "--test-threads",
- "1",
- "-Zunstable-options",
- "-q",
- ],
- );
- run_cmd.env("RUSTFLAGS", lint_rust_flags);
- spawn_and_wait(run_cmd);
- } else {
- eprintln!("Cross-Compiling: Not running tests");
- let mut build_cmd =
- runner.cargo_command("build", ["--tests", "--target", &runner.target_triple]);
- build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
- spawn_and_wait(build_cmd);
- }
- });
+ spawn_and_wait(REGEX.clean(&runner.host_compiler.cargo, &runner.dirs));
+
+ // newer aho_corasick versions throw a deprecation warning
+ let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
+
+ if runner.is_native {
+ let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs);
+ run_cmd.args([
+ "--tests",
+ "--",
+ "--exclude-should-panic",
+ "--test-threads",
+ "1",
+ "-Zunstable-options",
+ "-q",
+ ]);
+ run_cmd.env("RUSTFLAGS", lint_rust_flags);
+ spawn_and_wait(run_cmd);
+ } else {
+ eprintln!("Cross-Compiling: Not running tests");
+ let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
+ build_cmd.arg("--tests");
+ build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
+ spawn_and_wait(build_cmd);
+ }
}),
TestCase::new("test.portable-simd", &|runner| {
- runner.in_dir(prepare::PORTABLE_SIMD.source_dir(), |runner| {
- runner.run_cargo("clean", []);
- runner.run_cargo("build", ["--all-targets", "--target", &runner.target_triple]);
+ spawn_and_wait(PORTABLE_SIMD.clean(&runner.host_compiler.cargo, &runner.dirs));
- if runner.host_triple == runner.target_triple {
- runner.run_cargo("test", ["-q"]);
- }
- });
+ let mut build_cmd = PORTABLE_SIMD.build(&runner.target_compiler, &runner.dirs);
+ build_cmd.arg("--all-targets");
+ spawn_and_wait(build_cmd);
+
+ if runner.is_native {
+ let mut test_cmd = PORTABLE_SIMD.test(&runner.target_compiler, &runner.dirs);
+ test_cmd.arg("-q");
+ spawn_and_wait(test_cmd);
+ }
}),
];
pub(crate) fn run_tests(
+ dirs: &Dirs,
channel: &str,
sysroot_kind: SysrootKind,
- target_dir: &Path,
cg_clif_dylib: &Path,
host_triple: &str,
target_triple: &str,
) {
- let runner = TestRunner::new(host_triple.to_string(), target_triple.to_string());
+ let runner = TestRunner::new(dirs.clone(), host_triple.to_string(), target_triple.to_string());
if config::get_bool("testsuite.no_sysroot") {
build_sysroot::build_sysroot(
+ dirs,
channel,
SysrootKind::None,
- &target_dir,
cg_clif_dylib,
&host_triple,
&target_triple,
);
- let _ = fs::remove_dir_all(Path::new("target").join("out"));
+ BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);
runner.run_testsuite(NO_SYSROOT_SUITE);
} else {
eprintln!("[SKIP] no_sysroot tests");
if run_base_sysroot || run_extended_sysroot {
build_sysroot::build_sysroot(
+ dirs,
channel,
sysroot_kind,
- &target_dir,
cg_clif_dylib,
&host_triple,
&target_triple,
}
struct TestRunner {
- root_dir: PathBuf,
- out_dir: PathBuf,
+ is_native: bool,
jit_supported: bool,
- rust_flags: String,
- run_wrapper: Vec<String>,
- host_triple: String,
- target_triple: String,
+ dirs: Dirs,
+ host_compiler: Compiler,
+ target_compiler: Compiler,
}
impl TestRunner {
- pub fn new(host_triple: String, target_triple: String) -> Self {
- let root_dir = env::current_dir().unwrap();
-
- let mut out_dir = root_dir.clone();
- out_dir.push("target");
- out_dir.push("out");
-
+ pub fn new(dirs: Dirs, host_triple: String, target_triple: String) -> Self {
let is_native = host_triple == target_triple;
let jit_supported =
target_triple.contains("x86_64") && is_native && !host_triple.contains("windows");
- let mut rust_flags = env::var("RUSTFLAGS").ok().unwrap_or("".to_string());
- let mut run_wrapper = Vec::new();
+ let rustc_clif =
+ RelPath::DIST.to_path(&dirs).join(get_wrapper_file_name("rustc-clif", "bin"));
+ let rustdoc_clif =
+ RelPath::DIST.to_path(&dirs).join(get_wrapper_file_name("rustdoc-clif", "bin"));
+
+ let mut rustflags = env::var("RUSTFLAGS").ok().unwrap_or("".to_string());
+ let mut runner = vec![];
if !is_native {
match target_triple.as_str() {
"aarch64-unknown-linux-gnu" => {
// We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
- rust_flags = format!("-Clinker=aarch64-linux-gnu-gcc{}", rust_flags);
- run_wrapper = vec!["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu"];
+ rustflags = format!("-Clinker=aarch64-linux-gnu-gcc{}", rustflags);
+ runner = vec![
+ "qemu-aarch64".to_owned(),
+ "-L".to_owned(),
+ "/usr/aarch64-linux-gnu".to_owned(),
+ ];
+ }
+ "s390x-unknown-linux-gnu" => {
+ // We are cross-compiling for s390x. Use the correct linker and run tests in qemu.
+ rustflags = format!("-Clinker=s390x-linux-gnu-gcc{}", rustflags);
+ runner = vec![
+ "qemu-s390x".to_owned(),
+ "-L".to_owned(),
+ "/usr/s390x-linux-gnu".to_owned(),
+ ];
}
"x86_64-pc-windows-gnu" => {
// We are cross-compiling for Windows. Run tests in wine.
- run_wrapper = vec!["wine"];
+ runner = vec!["wine".to_owned()];
}
_ => {
println!("Unknown non-native platform");
}
// FIXME fix `#[linkage = "extern_weak"]` without this
- if host_triple.contains("darwin") {
- rust_flags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rust_flags);
+ if target_triple.contains("darwin") {
+ rustflags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rustflags);
}
- Self {
- root_dir,
- out_dir,
- jit_supported,
- rust_flags,
- run_wrapper: run_wrapper.iter().map(|s| s.to_string()).collect(),
- host_triple,
- target_triple,
- }
+ let host_compiler = Compiler {
+ cargo: get_cargo_path(),
+ rustc: rustc_clif.clone(),
+ rustdoc: rustdoc_clif.clone(),
+ rustflags: String::new(),
+ rustdocflags: String::new(),
+ triple: host_triple,
+ runner: vec![],
+ };
+
+ let target_compiler = Compiler {
+ cargo: get_cargo_path(),
+ rustc: rustc_clif,
+ rustdoc: rustdoc_clif,
+ rustflags: rustflags.clone(),
+ rustdocflags: rustflags,
+ triple: target_triple,
+ runner,
+ };
+
+ Self { is_native, jit_supported, dirs, host_compiler, target_compiler }
}
pub fn run_testsuite(&self, tests: &[TestCase]) {
}
}
- fn in_dir(&self, new: impl AsRef<Path>, callback: impl FnOnce(&TestRunner)) {
- let current = env::current_dir().unwrap();
-
- env::set_current_dir(new).unwrap();
- callback(self);
- env::set_current_dir(current).unwrap();
- }
-
+ #[must_use]
fn rustc_command<I, S>(&self, args: I) -> Command
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
- let mut rustc_clif = self.root_dir.clone();
- rustc_clif.push("build");
- rustc_clif.push(get_wrapper_file_name("rustc-clif", "bin"));
-
- let mut cmd = Command::new(rustc_clif);
- cmd.args(self.rust_flags.split_whitespace());
+ let mut cmd = Command::new(&self.target_compiler.rustc);
+ cmd.args(self.target_compiler.rustflags.split_whitespace());
cmd.arg("-L");
- cmd.arg(format!("crate={}", self.out_dir.display()));
+ cmd.arg(format!("crate={}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
cmd.arg("--out-dir");
- cmd.arg(format!("{}", self.out_dir.display()));
+ cmd.arg(format!("{}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
cmd.arg("-Cdebuginfo=2");
cmd.args(args);
cmd
let mut full_cmd = vec![];
// Prepend the RUN_WRAPPER's
- if !self.run_wrapper.is_empty() {
- full_cmd.extend(self.run_wrapper.iter().cloned());
+ if !self.target_compiler.runner.is_empty() {
+ full_cmd.extend(self.target_compiler.runner.iter().cloned());
}
- full_cmd.push({
- let mut out_path = self.out_dir.clone();
- out_path.push(name);
- out_path.to_str().unwrap().to_string()
- });
+ full_cmd.push(
+ BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name).to_str().unwrap().to_string(),
+ );
for arg in args.into_iter() {
full_cmd.push(arg.to_string());
spawn_and_wait(cmd);
}
-
- fn cargo_command<'a, I>(&self, subcommand: &str, args: I) -> Command
- where
- I: IntoIterator<Item = &'a str>,
- {
- let mut cargo_clif = self.root_dir.clone();
- cargo_clif.push("build");
- cargo_clif.push(get_wrapper_file_name("cargo-clif", "bin"));
-
- let mut cmd = cargo_command(
- cargo_clif,
- subcommand,
- if subcommand == "clean" { None } else { Some(&self.target_triple) },
- Path::new("."),
- );
- cmd.args(args);
- cmd.env("RUSTFLAGS", &self.rust_flags);
- cmd
- }
-
- fn run_cargo<'a, I>(&self, subcommand: &str, args: I)
- where
- I: IntoIterator<Item = &'a str>,
- {
- spawn_and_wait(self.cargo_command(subcommand, args));
- }
}
use std::env;
use std::fs;
use std::io::Write;
-use std::path::Path;
+use std::path::{Path, PathBuf};
use std::process::{self, Command, Stdio};
-pub(crate) fn cargo_command(
- cargo: impl AsRef<Path>,
- subcommand: &str,
- triple: Option<&str>,
- source_dir: &Path,
-) -> Command {
- let mut cmd = Command::new(cargo.as_ref());
- cmd.arg(subcommand)
- .arg("--manifest-path")
- .arg(source_dir.join("Cargo.toml"))
- .arg("--target-dir")
- .arg(source_dir.join("target"));
+use super::path::{Dirs, RelPath};
+use super::rustc_info::{get_cargo_path, get_host_triple, get_rustc_path, get_rustdoc_path};
+
+pub(crate) struct Compiler {
+ pub(crate) cargo: PathBuf,
+ pub(crate) rustc: PathBuf,
+ pub(crate) rustdoc: PathBuf,
+ pub(crate) rustflags: String,
+ pub(crate) rustdocflags: String,
+ pub(crate) triple: String,
+ pub(crate) runner: Vec<String>,
+}
+
+impl Compiler {
+ pub(crate) fn host() -> Compiler {
+ Compiler {
+ cargo: get_cargo_path(),
+ rustc: get_rustc_path(),
+ rustdoc: get_rustdoc_path(),
+ rustflags: String::new(),
+ rustdocflags: String::new(),
+ triple: get_host_triple(),
+ runner: vec![],
+ }
+ }
+
+ pub(crate) fn with_triple(triple: String) -> Compiler {
+ Compiler {
+ cargo: get_cargo_path(),
+ rustc: get_rustc_path(),
+ rustdoc: get_rustdoc_path(),
+ rustflags: String::new(),
+ rustdocflags: String::new(),
+ triple,
+ runner: vec![],
+ }
+ }
+}
+
+pub(crate) struct CargoProject {
+ source: &'static RelPath,
+ target: &'static str,
+}
+
+impl CargoProject {
+ pub(crate) const fn new(path: &'static RelPath, target: &'static str) -> CargoProject {
+ CargoProject { source: path, target }
+ }
+
+ pub(crate) fn source_dir(&self, dirs: &Dirs) -> PathBuf {
+ self.source.to_path(dirs)
+ }
+
+ pub(crate) fn manifest_path(&self, dirs: &Dirs) -> PathBuf {
+ self.source_dir(dirs).join("Cargo.toml")
+ }
+
+ pub(crate) fn target_dir(&self, dirs: &Dirs) -> PathBuf {
+ RelPath::BUILD.join(self.target).to_path(dirs)
+ }
- if let Some(triple) = triple {
- cmd.arg("--target").arg(triple);
+ fn base_cmd(&self, command: &str, cargo: &Path, dirs: &Dirs) -> Command {
+ let mut cmd = Command::new(cargo);
+
+ cmd.arg(command)
+ .arg("--manifest-path")
+ .arg(self.manifest_path(dirs))
+ .arg("--target-dir")
+ .arg(self.target_dir(dirs));
+
+ cmd
+ }
+
+ fn build_cmd(&self, command: &str, compiler: &Compiler, dirs: &Dirs) -> Command {
+ let mut cmd = self.base_cmd(command, &compiler.cargo, dirs);
+
+ cmd.arg("--target").arg(&compiler.triple);
+
+ cmd.env("RUSTC", &compiler.rustc);
+ cmd.env("RUSTDOC", &compiler.rustdoc);
+ cmd.env("RUSTFLAGS", &compiler.rustflags);
+ cmd.env("RUSTDOCFLAGS", &compiler.rustdocflags);
+ if !compiler.runner.is_empty() {
+ cmd.env(
+ format!("CARGO_TARGET_{}_RUNNER", compiler.triple.to_uppercase().replace('-', "_")),
+ compiler.runner.join(" "),
+ );
+ }
+
+ cmd
}
- cmd
+ #[must_use]
+ pub(crate) fn fetch(&self, cargo: impl AsRef<Path>, dirs: &Dirs) -> Command {
+ let mut cmd = Command::new(cargo.as_ref());
+
+ cmd.arg("fetch").arg("--manifest-path").arg(self.manifest_path(dirs));
+
+ cmd
+ }
+
+ #[must_use]
+ pub(crate) fn clean(&self, cargo: &Path, dirs: &Dirs) -> Command {
+ self.base_cmd("clean", cargo, dirs)
+ }
+
+ #[must_use]
+ pub(crate) fn build(&self, compiler: &Compiler, dirs: &Dirs) -> Command {
+ self.build_cmd("build", compiler, dirs)
+ }
+
+ #[must_use]
+ pub(crate) fn test(&self, compiler: &Compiler, dirs: &Dirs) -> Command {
+ self.build_cmd("test", compiler, dirs)
+ }
+
+ #[must_use]
+ pub(crate) fn run(&self, compiler: &Compiler, dirs: &Dirs) -> Command {
+ self.build_cmd("run", compiler, dirs)
+ }
}
+#[must_use]
pub(crate) fn hyperfine_command(
warmup: u64,
runs: u64,
- prepare: Option<Command>,
- a: Command,
- b: Command,
+ prepare: Option<&str>,
+ a: &str,
+ b: &str,
) -> Command {
let mut bench = Command::new("hyperfine");
}
if let Some(prepare) = prepare {
- bench.arg("--prepare").arg(format!("{:?}", prepare));
+ bench.arg("--prepare").arg(prepare);
}
- bench.arg(format!("{:?}", a)).arg(format!("{:?}", b));
+ bench.arg(a).arg(b);
bench
}
set -e
rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
-rm -rf target/ build/ perf.data{,.old} y.bin
+rm -rf target/ build/ dist/ perf.data{,.old} y.bin
rm -rf download/
# Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh
aot.track-caller-attribute
aot.float-minmax-pass
aot.mod_bench
+aot.issue-72793
testsuite.extended_sysroot
test.rust-random/rand
In the directory with your project (where you can do the usual `cargo build`), run:
```bash
-$ $cg_clif_dir/build/cargo-clif build
+$ $cg_clif_dir/dist/cargo-clif build
```
This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend.
> You should prefer using the Cargo method.
```bash
-$ $cg_clif_dir/build/rustc-clif my_crate.rs
+$ $cg_clif_dir/dist/rustc-clif my_crate.rs
```
## Jit mode
> The jit mode will probably need cargo integration to make this possible.
```bash
-$ $cg_clif_dir/build/cargo-clif jit
+$ $cg_clif_dir/dist/cargo-clif jit
```
or
```bash
-$ $cg_clif_dir/build/rustc-clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
+$ $cg_clif_dir/dist/rustc-clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
```
There is also an experimental lazy jit mode. In this mode functions are only compiled once they are
first called.
```bash
-$ $cg_clif_dir/build/cargo-clif lazy-jit
+$ $cg_clif_dir/dist/cargo-clif lazy-jit
```
## Shell
```bash
function jit_naked() {
- echo "$@" | $cg_clif_dir/build/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
+ echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
}
function jit() {
--- /dev/null
+// Adapted from rustc ui test suite (ui/type-alias-impl-trait/issue-72793.rs)
+
+#![feature(type_alias_impl_trait)]
+
+trait T { type Item; }
+
+type Alias<'a> = impl T<Item = &'a ()>;
+
+struct S;
+impl<'a> T for &'a S {
+ type Item = &'a ();
+}
+
+fn filter_positive<'a>() -> Alias<'a> {
+ &S
+}
+
+fn with_positive(fun: impl Fn(Alias<'_>)) {
+ fun(filter_positive());
+}
+
+fn main() {
+ with_positive(|_| ());
+}
#[lang = "destruct"]
pub trait Destruct {}
+#[lang = "tuple_trait"]
+pub trait Tuple {}
+
#[lang = "unsize"]
pub trait Unsize<T: ?Sized> {}
#[lang = "fn_once"]
#[rustc_paren_sugar]
-pub trait FnOnce<Args> {
+pub trait FnOnce<Args: Tuple> {
#[lang = "fn_once_output"]
type Output;
#[lang = "fn_mut"]
#[rustc_paren_sugar]
-pub trait FnMut<Args>: FnOnce<Args> {
+pub trait FnMut<Args: Tuple>: FnOnce<Args> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
assert_eq!(slice_ptr as usize % 4, 0);
- //return;
-
unsafe {
printf("Hello %s\n\0" as *const str as *const i8, "printf\0" as *const str as *const i8);
let cmp_eq = _mm_cmpeq_epi8(y, y);
let cmp_lt = _mm_cmplt_epi8(y, y);
+ let (zero0, zero1) = std::mem::transmute::<_, (u64, u64)>(x);
+ assert_eq!((zero0, zero1), (0, 0));
assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);
[toolchain]
-channel = "nightly-2022-10-23"
+channel = "nightly-2022-12-13"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
+ignore = ["y.rs"]
+
# Matches rustfmt.toml of rustc
version = "Two"
use_small_heuristics = "Max"
#![forbid(unsafe_code)]/* This line is ignored by bash
# This block is ignored by rustc
pushd $(dirname "$0")/../
-RUSTC="$(pwd)/build/rustc-clif"
+RUSTC="$(pwd)/dist/rustc-clif"
popd
PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic $0
#*/
--- /dev/null
+use std::env;
+use std::ffi::OsString;
+#[cfg(unix)]
+use std::os::unix::process::CommandExt;
+use std::path::PathBuf;
+use std::process::Command;
+
+fn main() {
+ let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
+
+ let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
+ env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
+ );
+
+ let mut args = std::env::args_os().skip(1).collect::<Vec<_>>();
+ args.push(OsString::from("-Cpanic=abort"));
+ args.push(OsString::from("-Zpanic-abort-tests"));
+ let mut codegen_backend_arg = OsString::from("-Zcodegen-backend=");
+ codegen_backend_arg.push(cg_clif_dylib_path);
+ args.push(codegen_backend_arg);
+ if !args.contains(&OsString::from("--sysroot")) {
+ args.push(OsString::from("--sysroot"));
+ args.push(OsString::from(sysroot.to_str().unwrap()));
+ }
+
+ // Ensure that the right toolchain is used
+ env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
+
+ #[cfg(unix)]
+ Command::new("rustdoc").args(args).exec();
+
+ #[cfg(not(unix))]
+ std::process::exit(
+ Command::new("rustdoc").args(args).spawn().unwrap().wait().unwrap().code().unwrap_or(1),
+ );
+}
[dev-dependencies]
rand = "0.7"
rand_xorshift = "0.2"
-diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
-index 8431aa7b818..a3ff7e68ce5 100644
---- a/src/tools/compiletest/src/runtest.rs
-+++ b/src/tools/compiletest/src/runtest.rs
-@@ -3489,12 +3489,7 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
- let compiler_src_dir = base_dir.join("compiler");
- normalize_path(&compiler_src_dir, "$(echo '$COMPILER_DIR')");
-
-- if let Some(virtual_rust_source_base_dir) =
-- option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from)
-- {
-- normalize_path(&virtual_rust_source_base_dir.join("library"), "$(echo '$SRC_DIR')");
-- normalize_path(&virtual_rust_source_base_dir.join("compiler"), "$(echo '$COMPILER_DIR')");
-- }
-+ normalize_path(&Path::new("$(cd ../build_sysroot/sysroot_src/library; pwd)"), "$(echo '$SRC_DIR')");
-
- // Paths into the build directory
- let test_build_dir = &self.config.build_base;
EOF
cat > config.toml <<EOF
ninja = false
[build]
-rustc = "$(pwd)/../build/rustc-clif"
+rustc = "$(pwd)/../dist/rustc-clif"
cargo = "$(rustup which cargo)"
full-bootstrap = true
local-rebuild = true
# FIXME remove once inline asm is fully supported
export RUSTFLAGS="$RUSTFLAGS --cfg=rustix_use_libc"
+export CFG_VIRTUAL_RUST_SOURCE_BASE_DIR="$(cd build_sysroot/sysroot_src; pwd)"
+
# Allow the testsuite to use llvm tools
host_triple=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
export LLVM_BIN_DIR="$(rustc --print sysroot)/lib/rustlib/$host_triple/bin"
done
git checkout -- src/test/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed
+git checkout -- src/test/ui/proc-macro/pretty-print-hack/
# missing features
# ================
# requires compiling with -Cpanic=unwind
rm -r src/test/ui/macros/rfc-2011-nicer-assert-messages/
+rm -r src/test/run-make/test-benches
# vendor intrinsics
rm src/test/ui/sse2.rs # cpuid not supported, so sse2 not detected
rm -r src/test/run-make/emit-named-files # requires full --emit support
rm src/test/ui/abi/stack-probes.rs # stack probes not yet implemented
rm src/test/ui/simd/intrinsic/ptr-cast.rs # simd_expose_addr intrinsic unimplemented
+rm -r src/test/run-make/repr128-dwarf # debuginfo test
+rm src/test/codegen-units/item-collection/asm-sym.rs # requires support for sym in asm!()
# optimization tests
# ==================
rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
rm src/test/ui/mir/mir_raw_fat_ptr.rs # same
rm src/test/ui/consts/issue-33537.rs # same
+rm src/test/ui/layout/valid_range_oob.rs # different ICE message
# doesn't work due to the way the rustc test suite is invoked.
# should work when using ./x.py test the way it is intended
# ============================================================
-rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/
+rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in dist/bin/
rm -r src/test/run-make/unstable-flag-required # same
rm -r src/test/run-make/rustdoc-* # same
rm -r src/test/run-make/issue-88756-default-output # same
rm -r src/test/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump
+rm -r src/test/ui/consts/missing_span_in_backtrace.rs # expects sysroot source to be elsewhere
# genuine bugs
# ============
-rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition
-
rm src/test/incremental/spike-neg1.rs # errors out for some reason
rm src/test/incremental/spike-neg2.rs # same
rm src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs
rm src/test/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
+rm src/test/ui/runtime/out-of-stack.rs # SIGSEGV instead of SIGABRT for some reason (#1301)
+
# bugs in the test suite
# ======================
rm src/test/ui/backtrace.rs # TODO warning
rm src/test/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout
# not sure if this is actually a bug in the test suite, but the symbol list shows the function without leading _ for some reason
rm -r src/test/run-make/native-link-modifier-bundle
+rm src/test/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
+rm src/test/ui/dyn-star/dispatch-on-pin-mut.rs # TODO failed assertion in vtable::get_ptr_and_method_ref
rm src/test/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
pub(crate) fn get_function_sig<'tcx>(
tcx: TyCtxt<'tcx>,
- triple: &target_lexicon::Triple,
+ default_call_conv: CallConv,
inst: Instance<'tcx>,
) -> Signature {
assert!(!inst.substs.needs_infer());
clif_sig_from_fn_abi(
tcx,
- CallConv::triple_default(triple),
+ default_call_conv,
&RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
)
}
inst: Instance<'tcx>,
) -> FuncId {
let name = tcx.symbol_name(inst).name;
- let sig = get_function_sig(tcx, module.isa().triple(), inst);
+ let sig = get_function_sig(tcx, module.target_config().default_call_conv, inst);
match module.declare_function(name, Linkage::Import, &sig) {
Ok(func_id) => func_id,
Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
destination: Place<'tcx>,
target: Option<BasicBlock>,
) {
- let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx));
- let fn_sig =
- fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx));
+ let func = codegen_operand(fx, func);
+ let fn_sig = func.layout().ty.fn_sig(fx.tcx);
let ret_place = codegen_place(fx, destination);
// Handle special calls like intrinsics and empty drop glue.
- let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() {
+ let instance = if let ty::FnDef(def_id, substs) = *func.layout().ty.kind() {
let instance =
ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs)
.polymorphize(fx.tcx);
None
};
- let extra_args = &args[fn_sig.inputs().len()..];
+ let extra_args = &args[fn_sig.inputs().skip_binder().len()..];
let extra_args = fx
.tcx
.mk_type_list(extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))));
let fn_abi = if let Some(instance) = instance {
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
} else {
- RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), extra_args)
+ RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args)
};
- let is_cold = if fn_sig.abi == Abi::RustCold {
+ let is_cold = if fn_sig.abi() == Abi::RustCold {
true
} else {
instance
}
// Unpack arguments tuple for closures
- let mut args = if fn_sig.abi == Abi::RustCall {
+ let mut args = if fn_sig.abi() == Abi::RustCall {
assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
let self_arg = codegen_call_argument_operand(fx, &args[0]);
let pack_arg = codegen_call_argument_operand(fx, &args[1]);
fx.add_comment(nop_inst, "indirect call");
}
- let func = codegen_operand(fx, func).load_scalar(fx);
+ let func = func.load_scalar(fx);
let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
let sig = fx.bcx.import_signature(sig);
};
// FIXME find a cleaner way to support varargs
- if fn_sig.c_variadic {
- if !matches!(fn_sig.abi, Abi::C { .. }) {
+ if fn_sig.c_variadic() {
+ if !matches!(fn_sig.abi(), Abi::C { .. }) {
fx.tcx.sess.span_fatal(
source_info.span,
- &format!("Variadic call for non-C abi {:?}", fn_sig.abi),
+ &format!("Variadic call for non-C abi {:?}", fn_sig.abi()),
);
}
let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
};
let sig = Signature {
- call_conv: CallConv::triple_default(module.isa().triple()),
+ call_conv: module.target_config().default_call_conv,
params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
returns: output.into_iter().map(AbiParam::new).collect(),
};
}
let sig = Signature {
- call_conv: CallConv::triple_default(module.isa().triple()),
+ call_conv: module.target_config().default_call_conv,
params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)],
returns: vec![],
};
// Declare function
let symbol_name = tcx.symbol_name(instance).name.to_string();
- let sig = get_function_sig(tcx, module.isa().triple(), instance);
+ let sig = get_function_sig(tcx, module.target_config().default_call_conv, instance);
let func_id = module.declare_function(&symbol_name, Linkage::Local, &sig).unwrap();
// Make the FunctionBuilder
_ => unreachable!("{:?}", targets),
};
- let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
let (discr, is_inverted) =
crate::optimize::peephole::maybe_unwrap_bool_not(&mut fx.bcx, discr);
let test_zero = if is_inverted { !test_zero } else { test_zero };
- let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
if let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken(
&fx.bcx, discr, test_zero,
) {
UnOp::Not => match layout.ty.kind() {
ty::Bool => {
let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
- CValue::by_val(fx.bcx.ins().bint(types::I8, res), layout)
+ CValue::by_val(res, layout)
}
ty::Uint(_) | ty::Int(_) => {
CValue::by_val(fx.bcx.ins().bnot(val), layout)
_ => unreachable!("un op Not for {:?}", layout.ty),
},
UnOp::Neg => match layout.ty.kind() {
- ty::Int(IntTy::I128) => {
- // FIXME remove this case once ineg.i128 works
- let zero =
- CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size));
- crate::num::codegen_int_binop(fx, BinOp::Sub, zero, operand)
- }
ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
_ => unreachable!("un op Neg for {:?}", layout.ty),
}
let is_not_nan = fx.bcx.ins().fcmp(FloatCC::Equal, from, from);
- let zero = fx.bcx.ins().iconst(to_ty, 0);
+ let zero = type_zero_value(&mut fx.bcx, to_ty);
fx.bcx.ins().select(is_not_nan, val, zero)
} else if from_ty.is_float() && to_ty.is_float() {
// float -> float
}
}
} else {
- let rhs = i64::try_from(rhs).expect("codegen_icmp_imm rhs out of range for <128bit int");
+ let rhs = rhs as i64; // Truncates on purpose in case rhs is actually an unsigned value
fx.bcx.ins().icmp_imm(intcc, lhs, rhs)
}
}
+pub(crate) fn type_zero_value(bcx: &mut FunctionBuilder<'_>, ty: Type) -> Value {
+ if ty == types::I128 {
+ let zero = bcx.ins().iconst(types::I64, 0);
+ bcx.ins().iconcat(zero, zero)
+ } else {
+ bcx.ins().iconst(ty, 0)
+ }
+}
+
pub(crate) fn type_min_max_value(
bcx: &mut FunctionBuilder<'_>,
ty: Type,
}
pub(crate) fn finalize(mut self, tcx: TyCtxt<'_>, module: &mut dyn Module) {
- //println!("todo {:?}", self.todo);
define_all_allocs(tcx, module, &mut self);
- //println!("done {:?}", self.done);
self.done.clear();
}
}
def_id: DefId,
definition: bool,
) -> DataId {
- let rlinkage = tcx.codegen_fn_attrs(def_id).linkage;
- let linkage = if definition {
- crate::linkage::get_static_linkage(tcx, def_id)
- } else if rlinkage == Some(rustc_middle::mir::mono::Linkage::ExternalWeak)
- || rlinkage == Some(rustc_middle::mir::mono::Linkage::WeakAny)
- {
- Linkage::Preemptible
- } else {
- Linkage::Import
- };
+ let attrs = tcx.codegen_fn_attrs(def_id);
let instance = Instance::mono(tcx, def_id).polymorphize(tcx);
let symbol_name = tcx.symbol_name(instance).name;
};
let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();
- let attrs = tcx.codegen_fn_attrs(def_id);
+ if let Some(import_linkage) = attrs.import_linkage {
+ assert!(!definition);
- let data_id = match module.declare_data(
- &*symbol_name,
- linkage,
- is_mutable,
- attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
- ) {
- Ok(data_id) => data_id,
- Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
- "attempt to declare `{symbol_name}` as static, but it was already declared as function"
- )),
- Err(err) => Err::<_, _>(err).unwrap(),
- };
+ let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak
+ || import_linkage == rustc_middle::mir::mono::Linkage::WeakAny
+ {
+ Linkage::Preemptible
+ } else {
+ Linkage::Import
+ };
+
+ let data_id = match module.declare_data(
+ &*symbol_name,
+ linkage,
+ is_mutable,
+ attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
+ ) {
+ Ok(data_id) => data_id,
+ Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
+ "attempt to declare `{symbol_name}` as static, but it was already declared as function"
+ )),
+ Err(err) => Err::<_, _>(err).unwrap(),
+ };
- if rlinkage.is_some() {
// Comment copied from https://github.com/rust-lang/rust/blob/45060c2a66dfd667f88bd8b94261b28a58d85bd5/src/librustc_codegen_llvm/consts.rs#L141
// Declare an internal global `extern_with_linkage_foo` which
// is initialized with the address of `foo`. If `foo` is
Err(ModuleError::DuplicateDefinition(_)) => {}
res => res.unwrap(),
}
- ref_data_id
- } else {
- data_id
+
+ return ref_data_id;
}
+
+ let linkage = if definition {
+ crate::linkage::get_static_linkage(tcx, def_id)
+ } else if attrs.linkage == Some(rustc_middle::mir::mono::Linkage::ExternalWeak)
+ || attrs.linkage == Some(rustc_middle::mir::mono::Linkage::WeakAny)
+ {
+ Linkage::Preemptible
+ } else {
+ Linkage::Import
+ };
+
+ let data_id = match module.declare_data(
+ &*symbol_name,
+ linkage,
+ is_mutable,
+ attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
+ ) {
+ Ok(data_id) => data_id,
+ Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
+ "attempt to declare `{symbol_name}` as static, but it was already declared as function"
+ )),
+ Err(err) => Err::<_, _>(err).unwrap(),
+ };
+
+ data_id
}
fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut ConstantCx) {
(data_id, alloc, None)
}
TodoItem::Static(def_id) => {
- //println!("static {:?}", def_id);
-
let section_name = tcx.codegen_fn_attrs(def_id).link_section;
let alloc = tcx.eval_static_initializer(def_id).unwrap();
}
};
- //("data_id {}", data_id);
if cx.done.contains(&data_id) {
continue;
}
}
pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) {
- let unwind_info = if let Some(unwind_info) = context.create_unwind_info(isa).unwrap() {
+ let unwind_info = if let Some(unwind_info) =
+ context.compiled_code().unwrap().create_unwind_info(isa).unwrap()
+ {
unwind_info
} else {
return;
//! Handling of enum discriminants
//!
-//! Adapted from <https://github.com/rust-lang/rust/blob/d760df5aea483aae041c9a241e7acacf48f75035/src/librustc_codegen_ssa/mir/place.rs>
+//! Adapted from <https://github.com/rust-lang/rust/blob/31c0645b9d2539f47eecb096142474b29dc542f7/compiler/rustc_codegen_ssa/src/mir/place.rs>
+//! (<https://github.com/rust-lang/rust/pull/104535>)
use rustc_target::abi::{Int, TagEncoding, Variants};
} => {
if variant_index != untagged_variant {
let niche = place.place_field(fx, mir::Field::new(tag_field));
+ let niche_type = fx.clif_type(niche.layout().ty).unwrap();
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
- let niche_value = ty::ScalarInt::try_from_uint(
- u128::from(niche_value).wrapping_add(niche_start),
- niche.layout().size,
- )
- .unwrap();
- let niche_llval = CValue::const_val(fx, niche.layout(), niche_value);
+ let niche_value = (niche_value as u128).wrapping_add(niche_start);
+ let niche_value = match niche_type {
+ types::I128 => {
+ let lsb = fx.bcx.ins().iconst(types::I64, niche_value as u64 as i64);
+ let msb =
+ fx.bcx.ins().iconst(types::I64, (niche_value >> 64) as u64 as i64);
+ fx.bcx.ins().iconcat(lsb, msb)
+ }
+ ty => fx.bcx.ins().iconst(ty, niche_value as i64),
+ };
+ let niche_llval = CValue::by_val(niche_value, niche.layout());
niche.write_cvalue(fx, niche_llval);
}
}
}
};
+ let cast_to_size = dest_layout.layout.size();
let cast_to = fx.clif_type(dest_layout.ty).unwrap();
// Read the tag/niche-encoded discriminant from memory.
dest.write_cvalue(fx, res);
}
TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
- // Rebase from niche values to discriminants, and check
- // whether the result is in range for the niche variants.
-
- // We first compute the "relative discriminant" (wrt `niche_variants`),
- // that is, if `n = niche_variants.end() - niche_variants.start()`,
- // we remap `niche_start..=niche_start + n` (which may wrap around)
- // to (non-wrap-around) `0..=n`, to be able to check whether the
- // discriminant corresponds to a niche variant with one comparison.
- // We also can't go directly to the (variant index) discriminant
- // and check that it is in the range `niche_variants`, because
- // that might not fit in the same type, on top of needing an extra
- // comparison (see also the comment on `let niche_discr`).
- let relative_discr = if niche_start == 0 {
- tag
+ let tag_size = tag_scalar.size(fx);
+ let max_unsigned = tag_size.unsigned_int_max();
+ let max_signed = tag_size.signed_int_max() as u128;
+ let min_signed = max_signed + 1;
+ let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
+ let niche_end = niche_start.wrapping_add(relative_max as u128) & max_unsigned;
+ let range = tag_scalar.valid_range(fx);
+
+ let sle = |lhs: u128, rhs: u128| -> bool {
+ // Signed and unsigned comparisons give the same results,
+ // except that in signed comparisons an integer with the
+ // sign bit set is less than one with the sign bit clear.
+ // Toggle the sign bit to do a signed comparison.
+ (lhs ^ min_signed) <= (rhs ^ min_signed)
+ };
+
+ // We have a subrange `niche_start..=niche_end` inside `range`.
+ // If the value of the tag is inside this subrange, it's a
+ // "niche value", an increment of the discriminant. Otherwise it
+ // indicates the untagged variant.
+ // A general algorithm to extract the discriminant from the tag
+ // is:
+ // relative_tag = tag - niche_start
+ // is_niche = relative_tag <= (ule) relative_max
+ // discr = if is_niche {
+ // cast(relative_tag) + niche_variants.start()
+ // } else {
+ // untagged_variant
+ // }
+ // However, we will likely be able to emit simpler code.
+
+ // Find the least and greatest values in `range`, considered
+ // both as signed and unsigned.
+ let (low_unsigned, high_unsigned) =
+ if range.start <= range.end { (range.start, range.end) } else { (0, max_unsigned) };
+ let (low_signed, high_signed) = if sle(range.start, range.end) {
+ (range.start, range.end)
} else {
+ (min_signed, max_signed)
+ };
+
+ let niches_ule = niche_start <= niche_end;
+ let niches_sle = sle(niche_start, niche_end);
+ let cast_smaller = cast_to_size <= tag_size;
+
+ // In the algorithm above, we can change
+ // cast(relative_tag) + niche_variants.start()
+ // into
+ // cast(tag + (niche_variants.start() - niche_start))
+ // if either the casted type is no larger than the original
+ // type, or if the niche values are contiguous (in either the
+ // signed or unsigned sense).
+ let can_incr = cast_smaller || niches_ule || niches_sle;
+
+ let data_for_boundary_niche = || -> Option<(IntCC, u128)> {
+ if !can_incr {
+ None
+ } else if niche_start == low_unsigned {
+ Some((IntCC::UnsignedLessThanOrEqual, niche_end))
+ } else if niche_end == high_unsigned {
+ Some((IntCC::UnsignedGreaterThanOrEqual, niche_start))
+ } else if niche_start == low_signed {
+ Some((IntCC::SignedLessThanOrEqual, niche_end))
+ } else if niche_end == high_signed {
+ Some((IntCC::SignedGreaterThanOrEqual, niche_start))
+ } else {
+ None
+ }
+ };
+
+ let (is_niche, tagged_discr, delta) = if relative_max == 0 {
+ // Best case scenario: only one tagged variant. This will
+ // likely become just a comparison and a jump.
+ // The algorithm is:
+ // is_niche = tag == niche_start
+ // discr = if is_niche {
+ // niche_start
+ // } else {
+ // untagged_variant
+ // }
+ let is_niche = codegen_icmp_imm(fx, IntCC::Equal, tag, niche_start as i128);
+ let tagged_discr =
+ fx.bcx.ins().iconst(cast_to, niche_variants.start().as_u32() as i64);
+ (is_niche, tagged_discr, 0)
+ } else if let Some((predicate, constant)) = data_for_boundary_niche() {
+ // The niche values are either the lowest or the highest in
+ // `range`. We can avoid the first subtraction in the
+ // algorithm.
+ // The algorithm is now this:
+ // is_niche = tag <= niche_end
+ // discr = if is_niche {
+ // cast(tag + (niche_variants.start() - niche_start))
+ // } else {
+ // untagged_variant
+ // }
+ // (the first line may instead be tag >= niche_start,
+ // and may be a signed or unsigned comparison)
+ // The arithmetic must be done before the cast, so we can
+ // have the correct wrapping behavior. See issue #104519 for
+ // the consequences of getting this wrong.
+ let is_niche = codegen_icmp_imm(fx, predicate, tag, constant as i128);
+ let delta = (niche_variants.start().as_u32() as u128).wrapping_sub(niche_start);
+ let incr_tag = if delta == 0 {
+ tag
+ } else {
+ let delta = match fx.bcx.func.dfg.value_type(tag) {
+ types::I128 => {
+ let lsb = fx.bcx.ins().iconst(types::I64, delta as u64 as i64);
+ let msb = fx.bcx.ins().iconst(types::I64, (delta >> 64) as u64 as i64);
+ fx.bcx.ins().iconcat(lsb, msb)
+ }
+ ty => fx.bcx.ins().iconst(ty, delta as i64),
+ };
+ fx.bcx.ins().iadd(tag, delta)
+ };
+
+ let cast_tag = clif_intcast(fx, incr_tag, cast_to, !niches_ule);
+
+ (is_niche, cast_tag, 0)
+ } else {
+ // The special cases don't apply, so we'll have to go with
+ // the general algorithm.
let niche_start = match fx.bcx.func.dfg.value_type(tag) {
types::I128 => {
let lsb = fx.bcx.ins().iconst(types::I64, niche_start as u64 as i64);
}
ty => fx.bcx.ins().iconst(ty, niche_start as i64),
};
- fx.bcx.ins().isub(tag, niche_start)
- };
- let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
- let is_niche = {
- codegen_icmp_imm(
+ let relative_discr = fx.bcx.ins().isub(tag, niche_start);
+ let cast_tag = clif_intcast(fx, relative_discr, cast_to, false);
+ let is_niche = crate::common::codegen_icmp_imm(
fx,
IntCC::UnsignedLessThanOrEqual,
relative_discr,
i128::from(relative_max),
- )
+ );
+ (is_niche, cast_tag, niche_variants.start().as_u32() as u128)
};
- // NOTE(eddyb) this addition needs to be performed on the final
- // type, in case the niche itself can't represent all variant
- // indices (e.g. `u8` niche with more than `256` variants,
- // but enough uninhabited variants so that the remaining variants
- // fit in the niche).
- // In other words, `niche_variants.end - niche_variants.start`
- // is representable in the niche, but `niche_variants.end`
- // might not be, in extreme cases.
- let niche_discr = {
- let relative_discr = if relative_max == 0 {
- // HACK(eddyb) since we have only one niche, we know which
- // one it is, and we can avoid having a dynamic value here.
- fx.bcx.ins().iconst(cast_to, 0)
- } else {
- clif_intcast(fx, relative_discr, cast_to, false)
+ let tagged_discr = if delta == 0 {
+ tagged_discr
+ } else {
+ let delta = match cast_to {
+ types::I128 => {
+ let lsb = fx.bcx.ins().iconst(types::I64, delta as u64 as i64);
+ let msb = fx.bcx.ins().iconst(types::I64, (delta >> 64) as u64 as i64);
+ fx.bcx.ins().iconcat(lsb, msb)
+ }
+ ty => fx.bcx.ins().iconst(ty, delta as i64),
};
- fx.bcx.ins().iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32()))
+ fx.bcx.ins().iadd(tagged_discr, delta)
};
- let untagged_variant =
- fx.bcx.ins().iconst(cast_to, i64::from(untagged_variant.as_u32()));
- let discr = fx.bcx.ins().select(is_niche, niche_discr, untagged_variant);
+ let untagged_variant = if cast_to == types::I128 {
+ let zero = fx.bcx.ins().iconst(types::I64, 0);
+ let untagged_variant =
+ fx.bcx.ins().iconst(types::I64, i64::from(untagged_variant.as_u32()));
+ fx.bcx.ins().iconcat(untagged_variant, zero)
+ } else {
+ fx.bcx.ins().iconst(cast_to, i64::from(untagged_variant.as_u32()))
+ };
+ let discr = fx.bcx.ins().select(is_niche, tagged_discr, untagged_variant);
let res = CValue::by_val(discr, dest_layout);
dest.write_cvalue(fx, res);
}
tcx.sess.abort_if_errors();
- jit_module.finalize_definitions();
+ jit_module.finalize_definitions().unwrap();
unsafe { cx.unwind_context.register_jit(&jit_module) };
println!(
let backend_config = lazy_jit_state.backend_config.clone();
let name = tcx.symbol_name(instance).name;
- let sig = crate::abi::get_function_sig(tcx, jit_module.isa().triple(), instance);
+ let sig = crate::abi::get_function_sig(
+ tcx,
+ jit_module.target_config().default_call_conv,
+ instance,
+ );
let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap();
let current_ptr = jit_module.read_got_entry(func_id);
});
assert!(cx.global_asm.is_empty());
- jit_module.finalize_definitions();
+ jit_module.finalize_definitions().unwrap();
unsafe { cx.unwind_context.register_jit(&jit_module) };
jit_module.get_finalized_function(func_id)
})
let pointer_type = module.target_config().pointer_type();
let name = tcx.symbol_name(inst).name;
- let sig = crate::abi::get_function_sig(tcx, module.isa().triple(), inst);
+ let sig = crate::abi::get_function_sig(tcx, module.target_config().default_call_conv, inst);
let func_id = module.declare_function(name, Linkage::Export, &sig).unwrap();
let instance_ptr = Box::into_raw(Box::new(inst));
MonoItem::Fn(instance) => {
let name = tcx.symbol_name(instance).name;
let _inst_guard = crate::PrintOnPanic(|| format!("{:?} {}", instance, name));
- let sig = get_function_sig(tcx, module.isa().triple(), instance);
+ let sig =
+ get_function_sig(tcx, module.target_config().default_call_conv, instance);
let linkage = crate::linkage::get_clif_linkage(
mono_item,
linkage,
pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
intrinsic: &str,
- _substs: SubstsRef<'tcx>,
+ substs: SubstsRef<'tcx>,
args: &[mir::Operand<'tcx>],
ret: CPlace<'tcx>,
target: Option<BasicBlock>,
) {
- match intrinsic {
- "llvm.x86.sse2.pause" | "llvm.aarch64.isb" => {
- // Spin loop hint
- }
+ if intrinsic.starts_with("llvm.aarch64") {
+ return llvm_aarch64::codegen_aarch64_llvm_intrinsic_call(
+ fx, intrinsic, substs, args, ret, target,
+ );
+ }
+ if intrinsic.starts_with("llvm.x86") {
+ return llvm_x86::codegen_x86_llvm_intrinsic_call(fx, intrinsic, substs, args, ret, target);
+ }
- // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
- "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd" => {
+ match intrinsic {
+ _ if intrinsic.starts_with("llvm.ctlz.v") => {
intrinsic_args!(fx, args => (a); intrinsic);
- let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
- let lane_ty = fx.clif_type(lane_ty).unwrap();
- assert!(lane_count <= 32);
-
- let mut res = fx.bcx.ins().iconst(types::I32, 0);
-
- for lane in (0..lane_count).rev() {
- let a_lane = a.value_lane(fx, lane).load_scalar(fx);
-
- // cast float to int
- let a_lane = match lane_ty {
- types::F32 => fx.bcx.ins().bitcast(types::I32, a_lane),
- types::F64 => fx.bcx.ins().bitcast(types::I64, a_lane),
- _ => a_lane,
- };
-
- // extract sign bit of an int
- let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_ty.bits() - 1));
-
- // shift sign bit into result
- let a_lane_sign = clif_intcast(fx, a_lane_sign, types::I32, false);
- res = fx.bcx.ins().ishl_imm(res, 1);
- res = fx.bcx.ins().bor(res, a_lane_sign);
- }
-
- let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
- ret.write_cvalue(fx, res);
- }
- "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd" => {
- let (x, y, kind) = match args {
- [x, y, kind] => (x, y, kind),
- _ => bug!("wrong number of args for intrinsic {intrinsic}"),
- };
- let x = codegen_operand(fx, x);
- let y = codegen_operand(fx, y);
- let kind = crate::constant::mir_operand_get_const_val(fx, kind)
- .expect("llvm.x86.sse2.cmp.* kind not const");
-
- let flt_cc = match kind
- .try_to_bits(Size::from_bytes(1))
- .unwrap_or_else(|| panic!("kind not scalar: {:?}", kind))
- {
- 0 => FloatCC::Equal,
- 1 => FloatCC::LessThan,
- 2 => FloatCC::LessThanOrEqual,
- 7 => FloatCC::Ordered,
- 3 => FloatCC::Unordered,
- 4 => FloatCC::NotEqual,
- 5 => FloatCC::UnorderedOrGreaterThanOrEqual,
- 6 => FloatCC::UnorderedOrGreaterThan,
- kind => unreachable!("kind {:?}", kind),
- };
-
- simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, res_lane_ty, x_lane, y_lane| {
- let res_lane = match lane_ty.kind() {
- ty::Float(_) => fx.bcx.ins().fcmp(flt_cc, x_lane, y_lane),
- _ => unreachable!("{:?}", lane_ty),
- };
- bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+ fx.bcx.ins().clz(lane)
});
}
- "llvm.x86.sse2.psrli.d" => {
- let (a, imm8) = match args {
- [a, imm8] => (a, imm8),
- _ => bug!("wrong number of args for intrinsic {intrinsic}"),
- };
- let a = codegen_operand(fx, a);
- let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
- .expect("llvm.x86.sse2.psrli.d imm8 not const");
- simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
- .try_to_bits(Size::from_bytes(4))
- .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
- {
- imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
- _ => fx.bcx.ins().iconst(types::I32, 0),
- });
- }
- "llvm.x86.sse2.pslli.d" => {
- let (a, imm8) = match args {
- [a, imm8] => (a, imm8),
- _ => bug!("wrong number of args for intrinsic {intrinsic}"),
- };
- let a = codegen_operand(fx, a);
- let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
- .expect("llvm.x86.sse2.psrli.d imm8 not const");
+ _ if intrinsic.starts_with("llvm.ctpop.v") => {
+ intrinsic_args!(fx, args => (a); intrinsic);
- simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
- .try_to_bits(Size::from_bytes(4))
- .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
- {
- imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
- _ => fx.bcx.ins().iconst(types::I32, 0),
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+ fx.bcx.ins().popcnt(lane)
});
}
- "llvm.x86.sse2.storeu.dq" => {
- intrinsic_args!(fx, args => (mem_addr, a); intrinsic);
- let mem_addr = mem_addr.load_scalar(fx);
-
- // FIXME correctly handle the unalignment
- let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
- dest.write_cvalue(fx, a);
- }
- "llvm.x86.addcarry.64" => {
- intrinsic_args!(fx, args => (c_in, a, b); intrinsic);
- let c_in = c_in.load_scalar(fx);
-
- llvm_add_sub(fx, BinOp::Add, ret, c_in, a, b);
- }
- "llvm.x86.subborrow.64" => {
- intrinsic_args!(fx, args => (b_in, a, b); intrinsic);
- let b_in = b_in.load_scalar(fx);
- llvm_add_sub(fx, BinOp::Sub, ret, b_in, a, b);
- }
_ => {
fx.tcx
.sess
let ret_block = fx.get_block(dest);
fx.bcx.ins().jump(ret_block, &[]);
}
-
-// llvm.x86.avx2.vperm2i128
-// llvm.x86.ssse3.pshuf.b.128
-// llvm.x86.avx2.pshuf.b
-// llvm.x86.avx2.psrli.w
-// llvm.x86.sse2.psrli.w
-
-fn llvm_add_sub<'tcx>(
- fx: &mut FunctionCx<'_, '_, 'tcx>,
- bin_op: BinOp,
- ret: CPlace<'tcx>,
- cb_in: Value,
- a: CValue<'tcx>,
- b: CValue<'tcx>,
-) {
- assert_eq!(
- a.layout().ty,
- fx.tcx.types.u64,
- "llvm.x86.addcarry.64/llvm.x86.subborrow.64 second operand must be u64"
- );
- assert_eq!(
- b.layout().ty,
- fx.tcx.types.u64,
- "llvm.x86.addcarry.64/llvm.x86.subborrow.64 third operand must be u64"
- );
-
- // c + carry -> c + first intermediate carry or borrow respectively
- let int0 = crate::num::codegen_checked_int_binop(fx, bin_op, a, b);
- let c = int0.value_field(fx, mir::Field::new(0));
- let cb0 = int0.value_field(fx, mir::Field::new(1)).load_scalar(fx);
-
- // c + carry -> c + second intermediate carry or borrow respectively
- let cb_in_as_u64 = fx.bcx.ins().uextend(types::I64, cb_in);
- let cb_in_as_u64 = CValue::by_val(cb_in_as_u64, fx.layout_of(fx.tcx.types.u64));
- let int1 = crate::num::codegen_checked_int_binop(fx, bin_op, c, cb_in_as_u64);
- let (c, cb1) = int1.load_scalar_pair(fx);
-
- // carry0 | carry1 -> carry or borrow respectively
- let cb_out = fx.bcx.ins().bor(cb0, cb1);
-
- let layout = fx.layout_of(fx.tcx.mk_tup([fx.tcx.types.u8, fx.tcx.types.u64].iter()));
- let val = CValue::by_val_pair(cb_out, c, layout);
- ret.write_cvalue(fx, val);
-}
--- /dev/null
+//! Emulate AArch64 LLVM intrinsics
+
+use crate::intrinsics::*;
+use crate::prelude::*;
+
+use rustc_middle::ty::subst::SubstsRef;
+
+pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>(
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ intrinsic: &str,
+ _substs: SubstsRef<'tcx>,
+ args: &[mir::Operand<'tcx>],
+ ret: CPlace<'tcx>,
+ target: Option<BasicBlock>,
+) {
+ // llvm.aarch64.neon.sqshl.v*i*
+
+ match intrinsic {
+ "llvm.aarch64.isb" => {
+ fx.bcx.ins().fence();
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.abs.v") => {
+ intrinsic_args!(fx, args => (a); intrinsic);
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+ fx.bcx.ins().iabs(lane)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.cls.v") => {
+ intrinsic_args!(fx, args => (a); intrinsic);
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+ fx.bcx.ins().cls(lane)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.rbit.v") => {
+ intrinsic_args!(fx, args => (a); intrinsic);
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+ fx.bcx.ins().bitrev(lane)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.sqadd.v") => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
+ simd_pair_for_each_lane_typed(fx, x, y, ret, &|fx, x_lane, y_lane| {
+ crate::num::codegen_saturating_int_binop(fx, BinOp::Add, x_lane, y_lane)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.sqsub.v") => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
+ simd_pair_for_each_lane_typed(fx, x, y, ret, &|fx, x_lane, y_lane| {
+ crate::num::codegen_saturating_int_binop(fx, BinOp::Sub, x_lane, y_lane)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.smax.v") => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
+ simd_pair_for_each_lane(
+ fx,
+ x,
+ y,
+ ret,
+ &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
+ let gt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, x_lane, y_lane);
+ fx.bcx.ins().select(gt, x_lane, y_lane)
+ },
+ );
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.umax.v") => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
+ simd_pair_for_each_lane(
+ fx,
+ x,
+ y,
+ ret,
+ &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
+ let gt = fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, x_lane, y_lane);
+ fx.bcx.ins().select(gt, x_lane, y_lane)
+ },
+ );
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.smaxv.i") => {
+ intrinsic_args!(fx, args => (v); intrinsic);
+
+ simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
+ let gt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, a, b);
+ fx.bcx.ins().select(gt, a, b)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.umaxv.i") => {
+ intrinsic_args!(fx, args => (v); intrinsic);
+
+ simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
+ let gt = fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, a, b);
+ fx.bcx.ins().select(gt, a, b)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.smin.v") => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
+ simd_pair_for_each_lane(
+ fx,
+ x,
+ y,
+ ret,
+ &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
+ let gt = fx.bcx.ins().icmp(IntCC::SignedLessThan, x_lane, y_lane);
+ fx.bcx.ins().select(gt, x_lane, y_lane)
+ },
+ );
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.umin.v") => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
+ simd_pair_for_each_lane(
+ fx,
+ x,
+ y,
+ ret,
+ &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
+ let gt = fx.bcx.ins().icmp(IntCC::UnsignedLessThan, x_lane, y_lane);
+ fx.bcx.ins().select(gt, x_lane, y_lane)
+ },
+ );
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.sminv.i") => {
+ intrinsic_args!(fx, args => (v); intrinsic);
+
+ simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
+ let gt = fx.bcx.ins().icmp(IntCC::SignedLessThan, a, b);
+ fx.bcx.ins().select(gt, a, b)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.uminv.i") => {
+ intrinsic_args!(fx, args => (v); intrinsic);
+
+ simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
+ let gt = fx.bcx.ins().icmp(IntCC::UnsignedLessThan, a, b);
+ fx.bcx.ins().select(gt, a, b)
+ });
+ }
+
+ /*
+ _ if intrinsic.starts_with("llvm.aarch64.neon.sshl.v")
+ || intrinsic.starts_with("llvm.aarch64.neon.sqshl.v")
+ // FIXME split this one out once saturating is implemented
+ || intrinsic.starts_with("llvm.aarch64.neon.sqshlu.v") =>
+ {
+ intrinsic_args!(fx, args => (a, b); intrinsic);
+
+ simd_pair_for_each_lane(fx, a, b, ret, &|fx, _lane_ty, _res_lane_ty, a, b| {
+ // FIXME saturate?
+ fx.bcx.ins().ishl(a, b)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.sqshrn.v") => {
+ let (a, imm32) = match args {
+ [a, imm32] => (a, imm32),
+ _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+ };
+ let a = codegen_operand(fx, a);
+ let imm32 = crate::constant::mir_operand_get_const_val(fx, imm32)
+ .expect("llvm.aarch64.neon.sqshrn.v* imm32 not const");
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm32
+ .try_to_bits(Size::from_bytes(4))
+ .unwrap_or_else(|| panic!("imm32 not scalar: {:?}", imm32))
+ {
+ imm32 if imm32 < 32 => fx.bcx.ins().sshr_imm(lane, i64::from(imm32 as u8)),
+ _ => fx.bcx.ins().iconst(types::I32, 0),
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.sqshrun.v") => {
+ let (a, imm32) = match args {
+ [a, imm32] => (a, imm32),
+ _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+ };
+ let a = codegen_operand(fx, a);
+ let imm32 = crate::constant::mir_operand_get_const_val(fx, imm32)
+ .expect("llvm.aarch64.neon.sqshrn.v* imm32 not const");
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm32
+ .try_to_bits(Size::from_bytes(4))
+ .unwrap_or_else(|| panic!("imm32 not scalar: {:?}", imm32))
+ {
+ imm32 if imm32 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm32 as u8)),
+ _ => fx.bcx.ins().iconst(types::I32, 0),
+ });
+ }
+ */
+ _ => {
+ fx.tcx.sess.warn(&format!(
+ "unsupported AArch64 llvm intrinsic {}; replacing with trap",
+ intrinsic
+ ));
+ crate::trap::trap_unimplemented(fx, intrinsic);
+ return;
+ }
+ }
+
+ let dest = target.expect("all llvm intrinsics used by stdlib should return");
+ let ret_block = fx.get_block(dest);
+ fx.bcx.ins().jump(ret_block, &[]);
+}
--- /dev/null
+//! Emulate x86 LLVM intrinsics
+
+use crate::intrinsics::*;
+use crate::prelude::*;
+
+use rustc_middle::ty::subst::SubstsRef;
+
+pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ intrinsic: &str,
+ _substs: SubstsRef<'tcx>,
+ args: &[mir::Operand<'tcx>],
+ ret: CPlace<'tcx>,
+ target: Option<BasicBlock>,
+) {
+ match intrinsic {
+ "llvm.x86.sse2.pause" | "llvm.aarch64.isb" => {
+ // Spin loop hint
+ }
+
+ // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
+ "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd" => {
+ intrinsic_args!(fx, args => (a); intrinsic);
+
+ let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
+ let lane_ty = fx.clif_type(lane_ty).unwrap();
+ assert!(lane_count <= 32);
+
+ let mut res = fx.bcx.ins().iconst(types::I32, 0);
+
+ for lane in (0..lane_count).rev() {
+ let a_lane = a.value_lane(fx, lane).load_scalar(fx);
+
+ // cast float to int
+ let a_lane = match lane_ty {
+ types::F32 => fx.bcx.ins().bitcast(types::I32, a_lane),
+ types::F64 => fx.bcx.ins().bitcast(types::I64, a_lane),
+ _ => a_lane,
+ };
+
+ // extract sign bit of an int
+ let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_ty.bits() - 1));
+
+ // shift sign bit into result
+ let a_lane_sign = clif_intcast(fx, a_lane_sign, types::I32, false);
+ res = fx.bcx.ins().ishl_imm(res, 1);
+ res = fx.bcx.ins().bor(res, a_lane_sign);
+ }
+
+ let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
+ ret.write_cvalue(fx, res);
+ }
+ "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd" => {
+ let (x, y, kind) = match args {
+ [x, y, kind] => (x, y, kind),
+ _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+ };
+ let x = codegen_operand(fx, x);
+ let y = codegen_operand(fx, y);
+ let kind = crate::constant::mir_operand_get_const_val(fx, kind)
+ .expect("llvm.x86.sse2.cmp.* kind not const");
+
+ let flt_cc = match kind
+ .try_to_bits(Size::from_bytes(1))
+ .unwrap_or_else(|| panic!("kind not scalar: {:?}", kind))
+ {
+ 0 => FloatCC::Equal,
+ 1 => FloatCC::LessThan,
+ 2 => FloatCC::LessThanOrEqual,
+ 7 => FloatCC::Ordered,
+ 3 => FloatCC::Unordered,
+ 4 => FloatCC::NotEqual,
+ 5 => FloatCC::UnorderedOrGreaterThanOrEqual,
+ 6 => FloatCC::UnorderedOrGreaterThan,
+ kind => unreachable!("kind {:?}", kind),
+ };
+
+ simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, res_lane_ty, x_lane, y_lane| {
+ let res_lane = match lane_ty.kind() {
+ ty::Float(_) => fx.bcx.ins().fcmp(flt_cc, x_lane, y_lane),
+ _ => unreachable!("{:?}", lane_ty),
+ };
+ bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
+ });
+ }
+ "llvm.x86.sse2.psrli.d" => {
+ let (a, imm8) = match args {
+ [a, imm8] => (a, imm8),
+ _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+ };
+ let a = codegen_operand(fx, a);
+ let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
+ .expect("llvm.x86.sse2.psrli.d imm8 not const");
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
+ .try_to_bits(Size::from_bytes(4))
+ .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
+ {
+ imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
+ _ => fx.bcx.ins().iconst(types::I32, 0),
+ });
+ }
+ "llvm.x86.sse2.pslli.d" => {
+ let (a, imm8) = match args {
+ [a, imm8] => (a, imm8),
+ _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+ };
+ let a = codegen_operand(fx, a);
+ let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
+ .expect("llvm.x86.sse2.psrli.d imm8 not const");
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
+ .try_to_bits(Size::from_bytes(4))
+ .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
+ {
+ imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
+ _ => fx.bcx.ins().iconst(types::I32, 0),
+ });
+ }
+ "llvm.x86.sse2.storeu.dq" => {
+ intrinsic_args!(fx, args => (mem_addr, a); intrinsic);
+ let mem_addr = mem_addr.load_scalar(fx);
+
+ // FIXME correctly handle the unalignment
+ let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
+ dest.write_cvalue(fx, a);
+ }
+ "llvm.x86.addcarry.64" => {
+ intrinsic_args!(fx, args => (c_in, a, b); intrinsic);
+ let c_in = c_in.load_scalar(fx);
+
+ llvm_add_sub(fx, BinOp::Add, ret, c_in, a, b);
+ }
+ "llvm.x86.subborrow.64" => {
+ intrinsic_args!(fx, args => (b_in, a, b); intrinsic);
+ let b_in = b_in.load_scalar(fx);
+
+ llvm_add_sub(fx, BinOp::Sub, ret, b_in, a, b);
+ }
+ _ => {
+ fx.tcx.sess.warn(&format!(
+ "unsupported x86 llvm intrinsic {}; replacing with trap",
+ intrinsic
+ ));
+ crate::trap::trap_unimplemented(fx, intrinsic);
+ return;
+ }
+ }
+
+ let dest = target.expect("all llvm intrinsics used by stdlib should return");
+ let ret_block = fx.get_block(dest);
+ fx.bcx.ins().jump(ret_block, &[]);
+}
+
+// llvm.x86.avx2.vperm2i128
+// llvm.x86.ssse3.pshuf.b.128
+// llvm.x86.avx2.pshuf.b
+// llvm.x86.avx2.psrli.w
+// llvm.x86.sse2.psrli.w
+
+fn llvm_add_sub<'tcx>(
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ bin_op: BinOp,
+ ret: CPlace<'tcx>,
+ cb_in: Value,
+ a: CValue<'tcx>,
+ b: CValue<'tcx>,
+) {
+ assert_eq!(
+ a.layout().ty,
+ fx.tcx.types.u64,
+ "llvm.x86.addcarry.64/llvm.x86.subborrow.64 second operand must be u64"
+ );
+ assert_eq!(
+ b.layout().ty,
+ fx.tcx.types.u64,
+ "llvm.x86.addcarry.64/llvm.x86.subborrow.64 third operand must be u64"
+ );
+
+ // c + carry -> c + first intermediate carry or borrow respectively
+ let int0 = crate::num::codegen_checked_int_binop(fx, bin_op, a, b);
+ let c = int0.value_field(fx, mir::Field::new(0));
+ let cb0 = int0.value_field(fx, mir::Field::new(1)).load_scalar(fx);
+
+ // c + carry -> c + second intermediate carry or borrow respectively
+ let cb_in_as_u64 = fx.bcx.ins().uextend(types::I64, cb_in);
+ let cb_in_as_u64 = CValue::by_val(cb_in_as_u64, fx.layout_of(fx.tcx.types.u64));
+ let int1 = crate::num::codegen_checked_int_binop(fx, bin_op, c, cb_in_as_u64);
+ let (c, cb1) = int1.load_scalar_pair(fx);
+
+ // carry0 | carry1 -> carry or borrow respectively
+ let cb_out = fx.bcx.ins().bor(cb0, cb1);
+
+ let layout = fx.layout_of(fx.tcx.mk_tup([fx.tcx.types.u8, fx.tcx.types.u64].iter()));
+ let val = CValue::by_val_pair(cb_out, c, layout);
+ ret.write_cvalue(fx, val);
+}
mod cpuid;
mod llvm;
+mod llvm_aarch64;
+mod llvm_x86;
mod simd;
pub(crate) use cpuid::codegen_cpuid_call;
ty => ty,
};
- let val = fx.bcx.ins().bint(int_ty, val);
- let mut res = fx.bcx.ins().ineg(val);
+ let mut res = fx.bcx.ins().bmask(int_ty, val);
if ty.is_float() {
res = fx.bcx.ins().bitcast(ty, res);
ret.write_cvalue(fx, res);
}
sym::bswap => {
- // FIXME(CraneStation/cranelift#794) add bswap instruction to cranelift
- fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
- match bcx.func.dfg.value_type(v) {
- types::I8 => v,
-
- // https://code.woboq.org/gcc/include/bits/byteswap.h.html
- types::I16 => {
- let tmp1 = bcx.ins().ishl_imm(v, 8);
- let n1 = bcx.ins().band_imm(tmp1, 0xFF00);
-
- let tmp2 = bcx.ins().ushr_imm(v, 8);
- let n2 = bcx.ins().band_imm(tmp2, 0x00FF);
-
- bcx.ins().bor(n1, n2)
- }
- types::I32 => {
- let tmp1 = bcx.ins().ishl_imm(v, 24);
- let n1 = bcx.ins().band_imm(tmp1, 0xFF00_0000);
-
- let tmp2 = bcx.ins().ishl_imm(v, 8);
- let n2 = bcx.ins().band_imm(tmp2, 0x00FF_0000);
-
- let tmp3 = bcx.ins().ushr_imm(v, 8);
- let n3 = bcx.ins().band_imm(tmp3, 0x0000_FF00);
-
- let tmp4 = bcx.ins().ushr_imm(v, 24);
- let n4 = bcx.ins().band_imm(tmp4, 0x0000_00FF);
-
- let or_tmp1 = bcx.ins().bor(n1, n2);
- let or_tmp2 = bcx.ins().bor(n3, n4);
- bcx.ins().bor(or_tmp1, or_tmp2)
- }
- types::I64 => {
- let tmp1 = bcx.ins().ishl_imm(v, 56);
- let n1 = bcx.ins().band_imm(tmp1, 0xFF00_0000_0000_0000u64 as i64);
-
- let tmp2 = bcx.ins().ishl_imm(v, 40);
- let n2 = bcx.ins().band_imm(tmp2, 0x00FF_0000_0000_0000u64 as i64);
-
- let tmp3 = bcx.ins().ishl_imm(v, 24);
- let n3 = bcx.ins().band_imm(tmp3, 0x0000_FF00_0000_0000u64 as i64);
-
- let tmp4 = bcx.ins().ishl_imm(v, 8);
- let n4 = bcx.ins().band_imm(tmp4, 0x0000_00FF_0000_0000u64 as i64);
-
- let tmp5 = bcx.ins().ushr_imm(v, 8);
- let n5 = bcx.ins().band_imm(tmp5, 0x0000_0000_FF00_0000u64 as i64);
-
- let tmp6 = bcx.ins().ushr_imm(v, 24);
- let n6 = bcx.ins().band_imm(tmp6, 0x0000_0000_00FF_0000u64 as i64);
-
- let tmp7 = bcx.ins().ushr_imm(v, 40);
- let n7 = bcx.ins().band_imm(tmp7, 0x0000_0000_0000_FF00u64 as i64);
-
- let tmp8 = bcx.ins().ushr_imm(v, 56);
- let n8 = bcx.ins().band_imm(tmp8, 0x0000_0000_0000_00FFu64 as i64);
-
- let or_tmp1 = bcx.ins().bor(n1, n2);
- let or_tmp2 = bcx.ins().bor(n3, n4);
- let or_tmp3 = bcx.ins().bor(n5, n6);
- let or_tmp4 = bcx.ins().bor(n7, n8);
-
- let or_tmp5 = bcx.ins().bor(or_tmp1, or_tmp2);
- let or_tmp6 = bcx.ins().bor(or_tmp3, or_tmp4);
- bcx.ins().bor(or_tmp5, or_tmp6)
- }
- types::I128 => {
- let (lo, hi) = bcx.ins().isplit(v);
- let lo = swap(bcx, lo);
- let hi = swap(bcx, hi);
- bcx.ins().iconcat(hi, lo)
- }
- ty => unreachable!("bswap {}", ty),
- }
- }
intrinsic_args!(fx, args => (arg); intrinsic);
let val = arg.load_scalar(fx);
- let res = CValue::by_val(swap(&mut fx.bcx, val), arg.layout());
+ let res = if fx.bcx.func.dfg.value_type(val) == types::I8 {
+ val
+ } else {
+ fx.bcx.ins().bswap(val)
+ };
+ let res = CValue::by_val(res, arg.layout());
ret.write_cvalue(fx, res);
}
sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => {
let old = fx.bcx.ins().atomic_cas(MemFlags::trusted(), ptr, test_old, new);
let is_eq = fx.bcx.ins().icmp(IntCC::Equal, old, test_old);
- let ret_val =
- CValue::by_val_pair(old, fx.bcx.ins().bint(types::I8, is_eq), ret.layout());
+ let ret_val = CValue::by_val_pair(old, is_eq, ret.layout());
ret.write_cvalue(fx, ret_val)
}
flags.set_notrap();
let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0);
let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0);
- let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val);
- fx.bcx.ins().bint(types::I8, eq)
+ fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val)
} else {
// Just call `memcmp` (like slices do in core) when the
// size is too large or it's not a power-of-two.
let returns = vec![AbiParam::new(types::I32)];
let args = &[lhs_ref, rhs_ref, bytes_val];
let cmp = fx.lib_call("memcmp", params, returns, args)[0];
- let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0);
- fx.bcx.ins().bint(types::I8, eq)
+ fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0)
};
ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout()));
}
_ => unreachable!(),
};
- let ty = fx.clif_type(res_lane_ty).unwrap();
-
- let res_lane = fx.bcx.ins().bint(ty, res_lane);
- fx.bcx.ins().ineg(res_lane)
+ bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
});
}
let res_type =
Type::int_with_byte_size(u16::try_from(expected_bytes).unwrap()).unwrap();
- let mut res = fx.bcx.ins().iconst(res_type, 0);
+ let mut res = type_zero_value(&mut fx.bcx, res_type);
let lanes = match fx.tcx.sess.target.endian {
Endian::Big => Box::new(0..lane_count) as Box<dyn Iterator<Item = u64>>,
returns: vec![AbiParam::new(m.target_config().pointer_type() /*isize*/)],
call_conv: crate::conv_to_call_conv(
tcx.sess.target.options.entry_abi,
- CallConv::triple_default(m.isa().triple()),
+ m.target_config().default_call_conv,
),
};
let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
let main_name = tcx.symbol_name(instance).name;
- let main_sig = get_function_sig(tcx, m.isa().triple(), instance);
+ let main_sig = get_function_sig(tcx, m.target_config().default_call_conv, instance);
let main_func_id = m.declare_function(main_name, Linkage::Import, &main_sig).unwrap();
let mut ctx = Context::new();
.polymorphize(tcx);
let report_name = tcx.symbol_name(report).name;
- let report_sig = get_function_sig(tcx, m.isa().triple(), report);
+ let report_sig = get_function_sig(tcx, m.target_config().default_call_conv, report);
let report_func_id =
m.declare_function(report_name, Linkage::Import, &report_sig).unwrap();
let report_func_ref = m.declare_func_in_func(report_func_id, &mut bcx.func);
) -> CValue<'tcx> {
let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
let val = fx.bcx.ins().icmp(intcc, lhs, rhs);
- let val = fx.bcx.ins().bint(types::I8, val);
CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
}
_ => bug!("binop {:?} on checked int/uint lhs: {:?} rhs: {:?}", bin_op, in_lhs, in_rhs),
};
- let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow);
-
let out_layout = fx.layout_of(fx.tcx.mk_tup([in_lhs.layout().ty, fx.tcx.types.bool].iter()));
CValue::by_val_pair(res, has_overflow, out_layout)
}
_ => unreachable!(),
};
let val = fx.bcx.ins().fcmp(fltcc, lhs, rhs);
- let val = fx.bcx.ins().bint(types::I8, val);
return CValue::by_val(val, fx.layout_of(fx.tcx.types.bool));
}
_ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
_ => panic!("bin_op {:?} on ptr", bin_op),
};
- CValue::by_val(fx.bcx.ins().bint(types::I8, res), fx.layout_of(fx.tcx.types.bool))
+ CValue::by_val(res, fx.layout_of(fx.tcx.types.bool))
}
}
use cranelift_codegen::ir::{condcodes::IntCC, InstructionData, Opcode, Value, ValueDef};
use cranelift_frontend::FunctionBuilder;
-/// If the given value was produced by a `bint` instruction, return it's input, otherwise return the
-/// given value.
-pub(crate) fn maybe_unwrap_bint(bcx: &mut FunctionBuilder<'_>, arg: Value) -> Value {
- if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
- match bcx.func.dfg[arg_inst] {
- InstructionData::Unary { opcode: Opcode::Bint, arg } => arg,
- _ => arg,
- }
- } else {
- arg
- }
-}
-
/// If the given value was produced by the lowering of `Rvalue::Not` return the input and true,
/// otherwise return the given value and false.
pub(crate) fn maybe_unwrap_bool_not(bcx: &mut FunctionBuilder<'_>, arg: Value) -> (Value, bool) {
};
match bcx.func.dfg[arg_inst] {
- InstructionData::UnaryBool { opcode: Opcode::Bconst, imm } => {
- if test_zero {
- Some(!imm)
- } else {
- Some(imm)
- }
- }
InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => {
if test_zero {
Some(imm.bits() == 0)
local: Local,
layout: TyAndLayout<'tcx>,
) -> CPlace<'tcx> {
- let var = Variable::with_u32(fx.next_ssa_var);
+ let var = Variable::from_u32(fx.next_ssa_var);
fx.next_ssa_var += 1;
fx.bcx.declare_var(var, fx.clif_type(layout.ty).unwrap());
CPlace { inner: CPlaceInner::Var(local, var), layout }
local: Local,
layout: TyAndLayout<'tcx>,
) -> CPlace<'tcx> {
- let var1 = Variable::with_u32(fx.next_ssa_var);
+ let var1 = Variable::from_u32(fx.next_ssa_var);
fx.next_ssa_var += 1;
- let var2 = Variable::with_u32(fx.next_ssa_var);
+ let var2 = Variable::from_u32(fx.next_ssa_var);
fx.next_ssa_var += 1;
let (ty1, ty2) = fx.clif_pair_type(layout.ty).unwrap();
| (types::F32, types::I32)
| (types::I64, types::F64)
| (types::F64, types::I64) => fx.bcx.ins().bitcast(dst_ty, data),
- _ if src_ty.is_vector() && dst_ty.is_vector() => {
- fx.bcx.ins().raw_bitcast(dst_ty, data)
- }
+ _ if src_ty.is_vector() && dst_ty.is_vector() => fx.bcx.ins().bitcast(dst_ty, data),
_ if src_ty.is_vector() || dst_ty.is_vector() => {
// FIXME do something more efficient for transmutes between vectors and integers.
let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
return;
}
CPlaceInner::VarPair(_local, var1, var2) => {
- let (data1, data2) = CValue(from.0, dst_layout).load_scalar_pair(fx);
+ let (ptr, meta) = from.force_stack(fx);
+ assert!(meta.is_none());
+ let (data1, data2) =
+ CValue(CValueInner::ByRef(ptr, None), dst_layout).load_scalar_pair(fx);
let (dst_ty1, dst_ty2) = fx.clif_pair_type(self.layout().ty).unwrap();
transmute_value(fx, var1, data1, dst_ty1);
transmute_value(fx, var2, data2, dst_ty2);
#!/usr/bin/env bash
-exec ./y.rs test
+exec ./y.rs test "$@"
# This block is ignored by rustc
set -e
echo "[BUILD] y.rs" 1>&2
-rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1
+rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021
exec ${0/.rs/.bin} $@
*/
use crate::llvm::archive_ro::{ArchiveRO, Child};
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
use rustc_codegen_ssa::back::archive::{
- get_native_object_symbols, try_extract_macho_fat_archive, ArArchiveBuilder,
- ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, UnknownArchiveKind,
+ get_native_object_symbols, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder,
+ ArchiveBuilderBuilder, UnknownArchiveKind,
};
use rustc_session::cstore::DllImport;
archive: &Path,
skip: Box<dyn FnMut(&str) -> bool + 'static>,
) -> io::Result<()> {
- let mut archive = archive.to_path_buf();
- if self.sess.target.llvm_target.contains("-apple-macosx") {
- if let Some(new_archive) = try_extract_macho_fat_archive(&self.sess, &archive)? {
- archive = new_archive
- }
- }
- let archive_ro = match ArchiveRO::open(&archive) {
+ let archive_ro = match ArchiveRO::open(archive) {
Ok(ar) => ar,
Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
};
return Ok(());
}
self.additions.push(Addition::Archive {
- path: archive,
+ path: archive.to_path_buf(),
archive: archive_ro,
skip: Box::new(skip),
});
}
pub(crate) fn prepare_thin(module: ModuleCodegen<ModuleLlvm>) -> (String, ThinBuffer) {
- let name = module.name.clone();
+ let name = module.name;
let buffer = ThinBuffer::new(module.module_llvm.llmod(), true);
(name, buffer)
}
use std::error::Error;
use std::fs::File;
-use std::io::{self, Write};
+use std::io;
use std::path::{Path, PathBuf};
// Re-exporting for rustc_codegen_llvm::back::archive
}
}
-fn try_filter_fat_archs(
+fn try_filter_fat_archs<'a>(
archs: object::read::Result<&[impl FatArch]>,
target_arch: object::Architecture,
- archive_path: &Path,
- archive_map_data: &[u8],
-) -> io::Result<Option<PathBuf>> {
+ archive_map_data: &'a [u8],
+) -> io::Result<Option<(&'a [u8], u64)>> {
let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let desired = match archs.iter().filter(|a| a.architecture() == target_arch).next() {
None => return Ok(None),
};
- let (mut new_f, extracted_path) = tempfile::Builder::new()
- .suffix(archive_path.file_name().unwrap())
- .tempfile()?
- .keep()
- .unwrap();
-
- new_f.write_all(
+ Ok(Some((
desired.data(archive_map_data).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?,
- )?;
-
- Ok(Some(extracted_path))
+ desired.offset().into(),
+ )))
}
-pub fn try_extract_macho_fat_archive(
+pub fn try_extract_macho_fat_archive<'a>(
sess: &Session,
- archive_path: &Path,
-) -> io::Result<Option<PathBuf>> {
- let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? };
+ archive_bytes: &'a [u8],
+) -> io::Result<Option<(&'a [u8], u64)>> {
let target_arch = match sess.target.arch.as_ref() {
"aarch64" => object::Architecture::Aarch64,
"x86_64" => object::Architecture::X86_64,
_ => return Ok(None),
};
- match object::macho::FatHeader::parse(&*archive_map) {
+ match object::macho::FatHeader::parse(archive_bytes) {
Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC => {
- let archs = object::macho::FatHeader::parse_arch32(&*archive_map);
- try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
+ let archs = object::macho::FatHeader::parse_arch32(archive_bytes);
+ try_filter_fat_archs(archs, target_arch, archive_bytes)
}
Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC_64 => {
- let archs = object::macho::FatHeader::parse_arch64(&*archive_map);
- try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
+ let archs = object::macho::FatHeader::parse_arch64(archive_bytes);
+ try_filter_fat_archs(archs, target_arch, archive_bytes)
}
// Not a FatHeader at all, just return None.
_ => Ok(None),
archive_path: &Path,
mut skip: Box<dyn FnMut(&str) -> bool + 'static>,
) -> io::Result<()> {
- let mut archive_path = archive_path.to_path_buf();
- if self.sess.target.llvm_target.contains("-apple-macosx") {
- if let Some(new_archive_path) =
- try_extract_macho_fat_archive(&self.sess, &archive_path)?
- {
- archive_path = new_archive_path
- }
- }
-
+ let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? };
if self.src_archives.iter().any(|archive| archive.0 == archive_path) {
return Ok(());
}
- let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? };
- let archive = ArchiveFile::parse(&*archive_map)
+ let (archive_bytes, offset) = if self.sess.target.llvm_target.contains("-apple-macosx") {
+ if let Some((sub_archive, archive_offset)) =
+ try_extract_macho_fat_archive(&self.sess, &*archive_map)?
+ {
+ (sub_archive, Some(archive_offset))
+ } else {
+ (&*archive_map, None)
+ }
+ } else {
+ (&*archive_map, None)
+ };
+
+ let archive = ArchiveFile::parse(&*archive_bytes)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
let archive_index = self.src_archives.len();
let file_name = String::from_utf8(entry.name().to_vec())
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
if !skip(&file_name) {
+ let mut range = entry.file_range();
+ if let Some(offset) = offset {
+ range.0 += offset;
+ }
self.entries.push((
file_name.into_bytes(),
- ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() },
+ ArchiveEntry::FromArchive { archive_index, file_range: range },
));
}
}
--- /dev/null
+use rustc_ast::{ast, MetaItemKind, NestedMetaItem};
+use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem};
+use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
+use rustc_middle::mir::mono::Linkage;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::{self as ty, DefIdTree, TyCtxt};
+use rustc_session::{lint, parse::feature_err};
+use rustc_span::{sym, Span};
+use rustc_target::spec::{abi, SanitizerSet};
+
+use crate::target_features::from_target_feature;
+use crate::{errors::ExpectedUsedSymbol, target_features::check_target_feature_trait_unsafe};
+
+fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
+ use rustc_middle::mir::mono::Linkage::*;
+
+ // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
+ // applicable to variable declarations and may not really make sense for
+ // Rust code in the first place but allow them anyway and trust that the
+ // user knows what they're doing. Who knows, unanticipated use cases may pop
+ // up in the future.
+ //
+ // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
+ // and don't have to be, LLVM treats them as no-ops.
+ match name {
+ "appending" => Appending,
+ "available_externally" => AvailableExternally,
+ "common" => Common,
+ "extern_weak" => ExternalWeak,
+ "external" => External,
+ "internal" => Internal,
+ "linkonce" => LinkOnceAny,
+ "linkonce_odr" => LinkOnceODR,
+ "private" => Private,
+ "weak" => WeakAny,
+ "weak_odr" => WeakODR,
+ _ => tcx.sess.span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
+ }
+}
+
+fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
+ if cfg!(debug_assertions) {
+ let def_kind = tcx.def_kind(did);
+ assert!(
+ def_kind.has_codegen_attrs(),
+ "unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
+ );
+ }
+
+ let did = did.expect_local();
+ let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did));
+ let mut codegen_fn_attrs = CodegenFnAttrs::new();
+ if tcx.should_inherit_track_caller(did) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
+ }
+
+ let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
+
+ let mut inline_span = None;
+ let mut link_ordinal_span = None;
+ let mut no_sanitize_span = None;
+ for attr in attrs.iter() {
+ if attr.has_name(sym::cold) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
+ } else if attr.has_name(sym::rustc_allocator) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
+ } else if attr.has_name(sym::ffi_returns_twice) {
+ if tcx.is_foreign_item(did) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
+ } else {
+ // `#[ffi_returns_twice]` is only allowed `extern fn`s.
+ struct_span_err!(
+ tcx.sess,
+ attr.span,
+ E0724,
+ "`#[ffi_returns_twice]` may only be used on foreign functions"
+ )
+ .emit();
+ }
+ } else if attr.has_name(sym::ffi_pure) {
+ if tcx.is_foreign_item(did) {
+ if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
+ // `#[ffi_const]` functions cannot be `#[ffi_pure]`
+ struct_span_err!(
+ tcx.sess,
+ attr.span,
+ E0757,
+ "`#[ffi_const]` function cannot be `#[ffi_pure]`"
+ )
+ .emit();
+ } else {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE;
+ }
+ } else {
+ // `#[ffi_pure]` is only allowed on foreign functions
+ struct_span_err!(
+ tcx.sess,
+ attr.span,
+ E0755,
+ "`#[ffi_pure]` may only be used on foreign functions"
+ )
+ .emit();
+ }
+ } else if attr.has_name(sym::ffi_const) {
+ if tcx.is_foreign_item(did) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
+ } else {
+ // `#[ffi_const]` is only allowed on foreign functions
+ struct_span_err!(
+ tcx.sess,
+ attr.span,
+ E0756,
+ "`#[ffi_const]` may only be used on foreign functions"
+ )
+ .emit();
+ }
+ } else if attr.has_name(sym::rustc_nounwind) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
+ } else if attr.has_name(sym::rustc_reallocator) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;
+ } else if attr.has_name(sym::rustc_deallocator) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR;
+ } else if attr.has_name(sym::rustc_allocator_zeroed) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED;
+ } else if attr.has_name(sym::naked) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
+ } else if attr.has_name(sym::no_mangle) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
+ } else if attr.has_name(sym::no_coverage) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
+ } else if attr.has_name(sym::rustc_std_internal_symbol) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
+ } else if attr.has_name(sym::used) {
+ let inner = attr.meta_item_list();
+ match inner.as_deref() {
+ Some([item]) if item.has_name(sym::linker) => {
+ if !tcx.features().used_with_arg {
+ feature_err(
+ &tcx.sess.parse_sess,
+ sym::used_with_arg,
+ attr.span,
+ "`#[used(linker)]` is currently unstable",
+ )
+ .emit();
+ }
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
+ }
+ Some([item]) if item.has_name(sym::compiler) => {
+ if !tcx.features().used_with_arg {
+ feature_err(
+ &tcx.sess.parse_sess,
+ sym::used_with_arg,
+ attr.span,
+ "`#[used(compiler)]` is currently unstable",
+ )
+ .emit();
+ }
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
+ }
+ Some(_) => {
+ tcx.sess.emit_err(ExpectedUsedSymbol { span: attr.span });
+ }
+ None => {
+ // Unfortunately, unconditionally using `llvm.used` causes
+ // issues in handling `.init_array` with the gold linker,
+ // but using `llvm.compiler.used` caused a nontrival amount
+ // of unintentional ecosystem breakage -- particularly on
+ // Mach-O targets.
+ //
+ // As a result, we emit `llvm.compiler.used` only on ELF
+ // targets. This is somewhat ad-hoc, but actually follows
+ // our pre-LLVM 13 behavior (prior to the ecosystem
+ // breakage), and seems to match `clang`'s behavior as well
+ // (both before and after LLVM 13), possibly because they
+ // have similar compatibility concerns to us. See
+ // https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146
+ // and following comments for some discussion of this, as
+ // well as the comments in `rustc_codegen_llvm` where these
+ // flags are handled.
+ //
+ // Anyway, to be clear: this is still up in the air
+ // somewhat, and is subject to change in the future (which
+ // is a good thing, because this would ideally be a bit
+ // more firmed up).
+ let is_like_elf = !(tcx.sess.target.is_like_osx
+ || tcx.sess.target.is_like_windows
+ || tcx.sess.target.is_like_wasm);
+ codegen_fn_attrs.flags |= if is_like_elf {
+ CodegenFnAttrFlags::USED
+ } else {
+ CodegenFnAttrFlags::USED_LINKER
+ };
+ }
+ }
+ } else if attr.has_name(sym::cmse_nonsecure_entry) {
+ if !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. }) {
+ struct_span_err!(
+ tcx.sess,
+ attr.span,
+ E0776,
+ "`#[cmse_nonsecure_entry]` requires C ABI"
+ )
+ .emit();
+ }
+ if !tcx.sess.target.llvm_target.contains("thumbv8m") {
+ struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
+ .emit();
+ }
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY;
+ } else if attr.has_name(sym::thread_local) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
+ } else if attr.has_name(sym::track_caller) {
+ if !tcx.is_closure(did.to_def_id()) && tcx.fn_sig(did).abi() != abi::Abi::Rust {
+ struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
+ .emit();
+ }
+ if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller {
+ feature_err(
+ &tcx.sess.parse_sess,
+ sym::closure_track_caller,
+ attr.span,
+ "`#[track_caller]` on closures is currently unstable",
+ )
+ .emit();
+ }
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
+ } else if attr.has_name(sym::export_name) {
+ if let Some(s) = attr.value_str() {
+ if s.as_str().contains('\0') {
+ // `#[export_name = ...]` will be converted to a null-terminated string,
+ // so it may not contain any null characters.
+ struct_span_err!(
+ tcx.sess,
+ attr.span,
+ E0648,
+ "`export_name` may not contain null characters"
+ )
+ .emit();
+ }
+ codegen_fn_attrs.export_name = Some(s);
+ }
+ } else if attr.has_name(sym::target_feature) {
+ if !tcx.is_closure(did.to_def_id())
+ && tcx.fn_sig(did).unsafety() == hir::Unsafety::Normal
+ {
+ if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
+ // The `#[target_feature]` attribute is allowed on
+ // WebAssembly targets on all functions, including safe
+ // ones. Other targets require that `#[target_feature]` is
+ // only applied to unsafe functions (pending the
+ // `target_feature_11` feature) because on most targets
+ // execution of instructions that are not supported is
+ // considered undefined behavior. For WebAssembly which is a
+ // 100% safe target at execution time it's not possible to
+ // execute undefined instructions, and even if a future
+ // feature was added in some form for this it would be a
+ // deterministic trap. There is no undefined behavior when
+ // executing WebAssembly so `#[target_feature]` is allowed
+ // on safe functions (but again, only for WebAssembly)
+ //
+ // Note that this is also allowed if `actually_rustdoc` so
+ // if a target is documenting some wasm-specific code then
+ // it's not spuriously denied.
+ } else if !tcx.features().target_feature_11 {
+ let mut err = feature_err(
+ &tcx.sess.parse_sess,
+ sym::target_feature_11,
+ attr.span,
+ "`#[target_feature(..)]` can only be applied to `unsafe` functions",
+ );
+ err.span_label(tcx.def_span(did), "not an `unsafe` function");
+ err.emit();
+ } else {
+ check_target_feature_trait_unsafe(tcx, did, attr.span);
+ }
+ }
+ from_target_feature(
+ tcx,
+ attr,
+ supported_target_features,
+ &mut codegen_fn_attrs.target_features,
+ );
+ } else if attr.has_name(sym::linkage) {
+ if let Some(val) = attr.value_str() {
+ let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
+ if tcx.is_foreign_item(did) {
+ codegen_fn_attrs.import_linkage = linkage;
+ } else {
+ codegen_fn_attrs.linkage = linkage;
+ }
+ }
+ } else if attr.has_name(sym::link_section) {
+ if let Some(val) = attr.value_str() {
+ if val.as_str().bytes().any(|b| b == 0) {
+ let msg = format!(
+ "illegal null byte in link_section \
+ value: `{}`",
+ &val
+ );
+ tcx.sess.span_err(attr.span, &msg);
+ } else {
+ codegen_fn_attrs.link_section = Some(val);
+ }
+ }
+ } else if attr.has_name(sym::link_name) {
+ codegen_fn_attrs.link_name = attr.value_str();
+ } else if attr.has_name(sym::link_ordinal) {
+ link_ordinal_span = Some(attr.span);
+ if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
+ codegen_fn_attrs.link_ordinal = ordinal;
+ }
+ } else if attr.has_name(sym::no_sanitize) {
+ no_sanitize_span = Some(attr.span);
+ if let Some(list) = attr.meta_item_list() {
+ for item in list.iter() {
+ if item.has_name(sym::address) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
+ } else if item.has_name(sym::cfi) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
+ } else if item.has_name(sym::kcfi) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI;
+ } else if item.has_name(sym::memory) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
+ } else if item.has_name(sym::memtag) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
+ } else if item.has_name(sym::shadow_call_stack) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK;
+ } else if item.has_name(sym::thread) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
+ } else if item.has_name(sym::hwaddress) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
+ } else {
+ tcx.sess
+ .struct_span_err(item.span(), "invalid argument for `no_sanitize`")
+ .note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
+ .emit();
+ }
+ }
+ }
+ } else if attr.has_name(sym::instruction_set) {
+ codegen_fn_attrs.instruction_set = match attr.meta_kind() {
+ Some(MetaItemKind::List(ref items)) => match items.as_slice() {
+ [NestedMetaItem::MetaItem(set)] => {
+ let segments =
+ set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
+ match segments.as_slice() {
+ [sym::arm, sym::a32] | [sym::arm, sym::t32] => {
+ if !tcx.sess.target.has_thumb_interworking {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ attr.span,
+ E0779,
+ "target does not support `#[instruction_set]`"
+ )
+ .emit();
+ None
+ } else if segments[1] == sym::a32 {
+ Some(InstructionSetAttr::ArmA32)
+ } else if segments[1] == sym::t32 {
+ Some(InstructionSetAttr::ArmT32)
+ } else {
+ unreachable!()
+ }
+ }
+ _ => {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ attr.span,
+ E0779,
+ "invalid instruction set specified",
+ )
+ .emit();
+ None
+ }
+ }
+ }
+ [] => {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ attr.span,
+ E0778,
+ "`#[instruction_set]` requires an argument"
+ )
+ .emit();
+ None
+ }
+ _ => {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ attr.span,
+ E0779,
+ "cannot specify more than one instruction set"
+ )
+ .emit();
+ None
+ }
+ },
+ _ => {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ attr.span,
+ E0778,
+ "must specify an instruction set"
+ )
+ .emit();
+ None
+ }
+ };
+ } else if attr.has_name(sym::repr) {
+ codegen_fn_attrs.alignment = match attr.meta_item_list() {
+ Some(items) => match items.as_slice() {
+ [item] => match item.name_value_literal() {
+ Some((sym::align, literal)) => {
+ let alignment = rustc_attr::parse_alignment(&literal.kind);
+
+ match alignment {
+ Ok(align) => Some(align),
+ Err(msg) => {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ attr.span,
+ E0589,
+ "invalid `repr(align)` attribute: {}",
+ msg
+ )
+ .emit();
+
+ None
+ }
+ }
+ }
+ _ => None,
+ },
+ [] => None,
+ _ => None,
+ },
+ None => None,
+ };
+ }
+ }
+
+ codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
+ if !attr.has_name(sym::inline) {
+ return ia;
+ }
+ match attr.meta_kind() {
+ Some(MetaItemKind::Word) => InlineAttr::Hint,
+ Some(MetaItemKind::List(ref items)) => {
+ inline_span = Some(attr.span);
+ if items.len() != 1 {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ attr.span,
+ E0534,
+ "expected one argument"
+ )
+ .emit();
+ InlineAttr::None
+ } else if list_contains_name(&items, sym::always) {
+ InlineAttr::Always
+ } else if list_contains_name(&items, sym::never) {
+ InlineAttr::Never
+ } else {
+ struct_span_err!(
+ tcx.sess.diagnostic(),
+ items[0].span(),
+ E0535,
+ "invalid argument"
+ )
+ .help("valid inline arguments are `always` and `never`")
+ .emit();
+
+ InlineAttr::None
+ }
+ }
+ Some(MetaItemKind::NameValue(_)) => ia,
+ None => ia,
+ }
+ });
+
+ codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
+ if !attr.has_name(sym::optimize) {
+ return ia;
+ }
+ let err = |sp, s| struct_span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s).emit();
+ match attr.meta_kind() {
+ Some(MetaItemKind::Word) => {
+ err(attr.span, "expected one argument");
+ ia
+ }
+ Some(MetaItemKind::List(ref items)) => {
+ inline_span = Some(attr.span);
+ if items.len() != 1 {
+ err(attr.span, "expected one argument");
+ OptimizeAttr::None
+ } else if list_contains_name(&items, sym::size) {
+ OptimizeAttr::Size
+ } else if list_contains_name(&items, sym::speed) {
+ OptimizeAttr::Speed
+ } else {
+ err(items[0].span(), "invalid argument");
+ OptimizeAttr::None
+ }
+ }
+ Some(MetaItemKind::NameValue(_)) => ia,
+ None => ia,
+ }
+ });
+
+ // #73631: closures inherit `#[target_feature]` annotations
+ if tcx.features().target_feature_11 && tcx.is_closure(did.to_def_id()) {
+ let owner_id = tcx.parent(did.to_def_id());
+ if tcx.def_kind(owner_id).has_codegen_attrs() {
+ codegen_fn_attrs
+ .target_features
+ .extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied());
+ }
+ }
+
+ // If a function uses #[target_feature] it can't be inlined into general
+ // purpose functions as they wouldn't have the right target features
+ // enabled. For that reason we also forbid #[inline(always)] as it can't be
+ // respected.
+ if !codegen_fn_attrs.target_features.is_empty() {
+ if codegen_fn_attrs.inline == InlineAttr::Always {
+ if let Some(span) = inline_span {
+ tcx.sess.span_err(
+ span,
+ "cannot use `#[inline(always)]` with \
+ `#[target_feature]`",
+ );
+ }
+ }
+ }
+
+ if !codegen_fn_attrs.no_sanitize.is_empty() {
+ if codegen_fn_attrs.inline == InlineAttr::Always {
+ if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(did);
+ tcx.struct_span_lint_hir(
+ lint::builtin::INLINE_NO_SANITIZE,
+ hir_id,
+ no_sanitize_span,
+ "`no_sanitize` will have no effect after inlining",
+ |lint| lint.span_note(inline_span, "inlining requested here"),
+ )
+ }
+ }
+ }
+
+ if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
+ codegen_fn_attrs.inline = InlineAttr::Never;
+ }
+
+ // Weak lang items have the same semantics as "std internal" symbols in the
+ // sense that they're preserved through all our LTO passes and only
+ // strippable by the linker.
+ //
+ // Additionally weak lang items have predetermined symbol names.
+ if WEAK_LANG_ITEMS.iter().any(|&l| tcx.lang_items().get(l) == Some(did.to_def_id())) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
+ }
+ if let Some((name, _)) = lang_items::extract(attrs)
+ && let Some(lang_item) = LangItem::from_name(name)
+ && let Some(link_name) = lang_item.link_name()
+ {
+ codegen_fn_attrs.export_name = Some(link_name);
+ codegen_fn_attrs.link_name = Some(link_name);
+ }
+ check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
+
+ // Internal symbols to the standard library all have no_mangle semantics in
+ // that they have defined symbol names present in the function name. This
+ // also applies to weak symbols where they all have known symbol names.
+ if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
+ }
+
+ // Any linkage to LLVM intrinsics for now forcibly marks them all as never
+ // unwinds since LLVM sometimes can't handle codegen which `invoke`s
+ // intrinsic functions.
+ if let Some(name) = &codegen_fn_attrs.link_name {
+ if name.as_str().starts_with("llvm.") {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
+ }
+ }
+
+ codegen_fn_attrs
+}
+
+/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
+/// applied to the method prototype.
+fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+ if let Some(impl_item) = tcx.opt_associated_item(def_id)
+ && let ty::AssocItemContainer::ImplContainer = impl_item.container
+ && let Some(trait_item) = impl_item.trait_item_def_id
+ {
+ return tcx
+ .codegen_fn_attrs(trait_item)
+ .flags
+ .intersects(CodegenFnAttrFlags::TRACK_CALLER);
+ }
+
+ false
+}
+
+fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
+ use rustc_ast::{LitIntType, LitKind, MetaItemLit};
+ if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" {
+ feature_err(
+ &tcx.sess.parse_sess,
+ sym::raw_dylib,
+ attr.span,
+ "`#[link_ordinal]` is unstable on x86",
+ )
+ .emit();
+ }
+ let meta_item_list = attr.meta_item_list();
+ let meta_item_list = meta_item_list.as_deref();
+ let sole_meta_list = match meta_item_list {
+ Some([item]) => item.lit(),
+ Some(_) => {
+ tcx.sess
+ .struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`")
+ .note("the attribute requires exactly one argument")
+ .emit();
+ return None;
+ }
+ _ => None,
+ };
+ if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
+ sole_meta_list
+ {
+ // According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header,
+ // the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
+ // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information
+ // to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
+ //
+ // FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for this:
+ // both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies
+ // a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import library
+ // for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import
+ // library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I don't know yet
+ // if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment
+ // about LINK.EXE failing.)
+ if *ordinal <= u16::MAX as u128 {
+ Some(*ordinal as u16)
+ } else {
+ let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
+ tcx.sess
+ .struct_span_err(attr.span, &msg)
+ .note("the value may not exceed `u16::MAX`")
+ .emit();
+ None
+ }
+ } else {
+ tcx.sess
+ .struct_span_err(attr.span, "illegal ordinal format in `link_ordinal`")
+ .note("an unsuffixed integer value, e.g., `1`, is expected")
+ .emit();
+ None
+ }
+}
+
+fn check_link_name_xor_ordinal(
+ tcx: TyCtxt<'_>,
+ codegen_fn_attrs: &CodegenFnAttrs,
+ inline_span: Option<Span>,
+) {
+ if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() {
+ return;
+ }
+ let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
+ if let Some(span) = inline_span {
+ tcx.sess.span_err(span, msg);
+ } else {
+ tcx.sess.err(msg);
+ }
+}
+
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
+}
let projection_bounds: SmallVec<[_; 4]> = trait_data
.projection_bounds()
.map(|bound| {
- let ExistentialProjection { item_def_id, term, .. } =
+ let ExistentialProjection { def_id: item_def_id, term, .. } =
tcx.erase_late_bound_regions(bound);
// FIXME(associated_const_equality): allow for consts here
(item_def_id, term.ty().unwrap())
ty::Error(_)
| ty::Infer(_)
| ty::Placeholder(..)
- | ty::Projection(..)
+ | ty::Alias(..)
| ty::Bound(..)
- | ty::Opaque(..)
| ty::GeneratorWitness(..) => {
bug!(
"debuginfo: Trying to create type name for \
pub struct UnknownArchiveKind<'a> {
pub kind: &'a str,
}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_expected_used_symbol)]
+pub struct ExpectedUsedSymbol {
+ #[primary_span]
+ pub span: Span,
+}
pub mod back;
pub mod base;
+pub mod codegen_attrs;
pub mod common;
pub mod coverageinfo;
pub mod debuginfo;
crate::back::symbol_export::provide(providers);
crate::base::provide(providers);
crate::target_features::provide(providers);
+ crate::codegen_attrs::provide(providers);
}
pub fn provide_extern(providers: &mut ExternProviders) {
match (src.layout.abi, dst.layout.abi) {
(abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
// HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
- if (src_scalar.primitive() == abi::Pointer)
- == (dst_scalar.primitive() == abi::Pointer)
- {
+ let src_is_ptr = src_scalar.primitive() == abi::Pointer;
+ let dst_is_ptr = dst_scalar.primitive() == abi::Pointer;
+ if src_is_ptr == dst_is_ptr {
assert_eq!(src.layout.size, dst.layout.size);
// NOTE(eddyb) the `from_immediate` and `to_immediate_scalar`
// conversions allow handling `bool`s the same as `u8`s.
let src = bx.from_immediate(src.immediate());
- let src_as_dst = bx.bitcast(src, bx.backend_type(dst.layout));
+ // LLVM also doesn't like `bitcast`s between pointers in different address spaces.
+ let src_as_dst = if src_is_ptr {
+ bx.pointercast(src, bx.backend_type(dst.layout))
+ } else {
+ bx.bitcast(src, bx.backend_type(dst.layout))
+ };
Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst);
return;
}
+use rustc_ast::ast;
+use rustc_attr::InstructionSetAttr;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::TyCtxt;
+use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::symbol::Symbol;
+use rustc_span::Span;
/// Features that control behaviour of rustc, rather than the codegen.
pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
}
}
-pub(crate) fn provide(providers: &mut Providers) {
- providers.supported_target_features = |tcx, cnum| {
- assert_eq!(cnum, LOCAL_CRATE);
- if tcx.sess.opts.actually_rustdoc {
- // rustdoc needs to be able to document functions that use all the features, so
- // whitelist them all
- all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
- } else {
- supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect()
- }
+pub fn from_target_feature(
+ tcx: TyCtxt<'_>,
+ attr: &ast::Attribute,
+ supported_target_features: &FxHashMap<String, Option<Symbol>>,
+ target_features: &mut Vec<Symbol>,
+) {
+ let Some(list) = attr.meta_item_list() else { return };
+ let bad_item = |span| {
+ let msg = "malformed `target_feature` attribute input";
+ let code = "enable = \"..\"";
+ tcx.sess
+ .struct_span_err(span, msg)
+ .span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
+ .emit();
};
+ let rust_features = tcx.features();
+ for item in list {
+ // Only `enable = ...` is accepted in the meta-item list.
+ if !item.has_name(sym::enable) {
+ bad_item(item.span());
+ continue;
+ }
+
+ // Must be of the form `enable = "..."` (a string).
+ let Some(value) = item.value_str() else {
+ bad_item(item.span());
+ continue;
+ };
+
+ // We allow comma separation to enable multiple features.
+ target_features.extend(value.as_str().split(',').filter_map(|feature| {
+ let Some(feature_gate) = supported_target_features.get(feature) else {
+ let msg =
+ format!("the feature named `{}` is not valid for this target", feature);
+ let mut err = tcx.sess.struct_span_err(item.span(), &msg);
+ err.span_label(
+ item.span(),
+ format!("`{}` is not valid for this target", feature),
+ );
+ if let Some(stripped) = feature.strip_prefix('+') {
+ let valid = supported_target_features.contains_key(stripped);
+ if valid {
+ err.help("consider removing the leading `+` in the feature name");
+ }
+ }
+ err.emit();
+ return None;
+ };
+
+ // Only allow features whose feature gates have been enabled.
+ let allowed = match feature_gate.as_ref().copied() {
+ Some(sym::arm_target_feature) => rust_features.arm_target_feature,
+ Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
+ Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
+ Some(sym::mips_target_feature) => rust_features.mips_target_feature,
+ Some(sym::riscv_target_feature) => rust_features.riscv_target_feature,
+ Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
+ Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
+ Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
+ Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
+ Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature,
+ Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
+ Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
+ Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
+ Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
+ Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
+ Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
+ Some(name) => bug!("unknown target feature gate {}", name),
+ None => true,
+ };
+ if !allowed {
+ feature_err(
+ &tcx.sess.parse_sess,
+ feature_gate.unwrap(),
+ item.span(),
+ &format!("the target feature `{}` is currently unstable", feature),
+ )
+ .emit();
+ }
+ Some(Symbol::intern(feature))
+ }));
+ }
+}
+
+/// Computes the set of target features used in a function for the purposes of
+/// inline assembly.
+fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> {
+ let mut target_features = tcx.sess.unstable_target_features.clone();
+ if tcx.def_kind(did).has_codegen_attrs() {
+ let attrs = tcx.codegen_fn_attrs(did);
+ target_features.extend(&attrs.target_features);
+ match attrs.instruction_set {
+ None => {}
+ Some(InstructionSetAttr::ArmA32) => {
+ target_features.remove(&sym::thumb_mode);
+ }
+ Some(InstructionSetAttr::ArmT32) => {
+ target_features.insert(sym::thumb_mode);
+ }
+ }
+ }
+
+ tcx.arena.alloc(target_features)
+}
+
+/// Checks the function annotated with `#[target_feature]` is not a safe
+/// trait method implementation, reporting an error if it is.
+pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(id);
+ let node = tcx.hir().get(hir_id);
+ if let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
+ let parent_id = tcx.hir().get_parent_item(hir_id);
+ let parent_item = tcx.hir().expect_item(parent_id.def_id);
+ if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
+ tcx.sess
+ .struct_span_err(
+ attr_span,
+ "`#[target_feature(..)]` cannot be applied to safe trait method",
+ )
+ .span_label(attr_span, "cannot be applied to safe trait method")
+ .span_label(tcx.def_span(id), "not an `unsafe` function")
+ .emit();
+ }
+ }
+}
+
+pub(crate) fn provide(providers: &mut Providers) {
+ *providers = Providers {
+ supported_target_features: |tcx, cnum| {
+ assert_eq!(cnum, LOCAL_CRATE);
+ if tcx.sess.opts.actually_rustdoc {
+ // rustdoc needs to be able to document functions that use all the features, so
+ // whitelist them all
+ all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
+ } else {
+ supported_target_features(tcx.sess)
+ .iter()
+ .map(|&(a, b)| (a.to_string(), b))
+ .collect()
+ }
+ },
+ asm_target_features,
+ ..*providers
+ }
}
self.report_decorated(tcx, message, |_| {})
}
+ #[instrument(level = "trace", skip(self, decorate))]
+ pub(super) fn decorate(&self, err: &mut Diagnostic, decorate: impl FnOnce(&mut Diagnostic)) {
+ trace!("reporting const eval failure at {:?}", self.span);
+ // Add some more context for select error types.
+ match self.error {
+ InterpError::Unsupported(
+ UnsupportedOpInfo::ReadPointerAsBytes
+ | UnsupportedOpInfo::PartialPointerOverwrite(_)
+ | UnsupportedOpInfo::PartialPointerCopy(_),
+ ) => {
+ err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
+ err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
+ }
+ _ => {}
+ }
+ // Add spans for the stacktrace. Don't print a single-line backtrace though.
+ if self.stacktrace.len() > 1 {
+ // Helper closure to print duplicated lines.
+ let mut flush_last_line = |last_frame, times| {
+ if let Some((line, span)) = last_frame {
+ err.span_note(span, &line);
+ // Don't print [... additional calls ...] if the number of lines is small
+ if times < 3 {
+ for _ in 0..times {
+ err.span_note(span, &line);
+ }
+ } else {
+ err.span_note(
+ span,
+ format!("[... {} additional calls {} ...]", times, &line),
+ );
+ }
+ }
+ };
+
+ let mut last_frame = None;
+ let mut times = 0;
+ for frame_info in &self.stacktrace {
+ let frame = (frame_info.to_string(), frame_info.span);
+ if last_frame.as_ref() == Some(&frame) {
+ times += 1;
+ } else {
+ flush_last_line(last_frame, times);
+ last_frame = Some(frame);
+ times = 0;
+ }
+ }
+ flush_last_line(last_frame, times);
+ }
+ // Let the caller attach any additional information it wants.
+ decorate(err);
+ }
+
/// Create a diagnostic for this const eval error.
///
/// Sets the message passed in via `message` and adds span labels with detailed error
message: &str,
decorate: impl FnOnce(&mut Diagnostic),
) -> ErrorHandled {
- let finish = |err: &mut Diagnostic, span_msg: Option<String>| {
- trace!("reporting const eval failure at {:?}", self.span);
- if let Some(span_msg) = span_msg {
- err.span_label(self.span, span_msg);
- }
- // Add some more context for select error types.
- match self.error {
- InterpError::Unsupported(
- UnsupportedOpInfo::ReadPointerAsBytes
- | UnsupportedOpInfo::PartialPointerOverwrite(_)
- | UnsupportedOpInfo::PartialPointerCopy(_),
- ) => {
- err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
- err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
- }
- _ => {}
- }
- // Add spans for the stacktrace. Don't print a single-line backtrace though.
- if self.stacktrace.len() > 1 {
- // Helper closure to print duplicated lines.
- let mut flush_last_line = |last_frame, times| {
- if let Some((line, span)) = last_frame {
- err.span_note(span, &line);
- // Don't print [... additional calls ...] if the number of lines is small
- if times < 3 {
- for _ in 0..times {
- err.span_note(span, &line);
- }
- } else {
- err.span_note(
- span,
- format!("[... {} additional calls {} ...]", times, &line),
- );
- }
- }
- };
-
- let mut last_frame = None;
- let mut times = 0;
- for frame_info in &self.stacktrace {
- let frame = (frame_info.to_string(), frame_info.span);
- if last_frame.as_ref() == Some(&frame) {
- times += 1;
- } else {
- flush_last_line(last_frame, times);
- last_frame = Some(frame);
- times = 0;
- }
- }
- flush_last_line(last_frame, times);
- }
- // Let the caller attach any additional information it wants.
- decorate(err);
- };
-
debug!("self.error: {:?}", self.error);
// Special handling for certain errors
match &self.error {
// Don't emit a new diagnostic for these errors
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
- return ErrorHandled::TooGeneric;
- }
- err_inval!(AlreadyReported(error_reported)) => {
- return ErrorHandled::Reported(*error_reported);
+ ErrorHandled::TooGeneric
}
+ err_inval!(AlreadyReported(error_reported)) => ErrorHandled::Reported(*error_reported),
err_inval!(Layout(LayoutError::SizeOverflow(_))) => {
// We must *always* hard error on these, even if the caller wants just a lint.
// The `message` makes little sense here, this is a more serious error than the
// caller thinks anyway.
// See <https://github.com/rust-lang/rust/pull/63152>.
let mut err = struct_error(tcx, &self.error.to_string());
- finish(&mut err, None);
- return ErrorHandled::Reported(err.emit());
+ self.decorate(&mut err, decorate);
+ ErrorHandled::Reported(err.emit())
}
- _ => {}
- };
-
- let err_msg = self.error.to_string();
-
- // Report as hard error.
- let mut err = struct_error(tcx, message);
- finish(&mut err, Some(err_msg));
- ErrorHandled::Reported(err.emit())
+ _ => {
+ // Report as hard error.
+ let mut err = struct_error(tcx, message);
+ err.span_label(self.span, self.error.to_string());
+ self.decorate(&mut err, decorate);
+ ErrorHandled::Reported(err.emit())
+ }
+ }
}
}
+use crate::const_eval::CheckAlignment;
use std::borrow::Cow;
use either::{Left, Right};
None => InternKind::Constant,
}
};
- ecx.machine.check_alignment = false; // interning doesn't need to respect alignment
+ ecx.machine.check_alignment = CheckAlignment::No; // interning doesn't need to respect alignment
intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
// we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway
tcx,
root_span,
param_env,
- CompileTimeInterpreter::new(
- tcx.const_eval_limit(),
- can_access_statics,
- /*check_alignment:*/ false,
- ),
+ CompileTimeInterpreter::new(tcx.const_eval_limit(), can_access_statics, CheckAlignment::No),
)
}
CompileTimeInterpreter::new(
tcx.const_eval_limit(),
/*can_access_statics:*/ is_static,
- /*check_alignment:*/ tcx.sess.opts.unstable_opts.extra_const_ub_checks,
+ if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
+ CheckAlignment::Error
+ } else {
+ CheckAlignment::FutureIncompat
+ },
),
);
use rustc_hir::def::DefKind;
-use rustc_hir::LangItem;
+use rustc_hir::{LangItem, CRATE_HIR_ID};
use rustc_middle::mir;
use rustc_middle::mir::interpret::PointerArithmetic;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::lint::builtin::INVALID_ALIGNMENT;
use std::borrow::Borrow;
use std::hash::Hash;
use std::ops::ControlFlow;
pub(super) can_access_statics: bool,
/// Whether to check alignment during evaluation.
- pub(super) check_alignment: bool,
+ pub(super) check_alignment: CheckAlignment,
+}
+
+#[derive(Copy, Clone)]
+pub enum CheckAlignment {
+ /// Ignore alignment when following relocations.
+ /// This is mainly used in interning.
+ No,
+ /// Hard error when dereferencing a misaligned pointer.
+ Error,
+ /// Emit a future incompat lint when dereferencing a misaligned pointer.
+ FutureIncompat,
+}
+
+impl CheckAlignment {
+ pub fn should_check(&self) -> bool {
+ match self {
+ CheckAlignment::No => false,
+ CheckAlignment::Error | CheckAlignment::FutureIncompat => true,
+ }
+ }
}
impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
pub(crate) fn new(
const_eval_limit: Limit,
can_access_statics: bool,
- check_alignment: bool,
+ check_alignment: CheckAlignment,
) -> Self {
CompileTimeInterpreter {
steps_remaining: const_eval_limit.0,
const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
#[inline(always)]
- fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+ fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
ecx.machine.check_alignment
}
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
}
+ fn alignment_check_failed(
+ ecx: &InterpCx<'mir, 'tcx, Self>,
+ has: Align,
+ required: Align,
+ check: CheckAlignment,
+ ) -> InterpResult<'tcx, ()> {
+ let err = err_ub!(AlignmentCheckFailed { has, required }).into();
+ match check {
+ CheckAlignment::Error => Err(err),
+ CheckAlignment::No => span_bug!(
+ ecx.cur_span(),
+ "`alignment_check_failed` called when no alignment check requested"
+ ),
+ CheckAlignment::FutureIncompat => {
+ let err = ConstEvalErr::new(ecx, err, None);
+ ecx.tcx.struct_span_lint_hir(
+ INVALID_ALIGNMENT,
+ ecx.stack().iter().find_map(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
+ err.span,
+ err.error.to_string(),
+ |db| {
+ err.decorate(db, |_| {});
+ db
+ },
+ );
+ Ok(())
+ }
+ }
+ }
+
fn load_mir(
ecx: &InterpCx<'mir, 'tcx, Self>,
instance: ty::InstanceDef<'tcx>,
| ty::Foreign(..)
| ty::Infer(ty::FreshIntTy(_))
| ty::Infer(ty::FreshFloatTy(_))
- | ty::Projection(..)
+ // FIXME(oli-obk): we could look behind opaque types
+ | ty::Alias(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Placeholder(..)
- // FIXME(oli-obk): we could look behind opaque types
- | ty::Opaque(..)
| ty::Infer(_)
// FIXME(oli-obk): we can probably encode closures just like structs
| ty::Closure(..)
| ty::Foreign(..)
| ty::Infer(ty::FreshIntTy(_))
| ty::Infer(ty::FreshFloatTy(_))
- | ty::Projection(..)
+ | ty::Alias(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Placeholder(..)
- | ty::Opaque(..)
| ty::Infer(_)
| ty::Closure(..)
| ty::Generator(..)
Right(span) => span,
}
}
+
+ pub fn lint_root(&self) -> Option<hir::HirId> {
+ self.current_source_info().and_then(|source_info| {
+ match &self.body.source_scopes[source_info.scope].local_data {
+ mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
+ mir::ClearCrossCrate::Clear => None,
+ }
+ })
+ }
}
impl<'tcx> fmt::Display for FrameInfo<'tcx> {
// This deliberately does *not* honor `requires_caller_location` since it is used for much
// more than just panics.
for frame in stack.iter().rev() {
- let lint_root = frame.current_source_info().and_then(|source_info| {
- match &frame.body.source_scopes[source_info.scope].local_data {
- mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
- mir::ClearCrossCrate::Clear => None,
- }
- });
+ let lint_root = frame.lint_root();
let span = frame.current_span();
frames.push(FrameInfo { span, instance: frame.instance, lint_root });
ty::Adt(ref adt, _) => {
ConstValue::from_machine_usize(adt.variants().len() as u64, &tcx)
}
- ty::Projection(_)
- | ty::Opaque(_, _)
- | ty::Param(_)
- | ty::Placeholder(_)
- | ty::Infer(_) => throw_inval!(TooGeneric),
+ ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
+ throw_inval!(TooGeneric)
+ }
ty::Bound(_, _) => bug!("bound ty during ctfe"),
ty::Bool
| ty::Char
use rustc_middle::mir;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::DefId;
-use rustc_target::abi::Size;
+use rustc_target::abi::{Align, Size};
use rustc_target::spec::abi::Abi as CallAbi;
+use crate::const_eval::CheckAlignment;
+
use super::{
AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
const PANIC_ON_ALLOC_FAIL: bool;
/// Whether memory accesses should be alignment-checked.
- fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+ fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment;
/// Whether, when checking alignment, we should look at the actual address and thus support
/// custom alignment logic based on whatever the integer address happens to be.
/// If this returns true, Provenance::OFFSET_IS_ADDR must be true.
fn use_addr_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+ fn alignment_check_failed(
+ ecx: &InterpCx<'mir, 'tcx, Self>,
+ has: Align,
+ required: Align,
+ check: CheckAlignment,
+ ) -> InterpResult<'tcx, ()>;
+
/// Whether to enforce the validity invariant
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
use rustc_target::abi::{Align, HasDataLayout, Size};
+use crate::const_eval::CheckAlignment;
+
use super::{
alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc, InterpCx,
InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, Scalar,
size: Size,
align: Align,
) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>> {
- let align = M::enforce_alignment(&self).then_some(align);
self.check_and_deref_ptr(
ptr,
size,
align,
+ M::enforce_alignment(self),
CheckInAllocMsg::MemoryAccessTest,
|alloc_id, offset, prov| {
let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
align: Align,
msg: CheckInAllocMsg,
) -> InterpResult<'tcx> {
- self.check_and_deref_ptr(ptr, size, Some(align), msg, |alloc_id, _, _| {
- let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
- Ok((size, align, ()))
- })?;
+ self.check_and_deref_ptr(
+ ptr,
+ size,
+ align,
+ CheckAlignment::Error,
+ msg,
+ |alloc_id, _, _| {
+ let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
+ Ok((size, align, ()))
+ },
+ )?;
Ok(())
}
&self,
ptr: Pointer<Option<M::Provenance>>,
size: Size,
- align: Option<Align>,
+ align: Align,
+ check: CheckAlignment,
msg: CheckInAllocMsg,
alloc_size: impl FnOnce(
AllocId,
M::ProvenanceExtra,
) -> InterpResult<'tcx, (Size, Align, T)>,
) -> InterpResult<'tcx, Option<T>> {
- fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
- if offset % align.bytes() == 0 {
- Ok(())
- } else {
- // The biggest power of two through which `offset` is divisible.
- let offset_pow2 = 1 << offset.trailing_zeros();
- throw_ub!(AlignmentCheckFailed {
- has: Align::from_bytes(offset_pow2).unwrap(),
- required: align,
- })
- }
- }
-
Ok(match self.ptr_try_get_alloc_id(ptr) {
Err(addr) => {
// We couldn't get a proper allocation. This is only okay if the access size is 0,
throw_ub!(DanglingIntPointer(addr, msg));
}
// Must be aligned.
- if let Some(align) = align {
- check_offset_align(addr, align)?;
+ if check.should_check() {
+ self.check_offset_align(addr, align, check)?;
}
None
}
}
// Test align. Check this last; if both bounds and alignment are violated
// we want the error to be about the bounds.
- if let Some(align) = align {
+ if check.should_check() {
if M::use_addr_for_alignment_check(self) {
// `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
- check_offset_align(ptr.addr().bytes(), align)?;
+ self.check_offset_align(ptr.addr().bytes(), align, check)?;
} else {
// Check allocation alignment and offset alignment.
if alloc_align.bytes() < align.bytes() {
- throw_ub!(AlignmentCheckFailed { has: alloc_align, required: align });
+ M::alignment_check_failed(self, alloc_align, align, check)?;
}
- check_offset_align(offset.bytes(), align)?;
+ self.check_offset_align(offset.bytes(), align, check)?;
}
}
}
})
}
+
+ fn check_offset_align(
+ &self,
+ offset: u64,
+ align: Align,
+ check: CheckAlignment,
+ ) -> InterpResult<'tcx> {
+ if offset % align.bytes() == 0 {
+ Ok(())
+ } else {
+ // The biggest power of two through which `offset` is divisible.
+ let offset_pow2 = 1 << offset.trailing_zeros();
+ M::alignment_check_failed(self, Align::from_bytes(offset_pow2).unwrap(), align, check)
+ }
+ }
}
/// Allocation accessors
size: Size,
align: Align,
) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra>>> {
- let align = M::enforce_alignment(self).then_some(align);
let ptr_and_alloc = self.check_and_deref_ptr(
ptr,
size,
align,
+ M::enforce_alignment(self),
CheckInAllocMsg::MemoryAccessTest,
|alloc_id, offset, prov| {
let alloc = self.get_alloc_raw(alloc_id)?;
.size_and_align_of_mplace(&mplace)?
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
assert!(mplace.align <= align, "dynamic alignment less strict than static one?");
- let align = M::enforce_alignment(self).then_some(align);
- self.check_ptr_access_align(
- mplace.ptr,
- size,
- align.unwrap_or(Align::ONE),
- CheckInAllocMsg::DerefTest,
- )?;
+ let align = if M::enforce_alignment(self).should_check() { align } else { Align::ONE };
+ self.check_ptr_access_align(mplace.ptr, size, align, CheckInAllocMsg::DerefTest)?;
Ok(())
}
| ty::Placeholder(..)
| ty::Bound(..)
| ty::Param(..)
- | ty::Opaque(..)
- | ty::Projection(..)
+ | ty::Alias(..)
| ty::GeneratorWitness(..) => bug!("Encountered invalid type {:?}", ty),
}
}
};
let always_live_locals = always_storage_live_locals(body);
- let storage_liveness = MaybeStorageLive::new(always_live_locals)
+ let storage_liveness = MaybeStorageLive::new(std::borrow::Cow::Owned(always_live_locals))
.into_engine(tcx, body)
.iterate_to_fixpoint()
.into_results_cursor(body);
param_env: ParamEnv<'tcx>,
mir_phase: MirPhase,
reachable_blocks: BitSet<BasicBlock>,
- storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive>,
+ storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'static>>,
place_cache: Vec<PlaceRef<'tcx>>,
value_cache: Vec<u128>,
}
};
let kind = match parent_ty.ty.kind() {
- &ty::Opaque(def_id, substs) => {
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
self.tcx.bound_type_of(def_id).subst(self.tcx, substs).kind()
}
kind => kind,
self.fail(location, "`SetDiscriminant`is not allowed until deaggregation");
}
let pty = place.ty(&self.body.local_decls, self.tcx).ty.kind();
- if !matches!(pty, ty::Adt(..) | ty::Generator(..) | ty::Opaque(..)) {
+ if !matches!(pty, ty::Adt(..) | ty::Generator(..) | ty::Alias(ty::Opaque, ..)) {
self.fail(
location,
format!(
use rustc_hir::def_id::DefId;
use rustc_hir::{lang_items, LangItem};
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AssocItemContainer, DefIdTree, Instance, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{AssocItemContainer, Instance, ParamEnv, Ty, TyCtxt};
use rustc_span::symbol::Ident;
use rustc_span::{sym, DesugaringKind, Span};
Normal {
self_arg: Option<Ident>,
desugaring: Option<(CallDesugaringKind, Ty<'tcx>)>,
- /// Whether the self type of the method call has an `.as_ref()` method.
- /// Used for better diagnostics.
- is_option_or_result: bool,
+ method_did: DefId,
},
/// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)`
FnCall { fn_trait_id: DefId, self_ty: Ty<'tcx> },
} else {
None
};
- let parent_did = tcx.parent(method_did);
- let parent_self_ty = (tcx.def_kind(parent_did) == rustc_hir::def::DefKind::Impl)
- .then_some(parent_did)
- .and_then(|did| match tcx.type_of(did).kind() {
- ty::Adt(def, ..) => Some(def.did()),
- _ => None,
- });
- let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
- matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
- });
- CallKind::Normal { self_arg, desugaring, is_option_or_result }
+ CallKind::Normal { self_arg, desugaring, method_did }
})
}
use rustc_session::Limit;
use rustc_target::abi::{Abi, FieldsShape, InitKind, Scalar, Variants};
-use crate::const_eval::CompileTimeInterpreter;
+use crate::const_eval::{CheckAlignment, CompileTimeInterpreter};
use crate::interpret::{InterpCx, MemoryKind, OpTy};
/// Determines if this type permits "raw" initialization by just transmuting some memory into an
let machine = CompileTimeInterpreter::new(
Limit::new(0),
/*can_access_statics:*/ false,
- /*check_alignment:*/ true,
+ CheckAlignment::Error,
);
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
// Types with identity (print the module path).
ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs)
| ty::FnDef(def_id, substs)
- | ty::Opaque(def_id, substs)
- | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs })
+ | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
| ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
pub const ALPHANUMERIC_ONLY: usize = 62;
pub const CASE_INSENSITIVE: usize = 36;
-const BASE_64: &[u8; MAX_BASE as usize] =
+const BASE_64: &[u8; MAX_BASE] =
b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$";
#[inline]
/// Iterate over the keys, sorted
#[inline]
pub fn keys(&self) -> impl Iterator<Item = &K> + ExactSizeIterator + DoubleEndedIterator {
- self.data.iter().map(|&(ref k, _)| k)
+ self.data.iter().map(|(k, _)| k)
}
/// Iterate over values, sorted by key
#[inline]
pub fn values(&self) -> impl Iterator<Item = &V> + ExactSizeIterator + DoubleEndedIterator {
- self.data.iter().map(|&(_, ref v)| v)
+ self.data.iter().map(|(_, v)| v)
}
#[inline]
K: Borrow<Q>,
Q: Ord + ?Sized,
{
- self.data.binary_search_by(|&(ref x, _)| x.borrow().cmp(key))
+ self.data.binary_search_by(|(x, _)| x.borrow().cmp(key))
}
#[inline]
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
let mut data: Vec<(K, V)> = iter.into_iter().collect();
- data.sort_unstable_by(|&(ref k1, _), &(ref k2, _)| k1.cmp(k2));
+ data.sort_unstable_by(|(k1, _), (k2, _)| k1.cmp(k2));
data.dedup_by(|&mut (ref k1, _), &mut (ref k2, _)| k1.cmp(k2) == Ordering::Equal);
SortedMap { data }
codegen_ssa_unknown_archive_kind =
Don't know how to build archive of type: {$kind}
+
+codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
.where_label = this `where` clause might not match the one in the trait
.bounds_label = this bound might be missing in the impl
+hir_analysis_async_trait_impl_should_be_async =
+ method `{$method_name}` should be async because the method from the trait is async
+ .trait_item_label = required because the trait method is async
+
hir_analysis_drop_impl_on_wrong_item =
the `Drop` trait may only be implemented for local structs, enums, and unions
.label = must be a struct, enum, or union in the current crate
`extern crate` is not idiomatic in the new edition
.suggestion = convert it to a `{$msg_code}`
-hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
-
hir_analysis_const_impl_for_non_const_trait =
const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
.suggestion = mark `{$trait_name}` as const
moving {$size} bytes
.label = value moved from here
.note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+
+monomorphize_couldnt_dump_mono_stats =
+ unexpected error occurred while dumping monomorphization stats: {$error}
parse_invalid_identifier_with_leading_number = expected identifier, found number literal
.label = identifiers cannot start with a number
+
+parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn`
+ .suggestion = replace `fn` with `impl` here
self.set_span(after);
for span_label in before.span_labels() {
if let Some(label) = span_label.label {
- self.span.push_span_label(after, label);
+ if span_label.is_primary {
+ self.span.push_span_label(after, label);
+ } else {
+ self.span.push_span_label(span_label.span, label);
+ }
}
}
self
debug_assert!(
!(suggestions
.iter()
- .flat_map(|suggs| suggs)
+ .flatten()
.any(|(sp, suggestion)| sp.is_empty() && suggestion.is_empty())),
"Span must not be empty and have no suggestion"
);
// see how it *looks* with
// very *weird* formats
// see?
- for &(ref text, ref style) in msg.iter() {
+ for (text, style) in msg.iter() {
let text = self.translate_message(text, args);
let lines = text.split('\n').collect::<Vec<_>>();
if lines.len() > 1 {
buffer.append(0, ": ", header_style);
label_width += 2;
}
- for &(ref text, _) in msg.iter() {
+ for (text, _) in msg.iter() {
let text = self.translate_message(text, args);
// Account for newlines to align output to its label.
for (line, text) in normalize_whitespace(&text).lines().enumerate() {
if !sm.ensure_source_file_source_present(annotated_file.file.clone()) {
if !self.short_message {
// We'll just print an unannotated message.
- for (annotation_id, line) in annotated_file.lines.into_iter().enumerate() {
+ for (annotation_id, line) in annotated_file.lines.iter().enumerate() {
let mut annotations = line.annotations.clone();
annotations.sort_by_key(|a| Reverse(a.start_col));
let mut line_idx = buffer.num_lines();
- buffer.append(
- line_idx,
- &format!(
- "{}:{}:{}",
- sm.filename_for_diagnostics(&annotated_file.file.name),
- sm.doctest_offset_line(&annotated_file.file.name, line.line_index),
- annotations[0].start_col + 1,
- ),
- Style::LineAndColumn,
- );
- if annotation_id == 0 {
- buffer.prepend(line_idx, "--> ", Style::LineNumber);
+
+ let labels: Vec<_> = annotations
+ .iter()
+ .filter_map(|a| Some((a.label.as_ref()?, a.is_primary)))
+ .filter(|(l, _)| !l.is_empty())
+ .collect();
+
+ if annotation_id == 0 || !labels.is_empty() {
+ buffer.append(
+ line_idx,
+ &format!(
+ "{}:{}:{}",
+ sm.filename_for_diagnostics(&annotated_file.file.name),
+ sm.doctest_offset_line(
+ &annotated_file.file.name,
+ line.line_index
+ ),
+ annotations[0].start_col + 1,
+ ),
+ Style::LineAndColumn,
+ );
+ if annotation_id == 0 {
+ buffer.prepend(line_idx, "--> ", Style::LineNumber);
+ } else {
+ buffer.prepend(line_idx, "::: ", Style::LineNumber);
+ }
for _ in 0..max_line_num_len {
buffer.prepend(line_idx, " ", Style::NoStyle);
}
line_idx += 1;
- };
- for (i, annotation) in annotations.into_iter().enumerate() {
- if let Some(label) = &annotation.label {
- let style = if annotation.is_primary {
- Style::LabelPrimary
- } else {
- Style::LabelSecondary
- };
- if annotation_id == 0 {
- buffer.prepend(line_idx, " |", Style::LineNumber);
- for _ in 0..max_line_num_len {
- buffer.prepend(line_idx, " ", Style::NoStyle);
- }
- line_idx += 1;
- buffer.append(line_idx + i, " = note: ", style);
- for _ in 0..max_line_num_len {
- buffer.prepend(line_idx, " ", Style::NoStyle);
- }
- } else {
- buffer.append(line_idx + i, ": ", style);
- }
- buffer.append(line_idx + i, label, style);
+ }
+ for (label, is_primary) in labels.into_iter() {
+ let style = if is_primary {
+ Style::LabelPrimary
+ } else {
+ Style::LabelSecondary
+ };
+ buffer.prepend(line_idx, " |", Style::LineNumber);
+ for _ in 0..max_line_num_len {
+ buffer.prepend(line_idx, " ", Style::NoStyle);
+ }
+ line_idx += 1;
+ buffer.append(line_idx, " = note: ", style);
+ for _ in 0..max_line_num_len {
+ buffer.prepend(line_idx, " ", Style::NoStyle);
}
+ buffer.append(line_idx, label, style);
+ line_idx += 1;
}
}
}
}
// Find overlapping multiline annotations, put them at different depths
- multiline_annotations.sort_by_key(|&(_, ref ml)| (ml.line_start, usize::MAX - ml.line_end));
+ multiline_annotations.sort_by_key(|(_, ml)| (ml.line_start, usize::MAX - ml.line_end));
for (_, ann) in multiline_annotations.clone() {
for (_, a) in multiline_annotations.iter_mut() {
// Move all other multiline annotations overlapping with this one
// Account for the difference between the width of the current code and the
// snippet being suggested, so that the *later* suggestions are correctly
// aligned on the screen.
- acc += len as isize - (cur_hi.col.0 - cur_lo.col.0) as isize;
+ acc += len - (cur_hi.col.0 - cur_lo.col.0) as isize;
}
prev_hi = cur_hi;
prev_line = sf.get_line(prev_hi.line - 1);
}
pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'hir>> {
- for param in self.params {
- if name == param.name.ident().name {
- return Some(param);
- }
- }
- None
+ self.params.iter().find(|¶m| name == param.name.ident().name)
}
pub fn spans(&self) -> MultiSpan {
let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);
let poly_trait_ref =
- ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars);
+ ty::Binder::bind_with_vars(tcx.mk_trait_ref(trait_def_id, substs), bound_vars);
debug!(?poly_trait_ref, ?assoc_bindings);
bounds.trait_bounds.push((poly_trait_ref, span, constness));
if let Some(b) = trait_segment.args().bindings.first() {
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
}
- ty::TraitRef::new(trait_def_id, substs)
+ self.tcx().mk_trait_ref(trait_def_id, substs)
}
#[instrument(level = "debug", skip(self, span))]
debug!(?substs_trait_ref_and_assoc_item);
- ty::ProjectionTy {
- item_def_id: assoc_item.def_id,
- substs: substs_trait_ref_and_assoc_item,
- }
+ self.tcx().mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
});
if !speculative {
// the "projection predicate" for:
//
// `<T as Iterator>::Item = u32`
- let assoc_item_def_id = projection_ty.skip_binder().item_def_id;
+ let assoc_item_def_id = projection_ty.skip_binder().def_id;
let def_kind = tcx.def_kind(assoc_item_def_id);
match (def_kind, term.unpack()) {
(hir::def::DefKind::AssocTy, ty::TermKind::Ty(_))
//
// Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
// parameter to have a skipped binder.
- let param_ty = tcx.mk_ty(ty::Projection(projection_ty.skip_binder()));
+ let param_ty = tcx.mk_ty(ty::Alias(ty::Projection, projection_ty.skip_binder()));
self.add_bounds(param_ty, ast_bounds.iter(), bounds, candidate.bound_vars());
}
}
assoc_item,
assoc_item,
default.span,
- ty::TraitRef { def_id: it.owner_id.to_def_id(), substs: trait_substs },
+ tcx.mk_trait_ref(it.owner_id.to_def_id(), trait_substs),
);
}
_ => {}
impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match *t.kind() {
- ty::Opaque(def, _) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
self.0.push(def);
ControlFlow::CONTINUE
}
return;
}
+ if let Err(_) = compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span) {
+ return;
+ }
+
if let Err(_) = compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
{
return;
Ok(())
}
+fn compare_asyncness<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_m: &ty::AssocItem,
+ impl_m_span: Span,
+ trait_m: &ty::AssocItem,
+ trait_item_span: Option<Span>,
+) -> Result<(), ErrorGuaranteed> {
+ if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
+ match tcx.fn_sig(impl_m.def_id).skip_binder().output().kind() {
+ ty::Alias(ty::Opaque, ..) => {
+ // allow both `async fn foo()` and `fn foo() -> impl Future`
+ }
+ ty::Error(rustc_errors::ErrorGuaranteed { .. }) => {
+ // We don't know if it's ok, but at least it's already an error.
+ }
+ _ => {
+ return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync {
+ span: impl_m_span,
+ method_name: trait_m.name,
+ trait_item_span,
+ }));
+ }
+ };
+ }
+
+ Ok(())
+}
+
#[instrument(skip(tcx), level = "debug", ret)]
pub fn collect_trait_impl_trait_tys<'tcx>(
tcx: TyCtxt<'tcx>,
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- if let ty::Projection(proj) = ty.kind()
- && self.tcx().def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
+ if let ty::Alias(ty::Projection, proj) = ty.kind()
+ && self.tcx().def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
{
- if let Some((ty, _)) = self.types.get(&proj.item_def_id) {
+ if let Some((ty, _)) = self.types.get(&proj.def_id) {
return *ty;
}
//FIXME(RPITIT): Deny nested RPITIT in substs too
span: self.span,
kind: TypeVariableOriginKind::MiscVariable,
});
- self.types.insert(proj.item_def_id, (infer_ty, proj.substs));
+ self.types.insert(proj.def_id, (infer_ty, proj.substs));
// Recurse into bounds
- for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.item_def_id).subst_iter_copied(self.tcx(), proj.substs) {
+ for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.def_id).subst_iter_copied(self.tcx(), proj.substs) {
let pred = pred.fold_with(self);
let pred = self.ocx.normalize(
&ObligationCause::misc(self.span, self.body_id),
ObligationCause::new(
self.span,
self.body_id,
- ObligationCauseCode::BindingObligation(proj.item_def_id, pred_span),
+ ObligationCauseCode::BindingObligation(proj.def_id, pred_span),
),
self.param_env,
pred,
let normalize_param_env = {
let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
match impl_ty_value.kind() {
- ty::Projection(proj)
- if proj.item_def_id == trait_ty.def_id && proj.substs == rebased_substs =>
+ ty::Alias(ty::Projection, proj)
+ if proj.def_id == trait_ty.def_id && proj.substs == rebased_substs =>
{
// Don't include this predicate if the projected type is
// exactly the same as the projection. This can occur in
_ => predicates.push(
ty::Binder::bind_with_vars(
ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy {
- item_def_id: trait_ty.def_id,
- substs: rebased_substs,
- },
+ projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_substs),
term: impl_ty_value.into(),
},
bound_vars,
// insert the associated types where they correspond, but for now let's be "lazy" and
// propose this instead of the following valid resugaring:
// `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
- where_clauses.push(format!(
- "{} = {}",
- tcx.def_path_str(p.projection_ty.item_def_id),
- p.term,
- ));
+ where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.def_id), p.term));
}
let where_clauses = if where_clauses.is_empty() {
String::new()
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() {
- ty::Projection(p) if p.item_def_id == self.gat => {
+ ty::Alias(ty::Projection, p) if p.def_id == self.gat => {
for (idx, subst) in p.substs.iter().enumerate() {
match subst.unpack() {
GenericArgKind::Lifetime(lt) if !lt.is_late_bound() => {
{
for arg in fn_output.walk() {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Projection(proj) = ty.kind()
- && tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
- && tcx.impl_trait_in_trait_parent(proj.item_def_id) == fn_def_id.to_def_id()
+ && let ty::Alias(ty::Projection, proj) = ty.kind()
+ && tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
+ && tcx.impl_trait_in_trait_parent(proj.def_id) == fn_def_id.to_def_id()
{
- let span = tcx.def_span(proj.item_def_id);
- let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id);
+ let span = tcx.def_span(proj.def_id);
+ let bounds = wfcx.tcx().explicit_item_bounds(proj.def_id);
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
let bound = ty::EarlyBinder(bound).subst(tcx, proj.substs);
let normalized_bound = wfcx.normalize(span, None, bound);
| ty::Tuple(..) => {
self.check_primitive_impl(item.owner_id.def_id, self_ty, items, ty.span)
}
- ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
+ ty::Alias(..) | ty::Param(_) => {
let mut err = struct_span_err!(
self.tcx.sess,
ty.span,
use crate::astconv::AstConv;
use crate::check::intrinsic::intrinsic_operation_unsafety;
use crate::errors;
-use rustc_ast as ast;
-use rustc_ast::{MetaItemKind, NestedMetaItem};
-use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
-use rustc_hir::{lang_items, GenericParamKind, LangItem, Node};
+use rustc_hir::{GenericParamKind, Node};
use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
-use rustc_middle::mir::mono::Linkage;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, ToPredicate, Ty, TyCtxt};
-use rustc_session::lint;
-use rustc_session::parse::feature_err;
+use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
-use rustc_target::spec::{abi, SanitizerSet};
+use rustc_target::spec::abi;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use std::iter;
impl_polarity,
is_foreign_item,
generator_kind,
- codegen_fn_attrs,
- asm_target_features,
collect_mod_item_types,
- should_inherit_track_caller,
..*providers
};
}
_ => bug!("generator_kind applied to non-local def-id {:?}", def_id),
}
}
-
-fn from_target_feature(
- tcx: TyCtxt<'_>,
- attr: &ast::Attribute,
- supported_target_features: &FxHashMap<String, Option<Symbol>>,
- target_features: &mut Vec<Symbol>,
-) {
- let Some(list) = attr.meta_item_list() else { return };
- let bad_item = |span| {
- let msg = "malformed `target_feature` attribute input";
- let code = "enable = \"..\"";
- tcx.sess
- .struct_span_err(span, msg)
- .span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
- .emit();
- };
- let rust_features = tcx.features();
- for item in list {
- // Only `enable = ...` is accepted in the meta-item list.
- if !item.has_name(sym::enable) {
- bad_item(item.span());
- continue;
- }
-
- // Must be of the form `enable = "..."` (a string).
- let Some(value) = item.value_str() else {
- bad_item(item.span());
- continue;
- };
-
- // We allow comma separation to enable multiple features.
- target_features.extend(value.as_str().split(',').filter_map(|feature| {
- let Some(feature_gate) = supported_target_features.get(feature) else {
- let msg =
- format!("the feature named `{}` is not valid for this target", feature);
- let mut err = tcx.sess.struct_span_err(item.span(), &msg);
- err.span_label(
- item.span(),
- format!("`{}` is not valid for this target", feature),
- );
- if let Some(stripped) = feature.strip_prefix('+') {
- let valid = supported_target_features.contains_key(stripped);
- if valid {
- err.help("consider removing the leading `+` in the feature name");
- }
- }
- err.emit();
- return None;
- };
-
- // Only allow features whose feature gates have been enabled.
- let allowed = match feature_gate.as_ref().copied() {
- Some(sym::arm_target_feature) => rust_features.arm_target_feature,
- Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
- Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
- Some(sym::mips_target_feature) => rust_features.mips_target_feature,
- Some(sym::riscv_target_feature) => rust_features.riscv_target_feature,
- Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
- Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
- Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
- Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
- Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature,
- Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
- Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
- Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
- Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
- Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
- Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
- Some(name) => bug!("unknown target feature gate {}", name),
- None => true,
- };
- if !allowed {
- feature_err(
- &tcx.sess.parse_sess,
- feature_gate.unwrap(),
- item.span(),
- &format!("the target feature `{}` is currently unstable", feature),
- )
- .emit();
- }
- Some(Symbol::intern(feature))
- }));
- }
-}
-
-fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
- use rustc_middle::mir::mono::Linkage::*;
-
- // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
- // applicable to variable declarations and may not really make sense for
- // Rust code in the first place but allow them anyway and trust that the
- // user knows what they're doing. Who knows, unanticipated use cases may pop
- // up in the future.
- //
- // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
- // and don't have to be, LLVM treats them as no-ops.
- match name {
- "appending" => Appending,
- "available_externally" => AvailableExternally,
- "common" => Common,
- "extern_weak" => ExternalWeak,
- "external" => External,
- "internal" => Internal,
- "linkonce" => LinkOnceAny,
- "linkonce_odr" => LinkOnceODR,
- "private" => Private,
- "weak" => WeakAny,
- "weak_odr" => WeakODR,
- _ => tcx.sess.span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
- }
-}
-
-fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
- if cfg!(debug_assertions) {
- let def_kind = tcx.def_kind(did);
- assert!(
- def_kind.has_codegen_attrs(),
- "unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
- );
- }
-
- let did = did.expect_local();
- let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did));
- let mut codegen_fn_attrs = CodegenFnAttrs::new();
- if tcx.should_inherit_track_caller(did) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
- }
-
- let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
-
- let mut inline_span = None;
- let mut link_ordinal_span = None;
- let mut no_sanitize_span = None;
- for attr in attrs.iter() {
- if attr.has_name(sym::cold) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
- } else if attr.has_name(sym::rustc_allocator) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
- } else if attr.has_name(sym::ffi_returns_twice) {
- if tcx.is_foreign_item(did) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
- } else {
- // `#[ffi_returns_twice]` is only allowed `extern fn`s.
- struct_span_err!(
- tcx.sess,
- attr.span,
- E0724,
- "`#[ffi_returns_twice]` may only be used on foreign functions"
- )
- .emit();
- }
- } else if attr.has_name(sym::ffi_pure) {
- if tcx.is_foreign_item(did) {
- if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
- // `#[ffi_const]` functions cannot be `#[ffi_pure]`
- struct_span_err!(
- tcx.sess,
- attr.span,
- E0757,
- "`#[ffi_const]` function cannot be `#[ffi_pure]`"
- )
- .emit();
- } else {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE;
- }
- } else {
- // `#[ffi_pure]` is only allowed on foreign functions
- struct_span_err!(
- tcx.sess,
- attr.span,
- E0755,
- "`#[ffi_pure]` may only be used on foreign functions"
- )
- .emit();
- }
- } else if attr.has_name(sym::ffi_const) {
- if tcx.is_foreign_item(did) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
- } else {
- // `#[ffi_const]` is only allowed on foreign functions
- struct_span_err!(
- tcx.sess,
- attr.span,
- E0756,
- "`#[ffi_const]` may only be used on foreign functions"
- )
- .emit();
- }
- } else if attr.has_name(sym::rustc_nounwind) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
- } else if attr.has_name(sym::rustc_reallocator) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;
- } else if attr.has_name(sym::rustc_deallocator) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR;
- } else if attr.has_name(sym::rustc_allocator_zeroed) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED;
- } else if attr.has_name(sym::naked) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
- } else if attr.has_name(sym::no_mangle) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
- } else if attr.has_name(sym::no_coverage) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
- } else if attr.has_name(sym::rustc_std_internal_symbol) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
- } else if attr.has_name(sym::used) {
- let inner = attr.meta_item_list();
- match inner.as_deref() {
- Some([item]) if item.has_name(sym::linker) => {
- if !tcx.features().used_with_arg {
- feature_err(
- &tcx.sess.parse_sess,
- sym::used_with_arg,
- attr.span,
- "`#[used(linker)]` is currently unstable",
- )
- .emit();
- }
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
- }
- Some([item]) if item.has_name(sym::compiler) => {
- if !tcx.features().used_with_arg {
- feature_err(
- &tcx.sess.parse_sess,
- sym::used_with_arg,
- attr.span,
- "`#[used(compiler)]` is currently unstable",
- )
- .emit();
- }
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
- }
- Some(_) => {
- tcx.sess.emit_err(errors::ExpectedUsedSymbol { span: attr.span });
- }
- None => {
- // Unfortunately, unconditionally using `llvm.used` causes
- // issues in handling `.init_array` with the gold linker,
- // but using `llvm.compiler.used` caused a nontrival amount
- // of unintentional ecosystem breakage -- particularly on
- // Mach-O targets.
- //
- // As a result, we emit `llvm.compiler.used` only on ELF
- // targets. This is somewhat ad-hoc, but actually follows
- // our pre-LLVM 13 behavior (prior to the ecosystem
- // breakage), and seems to match `clang`'s behavior as well
- // (both before and after LLVM 13), possibly because they
- // have similar compatibility concerns to us. See
- // https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146
- // and following comments for some discussion of this, as
- // well as the comments in `rustc_codegen_llvm` where these
- // flags are handled.
- //
- // Anyway, to be clear: this is still up in the air
- // somewhat, and is subject to change in the future (which
- // is a good thing, because this would ideally be a bit
- // more firmed up).
- let is_like_elf = !(tcx.sess.target.is_like_osx
- || tcx.sess.target.is_like_windows
- || tcx.sess.target.is_like_wasm);
- codegen_fn_attrs.flags |= if is_like_elf {
- CodegenFnAttrFlags::USED
- } else {
- CodegenFnAttrFlags::USED_LINKER
- };
- }
- }
- } else if attr.has_name(sym::cmse_nonsecure_entry) {
- if !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. }) {
- struct_span_err!(
- tcx.sess,
- attr.span,
- E0776,
- "`#[cmse_nonsecure_entry]` requires C ABI"
- )
- .emit();
- }
- if !tcx.sess.target.llvm_target.contains("thumbv8m") {
- struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
- .emit();
- }
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY;
- } else if attr.has_name(sym::thread_local) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
- } else if attr.has_name(sym::track_caller) {
- if !tcx.is_closure(did.to_def_id()) && tcx.fn_sig(did).abi() != abi::Abi::Rust {
- struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
- .emit();
- }
- if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller {
- feature_err(
- &tcx.sess.parse_sess,
- sym::closure_track_caller,
- attr.span,
- "`#[track_caller]` on closures is currently unstable",
- )
- .emit();
- }
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
- } else if attr.has_name(sym::export_name) {
- if let Some(s) = attr.value_str() {
- if s.as_str().contains('\0') {
- // `#[export_name = ...]` will be converted to a null-terminated string,
- // so it may not contain any null characters.
- struct_span_err!(
- tcx.sess,
- attr.span,
- E0648,
- "`export_name` may not contain null characters"
- )
- .emit();
- }
- codegen_fn_attrs.export_name = Some(s);
- }
- } else if attr.has_name(sym::target_feature) {
- if !tcx.is_closure(did.to_def_id())
- && tcx.fn_sig(did).unsafety() == hir::Unsafety::Normal
- {
- if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
- // The `#[target_feature]` attribute is allowed on
- // WebAssembly targets on all functions, including safe
- // ones. Other targets require that `#[target_feature]` is
- // only applied to unsafe functions (pending the
- // `target_feature_11` feature) because on most targets
- // execution of instructions that are not supported is
- // considered undefined behavior. For WebAssembly which is a
- // 100% safe target at execution time it's not possible to
- // execute undefined instructions, and even if a future
- // feature was added in some form for this it would be a
- // deterministic trap. There is no undefined behavior when
- // executing WebAssembly so `#[target_feature]` is allowed
- // on safe functions (but again, only for WebAssembly)
- //
- // Note that this is also allowed if `actually_rustdoc` so
- // if a target is documenting some wasm-specific code then
- // it's not spuriously denied.
- } else if !tcx.features().target_feature_11 {
- let mut err = feature_err(
- &tcx.sess.parse_sess,
- sym::target_feature_11,
- attr.span,
- "`#[target_feature(..)]` can only be applied to `unsafe` functions",
- );
- err.span_label(tcx.def_span(did), "not an `unsafe` function");
- err.emit();
- } else {
- check_target_feature_trait_unsafe(tcx, did, attr.span);
- }
- }
- from_target_feature(
- tcx,
- attr,
- supported_target_features,
- &mut codegen_fn_attrs.target_features,
- );
- } else if attr.has_name(sym::linkage) {
- if let Some(val) = attr.value_str() {
- let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
- if tcx.is_foreign_item(did) {
- codegen_fn_attrs.import_linkage = linkage;
- } else {
- codegen_fn_attrs.linkage = linkage;
- }
- }
- } else if attr.has_name(sym::link_section) {
- if let Some(val) = attr.value_str() {
- if val.as_str().bytes().any(|b| b == 0) {
- let msg = format!(
- "illegal null byte in link_section \
- value: `{}`",
- &val
- );
- tcx.sess.span_err(attr.span, &msg);
- } else {
- codegen_fn_attrs.link_section = Some(val);
- }
- }
- } else if attr.has_name(sym::link_name) {
- codegen_fn_attrs.link_name = attr.value_str();
- } else if attr.has_name(sym::link_ordinal) {
- link_ordinal_span = Some(attr.span);
- if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
- codegen_fn_attrs.link_ordinal = ordinal;
- }
- } else if attr.has_name(sym::no_sanitize) {
- no_sanitize_span = Some(attr.span);
- if let Some(list) = attr.meta_item_list() {
- for item in list.iter() {
- if item.has_name(sym::address) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
- } else if item.has_name(sym::cfi) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
- } else if item.has_name(sym::kcfi) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI;
- } else if item.has_name(sym::memory) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
- } else if item.has_name(sym::memtag) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
- } else if item.has_name(sym::shadow_call_stack) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK;
- } else if item.has_name(sym::thread) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
- } else if item.has_name(sym::hwaddress) {
- codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
- } else {
- tcx.sess
- .struct_span_err(item.span(), "invalid argument for `no_sanitize`")
- .note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
- .emit();
- }
- }
- }
- } else if attr.has_name(sym::instruction_set) {
- codegen_fn_attrs.instruction_set = match attr.meta_kind() {
- Some(MetaItemKind::List(ref items)) => match items.as_slice() {
- [NestedMetaItem::MetaItem(set)] => {
- let segments =
- set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
- match segments.as_slice() {
- [sym::arm, sym::a32] | [sym::arm, sym::t32] => {
- if !tcx.sess.target.has_thumb_interworking {
- struct_span_err!(
- tcx.sess.diagnostic(),
- attr.span,
- E0779,
- "target does not support `#[instruction_set]`"
- )
- .emit();
- None
- } else if segments[1] == sym::a32 {
- Some(InstructionSetAttr::ArmA32)
- } else if segments[1] == sym::t32 {
- Some(InstructionSetAttr::ArmT32)
- } else {
- unreachable!()
- }
- }
- _ => {
- struct_span_err!(
- tcx.sess.diagnostic(),
- attr.span,
- E0779,
- "invalid instruction set specified",
- )
- .emit();
- None
- }
- }
- }
- [] => {
- struct_span_err!(
- tcx.sess.diagnostic(),
- attr.span,
- E0778,
- "`#[instruction_set]` requires an argument"
- )
- .emit();
- None
- }
- _ => {
- struct_span_err!(
- tcx.sess.diagnostic(),
- attr.span,
- E0779,
- "cannot specify more than one instruction set"
- )
- .emit();
- None
- }
- },
- _ => {
- struct_span_err!(
- tcx.sess.diagnostic(),
- attr.span,
- E0778,
- "must specify an instruction set"
- )
- .emit();
- None
- }
- };
- } else if attr.has_name(sym::repr) {
- codegen_fn_attrs.alignment = match attr.meta_item_list() {
- Some(items) => match items.as_slice() {
- [item] => match item.name_value_literal() {
- Some((sym::align, literal)) => {
- let alignment = rustc_attr::parse_alignment(&literal.kind);
-
- match alignment {
- Ok(align) => Some(align),
- Err(msg) => {
- struct_span_err!(
- tcx.sess.diagnostic(),
- attr.span,
- E0589,
- "invalid `repr(align)` attribute: {}",
- msg
- )
- .emit();
-
- None
- }
- }
- }
- _ => None,
- },
- [] => None,
- _ => None,
- },
- None => None,
- };
- }
- }
-
- codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
- if !attr.has_name(sym::inline) {
- return ia;
- }
- match attr.meta_kind() {
- Some(MetaItemKind::Word) => InlineAttr::Hint,
- Some(MetaItemKind::List(ref items)) => {
- inline_span = Some(attr.span);
- if items.len() != 1 {
- struct_span_err!(
- tcx.sess.diagnostic(),
- attr.span,
- E0534,
- "expected one argument"
- )
- .emit();
- InlineAttr::None
- } else if list_contains_name(&items, sym::always) {
- InlineAttr::Always
- } else if list_contains_name(&items, sym::never) {
- InlineAttr::Never
- } else {
- struct_span_err!(
- tcx.sess.diagnostic(),
- items[0].span(),
- E0535,
- "invalid argument"
- )
- .help("valid inline arguments are `always` and `never`")
- .emit();
-
- InlineAttr::None
- }
- }
- Some(MetaItemKind::NameValue(_)) => ia,
- None => ia,
- }
- });
-
- codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
- if !attr.has_name(sym::optimize) {
- return ia;
- }
- let err = |sp, s| struct_span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s).emit();
- match attr.meta_kind() {
- Some(MetaItemKind::Word) => {
- err(attr.span, "expected one argument");
- ia
- }
- Some(MetaItemKind::List(ref items)) => {
- inline_span = Some(attr.span);
- if items.len() != 1 {
- err(attr.span, "expected one argument");
- OptimizeAttr::None
- } else if list_contains_name(&items, sym::size) {
- OptimizeAttr::Size
- } else if list_contains_name(&items, sym::speed) {
- OptimizeAttr::Speed
- } else {
- err(items[0].span(), "invalid argument");
- OptimizeAttr::None
- }
- }
- Some(MetaItemKind::NameValue(_)) => ia,
- None => ia,
- }
- });
-
- // #73631: closures inherit `#[target_feature]` annotations
- if tcx.features().target_feature_11 && tcx.is_closure(did.to_def_id()) {
- let owner_id = tcx.parent(did.to_def_id());
- if tcx.def_kind(owner_id).has_codegen_attrs() {
- codegen_fn_attrs
- .target_features
- .extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied());
- }
- }
-
- // If a function uses #[target_feature] it can't be inlined into general
- // purpose functions as they wouldn't have the right target features
- // enabled. For that reason we also forbid #[inline(always)] as it can't be
- // respected.
- if !codegen_fn_attrs.target_features.is_empty() {
- if codegen_fn_attrs.inline == InlineAttr::Always {
- if let Some(span) = inline_span {
- tcx.sess.span_err(
- span,
- "cannot use `#[inline(always)]` with \
- `#[target_feature]`",
- );
- }
- }
- }
-
- if !codegen_fn_attrs.no_sanitize.is_empty() {
- if codegen_fn_attrs.inline == InlineAttr::Always {
- if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
- let hir_id = tcx.hir().local_def_id_to_hir_id(did);
- tcx.struct_span_lint_hir(
- lint::builtin::INLINE_NO_SANITIZE,
- hir_id,
- no_sanitize_span,
- "`no_sanitize` will have no effect after inlining",
- |lint| lint.span_note(inline_span, "inlining requested here"),
- )
- }
- }
- }
-
- if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
- codegen_fn_attrs.inline = InlineAttr::Never;
- }
-
- // Weak lang items have the same semantics as "std internal" symbols in the
- // sense that they're preserved through all our LTO passes and only
- // strippable by the linker.
- //
- // Additionally weak lang items have predetermined symbol names.
- if WEAK_LANG_ITEMS.iter().any(|&l| tcx.lang_items().get(l) == Some(did.to_def_id())) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
- }
- if let Some((name, _)) = lang_items::extract(attrs)
- && let Some(lang_item) = LangItem::from_name(name)
- && let Some(link_name) = lang_item.link_name()
- {
- codegen_fn_attrs.export_name = Some(link_name);
- codegen_fn_attrs.link_name = Some(link_name);
- }
- check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
-
- // Internal symbols to the standard library all have no_mangle semantics in
- // that they have defined symbol names present in the function name. This
- // also applies to weak symbols where they all have known symbol names.
- if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
- }
-
- // Any linkage to LLVM intrinsics for now forcibly marks them all as never
- // unwinds since LLVM sometimes can't handle codegen which `invoke`s
- // intrinsic functions.
- if let Some(name) = &codegen_fn_attrs.link_name {
- if name.as_str().starts_with("llvm.") {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
- }
- }
-
- codegen_fn_attrs
-}
-
-/// Computes the set of target features used in a function for the purposes of
-/// inline assembly.
-fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> {
- let mut target_features = tcx.sess.unstable_target_features.clone();
- if tcx.def_kind(did).has_codegen_attrs() {
- let attrs = tcx.codegen_fn_attrs(did);
- target_features.extend(&attrs.target_features);
- match attrs.instruction_set {
- None => {}
- Some(InstructionSetAttr::ArmA32) => {
- target_features.remove(&sym::thumb_mode);
- }
- Some(InstructionSetAttr::ArmT32) => {
- target_features.insert(sym::thumb_mode);
- }
- }
- }
-
- tcx.arena.alloc(target_features)
-}
-
-/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
-/// applied to the method prototype.
-fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
- if let Some(impl_item) = tcx.opt_associated_item(def_id)
- && let ty::AssocItemContainer::ImplContainer = impl_item.container
- && let Some(trait_item) = impl_item.trait_item_def_id
- {
- return tcx
- .codegen_fn_attrs(trait_item)
- .flags
- .intersects(CodegenFnAttrFlags::TRACK_CALLER);
- }
-
- false
-}
-
-fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
- use rustc_ast::{LitIntType, LitKind, MetaItemLit};
- if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" {
- feature_err(
- &tcx.sess.parse_sess,
- sym::raw_dylib,
- attr.span,
- "`#[link_ordinal]` is unstable on x86",
- )
- .emit();
- }
- let meta_item_list = attr.meta_item_list();
- let meta_item_list = meta_item_list.as_deref();
- let sole_meta_list = match meta_item_list {
- Some([item]) => item.lit(),
- Some(_) => {
- tcx.sess
- .struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`")
- .note("the attribute requires exactly one argument")
- .emit();
- return None;
- }
- _ => None,
- };
- if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
- sole_meta_list
- {
- // According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header,
- // the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
- // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information
- // to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
- //
- // FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for this:
- // both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies
- // a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import library
- // for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import
- // library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I don't know yet
- // if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment
- // about LINK.EXE failing.)
- if *ordinal <= u16::MAX as u128 {
- Some(*ordinal as u16)
- } else {
- let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
- tcx.sess
- .struct_span_err(attr.span, &msg)
- .note("the value may not exceed `u16::MAX`")
- .emit();
- None
- }
- } else {
- tcx.sess
- .struct_span_err(attr.span, "illegal ordinal format in `link_ordinal`")
- .note("an unsuffixed integer value, e.g., `1`, is expected")
- .emit();
- None
- }
-}
-
-fn check_link_name_xor_ordinal(
- tcx: TyCtxt<'_>,
- codegen_fn_attrs: &CodegenFnAttrs,
- inline_span: Option<Span>,
-) {
- if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() {
- return;
- }
- let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
- if let Some(span) = inline_span {
- tcx.sess.span_err(span, msg);
- } else {
- tcx.sess.err(msg);
- }
-}
-
-/// Checks the function annotated with `#[target_feature]` is not a safe
-/// trait method implementation, reporting an error if it is.
-fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
- let hir_id = tcx.hir().local_def_id_to_hir_id(id);
- let node = tcx.hir().get(hir_id);
- if let Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
- let parent_id = tcx.hir().get_parent_item(hir_id);
- let parent_item = tcx.hir().expect_item(parent_id.def_id);
- if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
- tcx.sess
- .struct_span_err(
- attr_span,
- "`#[target_feature(..)]` cannot be applied to safe trait method",
- )
- .span_label(attr_span, "cannot be applied to safe trait method")
- .span_label(tcx.def_span(id), "not an `unsafe` function")
- .emit();
- }
- }
-}
ty::Param(param_ty) => {
self.arg_is_constrained[param_ty.index as usize] = true;
}
- ty::Projection(_) => return ControlFlow::Continue(()),
+ ty::Alias(ty::Projection, _) => return ControlFlow::Continue(()),
_ => (),
}
t.super_visit_with(self)
const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
- // We use an `IndexSet` to preserves order of insertion.
+ // We use an `IndexSet` to preserve order of insertion.
// Preserving the order of insertion is important here so as not to break UI tests.
let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
| ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics) => *generics,
- ItemKind::Trait(_, _, ref generics, ..) => {
- is_trait = Some(ty::TraitRef::identity(tcx, def_id));
- *generics
- }
- ItemKind::TraitAlias(ref generics, _) => {
+ ItemKind::Trait(_, _, ref generics, ..) | ItemKind::TraitAlias(ref generics, _) => {
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
*generics
}
// For a predicate from a where clause to become a bound on an
// associated type:
// * It must use the identity substs of the item.
- // * Since any generic parameters on the item are not in scope,
- // this means that the item is not a GAT, and its identity
- // substs are the same as the trait's.
+ // * We're in the scope of the trait, so we can't name any
+ // parameters of the GAT. That means that all we need to
+ // check are that the substs of the projection are the
+ // identity substs of the trait.
// * It must be an associated type for this trait (*not* a
// supertrait).
- if let ty::Projection(projection) = ty.kind() {
+ if let ty::Alias(ty::Projection, projection) = ty.kind() {
projection.substs == trait_identity_substs
- && tcx.associated_item(projection.item_def_id).container_id(tcx) == def_id
+ && tcx.associated_item(projection.def_id).container_id(tcx) == def_id
} else {
false
}
// Using the ItemCtxt convert the HIR for the unresolved assoc type into a
// ty which is a fully resolved projection.
// For the code example above, this would mean converting Self::Assoc<3>
- // into a ty::Projection(<Self as Foo>::Assoc<3>)
+ // into a ty::Alias(ty::Projection, <Self as Foo>::Assoc<3>)
let item_hir_id = tcx
.hir()
.parent_iter(hir_id)
// the def_id that this query was called with. We filter to only type and const args here
// as a precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
// but it can't hurt to be safe ^^
- if let ty::Projection(projection) = ty.kind() {
- let generics = tcx.generics_of(projection.item_def_id);
+ if let ty::Alias(ty::Projection, projection) = ty.kind() {
+ let generics = tcx.generics_of(projection.def_id);
let arg_index = segment
.args
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let scope = tcx.hir().get_defining_scope(hir_id);
- let mut locator = ConstraintLocator { def_id: def_id, tcx, found: None, typeck_types: vec![] };
+ let mut locator = ConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };
debug!(?scope);
if let Some(concrete) = concrete {
let scope = tcx.hir().local_def_id_to_hir_id(owner_def_id);
debug!(?scope);
- let mut locator = ConstraintChecker { def_id: def_id, tcx, found: concrete };
+ let mut locator = ConstraintChecker { def_id, tcx, found: concrete };
match tcx.hir().get(scope) {
Node::Item(it) => intravisit::walk_item(&mut locator, it),
impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match *t.kind() {
- ty::Projection(..) if !self.include_nonconstraining => {
+ ty::Alias(ty::Projection, ..) if !self.include_nonconstraining => {
// projections are not injective
return ControlFlow::CONTINUE;
}
pub ident: Ident,
}
+#[derive(Diagnostic)]
+#[diag(hir_analysis_async_trait_impl_should_be_async)]
+pub struct AsyncTraitImplShouldBeAsync {
+ #[primary_span]
+ // #[label]
+ pub span: Span,
+ #[label(trait_item_label)]
+ pub trait_item_span: Option<Span>,
+ pub method_name: Symbol,
+}
+
#[derive(Diagnostic)]
#[diag(hir_analysis_drop_impl_on_wrong_item, code = "E0120")]
pub struct DropImplOnWrongItem {
pub suggestion_code: String,
}
-#[derive(Diagnostic)]
-#[diag(hir_analysis_expected_used_symbol)]
-pub struct ExpectedUsedSymbol {
- #[primary_span]
- pub span: Span,
-}
-
#[derive(Diagnostic)]
#[diag(hir_analysis_const_impl_for_non_const_trait)]
pub struct ConstImplForNonConstTrait {
}
}
- ty::Projection(obj) => {
+ ty::Alias(ty::Projection, obj) => {
// This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the
// explicit predicates as well.
debug!("Projection");
check_explicit_predicates(
tcx,
- tcx.parent(obj.item_def_id),
+ tcx.parent(obj.def_id),
obj.substs,
required_predicates,
explicit_map,
// ```
//
// Here we want to add an explicit `where <T as Iterator>::Item: 'a`.
- let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.item_def_id, proj_ty.substs);
+ let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.def_id, proj_ty.substs);
required_predicates
.entry(ty::OutlivesPredicate(ty.into(), outlived_region))
.or_insert(span);
self.add_constraints_from_substs(current, def.did(), substs, variance);
}
- ty::Projection(ref data) => {
+ ty::Alias(_, ref data) => {
self.add_constraints_from_invariant_substs(current, data.substs, variance);
}
- ty::Opaque(_, substs) => {
- self.add_constraints_from_invariant_substs(current, substs, variance);
- }
-
ty::Dynamic(data, r, _) => {
// The type `Foo<T+'a>` is contravariant w/r/t `'a`:
let contra = self.contravariant(variance);
#[instrument(level = "trace", skip(self), ret)]
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() {
- ty::Opaque(def_id, substs) => self.visit_opaque(*def_id, substs),
- ty::Projection(proj)
- if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
+ ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+ if matches!(
+ self.tcx.def_kind(*def_id),
+ DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder
+ ) =>
{
- self.visit_opaque(proj.item_def_id, proj.substs)
+ self.visit_opaque(*def_id, substs)
}
_ => t.super_visit_with(self),
}
// instead of requiring an additional `+ 'a`.
match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
- trait_ref: ty::TraitRef { def_id: _, substs },
+ trait_ref: ty::TraitRef { def_id: _, substs, .. },
constness: _,
polarity: _,
})) => {
}
}
ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy { substs, item_def_id: _ },
+ projection_ty: ty::AliasTy { substs, .. },
term,
})) => {
for subst in &substs[1..] {
self.print_qpath(qpath, true);
self.popen();
if let Some(ddpos) = ddpos.as_opt_usize() {
- let ddpos = ddpos as usize;
self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
if ddpos != 0 {
self.word_space(",");
self.can_coerce(arm_ty, ret_ty)
&& prior_arm.map_or(true, |(_, ty, _)| self.can_coerce(ty, ret_ty))
// The match arms need to unify for the case of `impl Trait`.
- && !matches!(ret_ty.kind(), ty::Opaque(..))
+ && !matches!(ret_ty.kind(), ty::Alias(ty::Opaque, ..))
}
_ => false,
};
let substs = sig.output().walk().find_map(|arg| {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Opaque(def_id, substs) = *ty.kind()
+ && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *ty.kind()
&& def_id == rpit_def_id
{
Some(substs)
ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => {
assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty);
ty::PredicateKind::Clause(ty::Clause::Trait(
- trait_pred.with_self_type(self.tcx, ty),
+ trait_pred.with_self_ty(self.tcx, ty),
))
}
ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => {
assert_eq!(proj_pred.projection_ty.self_ty(), opaque_ty);
- proj_pred.projection_ty.substs = self.tcx.mk_substs_trait(
- ty,
- proj_pred.projection_ty.substs.iter().skip(1),
- );
+ proj_pred = proj_pred.with_self_ty(self.tcx, ty);
ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred))
}
_ => continue,
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::cast::{CastKind, CastTy};
use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
use rustc_session::lint;
use rustc_session::Session;
VTable(Option<DefId>),
/// Slice
Length,
- /// The unsize info of this projection
- OfProjection(ty::ProjectionTy<'tcx>),
- /// The unsize info of this opaque ty
- OfOpaque(DefId, SubstsRef<'tcx>),
+ /// The unsize info of this projection or opaque type
+ OfAlias(ty::AliasTy<'tcx>),
/// The unsize info of this parameter
OfParam(ty::ParamTy),
}
// Pointers to foreign types are thin, despite being unsized
ty::Foreign(..) => Some(PointerKind::Thin),
// We should really try to normalize here.
- ty::Projection(pi) => Some(PointerKind::OfProjection(pi)),
- ty::Opaque(def_id, substs) => Some(PointerKind::OfOpaque(def_id, substs)),
+ ty::Alias(_, pi) => Some(PointerKind::OfAlias(pi)),
ty::Param(p) => Some(PointerKind::OfParam(p)),
// Insufficient type information.
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) => None,
Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
Some(PointerKind::VTable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))),
Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))),
- Some(
- PointerKind::OfProjection(_)
- | PointerKind::OfOpaque(_, _)
- | PointerKind::OfParam(_),
- ) => Err(CastError::IntToFatCast(None)),
+ Some(PointerKind::OfAlias(_) | PointerKind::OfParam(_)) => {
+ Err(CastError::IntToFatCast(None))
+ }
}
}
expected_ty: Ty<'tcx>,
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
match *expected_ty.kind() {
- ty::Opaque(def_id, substs) => self.deduce_signature_from_predicates(
- self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
- ),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
+ .deduce_signature_from_predicates(
+ self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
+ ),
ty::Dynamic(ref object_type, ..) => {
let sig = object_type.projection_bounds().find_map(|pb| {
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
get_future_output(obligation.predicate, obligation.cause.span)
})?
}
- ty::Opaque(def_id, substs) => self
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
.tcx
.bound_explicit_item_bounds(def_id)
.subst_iter_copied(self.tcx, substs)
.find_map(|(p, s)| get_future_output(p, s))?,
ty::Error(_) => return None,
- ty::Projection(proj)
- if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
+ ty::Alias(ty::Projection, proj)
+ if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder =>
{
self.tcx
- .bound_explicit_item_bounds(proj.item_def_id)
+ .bound_explicit_item_bounds(proj.def_id)
.subst_iter_copied(self.tcx, proj.substs)
.find_map(|(p, s)| get_future_output(p, s))?
}
// The `Future` trait has only one associated item, `Output`,
// so check that this is what we see.
let output_assoc_item = self.tcx.associated_item_def_ids(future_trait)[0];
- if output_assoc_item != predicate.projection_ty.item_def_id {
+ if output_assoc_item != predicate.projection_ty.def_id {
span_bug!(
cause_span,
"projecting associated item `{:?}` from future, which is not Output `{:?}`",
- predicate.projection_ty.item_def_id,
+ predicate.projection_ty.def_id,
output_assoc_item,
);
}
{
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(fcx, ty);
// Get the `impl Trait`'s `DefId`.
- if let ty::Opaque(def_id, _) = ty.kind()
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind()
// Get the `impl Trait`'s `Item` so that we can get its trait bounds and
// get the `Trait`'s `DefId`.
&& let hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }) =
ty::Param(param_ty) => {
self.point_at_param_definition(&mut err, param_ty);
}
- ty::Opaque(_, _) => {
+ ty::Alias(ty::Opaque, _) => {
self.suggest_await_on_field_access(&mut err, ident, base, base_ty.peel_refs());
}
_ => {}
if formal_ret.has_infer_types() {
for ty in ret_ty.walk() {
if let ty::subst::GenericArgKind::Type(ty) = ty.unpack()
- && let ty::Opaque(def_id, _) = *ty.kind()
+ && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
&& let Some(def_id) = def_id.as_local()
&& self.opaque_type_origin(def_id, DUMMY_SP).is_some() {
return None;
}
}
}
- ty::Opaque(new_def_id, _)
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: new_def_id, .. })
| ty::Closure(new_def_id, _)
| ty::FnDef(new_def_id, _) => {
def_id = new_def_id;
_ => {
// Look for a user-provided impl of a `Fn` trait, and point to it.
let new_def_id = self.probe(|_| {
- let trait_ref = ty::TraitRef::new(
+ let trait_ref = self.tcx.mk_trait_ref(
call_kind.to_def_id(self.tcx),
- self.tcx.mk_substs(
- [
- ty::GenericArg::from(callee_ty),
- self.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span: rustc_span::DUMMY_SP,
- })
- .into(),
- ]
- .into_iter(),
- ),
+ [
+ callee_ty,
+ self.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::MiscVariable,
+ span: rustc_span::DUMMY_SP,
+ }),
+ ],
);
let obligation = traits::Obligation::new(
self.tcx,
if arg == param_to_point_at {
return true;
} else if let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Projection(..) = ty.kind()
+ && let ty::Alias(ty::Projection, ..) = ty.kind()
{
// This logic may seem a bit strange, but typically when
// we have a projection type in a function signature, the
use rustc_infer::infer;
use rustc_infer::traits::{self, StatementAsExpression};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty};
+use rustc_middle::ty::{
+ self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty,
+};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::symbol::sym;
use rustc_span::Span;
let fn_sig = substs.as_closure().sig();
Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..])))
}
- ty::Opaque(def_id, substs) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
- && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+ && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
// args tuple will always be substs[1]
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
{
ty::Dynamic(data, _, ty::Dyn) => {
data.iter().find_map(|pred| {
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
- && Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
+ && Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
// for existential projection, substs are shifted over by 1
&& let ty::Tuple(args) = proj.substs.type_at(0).kind()
{
let def_id = self.tcx.generics_of(self.body_id.owner).type_param(¶m, self.tcx).def_id;
self.tcx.predicates_of(self.body_id.owner).predicates.iter().find_map(|(pred, _)| {
if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
- && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+ && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
&& proj.projection_ty.self_ty() == found
// args tuple will always be substs[1]
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
&& !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
// Check that we're in fact trying to clone into the expected type
&& self.can_coerce(*pointee_ty, expected_ty)
+ && let trait_ref = ty::Binder::dummy(self.tcx.mk_trait_ref(clone_trait_did, [expected_ty]))
// And the expected type doesn't implement `Clone`
- && !self.predicate_must_hold_considering_regions(&traits::Obligation {
- cause: traits::ObligationCause::dummy(),
- param_env: self.param_env,
- recursion_depth: 0,
- predicate: ty::Binder::dummy(ty::TraitRef {
- def_id: clone_trait_did,
- substs: self.tcx.mk_substs([expected_ty.into()].iter()),
- })
- .without_const()
- .to_predicate(self.tcx),
- })
+ && !self.predicate_must_hold_considering_regions(&traits::Obligation::new(
+ self.tcx,
+ traits::ObligationCause::dummy(),
+ self.param_env,
+ trait_ref,
+ ))
{
diag.span_note(
callee_expr.span,
"`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
),
);
+ let owner = self.tcx.hir().enclosing_body_owner(expr.hir_id);
+ if let ty::Param(param) = expected_ty.kind()
+ && let Some(generics) = self.tcx.hir().get_generics(owner)
+ {
+ suggest_constraining_type_params(
+ self.tcx,
+ generics,
+ diag,
+ vec![(param.name.as_str(), "Clone", Some(clone_trait_did))].into_iter(),
+ );
+ } else {
+ self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]);
+ }
}
}
}
ty::Adt(def, _) => check_must_not_suspend_def(fcx.tcx, def.did(), hir_id, data),
// FIXME: support adding the attribute to TAITs
- ty::Opaque(def, _) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
let mut has_emitted = false;
for &(predicate, _) in fcx.tcx.explicit_item_bounds(def) {
// We only look at the `DefId`, so it is safe to skip the binder here.
ProbeScope::TraitsInScope,
) {
Ok(ref new_pick) if pick.differs_from(new_pick) => {
- needs_mut = true;
+ needs_mut = new_pick.self_ty.ref_mutability() != self_ty.ref_mutability();
}
_ => {}
}
self.var_for_def(span, param)
});
- let trait_ref = ty::TraitRef::new(trait_def_id, substs);
+ let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
self.var_for_def(span, param)
});
- let trait_ref = ty::TraitRef::new(trait_def_id, substs);
+ let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
) {
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
let trait_substs = self.fresh_item_substs(trait_def_id);
- let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
+ let trait_ref = self.tcx.mk_trait_ref(trait_def_id, trait_substs);
if self.tcx.is_trait_alias(trait_def_id) {
// For trait aliases, assume all supertraits are relevant.
use rustc_middle::traits::util::supertraits;
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
-use rustc_middle::ty::print::with_crate_prefix;
+use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
use rustc_middle::ty::{self, DefIdTree, GenericArgKind, Ty, TyCtxt, TypeVisitable};
use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
use rustc_span::symbol::{kw, sym, Ident};
let tcx = self.tcx;
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
- let ty_str = self.ty_to_string(rcvr_ty);
+ let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
let is_method = mode == Mode::MethodCall;
let item_kind = if is_method {
"method"
.chain(projection_ty.substs.iter().skip(1)),
);
- let quiet_projection_ty = ty::ProjectionTy {
- substs: substs_with_infer_self,
- item_def_id: projection_ty.item_def_id,
- };
+ let quiet_projection_ty =
+ tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
let term = pred.skip_binder().term;
let obligation = format!("{} = {}", projection_ty, term);
- let quiet = format!("{} = {}", quiet_projection_ty, term);
+ let quiet = with_forced_trimmed_paths!(format!(
+ "{} = {}",
+ quiet_projection_ty, term
+ ));
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
Some((obligation, projection_ty.self_ty()))
let self_ty = p.self_ty();
let path = p.print_only_trait_path();
let obligation = format!("{}: {}", self_ty, path);
- let quiet = format!("_: {}", path);
+ let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
bound_span_label(self_ty, &obligation, &quiet);
Some((obligation, self_ty))
}
(None, None)
};
let primary_message = primary_message.unwrap_or_else(|| format!(
- "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
+ "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
+ but its trait bounds were not satisfied"
));
err.set_primary_message(&primary_message);
if let Some(label) = label {
}
}
} else {
- err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
+ let ty_str = if ty_str.len() > 50 {
+ String::new()
+ } else {
+ format!("on `{ty_str}` ")
+ };
+ err.span_label(span, format!(
+ "{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds"
+ ));
}
};
self.suggest_derive(err, &preds);
}
- fn suggest_derive(
+ pub fn suggest_derive(
&self,
err: &mut Diagnostic,
unsatisfied_predicates: &[(
)],
) {
let mut derives = Vec::<(String, Span, Symbol)>::new();
- let mut traits = Vec::<Span>::new();
+ let mut traits = Vec::new();
for (pred, _, _) in unsatisfied_predicates {
let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = pred.kind().skip_binder() else { continue };
let adt = match trait_pred.self_ty().ty_adt_def() {
}
derives.push((self_name, self_span, diagnostic_name));
} else {
- traits.push(self.tcx.def_span(trait_pred.def_id()));
+ traits.push(trait_pred.def_id());
}
} else {
- traits.push(self.tcx.def_span(trait_pred.def_id()));
+ traits.push(trait_pred.def_id());
}
}
traits.sort();
let len = traits.len();
if len > 0 {
- let span: MultiSpan = traits.into();
+ let span =
+ MultiSpan::from_spans(traits.iter().map(|&did| self.tcx.def_span(did)).collect());
+ let mut names = format!("`{}`", self.tcx.def_path_str(traits[0]));
+ for (i, &did) in traits.iter().enumerate().skip(1) {
+ if len > 2 {
+ names.push_str(", ");
+ }
+ if i == len - 1 {
+ names.push_str(" and ");
+ }
+ names.push('`');
+ names.push_str(&self.tcx.def_path_str(did));
+ names.push('`');
+ }
err.span_note(
span,
- &format!("the following trait{} must be implemented", pluralize!(len),),
+ &format!("the trait{} {} must be implemented", pluralize!(len), names),
);
}
| ty::Float(_)
| ty::Adt(_, _)
| ty::Str
- | ty::Projection(_)
+ | ty::Alias(ty::Projection, _)
| ty::Param(_) => format!("{deref_ty}"),
// we need to test something like <&[_]>::len or <(&[u32])>::len
// and Vec::function();
t.def_id() == info.def_id
}
ty::PredicateKind::Clause(ty::Clause::Projection(p)) => {
- p.projection_ty.item_def_id == info.def_id
+ p.projection_ty.def_id == info.def_id
}
_ => false,
}
impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
type BreakTy = ();
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let ty::Opaque(def_id, _) = *t.kind() {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *t.kind() {
if def_id == self.def_id.to_def_id() {
return ControlFlow::Break(());
}
self.words[start_word_index] |= !(start_mask - 1);
// And all trailing bits (i.e. from 0..=end) in the end word,
// including the end.
- self.words[end_word_index] |= end_mask | end_mask - 1;
+ self.words[end_word_index] |= end_mask | (end_mask - 1);
} else {
self.words[start_word_index] |= end_mask | (end_mask - start_mask);
}
pub expl: Option<note_and_explain::RegionExplanation<'a>>,
#[subdiagnostic]
pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl,
- #[subdiagnostic(eager)]
+ #[subdiagnostic]
pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
}
}
}
-impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> {
+impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
fn to_trace(
tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a: Self,
b: Self,
) -> TypeTrace<'tcx> {
- let a_ty = tcx.mk_projection(a.item_def_id, a.substs);
- let b_ty = tcx.mk_projection(b.item_def_id, b.substs);
+ let a_ty = tcx.mk_projection(a.def_id, a.substs);
+ let b_ty = tcx.mk_projection(b.def_id, b.substs);
TypeTrace {
cause: cause.clone(),
values: Terms(ExpectedFound::new(a_is_expected, a_ty.into(), b_ty.into())),
| ty::Dynamic(..)
| ty::Never
| ty::Tuple(..)
- | ty::Projection(..)
+ | ty::Alias(..)
| ty::Foreign(..)
- | ty::Param(..)
- | ty::Opaque(..) => {
+ | ty::Param(..) => {
if t.flags().intersects(self.needs_canonical_flags) {
t.super_fold_with(self)
} else {
// relatable.
Ok(t)
}
- ty::Opaque(def_id, substs) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
let s = self.relate(substs, substs)?;
Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) })
}
self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?;
}
- (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
+ (
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+ ) if a_def_id == b_def_id => {
self.fields.infcx.super_combine_tys(self, a, b)?;
}
- (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
- if self.fields.define_opaque_types && did.is_local() =>
+ (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+ | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
+ if self.fields.define_opaque_types && def_id.is_local() =>
{
self.fields.obligations.extend(
infcx
where
T: Relate<'tcx>,
{
+ // A binder is equal to itself if it's structually equal to itself
+ if a == b {
+ return Ok(a);
+ }
+
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
self.fields.higher_ranked_sub(b, a, self.a_is_expected)?;
impl<'tcx> InferCtxt<'tcx> {
pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
let (def_id, substs) = match *ty.kind() {
- ty::Opaque(def_id, substs) => (def_id, substs),
- ty::Projection(data)
- if self.tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder =>
+ ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+ if matches!(
+ self.tcx.def_kind(def_id),
+ DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder
+ ) =>
{
- (data.item_def_id, data.substs)
+ (def_id, substs)
}
_ => return None,
};
.kind()
.map_bound(|kind| match kind {
ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate))
- if projection_predicate.projection_ty.item_def_id == item_def_id =>
+ if projection_predicate.projection_ty.def_id == item_def_id =>
{
projection_predicate.term.ty()
}
let extra = expected == found;
let sort_string = |ty: Ty<'tcx>, path: Option<PathBuf>| {
let mut s = match (extra, ty.kind()) {
- (true, ty::Opaque(def_id, _)) => {
+ (true, ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) => {
let sm = self.tcx.sess.source_map();
let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
format!(
pos.col.to_usize() + 1,
)
}
- (true, ty::Projection(proj))
- if self.tcx.def_kind(proj.item_def_id)
+ (true, ty::Alias(ty::Projection, proj))
+ if self.tcx.def_kind(proj.def_id)
== DefKind::ImplTraitPlaceholder =>
{
let sm = self.tcx.sess.source_map();
- let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
+ let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
format!(
" (trait associated opaque type at <{}:{}:{}>)",
sm.filename_for_diagnostics(&pos.file.name),
// fn get_later<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
// suggest:
// fn get_later<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
- ty::Closure(_, _substs) | ty::Opaque(_, _substs) if return_impl_trait => {
+ ty::Closure(..) | ty::Alias(ty::Opaque, ..) if return_impl_trait => {
new_binding_suggestion(&mut err, type_param_span);
}
_ => {
pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
match *ty.kind() {
ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
- ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => Some((Self::Opaque, def_id)),
ty::Generator(def_id, ..) => {
Some((Self::Generator(tcx.generator_kind(def_id).unwrap()), def_id))
}
use rustc_middle::ty::{self, DefIdTree, InferConst};
use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
-use rustc_span::symbol::{kw, Ident};
+use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{BytePos, Span};
use std::borrow::Cow;
use std::iter;
fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str {
if in_type.is_ty_infer() {
- "empty"
+ ""
} else if self.name == "_" {
// FIXME: Consider specializing this message if there is a single `_`
// in the type.
printer
}
-fn ty_to_string<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
+fn ty_to_string<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ called_method_def_id: Option<DefId>,
+) -> String {
let printer = fmt_printer(infcx, Namespace::TypeNS);
let ty = infcx.resolve_vars_if_possible(ty);
- match ty.kind() {
+ match (ty.kind(), called_method_def_id) {
// We don't want the regular output for `fn`s because it includes its path in
// invalid pseudo-syntax, we want the `fn`-pointer output instead.
- ty::FnDef(..) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(),
+ (ty::FnDef(..), _) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(),
+ (_, Some(def_id))
+ if ty.is_ty_infer()
+ && infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(def_id) =>
+ {
+ "Vec<_>".to_string()
+ }
+ _ if ty.is_ty_infer() => "/* Type */".to_string(),
// FIXME: The same thing for closures, but this only works when the closure
// does not capture anything.
//
.map(|args| {
args.tuple_fields()
.iter()
- .map(|arg| ty_to_string(infcx, arg))
+ .map(|arg| ty_to_string(infcx, arg, None))
.collect::<Vec<_>>()
.join(", ")
})
let ret = if fn_sig.output().skip_binder().is_unit() {
String::new()
} else {
- format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder()))
+ format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder(), None))
};
format!("fn({}){}", args, ret)
}
}
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+ #[instrument(level = "debug", skip(self, error_code))]
pub fn emit_inference_failure_err(
&self,
body_id: Option<hir::BodyId>,
let mut infer_subdiags = Vec::new();
let mut multi_suggestions = Vec::new();
match kind {
- InferSourceKind::LetBinding { insert_span, pattern_name, ty } => {
+ InferSourceKind::LetBinding { insert_span, pattern_name, ty, def_id } => {
infer_subdiags.push(SourceKindSubdiag::LetLike {
span: insert_span,
name: pattern_name.map(|name| name.to_string()).unwrap_or_else(String::new),
prefix: arg_data.kind.try_get_prefix().unwrap_or_default(),
arg_name: arg_data.name,
kind: if pattern_name.is_some() { "with_pattern" } else { "other" },
- type_name: ty_to_string(self, ty),
+ type_name: ty_to_string(self, ty, def_id),
});
}
InferSourceKind::ClosureArg { insert_span, ty } => {
prefix: arg_data.kind.try_get_prefix().unwrap_or_default(),
arg_name: arg_data.name,
kind: "closure",
- type_name: ty_to_string(self, ty),
+ type_name: ty_to_string(self, ty, None),
});
}
InferSourceKind::GenericArg {
parent_name,
});
- let args = fmt_printer(self, Namespace::TypeNS)
- .comma_sep(generic_args.iter().copied().map(|arg| {
- if arg.is_suggestable(self.tcx, true) {
- return arg;
- }
+ let args = if self.infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn)
+ == Some(generics_def_id)
+ {
+ "Vec<_>".to_string()
+ } else {
+ fmt_printer(self, Namespace::TypeNS)
+ .comma_sep(generic_args.iter().copied().map(|arg| {
+ if arg.is_suggestable(self.tcx, true) {
+ return arg;
+ }
- match arg.unpack() {
- GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
- GenericArgKind::Type(_) => self
- .next_ty_var(TypeVariableOrigin {
- span: rustc_span::DUMMY_SP,
- kind: TypeVariableOriginKind::MiscVariable,
- })
- .into(),
- GenericArgKind::Const(arg) => self
- .next_const_var(
- arg.ty(),
- ConstVariableOrigin {
+ match arg.unpack() {
+ GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
+ GenericArgKind::Type(_) => self
+ .next_ty_var(TypeVariableOrigin {
span: rustc_span::DUMMY_SP,
- kind: ConstVariableOriginKind::MiscVariable,
- },
- )
- .into(),
- }
- }))
- .unwrap()
- .into_buffer();
+ kind: TypeVariableOriginKind::MiscVariable,
+ })
+ .into(),
+ GenericArgKind::Const(arg) => self
+ .next_const_var(
+ arg.ty(),
+ ConstVariableOrigin {
+ span: rustc_span::DUMMY_SP,
+ kind: ConstVariableOriginKind::MiscVariable,
+ },
+ )
+ .into(),
+ }
+ }))
+ .unwrap()
+ .into_buffer()
+ };
if !have_turbofish {
infer_subdiags.push(SourceKindSubdiag::GenericSuggestion {
));
}
InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
- let ty_info = ty_to_string(self, ty);
+ let ty_info = ty_to_string(self, ty, None);
multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
ty_info,
data,
insert_span: Span,
pattern_name: Option<Ident>,
ty: Ty<'tcx>,
+ def_id: Option<DefId>,
},
ClosureArg {
insert_span: Span,
if ty.is_closure() {
("closure", closure_as_fn_str(infcx, ty))
} else if !ty.is_ty_infer() {
- ("normal", ty_to_string(infcx, ty))
+ ("normal", ty_to_string(infcx, ty, None))
} else {
("other", String::new())
}
/// Uses `fn source_cost` to determine whether this inference source is preferable to
/// previous sources. We generally prefer earlier sources.
#[instrument(level = "debug", skip(self))]
- fn update_infer_source(&mut self, new_source: InferSource<'tcx>) {
+ fn update_infer_source(&mut self, mut new_source: InferSource<'tcx>) {
let cost = self.source_cost(&new_source) + self.attempt;
debug!(?cost);
self.attempt += 1;
+ if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, ..}, .. }) = self.infer_source
+ && let InferSourceKind::LetBinding { ref ty, ref mut def_id, ..} = new_source.kind
+ && ty.is_ty_infer()
+ {
+ // Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of
+ // `let x: _ = iter.collect();`, as this is a very common case.
+ *def_id = Some(did);
+ }
if cost < self.infer_source_cost {
self.infer_source_cost = cost;
self.infer_source = Some(new_source);
match inner.unpack() {
GenericArgKind::Lifetime(_) => {}
GenericArgKind::Type(ty) => {
- if matches!(ty.kind(), ty::Opaque(..) | ty::Closure(..) | ty::Generator(..)) {
+ if matches!(
+ ty.kind(),
+ ty::Alias(ty::Opaque, ..) | ty::Closure(..) | ty::Generator(..)
+ ) {
// Opaque types can't be named by the user right now.
//
// Both the generic arguments of closures and generators can
insert_span: local.pat.span.shrink_to_hi(),
pattern_name: local.pat.simple_ident(),
ty,
+ def_id: None,
},
})
}
false
};
- let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef {
- def_id: trait_def_id,
- substs: expected_substs,
- });
- let actual_trait_ref = self
+ let expected_trait_ref = self
.cx
- .resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs });
+ .resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, expected_substs));
+ let actual_trait_ref =
+ self.cx.resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, actual_substs));
// Search the expected and actual trait references to see (a)
// whether the sub/sup placeholders appear in them (sometimes
Applicability::MaybeIncorrect,
);
}
- if let Some((param_span, param_ty)) = param.clone() {
+ if let Some((param_span, ref param_ty)) = param {
err.span_suggestion_verbose(
param_span,
add_static_bound,
_ if self.same_type_modulo_infer(last_expr_ty, expected_ty) => {
StatementAsExpression::CorrectType
}
- (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _))
- if last_def_id == exp_def_id =>
- {
- StatementAsExpression::CorrectType
- }
- (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => {
+ (
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, .. }),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, .. }),
+ ) if last_def_id == exp_def_id => StatementAsExpression::CorrectType,
+ (
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, substs: last_bounds, .. }),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, substs: exp_bounds, .. }),
+ ) => {
debug!(
"both opaque, likely future {:?} {:?} {:?} {:?}",
last_def_id, last_bounds, exp_def_id, exp_bounds
| ty::Dynamic(..)
| ty::Never
| ty::Tuple(..)
- | ty::Projection(..)
+ | ty::Alias(..)
| ty::Foreign(..)
| ty::Param(..)
| ty::Closure(..)
- | ty::GeneratorWitness(..)
- | ty::Opaque(..) => t.super_fold_with(self),
+ | ty::GeneratorWitness(..) => t.super_fold_with(self),
ty::Placeholder(..) | ty::Bound(..) => bug!("unexpected type {:?}", t),
}
where
T: Relate<'tcx>,
{
+ // GLB of a binder and itself is just itself
+ if a == b {
+ return Ok(a);
+ }
+
debug!("binders(a={:?}, b={:?})", a, b);
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
// When higher-ranked types are involved, computing the GLB is
Ok(v)
}
- (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
- infcx.super_combine_tys(this, a, b)
- }
- (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
- if this.define_opaque_types() && did.is_local() =>
+ (
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+ ) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b),
+ (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+ | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
+ if this.define_opaque_types() && def_id.is_local() =>
{
this.add_obligations(
infcx
where
T: Relate<'tcx>,
{
+ // LUB of a binder and itself is just itself
+ if a == b {
+ return Ok(a);
+ }
+
debug!("binders(a={:?}, b={:?})", a, b);
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
// When higher-ranked types are involved, computing the LUB is
tcx: TyCtxt<'tcx>,
substs: SubstsRef<'tcx>,
) -> SubstsRef<'tcx> {
- tcx.mk_substs(substs.iter().enumerate().map(|(idx, arg)| {
- match arg.unpack() {
- GenericArgKind::Type(_) if arg.has_non_region_param() || arg.has_non_region_infer() => {
- tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
+ struct ReplaceParamAndInferWithPlaceholder<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ idx: usize,
+ }
+
+ impl<'tcx> TypeFolder<'tcx> for ReplaceParamAndInferWithPlaceholder<'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ if let ty::Infer(_) = t.kind() {
+ self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::ROOT,
- name: ty::BoundVar::from_usize(idx),
+ name: ty::BoundVar::from_usize({
+ let idx = self.idx;
+ self.idx += 1;
+ idx
+ }),
}))
- .into()
+ } else {
+ t.super_fold_with(self)
}
- GenericArgKind::Const(ct) if ct.has_non_region_infer() || ct.has_non_region_param() => {
- let ty = ct.ty();
- // If the type references param or infer, replace that too...
+ }
+
+ fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ if let ty::ConstKind::Infer(_) = c.kind() {
+ let ty = c.ty();
+ // If the type references param or infer then ICE ICE ICE
if ty.has_non_region_param() || ty.has_non_region_infer() {
- bug!("const `{ct}`'s type should not reference params or types");
+ bug!("const `{c}`'s type should not reference params or types");
}
- tcx.mk_const(
+ self.tcx.mk_const(
ty::PlaceholderConst {
universe: ty::UniverseIndex::ROOT,
- name: ty::BoundVar::from_usize(idx),
+ name: ty::BoundVar::from_usize({
+ let idx = self.idx;
+ self.idx += 1;
+ idx
+ }),
},
ty,
)
- .into()
+ } else {
+ c.super_fold_with(self)
}
- _ => arg,
}
- }))
+ }
+
+ substs.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 })
}
/// `ProjectionEq(projection = ?U)`, `ProjectionEq(other_projection = ?U)`.
fn relate_projection_ty(
&mut self,
- projection_ty: ty::ProjectionTy<'tcx>,
+ projection_ty: ty::AliasTy<'tcx>,
value_ty: Ty<'tcx>,
) -> Ty<'tcx> {
use rustc_span::DUMMY_SP;
match *value_ty.kind() {
- ty::Projection(other_projection_ty) => {
+ ty::Alias(ty::Projection, other_projection_ty) => {
let var = self.infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span: DUMMY_SP,
return Ok(value_ty);
}
- ty::Projection(projection_ty) if D::normalization() == NormalizationStrategy::Lazy => {
+ ty::Alias(ty::Projection, projection_ty)
+ if D::normalization() == NormalizationStrategy::Lazy =>
+ {
return Ok(self.relate_projection_ty(projection_ty, self.infcx.tcx.mk_ty_var(vid)));
}
}
};
let (a, b) = match (a.kind(), b.kind()) {
- (&ty::Opaque(..), _) => (a, generalize(b, false)?),
- (_, &ty::Opaque(..)) => (generalize(a, true)?, b),
+ (&ty::Alias(ty::Opaque, ..), _) => (a, generalize(b, false)?),
+ (_, &ty::Alias(ty::Opaque, ..)) => (generalize(a, true)?, b),
_ => unreachable!(),
};
let cause = ObligationCause::dummy_with_span(self.delegate.span());
(&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)),
- (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
- infcx.super_combine_tys(self, a, b).or_else(|err| {
- self.tcx().sess.delay_span_bug(
- self.delegate.span(),
- "failure to relate an opaque to itself should result in an error later on",
- );
- if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
- })
- }
- (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if did.is_local() => {
+ (
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+ ) if a_def_id == b_def_id => infcx.super_combine_tys(self, a, b).or_else(|err| {
+ self.tcx().sess.delay_span_bug(
+ self.delegate.span(),
+ "failure to relate an opaque to itself should result in an error later on",
+ );
+ if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
+ }),
+ (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+ | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
+ if def_id.is_local() =>
+ {
self.relate_opaques(a, b)
}
- (&ty::Projection(projection_ty), _)
+ (&ty::Alias(ty::Projection, projection_ty), _)
if D::normalization() == NormalizationStrategy::Lazy =>
{
Ok(self.relate_projection_ty(projection_ty, b))
}
- (_, &ty::Projection(projection_ty))
+ (_, &ty::Alias(ty::Projection, projection_ty))
if D::normalization() == NormalizationStrategy::Lazy =>
{
Ok(self.relate_projection_ty(projection_ty, a))
lt_op: |lt| lt,
ct_op: |ct| ct,
ty_op: |ty| match *ty.kind() {
- ty::Opaque(def_id, _substs) if replace_opaque_type(def_id) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })
+ if replace_opaque_type(def_id) =>
+ {
let def_span = self.tcx.def_span(def_id);
let span = if span.contains(def_span) { def_span } else { span };
let code = traits::ObligationCauseCode::OpaqueReturnType(None);
}
let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() {
- ty::Opaque(def_id, substs) if def_id.is_local() => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) if def_id.is_local() => {
let def_id = def_id.expect_local();
let origin = match self.defining_use_anchor {
DefiningAnchor::Bind(_) => {
DefiningAnchor::Bubble => self.opaque_ty_origin_unchecked(def_id, cause.span),
DefiningAnchor::Error => return None,
};
- if let ty::Opaque(did2, _) = *b.kind() {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
// We could accept this, but there are various ways to handle this situation, and we don't
// want to make a decision on it right now. Likely this case is so super rare anyway, that
// no one encounters it in practice.
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
// where it is of no concern, so we only check for TAITs.
- if let Some(OpaqueTyOrigin::TyAlias) =
- did2.as_local().and_then(|did2| self.opaque_type_origin(did2, cause.span))
+ if let Some(OpaqueTyOrigin::TyAlias) = b_def_id
+ .as_local()
+ .and_then(|b_def_id| self.opaque_type_origin(b_def_id, cause.span))
{
self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
span: cause.span,
- hidden_type: self.tcx.def_span(did2),
+ hidden_type: self.tcx.def_span(b_def_id),
opaque_type: self.tcx.def_span(def_id),
});
}
substs.as_generator().resume_ty().visit_with(self);
}
- ty::Opaque(def_id, ref substs) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, ref substs, .. }) => {
// Skip lifetime paramters that are not captures.
let variances = self.tcx.variances_of(*def_id);
}
}
- ty::Projection(proj)
- if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
+ ty::Alias(ty::Projection, proj)
+ if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder =>
{
// Skip lifetime paramters that are not captures.
- let variances = self.tcx.variances_of(proj.item_def_id);
+ let variances = self.tcx.variances_of(proj.def_id);
for (v, s) in std::iter::zip(variances, proj.substs.iter()) {
if *v != ty::Variance::Bivariant {
// We can't normalize associated types from `rustc_infer`,
// but we can eagerly register inference variables for them.
// FIXME(RPITIT): Don't replace RPITITs with inference vars.
- ty::Projection(projection_ty)
+ ty::Alias(ty::Projection, projection_ty)
if !projection_ty.has_escaping_bound_vars()
- && tcx.def_kind(projection_ty.item_def_id)
+ && tcx.def_kind(projection_ty.def_id)
!= DefKind::ImplTraitPlaceholder =>
{
self.infer_projection(
}
// Replace all other mentions of the same opaque type with the hidden type,
// as the bounds must hold on the hidden type after all.
- ty::Opaque(def_id2, substs2)
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: def_id2, substs: substs2, .. })
if def_id.to_def_id() == def_id2 && substs == substs2 =>
{
hidden_ty
}
// FIXME(RPITIT): This can go away when we move to associated types
- ty::Projection(proj)
- if def_id.to_def_id() == proj.item_def_id && substs == proj.substs =>
- {
- hidden_ty
- }
+ ty::Alias(
+ ty::Projection,
+ ty::AliasTy { def_id: def_id2, substs: substs2, .. },
+ ) if def_id.to_def_id() == def_id2 && substs == substs2 => hidden_ty,
_ => ty,
},
lt_op: |lt| lt,
// is not in a position to judge which is the best technique, so
// we just product the projection as a component and leave it to
// the consumer to decide (but see `EscapingProjection` below).
- Projection(ty::ProjectionTy<'tcx>),
+ Projection(ty::AliasTy<'tcx>),
// In the case where a projection has escaping regions -- meaning
// regions bound within the type itself -- we always use
// outlives any other lifetime, which is unsound.
// See https://github.com/rust-lang/rust/issues/84305 for
// more details.
- ty::Opaque(def_id, substs) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
out.push(Component::Opaque(def_id, substs));
},
// trait-ref. Therefore, if we see any higher-ranked regions,
// we simply fallback to the most restrictive rule, which
// requires that `Pi: 'a` for all `i`.
- ty::Projection(ref data) => {
+ ty::Alias(ty::Projection, ref data) => {
if !data.has_escaping_bound_vars() {
// best case: no escaping regions, so push the
// projection and skip the subtree (thus generating no
substs,
true,
|ty| match *ty.kind() {
- ty::Opaque(def_id, substs) => (def_id, substs),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => (def_id, substs),
_ => bug!("expected only projection types from env, not {:?}", ty),
},
);
&mut self,
origin: infer::SubregionOrigin<'tcx>,
region: ty::Region<'tcx>,
- projection_ty: ty::ProjectionTy<'tcx>,
+ projection_ty: ty::AliasTy<'tcx>,
) {
self.generic_must_outlive(
origin,
region,
GenericKind::Projection(projection_ty),
- projection_ty.item_def_id,
+ projection_ty.def_id,
projection_ty.substs,
false,
|ty| match ty.kind() {
- ty::Projection(projection_ty) => (projection_ty.item_def_id, projection_ty.substs),
+ ty::Alias(ty::Projection, projection_ty) => {
+ (projection_ty.def_id, projection_ty.substs)
+ }
_ => bug!("expected only projection types from env, not {:?}", ty),
},
);
),
Component::Projection(projection_ty) => self.projection_opaque_bounds(
GenericKind::Projection(projection_ty),
- projection_ty.item_def_id,
+ projection_ty.def_id,
projection_ty.substs,
visited,
),
pub fn infer_projection(
&self,
param_env: ty::ParamEnv<'tcx>,
- projection_ty: ty::ProjectionTy<'tcx>,
+ projection_ty: ty::AliasTy<'tcx>,
cause: ObligationCause<'tcx>,
recursion_depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>,
) -> Ty<'tcx> {
- let def_id = projection_ty.item_def_id;
+ let def_id = projection_ty.def_id;
let ty_var = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::NormalizeProjectionType,
span: self.tcx.def_span(def_id),
#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
pub enum GenericKind<'tcx> {
Param(ty::ParamTy),
- Projection(ty::ProjectionTy<'tcx>),
+ Projection(ty::AliasTy<'tcx>),
Opaque(DefId, SubstsRef<'tcx>),
}
pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match *self {
GenericKind::Param(ref p) => p.to_ty(tcx),
- GenericKind::Projection(ref p) => tcx.mk_projection(p.item_def_id, p.substs),
+ GenericKind::Projection(ref p) => tcx.mk_projection(p.def_id, p.substs),
GenericKind::Opaque(def_id, substs) => tcx.mk_opaque(def_id, substs),
}
}
Ok(self.tcx().ty_error_with_guaranteed(e))
}
- (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
+ (
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+ ) if a_def_id == b_def_id => {
self.fields.infcx.super_combine_tys(self, a, b)?;
Ok(a)
}
- (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
- if self.fields.define_opaque_types && did.is_local() =>
+ (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+ | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
+ if self.fields.define_opaque_types && def_id.is_local() =>
{
self.fields.obligations.extend(
infcx
where
T: Relate<'tcx>,
{
+ // A binder is always a subtype of itself if it's structually equal to itself
+ if a == b {
+ return Ok(a);
+ }
+
self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
Ok(a)
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct ProjectionCacheKey<'tcx> {
- ty: ty::ProjectionTy<'tcx>,
+ ty: ty::AliasTy<'tcx>,
}
impl<'tcx> ProjectionCacheKey<'tcx> {
- pub fn new(ty: ty::ProjectionTy<'tcx>) -> Self {
+ pub fn new(ty: ty::AliasTy<'tcx>) -> Self {
Self { ty }
}
}
Component::Projection(projection) => {
// We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
// With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
- let ty =
- tcx.mk_projection(projection.item_def_id, projection.substs);
+ let ty = tcx.mk_projection(projection.def_id, projection.substs);
Some(ty::PredicateKind::Clause(ty::Clause::TypeOutlives(
ty::OutlivesPredicate(ty, r_min),
)))
})?;
}
Some(c) => {
- let digit =
+ let digit: u32 =
c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?;
n_digits += 1;
if n_digits > 6 {
// Stop updating value since we're sure that it's incorrect already.
continue;
}
- let digit = digit as u32;
value = value * 16 + digit;
}
};
| (Closure(..), Closure(..))
| (Generator(..), Generator(..))
| (GeneratorWitness(..), GeneratorWitness(..))
- | (Projection(..), Projection(..))
- | (Opaque(..), Opaque(..)) => false,
+ | (Alias(ty::Projection, ..), Alias(ty::Projection, ..))
+ | (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false,
// These definitely should have been caught above.
(Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
tcx.associated_items(trait_id)
.find_by_name_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
.and_then(|assoc| {
- let proj = tcx.mk_projection(assoc.def_id, tcx.mk_substs_trait(self_ty, []));
+ let proj = tcx.mk_projection(assoc.def_id, [self_ty]);
tcx.try_normalize_erasing_regions(self.param_env, proj).ok()
})
}
let Some(proj_term) = proj.term.ty() else { continue };
let proj_ty =
- cx.tcx.mk_projection(proj.projection_ty.item_def_id, proj.projection_ty.substs);
+ cx.tcx.mk_projection(proj.projection_ty.def_id, proj.projection_ty.substs);
// For every instance of the projection type in the bounds,
// replace them with the term we're assigning to the associated
// type in our opaque type.
// with `impl Send: OtherTrait`.
for (assoc_pred, assoc_pred_span) in cx
.tcx
- .bound_explicit_item_bounds(proj.projection_ty.item_def_id)
+ .bound_explicit_item_bounds(proj.projection_ty.def_id)
.subst_iter_copied(cx.tcx, &proj.projection_ty.substs)
{
let assoc_pred = assoc_pred.fold_with(proj_replacer);
// then we can emit a suggestion to add the bound.
let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
(
- ty::Opaque(def_id, _),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }),
ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)),
) => Some(AddBound {
suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(),
// While opaque types are checked for earlier, if a projection in a struct field
// normalizes to an opaque type, then it will reach this branch.
- ty::Opaque(..) => {
+ ty::Alias(ty::Opaque, ..) => {
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_opaque, help: None }
}
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
// so they are currently ignored for the purposes of this lint.
- ty::Param(..) | ty::Projection(..) if matches!(self.mode, CItemKind::Definition) => {
+ ty::Param(..) | ty::Alias(ty::Projection, ..)
+ if matches!(self.mode, CItemKind::Definition) =>
+ {
FfiSafe
}
ty::Param(..)
- | ty::Projection(..)
+ | ty::Alias(ty::Projection, ..)
| ty::Infer(..)
| ty::Bound(..)
| ty::Error(_)
return ControlFlow::CONTINUE;
}
- if let ty::Opaque(..) = ty.kind() {
+ if let ty::Alias(ty::Opaque, ..) = ty.kind() {
ControlFlow::Break(ty)
} else {
ty.super_visit_with(self)
if let hir::ExprKind::Match(await_expr, _arms, hir::MatchSource::AwaitDesugar) = expr.kind
&& let ty = cx.typeck_results().expr_ty(&await_expr)
- && let ty::Opaque(future_def_id, _) = ty.kind()
+ && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: future_def_id, .. }) = ty.kind()
&& cx.tcx.ty_is_opaque_future(ty)
// FIXME: This also includes non-async fns that return `impl Future`.
&& let async_fn_def_id = cx.tcx.parent(*future_def_id)
.map(|inner| MustUsePath::Boxed(Box::new(inner)))
}
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
- ty::Opaque(def, _) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
elaborate_predicates_with_span(
cx.tcx,
cx.tcx.explicit_item_bounds(def).iter().cloned(),
declare_lint! {
/// The `trivial_casts` lint detects trivial casts which could be replaced
- /// with coercion, which may require [type ascription] or a temporary
- /// variable.
+ /// with coercion, which may require a temporary variable.
///
/// ### Example
///
/// with FFI interfaces or complex type aliases, where it triggers
/// incorrectly, or in situations where it will be more difficult to
/// clearly express the intent. It may be possible that this will become a
- /// warning in the future, possibly with [type ascription] providing a
- /// convenient way to work around the current issues. See [RFC 401] for
- /// historical context.
- ///
- /// [type ascription]: https://github.com/rust-lang/rust/issues/23416
- /// [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
+ /// warning in the future, possibly with an explicit syntax for coercions
+ /// providing a convenient way to work around the current issues.
+ /// See [RFC 401 (coercions)][rfc-401], [RFC 803 (type ascription)][rfc-803] and
+ /// [RFC 3307 (remove type ascription)][rfc-3307] for historical context.
+ ///
+ /// [rfc-401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
+ /// [rfc-803]: https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md
+ /// [rfc-3307]: https://github.com/rust-lang/rfcs/blob/master/text/3307-de-rfc-type-ascription.md
pub TRIVIAL_CASTS,
Allow,
"detects trivial casts which could be removed"
/// with FFI interfaces or complex type aliases, where it triggers
/// incorrectly, or in situations where it will be more difficult to
/// clearly express the intent. It may be possible that this will become a
- /// warning in the future, possibly with [type ascription] providing a
- /// convenient way to work around the current issues. See [RFC 401] for
- /// historical context.
- ///
- /// [type ascription]: https://github.com/rust-lang/rust/issues/23416
- /// [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
+ /// warning in the future, possibly with an explicit syntax for coercions
+ /// providing a convenient way to work around the current issues.
+ /// See [RFC 401 (coercions)][rfc-401], [RFC 803 (type ascription)][rfc-803] and
+ /// [RFC 3307 (remove type ascription)][rfc-3307] for historical context.
+ ///
+ /// [rfc-401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
+ /// [rfc-803]: https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md
+ /// [rfc-3307]: https://github.com/rust-lang/rfcs/blob/master/text/3307-de-rfc-type-ascription.md
pub TRIVIAL_NUMERIC_CASTS,
Allow,
"detects trivial casts of numeric types which could be removed"
};
}
+declare_lint! {
+ /// The `invalid_alignment` lint detects dereferences of misaligned pointers during
+ /// constant evluation.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![feature(const_ptr_read)]
+ /// const FOO: () = unsafe {
+ /// let x = &[0_u8; 4];
+ /// let y = x.as_ptr().cast::<u32>();
+ /// y.read(); // the address of a `u8` array is unknown and thus we don't know if
+ /// // it is aligned enough for reading a `u32`.
+ /// };
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The compiler allowed dereferencing raw pointers irrespective of alignment
+ /// during const eval due to the const evaluator at the time not making it easy
+ /// or cheap to check. Now that it is both, this is not accepted anymore.
+ ///
+ /// Since it was undefined behaviour to begin with, this breakage does not violate
+ /// Rust's stability guarantees. Using undefined behaviour can cause arbitrary
+ /// behaviour, including failure to build.
+ ///
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
+ pub INVALID_ALIGNMENT,
+ Deny,
+ "raw pointers must be aligned before dereferencing",
+ @future_incompatible = FutureIncompatibleInfo {
+ reference: "issue #68585 <https://github.com/rust-lang/rust/issues/104616>",
+ reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
+ };
+}
+
declare_lint! {
/// The `exported_private_dependencies` lint detects private dependencies
/// that are exposed in a public interface.
let crate_name = std::env::var("CARGO_CRATE_NAME").ok()?;
// If we're not in a "rustc_" crate, bail.
- let Some(("rustc", slug_prefix)) = crate_name.split_once("_") else { return None };
+ let Some(("rustc", slug_prefix)) = crate_name.split_once('_') else { return None };
let slug_name = slug.segments.first()?.ident.to_string();
if !slug_name.starts_with(slug_prefix) {
}
}
(Meta::Path(_), "subdiagnostic") => {
- return Ok(quote! { #diag.subdiagnostic(#binding); });
+ if FieldInnerTy::from_type(&info.binding.ast().ty).will_iterate() {
+ let DiagnosticDeriveKind::Diagnostic { handler } = &self.parent.kind else {
+ // No eager translation for lints.
+ return Ok(quote! { #diag.subdiagnostic(#binding); });
+ };
+ return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); });
+ } else {
+ return Ok(quote! { #diag.subdiagnostic(#binding); });
+ }
}
- (Meta::NameValue(_), "subdiagnostic") => {
+ (Meta::List(_), "subdiagnostic") => {
throw_invalid_attr!(attr, &meta, |diag| {
- diag.help("`eager` is the only supported nested attribute for `subdiagnostic`")
+ diag.help("`subdiagnostic` does not support nested attributes")
})
}
- (Meta::List(MetaList { ref nested, .. }), "subdiagnostic") => {
- if nested.len() != 1 {
- throw_invalid_attr!(attr, &meta, |diag| {
- diag.help(
- "`eager` is the only supported nested attribute for `subdiagnostic`",
- )
- })
- }
-
- let handler = match &self.parent.kind {
- DiagnosticDeriveKind::Diagnostic { handler } => handler,
- DiagnosticDeriveKind::LintDiagnostic => {
- throw_invalid_attr!(attr, &meta, |diag| {
- diag.help("eager subdiagnostics are not supported on lints")
- })
- }
- };
-
- let nested_attr = nested.first().expect("pop failed for single element list");
- match nested_attr {
- NestedMeta::Meta(meta @ Meta::Path(_))
- if meta.path().segments.last().unwrap().ident.to_string().as_str()
- == "eager" =>
- {
- return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); });
- }
- _ => {
- throw_invalid_nested_attr!(attr, nested_attr, |diag| {
- diag.help("`eager` is the only supported nested attribute for `subdiagnostic`")
- })
- }
- }
- }
_ => (),
}
if let Some(virtual_dir) = &sess.opts.unstable_opts.simulate_remapped_rust_src_base
{
if let Some(real_dir) = &sess.opts.real_rust_source_base_dir {
- if let rustc_span::FileName::Real(ref mut old_name) = name {
- if let rustc_span::RealFileName::LocalPath(local) = old_name {
- if let Ok(rest) = local.strip_prefix(real_dir) {
- *old_name = rustc_span::RealFileName::Remapped {
- local_path: None,
- virtual_name: virtual_dir.join(rest),
- };
+ for subdir in ["library", "compiler"] {
+ if let rustc_span::FileName::Real(ref mut old_name) = name {
+ if let rustc_span::RealFileName::LocalPath(local) = old_name {
+ if let Ok(rest) = local.strip_prefix(real_dir.join(subdir)) {
+ *old_name = rustc_span::RealFileName::Remapped {
+ local_path: None,
+ virtual_name: virtual_dir.join(subdir).join(rest),
+ };
+ }
}
}
}
// associated types.
tcx.fn_sig(trait_item_def_id).skip_binder().output().walk().any(|arg| {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Projection(data) = ty.kind()
- && tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder
+ && let ty::Alias(ty::Projection, data) = ty.kind()
+ && tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder
{
true
} else {
pub fn function_handle(
tcx: TyCtxt<'tcx>,
def_id: DefId,
- substs: SubstsRef<'tcx>,
+ substs: impl IntoIterator<Item = GenericArg<'tcx>>,
span: Span,
) -> Self {
let ty = tcx.mk_fn_def(def_id, substs);
MonoItem::GlobalAsm(..) => LOCAL_CRATE,
}
}
+
+ /// Returns the item's `DefId`
+ pub fn def_id(&self) -> DefId {
+ match *self {
+ MonoItem::Fn(Instance { def, .. }) => def.def_id(),
+ MonoItem::Static(def_id) => def_id,
+ MonoItem::GlobalAsm(item_id) => item_id.owner_id.to_def_id(),
+ }
+ }
}
impl<'tcx> fmt::Display for MonoItem<'tcx> {
TupleElem,
/// This is the trait reference from the given projection.
- ProjectionWf(ty::ProjectionTy<'tcx>),
+ ProjectionWf(ty::AliasTy<'tcx>),
/// Must satisfy all of the where-clause predicates of the
/// given item.
}
}
-pub type CanonicalProjectionGoal<'tcx> =
- Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>;
+pub type CanonicalProjectionGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>;
pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
pub enum OutlivesBound<'tcx> {
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
- RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
+ RegionSubProjection(ty::Region<'tcx>, ty::AliasTy<'tcx>),
RegionSubOpaque(ty::Region<'tcx>, DefId, SubstsRef<'tcx>),
}
.find(|m| m.kind == ty::AssocKind::Fn)
.unwrap()
.def_id;
- tcx.mk_fn_def(method_def_id, tcx.mk_substs_trait(source, []))
+ tcx.mk_fn_def(method_def_id, [source])
}
}
self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
ClosureSizeProfileData, Const, ConstS, DefIdTree, FloatTy, FloatVar, FloatVid,
GenericParamDefKind, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
- PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, ProjectionTy, Region,
- RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy,
- Visibility,
+ PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions,
+ TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
};
use crate::ty::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef, UserSubsts};
use rustc_ast as ast;
type ListBinderExistentialPredicate = &'tcx List<PolyExistentialPredicate<'tcx>>;
type BinderListTy = Binder<'tcx, &'tcx List<Ty<'tcx>>>;
type ListTy = &'tcx List<Ty<'tcx>>;
- type ProjectionTy = ty::ProjectionTy<'tcx>;
+ type AliasTy = ty::AliasTy<'tcx>;
type ParamTy = ParamTy;
type BoundTy = ty::BoundTy;
type PlaceholderType = ty::PlaceholderType;
Bound,
Param,
Infer,
- Projection,
- Opaque,
+ Alias,
Foreign
)?;
/// Given a `ty`, return whether it's an `impl Future<...>`.
pub fn ty_is_opaque_future(self, ty: Ty<'_>) -> bool {
- let ty::Opaque(def_id, _) = ty.kind() else { return false };
+ let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false };
let future_trait = self.require_lang_item(LangItem::Future, None);
self.explicit_item_bounds(def_id).iter().any(|(predicate, _)| {
}
#[inline]
- pub fn mk_fn_def(self, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
- debug_assert_eq!(
- self.generics_of(def_id).count(),
- substs.len(),
- "wrong number of generic parameters for {def_id:?}: {substs:?}",
- );
+ pub fn mk_fn_def(
+ self,
+ def_id: DefId,
+ substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+ ) -> Ty<'tcx> {
+ let substs = self.check_substs(def_id, substs);
self.mk_ty(FnDef(def_id, substs))
}
+ #[inline(always)]
+ fn check_substs(
+ self,
+ _def_id: DefId,
+ substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+ ) -> SubstsRef<'tcx> {
+ let substs = substs.into_iter().map(Into::into);
+ #[cfg(debug_assertions)]
+ {
+ let n = self.generics_of(_def_id).count();
+ assert_eq!(
+ (n, Some(n)),
+ substs.size_hint(),
+ "wrong number of generic parameters for {_def_id:?}: {:?}",
+ substs.collect::<Vec<_>>(),
+ );
+ }
+ self.mk_substs(substs)
+ }
+
#[inline]
pub fn mk_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
self.mk_ty(FnPtr(fty))
}
#[inline]
- pub fn mk_projection(self, item_def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
- debug_assert_eq!(
- self.generics_of(item_def_id).count(),
- substs.len(),
- "wrong number of generic parameters for {item_def_id:?}: {substs:?}",
- );
- self.mk_ty(Projection(ProjectionTy { item_def_id, substs }))
+ pub fn mk_projection(
+ self,
+ item_def_id: DefId,
+ substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+ ) -> Ty<'tcx> {
+ self.mk_ty(Alias(ty::Projection, self.mk_alias_ty(item_def_id, substs)))
}
#[inline]
#[inline]
pub fn mk_opaque(self, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
- self.mk_ty(Opaque(def_id, substs))
+ self.mk_ty(Alias(ty::Opaque, self.mk_alias_ty(def_id, substs)))
}
pub fn mk_place_field(self, place: Place<'tcx>, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
trait_def_id: DefId,
substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
) -> ty::TraitRef<'tcx> {
- let substs = substs.into_iter().map(Into::into);
- let n = self.generics_of(trait_def_id).count();
- debug_assert_eq!(
- (n, Some(n)),
- substs.size_hint(),
- "wrong number of generic parameters for {trait_def_id:?}: {:?} \nDid you accidentally include the self-type in the params list?",
- substs.collect::<Vec<_>>(),
- );
- let substs = self.mk_substs(substs);
- ty::TraitRef::new(trait_def_id, substs)
+ let substs = self.check_substs(trait_def_id, substs);
+ ty::TraitRef { def_id: trait_def_id, substs, _use_mk_trait_ref_instead: () }
+ }
+
+ pub fn mk_alias_ty(
+ self,
+ def_id: DefId,
+ substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+ ) -> ty::AliasTy<'tcx> {
+ let substs = self.check_substs(def_id, substs);
+ ty::AliasTy { def_id, substs, _use_mk_alias_ty_instead: () }
}
pub fn mk_bound_variable_kinds<
use std::ops::ControlFlow;
use crate::ty::{
- visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferConst, InferTy,
+ visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, InferConst, InferTy, Opaque,
PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
};
return ControlFlow::Break(());
}
- Opaque(did, _) => {
- let parent = self.tcx.parent(*did);
+ Alias(Opaque, AliasTy { def_id, .. }) => {
+ let parent = self.tcx.parent(*def_id);
if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
- && let Opaque(parent_did, _) = self.tcx.type_of(parent).kind()
- && parent_did == did
+ && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = self.tcx.type_of(parent).kind()
+ && parent_opaque_def_id == def_id
{
// Okay
} else {
}
}
- Dynamic(dty, _, _) => {
- for pred in *dty {
- match pred.skip_binder() {
- ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => {
- // Okay
- }
- _ => return ControlFlow::Break(()),
- }
- }
- }
-
Param(param) => {
// FIXME: It would be nice to make this not use string manipulation,
// but it's pretty hard to do this, since `ty::ParamTy` is missing
ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
- ty::Projection(_) => "associated type".into(),
+ ty::Alias(ty::Projection, _) => "associated type".into(),
ty::Param(p) => format!("type parameter `{}`", p).into(),
- ty::Opaque(..) => "opaque type".into(),
+ ty::Alias(ty::Opaque, ..) => "opaque type".into(),
ty::Error(_) => "type error".into(),
}
}
ty::Tuple(..) => "tuple".into(),
ty::Placeholder(..) => "higher-ranked type".into(),
ty::Bound(..) => "bound type variable".into(),
- ty::Projection(_) => "associated type".into(),
+ ty::Alias(ty::Projection, _) => "associated type".into(),
ty::Param(_) => "type parameter".into(),
- ty::Opaque(..) => "opaque type".into(),
+ ty::Alias(ty::Opaque, ..) => "opaque type".into(),
}
}
}
diag.note("no two closures, even if identical, have the same type");
diag.help("consider boxing your closure and/or using it as a trait object");
}
- (ty::Opaque(..), ty::Opaque(..)) => {
+ (ty::Alias(ty::Opaque, ..), ty::Alias(ty::Opaque, ..)) => {
// Issue #63167
diag.note("distinct uses of `impl Trait` result in different opaque types");
}
#traits-as-parameters",
);
}
- (ty::Projection(_), ty::Projection(_)) => {
+ (ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => {
diag.note("an associated type was expected, but a different one was found");
}
- (ty::Param(p), ty::Projection(proj)) | (ty::Projection(proj), ty::Param(p))
- if self.def_kind(proj.item_def_id) != DefKind::ImplTraitPlaceholder =>
+ (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
+ if self.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder =>
{
let generics = self.generics_of(body_owner_def_id);
let p_span = self.def_span(generics.type_param(p, self).def_id);
let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self);
let path =
self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
- let item_name = self.item_name(proj.item_def_id);
+ let item_name = self.item_name(proj.def_id);
let item_args = self.format_generic_args(assoc_substs);
let path = if path.ends_with('>') {
diag.note("you might be missing a type parameter or trait bound");
}
}
- (ty::Param(p), ty::Dynamic(..) | ty::Opaque(..))
- | (ty::Dynamic(..) | ty::Opaque(..), ty::Param(p)) => {
+ (ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..))
+ | (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => {
let generics = self.generics_of(body_owner_def_id);
let p_span = self.def_span(generics.type_param(p, self).def_id);
if !sp.contains(p_span) {
diag.span_label(p_span, "this type parameter");
}
}
- (ty::Projection(proj_ty), _) if self.def_kind(proj_ty.item_def_id) != DefKind::ImplTraitPlaceholder => {
+ (ty::Alias(ty::Projection, proj_ty), _) if self.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
self.expected_projection(
diag,
proj_ty,
cause.code(),
);
}
- (_, ty::Projection(proj_ty)) if self.def_kind(proj_ty.item_def_id) != DefKind::ImplTraitPlaceholder => {
+ (_, ty::Alias(ty::Projection, proj_ty)) if self.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
let msg = format!(
"consider constraining the associated type `{}` to `{}`",
values.found, values.expected,
diag: &mut Diagnostic,
msg: &str,
body_owner_def_id: DefId,
- proj_ty: &ty::ProjectionTy<'tcx>,
+ proj_ty: &ty::AliasTy<'tcx>,
ty: Ty<'tcx>,
) -> bool {
- let assoc = self.associated_item(proj_ty.item_def_id);
+ let assoc = self.associated_item(proj_ty.def_id);
let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
if let Some(hir_generics) = item.generics() {
fn expected_projection(
self,
diag: &mut Diagnostic,
- proj_ty: &ty::ProjectionTy<'tcx>,
+ proj_ty: &ty::AliasTy<'tcx>,
values: ExpectedFound<Ty<'tcx>>,
body_owner_def_id: DefId,
cause_code: &ObligationCauseCode<'_>,
);
let impl_comparison =
matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. });
- let assoc = self.associated_item(proj_ty.item_def_id);
+ let assoc = self.associated_item(proj_ty.def_id);
if !callable_scope || impl_comparison {
// We do not want to suggest calling functions when the reason of the
// type error is a comparison of an `impl` with its `trait` or when the
diag,
assoc.container_id(self),
current_method_ident,
- proj_ty.item_def_id,
+ proj_ty.def_id,
values.expected,
);
// Possibly suggest constraining the associated type to conform to the
self,
diag: &mut Diagnostic,
msg: &str,
- proj_ty: &ty::ProjectionTy<'tcx>,
+ proj_ty: &ty::AliasTy<'tcx>,
ty: Ty<'tcx>,
) -> bool {
- let assoc = self.associated_item(proj_ty.item_def_id);
- if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
+ let assoc = self.associated_item(proj_ty.def_id);
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() {
let opaque_local_def_id = def_id.as_local();
let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
match &self.hir().expect_item(opaque_local_def_id).kind {
.filter_map(|(_, item)| {
let method = self.fn_sig(item.def_id);
match *method.output().skip_binder().kind() {
- ty::Projection(ty::ProjectionTy { item_def_id, .. })
+ ty::Alias(ty::Projection, ty::AliasTy { def_id: item_def_id, .. })
if item_def_id == proj_ty_item_def_id =>
{
Some((
}
let mut short;
loop {
- // Look for the longest properly trimmed path that still fits in lenght_limit.
+ // Look for the longest properly trimmed path that still fits in length_limit.
short = with_forced_trimmed_paths!(
FmtPrinter::new_with_limit(
self,
TreatParams::AsPlaceholder => Some(PlaceholderSimplifiedType),
TreatParams::AsInfer => None,
},
- ty::Opaque(..) | ty::Projection(_) => match treat_params {
+ ty::Alias(..) => match treat_params {
// When treating `ty::Param` as a placeholder, projections also
// don't unify with anything else as long as they are fully normalized.
//
match impl_ty.kind() {
// Start by checking whether the type in the impl may unify with
// pretty much everything. Just return `true` in that case.
- ty::Param(_) | ty::Projection(_) | ty::Error(_) | ty::Opaque(..) => return true,
+ ty::Param(_) | ty::Error(_) | ty::Alias(..) => return true,
// These types only unify with inference variables or their own
// variant.
ty::Bool
_ => false,
},
- ty::Opaque(..) => true,
-
// Impls cannot contain these types as these cannot be named directly.
ty::FnDef(..) | ty::Closure(..) | ty::Generator(..) => false,
// projections can unify with other stuff.
//
// Looking forward to lazy normalization this is the safer strategy anyways.
- ty::Projection(_) => true,
+ ty::Alias(..) => true,
ty::Error(_) => true,
self.add_substs(substs);
}
- &ty::Projection(data) => {
+ &ty::Alias(ty::Projection, data) => {
self.add_flags(TypeFlags::HAS_TY_PROJECTION);
self.add_projection_ty(data);
}
- &ty::Opaque(_, substs) => {
+ &ty::Alias(ty::Opaque, ty::AliasTy { substs, .. }) => {
self.add_flags(TypeFlags::HAS_TY_OPAQUE);
self.add_substs(substs);
}
}
}
- fn add_projection_ty(&mut self, projection_ty: ty::ProjectionTy<'_>) {
+ fn add_projection_ty(&mut self, projection_ty: ty::AliasTy<'_>) {
self.add_substs(projection_ty.substs);
}
InhabitedPredicate::True
}
Never => InhabitedPredicate::False,
- Param(_) | Projection(_) => InhabitedPredicate::GenericType(self),
+ Param(_) | Alias(ty::Projection, _) => InhabitedPredicate::GenericType(self),
Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
// use a query for more complex cases
Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
let non_zero = !ty.is_unsafe_ptr();
let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
match tail.kind() {
- ty::Param(_) | ty::Projection(_) => {
+ ty::Param(_) | ty::Alias(ty::Projection, _) => {
debug_assert!(tail.has_non_region_param());
Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
}
}
}
- ty::Projection(_) | ty::Opaque(..) => {
+ ty::Alias(..) => {
let normalized = tcx.normalize_erasing_regions(param_env, ty);
if ty == normalized {
Err(err)
}
}
- ty::Projection(_)
+ ty::Alias(..)
| ty::Bound(..)
| ty::Placeholder(..)
- | ty::Opaque(..)
| ty::Param(_)
| ty::Infer(_)
| ty::Error(_) => bug!("TyAndLayout::field: unexpected type `{}`", this.ty),
use std::{fmt, str};
pub use crate::ty::diagnostics::*;
+pub use rustc_type_ir::AliasKind::*;
pub use rustc_type_ir::DynKind::*;
pub use rustc_type_ir::InferTy::*;
pub use rustc_type_ir::RegionKind::*;
pub use self::rvalue_scopes::RvalueScopes;
pub use self::sty::BoundRegionKind::*;
pub use self::sty::{
- Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
+ AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid,
EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts,
InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialPredicate,
PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef,
- ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts,
- VarianceDiagInfo,
+ Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo,
};
pub use self::trait_def::TraitDef;
pub predicates: Vec<Predicate<'tcx>>,
}
-#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
pub enum ImplSubject<'tcx> {
Trait(TraitRef<'tcx>),
Inherent(Ty<'tcx>),
}
}
- pub fn with_self_type(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
- Self { trait_ref: self.trait_ref.with_self_type(tcx, self_ty), ..self }
+ pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
+ Self { trait_ref: self.trait_ref.with_self_ty(tcx, self_ty), ..self }
}
pub fn def_id(self) -> DefId {
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
pub struct ProjectionPredicate<'tcx> {
- pub projection_ty: ProjectionTy<'tcx>,
+ pub projection_ty: AliasTy<'tcx>,
pub term: Term<'tcx>,
}
/// associated type, which is in `tcx.associated_item(projection_def_id()).container`.
pub fn projection_def_id(&self) -> DefId {
// Ok to skip binder since trait `DefId` does not care about regions.
- self.skip_binder().projection_ty.item_def_id
+ self.skip_binder().projection_ty.def_id
+ }
+}
+
+impl<'tcx> ProjectionPredicate<'tcx> {
+ pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
+ Self {
+ projection_ty: tcx.mk_alias_ty(
+ self.projection_ty.def_id,
+ [self_ty.into()].into_iter().chain(self.projection_ty.substs.iter().skip(1)),
+ ),
+ ..self
+ }
}
}
self.path_append(
|cx: Self| {
if trait_qualify_parent {
- let trait_ref = ty::TraitRef::new(
- parent_def_id,
- cx.tcx().intern_substs(parent_substs),
- );
+ let trait_ref =
+ cx.tcx().mk_trait_ref(parent_def_id, parent_substs.iter().copied());
cx.path_qualified(trait_ref.self_ty(), Some(trait_ref))
} else {
cx.print_def_path(parent_def_id, parent_substs)
| ty::Uint(_)
| ty::Str
| ty::FnPtr(_)
- | ty::Projection(_)
+ | ty::Alias(..)
| ty::Placeholder(..)
| ty::Param(_)
- | ty::Opaque(..)
| ty::Infer(_)
| ty::Bound(..)
| ty::Error(_)
use rustc_session::cstore::{ExternCrate, ExternCrateSource};
use rustc_session::Limit;
use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::FileNameDisplayPreference;
use rustc_target::abi::Size;
use rustc_target::spec::abi::Abi;
use smallvec::SmallVec;
ty::Foreign(def_id) => {
p!(print_def_path(def_id, &[]));
}
- ty::Projection(ref data) => {
+ ty::Alias(ty::Projection, ref data) => {
if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get()))
- && self.tcx().def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder
+ && self.tcx().def_kind(data.def_id) == DefKind::ImplTraitPlaceholder
{
- return self.pretty_print_opaque_impl_type(data.item_def_id, data.substs);
+ return self.pretty_print_opaque_impl_type(data.def_id, data.substs);
} else {
p!(print(data))
}
}
ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
- ty::Opaque(def_id, substs) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
// FIXME(eddyb) print this with `print_def_path`.
// We use verbose printing in 'NO_QUERIES' mode, to
// avoid needing to call `predicates_of`. This should
let parent = self.tcx().parent(def_id);
match self.tcx().def_kind(parent) {
DefKind::TyAlias | DefKind::AssocTy => {
- if let ty::Opaque(d, _) = *self.tcx().type_of(parent).kind() {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: d, .. }) =
+ *self.tcx().type_of(parent).kind()
+ {
if d == def_id {
// If the type alias directly starts with the `impl` of the
// opaque type we're printing, then skip the `::{opaque#1}`.
p!("@", print_def_path(did.to_def_id(), substs));
} else {
let span = self.tcx().def_span(did);
+ let preference = if FORCE_TRIMMED_PATH.with(|flag| flag.get()) {
+ FileNameDisplayPreference::Short
+ } else {
+ FileNameDisplayPreference::Remapped
+ };
p!(write(
"@{}",
// This may end up in stderr diagnostics but it may also be emitted
// into MIR. Hence we use the remapped path if available
- self.tcx().sess.source_map().span_to_embeddable_string(span)
+ self.tcx().sess.source_map().span_to_string(span, preference)
));
}
} else {
// Skip printing `<[generator@] as Generator<_>>::Return` from async blocks,
// unless we can find out what generator return type it comes from.
let term = if let Some(ty) = term.skip_binder().ty()
- && let ty::Projection(proj) = ty.kind()
- && let Some(assoc) = tcx.opt_associated_item(proj.item_def_id)
+ && let ty::Alias(ty::Projection, proj) = ty.kind()
+ && let Some(assoc) = tcx.opt_associated_item(proj.def_id)
&& assoc.trait_container(tcx) == tcx.lang_items().gen_trait()
&& assoc.name == rustc_span::sym::Return
{
}
ty::ExistentialProjection<'tcx> {
- let name = cx.tcx().associated_item(self.item_def_id).name;
+ let name = cx.tcx().associated_item(self.def_id).name;
p!(write("{} = ", name), print(self.term))
}
}
}
- ty::ProjectionTy<'tcx> {
- p!(print_def_path(self.item_def_id, self.substs));
+ ty::AliasTy<'tcx> {
+ p!(print_def_path(self.def_id, self.substs));
}
ty::ClosureKind {
T: Relate<'tcx>;
}
-pub trait Relate<'tcx>: TypeFoldable<'tcx> + Copy {
+pub trait Relate<'tcx>: TypeFoldable<'tcx> + PartialEq + Copy {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
a: Self,
}
}
-impl<'tcx> Relate<'tcx> for ty::ProjectionTy<'tcx> {
+impl<'tcx> Relate<'tcx> for ty::AliasTy<'tcx> {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
- a: ty::ProjectionTy<'tcx>,
- b: ty::ProjectionTy<'tcx>,
- ) -> RelateResult<'tcx, ty::ProjectionTy<'tcx>> {
- if a.item_def_id != b.item_def_id {
- Err(TypeError::ProjectionMismatched(expected_found(
- relation,
- a.item_def_id,
- b.item_def_id,
- )))
+ a: ty::AliasTy<'tcx>,
+ b: ty::AliasTy<'tcx>,
+ ) -> RelateResult<'tcx, ty::AliasTy<'tcx>> {
+ if a.def_id != b.def_id {
+ Err(TypeError::ProjectionMismatched(expected_found(relation, a.def_id, b.def_id)))
} else {
let substs = relation.relate(a.substs, b.substs)?;
- Ok(ty::ProjectionTy { item_def_id: a.item_def_id, substs: &substs })
+ Ok(relation.tcx().mk_alias_ty(a.def_id, substs))
}
}
}
a: ty::ExistentialProjection<'tcx>,
b: ty::ExistentialProjection<'tcx>,
) -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>> {
- if a.item_def_id != b.item_def_id {
- Err(TypeError::ProjectionMismatched(expected_found(
- relation,
- a.item_def_id,
- b.item_def_id,
- )))
+ if a.def_id != b.def_id {
+ Err(TypeError::ProjectionMismatched(expected_found(relation, a.def_id, b.def_id)))
} else {
let term = relation.relate_with_variance(
ty::Invariant,
a.substs,
b.substs,
)?;
- Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, term })
+ Ok(ty::ExistentialProjection { def_id: a.def_id, substs, term })
}
}
}
Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
} else {
let substs = relate_substs(relation, a.substs, b.substs)?;
- Ok(ty::TraitRef { def_id: a.def_id, substs })
+ Ok(relation.tcx().mk_trait_ref(a.def_id, substs))
}
}
}
}
}
-#[derive(Copy, Debug, Clone, TypeFoldable, TypeVisitable)]
+#[derive(PartialEq, Copy, Debug, Clone, TypeFoldable, TypeVisitable)]
struct GeneratorWitness<'tcx>(&'tcx ty::List<Ty<'tcx>>);
impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> {
}
// these two are already handled downstream in case of lazy normalization
- (&ty::Projection(a_data), &ty::Projection(b_data)) => {
+ (&ty::Alias(ty::Projection, a_data), &ty::Alias(ty::Projection, b_data)) => {
let projection_ty = relation.relate(a_data, b_data)?;
- Ok(tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs))
+ Ok(tcx.mk_projection(projection_ty.def_id, projection_ty.substs))
}
- (&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs))
- if a_def_id == b_def_id =>
- {
+ (
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs, .. }),
+ ) if a_def_id == b_def_id => {
if relation.intercrate() {
// During coherence, opaque types should be treated as equal to each other, even if their generic params
// differ, as they could resolve to the same hidden type, even for different generic params.
}
ty::GeneratorWitness(types) => ty::GeneratorWitness(types.try_fold_with(folder)?),
ty::Closure(did, substs) => ty::Closure(did, substs.try_fold_with(folder)?),
- ty::Projection(data) => ty::Projection(data.try_fold_with(folder)?),
- ty::Opaque(did, substs) => ty::Opaque(did, substs.try_fold_with(folder)?),
+ ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?),
ty::Bool
| ty::Char
ty::Generator(_did, ref substs, _) => substs.visit_with(visitor),
ty::GeneratorWitness(ref types) => types.visit_with(visitor),
ty::Closure(_did, ref substs) => substs.visit_with(visitor),
- ty::Projection(ref data) => data.visit_with(visitor),
- ty::Opaque(_, ref substs) => substs.visit_with(visitor),
+ ty::Alias(_, ref data) => data.visit_with(visitor),
ty::Bool
| ty::Char
/// * `GR`: The "return type", which is the type of value returned upon
/// completion of the generator.
/// * `GW`: The "generator witness".
-#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable, Lift)]
pub struct ClosureSubsts<'tcx> {
/// Lifetime and type parameters from the enclosing function,
/// concatenated with a tuple containing the types of the upvars.
}
/// Similar to `ClosureSubsts`; see the above documentation for more.
-#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable, Lift)]
pub struct GeneratorSubsts<'tcx> {
pub substs: SubstsRef<'tcx>,
}
match (*self, *other) {
(Trait(_), Trait(_)) => Ordering::Equal,
(Projection(ref a), Projection(ref b)) => {
- tcx.def_path_hash(a.item_def_id).cmp(&tcx.def_path_hash(b.item_def_id))
+ tcx.def_path_hash(a.def_id).cmp(&tcx.def_path_hash(b.def_id))
}
(AutoTrait(ref a), AutoTrait(ref b)) => {
tcx.def_path_hash(*a).cmp(&tcx.def_path_hash(*b))
pub struct TraitRef<'tcx> {
pub def_id: DefId,
pub substs: SubstsRef<'tcx>,
+ /// This field exists to prevent the creation of `TraitRef` without
+ /// calling [TyCtxt::mk_trait_ref].
+ pub(super) _use_mk_trait_ref_instead: (),
}
impl<'tcx> TraitRef<'tcx> {
- pub fn new(def_id: DefId, substs: SubstsRef<'tcx>) -> TraitRef<'tcx> {
- TraitRef { def_id, substs }
- }
-
- pub fn with_self_type(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
+ pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
tcx.mk_trait_ref(
self.def_id,
[self_ty.into()].into_iter().chain(self.substs.iter().skip(1)),
/// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`
/// are the parameters defined on trait.
pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> Binder<'tcx, TraitRef<'tcx>> {
- ty::Binder::dummy(TraitRef {
- def_id,
- substs: InternalSubsts::identity_for_item(tcx, def_id),
- })
+ ty::Binder::dummy(tcx.mk_trait_ref(def_id, InternalSubsts::identity_for_item(tcx, def_id)))
}
#[inline]
substs: SubstsRef<'tcx>,
) -> ty::TraitRef<'tcx> {
let defs = tcx.generics_of(trait_id);
- ty::TraitRef { def_id: trait_id, substs: tcx.intern_substs(&substs[..defs.params.len()]) }
+ tcx.mk_trait_ref(trait_id, tcx.intern_substs(&substs[..defs.params.len()]))
}
}
/// contain any bound vars that would be bound by the
/// binder. This is commonly used to 'inject' a value T into a
/// different binding level.
+ #[track_caller]
pub fn dummy(value: T) -> Binder<'tcx, T> {
- assert!(!value.has_escaping_bound_vars());
+ assert!(
+ !value.has_escaping_bound_vars(),
+ "`{value:?}` has escaping bound vars, so it cannot be wrapped in a dummy binder."
+ );
Binder(value, ty::List::empty())
}
}
}
-/// Represents the projection of an associated type. In explicit UFCS
-/// form this would be written `<T as Trait<..>>::N`.
+impl<'tcx, T: IntoIterator> Binder<'tcx, T> {
+ pub fn iter(self) -> impl Iterator<Item = ty::Binder<'tcx, T::Item>> {
+ let bound_vars = self.1;
+ self.0.into_iter().map(|v| Binder(v, bound_vars))
+ }
+}
+
+/// Represents the projection of an associated type.
+///
+/// For a projection, this would be `<Ty as Trait<...>>::N`.
+///
+/// For an opaque type, there is no explicit syntax.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct ProjectionTy<'tcx> {
- /// The parameters of the associated item.
+pub struct AliasTy<'tcx> {
+ /// The parameters of the associated or opaque item.
+ ///
+ /// For a projection, these are the substitutions for the trait and the
+ /// GAT substitutions, if there are any.
+ ///
+ /// For RPIT the substitutions are for the generics of the function,
+ /// while for TAIT it is used for the generic parameters of the alias.
pub substs: SubstsRef<'tcx>,
- /// The `DefId` of the `TraitItem` for the associated type `N`.
+ /// The `DefId` of the `TraitItem` for the associated type `N` if this is a projection,
+ /// or the `OpaqueType` item if this is an opaque.
///
- /// Note that this is not the `DefId` of the `TraitRef` containing this
- /// associated type, which is in `tcx.associated_item(item_def_id).container`,
- /// aka. `tcx.parent(item_def_id).unwrap()`.
- pub item_def_id: DefId,
+ /// During codegen, `tcx.type_of(def_id)` can be used to get the type of the
+ /// underlying type if the type is an opaque.
+ ///
+ /// Note that if this is an associated type, this is not the `DefId` of the
+ /// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`,
+ /// aka. `tcx.parent(def_id)`.
+ pub def_id: DefId,
+
+ /// This field exists to prevent the creation of `ProjectionTy` without using
+ /// [TyCtxt::mk_alias_ty].
+ pub(super) _use_mk_alias_ty_instead: (),
}
-impl<'tcx> ProjectionTy<'tcx> {
+impl<'tcx> AliasTy<'tcx> {
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
- match tcx.def_kind(self.item_def_id) {
- DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.item_def_id),
+ match tcx.def_kind(self.def_id) {
+ DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
DefKind::ImplTraitPlaceholder => {
- tcx.parent(tcx.impl_trait_in_trait_parent(self.item_def_id))
+ tcx.parent(tcx.impl_trait_in_trait_parent(self.def_id))
}
kind => bug!("unexpected DefKind in ProjectionTy: {kind:?}"),
}
&self,
tcx: TyCtxt<'tcx>,
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
- let def_id = tcx.parent(self.item_def_id);
- assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
- let trait_generics = tcx.generics_of(def_id);
+ debug_assert!(matches!(tcx.def_kind(self.def_id), DefKind::AssocTy | DefKind::AssocConst));
+ let trait_def_id = self.trait_def_id(tcx);
+ let trait_generics = tcx.generics_of(trait_def_id);
(
- ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },
+ tcx.mk_trait_ref(trait_def_id, self.substs.truncate_to(tcx, trait_generics)),
&self.substs[trait_generics.count()..],
)
}
/// as well.
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
let def_id = self.trait_def_id(tcx);
- ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) }
+ tcx.mk_trait_ref(def_id, self.substs.truncate_to(tcx, tcx.generics_of(def_id)))
}
pub fn self_ty(&self) -> Ty<'tcx> {
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
pub struct ExistentialProjection<'tcx> {
- pub item_def_id: DefId,
+ pub def_id: DefId,
pub substs: SubstsRef<'tcx>,
pub term: Term<'tcx>,
}
/// then this function would return an `exists T. T: Iterator` existential trait
/// reference.
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
- let def_id = tcx.parent(self.item_def_id);
+ let def_id = tcx.parent(self.def_id);
let subst_count = tcx.generics_of(def_id).count() - 1;
let substs = tcx.intern_substs(&self.substs[..subst_count]);
ty::ExistentialTraitRef { def_id, substs }
debug_assert!(!self_ty.has_escaping_bound_vars());
ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy {
- item_def_id: self.item_def_id,
- substs: tcx.mk_substs_trait(self_ty, self.substs),
- },
+ projection_ty: tcx
+ .mk_alias_ty(self.def_id, [self_ty.into()].into_iter().chain(self.substs)),
term: self.term,
}
}
projection_predicate.projection_ty.substs.type_at(0);
Self {
- item_def_id: projection_predicate.projection_ty.item_def_id,
+ def_id: projection_predicate.projection_ty.def_id,
substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
term: projection_predicate.term,
}
}
pub fn item_def_id(&self) -> DefId {
- self.skip_binder().item_def_id
+ self.skip_binder().def_id
}
}
#[inline]
pub fn is_impl_trait(self) -> bool {
- matches!(self.kind(), Opaque(..))
+ matches!(self.kind(), Alias(ty::Opaque, ..))
}
#[inline]
ty::Adt(adt, _) if adt.is_enum() => adt.repr().discr_type().to_ty(tcx),
ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx),
- ty::Param(_) | ty::Projection(_) | ty::Opaque(..) | ty::Infer(ty::TyVar(_)) => {
+ ty::Param(_) | ty::Alias(..) | ty::Infer(ty::TyVar(_)) => {
let assoc_items = tcx.associated_item_def_ids(
tcx.require_lang_item(hir::LangItem::DiscriminantKind, None),
);
// type parameters only have unit metadata if they're sized, so return true
// to make sure we double check this during confirmation
- ty::Param(_) | ty::Projection(_) | ty::Opaque(..) => (tcx.types.unit, true),
+ ty::Param(_) | ty::Alias(..) => (tcx.types.unit, true),
ty::Infer(ty::TyVar(_))
| ty::Bound(..)
ty::Adt(def, _substs) => def.sized_constraint(tcx).0.is_empty(),
- ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => false,
+ ty::Alias(..) | ty::Param(_) => false,
ty::Infer(ty::TyVar(_)) => false,
ty::Generator(..) | ty::GeneratorWitness(..) => false,
// Might be, but not "trivial" so just giving the safe answer.
- ty::Adt(..) | ty::Closure(..) | ty::Opaque(..) => false,
+ ty::Adt(..) | ty::Closure(..) => false,
+
+ // Needs normalization or revealing to determine, so no is the safe answer.
+ ty::Alias(..) => false,
- ty::Projection(..) | ty::Param(..) | ty::Infer(..) | ty::Error(..) => false,
+ ty::Param(..) | ty::Infer(..) | ty::Error(..) => false,
ty::Bound(..) | ty::Placeholder(..) => {
bug!("`is_trivially_pure_clone_copy` applied to unexpected type: {:?}", self);
}
}
-/// A substitution mapping generic parameters to new values.
+/// List of generic arguments that are gonna be used to substitute generic parameters.
pub type InternalSubsts<'tcx> = List<GenericArg<'tcx>>;
pub type SubstsRef<'tcx> = &'tcx InternalSubsts<'tcx>;
ty::Tuple(_) => break,
- ty::Projection(_) | ty::Opaque(..) => {
+ ty::Alias(..) => {
let normalized = normalize(ty);
if ty == normalized {
return ty;
break;
}
}
- (ty::Projection(_) | ty::Opaque(..), _)
- | (_, ty::Projection(_) | ty::Opaque(..)) => {
+ (ty::Alias(..), _) | (_, ty::Alias(..)) => {
// If either side is a projection, attempt to
// progress via normalization. (Should be safe to
// apply to both sides as normalization is
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if let ty::Opaque(def_id, substs) = *t.kind() {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *t.kind() {
self.expand_opaque_ty(def_id, substs).unwrap_or(t)
} else if t.has_opaque_types() {
t.super_fold_with(self)
| ty::Generator(..)
| ty::GeneratorWitness(_)
| ty::Infer(_)
- | ty::Opaque(..)
+ | ty::Alias(..)
| ty::Param(_)
- | ty::Placeholder(_)
- | ty::Projection(_) => false,
+ | ty::Placeholder(_) => false,
}
}
| ty::Generator(..)
| ty::GeneratorWitness(_)
| ty::Infer(_)
- | ty::Opaque(..)
+ | ty::Alias(..)
| ty::Param(_)
- | ty::Placeholder(_)
- | ty::Projection(_) => false,
+ | ty::Placeholder(_) => false,
}
}
//
// FIXME(ecstaticmorse): Maybe we should `bug` here? This should probably only be
// called for known, fully-monomorphized types.
- ty::Projection(_)
- | ty::Opaque(..)
- | ty::Param(_)
- | ty::Bound(..)
- | ty::Placeholder(_)
- | ty::Infer(_) => false,
+ ty::Alias(..) | ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) => {
+ false
+ }
ty::Foreign(_) | ty::GeneratorWitness(..) | ty::Error(_) => false,
}
// These require checking for `Copy` bounds or `Adt` destructors.
ty::Adt(..)
- | ty::Projection(..)
+ | ty::Alias(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Placeholder(..)
- | ty::Opaque(..)
| ty::Infer(_)
| ty::Closure(..)
| ty::Generator(..) => Ok(smallvec![ty]),
| ty::Never
| ty::Foreign(_) => true,
- ty::Opaque(..)
+ ty::Alias(..)
| ty::Dynamic(..)
| ty::Error(_)
| ty::Bound(..)
| ty::Param(_)
| ty::Placeholder(_)
- | ty::Projection(_)
| ty::Infer(_) => false,
// Not trivial because they have components, and instead of looking inside,
// ignore the inputs to a projection, as they may not appear
// in the normalized form
if self.just_constrained {
- if let ty::Projection(..) | ty::Opaque(..) = t.kind() {
+ if let ty::Alias(..) = t.kind() {
return ControlFlow::CONTINUE;
}
}
stack.push(ty.into());
stack.push(lt.into());
}
- ty::Projection(data) => {
+ ty::Alias(_, data) => {
stack.extend(data.substs.iter().rev());
}
ty::Dynamic(obj, lt, _) => {
}));
}
ty::Adt(_, substs)
- | ty::Opaque(_, substs)
| ty::Closure(_, substs)
| ty::Generator(_, substs, _)
| ty::FnDef(_, substs) => {
remainder_span,
pattern,
None,
- Some((None, initializer_span)),
+ Some((Some(&destination), initializer_span)),
);
this.visit_primary_bindings(
pattern,
// the case of `!`, no return value is required, as the block will never return.
// Opaque types of empty bodies also need this unit assignment, in order to infer that their
// type is actually unit. Otherwise there will be no defining use found in the MIR.
- if destination_ty.is_unit() || matches!(destination_ty.kind(), ty::Opaque(..)) {
+ if destination_ty.is_unit()
+ || matches!(destination_ty.kind(), ty::Alias(ty::Opaque, ..))
+ {
// We only want to assign an implicit `()` as the return value of the block if the
// block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
use rustc_ast::Attribute;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
+use rustc_hir::HirId;
use rustc_index::vec::IndexVec;
use rustc_middle::{
mir::*,
pub(super) fn build_custom_mir<'tcx>(
tcx: TyCtxt<'tcx>,
did: DefId,
+ hir_id: HirId,
thir: &Thir<'tcx>,
expr: ExprId,
params: &IndexVec<ParamId, Param<'tcx>>,
parent_scope: None,
inlined: None,
inlined_parent_scope: None,
- local_data: ClearCrossCrate::Clear,
+ local_data: ClearCrossCrate::Set(SourceScopeLocalData {
+ lint_root: hir_id,
+ safety: Safety::Safe,
+ }),
});
body.injection_phase = Some(parse_attribute(attr));
let exchange_malloc = Operand::function_handle(
tcx,
tcx.require_lang_item(LangItem::ExchangeMalloc, Some(expr_span)),
- ty::List::empty(),
+ [],
expr_span,
);
let storage = this.temp(tcx.mk_mut_ptr(tcx.types.u8), expr_span);
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Builds a block of MIR statements to evaluate the THIR `expr`.
- /// If the original expression was an AST statement,
- /// (e.g., `some().code(&here());`) then `opt_stmt_span` is the
- /// span of that statement (including its semicolon, if any).
- /// The scope is used if a statement temporary must be dropped.
+ ///
+ /// The `statement_scope` is used if a statement temporary must be dropped.
pub(crate) fn stmt_expr(
&mut self,
mut block: BasicBlock,
method_name: Symbol,
substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
) -> ConstantKind<'tcx> {
- let substs = tcx.mk_substs(substs.into_iter().map(Into::into));
-
// The unhygienic comparison here is acceptable because this is only
// used on known traits.
let item = tcx
return custom::build_custom_mir(
tcx,
fn_def.did.to_def_id(),
+ fn_id,
thir,
expr,
arguments,
fn unsafe_op_in_unsafe_fn_allowed(&self) -> bool {
self.tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, self.hir_context).0 == Level::Allow
}
+
+ /// Handle closures/generators/inline-consts, which is unsafecked with their parent body.
+ fn visit_inner_body(&mut self, def: ty::WithOptConstParam<LocalDefId>) {
+ if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
+ let inner_thir = &inner_thir.borrow();
+ let hir_context = self.tcx.hir().local_def_id_to_hir_id(def.did);
+ let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, hir_context, ..*self };
+ inner_visitor.visit_expr(&inner_thir[expr]);
+ // Unsafe blocks can be used in the inner body, make sure to take it into account
+ self.safety_context = inner_visitor.safety_context;
+ }
+ }
}
// Searches for accesses to layout constrained fields.
} else {
ty::WithOptConstParam::unknown(closure_id)
};
- let (closure_thir, expr) = self.tcx.thir_body(closure_def).unwrap_or_else(|_| {
- (self.tcx.alloc_steal_thir(Thir::new()), ExprId::from_u32(0))
- });
- let closure_thir = &closure_thir.borrow();
- let hir_context = self.tcx.hir().local_def_id_to_hir_id(closure_id);
- let mut closure_visitor =
- UnsafetyVisitor { thir: closure_thir, hir_context, ..*self };
- closure_visitor.visit_expr(&closure_thir[expr]);
- // Unsafe blocks can be used in closures, make sure to take it into account
- self.safety_context = closure_visitor.safety_context;
+ self.visit_inner_body(closure_def);
+ }
+ ExprKind::ConstBlock { did, substs: _ } => {
+ let def_id = did.expect_local();
+ self.visit_inner_body(ty::WithOptConstParam::unknown(def_id));
}
ExprKind::Field { lhs, .. } => {
let lhs = &self.thir[lhs];
return;
}
- // Closures are handled by their owner, if it has a body
- if tcx.is_closure(def.did.to_def_id()) {
- let hir = tcx.hir();
- let owner = hir.enclosing_body_owner(hir.local_def_id_to_hir_id(def.did));
- tcx.ensure().thir_check_unsafety(owner);
+ // Closures and inline consts are handled by their owner, if it has a body
+ if tcx.is_typeck_child(def.did.to_def_id()) {
return;
}
ty::Dynamic(..) => {
"trait objects cannot be used in patterns".to_string()
}
- ty::Opaque(..) => {
+ ty::Alias(ty::Opaque, ..) => {
"opaque types cannot be used in patterns".to_string()
}
ty::Closure(..) => {
// Opaque types can't get destructured/split, but the patterns can
// actually hint at hidden types, so we use the patterns' types instead.
- if let ty::Opaque(..) = ty.kind() {
+ if let ty::Alias(ty::Opaque, ..) = ty.kind() {
if let Some(row) = rows.first() {
ty = row.head().ty();
}
None
}
-/// When enumerating the child fragments of a path, don't recurse into
-/// paths (1.) past arrays, slices, and pointers, nor (2.) into a type
-/// that implements `Drop`.
-///
-/// Places behind references or arrays are not tracked by elaboration
-/// and are always assumed to be initialized when accessible. As
-/// references and indexes can be reseated, trying to track them can
-/// only lead to trouble.
-///
-/// Places behind ADT's with a Drop impl are not tracked by
-/// elaboration since they can never have a drop-flag state that
-/// differs from that of the parent with the Drop impl.
-///
-/// In both cases, the contents can only be accessed if and only if
-/// their parents are initialized. This implies for example that there
-/// is no need to maintain separate drop flags to track such state.
-//
-// FIXME: we have to do something for moving slice patterns.
-fn place_contents_drop_state_cannot_differ<'tcx>(
- tcx: TyCtxt<'tcx>,
- body: &Body<'tcx>,
- place: mir::Place<'tcx>,
-) -> bool {
- let ty = place.ty(body, tcx).ty;
- match ty.kind() {
- ty::Array(..) => {
- debug!(
- "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false",
- place, ty
- );
- false
- }
- ty::Slice(..) | ty::Ref(..) | ty::RawPtr(..) => {
- debug!(
- "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true",
- place, ty
- );
- true
- }
- ty::Adt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => {
- debug!(
- "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} Drop => true",
- place, ty
- );
- true
- }
- _ => false,
- }
-}
-
pub fn on_lookup_result_bits<'tcx, F>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
) where
F: FnMut(MovePathIndex),
{
+ #[inline]
fn is_terminal_path<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
move_data: &MoveData<'tcx>,
path: MovePathIndex,
) -> bool {
- place_contents_drop_state_cannot_differ(tcx, body, move_data.move_paths[path].place)
+ let place = move_data.move_paths[path].place;
+
+ // When enumerating the child fragments of a path, don't recurse into
+ // paths (1.) past arrays, slices, and pointers, nor (2.) into a type
+ // that implements `Drop`.
+ //
+ // Places behind references or arrays are not tracked by elaboration
+ // and are always assumed to be initialized when accessible. As
+ // references and indexes can be reseated, trying to track them can
+ // only lead to trouble.
+ //
+ // Places behind ADT's with a Drop impl are not tracked by
+ // elaboration since they can never have a drop-flag state that
+ // differs from that of the parent with the Drop impl.
+ //
+ // In both cases, the contents can only be accessed if and only if
+ // their parents are initialized. This implies for example that there
+ // is no need to maintain separate drop flags to track such state.
+ //
+ // FIXME: we have to do something for moving slice patterns.
+ let ty = place.ty(body, tcx).ty;
+ match ty.kind() {
+ ty::Adt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => {
+ debug!(
+ "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} Drop => true",
+ place, ty
+ );
+ true
+ }
+ ty::Array(..) => {
+ debug!(
+ "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false",
+ place, ty
+ );
+ false
+ }
+ ty::Slice(..) | ty::Ref(..) | ty::RawPtr(..) => {
+ debug!(
+ "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true",
+ place, ty
+ );
+ true
+ }
+ _ => false,
+ }
}
fn on_all_children_bits<'tcx, F>(
let drop_trait = tcx.require_lang_item(LangItem::Drop, None);
let drop_fn = tcx.associated_item_def_ids(drop_trait)[0];
let ty = self.place_ty(self.place);
- let substs = tcx.mk_substs_trait(ty, []);
let ref_ty =
tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut });
)],
terminator: Some(Terminator {
kind: TerminatorKind::Call {
- func: Operand::function_handle(tcx, drop_fn, substs, self.source_info.span),
+ func: Operand::function_handle(
+ tcx,
+ drop_fn,
+ [ty.into()],
+ self.source_info.span,
+ ),
args: vec![Operand::Move(Place::from(ref_place))],
destination: unit_temp,
target: Some(succ),
use crate::{CallReturnPlaces, GenKill, Results, ResultsRefCursor};
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
+use std::borrow::Cow;
use std::cell::RefCell;
#[derive(Clone)]
-pub struct MaybeStorageLive {
- always_live_locals: BitSet<Local>,
+pub struct MaybeStorageLive<'a> {
+ always_live_locals: Cow<'a, BitSet<Local>>,
}
-impl MaybeStorageLive {
- pub fn new(always_live_locals: BitSet<Local>) -> Self {
+impl<'a> MaybeStorageLive<'a> {
+ pub fn new(always_live_locals: Cow<'a, BitSet<Local>>) -> Self {
MaybeStorageLive { always_live_locals }
}
}
-impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageLive {
+impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> {
type Domain = BitSet<Local>;
const NAME: &'static str = "maybe_storage_live";
}
}
-impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageLive {
+impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
type Idx = Local;
fn statement_effect(
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::hir_id::HirId;
use rustc_hir::intravisit;
self.super_rvalue(rvalue, location);
}
+ fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
+ if let Operand::Constant(constant) = op {
+ let maybe_uneval = match constant.literal {
+ ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
+ ConstantKind::Unevaluated(uv, _) => Some(uv),
+ };
+
+ if let Some(uv) = maybe_uneval {
+ if uv.promoted.is_none() {
+ let def_id = uv.def.def_id_for_type_of();
+ if self.tcx.def_kind(def_id) == DefKind::InlineConst {
+ let local_def_id = def_id.expect_local();
+ let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
+ self.tcx.unsafety_check_result(local_def_id);
+ self.register_violations(violations, used_unsafe_blocks.iter().copied());
+ }
+ }
+ }
+ }
+ self.super_operand(op, location);
+ }
+
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
// On types with `scalar_valid_range`, prevent
// * `&mut x.field`
intravisit::walk_block(self, block);
}
+ fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
+ if matches!(self.tcx.def_kind(c.def_id), DefKind::InlineConst) {
+ self.visit_body(self.tcx.hir().body(c.body))
+ }
+ }
+
fn visit_fn(
&mut self,
fk: intravisit::FnKind<'tcx>,
let mut checker = UnsafetyChecker::new(body, def.did, tcx, param_env);
checker.visit_body(&body);
- let unused_unsafes = (!tcx.is_closure(def.did.to_def_id()))
+ let unused_unsafes = (!tcx.is_typeck_child(def.did.to_def_id()))
.then(|| check_unused_unsafe(tcx, def.did, &checker.used_unsafe_blocks));
tcx.arena.alloc(UnsafetyCheckResult {
pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
debug!("check_unsafety({:?})", def_id);
- // closures are handled by their parent fn.
- if tcx.is_closure(def_id.to_def_id()) {
+ // closures and inline consts are handled by their parent fn.
+ if tcx.is_typeck_child(def_id.to_def_id()) {
return;
}
use either::Right;
use rustc_ast::Mutability;
+use rustc_const_eval::const_eval::CheckAlignment;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::DefKind;
use rustc_index::bit_set::BitSet;
use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable};
use rustc_span::{def_id::DefId, Span};
-use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout};
+use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout};
use rustc_target::spec::abi::Abi as CallAbi;
use rustc_trait_selection::traits;
type MemoryKind = !;
#[inline(always)]
- fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+ fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
// We do not check for alignment to avoid having to carry an `Align`
// in `ConstValue::ByRef`.
- false
+ CheckAlignment::No
}
#[inline(always)]
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
false // for now, we don't enforce validity
}
+ fn alignment_check_failed(
+ ecx: &InterpCx<'mir, 'tcx, Self>,
+ _has: Align,
+ _required: Align,
+ _check: CheckAlignment,
+ ) -> InterpResult<'tcx, ()> {
+ span_bug!(
+ ecx.cur_span(),
+ "`alignment_check_failed` called when no alignment check requested"
+ )
+ }
fn load_mir(
_ecx: &InterpCx<'mir, 'tcx, Self>,
//!
//! Currently, this pass only propagates scalar values.
+use rustc_const_eval::const_eval::CheckAlignment;
use rustc_const_eval::interpret::{ConstValue, ImmTy, Immediate, InterpCx, Scalar};
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::mir::visit::{MutVisitor, Visitor};
use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace};
use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects};
use rustc_span::DUMMY_SP;
+use rustc_target::abi::Align;
use crate::MirPass;
type MemoryKind = !;
const PANIC_ON_ALLOC_FAIL: bool = true;
- fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+ fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
unimplemented!()
}
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
unimplemented!()
}
+ fn alignment_check_failed(
+ _ecx: &InterpCx<'mir, 'tcx, Self>,
+ _has: Align,
+ _required: Align,
+ _check: CheckAlignment,
+ ) -> interpret::InterpResult<'tcx, ()> {
+ unimplemented!()
+ }
fn find_mir_or_eval_fn(
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
use crate::MirPass;
use rustc_data_structures::fx::FxHashMap;
use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
use rustc_middle::mir::{dump_mir, PassWhere};
use rustc_middle::mir::{
traversal, BasicBlock, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place,
Rvalue, Statement, StatementKind, TerminatorKind,
};
-use rustc_middle::mir::{
- visit::{MutVisitor, PlaceContext, Visitor},
- ProjectionElem,
-};
use rustc_middle::ty::TyCtxt;
use rustc_mir_dataflow::impls::MaybeLiveLocals;
use rustc_mir_dataflow::{Analysis, ResultsCursor};
// through these methods, and not directly.
impl<'alloc> Candidates<'alloc> {
/// Just `Vec::retain`, but the condition is inverted and we add debugging output
- fn vec_remove_debug(
+ fn vec_filter_candidates(
src: Local,
v: &mut Vec<Local>,
- mut f: impl FnMut(Local) -> bool,
+ mut f: impl FnMut(Local) -> CandidateFilter,
at: Location,
) {
v.retain(|dest| {
let remove = f(*dest);
- if remove {
+ if remove == CandidateFilter::Remove {
trace!("eliminating {:?} => {:?} due to conflict at {:?}", src, dest, at);
}
- !remove
+ remove == CandidateFilter::Keep
});
}
- /// `vec_remove_debug` but for an `Entry`
- fn entry_remove(
+ /// `vec_filter_candidates` but for an `Entry`
+ fn entry_filter_candidates(
mut entry: OccupiedEntry<'_, Local, Vec<Local>>,
p: Local,
- f: impl FnMut(Local) -> bool,
+ f: impl FnMut(Local) -> CandidateFilter,
at: Location,
) {
let candidates = entry.get_mut();
- Self::vec_remove_debug(p, candidates, f, at);
+ Self::vec_filter_candidates(p, candidates, f, at);
if candidates.len() == 0 {
entry.remove();
}
}
- /// Removes all candidates `(p, q)` or `(q, p)` where `p` is the indicated local and `f(q)` is true.
- fn remove_candidates_if(&mut self, p: Local, mut f: impl FnMut(Local) -> bool, at: Location) {
+ /// For all candidates `(p, q)` or `(q, p)` removes the candidate if `f(q)` says to do so
+ fn filter_candidates_by(
+ &mut self,
+ p: Local,
+ mut f: impl FnMut(Local) -> CandidateFilter,
+ at: Location,
+ ) {
// Cover the cases where `p` appears as a `src`
if let Entry::Occupied(entry) = self.c.entry(p) {
- Self::entry_remove(entry, p, &mut f, at);
+ Self::entry_filter_candidates(entry, p, &mut f, at);
}
// And the cases where `p` appears as a `dest`
let Some(srcs) = self.reverse.get_mut(&p) else {
// We use `retain` here to remove the elements from the reverse set if we've removed the
// matching candidate in the forward set.
srcs.retain(|src| {
- if !f(*src) {
+ if f(*src) == CandidateFilter::Keep {
return true;
}
let Entry::Occupied(entry) = self.c.entry(*src) else {
return false;
};
- Self::entry_remove(entry, *src, |dest| dest == p, at);
+ Self::entry_filter_candidates(
+ entry,
+ *src,
+ |dest| {
+ if dest == p { CandidateFilter::Remove } else { CandidateFilter::Keep }
+ },
+ at,
+ );
false
});
}
}
+#[derive(Copy, Clone, PartialEq, Eq)]
+enum CandidateFilter {
+ Keep,
+ Remove,
+}
+
impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
/// Filters the set of candidates to remove those that conflict.
///
for (i, statement) in data.statements.iter().enumerate().rev() {
self.at = Location { block, statement_index: i };
self.live.seek_after_primary_effect(self.at);
- self.get_statement_write_info(&statement.kind);
+ self.write_info.for_statement(&statement.kind, self.body);
self.apply_conflicts();
}
}
fn apply_conflicts(&mut self) {
let writes = &self.write_info.writes;
for p in writes {
- self.candidates.remove_candidates_if(
+ let other_skip = self.write_info.skip_pair.and_then(|(a, b)| {
+ if a == *p {
+ Some(b)
+ } else if b == *p {
+ Some(a)
+ } else {
+ None
+ }
+ });
+ self.candidates.filter_candidates_by(
*p,
- // It is possible that a local may be live for less than the
- // duration of a statement This happens in the case of function
- // calls or inline asm. Because of this, we also mark locals as
- // conflicting when both of them are written to in the same
- // statement.
- |q| self.live.contains(q) || writes.contains(&q),
+ |q| {
+ if Some(q) == other_skip {
+ return CandidateFilter::Keep;
+ }
+ // It is possible that a local may be live for less than the
+ // duration of a statement This happens in the case of function
+ // calls or inline asm. Because of this, we also mark locals as
+ // conflicting when both of them are written to in the same
+ // statement.
+ if self.live.contains(q) || writes.contains(&q) {
+ CandidateFilter::Remove
+ } else {
+ CandidateFilter::Keep
+ }
+ },
self.at,
);
}
}
-
- /// Gets the write info for the `statement`.
- fn get_statement_write_info(&mut self, statement: &StatementKind<'tcx>) {
- self.write_info.writes.clear();
- match statement {
- StatementKind::Assign(box (lhs, rhs)) => match rhs {
- Rvalue::Use(op) => {
- if !lhs.is_indirect() {
- self.get_assign_use_write_info(*lhs, op);
- return;
- }
- }
- _ => (),
- },
- _ => (),
- }
-
- self.write_info.for_statement(statement);
- }
-
- fn get_assign_use_write_info(&mut self, lhs: Place<'tcx>, rhs: &Operand<'tcx>) {
- // We register the writes for the operand unconditionally
- self.write_info.add_operand(rhs);
- // However, we cannot do the same thing for the `lhs` as that would always block the
- // optimization. Instead, we consider removing candidates manually.
- let Some(rhs) = rhs.place() else {
- self.write_info.add_place(lhs);
- return;
- };
- // Find out which candidate pair we should skip, if any
- let Some((src, dest)) = places_to_candidate_pair(lhs, rhs, self.body) else {
- self.write_info.add_place(lhs);
- return;
- };
- self.candidates.remove_candidates_if(
- lhs.local,
- |other| {
- // Check if this is the candidate pair that should not be removed
- if (lhs.local == src && other == dest) || (lhs.local == dest && other == src) {
- return false;
- }
- // Otherwise, do the "standard" thing
- self.live.contains(other)
- },
- self.at,
- )
- }
}
/// Describes where a statement/terminator writes to
#[derive(Default, Debug)]
struct WriteInfo {
writes: Vec<Local>,
+ /// If this pair of locals is a candidate pair, completely skip processing it during this
+ /// statement. All other candidates are unaffected.
+ skip_pair: Option<(Local, Local)>,
}
impl WriteInfo {
- fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>) {
+ fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>, body: &Body<'tcx>) {
+ self.reset();
match statement {
StatementKind::Assign(box (lhs, rhs)) => {
self.add_place(*lhs);
match rhs {
- Rvalue::Use(op) | Rvalue::Repeat(op, _) => {
+ Rvalue::Use(op) => {
+ self.add_operand(op);
+ self.consider_skipping_for_assign_use(*lhs, op, body);
+ }
+ Rvalue::Repeat(op, _) => {
self.add_operand(op);
}
Rvalue::Cast(_, op, _)
}
}
+ fn consider_skipping_for_assign_use<'tcx>(
+ &mut self,
+ lhs: Place<'tcx>,
+ rhs: &Operand<'tcx>,
+ body: &Body<'tcx>,
+ ) {
+ let Some(rhs) = rhs.place() else {
+ return
+ };
+ if let Some(pair) = places_to_candidate_pair(lhs, rhs, body) {
+ self.skip_pair = Some(pair);
+ }
+ }
+
fn for_terminator<'tcx>(&mut self, terminator: &TerminatorKind<'tcx>) {
- self.writes.clear();
+ self.reset();
match terminator {
TerminatorKind::SwitchInt { discr: op, .. }
| TerminatorKind::Assert { cond: op, .. } => {
Operand::Copy(_) | Operand::Constant(_) => (),
}
}
+
+ fn reset(&mut self) {
+ self.writes.clear();
+ self.skip_pair = None;
+ }
}
/////////////////////////////////////////////////////
// Candidate accumulation
-fn is_constant<'tcx>(place: Place<'tcx>) -> bool {
- place.projection.iter().all(|p| !matches!(p, ProjectionElem::Deref | ProjectionElem::Index(_)))
-}
-
/// If the pair of places is being considered for merging, returns the candidate which would be
/// merged in order to accomplish this.
///
Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
)) = &statement.kind
{
- if !is_constant(*lhs) || !is_constant(*rhs) {
- return;
- }
-
let Some((src, dest)) = places_to_candidate_pair(*lhs, *rhs, self.body) else {
return;
};
// Calculate when MIR locals have live storage. This gives us an upper bound of their
// lifetimes.
- let mut storage_live = MaybeStorageLive::new(always_live_locals.clone())
+ let mut storage_live = MaybeStorageLive::new(std::borrow::Cow::Borrowed(always_live_locals))
.into_engine(tcx, body_ref)
.iterate_to_fixpoint()
.into_results_cursor(body_ref);
};
let kind = match parent_ty.ty.kind() {
- &ty::Opaque(def_id, substs) => {
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
self.tcx.bound_type_of(def_id).subst(self.tcx, substs).kind()
}
kind => kind,
fn maybe_zst(ty: Ty<'_>) -> bool {
match ty.kind() {
// maybe ZST (could be more precise)
- ty::Adt(..) | ty::Array(..) | ty::Closure(..) | ty::Tuple(..) | ty::Opaque(..) => true,
+ ty::Adt(..)
+ | ty::Array(..)
+ | ty::Closure(..)
+ | ty::Tuple(..)
+ | ty::Alias(ty::Opaque, ..) => true,
// definitely ZST
ty::FnDef(..) | ty::Never => true,
// unreachable or can't be ZST
// we must subst the self_ty because it's
// otherwise going to be TySelf and we can't index
// or access fields of a Place of type TySelf.
- let substs = tcx.mk_substs_trait(self_ty, []);
- let sig = tcx.bound_fn_sig(def_id).subst(tcx, substs);
+ let sig = tcx.bound_fn_sig(def_id).subst(tcx, &[self_ty.into()]);
let sig = tcx.erase_late_bound_regions(sig);
let span = tcx.def_span(def_id);
) {
let tcx = self.tcx;
- let substs = tcx.mk_substs_trait(ty, []);
-
// `func == Clone::clone(&ty) -> ty`
- let func_ty = tcx.mk_fn_def(self.def_id, substs);
+ let func_ty = tcx.mk_fn_def(self.def_id, [ty]);
let func = Operand::Constant(Box::new(Constant {
span: self.span,
user_ty: None,
// Create substitutions for the `Self` and `Args` generic parameters of the shim body.
let arg_tup = tcx.mk_tup(untuple_args.iter());
- let sig_substs = tcx.mk_substs_trait(ty, [ty::subst::GenericArg::from(arg_tup)]);
- (Some(sig_substs), Some(untuple_args))
+ (Some([ty.into(), arg_tup.into()]), Some(untuple_args))
} else {
(None, None)
};
assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body());
let mut sig =
- if let Some(sig_substs) = sig_substs { sig.subst(tcx, sig_substs) } else { sig.0 };
+ if let Some(sig_substs) = sig_substs { sig.subst(tcx, &sig_substs) } else { sig.0 };
if let CallKind::Indirect(fnty) = call_kind {
// `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
pub span: Option<Span>,
pub symbol: String,
}
+
+#[derive(Diagnostic)]
+#[diag(monomorphize_couldnt_dump_mono_stats)]
+pub struct CouldntDumpMonoStats {
+ pub error: String,
+}
mod default;
mod merging;
+use std::cmp;
+use std::fs::{self, File};
+use std::io::{BufWriter, Write};
+use std::path::{Path, PathBuf};
+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync;
use rustc_hir::def_id::DefIdSet;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
+use rustc_session::config::SwitchWithOptPath;
use rustc_span::symbol::Symbol;
use crate::collector::InliningMap;
use crate::collector::{self, MonoItemCollectionMode};
-use crate::errors::{SymbolAlreadyDefined, UnknownPartitionStrategy};
+use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownPartitionStrategy};
pub struct PartitioningCx<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
})
.collect();
+ // Output monomorphization stats per def_id
+ if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats {
+ if let Err(err) =
+ dump_mono_items_stats(tcx, &codegen_units, path, tcx.sess.opts.crate_name.as_deref())
+ {
+ tcx.sess.emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
+ }
+ }
+
if tcx.sess.opts.unstable_opts.print_mono_items.is_some() {
let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default();
(tcx.arena.alloc(mono_items), codegen_units)
}
+/// Outputs stats about instantation counts and estimated size, per `MonoItem`'s
+/// def, to a file in the given output directory.
+fn dump_mono_items_stats<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ codegen_units: &[CodegenUnit<'tcx>],
+ output_directory: &Option<PathBuf>,
+ crate_name: Option<&str>,
+) -> Result<(), Box<dyn std::error::Error>> {
+ let output_directory = if let Some(ref directory) = output_directory {
+ fs::create_dir_all(directory)?;
+ directory
+ } else {
+ Path::new(".")
+ };
+
+ let filename = format!("{}.mono_items.md", crate_name.unwrap_or("unknown-crate"));
+ let output_path = output_directory.join(&filename);
+ let file = File::create(output_path)?;
+ let mut file = BufWriter::new(file);
+
+ // Gather instantiated mono items grouped by def_id
+ let mut items_per_def_id: FxHashMap<_, Vec<_>> = Default::default();
+ for cgu in codegen_units {
+ for (&mono_item, _) in cgu.items() {
+ // Avoid variable-sized compiler-generated shims
+ if mono_item.is_user_defined() {
+ items_per_def_id.entry(mono_item.def_id()).or_default().push(mono_item);
+ }
+ }
+ }
+
+ // Output stats sorted by total instantiated size, from heaviest to lightest
+ let mut stats: Vec<_> = items_per_def_id
+ .into_iter()
+ .map(|(def_id, items)| {
+ let instantiation_count = items.len();
+ let size_estimate = items[0].size_estimate(tcx);
+ let total_estimate = instantiation_count * size_estimate;
+ (def_id, instantiation_count, size_estimate, total_estimate)
+ })
+ .collect();
+ stats.sort_unstable_by_key(|(_, _, _, total_estimate)| cmp::Reverse(*total_estimate));
+
+ if !stats.is_empty() {
+ writeln!(
+ file,
+ "| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
+ )?;
+ writeln!(file, "| --- | ---: | ---: | ---: |")?;
+ for (def_id, instantiation_count, size_estimate, total_estimate) in stats {
+ let item = with_no_trimmed_paths!(tcx.def_path_str(def_id));
+ writeln!(
+ file,
+ "| {item} | {instantiation_count} | {size_estimate} | {total_estimate} |"
+ )?;
+ }
+ }
+
+ Ok(())
+}
+
fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx DefIdSet {
let (items, cgus) = tcx.collect_and_partition_mono_items(());
let mut visited = DefIdSet::default();
#[suggestion(applicability = "machine-applicable", code = " ", style = "verbose")]
pub Span,
);
+
+#[derive(Diagnostic)]
+#[diag(parse_maybe_fn_typo_with_impl)]
+pub(crate) struct FnTypoWithImpl {
+ #[primary_span]
+ #[suggestion(applicability = "maybe-incorrect", code = "impl", style = "verbose")]
+ pub fn_span: Span,
+}
Standalone,
/// It's a subexpression, i.e., *not* standalone.
Subexpr,
- /// It's maybe standalone; we're not sure.
- Maybe,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
err.multipart_suggestion(&self.msg, self.patches, self.applicability);
}
- /// Overrides individual messages and applicabilities.
- fn emit_many(
- err: &mut Diagnostic,
- msg: &str,
- applicability: Applicability,
- suggestions: impl Iterator<Item = Self>,
- ) {
- err.multipart_suggestions(msg, suggestions.map(|s| s.patches), applicability);
+ fn emit_verbose(self, err: &mut Diagnostic) {
+ err.multipart_suggestion_verbose(&self.msg, self.patches, self.applicability);
}
}
&mut self,
operand_expr: P<Expr>,
op_span: Span,
- prev_is_semi: bool,
+ start_stmt: bool,
) -> PResult<'a, P<Expr>> {
- let standalone =
- if prev_is_semi { IsStandalone::Standalone } else { IsStandalone::Subexpr };
+ let standalone = if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr };
let kind = IncDecRecovery { standalone, op: IncOrDec::Inc, fixity: UnaryFixity::Pre };
-
self.recover_from_inc_dec(operand_expr, kind, op_span)
}
&mut self,
operand_expr: P<Expr>,
op_span: Span,
+ start_stmt: bool,
) -> PResult<'a, P<Expr>> {
let kind = IncDecRecovery {
- standalone: IsStandalone::Maybe,
+ standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr },
op: IncOrDec::Inc,
fixity: UnaryFixity::Post,
};
-
self.recover_from_inc_dec(operand_expr, kind, op_span)
}
};
match kind.standalone {
- IsStandalone::Standalone => self.inc_dec_standalone_suggest(kind, spans).emit(&mut err),
+ IsStandalone::Standalone => {
+ self.inc_dec_standalone_suggest(kind, spans).emit_verbose(&mut err)
+ }
IsStandalone::Subexpr => {
let Ok(base_src) = self.span_to_snippet(base.span)
- else { return help_base_case(err, base) };
+ else { return help_base_case(err, base) };
match kind.fixity {
UnaryFixity::Pre => {
self.prefix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
}
UnaryFixity::Post => {
- self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
+ // won't suggest since we can not handle the precedences
+ // for example: `a + b++` has been parsed (a + b)++ and we can not suggest here
+ if !matches!(base.kind, ExprKind::Binary(_, _, _)) {
+ self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
+ }
}
}
}
- IsStandalone::Maybe => {
- let Ok(base_src) = self.span_to_snippet(base.span)
- else { return help_base_case(err, base) };
- let sugg1 = match kind.fixity {
- UnaryFixity::Pre => self.prefix_inc_dec_suggest(base_src, kind, spans),
- UnaryFixity::Post => self.postfix_inc_dec_suggest(base_src, kind, spans),
- };
- let sugg2 = self.inc_dec_standalone_suggest(kind, spans);
- MultiSugg::emit_many(
- &mut err,
- "use `+= 1` instead",
- Applicability::Unspecified,
- [sugg1, sugg2].into_iter(),
- )
- }
}
Err(err)
}
}
patches.push((post_span, format!(" {}= 1", kind.op.chr())));
-
MultiSugg {
msg: format!("use `{}= 1` instead", kind.op.chr()),
patches,
pub(super) enum LhsExpr {
NotYetParsed,
AttributesParsed(AttrWrapper),
- AlreadyParsed(P<Expr>),
+ AlreadyParsed(P<Expr>, bool), // (expr, starts_statement)
}
impl From<Option<AttrWrapper>> for LhsExpr {
///
/// This conversion does not allocate.
fn from(expr: P<Expr>) -> Self {
- LhsExpr::AlreadyParsed(expr)
+ LhsExpr::AlreadyParsed(expr, false)
}
}
min_prec: usize,
lhs: LhsExpr,
) -> PResult<'a, P<Expr>> {
- let mut lhs = if let LhsExpr::AlreadyParsed(expr) = lhs {
+ let mut starts_stmt = false;
+ let mut lhs = if let LhsExpr::AlreadyParsed(expr, starts_statement) = lhs {
+ starts_stmt = starts_statement;
expr
} else {
let attrs = match lhs {
let op_span = self.prev_token.span.to(self.token.span);
// Eat the second `+`
self.bump();
- lhs = self.recover_from_postfix_increment(lhs, op_span)?;
+ lhs = self.recover_from_postfix_increment(lhs, op_span, starts_stmt)?;
continue;
}
token::BinOp(token::Plus)
if this.look_ahead(1, |t| *t == token::BinOp(token::Plus)) =>
{
- let prev_is_semi = this.prev_token == token::Semi;
+ let starts_stmt = this.prev_token == token::Semi
+ || this.prev_token == token::CloseDelim(Delimiter::Brace);
let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span));
// Eat both `+`s.
this.bump();
this.bump();
let operand_expr = this.parse_dot_or_call_expr(Default::default())?;
- this.recover_from_prefix_increment(operand_expr, pre_span, prev_is_semi)
+ this.recover_from_prefix_increment(operand_expr, pre_span, starts_stmt)
}
token::Ident(..) if this.token.is_keyword(kw::Box) => {
make_it!(this, attrs, |this, _| this.parse_box_expr(lo))
use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
+use crate::errors::FnTypoWithImpl;
use rustc_ast::ast::*;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, TokenKind};
vis: &Visibility,
case: Case,
) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
+ let fn_span = self.token.span;
let header = self.parse_fn_front_matter(vis, case)?; // `const ... fn`
let ident = self.parse_ident()?; // `foo`
let mut generics = self.parse_generics()?; // `<'a, T, ...>`
- let decl =
- self.parse_fn_decl(fn_parse_mode.req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)`
+ let decl = match self.parse_fn_decl(
+ fn_parse_mode.req_name,
+ AllowPlus::Yes,
+ RecoverReturnSign::Yes,
+ ) {
+ Ok(decl) => decl,
+ Err(old_err) => {
+ // If we see `for Ty ...` then user probably meant `impl` item.
+ if self.token.is_keyword(kw::For) {
+ old_err.cancel();
+ return Err(self.sess.create_err(FnTypoWithImpl { fn_span }));
+ } else {
+ return Err(old_err);
+ }
+ }
+ };
generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
let mut sig_hi = self.prev_token.span;
// Perform this outside of the `collect_tokens_trailing_token` closure,
// since our outer attributes do not apply to this part of the expression
let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
- this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
+ this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr, true))
})?;
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
} else {
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
let e = self.maybe_recover_from_bad_qpath(e)?;
let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
- let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
+ let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e, false))?;
StmtKind::Expr(e)
};
Ok(self.mk_stmt(lo.to(hi), kind))
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<Self::BreakTy> {
self.skeleton().visit_trait(trait_ref)
}
- fn visit_projection_ty(
- &mut self,
- projection: ty::ProjectionTy<'tcx>,
- ) -> ControlFlow<Self::BreakTy> {
+ fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow<Self::BreakTy> {
self.skeleton().visit_projection_ty(projection)
}
fn visit_predicates(
V: DefIdVisitor<'tcx> + ?Sized,
{
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<V::BreakTy> {
- let TraitRef { def_id, substs } = trait_ref;
+ let TraitRef { def_id, substs, .. } = trait_ref;
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?;
if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
}
- fn visit_projection_ty(
- &mut self,
- projection: ty::ProjectionTy<'tcx>,
- ) -> ControlFlow<V::BreakTy> {
+ fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow<V::BreakTy> {
let tcx = self.def_id_visitor.tcx();
- let (trait_ref, assoc_substs) = if tcx.def_kind(projection.item_def_id)
- != DefKind::ImplTraitPlaceholder
- {
- projection.trait_ref_and_own_substs(tcx)
- } else {
- // HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys
- let def_id = tcx.impl_trait_in_trait_parent(projection.item_def_id);
- let trait_generics = tcx.generics_of(def_id);
- (
- ty::TraitRef { def_id, substs: projection.substs.truncate_to(tcx, trait_generics) },
- &projection.substs[trait_generics.count()..],
- )
- };
+ let (trait_ref, assoc_substs) =
+ if tcx.def_kind(projection.def_id) != DefKind::ImplTraitPlaceholder {
+ projection.trait_ref_and_own_substs(tcx)
+ } else {
+ // HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys
+ let def_id = tcx.impl_trait_in_trait_parent(projection.def_id);
+ let trait_generics = tcx.generics_of(def_id);
+ (
+ tcx.mk_trait_ref(def_id, projection.substs.truncate_to(tcx, trait_generics)),
+ &projection.substs[trait_generics.count()..],
+ )
+ };
self.visit_trait(trait_ref)?;
if self.def_id_visitor.shallow() {
ControlFlow::CONTINUE
}
}
}
- ty::Projection(proj) => {
+ ty::Alias(ty::Projection, proj) => {
if self.def_id_visitor.skip_assoc_tys() {
// Visitors searching for minimal visibility/reachability want to
// conservatively approximate associated types like `<Type as Trait>::Alias`
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)?;
}
}
- ty::Opaque(def_id, ..) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
// Skip repeated `Opaque`s to avoid infinite recursion.
if self.visited_opaque_tys.insert(def_id) {
// The intent is to treat `impl Trait1 + Trait2` identically to
let is_local_static =
if let DefKind::Static(_) = kind { def_id.is_local() } else { false };
if !self.item_is_accessible(def_id) && !is_local_static {
- let sess = self.tcx.sess;
- let sm = sess.source_map();
- let name = match qpath {
- hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => {
- sm.span_to_snippet(qpath.span()).ok()
+ let name = match *qpath {
+ hir::QPath::LangItem(it, ..) => {
+ self.tcx.lang_items().get(it).map(|did| self.tcx.def_path_str(did))
}
+ hir::QPath::Resolved(_, path) => Some(self.tcx.def_path_str(path.res.def_id())),
hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
};
let kind = kind.descr(def_id);
+ let sess = self.tcx.sess;
let _ = match name {
Some(name) => {
sess.emit_err(ItemIsPrivate { span, kind, descr: (&name).into() })
#[primary_span]
pub span: Span,
pub stack_bottom: String,
- #[subdiagnostic(eager)]
+ #[subdiagnostic]
pub cycle_stack: Vec<CycleStack>,
#[subdiagnostic]
pub stack_count: StackCount,
/// FIXME #4948: Reuse ribs to avoid allocation.
ribs: PerNS<Vec<Rib<'a>>>,
+ /// Previous poped `rib`, only used for diagnostic.
+ last_block_rib: Option<Rib<'a>>,
+
/// The current set of local scopes, for labels.
label_ribs: Vec<Rib<'a, NodeId>>,
// Ignore errors in function bodies if this is rustdoc
// Be sure not to set this until the function signature has been resolved.
let previous_state = replace(&mut this.in_func_body, true);
+ // We only care block in the same function
+ this.last_block_rib = None;
// Resolve the function body, potentially inside the body of an async closure
this.with_lifetime_rib(
LifetimeRibKind::Elided(LifetimeRes::Infer),
type_ns: vec![Rib::new(start_rib_kind)],
macro_ns: vec![Rib::new(start_rib_kind)],
},
+ last_block_rib: None,
label_ribs: Vec::new(),
lifetime_ribs: Vec::new(),
lifetime_elision_candidates: None,
self.ribs[ValueNS].pop();
self.label_ribs.pop();
}
- self.ribs[ValueNS].pop();
+ self.last_block_rib = self.ribs[ValueNS].pop();
if anonymous_module.is_some() {
self.ribs[TypeNS].pop();
}
return (true, candidates);
}
}
+
+ // Try to find in last block rib
+ if let Some(rib) = &self.last_block_rib && let RibKind::NormalRibKind = rib.kind {
+ for (ident, &res) in &rib.bindings {
+ if let Res::Local(_) = res && path.len() == 1 &&
+ ident.span.eq_ctxt(path[0].ident.span) &&
+ ident.name == path[0].ident.name {
+ err.span_help(
+ ident.span,
+ &format!("the binding `{}` is available in a different scope in the same function", path_str),
+ );
+ return (true, candidates);
+ }
+ }
+ }
+
return (false, candidates);
}
pub key: PAuthKey,
}
-#[derive(Clone, Copy, Hash, Debug, PartialEq)]
+#[derive(Clone, Copy, Hash, Debug, PartialEq, Default)]
pub struct BranchProtection {
pub bti: bool,
pub pac_ret: Option<PacRet>,
}
-impl Default for BranchProtection {
- fn default() -> Self {
- BranchProtection { bti: false, pac_ret: None }
- }
-}
-
pub const fn default_lib_output() -> CrateType {
CrateType::Rlib
}
.into_iter()
.flat_map(|(i, s)| {
// NB: This can match a string without `=`.
- if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
+ if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
})
.max();
if max_o > max_c {
.into_iter()
.flat_map(|(i, s)| {
// NB: This can match a string without `=`.
- if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
+ if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
})
.max();
if max_g > max_c {
#[derive(Diagnostic)]
#[diag(session_skipping_const_checks)]
pub struct SkippingConstChecks {
- #[subdiagnostic(eager)]
+ #[subdiagnostic]
pub unleashed_features: Vec<UnleashedFeatureHelp>,
}
s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit())
}
- // Try to lowercase the prefix if it's a valid base prefix.
- fn fix_base_capitalisation(s: &str) -> Option<String> {
- if let Some(stripped) = s.strip_prefix('B') {
- Some(format!("0b{stripped}"))
- } else if let Some(stripped) = s.strip_prefix('O') {
- Some(format!("0o{stripped}"))
- } else if let Some(stripped) = s.strip_prefix('X') {
- Some(format!("0x{stripped}"))
+ // Try to lowercase the prefix if the prefix and suffix are valid.
+ fn fix_base_capitalisation(prefix: &str, suffix: &str) -> Option<String> {
+ let mut chars = suffix.chars();
+
+ let base_char = chars.next().unwrap();
+ let base = match base_char {
+ 'B' => 2,
+ 'O' => 8,
+ 'X' => 16,
+ _ => return None,
+ };
+
+ // check that the suffix contains only base-appropriate characters
+ let valid = prefix == "0"
+ && chars
+ .filter(|c| *c != '_')
+ .take_while(|c| *c != 'i' && *c != 'u')
+ .all(|c| c.to_digit(base).is_some());
+
+ if valid {
+ Some(format!("0{}{}", base_char.to_ascii_lowercase(), &suffix[1..]))
} else {
None
}
}
- let token::Lit { kind, suffix, .. } = lit;
+ let token::Lit { kind, symbol, suffix, .. } = lit;
match err {
// `LexerError` is an error, but it was already reported
// by lexer, so here we don't report it the second time.
if looks_like_width_suffix(&['i', 'u'], suf) {
// If it looks like a width, try to be helpful.
sess.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() });
- } else if let Some(fixed) = fix_base_capitalisation(suf) {
+ } else if let Some(fixed) = fix_base_capitalisation(symbol.as_str(), suf) {
sess.emit_err(InvalidNumLiteralBasePrefix { span, fixed });
} else {
sess.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() });
computed `block` spans (one span encompassing a block's terminator and \
all statements). If `-Z instrument-coverage` is also enabled, create \
an additional `.html` file showing the computed coverage spans."),
+ dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
+ parse_switch_with_opt_path, [UNTRACKED],
+ "output statistics about monomorphization collection (format: markdown)"),
dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
dylib_lto: bool = (false, parse_bool, [UNTRACKED],
// There might still be a tail left to analyze
let tail_start = chunk_count * CHUNK_SIZE + intra_chunk_offset;
if tail_start < src.len() {
- analyze_source_file_generic(&src[tail_start as usize ..],
+ analyze_source_file_generic(&src[tail_start ..],
src.len() - tail_start,
output_offset + BytePos::from_usize(tail_start),
lines,
while i < scan_len {
let byte = unsafe {
// We verified that i < scan_len <= src.len()
- *src_bytes.get_unchecked(i as usize)
+ *src_bytes.get_unchecked(i)
};
// How much to advance in order to get to the next UTF-8 char in the
FileNameDisplayPreference::Remapped => {
self.remapped_path_if_available().to_string_lossy()
}
+ FileNameDisplayPreference::Short => self
+ .local_path_if_available()
+ .file_name()
+ .map_or_else(|| "".into(), |f| f.to_string_lossy()),
}
}
}
/// Display the path before the application of rewrite rules provided via `--remap-path-prefix`.
/// This is appropriate for use in user-facing output (such as diagnostics).
Local,
+ /// Display only the filename, as a way to reduce the verbosity of the output.
+ /// This is appropriate for use in user-facing output (such as diagnostics).
+ Short,
}
pub struct FileNameDisplay<'a> {
4 => {
raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
for diff in diff_iter {
- raw_diffs.extend_from_slice(&(diff.0 as u32).to_le_bytes());
+ raw_diffs.extend_from_slice(&(diff.0).to_le_bytes());
}
}
_ => unreachable!(),
}
}
- fn span_to_string(&self, sp: Span, filename_display_pref: FileNameDisplayPreference) -> String {
+ pub fn span_to_string(
+ &self,
+ sp: Span,
+ filename_display_pref: FileNameDisplayPreference,
+ ) -> String {
if self.files.borrow().source_files.is_empty() || sp.is_dummy() {
return "no-location".to_string();
}
let lo = self.lookup_char_pos(sp.lo());
let hi = self.lookup_char_pos(sp.hi());
format!(
- "{}:{}:{}: {}:{}",
+ "{}:{}:{}{}",
lo.file.name.display(filename_display_pref),
lo.line,
lo.col.to_usize() + 1,
- hi.line,
- hi.col.to_usize() + 1,
+ if let FileNameDisplayPreference::Short = filename_display_pref {
+ String::new()
+ } else {
+ format!(": {}:{}", hi.line, hi.col.to_usize() + 1)
+ }
)
}
/// Otherwise, the span reached to limit is returned.
pub fn span_look_ahead(&self, span: Span, expect: Option<&str>, limit: Option<usize>) -> Span {
let mut sp = span;
- for _ in 0..limit.unwrap_or(100 as usize) {
+ for _ in 0..limit.unwrap_or(100_usize) {
sp = self.next_point(sp);
if let Ok(ref snippet) = self.span_to_snippet(sp) {
if expect.map_or(false, |es| snippet == es) {
// NOTE: We are iterating over the mapping entries from last to first
// because entries specified later on the command line should
// take precedence.
- for &(ref from, ref to) in mapping.iter().rev() {
+ for (from, to) in mapping.iter().rev() {
debug!("Trying to apply {from:?} => {to:?}");
if let Ok(rest) = path.strip_prefix(from) {
item_like_imports,
iter,
iter_repeat,
+ iterator_collect_fn,
kcfi,
keyword,
kind,
match *ty.kind() {
// Print all nominal types as paths (unlike `pretty_print_type`).
ty::FnDef(def_id, substs)
- | ty::Opaque(def_id, substs)
- | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs })
+ | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
| ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
// Similar to `pretty_path_qualified`, but for the other
// types that are printed as paths (see `print_type` above).
match self_ty.kind() {
- ty::FnDef(..)
- | ty::Opaque(..)
- | ty::Projection(_)
- | ty::Closure(..)
- | ty::Generator(..)
+ ty::FnDef(..) | ty::Alias(..) | ty::Closure(..) | ty::Generator(..)
if trait_ref.is_none() =>
{
self.print_type(self_ty)
s.push_str(&encode_substs(tcx, trait_ref.substs, dict, options));
}
ty::ExistentialPredicate::Projection(projection) => {
- let name = encode_ty_name(tcx, projection.item_def_id);
+ let name = encode_ty_name(tcx, projection.def_id);
let _ = write!(s, "u{}{}", name.len(), &name);
s.push_str(&encode_substs(tcx, projection.substs, dict, options));
match projection.term.unpack() {
| ty::Error(..)
| ty::GeneratorWitness(..)
| ty::Infer(..)
- | ty::Opaque(..)
+ | ty::Alias(..)
| ty::Param(..)
- | ty::Placeholder(..)
- | ty::Projection(..) => {
+ | ty::Placeholder(..) => {
bug!("encode_ty: unexpected `{:?}`", ty.kind());
}
};
| ty::Error(..)
| ty::GeneratorWitness(..)
| ty::Infer(..)
- | ty::Opaque(..)
+ | ty::Alias(..)
| ty::Param(..)
- | ty::Placeholder(..)
- | ty::Projection(..) => {
+ | ty::Placeholder(..) => {
bug!("transform_ty: unexpected `{:?}`", ty.kind());
}
}
// Mangle all nominal types as paths.
ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs)
| ty::FnDef(def_id, substs)
- | ty::Opaque(def_id, substs)
- | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs })
+ | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
| ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, _) => {
self = self.print_def_path(def_id, substs)?;
cx = cx.print_def_path(trait_ref.def_id, trait_ref.substs)?;
}
ty::ExistentialPredicate::Projection(projection) => {
- let name = cx.tcx.associated_item(projection.item_def_id).name;
+ let name = cx.tcx.associated_item(projection.def_id).name;
cx.push("p");
cx.push_ident(name.as_str());
cx = match projection.term.unpack() {
_ => os.into(),
};
- let platform_version: StaticCow<str> = match os.as_ref() {
+ let platform_version: StaticCow<str> = match os {
"ios" => ios_lld_platform_version(),
"tvos" => tvos_lld_platform_version(),
"watchos" => watchos_lld_platform_version(),
base.max_atomic_width = Some(64);
base.add_pre_link_args(
LinkerFlavor::Unix(Cc::No),
- &[
- "-b64".into(),
- "-bpT:0x100000000".into(),
- "-bpD:0x110000000".into(),
- "-bcdtors:all:0:s".into(),
- ],
+ &["-b64", "-bpT:0x100000000", "-bpD:0x110000000", "-bcdtors:all:0:s"],
);
Target {
pub fn is_of_param(&self, ty: Ty<'_>) -> bool {
match ty.kind() {
ty::Param(_) => true,
- ty::Projection(p) => self.is_of_param(p.self_ty()),
+ ty::Alias(ty::Projection, p) => self.is_of_param(p.self_ty()),
_ => false,
}
}
fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
if let Some(ty) = p.term().skip_binder().ty() {
- matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty)
+ matches!(ty.kind(), ty::Alias(ty::Projection, proj) if proj == &p.skip_binder().projection_ty)
} else {
false
}
| ty::RawPtr(..)
| ty::Never
| ty::Tuple(..)
- | ty::Projection(..) => self.found_non_local_ty(ty),
+ | ty::Alias(ty::Projection, ..) => self.found_non_local_ty(ty),
ty::Param(..) => self.found_param_ty(ty),
);
ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
}
- ty::Opaque(..) => {
+ ty::Alias(ty::Opaque, ..) => {
// This merits some explanation.
// Normally, opaque types are not involved when performing
// coherence checking, since it is illegal to directly
use rustc_hir::def_id::DefId;
-use rustc_infer::infer::InferCtxt;
+use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime};
+use rustc_infer::traits::util::elaborate_predicates_with_span;
use rustc_infer::traits::{Obligation, ObligationCause, TraitObligation};
-use rustc_span::DUMMY_SP;
+use rustc_middle::ty;
+use rustc_span::{Span, DUMMY_SP};
use crate::traits::ObligationCtxt;
+pub enum Ambiguity {
+ DefId(DefId),
+ ParamEnv(Span),
+}
+
pub fn recompute_applicable_impls<'tcx>(
infcx: &InferCtxt<'tcx>,
obligation: &TraitObligation<'tcx>,
-) -> Vec<DefId> {
+) -> Vec<Ambiguity> {
let tcx = infcx.tcx;
let param_env = obligation.param_env;
- let dummy_cause = ObligationCause::dummy();
+
let impl_may_apply = |impl_def_id| {
let ocx = ObligationCtxt::new_in_snapshot(infcx);
let placeholder_obligation =
infcx.replace_bound_vars_with_placeholders(obligation.predicate);
let obligation_trait_ref =
- ocx.normalize(&dummy_cause, param_env, placeholder_obligation.trait_ref);
+ ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs);
let impl_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
- if let Err(_) = ocx.eq(&dummy_cause, param_env, obligation_trait_ref, impl_trait_ref) {
+ if let Err(_) =
+ ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref)
+ {
return false;
}
let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs);
- ocx.register_obligations(
- impl_predicates
- .predicates
- .iter()
- .map(|&predicate| Obligation::new(tcx, dummy_cause.clone(), param_env, predicate)),
+ ocx.register_obligations(impl_predicates.predicates.iter().map(|&predicate| {
+ Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
+ }));
+
+ ocx.select_where_possible().is_empty()
+ };
+
+ let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| {
+ let ocx = ObligationCtxt::new_in_snapshot(infcx);
+ let placeholder_obligation =
+ infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+ let obligation_trait_ref =
+ ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
+
+ let param_env_predicate = infcx.replace_bound_vars_with_fresh_vars(
+ DUMMY_SP,
+ LateBoundRegionConversionTime::HigherRankedType,
+ poly_trait_predicate,
);
+ let param_env_trait_ref =
+ ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref);
+
+ if let Err(_) =
+ ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, param_env_trait_ref)
+ {
+ return false;
+ }
ocx.select_where_possible().is_empty()
};
- let mut impls = Vec::new();
+ let mut ambiguities = Vec::new();
+
tcx.for_each_relevant_impl(
obligation.predicate.def_id(),
obligation.predicate.skip_binder().trait_ref.self_ty(),
|impl_def_id| {
- if infcx.probe(move |_snapshot| impl_may_apply(impl_def_id)) {
- impls.push(impl_def_id)
+ if infcx.probe(|_| impl_may_apply(impl_def_id)) {
+ ambiguities.push(Ambiguity::DefId(impl_def_id))
}
},
);
- impls
+
+ let predicates =
+ tcx.predicates_of(obligation.cause.body_id.owner.to_def_id()).instantiate_identity(tcx);
+ for obligation in
+ elaborate_predicates_with_span(tcx, std::iter::zip(predicates.predicates, predicates.spans))
+ {
+ let kind = obligation.predicate.kind();
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder()
+ && param_env_candidate_may_apply(kind.rebind(trait_pred))
+ {
+ if kind.rebind(trait_pred.trait_ref) == ty::TraitRef::identity(tcx, trait_pred.def_id()) {
+ ambiguities.push(Ambiguity::ParamEnv(tcx.def_span(trait_pred.def_id())))
+ } else {
+ ambiguities.push(Ambiguity::ParamEnv(obligation.cause.span))
+ }
+ }
+ }
+
+ ambiguities
}
--- /dev/null
+use crate::infer::InferCtxt;
+
+use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+
+pub struct CollectAllMismatches<'a, 'tcx> {
+ pub infcx: &'a InferCtxt<'tcx>,
+ pub param_env: ty::ParamEnv<'tcx>,
+ pub errors: Vec<TypeError<'tcx>>,
+}
+
+impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
+ fn tag(&self) -> &'static str {
+ "CollectAllMismatches"
+ }
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.infcx.tcx
+ }
+ fn intercrate(&self) -> bool {
+ false
+ }
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ self.param_env
+ }
+ fn a_is_expected(&self) -> bool {
+ true
+ } // irrelevant
+ fn mark_ambiguous(&mut self) {
+ bug!()
+ }
+ fn relate_with_variance<T: Relate<'tcx>>(
+ &mut self,
+ _: ty::Variance,
+ _: ty::VarianceDiagInfo<'tcx>,
+ a: T,
+ b: T,
+ ) -> RelateResult<'tcx, T> {
+ self.relate(a, b)
+ }
+ fn regions(
+ &mut self,
+ a: ty::Region<'tcx>,
+ _b: ty::Region<'tcx>,
+ ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+ Ok(a)
+ }
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ if a == b || matches!(a.kind(), ty::Infer(_)) || matches!(b.kind(), ty::Infer(_)) {
+ return Ok(a);
+ }
+ relate::super_relate_tys(self, a, b).or_else(|e| {
+ self.errors.push(e);
+ Ok(a)
+ })
+ }
+ fn consts(
+ &mut self,
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+ if a == b {
+ return Ok(a);
+ }
+ relate::super_relate_consts(self, a, b) // could do something similar here for constants!
+ }
+ fn binders<T: Relate<'tcx>>(
+ &mut self,
+ a: ty::Binder<'tcx, T>,
+ b: ty::Binder<'tcx, T>,
+ ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> {
+ Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
+ }
+}
mod ambiguity;
+pub mod method_chain;
pub mod on_unimplemented;
pub mod suggestions;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::print::{FmtPrinter, Print};
+use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
use rustc_middle::ty::{
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
TypeVisitable,
};
use rustc_session::Limit;
use rustc_span::def_id::LOCAL_CRATE;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::sym;
use rustc_span::{ExpnKind, Span, DUMMY_SP};
use std::fmt;
use std::iter;
|err| {
self.note_obligation_cause_code(
err,
- &predicate,
+ predicate,
obligation.param_env,
obligation.cause.code(),
&mut vec![],
trait_ref,
obligation.cause.body_id,
&mut err,
+ true,
) {
// This is *almost* equivalent to
// `obligation.cause.code().peel_derives()`, but it gives us the
trait_ref,
obligation.cause.body_id,
&mut err,
+ true,
);
}
}
&& self.fallback_has_occurred
{
let predicate = trait_predicate.map_bound(|trait_pred| {
- trait_pred.with_self_type(self.tcx, self.tcx.mk_unit())
+ trait_pred.with_self_ty(self.tcx, self.tcx.mk_unit())
});
let unit_obligation = obligation.with(tcx, predicate);
if self.predicate_may_hold(&unit_obligation) {
_ => None,
};
+ let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did));
let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did));
if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
found_trait_ref,
expected_trait_ref,
obligation.cause.code(),
+ found_node,
)
} else {
let (closure_span, closure_arg_span, found) = found_did
trait_ref: ty::PolyTraitRef<'tcx>,
body_id: hir::HirId,
err: &mut Diagnostic,
+ other: bool,
) -> bool;
/// Gets the parent trait chain start
fn annotate_source_of_ambiguity(
&self,
err: &mut Diagnostic,
- impls: &[DefId],
+ impls: &[ambiguity::Ambiguity],
predicate: ty::Predicate<'tcx>,
);
{
self.note_obligation_cause_code(
&mut diag,
- &error.obligation.predicate,
+ error.obligation.predicate,
error.obligation.param_env,
code,
&mut vec![],
infer::LateBoundRegionConversionTime::HigherRankedType,
bound_predicate.rebind(data),
);
- let normalized_ty = ocx.normalize(
- &obligation.cause,
- obligation.param_env,
- self.tcx
- .mk_projection(data.projection_ty.item_def_id, data.projection_ty.substs),
- );
+ let unnormalized_term = match data.term.unpack() {
+ ty::TermKind::Ty(_) => self
+ .tcx
+ .mk_projection(data.projection_ty.def_id, data.projection_ty.substs)
+ .into(),
+ ty::TermKind::Const(ct) => self
+ .tcx
+ .mk_const(
+ ty::UnevaluatedConst {
+ def: ty::WithOptConstParam::unknown(data.projection_ty.def_id),
+ substs: data.projection_ty.substs,
+ },
+ ct.ty(),
+ )
+ .into(),
+ };
+ let normalized_term =
+ ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
debug!(?obligation.cause, ?obligation.param_env);
- debug!(?normalized_ty, data.ty = ?data.term);
+ debug!(?normalized_term, data.ty = ?data.term);
- let is_normalized_ty_expected = !matches!(
+ let is_normalized_term_expected = !matches!(
obligation.cause.code().peel_derives(),
ObligationCauseCode::ItemObligation(_)
| ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ObjectCastObligation(..)
| ObligationCauseCode::OpaqueType
);
- let expected_ty = data.term.ty().unwrap_or_else(|| self.tcx.ty_error());
// constrain inference variables a bit more to nested obligations from normalize so
// we can have more helpful errors.
if let Err(new_err) = ocx.eq_exp(
&obligation.cause,
obligation.param_env,
- is_normalized_ty_expected,
- normalized_ty,
- expected_ty,
+ is_normalized_term_expected,
+ normalized_term,
+ data.term,
) {
- (Some((data, is_normalized_ty_expected, normalized_ty, expected_ty)), new_err)
+ (Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err)
} else {
(None, error.err)
}
};
let msg = values
- .and_then(|(predicate, _, normalized_ty, expected_ty)| {
- self.maybe_detailed_projection_msg(
- predicate,
- normalized_ty.into(),
- expected_ty.into(),
- )
+ .and_then(|(predicate, _, normalized_term, expected_term)| {
+ self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term)
})
.unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate));
let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
let secondary_span = match predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => self
.tcx
- .opt_associated_item(proj.projection_ty.item_def_id)
+ .opt_associated_item(proj.projection_ty.def_id)
.and_then(|trait_assoc_item| {
self.tcx
- .trait_of_item(proj.projection_ty.item_def_id)
+ .trait_of_item(proj.projection_ty.def_id)
.map(|id| (trait_assoc_item, id))
})
.and_then(|(trait_assoc_item, id)| {
let trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
let self_ty = pred.projection_ty.self_ty();
- if Some(pred.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() {
- Some(format!(
- "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it returns `{normalized_ty}`",
- fn_kind = self_ty.prefix_string(self.tcx)
- ))
- } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
- Some(format!(
- "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it resolves to `{normalized_ty}`"
- ))
- } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
- Some(format!(
- "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it yields `{normalized_ty}`"
- ))
- } else {
- None
+ with_forced_trimmed_paths! {
+ if Some(pred.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() {
+ Some(format!(
+ "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it \
+ returns `{normalized_ty}`",
+ fn_kind = self_ty.prefix_string(self.tcx)
+ ))
+ } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
+ Some(format!(
+ "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \
+ resolves to `{normalized_ty}`"
+ ))
+ } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
+ Some(format!(
+ "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \
+ yields `{normalized_ty}`"
+ ))
+ } else {
+ None
+ }
}
}
ty::Closure(..) => Some(9),
ty::Tuple(..) => Some(10),
ty::Param(..) => Some(11),
- ty::Projection(..) => Some(12),
- ty::Opaque(..) => Some(13),
+ ty::Alias(ty::Projection, ..) => Some(12),
+ ty::Alias(ty::Opaque, ..) => Some(13),
ty::Never => Some(14),
ty::Adt(..) => Some(15),
ty::Generator(..) => Some(16),
trait_ref: ty::PolyTraitRef<'tcx>,
body_id: hir::HirId,
err: &mut Diagnostic,
+ other: bool,
) -> bool {
+ let other = if other { "other " } else { "" };
let report = |mut candidates: Vec<TraitRef<'tcx>>, err: &mut Diagnostic| {
candidates.sort();
candidates.dedup();
candidates.dedup();
let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
err.help(&format!(
- "the following other types implement trait `{}`:{}{}",
+ "the following {other}types implement trait `{}`:{}{}",
trait_ref.print_only_trait_path(),
candidates[..end].join(""),
if len > 9 { format!("\nand {} others", len - 8) } else { String::new() }
param_env: ty::ParamEnv<'tcx>,
trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
) -> PredicateObligation<'tcx> {
- let trait_pred = trait_ref_and_ty
- .map_bound(|(tr, new_self_ty)| tr.with_self_type(self.tcx, new_self_ty));
+ let trait_pred =
+ trait_ref_and_ty.map_bound(|(tr, new_self_ty)| tr.with_self_ty(self.tcx, new_self_ty));
Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred)
}
let mut selcx = SelectionContext::new(&self);
match selcx.select_from_obligation(&obligation) {
Ok(None) => {
- let impls = ambiguity::recompute_applicable_impls(self.infcx, &obligation);
+ let ambiguities =
+ ambiguity::recompute_applicable_impls(self.infcx, &obligation);
let has_non_region_infer =
trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_infer());
// It doesn't make sense to talk about applicable impls if there are more
// than a handful of them.
- if impls.len() > 1 && impls.len() < 5 && has_non_region_infer {
- self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+ if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
+ if self.tainted_by_errors().is_some() && subst.is_none() {
+ // If `subst.is_none()`, then this is probably two param-env
+ // candidates or impl candidates that are equal modulo lifetimes.
+ // Therefore, if we've already emitted an error, just skip this
+ // one, since it's not particularly actionable.
+ err.cancel();
+ return;
+ }
+ self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
} else {
if self.tainted_by_errors().is_some() {
err.cancel();
return;
}
err.note(&format!("cannot satisfy `{}`", predicate));
+ let impl_candidates = self.find_similar_impl_candidates(
+ predicate.to_opt_poly_trait_pred().unwrap(),
+ );
+ if impl_candidates.len() < 10 {
+ self.report_similar_impl_candidates(
+ impl_candidates,
+ trait_ref,
+ body_id.map(|id| id.hir_id).unwrap_or(obligation.cause.body_id),
+ &mut err,
+ false,
+ );
+ }
}
}
_ => {
}
}
- if let ObligationCauseCode::ItemObligation(def_id) | ObligationCauseCode::ExprItemObligation(def_id, ..) = *obligation.cause.code() {
- self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
- } else if let Ok(snippet) = &self.tcx.sess.source_map().span_to_snippet(span)
- && let ObligationCauseCode::BindingObligation(def_id, _) | ObligationCauseCode::ExprBindingObligation(def_id, ..)
- = *obligation.cause.code()
+ if let ObligationCauseCode::ItemObligation(def_id)
+ | ObligationCauseCode::ExprItemObligation(def_id, ..) = *obligation.cause.code()
{
- let generics = self.tcx.generics_of(def_id);
- if generics.params.iter().any(|p| p.name != kw::SelfUpper)
- && !snippet.ends_with('>')
- && !generics.has_impl_trait()
- && !self.tcx.is_fn_trait(def_id)
- {
- // FIXME: To avoid spurious suggestions in functions where type arguments
- // where already supplied, we check the snippet to make sure it doesn't
- // end with a turbofish. Ideally we would have access to a `PathSegment`
- // instead. Otherwise we would produce the following output:
- //
- // error[E0283]: type annotations needed
- // --> $DIR/issue-54954.rs:3:24
- // |
- // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
- // | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- // | |
- // | cannot infer type
- // | help: consider specifying the type argument
- // | in the function call:
- // | `Tt::const_val::<[i8; 123]>::<T>`
- // ...
- // LL | const fn const_val<T: Sized>() -> usize {
- // | - required by this bound in `Tt::const_val`
- // |
- // = note: cannot satisfy `_: Tt`
-
- // Clear any more general suggestions in favor of our specific one
- err.clear_suggestions();
-
- err.span_suggestion_verbose(
- span.shrink_to_hi(),
- &format!(
- "consider specifying the type argument{} in the function call",
- pluralize!(generics.params.len()),
- ),
- format!(
- "::<{}>",
- generics
- .params
- .iter()
- .map(|p| p.name.to_string())
- .collect::<Vec<String>>()
- .join(", ")
- ),
- Applicability::HasPlaceholders,
- );
- }
+ self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
}
if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) =
fn annotate_source_of_ambiguity(
&self,
err: &mut Diagnostic,
- impls: &[DefId],
+ ambiguities: &[ambiguity::Ambiguity],
predicate: ty::Predicate<'tcx>,
) {
let mut spans = vec![];
let mut crates = vec![];
let mut post = vec![];
- for def_id in impls {
- match self.tcx.span_of_impl(*def_id) {
- Ok(span) => spans.push(span),
- Err(name) => {
- crates.push(name);
- if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) {
- post.push(header);
+ let mut has_param_env = false;
+ for ambiguity in ambiguities {
+ match ambiguity {
+ ambiguity::Ambiguity::DefId(impl_def_id) => {
+ match self.tcx.span_of_impl(*impl_def_id) {
+ Ok(span) => spans.push(span),
+ Err(name) => {
+ crates.push(name);
+ if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) {
+ post.push(header);
+ }
+ }
}
}
+ ambiguity::Ambiguity::ParamEnv(span) => {
+ has_param_env = true;
+ spans.push(*span);
+ }
}
}
let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
return;
}
- let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
+ let msg = format!(
+ "multiple `impl`s{} satisfying `{}` found",
+ if has_param_env { " or `where` clauses" } else { "" },
+ predicate
+ );
let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
} else if post.len() == 1 {
if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
self.note_obligation_cause_code(
err,
- &obligation.predicate,
+ obligation.predicate,
obligation.param_env,
obligation.cause.code(),
&mut vec![],
+// ignore-tidy-filelength
+
use super::{DefIdOrName, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation};
use crate::autoderef::Autoderef;
use crate::infer::InferCtxt;
-use crate::traits::NormalizeExt;
+use crate::traits::{NormalizeExt, ObligationCtxt};
use hir::def::CtorOf;
use hir::HirId;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{InferOk, LateBoundRegionConversionTime};
use rustc_middle::hir::map;
+use rustc_middle::ty::error::TypeError::{self, Sorts};
+use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::{
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
- GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable,
- ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
+ GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts,
+ IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder,
+ TypeSuperFoldable, TypeVisitable, TypeckResults,
};
-use rustc_middle::ty::{TypeAndMut, TypeckResults};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP};
use rustc_target::spec::abi;
-use std::fmt;
+use std::ops::Deref;
+use super::method_chain::CollectAllMismatches;
use super::InferCtxtPrivExt;
use crate::infer::InferCtxtExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
found: ty::PolyTraitRef<'tcx>,
expected: ty::PolyTraitRef<'tcx>,
cause: &ObligationCauseCode<'tcx>,
+ found_node: Option<Node<'_>>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
fn note_conflicting_closure_bounds(
fn note_obligation_cause_code<T>(
&self,
err: &mut Diagnostic,
- predicate: &T,
+ predicate: T,
param_env: ty::ParamEnv<'tcx>,
cause_code: &ObligationCauseCode<'tcx>,
obligated_types: &mut Vec<Ty<'tcx>>,
seen_requirements: &mut FxHashSet<DefId>,
) where
- T: fmt::Display + ToPredicate<'tcx>;
+ T: ToPredicate<'tcx>;
/// Suggest to await before try: future? => future.await?
fn suggest_await_before_try(
err: &mut Diagnostic,
trait_pred: ty::PolyTraitPredicate<'tcx>,
);
+ fn function_argument_obligation(
+ &self,
+ arg_hir_id: HirId,
+ err: &mut Diagnostic,
+ parent_code: &ObligationCauseCode<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ predicate: ty::Predicate<'tcx>,
+ call_hir_id: HirId,
+ );
+ fn point_at_chain(
+ &self,
+ expr: &hir::Expr<'_>,
+ typeck_results: &TypeckResults<'tcx>,
+ type_diffs: Vec<TypeError<'tcx>>,
+ param_env: ty::ParamEnv<'tcx>,
+ err: &mut Diagnostic,
+ );
+ fn probe_assoc_types_at_expr(
+ &self,
+ type_diffs: &[TypeError<'tcx>],
+ span: Span,
+ prev_ty: Ty<'tcx>,
+ body_id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>>;
}
fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {
msg: &str,
err: &mut Diagnostic,
fn_sig: Option<&hir::FnSig<'_>>,
- projection: Option<&ty::ProjectionTy<'_>>,
+ projection: Option<&ty::AliasTy<'_>>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
// When we are dealing with a trait, `super_traits` will be `Some`:
// Given `trait T: A + B + C {}`
let self_ty = trait_pred.skip_binder().self_ty();
let (param_ty, projection) = match self_ty.kind() {
ty::Param(_) => (true, None),
- ty::Projection(projection) => (false, Some(projection)),
+ ty::Alias(ty::Projection, projection) => (false, Some(projection)),
_ => (false, None),
};
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
// It only make sense when suggesting dereferences for arguments
- let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code()
+ let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, call_hir_id, .. } = obligation.cause.code()
else { return false; };
let Some(typeck_results) = &self.typeck_results
else { return false; };
real_trait_pred_and_base_ty,
);
if self.predicate_may_hold(&obligation) {
- err.span_suggestion_verbose(
- span.shrink_to_lo(),
- "consider dereferencing here",
- "*",
- Applicability::MachineApplicable,
+ let call_node = self.tcx.hir().get(*call_hir_id);
+ let msg = "consider dereferencing here";
+ let is_receiver = matches!(
+ call_node,
+ Node::Expr(hir::Expr {
+ kind: hir::ExprKind::MethodCall(_, receiver_expr, ..),
+ ..
+ })
+ if receiver_expr.hir_id == *arg_hir_id
);
+ if is_receiver {
+ err.multipart_suggestion_verbose(
+ msg,
+ vec![
+ (span.shrink_to_lo(), "(*".to_string()),
+ (span.shrink_to_hi(), ")".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ )
+ } else {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ msg,
+ '*',
+ Applicability::MachineApplicable,
+ )
+ };
return true;
}
}
fn_sig.inputs().map_bound(|inputs| &inputs[1..]),
))
}
- ty::Opaque(def_id, substs) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
- && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+ && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
// args tuple will always be substs[1]
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
{
ty::Dynamic(data, _, ty::Dyn) => {
data.iter().find_map(|pred| {
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
- && Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
+ && Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
// for existential projection, substs are shifted over by 1
&& let ty::Tuple(args) = proj.substs.type_at(0).kind()
{
ty::Param(_) => {
obligation.param_env.caller_bounds().iter().find_map(|pred| {
if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
- && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+ && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
&& proj.projection_ty.self_ty() == found
// args tuple will always be substs[1]
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
found: ty::PolyTraitRef<'tcx>,
expected: ty::PolyTraitRef<'tcx>,
cause: &ObligationCauseCode<'tcx>,
+ found_node: Option<Node<'_>>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
pub(crate) fn build_fn_sig_ty<'tcx>(
infcx: &InferCtxt<'tcx>,
self.note_conflicting_closure_bounds(cause, &mut err);
+ if let Some(found_node) = found_node {
+ hint_missing_borrow(span, found_span, found, expected, found_node, &mut err);
+ }
+
err
}
format!("does not implement `{}`", trait_pred.print_modifiers_and_trait_path())
};
- let mut explain_yield = |interior_span: Span,
- yield_span: Span,
- scope_span: Option<Span>| {
- let mut span = MultiSpan::from_span(yield_span);
- if let Ok(snippet) = source_map.span_to_snippet(interior_span) {
- // #70935: If snippet contains newlines, display "the value" instead
- // so that we do not emit complex diagnostics.
- let snippet = &format!("`{}`", snippet);
- let snippet = if snippet.contains('\n') { "the value" } else { snippet };
+ let mut explain_yield =
+ |interior_span: Span, yield_span: Span, scope_span: Option<Span>| {
+ let mut span = MultiSpan::from_span(yield_span);
+ let snippet = match source_map.span_to_snippet(interior_span) {
+ // #70935: If snippet contains newlines, display "the value" instead
+ // so that we do not emit complex diagnostics.
+ Ok(snippet) if !snippet.contains('\n') => format!("`{}`", snippet),
+ _ => "the value".to_string(),
+ };
// note: future is not `Send` as this value is used across an await
// --> $DIR/issue-70935-complex-spans.rs:13:9
// |
interior_span,
format!("has type `{}` which {}", target_ty, trait_explanation),
);
- // If available, use the scope span to annotate the drop location.
- let mut scope_note = None;
if let Some(scope_span) = scope_span {
let scope_span = source_map.end_point(scope_span);
let msg = format!("{} is later dropped here", snippet);
- if source_map.is_multiline(yield_span.between(scope_span)) {
- span.push_span_label(scope_span, msg);
- } else {
- scope_note = Some((scope_span, msg));
- }
+ span.push_span_label(scope_span, msg);
}
err.span_note(
span,
future_or_generator, trait_explanation, an_await_or_yield
),
);
- if let Some((span, msg)) = scope_note {
- err.span_note(span, &msg);
- }
- }
- };
+ };
match interior_or_upvar_span {
GeneratorInteriorOrUpvar::Interior(interior_span, interior_extra_info) => {
if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info {
debug!(?next_code);
self.note_obligation_cause_code(
err,
- &obligation.predicate,
+ obligation.predicate,
obligation.param_env,
next_code.unwrap(),
&mut Vec::new(),
fn note_obligation_cause_code<T>(
&self,
err: &mut Diagnostic,
- predicate: &T,
+ predicate: T,
param_env: ty::ParamEnv<'tcx>,
cause_code: &ObligationCauseCode<'tcx>,
obligated_types: &mut Vec<Ty<'tcx>>,
seen_requirements: &mut FxHashSet<DefId>,
) where
- T: fmt::Display + ToPredicate<'tcx>,
+ T: ToPredicate<'tcx>,
{
let tcx = self.tcx;
+ let predicate = predicate.to_predicate(tcx);
match *cause_code {
ObligationCauseCode::ExprAssignable
| ObligationCauseCode::MatchExpressionArm { .. }
err.note("only the last element of a tuple may have a dynamically sized type");
}
ObligationCauseCode::ProjectionWf(data) => {
- err.note(&format!("required so that the projection `{}` is well-formed", data,));
+ err.note(&format!("required so that the projection `{data}` is well-formed"));
}
ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => {
err.note(&format!(
- "required so that reference `{}` does not outlive its referent",
- ref_ty,
+ "required so that reference `{ref_ty}` does not outlive its referent"
));
}
ObligationCauseCode::ObjectTypeBound(object_ty, region) => {
Some(ident) => err.span_note(ident.span, &msg),
None => err.note(&msg),
},
- ty::Opaque(def_id, _) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
// Avoid printing the future from `core::future::identity_future`, it's not helpful
if tcx.parent(*def_id) == identity_future {
break 'print;
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
err,
- &parent_predicate,
+ parent_predicate,
param_env,
&data.parent_code,
obligated_types,
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
err,
- &parent_predicate,
+ parent_predicate,
param_env,
cause_code.peel_derives(),
obligated_types,
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
err,
- &parent_predicate,
+ parent_predicate,
param_env,
&data.parent_code,
obligated_types,
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
err,
- &parent_predicate,
+ parent_predicate,
param_env,
&data.parent_code,
obligated_types,
arg_hir_id,
call_hir_id,
ref parent_code,
+ ..
} => {
- let hir = self.tcx.hir();
- if let Some(Node::Expr(expr @ hir::Expr { kind: hir::ExprKind::Block(..), .. })) =
- hir.find(arg_hir_id)
- {
- let parent_id = hir.get_parent_item(arg_hir_id);
- let typeck_results: &TypeckResults<'tcx> = match &self.typeck_results {
- Some(t) if t.hir_owner == parent_id => t,
- _ => self.tcx.typeck(parent_id.def_id),
- };
- let expr = expr.peel_blocks();
- let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error());
- let span = expr.span;
- if Some(span) != err.span.primary_span() {
- err.span_label(
- span,
- if ty.references_error() {
- String::new()
- } else {
- format!("this tail expression is of type `{:?}`", ty)
- },
- );
- }
- }
- if let Some(Node::Expr(hir::Expr {
- kind:
- hir::ExprKind::Call(hir::Expr { span, .. }, _)
- | hir::ExprKind::MethodCall(
- hir::PathSegment { ident: Ident { span, .. }, .. },
- ..,
- ),
- ..
- })) = hir.find(call_hir_id)
- {
- if Some(*span) != err.span.primary_span() {
- err.span_label(*span, "required by a bound introduced by this call");
- }
- }
+ self.function_argument_obligation(
+ arg_hir_id,
+ err,
+ parent_code,
+ param_env,
+ predicate,
+ call_hir_id,
+ );
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
err,
ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => {
let item_name = self.tcx.item_name(trait_item_def_id);
let msg = format!(
- "the requirement `{}` appears on the `impl`'s {kind} `{}` but not on the \
- corresponding trait's {kind}",
- predicate, item_name,
+ "the requirement `{predicate}` appears on the `impl`'s {kind} \
+ `{item_name}` but not on the corresponding trait's {kind}",
);
let sp = self
.tcx
let mut assoc_span: MultiSpan = sp.into();
assoc_span.push_span_label(
sp,
- format!("this trait's {kind} doesn't have the requirement `{}`", predicate),
+ format!("this trait's {kind} doesn't have the requirement `{predicate}`"),
);
if let Some(ident) = self
.tcx
}
ObligationCauseCode::OpaqueReturnType(expr_info) => {
if let Some((expr_ty, expr_span)) = expr_info {
- let expr_ty = self.resolve_vars_if_possible(expr_ty);
+ let expr_ty = with_forced_trimmed_paths!(self.ty_to_string(expr_ty));
err.span_label(
expr_span,
format!("return type was inferred to be `{expr_ty}` here"),
self.tcx.mk_projection(
item_def_id,
// Future::Output has no substs
- self.tcx.mk_substs_trait(trait_pred.self_ty(), []),
+ [trait_pred.self_ty()],
)
});
let InferOk { value: projection_ty, .. } =
);
}
}
+ fn function_argument_obligation(
+ &self,
+ arg_hir_id: HirId,
+ err: &mut Diagnostic,
+ parent_code: &ObligationCauseCode<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ predicate: ty::Predicate<'tcx>,
+ call_hir_id: HirId,
+ ) {
+ let tcx = self.tcx;
+ let hir = tcx.hir();
+ if let Some(Node::Expr(expr)) = hir.find(arg_hir_id) {
+ let parent_id = hir.get_parent_item(arg_hir_id);
+ let typeck_results: &TypeckResults<'tcx> = match &self.typeck_results {
+ Some(t) if t.hir_owner == parent_id => t,
+ _ => self.tcx.typeck(parent_id.def_id),
+ };
+ if let hir::Expr { kind: hir::ExprKind::Block(..), .. } = expr {
+ let expr = expr.peel_blocks();
+ let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error());
+ let span = expr.span;
+ if Some(span) != err.span.primary_span() {
+ err.span_label(
+ span,
+ if ty.references_error() {
+ String::new()
+ } else {
+ let ty = with_forced_trimmed_paths!(self.ty_to_string(ty));
+ format!("this tail expression is of type `{ty}`")
+ },
+ );
+ }
+ }
+
+ // FIXME: visit the ty to see if there's any closure involved, and if there is,
+ // check whether its evaluated return type is the same as the one corresponding
+ // to an associated type (as seen from `trait_pred`) in the predicate. Like in
+ // trait_pred `S: Sum<<Self as Iterator>::Item>` and predicate `i32: Sum<&()>`
+ let mut type_diffs = vec![];
+
+ if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref()
+ && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
+ && let Some(pred) = predicates.predicates.get(*idx)
+ {
+ if let Ok(trait_pred) = pred.kind().try_map_bound(|pred| match pred {
+ ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred),
+ _ => Err(()),
+ })
+ && let Ok(trait_predicate) = predicate.kind().try_map_bound(|pred| match pred {
+ ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred),
+ _ => Err(()),
+ })
+ {
+ let mut c = CollectAllMismatches {
+ infcx: self.infcx,
+ param_env,
+ errors: vec![],
+ };
+ if let Ok(_) = c.relate(trait_pred, trait_predicate) {
+ type_diffs = c.errors;
+ }
+ } else if let ty::PredicateKind::Clause(
+ ty::Clause::Projection(proj)
+ ) = pred.kind().skip_binder()
+ && let ty::PredicateKind::Clause(
+ ty::Clause::Projection(projection)
+ ) = predicate.kind().skip_binder()
+ {
+ type_diffs = vec![
+ Sorts(ty::error::ExpectedFound {
+ expected: self.tcx.mk_ty(ty::Alias(ty::Projection, proj.projection_ty)),
+ found: projection.term.ty().unwrap(),
+ }),
+ ];
+ }
+ }
+ if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
+ && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
+ && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id)
+ && let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
+ && let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id)
+ && let Some(binding_expr) = local.init
+ {
+ // If the expression we're calling on is a binding, we want to point at the
+ // `let` when talking about the type. Otherwise we'll point at every part
+ // of the method chain with the type.
+ self.point_at_chain(binding_expr, typeck_results, type_diffs, param_env, err);
+ } else {
+ self.point_at_chain(expr, typeck_results, type_diffs, param_env, err);
+ }
+ }
+ let call_node = hir.find(call_hir_id);
+ if let Some(Node::Expr(hir::Expr {
+ kind: hir::ExprKind::MethodCall(path, rcvr, ..), ..
+ })) = call_node
+ {
+ if Some(rcvr.span) == err.span.primary_span() {
+ err.replace_span_with(path.ident.span);
+ }
+ }
+ if let Some(Node::Expr(hir::Expr {
+ kind:
+ hir::ExprKind::Call(hir::Expr { span, .. }, _)
+ | hir::ExprKind::MethodCall(hir::PathSegment { ident: Ident { span, .. }, .. }, ..),
+ ..
+ })) = hir.find(call_hir_id)
+ {
+ if Some(*span) != err.span.primary_span() {
+ err.span_label(*span, "required by a bound introduced by this call");
+ }
+ }
+ }
+
+ fn point_at_chain(
+ &self,
+ expr: &hir::Expr<'_>,
+ typeck_results: &TypeckResults<'tcx>,
+ type_diffs: Vec<TypeError<'tcx>>,
+ param_env: ty::ParamEnv<'tcx>,
+ err: &mut Diagnostic,
+ ) {
+ let mut primary_spans = vec![];
+ let mut span_labels = vec![];
+
+ let tcx = self.tcx;
+
+ let mut print_root_expr = true;
+ let mut assocs = vec![];
+ let mut expr = expr;
+ let mut prev_ty = self.resolve_vars_if_possible(
+ typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()),
+ );
+ while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind {
+ // Point at every method call in the chain with the resulting type.
+ // vec![1, 2, 3].iter().map(mapper).sum<i32>()
+ // ^^^^^^ ^^^^^^^^^^^
+ expr = rcvr_expr;
+ let assocs_in_this_method =
+ self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
+ assocs.push(assocs_in_this_method);
+ prev_ty = self.resolve_vars_if_possible(
+ typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()),
+ );
+
+ if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
+ && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
+ && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id)
+ && let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
+ && let Some(parent) = self.tcx.hir().find(parent_hir_id)
+ {
+ // We've reached the root of the method call chain...
+ if let hir::Node::Local(local) = parent
+ && let Some(binding_expr) = local.init
+ {
+ // ...and it is a binding. Get the binding creation and continue the chain.
+ expr = binding_expr;
+ }
+ if let hir::Node::Param(param) = parent {
+ // ...and it is a an fn argument.
+ let prev_ty = self.resolve_vars_if_possible(
+ typeck_results.node_type_opt(param.hir_id).unwrap_or(tcx.ty_error()),
+ );
+ let assocs_in_this_method = self.probe_assoc_types_at_expr(&type_diffs, param.ty_span, prev_ty, param.hir_id, param_env);
+ if assocs_in_this_method.iter().any(|a| a.is_some()) {
+ assocs.push(assocs_in_this_method);
+ print_root_expr = false;
+ }
+ break;
+ }
+ }
+ }
+ // We want the type before deref coercions, otherwise we talk about `&[_]`
+ // instead of `Vec<_>`.
+ if let Some(ty) = typeck_results.expr_ty_opt(expr) && print_root_expr {
+ let ty = with_forced_trimmed_paths!(self.ty_to_string(ty));
+ // Point at the root expression
+ // vec![1, 2, 3].iter().map(mapper).sum<i32>()
+ // ^^^^^^^^^^^^^
+ span_labels.push((expr.span, format!("this expression has type `{ty}`")));
+ };
+ // Only show this if it is not a "trivial" expression (not a method
+ // chain) and there are associated types to talk about.
+ let mut assocs = assocs.into_iter().peekable();
+ while let Some(assocs_in_method) = assocs.next() {
+ let Some(prev_assoc_in_method) = assocs.peek() else {
+ for entry in assocs_in_method {
+ let Some((span, (assoc, ty))) = entry else { continue; };
+ if primary_spans.is_empty() || type_diffs.iter().any(|diff| {
+ let Sorts(expected_found) = diff else { return false; };
+ self.can_eq(param_env, expected_found.found, ty).is_ok()
+ }) {
+ // FIXME: this doesn't quite work for `Iterator::collect`
+ // because we have `Vec<i32>` and `()`, but we'd want `i32`
+ // to point at the `.into_iter()` call, but as long as we
+ // still point at the other method calls that might have
+ // introduced the issue, this is fine for now.
+ primary_spans.push(span);
+ }
+ span_labels.push((
+ span,
+ with_forced_trimmed_paths!(format!(
+ "`{}` is `{ty}` here",
+ self.tcx.def_path_str(assoc),
+ )),
+ ));
+ }
+ break;
+ };
+ for (entry, prev_entry) in
+ assocs_in_method.into_iter().zip(prev_assoc_in_method.into_iter())
+ {
+ match (entry, prev_entry) {
+ (Some((span, (assoc, ty))), Some((_, (_, prev_ty)))) => {
+ let ty_str = with_forced_trimmed_paths!(self.ty_to_string(ty));
+
+ let assoc = with_forced_trimmed_paths!(self.tcx.def_path_str(assoc));
+ if self.can_eq(param_env, ty, *prev_ty).is_err() {
+ if type_diffs.iter().any(|diff| {
+ let Sorts(expected_found) = diff else { return false; };
+ self.can_eq(param_env, expected_found.found, ty).is_ok()
+ }) {
+ primary_spans.push(span);
+ }
+ span_labels
+ .push((span, format!("`{assoc}` changed to `{ty_str}` here")));
+ } else {
+ span_labels.push((span, format!("`{assoc}` remains `{ty_str}` here")));
+ }
+ }
+ (Some((span, (assoc, ty))), None) => {
+ span_labels.push((
+ span,
+ with_forced_trimmed_paths!(format!(
+ "`{}` is `{}` here",
+ self.tcx.def_path_str(assoc),
+ self.ty_to_string(ty),
+ )),
+ ));
+ }
+ (None, Some(_)) | (None, None) => {}
+ }
+ }
+ }
+ if !primary_spans.is_empty() {
+ let mut multi_span: MultiSpan = primary_spans.into();
+ for (span, label) in span_labels {
+ multi_span.push_span_label(span, label);
+ }
+ err.span_note(
+ multi_span,
+ format!("the method call chain might not have had the expected associated types"),
+ );
+ }
+ }
+
+ fn probe_assoc_types_at_expr(
+ &self,
+ type_diffs: &[TypeError<'tcx>],
+ span: Span,
+ prev_ty: Ty<'tcx>,
+ body_id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>> {
+ let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
+ let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len());
+ for diff in type_diffs {
+ let Sorts(expected_found) = diff else { continue; };
+ let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else { continue; };
+
+ let origin = TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span };
+ let trait_def_id = proj.trait_def_id(self.tcx);
+ // Make `Self` be equivalent to the type of the call chain
+ // expression we're looking at now, so that we can tell what
+ // for example `Iterator::Item` is at this point in the chain.
+ let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
+ match param.kind {
+ ty::GenericParamDefKind::Type { .. } => {
+ if param.index == 0 {
+ return prev_ty.into();
+ }
+ }
+ ty::GenericParamDefKind::Lifetime | ty::GenericParamDefKind::Const { .. } => {}
+ }
+ self.var_for_def(span, param)
+ });
+ // This will hold the resolved type of the associated type, if the
+ // current expression implements the trait that associated type is
+ // in. For example, this would be what `Iterator::Item` is here.
+ let ty_var = self.infcx.next_ty_var(origin);
+ // This corresponds to `<ExprTy as Iterator>::Item = _`.
+ let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection(
+ ty::ProjectionPredicate {
+ projection_ty: self.tcx.mk_alias_ty(proj.def_id, substs),
+ term: ty_var.into(),
+ },
+ )));
+ // Add `<ExprTy as Iterator>::Item = _` obligation.
+ ocx.register_obligation(Obligation::misc(
+ self.tcx, span, body_id, param_env, projection,
+ ));
+ if ocx.select_where_possible().is_empty() {
+ // `ty_var` now holds the type that `Item` is for `ExprTy`.
+ let ty_var = self.resolve_vars_if_possible(ty_var);
+ assocs_in_this_method.push(Some((span, (proj.def_id, ty_var))));
+ } else {
+ // `<ExprTy as Iterator>` didn't select, so likely we've
+ // reached the end of the iterator chain, like the originating
+ // `Vec<_>`.
+ // Keep the space consistent for later zipping.
+ assocs_in_this_method.push(None);
+ }
+ }
+ assocs_in_this_method
+ }
+}
+
+/// Add a hint to add a missing borrow or remove an unnecessary one.
+fn hint_missing_borrow<'tcx>(
+ span: Span,
+ found_span: Span,
+ found: Ty<'tcx>,
+ expected: Ty<'tcx>,
+ found_node: Node<'_>,
+ err: &mut Diagnostic,
+) {
+ let found_args = match found.kind() {
+ ty::FnPtr(f) => f.inputs().skip_binder().iter(),
+ kind => {
+ span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
+ }
+ };
+ let expected_args = match expected.kind() {
+ ty::FnPtr(f) => f.inputs().skip_binder().iter(),
+ kind => {
+ span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
+ }
+ };
+
+ let fn_decl = found_node
+ .fn_decl()
+ .unwrap_or_else(|| span_bug!(found_span, "found node must be a function"));
+
+ let arg_spans = fn_decl.inputs.iter().map(|ty| ty.span);
+
+ fn get_deref_type_and_refs<'tcx>(mut ty: Ty<'tcx>) -> (Ty<'tcx>, usize) {
+ let mut refs = 0;
+
+ while let ty::Ref(_, new_ty, _) = ty.kind() {
+ ty = *new_ty;
+ refs += 1;
+ }
+
+ (ty, refs)
+ }
+
+ let mut to_borrow = Vec::new();
+ let mut remove_borrow = Vec::new();
+
+ for ((found_arg, expected_arg), arg_span) in found_args.zip(expected_args).zip(arg_spans) {
+ let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg);
+ let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg);
+
+ if found_ty == expected_ty {
+ if found_refs < expected_refs {
+ to_borrow.push((arg_span, expected_arg.to_string()));
+ } else if found_refs > expected_refs {
+ remove_borrow.push((arg_span, expected_arg.to_string()));
+ }
+ }
+ }
+
+ if !to_borrow.is_empty() {
+ err.multipart_suggestion(
+ "consider borrowing the argument",
+ to_borrow,
+ Applicability::MaybeIncorrect,
+ );
+ }
+
+ if !remove_borrow.is_empty() {
+ err.multipart_suggestion(
+ "do not borrow the argument",
+ remove_borrow,
+ Applicability::MaybeIncorrect,
+ );
+ }
}
/// Collect all the returned expressions within the input expression.
bound: DefId,
) -> Vec<FulfillmentError<'tcx>> {
let tcx = infcx.tcx;
- let trait_ref = ty::TraitRef { def_id: bound, substs: tcx.mk_substs_trait(ty, []) };
- let obligation = Obligation {
- cause,
- recursion_depth: 0,
- param_env,
- predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
- };
+ let trait_ref = tcx.mk_trait_ref(bound, [ty]);
+ let obligation = Obligation::new(tcx, cause, param_env, ty::Binder::dummy(trait_ref));
fully_solve_obligation(infcx, obligation)
}
let pred = obligation.predicate.to_opt_poly_projection_pred()?;
Some(pred.map_bound(|p| {
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
- item_def_id: p.projection_ty.item_def_id,
+ def_id: p.projection_ty.def_id,
substs: p.projection_ty.substs,
term: p.term,
})
// U: Trait<Arg1, ..., ArgN>
let trait_predicate = {
- let substs =
- InternalSubsts::for_item(tcx, method.trait_container(tcx).unwrap(), |param, _| {
- if param.index == 0 {
- unsized_self_ty.into()
- } else {
- tcx.mk_param_from_def(param)
- }
- });
+ let trait_def_id = method.trait_container(tcx).unwrap();
+ let substs = InternalSubsts::for_item(tcx, trait_def_id, |param, _| {
+ if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
+ });
- ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs })
- .without_const()
- .to_predicate(tcx)
+ ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, substs)).to_predicate(tcx)
};
let caller_bounds: Vec<Predicate<'tcx>> =
ControlFlow::CONTINUE
}
}
- ty::Projection(ref data)
- if self.tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder =>
+ ty::Alias(ty::Projection, ref data)
+ if self.tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder =>
{
// We'll deny these later in their own pass
ControlFlow::CONTINUE
}
- ty::Projection(ref data) => {
+ ty::Alias(ty::Projection, ref data) => {
// This is a projected type `<Foo as SomeTrait>::X`.
// Compute supertraits of current trait lazily.
// FIXME(RPITIT): Perhaps we should use a visitor here?
ty.skip_binder().walk().find_map(|arg| {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Projection(proj) = ty.kind()
- && tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
+ && let ty::Alias(ty::Projection, proj) = ty.kind()
+ && tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
{
- Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.item_def_id)))
+ Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.def_id)))
} else {
None
}
pub type ProjectionObligation<'tcx> = Obligation<'tcx, ty::ProjectionPredicate<'tcx>>;
-pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::ProjectionTy<'tcx>>;
+pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::AliasTy<'tcx>>;
pub(super) struct InProgress;
// This is really important. While we *can* handle this, this has
// severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark.
- ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. })
+ if !substs.has_escaping_bound_vars() =>
+ {
// Only normalize `impl Trait` outside of type inference, usually in codegen.
match self.param_env.reveal() {
Reveal::UserFacing => ty.super_fold_with(self),
}
}
- ty::Projection(data) if !data.has_escaping_bound_vars() => {
+ ty::Alias(ty::Projection, data) if !data.has_escaping_bound_vars() => {
// This branch is *mostly* just an optimization: when we don't
// have escaping bound vars, we don't need to replace them with
// placeholders (see branch below). *Also*, we know that we can
normalized_ty.ty().unwrap()
}
- ty::Projection(data) => {
+ ty::Alias(ty::Projection, data) => {
// If there are escaping bound vars, we temporarily replace the
// bound vars with placeholders. Note though, that in the case
// that we still can't project for whatever reason (e.g. self
pub fn normalize_projection_type<'a, 'b, 'tcx>(
selcx: &'a mut SelectionContext<'b, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- projection_ty: ty::ProjectionTy<'tcx>,
+ projection_ty: ty::AliasTy<'tcx>,
cause: ObligationCause<'tcx>,
depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>,
fn opt_normalize_projection_type<'a, 'b, 'tcx>(
selcx: &'a mut SelectionContext<'b, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- projection_ty: ty::ProjectionTy<'tcx>,
+ projection_ty: ty::AliasTy<'tcx>,
cause: ObligationCause<'tcx>,
depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>,
fn normalize_to_error<'a, 'tcx>(
selcx: &mut SelectionContext<'a, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- projection_ty: ty::ProjectionTy<'tcx>,
+ projection_ty: ty::AliasTy<'tcx>,
cause: ObligationCause<'tcx>,
depth: usize,
) -> NormalizedTy<'tcx> {
predicate: trait_ref.without_const().to_predicate(selcx.tcx()),
};
let tcx = selcx.infcx.tcx;
- let def_id = projection_ty.item_def_id;
let new_value = selcx.infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::NormalizeProjectionType,
- span: tcx.def_span(def_id),
+ span: tcx.def_span(projection_ty.def_id),
});
Normalized { value: new_value, obligations: vec![trait_obligation] }
}
// need to investigate whether or not this is fine.
selcx
.tcx()
- .mk_projection(obligation.predicate.item_def_id, obligation.predicate.substs)
+ .mk_projection(obligation.predicate.def_id, obligation.predicate.substs)
.into(),
)),
// Error occurred while trying to processing impls.
candidate_set: &mut ProjectionCandidateSet<'tcx>,
) {
let tcx = selcx.tcx();
- if tcx.def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder {
- let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id);
+ if tcx.def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder {
+ let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id);
// If we are trying to project an RPITIT with trait's default `Self` parameter,
// then we must be within a default trait body.
if obligation.predicate.self_ty()
- == ty::InternalSubsts::identity_for_item(tcx, obligation.predicate.item_def_id)
- .type_at(0)
+ == ty::InternalSubsts::identity_for_item(tcx, obligation.predicate.def_id).type_at(0)
&& tcx.associated_item(trait_fn_def_id).defaultness(tcx).has_value()
{
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(
let trait_substs =
obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
// FIXME(named-returns): Binders
- let trait_predicate =
- ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs });
+ let trait_predicate = ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, trait_substs));
let _ = selcx.infcx.commit_if_ok(|_| {
match selcx.select(&obligation.with(tcx, trait_predicate)) {
// Check whether the self-type is itself a projection.
// If so, extract what we know from the trait and try to come up with a good answer.
let bounds = match *obligation.predicate.self_ty().kind() {
- ty::Projection(ref data) => tcx.bound_item_bounds(data.item_def_id).subst(tcx, data.substs),
- ty::Opaque(def_id, substs) => tcx.bound_item_bounds(def_id).subst(tcx, substs),
+ ty::Alias(_, ref data) => tcx.bound_item_bounds(data.def_id).subst(tcx, data.substs),
ty::Infer(ty::TyVar(_)) => {
// If the self-type is an inference variable, then it MAY wind up
// being a projected type, so induce an ambiguity.
};
let env_predicates = data
.projection_bounds()
- .filter(|bound| bound.item_def_id() == obligation.predicate.item_def_id)
+ .filter(|bound| bound.item_def_id() == obligation.predicate.def_id)
.map(|p| p.with_self_ty(tcx, object_ty).to_predicate(tcx));
assemble_candidates_from_predicates(
predicate.kind().skip_binder()
{
let data = bound_predicate.rebind(data);
- if data.projection_def_id() != obligation.predicate.item_def_id {
+ if data.projection_def_id() != obligation.predicate.def_id {
continue;
}
candidate_set: &mut ProjectionCandidateSet<'tcx>,
) {
// Can't assemble candidate from impl for RPITIT
- if selcx.tcx().def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder {
+ if selcx.tcx().def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder {
return;
}
// NOTE: This should be kept in sync with the similar code in
// `rustc_ty_utils::instance::resolve_associated_item()`.
let node_item =
- assoc_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id)
+ assoc_def(selcx, impl_data.impl_def_id, obligation.predicate.def_id)
.map_err(|ErrorGuaranteed { .. }| ())?;
if node_item.is_final() {
// type parameters, opaques, and unnormalized projections have pointer
// metadata if they're known (e.g. by the param_env) to be sized
ty::Param(_)
- | ty::Projection(..)
- | ty::Opaque(..)
+ | ty::Alias(..)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..)
// type parameters, opaques, and unnormalized projections have pointer
// metadata if they're known (e.g. by the param_env) to be sized
- ty::Param(_) | ty::Projection(..) | ty::Opaque(..)
+ ty::Param(_) | ty::Alias(..)
if selcx.infcx.predicate_must_hold_modulo_regions(
&obligation.with(
selcx.tcx(),
// FIXME(compiler-errors): are Bound and Placeholder types ever known sized?
ty::Param(_)
- | ty::Projection(..)
- | ty::Opaque(..)
+ | ty::Alias(..)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..)
ProjectionCandidate::ImplTraitInTrait(ImplTraitInTraitCandidate::Trait) => Progress {
term: selcx
.tcx()
- .mk_opaque(obligation.predicate.item_def_id, obligation.predicate.substs)
+ .mk_opaque(obligation.predicate.def_id, obligation.predicate.substs)
.into(),
obligations: vec![],
},
gen_sig,
)
.map_bound(|(trait_ref, yield_ty, return_ty)| {
- let name = tcx.associated_item(obligation.predicate.item_def_id).name;
+ let name = tcx.associated_item(obligation.predicate.def_id).name;
let ty = if name == sym::Return {
return_ty
} else if name == sym::Yield {
};
ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy {
- substs: trait_ref.substs,
- item_def_id: obligation.predicate.item_def_id,
- },
+ projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.substs),
term: ty.into(),
}
});
gen_sig,
)
.map_bound(|(trait_ref, return_ty)| {
- debug_assert_eq!(tcx.associated_item(obligation.predicate.item_def_id).name, sym::Output);
+ debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output);
ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy {
- substs: trait_ref.substs,
- item_def_id: obligation.predicate.item_def_id,
- },
+ projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.substs),
term: return_ty.into(),
}
});
let self_ty = obligation.predicate.self_ty();
let substs = tcx.mk_substs([self_ty.into()].iter());
let lang_items = tcx.lang_items();
- let item_def_id = obligation.predicate.item_def_id;
+ let item_def_id = obligation.predicate.def_id;
let trait_def_id = tcx.trait_of_item(item_def_id).unwrap();
let (term, obligations) = if lang_items.discriminant_kind_trait() == Some(trait_def_id) {
let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None);
};
let predicate =
- ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { substs, item_def_id }, term };
+ ty::ProjectionPredicate { projection_ty: tcx.mk_alias_ty(item_def_id, substs), term };
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
.with_addl_obligations(obligations)
flag,
)
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy {
- substs: trait_ref.substs,
- item_def_id: fn_once_output_def_id,
- },
+ projection_ty: tcx.mk_alias_ty(fn_once_output_def_id, trait_ref.substs),
term: ret_type.into(),
});
let tcx = selcx.tcx();
let ImplSourceUserDefinedData { impl_def_id, substs, mut nested } = impl_impl_source;
- let assoc_item_id = obligation.predicate.item_def_id;
+ let assoc_item_id = obligation.predicate.def_id;
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
let param_env = obligation.param_env;
let tcx = selcx.tcx();
let mut obligations = data.nested;
- let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id);
+ let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id);
let Ok(leaf_def) = assoc_def(selcx, data.impl_def_id, trait_fn_def_id) else {
return Progress { term: tcx.ty_error().into(), obligations };
};
// Use the default `impl Trait` for the trait, e.g., for a default trait body
if leaf_def.item.container == ty::AssocItemContainer::TraitContainer {
return Progress {
- term: tcx
- .mk_opaque(obligation.predicate.item_def_id, obligation.predicate.substs)
- .into(),
+ term: tcx.mk_opaque(obligation.predicate.def_id, obligation.predicate.substs).into(),
obligations,
};
}
obligation.recursion_depth + 1,
tcx.bound_trait_impl_trait_tys(impl_fn_def_id)
.map_bound(|tys| {
- tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.item_def_id])
+ tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.def_id])
})
.subst(tcx, impl_fn_substs),
&mut obligations,
) {
let tcx = selcx.tcx();
let own = tcx
- .predicates_of(obligation.predicate.item_def_id)
+ .predicates_of(obligation.predicate.def_id)
.instantiate_own(tcx, obligation.predicate.substs);
for (predicate, span) in std::iter::zip(own.predicates, own.spans) {
let normalized = normalize_with_depth_to(
ObligationCause::new(
obligation.cause.span,
obligation.cause.body_id,
- super::ItemObligation(obligation.predicate.item_def_id),
+ super::ItemObligation(obligation.predicate.def_id),
)
} else {
ObligationCause::new(
obligation.cause.span,
obligation.cause.body_id,
- super::BindingObligation(obligation.predicate.item_def_id, span),
+ super::BindingObligation(obligation.predicate.def_id, span),
)
};
nested.push(Obligation::with_depth(
// The following *might* require a destructor: needs deeper inspection.
ty::Dynamic(..)
- | ty::Projection(..)
+ | ty::Alias(..)
| ty::Param(_)
- | ty::Opaque(..)
| ty::Placeholder(..)
| ty::Infer(_)
| ty::Bound(..)
// This is really important. While we *can* handle this, this has
// severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark.
- ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. })
+ if !substs.has_escaping_bound_vars() =>
+ {
// Only normalize `impl Trait` outside of type inference, usually in codegen.
match self.param_env.reveal() {
Reveal::UserFacing => ty.try_super_fold_with(self),
}
}
- ty::Projection(data) if !data.has_escaping_bound_vars() => {
+ ty::Alias(ty::Projection, data) if !data.has_escaping_bound_vars() => {
// This branch is just an optimization: when we don't have escaping bound vars,
// we don't need to replace them with placeholders (see branch below).
}
}
- ty::Projection(data) => {
+ ty::Alias(ty::Projection, data) => {
// See note in `rustc_trait_selection::traits::project`
let tcx = self.infcx.tcx;
.kind()
.rebind(
// (*) binder moved here
- ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_type(infcx.tcx, new_self_ty)))
+ ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_ty(infcx.tcx, new_self_ty)))
),
);
// Don't report overflow errors. Otherwise equivalent to may_hold.
// Before we go into the whole placeholder thing, just
// quickly check if the self-type is a projection at all.
match obligation.predicate.skip_binder().trait_ref.self_ty().kind() {
- ty::Projection(_) | ty::Opaque(..) => {}
+ ty::Alias(..) => {}
ty::Infer(ty::TyVar(_)) => {
span_bug!(
obligation.cause.span,
// still be provided by a manual implementation for
// this trait and type.
}
- ty::Param(..) | ty::Projection(..) => {
+ ty::Param(..) | ty::Alias(ty::Projection, ..) => {
// In these cases, we don't know what the actual
// type is. Therefore, we cannot break it down
// into its constituent types. So we don't
let ty = traits::normalize_projection_type(
self,
param_env,
- ty::ProjectionTy {
- item_def_id: tcx.lang_items().deref_target()?,
- substs: trait_ref.substs,
- },
+ tcx.mk_alias_ty(tcx.lang_items().deref_target()?, trait_ref.substs),
cause.clone(),
0,
// We're *intentionally* throwing these away,
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
match self_ty.skip_binder().kind() {
- ty::Opaque(..)
+ ty::Alias(..)
| ty::Dynamic(..)
| ty::Error(_)
| ty::Bound(..)
| ty::Param(_)
- | ty::Placeholder(_)
- | ty::Projection(_) => {
+ | ty::Placeholder(_) => {
// We don't know if these are `~const Destruct`, at least
// not structurally... so don't push a candidate.
}
| ty::Generator(_, _, _)
| ty::GeneratorWitness(_)
| ty::Never
- | ty::Projection(_)
- | ty::Opaque(_, _)
+ | ty::Alias(..)
| ty::Param(_)
| ty::Bound(_, _)
| ty::Error(_)
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
let (def_id, substs) = match *placeholder_self_ty.kind() {
- ty::Projection(proj) => (proj.item_def_id, proj.substs),
- ty::Opaque(def_id, substs) => (def_id, substs),
+ ty::Alias(_, ty::AliasTy { def_id, substs, .. }) => (def_id, substs),
_ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
};
.map_err(|_| Unimplemented)
})?);
- if let ty::Projection(..) = placeholder_self_ty.kind() {
+ if let ty::Alias(ty::Projection, ..) = placeholder_self_ty.kind() {
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates;
debug!(?predicates, "projection predicates");
for predicate in predicates {
// If we have a projection type, make sure to normalize it so we replace it
// with a fresh infer variable
- ty::Projection(..) => {
+ ty::Alias(ty::Projection, ..) => {
let predicate = normalize_with_depth_to(
self,
obligation.param_env,
let tcx = self.infcx.tcx;
let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
- ty::Projection(ref data) => (data.item_def_id, data.substs),
- ty::Opaque(def_id, substs) => (def_id, substs),
+ ty::Alias(_, ty::AliasTy { def_id, substs, .. }) => (def_id, substs),
_ => {
span_bug!(
obligation.cause.span,
});
if is_match {
- let generics = self.tcx().generics_of(obligation.predicate.item_def_id);
+ let generics = self.tcx().generics_of(obligation.predicate.def_id);
// FIXME(generic-associated-types): Addresses aggressive inference in #92917.
// If this type is a GAT, and of the GAT substs resolve to something new,
// that means that we must have newly inferred something about the GAT.
}))
}
- ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None,
+ ty::Alias(..) | ty::Param(_) => None,
ty::Infer(ty::TyVar(_)) => Ambiguous,
ty::Placeholder(..)
}
}
- ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => {
+ ty::Adt(..) | ty::Alias(..) | ty::Param(..) => {
// Fallback to whatever user-defined impls exist in this case.
None
}
| ty::Dynamic(..)
| ty::Param(..)
| ty::Foreign(..)
- | ty::Projection(..)
+ | ty::Alias(ty::Projection, ..)
| ty::Bound(..)
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("asked to assemble constituent types of unexpected type: {:?}", t);
t.rebind(def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect())
}
- ty::Opaque(def_id, substs) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
// We can resolve the `impl Trait` to its concrete type,
// which enforces a DAG between the functions requiring
// the auto trait bounds in question.
ty::Foreign(_) => {
return ControlFlow::Break(ty);
}
- ty::Opaque(..) => {
- return ControlFlow::Break(ty);
- }
- ty::Projection(..) => {
+ ty::Alias(..) => {
return ControlFlow::Break(ty);
}
ty::Closure(..) => {
// projection coming from another associated type. See
// `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and
// `traits-assoc-type-in-supertrait-bad.rs`.
- if let Some(ty::Projection(projection_ty)) = proj.term.ty().map(|ty| ty.kind())
+ if let Some(ty::Alias(ty::Projection, projection_ty)) = proj.term.ty().map(|ty| ty.kind())
&& let Some(&impl_item_id) =
- tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id)
+ tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.def_id)
&& let Some(impl_item_span) = items
.iter()
.find(|item| item.id.owner_id.to_def_id() == impl_item_id)
// An associated item obligation born out of the `trait` failed to be met. An example
// can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`.
debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred);
- if let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = *pred.self_ty().kind()
+ if let ty::Alias(ty::Projection, ty::AliasTy { def_id, .. }) = *pred.self_ty().kind()
&& let Some(&impl_item_id) =
- tcx.impl_item_implementor_ids(impl_def_id).get(&item_def_id)
+ tcx.impl_item_implementor_ids(impl_def_id).get(&def_id)
&& let Some(impl_item_span) = items
.iter()
.find(|item| item.id.owner_id.to_def_id() == impl_item_id)
/// Pushes the obligations required for `trait_ref::Item` to be WF
/// into `self.out`.
- fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) {
+ fn compute_projection(&mut self, data: ty::AliasTy<'tcx>) {
// A projection is well-formed if
//
// (a) its predicates hold (*)
// `i32: Copy`
// ]
// Projection types do not require const predicates.
- let obligations = self.nominal_obligations_without_const(data.item_def_id, data.substs);
+ let obligations = self.nominal_obligations_without_const(data.def_id, data.substs);
self.out.extend(obligations);
let tcx = self.tcx();
// Simple cases that are WF if their type args are WF.
}
- ty::Projection(data) => {
+ ty::Alias(ty::Projection, data) => {
walker.skip_current_subtree(); // Subtree handled by compute_projection.
self.compute_projection(data);
}
// types appearing in the fn signature
}
- ty::Opaque(did, substs) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
// All of the requirements on type parameters
// have already been checked for `impl Trait` in
// return position. We do need to check type-alias-impl-trait though.
- if ty::is_impl_trait_defn(self.tcx, did).is_none() {
- let obligations = self.nominal_obligations(did, substs);
+ if ty::is_impl_trait_defn(self.tcx, def_id).is_none() {
+ let obligations = self.nominal_obligations(def_id, substs);
self.out.extend(obligations);
}
}
(ast::Mutability::Not, chalk_ir::Mutability::Not) => true,
}
}
- (&ty::Opaque(def_id, ..), OpaqueType(opaque_ty_id, ..)) => def_id == opaque_ty_id.0,
+ (
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }),
+ OpaqueType(opaque_ty_id, ..),
+ ) => def_id == opaque_ty_id.0,
(&ty::FnDef(def_id, ..), FnDef(fn_def_id, ..)) => def_id == fn_def_id.0,
(&ty::Str, Str) => true,
(&ty::Never, Never) => true,
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- if let ty::Opaque(def_id, substs) = *ty.kind() {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *ty.kind() {
if def_id == self.opaque_ty_id.0 && substs == self.identity_substs {
return self.tcx.mk_ty(ty::Bound(
self.binder_index,
}
}
-impl<'tcx> LowerInto<'tcx, chalk_ir::AliasTy<RustInterner<'tcx>>> for ty::ProjectionTy<'tcx> {
- fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::AliasTy<RustInterner<'tcx>> {
- chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
- associated_ty_id: chalk_ir::AssocTypeId(self.item_def_id),
- substitution: self.substs.lower_into(interner),
- })
- }
-}
-
impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'tcx>>>>
for ChalkEnvironmentAndGoal<'tcx>
{
// FIXME(associated_const_equality): teach chalk about terms for alias eq.
chalk_ir::AliasEq {
ty: self.term.ty().unwrap().lower_into(interner),
- alias: self.projection_ty.lower_into(interner),
+ alias: chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
+ associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.def_id),
+ substitution: self.projection_ty.substs.lower_into(interner),
+ }),
}
}
}
ty::Tuple(types) => {
chalk_ir::TyKind::Tuple(types.len(), types.as_substs().lower_into(interner))
}
- ty::Projection(proj) => chalk_ir::TyKind::Alias(proj.lower_into(interner)),
- ty::Opaque(def_id, substs) => {
+ ty::Alias(ty::Projection, ty::AliasTy { def_id, substs, .. }) => {
+ chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
+ associated_ty_id: chalk_ir::AssocTypeId(def_id),
+ substitution: substs.lower_into(interner),
+ }))
+ }
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
opaque_ty_id: chalk_ir::OpaqueTyId(def_id),
substitution: substs.lower_into(interner),
mutbl.lower_into(interner),
),
TyKind::Str => ty::Str,
- TyKind::OpaqueType(opaque_ty, substitution) => {
- ty::Opaque(opaque_ty.0, substitution.lower_into(interner))
- }
- TyKind::AssociatedType(assoc_ty, substitution) => ty::Projection(ty::ProjectionTy {
- substs: substitution.lower_into(interner),
- item_def_id: assoc_ty.0,
- }),
+ TyKind::OpaqueType(opaque_ty, substitution) => ty::Alias(
+ ty::Opaque,
+ interner.tcx.mk_alias_ty(opaque_ty.0, substitution.lower_into(interner)),
+ ),
+ TyKind::AssociatedType(assoc_ty, substitution) => ty::Alias(
+ ty::Projection,
+ interner.tcx.mk_alias_ty(assoc_ty.0, substitution.lower_into(interner)),
+ ),
TyKind::Foreign(def_id) => ty::Foreign(def_id.0),
TyKind::Error => return interner.tcx.ty_error(),
TyKind::Placeholder(placeholder) => ty::Placeholder(ty::Placeholder {
name: ty::BoundVar::from_usize(placeholder.idx),
}),
TyKind::Alias(alias_ty) => match alias_ty {
- chalk_ir::AliasTy::Projection(projection) => ty::Projection(ty::ProjectionTy {
- item_def_id: projection.associated_ty_id.0,
- substs: projection.substitution.lower_into(interner),
- }),
- chalk_ir::AliasTy::Opaque(opaque) => {
- ty::Opaque(opaque.opaque_ty_id.0, opaque.substitution.lower_into(interner))
- }
+ chalk_ir::AliasTy::Projection(projection) => ty::Alias(
+ ty::Projection,
+ interner.tcx.mk_alias_ty(
+ projection.associated_ty_id.0,
+ projection.substitution.lower_into(interner),
+ ),
+ ),
+ chalk_ir::AliasTy::Opaque(opaque) => ty::Alias(
+ ty::Opaque,
+ interner.tcx.mk_alias_ty(
+ opaque.opaque_ty_id.0,
+ opaque.substitution.lower_into(interner),
+ ),
+ ),
},
TyKind::Function(_quantified_ty) => unimplemented!(),
TyKind::BoundVar(_bound) => ty::Bound(
binders.clone(),
chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq {
alias: chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
- associated_ty_id: chalk_ir::AssocTypeId(predicate.item_def_id),
+ associated_ty_id: chalk_ir::AssocTypeId(predicate.def_id),
substitution: interner
.tcx
.mk_substs_trait(self_ty, predicate.substs)
let (trait_ref, own_substs) = self.projection_ty.trait_ref_and_own_substs(interner.tcx);
chalk_solve::rust_ir::AliasEqBound {
trait_bound: trait_ref.lower_into(interner),
- associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
+ associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.def_id),
parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
value: self.term.ty().unwrap().lower_into(interner),
}
// A projection that we couldn't resolve - it
// might have a destructor.
- ty::Projection(..) | ty::Opaque(..) => {
+ ty::Alias(..) => {
result.kinds.push(ty.into());
}
}
// Types that can't be resolved. Pass them forward.
- ty::Projection(..) | ty::Opaque(..) | ty::Param(..) => {
+ ty::Alias(..) | ty::Param(..) => {
constraints.dtorck_types.push(ty);
}
let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) {
debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
- resolve_associated_item(tcx, def.did, param_env, trait_def_id, substs)
+ resolve_associated_item(
+ tcx,
+ def.did,
+ param_env,
+ trait_def_id,
+ tcx.normalize_erasing_regions(param_env, substs),
+ )
} else {
let ty = tcx.type_of(def.def_id_for_type_of());
let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty);
}
// Types with no meaningful known layout.
- ty::Projection(_) | ty::Opaque(..) => {
+ ty::Alias(..) => {
// NOTE(eddyb) `layout_of` query should've normalized these away,
// if that was possible, so there's no reason to try again here.
return Err(LayoutError::Unknown(ty));
def_id: DefId,
substs: ty::SubstsRef<'tcx>,
) -> (Vec<VariantInfo>, Option<Size>) {
- let Variants::Multiple { tag, ref tag_encoding, .. } = layout.variants else {
+ let Variants::Multiple { tag, ref tag_encoding, tag_field, .. } = layout.variants else {
return (vec![], None);
};
if variant_size == Size::ZERO {
variant_size = upvars_size;
}
- // We need to add the discriminant size back into min_size, since it is subtracted
- // later during printing.
- variant_size += match tag_encoding {
- TagEncoding::Direct => tag.size(cx),
- _ => Size::ZERO,
- };
+
+ // This `if` deserves some explanation.
+ //
+ // The layout code has a choice of where to place the discriminant of this generator.
+ // If the discriminant of the generator is placed early in the layout (before the
+ // variant's own fields), then it'll implicitly be counted towards the size of the
+ // variant, since we use the maximum offset to calculate size.
+ // (side-note: I know this is a bit problematic given upvars placement, etc).
+ //
+ // This is important, since the layout printing code always subtracts this discriminant
+ // size from the variant size if the struct is "enum"-like, so failing to account for it
+ // will either lead to numerical underflow, or an underreported variant size...
+ //
+ // However, if the discriminant is placed past the end of the variant, then we need
+ // to factor in the size of the discriminant manually. This really should be refactored
+ // better, but this "works" for now.
+ if layout.fields.offset(tag_field) >= variant_size {
+ variant_size += match tag_encoding {
+ TagEncoding::Direct => tag.size(cx),
+ _ => Size::ZERO,
+ };
+ }
VariantInfo {
name: Some(Symbol::intern(&ty::GeneratorSubsts::variant_name(variant_idx))),
queue_type(self, required);
}
}
- ty::Array(..) | ty::Opaque(..) | ty::Projection(..) | ty::Param(_) => {
+ ty::Array(..) | ty::Alias(..) | ty::Param(_) => {
if ty == component {
// Return the type to the caller: they may be able
// to normalize further than we can.
.collect()
}
- Projection(..) | Opaque(..) => {
+ Alias(..) => {
// must calculate explicitly.
// FIXME: consider special-casing always-Sized projections
vec![ty]
type ListBinderExistentialPredicate: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
type BinderListTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
type ListTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type ProjectionTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+ type AliasTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
type ParamTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
type BoundTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
type PlaceholderType: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
use rustc_serialize::{Decodable, Decoder, Encodable};
/// Specifies how a trait object is represented.
-#[derive(
- Clone,
- Copy,
- PartialEq,
- Eq,
- PartialOrd,
- Ord,
- Hash,
- Debug,
- Encodable,
- Decodable,
- HashStable_Generic
-)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
pub enum DynKind {
/// An unsized `dyn Trait` object
Dyn,
DynStar,
}
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
+pub enum AliasKind {
+ Projection,
+ Opaque,
+}
+
/// Defines the kinds of types used by the type system.
///
/// Types written by the user start out as `hir::TyKind` and get
/// A tuple type. For example, `(i32, bool)`.
Tuple(I::ListTy),
- /// The projection of an associated type. For example,
- /// `<T as Trait<..>>::N`.
- Projection(I::ProjectionTy),
-
- /// Opaque (`impl Trait`) type found in a return type.
- ///
- /// The `DefId` comes either from
- /// * the `impl Trait` ast::Ty node,
- /// * or the `type Foo = impl Trait` declaration
- ///
- /// For RPIT the substitutions are for the generics of the function,
- /// while for TAIT it is used for the generic parameters of the alias.
- ///
- /// During codegen, `tcx.type_of(def_id)` can be used to get the underlying type.
- Opaque(I::DefId, I::SubstsRef),
+ /// A projection or opaque type. Both of these types
+ Alias(AliasKind, I::AliasTy),
/// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
Param(I::ParamTy),
GeneratorWitness(_) => 17,
Never => 18,
Tuple(_) => 19,
- Projection(_) => 20,
- Opaque(_, _) => 21,
- Param(_) => 22,
- Bound(_, _) => 23,
- Placeholder(_) => 24,
- Infer(_) => 25,
- Error(_) => 26,
+ Alias(_, _) => 20,
+ Param(_) => 21,
+ Bound(_, _) => 22,
+ Placeholder(_) => 23,
+ Infer(_) => 24,
+ Error(_) => 25,
}
}
match self {
Bool => Bool,
Char => Char,
- Int(i) => Int(i.clone()),
- Uint(u) => Uint(u.clone()),
- Float(f) => Float(f.clone()),
+ Int(i) => Int(*i),
+ Uint(u) => Uint(*u),
+ Float(f) => Float(*f),
Adt(d, s) => Adt(d.clone(), s.clone()),
Foreign(d) => Foreign(d.clone()),
Str => Str,
Ref(r, t, m) => Ref(r.clone(), t.clone(), m.clone()),
FnDef(d, s) => FnDef(d.clone(), s.clone()),
FnPtr(s) => FnPtr(s.clone()),
- Dynamic(p, r, repr) => Dynamic(p.clone(), r.clone(), repr.clone()),
+ Dynamic(p, r, repr) => Dynamic(p.clone(), r.clone(), *repr),
Closure(d, s) => Closure(d.clone(), s.clone()),
Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()),
GeneratorWitness(g) => GeneratorWitness(g.clone()),
Never => Never,
Tuple(t) => Tuple(t.clone()),
- Projection(p) => Projection(p.clone()),
- Opaque(d, s) => Opaque(d.clone(), s.clone()),
+ Alias(k, p) => Alias(*k, p.clone()),
Param(p) => Param(p.clone()),
- Bound(d, b) => Bound(d.clone(), b.clone()),
+ Bound(d, b) => Bound(*d, b.clone()),
Placeholder(p) => Placeholder(p.clone()),
Infer(t) => Infer(t.clone()),
Error(e) => Error(e.clone()),
}
(GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g,
(Tuple(a_t), Tuple(b_t)) => a_t == b_t,
- (Projection(a_p), Projection(b_p)) => a_p == b_p,
- (Opaque(a_d, a_s), Opaque(b_d, b_s)) => a_d == b_d && a_s == b_s,
+ (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p,
(Param(a_p), Param(b_p)) => a_p == b_p,
(Bound(a_d, a_b), Bound(b_d, b_b)) => a_d == b_d && a_b == b_b,
(Placeholder(a_p), Placeholder(b_p)) => a_p == b_p,
}
(GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g.cmp(b_g),
(Tuple(a_t), Tuple(b_t)) => a_t.cmp(b_t),
- (Projection(a_p), Projection(b_p)) => a_p.cmp(b_p),
- (Opaque(a_d, a_s), Opaque(b_d, b_s)) => a_d.cmp(b_d).then_with(|| a_s.cmp(b_s)),
+ (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i.cmp(b_i).then_with(|| a_p.cmp(b_p)),
(Param(a_p), Param(b_p)) => a_p.cmp(b_p),
(Bound(a_d, a_b), Bound(b_d, b_b)) => a_d.cmp(b_d).then_with(|| a_b.cmp(b_b)),
(Placeholder(a_p), Placeholder(b_p)) => a_p.cmp(b_p),
}
GeneratorWitness(g) => g.hash(state),
Tuple(t) => t.hash(state),
- Projection(p) => p.hash(state),
- Opaque(d, s) => {
- d.hash(state);
- s.hash(state)
+ Alias(i, p) => {
+ i.hash(state);
+ p.hash(state);
}
Param(p) => p.hash(state),
Bound(d, b) => {
GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", g),
Never => f.write_str("Never"),
Tuple(t) => f.debug_tuple_field1_finish("Tuple", t),
- Projection(p) => f.debug_tuple_field1_finish("Projection", p),
- Opaque(d, s) => f.debug_tuple_field2_finish("Opaque", d, s),
+ Alias(i, a) => f.debug_tuple_field2_finish("Alias", i, a),
Param(p) => f.debug_tuple_field1_finish("Param", p),
Bound(d, b) => f.debug_tuple_field2_finish("Bound", d, b),
Placeholder(p) => f.debug_tuple_field1_finish("Placeholder", p),
I::ListBinderExistentialPredicate: Encodable<E>,
I::BinderListTy: Encodable<E>,
I::ListTy: Encodable<E>,
- I::ProjectionTy: Encodable<E>,
+ I::AliasTy: Encodable<E>,
I::ParamTy: Encodable<E>,
I::BoundTy: Encodable<E>,
I::PlaceholderType: Encodable<E>,
Tuple(substs) => e.emit_enum_variant(disc, |e| {
substs.encode(e);
}),
- Projection(p) => e.emit_enum_variant(disc, |e| {
+ Alias(k, p) => e.emit_enum_variant(disc, |e| {
+ k.encode(e);
p.encode(e);
}),
- Opaque(def_id, substs) => e.emit_enum_variant(disc, |e| {
- def_id.encode(e);
- substs.encode(e);
- }),
Param(p) => e.emit_enum_variant(disc, |e| {
p.encode(e);
}),
I::ListBinderExistentialPredicate: Decodable<D>,
I::BinderListTy: Decodable<D>,
I::ListTy: Decodable<D>,
- I::ProjectionTy: Decodable<D>,
+ I::AliasTy: Decodable<D>,
I::ParamTy: Decodable<D>,
+ I::AliasTy: Decodable<D>,
I::BoundTy: Decodable<D>,
I::PlaceholderType: Decodable<D>,
I::InferTy: Decodable<D>,
17 => GeneratorWitness(Decodable::decode(d)),
18 => Never,
19 => Tuple(Decodable::decode(d)),
- 20 => Projection(Decodable::decode(d)),
- 21 => Opaque(Decodable::decode(d), Decodable::decode(d)),
- 22 => Param(Decodable::decode(d)),
- 23 => Bound(Decodable::decode(d), Decodable::decode(d)),
- 24 => Placeholder(Decodable::decode(d)),
- 25 => Infer(Decodable::decode(d)),
- 26 => Error(Decodable::decode(d)),
+ 20 => Alias(Decodable::decode(d), Decodable::decode(d)),
+ 21 => Param(Decodable::decode(d)),
+ 22 => Bound(Decodable::decode(d), Decodable::decode(d)),
+ 23 => Placeholder(Decodable::decode(d)),
+ 24 => Infer(Decodable::decode(d)),
+ 25 => Error(Decodable::decode(d)),
_ => panic!(
"{}",
format!(
I::Mutability: HashStable<CTX>,
I::BinderListTy: HashStable<CTX>,
I::ListTy: HashStable<CTX>,
- I::ProjectionTy: HashStable<CTX>,
+ I::AliasTy: HashStable<CTX>,
I::BoundTy: HashStable<CTX>,
I::ParamTy: HashStable<CTX>,
I::PlaceholderType: HashStable<CTX>,
Tuple(substs) => {
substs.hash_stable(__hcx, __hasher);
}
- Projection(p) => {
+ Alias(k, p) => {
+ k.hash_stable(__hcx, __hasher);
p.hash_stable(__hcx, __hasher);
}
- Opaque(def_id, substs) => {
- def_id.hash_stable(__hcx, __hasher);
- substs.hash_stable(__hcx, __hasher);
- }
Param(p) => {
p.hash_stable(__hcx, __hasher);
}
fn clone(&self) -> Self {
match self {
ReEarlyBound(r) => ReEarlyBound(r.clone()),
- ReLateBound(d, r) => ReLateBound(d.clone(), r.clone()),
+ ReLateBound(d, r) => ReLateBound(*d, r.clone()),
ReFree(r) => ReFree(r.clone()),
ReStatic => ReStatic,
ReVar(r) => ReVar(r.clone()),
/// to be modified, it can additionally implement [`BorrowMut<T>`].
///
/// Further, when providing implementations for additional traits, it needs
-/// to be considered whether they should behave identical to those of the
+/// to be considered whether they should behave identically to those of the
/// underlying type as a consequence of acting as a representation of that
/// underlying type. Generic code typically uses `Borrow<T>` when it relies
/// on the identical behavior of these additional trait implementations.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "iterator_collect_fn")]
fn collect<B: FromIterator<Self::Item>>(self) -> B
where
Self: Sized,
//! }
//! ```
//!
+//! # The question mark operator, `?`
+//!
+//! Similar to the [`Result`] type, when writing code that calls many functions that return the
+//! [`Option`] type, handling `Some`/`None` can be tedious. The question mark
+//! operator, [`?`], hides some of the boilerplate of propagating values
+//! up the call stack.
+//!
+//! It replaces this:
+//!
+//! ```
+//! # #![allow(dead_code)]
+//! fn add_last_numbers(stack: &mut Vec<i32>) -> Option<i32> {
+//! let a = stack.pop();
+//! let b = stack.pop();
+//!
+//! match (a, b) {
+//! (Some(x), Some(y)) => Some(x + y),
+//! _ => None,
+//! }
+//! }
+//!
+//! ```
+//!
+//! With this:
+//!
+//! ```
+//! # #![allow(dead_code)]
+//! fn add_last_numbers(stack: &mut Vec<i32>) -> Option<i32> {
+//! Some(stack.pop()? + stack.pop()?)
+//! }
+//! ```
+//!
+//! *It's much nicer!*
+//!
+//! Ending the expression with [`?`] will result in the [`Some`]'s unwrapped value, unless the
+//! result is [`None`], in which case [`None`] is returned early from the enclosing function.
+//!
+//! [`?`] can be used in functions that return [`Option`] because of the
+//! early return of [`None`] that it provides.
+//!
+//! [`?`]: crate::ops::Try
+//! [`Some`]: Some
+//! [`None`]: None
+//!
//! # Representation
//!
//! Rust guarantees to optimize the following types `T` such that
//!
//! *It's much nicer!*
//!
-//! Ending the expression with [`?`] will result in the unwrapped
-//! success ([`Ok`]) value, unless the result is [`Err`], in which case
-//! [`Err`] is returned early from the enclosing function.
+//! Ending the expression with [`?`] will result in the [`Ok`]'s unwrapped value, unless the result
+//! is [`Err`], in which case [`Err`] is returned early from the enclosing function.
//!
-//! [`?`] can only be used in functions that return [`Result`] because of the
+//! [`?`] can be used in functions that return [`Result`] because of the
//! early return of [`Err`] that it provides.
//!
//! [`expect`]: Result::expect
unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) }
}
- /// Build a _mutable_ references to an `Exclusive<T>` from
+ /// Build a _mutable_ reference to an `Exclusive<T>` from
/// a _mutable_ reference to a `T`. This allows you to skip
/// building an `Exclusive` with [`Exclusive::new`].
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
unsafe { &mut *(r as *mut T as *mut Exclusive<T>) }
}
- /// Build a _pinned mutable_ references to an `Exclusive<T>` from
+ /// Build a _pinned mutable_ reference to an `Exclusive<T>` from
/// a _pinned mutable_ reference to a `T`. This allows you to skip
/// building an `Exclusive` with [`Exclusive::new`].
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
use std::ffi::OsStr;
/// Retrieve an environment variable and add it to build dependency info.
- /// Build system executing the compiler will know that the variable was accessed during
+ /// The build system executing the compiler will know that the variable was accessed during
/// compilation, and will be able to rerun the build when the value of that variable changes.
/// Besides the dependency tracking this function should be equivalent to `env::var` from the
/// standard library, except that the argument must be UTF-8.
use crate::sys::common::small_c_string::run_path_with_cstr;
use crate::sys::{cvt, cvt_r};
- #[cfg(not(all(target_os = "macos", not(target_arch = "aarch64")),))]
+ #[cfg(not(any(
+ target_os = "linux",
+ all(target_os = "macos", not(target_arch = "aarch64"))
+ )))]
use libc::{fdopendir, openat, unlinkat};
+ #[cfg(target_os = "linux")]
+ use libc::{fdopendir, openat64 as openat, unlinkat};
#[cfg(all(target_os = "macos", not(target_arch = "aarch64")))]
use macos_weak::{fdopendir, openat, unlinkat};
use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use crate::sys::cvt;
use crate::sys::weak::syscall;
+#[cfg(not(target_os = "linux"))]
+use libc::sendfile as sendfile64;
+#[cfg(target_os = "linux")]
+use libc::sendfile64;
use libc::{EBADF, EINVAL, ENOSYS, EOPNOTSUPP, EOVERFLOW, EPERM, EXDEV};
#[cfg(test)]
let result = match mode {
SpliceMode::Sendfile => {
- cvt(unsafe { libc::sendfile(writer, reader, ptr::null_mut(), chunk_size) })
+ cvt(unsafe { sendfile64(writer, reader, ptr::null_mut(), chunk_size) })
}
SpliceMode::Splice => cvt(unsafe {
splice(reader, ptr::null_mut(), writer, ptr::null_mut(), chunk_size, 0)
)))]
'poll: {
use crate::sys::os::errno;
+ #[cfg(not(target_os = "linux"))]
+ use libc::open as open64;
+ #[cfg(target_os = "linux")]
+ use libc::open64;
let pfds: &mut [_] = &mut [
libc::pollfd { fd: 0, events: 0, revents: 0 },
libc::pollfd { fd: 1, events: 0, revents: 0 },
if pfd.revents & libc::POLLNVAL == 0 {
continue;
}
- if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+ if open64("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
// If the stream is closed but we failed to reopen it, abort the
// process. Otherwise we wouldn't preserve the safety of
// operations on the corresponding Rust object Stdin, Stdout, or
)))]
{
use crate::sys::os::errno;
+ #[cfg(not(target_os = "linux"))]
+ use libc::open as open64;
+ #[cfg(target_os = "linux")]
+ use libc::open64;
for fd in 0..3 {
if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
- if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+ if open64("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
// If the stream is closed but we failed to reopen it, abort the
// process. Otherwise we wouldn't preserve the safety of
// operations on the corresponding Rust object Stdin, Stdout, or
//
// Note that as soon as we're done with the fork there's no need to hold
// a lock any more because the parent won't do anything and the child is
- // in its own process. Thus the parent drops the lock guard while the child
- // forgets it to avoid unlocking it on a new thread, which would be invalid.
+ // in its own process. Thus the parent drops the lock guard immediately.
+ // The child calls `mem::forget` to leak the lock, which is crucial because
+ // releasing a lock is not async-signal-safe.
let env_lock = sys::os::env_read_lock();
let (pid, pidfd) = unsafe { self.do_fork()? };
if pid == 0 {
crate::panic::always_abort();
- mem::forget(env_lock);
+ mem::forget(env_lock); // avoid non-async-signal-safe unlocking
drop(input);
let Err(err) = unsafe { self.do_exec(theirs, envp.as_ref()) };
let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32;
use crate::thread;
use libc::MAP_FAILED;
- use libc::{mmap, munmap};
+ #[cfg(not(target_os = "linux"))]
+ use libc::{mmap as mmap64, munmap};
+ #[cfg(target_os = "linux")]
+ use libc::{mmap64, munmap};
use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL};
use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV};
#[cfg(not(any(target_os = "openbsd", target_os = "netbsd", target_os = "linux",)))]
let flags = MAP_PRIVATE | MAP_ANON;
let stackp =
- mmap(ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, flags, -1, 0);
+ mmap64(ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, flags, -1, 0);
if stackp == MAP_FAILED {
panic!("failed to allocate an alternative stack: {}", io::Error::last_os_error());
}
))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
- use libc::{mmap, mprotect};
+ #[cfg(not(target_os = "linux"))]
+ use libc::{mmap as mmap64, mprotect};
+ #[cfg(target_os = "linux")]
+ use libc::{mmap64, mprotect};
use libc::{MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
use crate::io;
// read/write permissions and only then mprotect() it to
// no permissions at all. See issue #50313.
let stackptr = get_stack_start_aligned()?;
- let result = mmap(
+ let result = mmap64(
stackptr,
page_size,
PROT_READ | PROT_WRITE,
impl<T: Internable + Deref> Deref for Interned<T> {
type Target = T::Target;
- fn deref(&self) -> &'static Self::Target {
+ fn deref(&self) -> &Self::Target {
let l = T::intern_cache().lock().unwrap();
- unsafe { mem::transmute::<&Self::Target, &'static Self::Target>(l.get(*self)) }
+ unsafe { mem::transmute::<&Self::Target, &Self::Target>(l.get(*self)) }
}
}
impl<T: Internable + AsRef<U>, U: ?Sized> AsRef<U> for Interned<T> {
- fn as_ref(&self) -> &'static U {
+ fn as_ref(&self) -> &U {
let l = T::intern_cache().lock().unwrap();
- unsafe { mem::transmute::<&U, &'static U>(l.get(*self).as_ref()) }
+ unsafe { mem::transmute::<&U, &U>(l.get(*self).as_ref()) }
}
}
let xform = |p: &Path| {
let mut contents = t!(fs::read_to_string(p));
- for tool in &["rust-demangler"] {
+ for tool in &["rust-demangler", "miri"] {
if !built_tools.contains(tool) {
contents = filter(&contents, tool);
}
prepare("rust-std");
prepare("rust-analysis");
prepare("clippy");
- prepare("miri");
prepare("rust-analyzer");
- for tool in &["rust-docs", "rust-demangler"] {
+ for tool in &["rust-docs", "rust-demangler", "miri"] {
if built_tools.contains(tool) {
prepare(tool);
}
prepare("rust-docs");
prepare("rust-std");
prepare("clippy");
- prepare("miri");
prepare("rust-analyzer");
- for tool in &["rust-demangler"] {
+ for tool in &["rust-demangler", "miri"] {
if built_tools.contains(tool) {
prepare(tool);
}
.arg(etc.join("msi/remove-duplicates.xsl")),
);
}
- builder.run(
- Command::new(&heat)
- .current_dir(&exe)
- .arg("dir")
- .arg("miri")
- .args(&heat_flags)
- .arg("-cg")
- .arg("MiriGroup")
- .arg("-dr")
- .arg("Miri")
- .arg("-var")
- .arg("var.MiriDir")
- .arg("-out")
- .arg(exe.join("MiriGroup.wxs"))
- .arg("-t")
- .arg(etc.join("msi/remove-duplicates.xsl")),
- );
+ if built_tools.contains("miri") {
+ builder.run(
+ Command::new(&heat)
+ .current_dir(&exe)
+ .arg("dir")
+ .arg("miri")
+ .args(&heat_flags)
+ .arg("-cg")
+ .arg("MiriGroup")
+ .arg("-dr")
+ .arg("Miri")
+ .arg("-var")
+ .arg("var.MiriDir")
+ .arg("-out")
+ .arg(exe.join("MiriGroup.wxs"))
+ .arg("-t")
+ .arg(etc.join("msi/remove-duplicates.xsl")),
+ );
+ }
builder.run(
Command::new(&heat)
.current_dir(&exe)
.arg("-dStdDir=rust-std")
.arg("-dAnalysisDir=rust-analysis")
.arg("-dClippyDir=clippy")
- .arg("-dMiriDir=miri")
.arg("-arch")
.arg(&arch)
.arg("-out")
if built_tools.contains("rust-analyzer") {
cmd.arg("-dRustAnalyzerDir=rust-analyzer");
}
+ if built_tools.contains("miri") {
+ cmd.arg("-dMiriDir=miri");
+ }
if target.ends_with("windows-gnu") {
cmd.arg("-dGccDir=rust-mingw");
}
candle("CargoGroup.wxs".as_ref());
candle("StdGroup.wxs".as_ref());
candle("ClippyGroup.wxs".as_ref());
- candle("MiriGroup.wxs".as_ref());
+ if built_tools.contains("miri") {
+ candle("MiriGroup.wxs".as_ref());
+ }
if built_tools.contains("rust-demangler") {
candle("RustDemanglerGroup.wxs".as_ref());
}
.arg("StdGroup.wixobj")
.arg("AnalysisGroup.wixobj")
.arg("ClippyGroup.wixobj")
- .arg("MiriGroup.wixobj")
.current_dir(&exe);
+ if built_tools.contains("miri") {
+ cmd.arg("MiriGroup.wixobj");
+ }
if built_tools.contains("rust-analyzer") {
cmd.arg("RustAnalyzerGroup.wixobj");
}
"-f",
self.ssh_keyfile_path(),
"-C",
- "Generated by test_toolchain.py",
+ "Generated by fuchsia-test-runner.py",
],
stdout=self.subprocess_output(),
stderr=self.subprocess_output(),
- name: dist-x86_64-apple
env:
SCRIPT: ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin
- RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin
+ RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
MACOSX_DEPLOYMENT_TARGET: 10.7
SELECT_XCODE: /Applications/Xcode_13.4.1.app
discard_positive_impl: bool,
) -> Option<Item> {
let tcx = self.cx.tcx;
- let trait_ref = tcx.mk_trait_ref(trait_def_id, [ty]);
+ let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, [ty]));
if !self.cx.generated_synthetics.insert((ty, trait_def_id)) {
debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref);
return None;
unsafety: hir::Unsafety::Normal,
generics: new_generics,
trait_: Some(clean_trait_ref_with_bindings(self.cx, trait_ref, ThinVec::new())),
- for_: clean_middle_ty(ty, self.cx, None),
+ for_: clean_middle_ty(ty::Binder::dummy(ty), self.cx, None),
items: Vec::new(),
polarity,
kind: ImplKind::Auto,
// the post-inference `trait_ref`, as it's more accurate.
trait_: Some(clean_trait_ref_with_bindings(
cx,
- trait_ref.0,
+ ty::Binder::dummy(trait_ref.0),
ThinVec::new(),
)),
- for_: clean_middle_ty(ty.0, cx, None),
+ for_: clean_middle_ty(ty::Binder::dummy(ty.0), cx, None),
items: cx
.tcx
.associated_items(impl_def_id)
.collect::<Vec<_>>(),
polarity: ty::ImplPolarity::Positive,
kind: ImplKind::Blanket(Box::new(clean_middle_ty(
- trait_ref.0.self_ty(),
+ ty::Binder::dummy(trait_ref.0.self_ty()),
cx,
None,
))),
fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box<clean::Typedef> {
let predicates = cx.tcx.explicit_predicates_of(did);
- let type_ = clean_middle_ty(cx.tcx.type_of(did), cx, Some(did));
+ let type_ = clean_middle_ty(ty::Binder::dummy(cx.tcx.type_of(did)), cx, Some(did));
Box::new(clean::Typedef {
type_,
let for_ = match &impl_item {
Some(impl_) => clean_ty(impl_.self_ty, cx),
- None => clean_middle_ty(tcx.type_of(did), cx, Some(did)),
+ None => clean_middle_ty(ty::Binder::dummy(tcx.type_of(did)), cx, Some(did)),
};
// Only inline impl if the implementing type is
),
};
let polarity = tcx.impl_polarity(did);
- let trait_ = associated_trait.map(|t| clean_trait_ref_with_bindings(cx, t, ThinVec::new()));
+ let trait_ = associated_trait
+ .map(|t| clean_trait_ref_with_bindings(cx, ty::Binder::dummy(t), ThinVec::new()));
if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
super::build_deref_target_impls(cx, &trait_items, ret);
}
fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant {
clean::Constant {
- type_: clean_middle_ty(cx.tcx.type_of(def_id), cx, Some(def_id)),
+ type_: clean_middle_ty(ty::Binder::dummy(cx.tcx.type_of(def_id)), cx, Some(def_id)),
kind: clean::ConstantKind::Extern { def_id },
}
}
fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::Static {
clean::Static {
- type_: clean_middle_ty(cx.tcx.type_of(did), cx, Some(did)),
+ type_: clean_middle_ty(ty::Binder::dummy(cx.tcx.type_of(did)), cx, Some(did)),
mutability: if mutable { Mutability::Mut } else { Mutability::Not },
expr: None,
}
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::InternalSubsts;
+use rustc_middle::ty::TypeVisitable;
use rustc_middle::ty::{self, AdtKind, DefIdTree, EarlyBinder, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::hygiene::{AstPass, MacroKind};
hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
- let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder();
+ let trait_ref = ty::TraitRef::identity(cx.tcx, def_id);
let generic_args = clean_generic_args(generic_args, cx);
let GenericArgs::AngleBracketed { bindings, .. } = generic_args
pub(crate) fn clean_trait_ref_with_bindings<'tcx>(
cx: &mut DocContext<'tcx>,
- trait_ref: ty::TraitRef<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
bindings: ThinVec<TypeBinding>,
) -> Path {
- let kind = cx.tcx.def_kind(trait_ref.def_id).into();
+ let kind = cx.tcx.def_kind(trait_ref.def_id()).into();
if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
- span_bug!(cx.tcx.def_span(trait_ref.def_id), "`TraitRef` had unexpected kind {:?}", kind);
+ span_bug!(cx.tcx.def_span(trait_ref.def_id()), "`TraitRef` had unexpected kind {:?}", kind);
}
- inline::record_extern_fqn(cx, trait_ref.def_id, kind);
- let path = external_path(cx, trait_ref.def_id, true, bindings, trait_ref.substs);
+ inline::record_extern_fqn(cx, trait_ref.def_id(), kind);
+ let path =
+ external_path(cx, trait_ref.def_id(), true, bindings, trait_ref.map_bound(|tr| tr.substs));
- debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs);
+ debug!(?trait_ref);
path
}
})
.collect();
- let trait_ = clean_trait_ref_with_bindings(cx, poly_trait_ref.skip_binder(), bindings);
+ let trait_ = clean_trait_ref_with_bindings(cx, poly_trait_ref, bindings);
GenericBound::TraitBound(
PolyTrait { trait_, generic_params: late_bound_regions },
hir::TraitBoundModifier::None,
pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'tcx>) -> Constant {
let def_id = cx.tcx.hir().body_owner_def_id(constant.value.body).to_def_id();
Constant {
- type_: clean_middle_ty(cx.tcx.type_of(def_id), cx, Some(def_id)),
+ type_: clean_middle_ty(ty::Binder::dummy(cx.tcx.type_of(def_id)), cx, Some(def_id)),
kind: ConstantKind::Anonymous { body: constant.value.body },
}
}
pub(crate) fn clean_middle_const<'tcx>(
- constant: ty::Const<'tcx>,
+ constant: ty::Binder<'tcx, ty::Const<'tcx>>,
cx: &mut DocContext<'tcx>,
) -> Constant {
// FIXME: instead of storing the stringified expression, store `self` directly instead.
Constant {
- type_: clean_middle_ty(constant.ty(), cx, None),
- kind: ConstantKind::TyConst { expr: constant.to_string().into() },
+ type_: clean_middle_ty(constant.map_bound(|c| c.ty()), cx, None),
+ kind: ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() },
}
}
let poly_trait_ref = pred.map_bound(|pred| pred.trait_ref);
Some(WherePredicate::BoundPredicate {
- ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None),
+ ty: clean_middle_ty(poly_trait_ref.self_ty(), cx, None),
bounds: vec![clean_poly_trait_ref_with_bindings(cx, poly_trait_ref, ThinVec::new())],
bound_params: Vec::new(),
})
let ty::OutlivesPredicate(ty, lt) = pred;
Some(WherePredicate::BoundPredicate {
- ty: clean_middle_ty(ty, cx, None),
+ ty: clean_middle_ty(ty::Binder::dummy(ty), cx, None),
bounds: vec![GenericBound::Outlives(
clean_middle_region(lt).expect("failed to clean lifetimes"),
)],
})
}
-fn clean_middle_term<'tcx>(term: ty::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term {
- match term.unpack() {
- ty::TermKind::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)),
- ty::TermKind::Const(c) => Term::Constant(clean_middle_const(c, cx)),
+fn clean_middle_term<'tcx>(
+ term: ty::Binder<'tcx, ty::Term<'tcx>>,
+ cx: &mut DocContext<'tcx>,
+) -> Term {
+ match term.skip_binder().unpack() {
+ ty::TermKind::Ty(ty) => Term::Type(clean_middle_ty(term.rebind(ty), cx, None)),
+ ty::TermKind::Const(c) => Term::Constant(clean_middle_const(term.rebind(c), cx)),
}
}
hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)),
hir::Term::Const(c) => {
let def_id = cx.tcx.hir().local_def_id(c.hir_id);
- Term::Constant(clean_middle_const(ty::Const::from_anon_const(cx.tcx, def_id), cx))
+ Term::Constant(clean_middle_const(
+ ty::Binder::dummy(ty::Const::from_anon_const(cx.tcx, def_id)),
+ cx,
+ ))
}
}
}
})
.collect();
- let ty::ProjectionPredicate { projection_ty, term } = pred.skip_binder();
-
WherePredicate::EqPredicate {
- lhs: Box::new(clean_projection(projection_ty, cx, None)),
- rhs: Box::new(clean_middle_term(term, cx)),
+ lhs: Box::new(clean_projection(pred.map_bound(|p| p.projection_ty), cx, None)),
+ rhs: Box::new(clean_middle_term(pred.map_bound(|p| p.term), cx)),
bound_params: late_bound_regions,
}
}
fn clean_projection<'tcx>(
- ty: ty::ProjectionTy<'tcx>,
+ ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>,
cx: &mut DocContext<'tcx>,
def_id: Option<DefId>,
) -> Type {
- if cx.tcx.def_kind(ty.item_def_id) == DefKind::ImplTraitPlaceholder {
+ if cx.tcx.def_kind(ty.skip_binder().def_id) == DefKind::ImplTraitPlaceholder {
let bounds = cx
.tcx
- .explicit_item_bounds(ty.item_def_id)
+ .explicit_item_bounds(ty.skip_binder().def_id)
.iter()
- .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, ty.substs))
+ .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, ty.skip_binder().substs))
.collect::<Vec<_>>();
return clean_middle_opaque_bounds(cx, bounds);
}
- let trait_ = clean_trait_ref_with_bindings(cx, ty.trait_ref(cx.tcx), ThinVec::new());
- let self_type = clean_middle_ty(ty.self_ty(), cx, None);
+ let trait_ =
+ clean_trait_ref_with_bindings(cx, ty.map_bound(|ty| ty.trait_ref(cx.tcx)), ThinVec::new());
+ let self_type = clean_middle_ty(ty.map_bound(|ty| ty.self_ty()), cx, None);
let self_def_id = if let Some(def_id) = def_id {
cx.tcx.opt_parent(def_id).or(Some(def_id))
} else {
}
fn projection_to_path_segment<'tcx>(
- ty: ty::ProjectionTy<'tcx>,
+ ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>,
cx: &mut DocContext<'tcx>,
) -> PathSegment {
- let item = cx.tcx.associated_item(ty.item_def_id);
- let generics = cx.tcx.generics_of(ty.item_def_id);
+ let item = cx.tcx.associated_item(ty.skip_binder().def_id);
+ let generics = cx.tcx.generics_of(ty.skip_binder().def_id);
PathSegment {
name: item.name,
args: GenericArgs::AngleBracketed {
- args: substs_to_args(cx, &ty.substs[generics.parent_count..], false).into(),
+ args: substs_to_args(cx, ty.map_bound(|ty| &ty.substs[generics.parent_count..]), false)
+ .into(),
bindings: Default::default(),
},
}
}
ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
let default = if has_default {
- Some(clean_middle_ty(cx.tcx.type_of(def.def_id), cx, Some(def.def_id)))
+ Some(clean_middle_ty(
+ ty::Binder::dummy(cx.tcx.type_of(def.def_id)),
+ cx,
+ Some(def.def_id),
+ ))
} else {
None
};
def.name,
GenericParamDefKind::Const {
did: def.def_id,
- ty: Box::new(clean_middle_ty(cx.tcx.type_of(def.def_id), cx, Some(def.def_id))),
+ ty: Box::new(clean_middle_ty(
+ ty::Binder::dummy(cx.tcx.type_of(def.def_id)),
+ cx,
+ Some(def.def_id),
+ )),
default: match has_default {
true => Some(Box::new(cx.tcx.const_param_default(def.def_id).to_string())),
false => None,
.collect::<ThinVec<GenericParamDef>>();
// param index -> [(trait DefId, associated type name & generics, type, higher-ranked params)]
- let mut impl_trait_proj =
- FxHashMap::<u32, Vec<(DefId, PathSegment, Ty<'_>, Vec<GenericParamDef>)>>::default();
+ let mut impl_trait_proj = FxHashMap::<
+ u32,
+ Vec<(DefId, PathSegment, ty::Binder<'_, Ty<'_>>, Vec<GenericParamDef>)>,
+ >::default();
let where_predicates = preds
.predicates
let proj = projection.map(|p| {
(
- clean_projection(p.skip_binder().projection_ty, cx, None),
- p.skip_binder().term,
+ clean_projection(p.map_bound(|p| p.projection_ty), cx, None),
+ p.map_bound(|p| p.term),
)
});
if let Some(((_, trait_did, name), rhs)) = proj
impl_trait_proj.entry(param_idx).or_default().push((
trait_did,
name,
- rhs.ty().unwrap(),
+ rhs.map_bound(|rhs| rhs.ty().unwrap()),
p.get_bound_params()
.into_iter()
.flatten()
// We assume all empty tuples are default return type. This theoretically can discard `-> ()`,
// but shouldn't change any code meaning.
- let output = match clean_middle_ty(sig.skip_binder().output(), cx, None) {
+ let output = match clean_middle_ty(sig.output(), cx, None) {
Type::Tuple(inner) if inner.is_empty() => DefaultReturn,
ty => Return(ty),
};
c_variadic: sig.skip_binder().c_variadic,
inputs: Arguments {
values: sig
- .skip_binder()
.inputs()
.iter()
.map(|t| Argument {
- type_: clean_middle_ty(*t, cx, None),
+ type_: clean_middle_ty(t.map_bound(|t| *t), cx, None),
name: names
.next()
.map(|i| i.name)
hir::TraitItemKind::Type(bounds, Some(default)) => {
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
- let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None);
+ let item_type =
+ clean_middle_ty(ty::Binder::dummy(hir_ty_to_ty(cx.tcx, default)), cx, None);
AssocTypeItem(
Box::new(Typedef {
type_: clean_ty(default, cx),
hir::ImplItemKind::Type(hir_ty) => {
let type_ = clean_ty(hir_ty, cx);
let generics = clean_generics(impl_.generics, cx);
- let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
+ let item_type =
+ clean_middle_ty(ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)), cx, None);
AssocTypeItem(
Box::new(Typedef { type_, generics, item_type: Some(item_type) }),
Vec::new(),
let tcx = cx.tcx;
let kind = match assoc_item.kind {
ty::AssocKind::Const => {
- let ty = clean_middle_ty(tcx.type_of(assoc_item.def_id), cx, Some(assoc_item.def_id));
+ let ty = clean_middle_ty(
+ ty::Binder::dummy(tcx.type_of(assoc_item.def_id)),
+ cx,
+ Some(assoc_item.def_id),
+ );
let provided = match assoc_item.container {
ty::ImplContainer => true,
AssocTypeItem(
Box::new(Typedef {
type_: clean_middle_ty(
- tcx.type_of(assoc_item.def_id),
+ ty::Binder::dummy(tcx.type_of(assoc_item.def_id)),
cx,
Some(assoc_item.def_id),
),
AssocTypeItem(
Box::new(Typedef {
type_: clean_middle_ty(
- tcx.type_of(assoc_item.def_id),
+ ty::Binder::dummy(tcx.type_of(assoc_item.def_id)),
cx,
Some(assoc_item.def_id),
),
hir::QPath::Resolved(Some(qself), p) => {
// Try to normalize `<X as Y>::T` to a type
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
- if let Some(normalized_value) = normalize(cx, ty) {
- return clean_middle_ty(normalized_value, cx, None);
+ // `hir_to_ty` can return projection types with escaping vars for GATs, e.g. `<() as Trait>::Gat<'_>`
+ if !ty.has_escaping_bound_vars() {
+ if let Some(normalized_value) = normalize(cx, ty::Binder::dummy(ty)) {
+ return clean_middle_ty(normalized_value, cx, None);
+ }
}
let trait_segments = &p.segments[..p.segments.len() - 1];
hir::QPath::TypeRelative(qself, segment) => {
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
let res = match ty.kind() {
- ty::Projection(proj) => Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id),
+ ty::Alias(ty::Projection, proj) => {
+ Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id)
+ }
// Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s.
ty::Error(_) => return Type::Infer,
// Otherwise, this is an inherent associated type.
- _ => return clean_middle_ty(ty, cx, None),
+ _ => return clean_middle_ty(ty::Binder::dummy(ty), cx, None),
};
let trait_ = clean_path(&hir::Path { span, res, segments: &[] }, cx);
register_res(cx, trait_.res);
}
/// Returns `None` if the type could not be normalized
-fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+fn normalize<'tcx>(
+ cx: &mut DocContext<'tcx>,
+ ty: ty::Binder<'tcx, Ty<'tcx>>,
+) -> Option<ty::Binder<'tcx, Ty<'tcx>>> {
// HACK: low-churn fix for #79459 while we wait for a trait normalization fix
if !cx.tcx.sess.opts.unstable_opts.normalize_docs {
return None;
}
}
+#[instrument(level = "trace", skip(cx), ret)]
pub(crate) fn clean_middle_ty<'tcx>(
- ty: Ty<'tcx>,
+ bound_ty: ty::Binder<'tcx, Ty<'tcx>>,
cx: &mut DocContext<'tcx>,
def_id: Option<DefId>,
) -> Type {
- trace!("cleaning type: {:?}", ty);
- let ty = normalize(cx, ty).unwrap_or(ty);
- match *ty.kind() {
+ let bound_ty = normalize(cx, bound_ty).unwrap_or(bound_ty);
+ match *bound_ty.skip_binder().kind() {
ty::Never => Primitive(PrimitiveType::Never),
ty::Bool => Primitive(PrimitiveType::Bool),
ty::Char => Primitive(PrimitiveType::Char),
ty::Uint(uint_ty) => Primitive(uint_ty.into()),
ty::Float(float_ty) => Primitive(float_ty.into()),
ty::Str => Primitive(PrimitiveType::Str),
- ty::Slice(ty) => Slice(Box::new(clean_middle_ty(ty, cx, None))),
+ ty::Slice(ty) => Slice(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None))),
ty::Array(ty, mut n) => {
n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
let n = print_const(cx, n);
- Array(Box::new(clean_middle_ty(ty, cx, None)), n.into())
+ Array(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None)), n.into())
+ }
+ ty::RawPtr(mt) => {
+ RawPointer(mt.mutbl, Box::new(clean_middle_ty(bound_ty.rebind(mt.ty), cx, None)))
}
- ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(clean_middle_ty(mt.ty, cx, None))),
ty::Ref(r, ty, mutbl) => BorrowedRef {
lifetime: clean_middle_region(r),
mutability: mutbl,
- type_: Box::new(clean_middle_ty(ty, cx, None)),
+ type_: Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None)),
},
ty::FnDef(..) | ty::FnPtr(_) => {
- let sig = ty.fn_sig(cx.tcx);
+ // FIXME: should we merge the outer and inner binders somehow?
+ let sig = bound_ty.skip_binder().fn_sig(cx.tcx);
let decl = clean_fn_decl_from_did_and_sig(cx, None, sig);
BareFunction(Box::new(BareFunctionDecl {
unsafety: sig.unsafety(),
AdtKind::Enum => ItemType::Enum,
};
inline::record_extern_fqn(cx, did, kind);
- let path = external_path(cx, did, false, ThinVec::new(), substs);
+ let path = external_path(cx, did, false, ThinVec::new(), bound_ty.rebind(substs));
Type::Path { path }
}
ty::Foreign(did) => {
inline::record_extern_fqn(cx, did, ItemType::ForeignType);
- let path = external_path(cx, did, false, ThinVec::new(), InternalSubsts::empty());
+ let path = external_path(
+ cx,
+ did,
+ false,
+ ThinVec::new(),
+ ty::Binder::dummy(InternalSubsts::empty()),
+ );
Type::Path { path }
}
ty::Dynamic(obj, ref reg, _) => {
let did = obj
.principal_def_id()
.or_else(|| dids.next())
- .unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", ty));
+ .unwrap_or_else(|| panic!("found trait object `{bound_ty:?}` with no traits?"));
let substs = match obj.principal() {
- Some(principal) => principal.skip_binder().substs,
+ Some(principal) => principal.map_bound(|p| p.substs),
// marker traits have no substs.
- _ => cx.tcx.intern_substs(&[]),
+ _ => ty::Binder::dummy(InternalSubsts::empty()),
};
inline::record_extern_fqn(cx, did, ItemType::Trait);
let lifetime = clean_middle_region(*reg);
let mut bounds = dids
.map(|did| {
- let empty = cx.tcx.intern_substs(&[]);
+ let empty = ty::Binder::dummy(InternalSubsts::empty());
let path = external_path(cx, did, false, ThinVec::new(), empty);
inline::record_extern_fqn(cx, did, ItemType::Trait);
PolyTrait { trait_: path, generic_params: Vec::new() }
.projection_bounds()
.map(|pb| TypeBinding {
assoc: projection_to_path_segment(
- pb.skip_binder()
- // HACK(compiler-errors): Doesn't actually matter what self
- // type we put here, because we're only using the GAT's substs.
- .with_self_ty(cx.tcx, cx.tcx.types.self_param)
- .projection_ty,
+ pb.map_bound(|pb| {
+ pb
+ // HACK(compiler-errors): Doesn't actually matter what self
+ // type we put here, because we're only using the GAT's substs.
+ .with_self_ty(cx.tcx, cx.tcx.types.self_param)
+ .projection_ty
+ }),
cx,
),
kind: TypeBindingKind::Equality {
- term: clean_middle_term(pb.skip_binder().term, cx),
+ term: clean_middle_term(pb.map_bound(|pb| pb.term), cx),
},
})
.collect();
DynTrait(bounds, lifetime)
}
- ty::Tuple(t) => Tuple(t.iter().map(|t| clean_middle_ty(t, cx, None)).collect()),
+ ty::Tuple(t) => {
+ Tuple(t.iter().map(|t| clean_middle_ty(bound_ty.rebind(t), cx, None)).collect())
+ }
- ty::Projection(ref data) => clean_projection(*data, cx, def_id),
+ ty::Alias(ty::Projection, ref data) => clean_projection(bound_ty.rebind(*data), cx, def_id),
ty::Param(ref p) => {
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
}
}
- ty::Opaque(def_id, substs) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
// by looking up the bounds associated with the def_id.
let bounds = cx
{
if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
Some(TypeBinding {
- assoc: projection_to_path_segment(proj.projection_ty, cx),
+ assoc: projection_to_path_segment(
+ bound.kind().rebind(proj.projection_ty),
+ cx,
+ ),
kind: TypeBindingKind::Equality {
- term: clean_middle_term(proj.term, cx),
+ term: clean_middle_term(bound.kind().rebind(proj.term), cx),
},
})
} else {
clean_field_with_def_id(
field.did,
field.name,
- clean_middle_ty(cx.tcx.type_of(field.did), cx, Some(field.did)),
+ clean_middle_ty(ty::Binder::dummy(cx.tcx.type_of(field.did)), cx, Some(field.did)),
cx,
)
}
}),
ItemKind::TyAlias(hir_ty, generics) => {
let rustdoc_ty = clean_ty(hir_ty, cx);
- let ty = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
+ let ty = clean_middle_ty(ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)), cx, None);
TypedefItem(Box::new(Typedef {
type_: rustdoc_ty,
generics: clean_generics(generics, cx),
let for_ = clean_ty(impl_.self_ty, cx);
let type_alias = for_.def_id(&cx.cache).and_then(|did| match tcx.def_kind(did) {
- DefKind::TyAlias => Some(clean_middle_ty(tcx.type_of(did), cx, Some(did))),
+ DefKind::TyAlias => {
+ Some(clean_middle_ty(ty::Binder::dummy(tcx.type_of(did)), cx, Some(did)))
+ }
_ => None,
});
let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
impl GenericBound {
pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
let did = cx.tcx.require_lang_item(LangItem::Sized, None);
- let empty = cx.tcx.intern_substs(&[]);
+ let empty = ty::Binder::dummy(ty::InternalSubsts::empty());
let path = external_path(cx, did, false, ThinVec::new(), empty);
inline::record_extern_fqn(cx, did, ItemType::Trait);
GenericBound::TraitBound(
pub(crate) fn substs_to_args<'tcx>(
cx: &mut DocContext<'tcx>,
- substs: &[ty::subst::GenericArg<'tcx>],
+ substs: ty::Binder<'tcx, &[ty::subst::GenericArg<'tcx>]>,
mut skip_first: bool,
) -> Vec<GenericArg> {
let mut ret_val =
- Vec::with_capacity(substs.len().saturating_sub(if skip_first { 1 } else { 0 }));
- ret_val.extend(substs.iter().filter_map(|kind| match kind.unpack() {
+ Vec::with_capacity(substs.skip_binder().len().saturating_sub(if skip_first {
+ 1
+ } else {
+ 0
+ }));
+ ret_val.extend(substs.iter().filter_map(|kind| match kind.skip_binder().unpack() {
GenericArgKind::Lifetime(lt) => {
Some(GenericArg::Lifetime(clean_middle_region(lt).unwrap_or(Lifetime::elided())))
}
skip_first = false;
None
}
- GenericArgKind::Type(ty) => Some(GenericArg::Type(clean_middle_ty(ty, cx, None))),
- GenericArgKind::Const(ct) => Some(GenericArg::Const(Box::new(clean_middle_const(ct, cx)))),
+ GenericArgKind::Type(ty) => {
+ Some(GenericArg::Type(clean_middle_ty(kind.rebind(ty), cx, None)))
+ }
+ GenericArgKind::Const(ct) => {
+ Some(GenericArg::Const(Box::new(clean_middle_const(kind.rebind(ct), cx))))
+ }
}));
ret_val
}
did: DefId,
has_self: bool,
bindings: ThinVec<TypeBinding>,
- substs: SubstsRef<'tcx>,
+ substs: ty::Binder<'tcx, SubstsRef<'tcx>>,
) -> GenericArgs {
- let args = substs_to_args(cx, substs, has_self);
+ let args = substs_to_args(cx, substs.map_bound(|substs| &substs[..]), has_self);
if cx.tcx.fn_trait_kind_from_def_id(did).is_some() {
+ let ty = substs
+ .iter()
+ .nth(if has_self { 1 } else { 0 })
+ .unwrap()
+ .map_bound(|arg| arg.expect_ty());
let inputs =
// The trait's first substitution is the one after self, if there is one.
- match substs.iter().nth(if has_self { 1 } else { 0 }).unwrap().expect_ty().kind() {
- ty::Tuple(tys) => tys.iter().map(|t| clean_middle_ty(t, cx, None)).collect::<Vec<_>>().into(),
+ match ty.skip_binder().kind() {
+ ty::Tuple(tys) => tys.iter().map(|t| clean_middle_ty(ty.rebind(t), cx, None)).collect::<Vec<_>>().into(),
_ => return GenericArgs::AngleBracketed { args: args.into(), bindings },
};
let output = bindings.into_iter().next().and_then(|binding| match binding.kind {
did: DefId,
has_self: bool,
bindings: ThinVec<TypeBinding>,
- substs: SubstsRef<'tcx>,
+ substs: ty::Binder<'tcx, SubstsRef<'tcx>>,
) -> Path {
let def_kind = cx.tcx.def_kind(did);
let name = cx.tcx.item_name(did);
ItemType::TraitAlias => "traitalias",
}
}
+ pub(crate) fn is_method(&self) -> bool {
+ matches!(*self, ItemType::Method | ItemType::TyMethod)
+ }
}
impl fmt::Display for ItemType {
return event;
};
- let mut origtext = String::new();
+ let mut original_text = String::new();
for event in &mut self.inner {
match event {
Event::End(Tag::CodeBlock(..)) => break,
Event::Text(ref s) => {
- origtext.push_str(s);
+ original_text.push_str(s);
}
_ => {}
}
<pre class=\"language-{}\"><code>{}</code></pre>\
</div>",
lang,
- Escape(&origtext),
+ Escape(&original_text),
)
.into(),
));
CodeBlockKind::Indented => Default::default(),
};
- let lines = origtext.lines().filter_map(|l| map_line(l).for_html());
+ let lines = original_text.lines().filter_map(|l| map_line(l).for_html());
let text = lines.intersperse("\n".into()).collect::<String>();
compile_fail = parse_result.compile_fail;
if url.is_empty() {
return None;
}
- let test = origtext
+ let test = original_text
.lines()
.map(|l| map_line(l).for_code())
.intersperse("\n".into())
You need to enable Javascript be able to update your settings.\
</section>\
</noscript>\
- <link rel=\"stylesheet\" type=\"text/css\" \
+ <link rel=\"stylesheet\" \
href=\"{static_root_path}{settings_css}\">\
<script defer src=\"{static_root_path}{settings_js}\"></script>",
static_root_path = page.get_static_root_path(),
let toggled = !doc_buffer.is_empty();
if toggled {
- let method_toggle_class =
- if item_type == ItemType::Method { " method-toggle" } else { "" };
+ let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class);
}
match &*item.kind {
document(&mut content, cx, m, Some(t), HeadingOffset::H5);
let toggled = !content.is_empty();
if toggled {
- write!(w, "<details class=\"rustdoc-toggle method-toggle\" open><summary>");
+ let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
+ write!(w, "<details class=\"rustdoc-toggle{method_toggle_class}\" open><summary>");
}
write!(w, "<section id=\"{}\" class=\"method has-srclink\">", id);
render_rightside(w, cx, m, t, RenderMode::Normal);
}
.source .content pre.rust {
- overflow: auto;
padding-left: 0;
}
text-overflow: ellipsis;
}
/* Wrap non-pre code blocks (`text`) but not (```text```). */
-.docblock > :not(pre) > code,
-.docblock-short > code {
+.docblock :not(pre) > code,
+.docblock-short code {
white-space: pre-wrap;
}
top: 100%;
right: 0;
z-index: 2;
- display: block;
margin-top: 7px;
border-radius: 3px;
border: 1px solid var(--border-color);
+ background-color: var(--main-background-color);
+ color: var(--main-color);
--popover-arrow-offset: 11px;
}
right: var(--popover-arrow-offset);
border: solid var(--border-color);
border-width: 1px 1px 0 0;
+ background-color: var(--main-background-color);
padding: 4px;
transform: rotate(-45deg);
top: -5px;
}
-.popover, .popover::before {
- background-color: var(--main-background-color);
- color: var(--main-color);
-}
-
/* use larger max-width for help popover, but not for help.html */
#help.popover {
max-width: 600px;
vertical-align: middle;
border: solid 1px var(--border-color);
border-radius: 3px;
- cursor: default;
color: var(--kbd--color);
background-color: var(--kbd-background);
box-shadow: inset 0 -1px 0 var(--kbd-box-shadow-color);
}
.variants > .docblock,
+.implementors-toggle > .docblock,
.impl-items > .rustdoc-toggle[open]:not(:last-child),
.methods > .rustdoc-toggle[open]:not(:last-child),
.implementors-toggle[open]:not(:last-child) {
}
.scraped-example .code-wrapper .src-line-numbers {
- margin: 0;
padding: 14px 0;
}
color: #c5c5c5;
}
-.content .item-info::before { color: #ccc; }
-
.sidebar h2 a,
.sidebar h3 a {
color: white;
--table-alt-row-background-color: #2A2A2A;
}
-.content .item-info::before { color: #ccc; }
-
body.source .example-wrap pre.rust a {
background: #333;
}
--table-alt-row-background-color: #F5F5F5;
}
-.content .item-info::before { color: #ccc; }
-
body.source .example-wrap pre.rust a {
background: #eee;
}
function loadCss(cssUrl) {
const link = document.createElement("link");
link.href = cssUrl;
- link.type = "text/css";
link.rel = "stylesheet";
document.getElementsByTagName("head")[0].appendChild(link);
}
let mut css = String::new();
for name in &options.markdown_css {
- write!(css, r#"<link rel="stylesheet" type="text/css" href="{name}">"#)
+ write!(css, r#"<link rel="stylesheet" href="{name}">"#)
.expect("Writing to a String can't fail");
}
ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did, .. }, _)), _) | ty::Foreign(did) => {
Res::from_def_id(self.cx.tcx, did)
}
- ty::Projection(_)
+ ty::Alias(..)
| ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(_)
- | ty::Opaque(..)
| ty::Dynamic(..)
| ty::Param(_)
| ty::Bound(..)
// It also validates that functions can be called through function pointers
// through traits.
-#![feature(no_core, lang_items, unboxed_closures, arbitrary_self_types)]
+#![feature(no_core, lang_items, intrinsics, unboxed_closures, arbitrary_self_types)]
#![crate_type = "lib"]
#![no_core]
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}
+extern "rust-intrinsic" {
+ pub fn transmute<Src, Dst>(src: Src) -> Dst;
+}
+
pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box;
pub static mut STORAGE_BAR: u32 = 12;
STORAGE_FOO(&1, &mut buf);
}
}
+
+// Validate that we can codegen transmutes between data ptrs and fn ptrs.
+
+// CHECK: define{{.+}}{{void \(\) addrspace\(1\)\*|ptr addrspace\(1\)}} @transmute_data_ptr_to_fn({{\{\}\*|ptr}}{{.*}} %x)
+#[no_mangle]
+pub unsafe fn transmute_data_ptr_to_fn(x: *const ()) -> fn() {
+ // It doesn't matter precisely how this is codegenned (through memory or an addrspacecast),
+ // as long as it doesn't cause a verifier error by using `bitcast`.
+ transmute(x)
+}
+
+// CHECK: define{{.+}}{{\{\}\*|ptr}} @transmute_fn_ptr_to_data({{void \(\) addrspace\(1\)\*|ptr addrspace\(1\)}}{{.*}} %x)
+#[no_mangle]
+pub unsafe fn transmute_fn_ptr_to_data(x: fn()) -> *const () {
+ // It doesn't matter precisely how this is codegenned (through memory or an addrspacecast),
+ // as long as it doesn't cause a verifier error by using `bitcast`.
+ transmute(x)
+}
}
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, typeck, optimized_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
#[rustc_clean(cfg="cfail6")]
pub fn change_continue_label() {
let mut _x = 0;
}
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail6")]
pub fn change_break_label() {
let mut _x = 0;
}
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail6")]
pub fn change_continue_label() {
let mut _x = 0;
}
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")]
#[rustc_clean(cfg="cfail6")]
pub fn change_break_label() {
let mut _x = 0;
}
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")]
#[rustc_clean(cfg="cfail6")]
pub fn change_continue_label() {
let mut _x = 0;
// Little explanations for this test: if the text wasn't displayed on two lines, it would take
// around 20px (which is the font size).
assert-property: (".docblock p > code", {"offsetHeight": "44"})
+
+// Same check, but where the long code block is also a link
+goto: "file://" + |DOC_PATH| + "/test_docs/long_code_block_link/index.html"
+assert-property: (".docblock p > a > code", {"offsetHeight": "44"})
click: "input#line-numbers"
wait-for: 100 // wait-for-false does not exist
assert-false: "pre.example-line-numbers"
+assert-local-storage: {"rustdoc-line-numbers": "false" }
// Finally, turn it on again.
click: "input#line-numbers"
wait-for: "pre.example-line-numbers"
+assert-local-storage: {"rustdoc-line-numbers": "true" }
"color": |color|,
"background-color": |background|,
"box-shadow": |box_shadow| + " 0px -1px 0px 0px inset",
- "cursor": "default",
}, ALL)),
],
)
--- /dev/null
+// A docblock on an impl must have a margin to separate it from the contents.
+goto: "file://" + |DOC_PATH| + "/test_docs/struct.TypeWithImplDoc.html"
+
+// The text is about 24px tall, so if there's a margin, then their position will be >24px apart
+compare-elements-position-near-false: (
+ "#implementations-list > .implementors-toggle > .docblock > p",
+ "#implementations-list > .implementors-toggle > .impl-items",
+ {"y": 24}
+)
/// Very long code text `hereIgoWithLongTextBecauseWhyNotAndWhyWouldntI`.
pub mod long_code_block {}
+/// Very long code text [`hereIgoWithLongTextBecauseWhyNotAndWhyWouldntI`][lnk].
+///
+/// [lnk]: crate::long_code_block_link
+pub mod long_code_block_link {}
+
#[macro_export]
macro_rules! repro {
() => {};
fn function2() {}
}
}
+
+pub struct TypeWithImplDoc;
+
+/// impl doc
+impl TypeWithImplDoc {
+ /// fn doc
+ pub fn test_fn() {}
+}
-Z dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no)
-Z dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no)
-Z dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans.
+ -Z dump-mono-stats=val -- output statistics about monomorphization collection (format: markdown)
-Z dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
-Z dylib-lto=val -- enables LTO for dylib crate type
-Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
// summary. Trait methods with no documentation should not be wrapped.
//
// @has foo/trait.Foo.html
+// @has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'type Item'
+// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'type Item2'
// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()'
// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
pub trait Foo {
+ /// is documented
+ type Item;
+
+ type Item2;
+
fn not_documented();
/// is_documented is documented
TyKind::GeneratorWitness(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Never => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Tuple(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
- TyKind::Projection(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
- TyKind::Opaque(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
+ TyKind::Alias(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Param(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Bound(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Placeholder(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:36:9
|
-LL | TyKind::Projection(..) => (),
+LL | TyKind::Alias(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
--> $DIR/ty_tykind_usage.rs:37:9
|
-LL | TyKind::Opaque(..) => (),
- | ^^^^^^ help: try using `ty::<kind>` directly: `ty`
-
-error: usage of `ty::TyKind::<kind>`
- --> $DIR/ty_tykind_usage.rs:38:9
- |
LL | TyKind::Param(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
- --> $DIR/ty_tykind_usage.rs:39:9
+ --> $DIR/ty_tykind_usage.rs:38:9
|
LL | TyKind::Bound(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
- --> $DIR/ty_tykind_usage.rs:40:9
+ --> $DIR/ty_tykind_usage.rs:39:9
|
LL | TyKind::Placeholder(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
- --> $DIR/ty_tykind_usage.rs:41:9
+ --> $DIR/ty_tykind_usage.rs:40:9
|
LL | TyKind::Infer(..) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
- --> $DIR/ty_tykind_usage.rs:42:9
+ --> $DIR/ty_tykind_usage.rs:41:9
|
LL | TyKind::Error(_) => (),
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind::<kind>`
- --> $DIR/ty_tykind_usage.rs:47:12
+ --> $DIR/ty_tykind_usage.rs:46:12
|
LL | if let TyKind::Int(int_ty) = kind {}
| ^^^^^^ help: try using `ty::<kind>` directly: `ty`
error: usage of `ty::TyKind`
- --> $DIR/ty_tykind_usage.rs:49:24
+ --> $DIR/ty_tykind_usage.rs:48:24
|
LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
| ^^^^^^^^^^
= help: try using `Ty` instead
error: usage of `ty::TyKind`
- --> $DIR/ty_tykind_usage.rs:51:37
+ --> $DIR/ty_tykind_usage.rs:50:37
|
LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
| ^^^^^^^^^^^
= help: try using `Ty` instead
error: usage of `ty::TyKind`
- --> $DIR/ty_tykind_usage.rs:51:53
+ --> $DIR/ty_tykind_usage.rs:50:53
|
LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
| ^^^^^^^^^^^
= help: try using `Ty` instead
error: usage of `ty::TyKind::<kind>`
- --> $DIR/ty_tykind_usage.rs:54:9
+ --> $DIR/ty_tykind_usage.rs:53:9
|
LL | IrTyKind::Bool
| --------^^^^^^
| |
| help: try using `ty::<kind>` directly: `ty`
-error: aborting due to 33 previous errors
+error: aborting due to 32 previous errors
#[diag(compiletest_example)]
struct SubdiagnosticBad {
#[subdiagnostic(bad)]
- //~^ ERROR `#[subdiagnostic(bad)]` is not a valid attribute
+ //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
note: Note,
}
#[diag(compiletest_example)]
struct SubdiagnosticBadLitStr {
#[subdiagnostic("bad")]
- //~^ ERROR `#[subdiagnostic("...")]` is not a valid attribute
+ //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
note: Note,
}
#[diag(compiletest_example)]
struct SubdiagnosticEagerCorrect {
#[subdiagnostic(eager)]
+ //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
note: Note,
}
#[diag(compiletest_example)]
struct SubdiagnosticEagerSuggestion {
#[subdiagnostic(eager)]
+ //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
sub: SubdiagnosticWithSuggestion,
}
|
= help: `#[label]` and `#[suggestion]` can only be applied to fields
-error: `#[subdiagnostic(bad)]` is not a valid attribute
- --> $DIR/diagnostic-derive.rs:685:21
+error: `#[subdiagnostic(...)]` is not a valid attribute
+ --> $DIR/diagnostic-derive.rs:685:5
|
LL | #[subdiagnostic(bad)]
- | ^^^
+ | ^^^^^^^^^^^^^^^^^^^^^
|
- = help: `eager` is the only supported nested attribute for `subdiagnostic`
+ = help: `subdiagnostic` does not support nested attributes
error: `#[subdiagnostic = ...]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:693:5
|
LL | #[subdiagnostic = "bad"]
| ^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: `eager` is the only supported nested attribute for `subdiagnostic`
error: `#[subdiagnostic(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:701:5
LL | #[subdiagnostic(bad, bad)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: `eager` is the only supported nested attribute for `subdiagnostic`
+ = help: `subdiagnostic` does not support nested attributes
-error: `#[subdiagnostic("...")]` is not a valid attribute
- --> $DIR/diagnostic-derive.rs:709:21
+error: `#[subdiagnostic(...)]` is not a valid attribute
+ --> $DIR/diagnostic-derive.rs:709:5
|
LL | #[subdiagnostic("bad")]
- | ^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: `eager` is the only supported nested attribute for `subdiagnostic`
+ = help: `subdiagnostic` does not support nested attributes
error: `#[subdiagnostic(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:717:5
LL | #[subdiagnostic(eager)]
| ^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: eager subdiagnostics are not supported on lints
+ = help: `subdiagnostic` does not support nested attributes
+
+error: `#[subdiagnostic(...)]` is not a valid attribute
+ --> $DIR/diagnostic-derive.rs:725:5
+ |
+LL | #[subdiagnostic(eager)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: `subdiagnostic` does not support nested attributes
+
+error: `#[subdiagnostic(...)]` is not a valid attribute
+ --> $DIR/diagnostic-derive.rs:746:5
+ |
+LL | #[subdiagnostic(eager)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: `subdiagnostic` does not support nested attributes
error: expected at least one string literal for `code(...)`
- --> $DIR/diagnostic-derive.rs:775:18
+ --> $DIR/diagnostic-derive.rs:777:18
|
LL | #[suggestion(code())]
| ^^^^^^
error: `code(...)` must contain only string literals
- --> $DIR/diagnostic-derive.rs:783:23
+ --> $DIR/diagnostic-derive.rs:785:23
|
LL | #[suggestion(code(foo))]
| ^^^
error: `code = "..."`/`code(...)` must contain only string literals
- --> $DIR/diagnostic-derive.rs:791:18
+ --> $DIR/diagnostic-derive.rs:793:18
|
LL | #[suggestion(code = 3)]
| ^^^^^^^^
= help: normalized in stderr
note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
--> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC
- |
-LL | arg: impl IntoDiagnosticArg,
- | ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
- = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `Diagnostic` which comes from the expansion of the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 83 previous errors
+error: aborting due to 85 previous errors
Some errors have detailed explanations: E0277, E0425.
For more information about an error, try `rustc --explain E0277`.
= note: struct `core::alloc::Layout` and struct `Layout` have similar names, but are actually distinct types
note: struct `core::alloc::Layout` is defined in crate `core`
--> $SRC_DIR/core/src/alloc/layout.rs:LL:COL
- |
-LL | pub struct Layout {
- | ^^^^^^^^^^^^^^^^^
note: struct `Layout` is defined in the current crate
--> $DIR/alloc-error-handler-bad-signature-2.rs:7:1
|
|
LL | fn f1<F>(_: F) where F: Fn(&(), &()) {}
| ^^^^^^^^^^^^ required by this bound in `f1`
+help: consider borrowing the argument
+ |
+LL | f1(|_: &(), _: &()| {});
+ | ~~~ ~~~
error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:3:5
|
LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f2`
+help: consider borrowing the argument
+ |
+LL | f2(|_: &'a (), _: &()| {});
+ | ~~~~~~ ~~~
error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:4:5
|
LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {}
| ^^^^^^^^^^^^^^^ required by this bound in `f3`
+help: consider borrowing the argument
+ |
+LL | f3(|_: &(), _: &()| {});
+ | ~~~ ~~~
error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:5:5
|
LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f4`
+help: consider borrowing the argument
+ |
+LL | f4(|_: &(), _: &'r ()| {});
+ | ~~~ ~~~~~~
error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:6:5
|
LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f5`
+help: consider borrowing the argument
+ |
+LL | f5(|_: &'r (), _: &'r ()| {});
+ | ~~~~~~ ~~~~~~
error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:7:5
|
LL | g1(|_: (), _: ()| {});
- | ^^ -------------- found signature defined here
- | |
+ | ^^ --------------
+ | | | |
+ | | | help: consider borrowing the argument: `&()`
+ | | found signature defined here
| expected due to this
|
= note: expected closure signature `for<'a> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _`
--> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
|
LL | g2(|_: (), _: ()| {});
- | ^^ -------------- found signature defined here
- | |
+ | ^^ --------------
+ | | | |
+ | | | help: consider borrowing the argument: `&()`
+ | | found signature defined here
| expected due to this
|
= note: expected closure signature `for<'a> fn(&'a (), for<'a> fn(&'a ())) -> _`
--> $DIR/anonymous-higher-ranked-lifetime.rs:9:5
|
LL | g3(|_: (), _: ()| {});
- | ^^ -------------- found signature defined here
- | |
+ | ^^ --------------
+ | | | |
+ | | | help: consider borrowing the argument: `&'s ()`
+ | | found signature defined here
| expected due to this
|
= note: expected closure signature `for<'s> fn(&'s (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _`
--> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
|
LL | g4(|_: (), _: ()| {});
- | ^^ -------------- found signature defined here
- | |
+ | ^^ --------------
+ | | | |
+ | | | help: consider borrowing the argument: `&()`
+ | | found signature defined here
| expected due to this
|
= note: expected closure signature `for<'a> fn(&'a (), for<'r> fn(&'r ())) -> _`
|
LL | fn h1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>, &(), fn(&(), &())) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `h1`
+help: consider borrowing the argument
+ |
+LL | h1(|_: &(), _: (), _: &(), _: ()| {});
+ | ~~~ ~~~
error[E0631]: type mismatch in closure arguments
--> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
|
LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<dyn Fn(&())>, &'t0 (), fn(&(), &())) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `h2`
+help: consider borrowing the argument
+ |
+LL | h2(|_: &(), _: (), _: &'t0 (), _: ()| {});
+ | ~~~ ~~~~~~~
error: aborting due to 11 previous errors
--- /dev/null
+use std::fmt::Display;
+
+fn foo(x: &(dyn Display + Send)) {}
+
+fn main() {
+ foo();
+ //~^ ERROR this function takes 1 argument but 0 arguments were supplied
+}
--- /dev/null
+error[E0061]: this function takes 1 argument but 0 arguments were supplied
+ --> $DIR/display-is-suggestable.rs:6:5
+ |
+LL | foo();
+ | ^^^-- an argument of type `&dyn std::fmt::Display + Send` is missing
+ |
+note: function defined here
+ --> $DIR/display-is-suggestable.rs:3:4
+ |
+LL | fn foo(x: &(dyn Display + Send)) {}
+ | ^^^ ------------------------
+help: provide the argument
+ |
+LL | foo(/* &dyn std::fmt::Display + Send */);
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0061`.
|
help: consider giving this pattern a type
|
-LL | let [_, _]: _ = a.into();
- | +++
+LL | let [_, _]: /* Type */ = a.into();
+ | ++++++++++++
error: aborting due to previous error
--- /dev/null
+// check-pass
+// compile-flags: -C debug_assertions=yes -Zunstable-options
+
+#[allow(dead_code)]
+fn problematic_function<Space>()
+where
+ DefaultAlloc: FinAllok<R1, Space>,
+{
+ let e = Edge2dElement;
+ let _ = Into::<Point>::into(e.map_reference_coords());
+}
+impl<N> Allocator<N, R0> for DefaultAlloc {
+ type Buffer = MStorage;
+}
+impl<N> Allocator<N, R1> for DefaultAlloc {
+ type Buffer = MStorage;
+}
+impl<N, D> From<VectorN<N, D>> for Point
+where
+ DefaultAlloc: Allocator<N, D>,
+{
+ fn from(_: VectorN<N, D>) -> Self {
+ unimplemented!()
+ }
+}
+impl<GeometryDim, NodalDim> FinAllok<GeometryDim, NodalDim> for DefaultAlloc
+where
+ DefaultAlloc: Allocator<Ure, GeometryDim>,
+ DefaultAlloc: Allocator<Ure, NodalDim>
+{
+}
+impl FiniteElement<R1> for Edge2dElement {
+ fn map_reference_coords(&self) -> VectorN<Ure, R1> {
+ unimplemented!()
+ }
+}
+type VectorN<N, R> = (N, R, <DefaultAlloc as Allocator<N, R>>::Buffer);
+struct DefaultAlloc;
+struct R0;
+struct R1;
+struct MStorage;
+struct Point;
+struct Edge2dElement;
+struct Ure;
+trait Allocator<N, R> {
+ type Buffer;
+}
+trait FinAllok<GeometryDim, NodalDim>:
+ Allocator<Ure, GeometryDim> +
+ Allocator<Ure, NodalDim> +
+{
+}
+trait FiniteElement<Rau>
+where
+ DefaultAlloc: FinAllok<Rau, Rau>,
+{
+ fn map_reference_coords(&self) -> VectorN<Ure, Rau>;
+}
+fn main() {}
--- /dev/null
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/const-projection-err.rs:4:26
+ |
+LL | #![cfg_attr(gce, feature(generic_const_exprs))]
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+error[E0271]: type mismatch resolving `<T as TraitWAssocConst>::A == 1`
+ --> $DIR/const-projection-err.rs:14:11
+ |
+LL | foo::<T>();
+ | ^ expected `0`, found `1`
+ |
+note: required by a bound in `foo`
+ --> $DIR/const-projection-err.rs:11:28
+ |
+LL | fn foo<T: TraitWAssocConst<A = 1>>() {}
+ | ^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0271`.
--- /dev/null
+// revisions: stock gce
+
+#![feature(associated_const_equality)]
+#![cfg_attr(gce, feature(generic_const_exprs))]
+//[gce]~^ WARN the feature `generic_const_exprs` is incomplete
+
+trait TraitWAssocConst {
+ const A: usize;
+}
+
+fn foo<T: TraitWAssocConst<A = 1>>() {}
+
+fn bar<T: TraitWAssocConst<A = 0>>() {
+ foo::<T>();
+ //~^ ERROR type mismatch resolving `<T as TraitWAssocConst>::A == 1`
+}
+
+fn main() {}
--- /dev/null
+error[E0271]: type mismatch resolving `<T as TraitWAssocConst>::A == 1`
+ --> $DIR/const-projection-err.rs:14:11
+ |
+LL | foo::<T>();
+ | ^ expected `1`, found `<T as TraitWAssocConst>::A`
+ |
+ = note: expected constant `1`
+ found constant `<T as TraitWAssocConst>::A`
+note: required by a bound in `foo`
+ --> $DIR/const-projection-err.rs:11:28
+ |
+LL | fn foo<T: TraitWAssocConst<A = 1>>() {}
+ | ^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
|
note: associated type defined here
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | type Item;
- | ^^^^^^^^^
error: aborting due to 2 previous errors
fn main() {
let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
- //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
+ //~^ ERROR expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
}
-error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
+error[E0271]: expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
--> $DIR/associated-types-overridden-binding-2.rs:6:43
|
LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
= help: the trait `Sized` is not implemented for `[u8]`
note: required by a bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- |
-LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
- | ^ required by this bound in `Vec`
error: aborting due to previous error
|
note: required by a bound in `Add`
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | pub trait Add<Rhs = Self> {
- | ^^^^^^^^^^ required by this bound in `Add`
help: consider further restricting `Self`
|
LL | trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> + Sized {}
--> $DIR/async-await-let-else.rs:33:28
|
LL | (Rc::new(()), bar().await);
- | ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later
- | |
+ | ----------- ^^^^^^ - `Rc::new(())` is later dropped here
+ | | |
+ | | await occurs here, with `Rc::new(())` maybe used later
| has type `Rc<()>` which is not `Send`
-note: `Rc::new(())` is later dropped here
- --> $DIR/async-await-let-else.rs:33:35
- |
-LL | (Rc::new(()), bar().await);
- | ^
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:19:15
|
--> $DIR/async-await-let-else.rs:33:28
|
LL | (Rc::new(()), bar().await);
- | ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later
- | |
+ | ----------- ^^^^^^ - `Rc::new(())` is later dropped here
+ | | |
+ | | await occurs here, with `Rc::new(())` maybe used later
| has type `Rc<()>` which is not `Send`
-note: `Rc::new(())` is later dropped here
- --> $DIR/async-await-let-else.rs:33:35
- |
-LL | (Rc::new(()), bar().await);
- | ^
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:19:15
|
found `async` block `[async block@$DIR/generator-desc.rs:10:19: 10:27]`
note: function defined here
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
- |
-LL | pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
- | ^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/generator-desc.rs:12:16
-// check-pass
// edition: 2021
#![feature(async_fn_in_trait)]
}
impl MyTrait for i32 {
- // This will break once a PR that implements #102745 is merged
fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>> {
- Box::pin(async {
- *self
- })
+ //~^ ERROR method `foo` should be async
+ Box::pin(async { *self })
}
}
--- /dev/null
+error: method `foo` should be async because the method from the trait is async
+ --> $DIR/async-example-desugared-boxed.rs:15:5
+ |
+LL | async fn foo(&self) -> i32;
+ | --------------------------- required because the trait method is async
+...
+LL | fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+use std::pin::Pin;
+use std::task::Poll;
+
+trait MyTrait {
+ async fn foo(&self) -> i32;
+}
+
+#[derive(Clone)]
+struct MyFuture(i32);
+
+impl Future for MyFuture {
+ type Output = i32;
+ fn poll(
+ self: Pin<&mut Self>,
+ _: &mut std::task::Context<'_>,
+ ) -> Poll<<Self as Future>::Output> {
+ Poll::Ready(self.0)
+ }
+}
+
+impl MyTrait for i32 {
+ // FIXME: this should eventually require `#[refine]` to compile, because it also provides
+ // `Clone`.
+ fn foo(&self) -> impl Future<Output = i32> + Clone {
+ MyFuture(*self)
+ }
+}
+
+fn main() {}
--- /dev/null
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+use std::task::Poll;
+
+trait MyTrait {
+ async fn foo(&self) -> i32;
+}
+
+struct MyFuture;
+impl Future for MyFuture {
+ type Output = i32;
+ fn poll(self: std::pin::Pin<&mut Self>, _: &mut std::task::Context<'_>) -> Poll<Self::Output> {
+ Poll::Ready(0)
+ }
+}
+
+impl MyTrait for u32 {
+ fn foo(&self) -> MyFuture {
+ //~^ ERROR method `foo` should be async
+ MyFuture
+ }
+}
+
+fn main() {}
--- /dev/null
+error: method `foo` should be async because the method from the trait is async
+ --> $DIR/async-example-desugared-manual.rs:23:5
+ |
+LL | async fn foo(&self) -> i32;
+ | --------------------------- required because the trait method is async
+...
+LL | fn foo(&self) -> MyFuture {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
}
impl MyTrait for i32 {
- // This will break once a PR that implements #102745 is merged
fn foo(&self) -> impl Future<Output = i32> + '_ {
- async {
- *self
- }
+ async { *self }
}
}
impl MyTrait for i32 {
fn foo(&self) -> i32 {
- //~^ ERROR: `i32` is not a future [E0277]
+ //~^ ERROR: method `foo` should be async
*self
}
}
-error[E0277]: `i32` is not a future
- --> $DIR/fn-not-async-err.rs:11:22
- |
-LL | fn foo(&self) -> i32 {
- | ^^^ `i32` is not a future
- |
- = help: the trait `Future` is not implemented for `i32`
- = note: i32 must be a future or must implement `IntoFuture` to be awaited
-note: required by a bound in `MyTrait::foo::{opaque#0}`
- --> $DIR/fn-not-async-err.rs:7:28
+error: method `foo` should be async because the method from the trait is async
+ --> $DIR/fn-not-async-err.rs:11:5
|
LL | async fn foo(&self) -> i32;
- | ^^^ required by this bound in `MyTrait::foo::{opaque#0}`
+ | --------------------------- required because the trait method is async
+...
+LL | fn foo(&self) -> i32 {
+ | ^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0277`.
impl MyTrait for i32 {
fn foo(&self) -> impl Future<Output = i32> {
//~^ ERROR `impl Trait` only allowed in function and inherent method return types, not in `impl` method return [E0562]
- async {
- *self
- }
+ async { *self }
}
}
--- /dev/null
+// edition:2021
+// check-pass
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+pub trait Pool {
+ type Conn;
+
+ async fn async_callback<'a, F: FnOnce(&'a Self::Conn) -> Fut, Fut: Future<Output = ()>>(
+ &'a self,
+ callback: F,
+ ) -> ();
+}
+
+pub struct PoolImpl;
+pub struct ConnImpl;
+
+impl Pool for PoolImpl {
+ type Conn = ConnImpl;
+
+ async fn async_callback<'a, F: FnOnce(&'a Self::Conn) -> Fut, Fut: Future<Output = ()>>(
+ &'a self,
+ _callback: F,
+ ) -> () {
+ todo!()
+ }
+}
+
+fn main() {}
| _____________-
LL | | foo(tx.clone());
LL | | }).await;
- | | - ^^^^^^ await occurs here, with the value maybe used later
- | |_________|
+ | | - ^^^^^^- the value is later dropped here
+ | | | |
+ | |_________| await occurs here, with the value maybe used later
| has type `[closure@$DIR/issue-70935-complex-spans.rs:17:13: 17:15]` which is not `Send`
-note: the value is later dropped here
- --> $DIR/issue-70935-complex-spans.rs:19:17
- |
-LL | }).await;
- | ^
error: aborting due to previous error
|
note: required by a bound in `File::open`
--> $SRC_DIR/std/src/fs.rs:LL:COL
- |
-LL | pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
- | ^^^^^^^^^^^ required by this bound in `File::open`
error: aborting due to previous error
| |
| expected 2 generic arguments
|
-note: enum defined here, with 2 generic parameters: `T`, `E`
- --> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | pub enum Result<T, E> {
- | ^^^^^^ - -
help: add missing generic argument
|
LL | async fn copy() -> Result<(), E>
--> $DIR/issue-65436-raw-ptr-not-send.rs:18:35
|
LL | bar(Foo(std::ptr::null())).await;
- | ---------------- ^^^^^^ await occurs here, with `std::ptr::null()` maybe used later
- | |
+ | ---------------- ^^^^^^- `std::ptr::null()` is later dropped here
+ | | |
+ | | await occurs here, with `std::ptr::null()` maybe used later
| has type `*const u8` which is not `Send`
-note: `std::ptr::null()` is later dropped here
- --> $DIR/issue-65436-raw-ptr-not-send.rs:18:41
- |
-LL | bar(Foo(std::ptr::null())).await;
- | ^
help: consider moving this into a `let` binding to create a shorter lived borrow
--> $DIR/issue-65436-raw-ptr-not-send.rs:18:13
|
--> $DIR/auxiliary/issue_67893.rs:9:26
|
LL | f(*x.lock().unwrap()).await;
- | ----------------- ^^^^^^ await occurs here, with `x.lock().unwrap()` maybe used later
- | |
+ | ----------------- ^^^^^^- `x.lock().unwrap()` is later dropped here
+ | | |
+ | | await occurs here, with `x.lock().unwrap()` maybe used later
| has type `MutexGuard<'_, ()>` which is not `Send`
-note: `x.lock().unwrap()` is later dropped here
- --> $DIR/auxiliary/issue_67893.rs:9:32
- |
-LL | f(*x.lock().unwrap()).await;
- | ^
note: required by a bound in `g`
--> $DIR/issue-67893.rs:6:14
|
| ^^^^^
note: required by a bound in `Pin::<P>::new`
--> $SRC_DIR/core/src/pin.rs:LL:COL
- |
-LL | impl<P: Deref<Target: Unpin>> Pin<P> {
- | ^^^^^ required by this bound in `Pin::<P>::new`
error: aborting due to previous error
...
LL | self.sleep.poll(cx)
| ^^^^ method not found in `Sleep`
+ --> $SRC_DIR/core/src/future/future.rs:LL:COL
|
- ::: $SRC_DIR/core/src/future/future.rs:LL:COL
- |
-LL | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
- | ---- the method is available for `Pin<&mut Sleep>` here
+ = note: the method is available for `Pin<&mut Sleep>` here
|
help: consider wrapping the receiver expression with the appropriate type
|
--- /dev/null
+// edition:2021
+
+#![feature(closure_track_caller, stmt_expr_attributes)]
+
+fn main() {
+ let _ = #[track_caller] async {
+ //~^ ERROR attribute should be applied to a function definition [E0739]
+ };
+}
--- /dev/null
+error[E0739]: attribute should be applied to a function definition
+ --> $DIR/async-block.rs:6:13
+ |
+LL | let _ = #[track_caller] async {
+ | _____________^^^^^^^^^^^^^^^_-
+LL | |
+LL | | };
+ | |_____- not a function definition
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0739`.
--- /dev/null
+// edition:2021
+
+#![feature(async_closure, stmt_expr_attributes)]
+
+fn main() {
+ let _ = #[track_caller] async || {
+ //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658]
+ //~| ERROR `#[track_caller]` on closures is currently unstable [E0658]
+ };
+}
--- /dev/null
+error[E0658]: `#[track_caller]` on closures is currently unstable
+ --> $DIR/async-closure-gate.rs:6:13
+ |
+LL | let _ = #[track_caller] async || {
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+ = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+ --> $DIR/async-closure-gate.rs:6:38
+ |
+LL | let _ = #[track_caller] async || {
+ | ______________________________________^
+LL | |
+LL | |
+LL | | };
+ | |_____^
+ |
+ = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+ = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
// run-pass
// edition:2021
// needs-unwind
-#![feature(closure_track_caller)]
+#![feature(closure_track_caller, async_closure, stmt_expr_attributes)]
use std::future::Future;
use std::panic;
Foo::bar_assoc().await
}
+async fn foo_closure() {
+ let c = #[track_caller] async || {
+ panic!();
+ };
+ c().await
+}
+
fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 {
let loc = Arc::new(Mutex::new(None));
assert_eq!(panicked_at(|| block_on(foo())), 41);
assert_eq!(panicked_at(|| block_on(foo_track_caller())), 54);
assert_eq!(panicked_at(|| block_on(foo_assoc())), 67);
+ assert_eq!(panicked_at(|| block_on(foo_closure())), 74);
}
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | fn add(self, rhs: Rhs) -> Self::Output;
- | ^^^^
help: consider further restricting this bound
|
LL | fn add<A: Add<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | fn sub(self, rhs: Rhs) -> Self::Output;
- | ^^^^
help: consider further restricting this bound
|
LL | fn sub<A: Sub<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | fn mul(self, rhs: Rhs) -> Self::Output;
- | ^^^^
help: consider further restricting this bound
|
LL | fn mul<A: Mul<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | fn div(self, rhs: Rhs) -> Self::Output;
- | ^^^^
help: consider further restricting this bound
|
LL | fn div<A: Div<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | fn rem(self, rhs: Rhs) -> Self::Output;
- | ^^^^
help: consider further restricting this bound
|
LL | fn rem<A: Rem<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
- |
-LL | fn bitand(self, rhs: Rhs) -> Self::Output;
- | ^^^^
help: consider further restricting this bound
|
LL | fn bitand<A: BitAnd<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
- |
-LL | fn bitor(self, rhs: Rhs) -> Self::Output;
- | ^^^^
help: consider further restricting this bound
|
LL | fn bitor<A: BitOr<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
- |
-LL | fn bitxor(self, rhs: Rhs) -> Self::Output;
- | ^^^^
help: consider further restricting this bound
|
LL | fn bitxor<A: BitXor<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
- |
-LL | fn shl(self, rhs: Rhs) -> Self::Output;
- | ^^^^
help: consider further restricting this bound
|
LL | fn shl<A: Shl<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
- |
-LL | fn shr(self, rhs: Rhs) -> Self::Output;
- | ^^^^
help: consider further restricting this bound
|
LL | fn shr<A: Shr<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | fn add(self, rhs: Rhs) -> Self::Output;
- | ^^^^
help: consider further restricting this bound
|
LL | fn double_move<T: Add<Output=()> + Copy>(x: T) {
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | fn add(self, rhs: Rhs) -> Self::Output;
- | ^^^^
error[E0507]: cannot move out of `*n` which is behind a shared reference
--> $DIR/binop-move-semantics.rs:32:5
|
LL | struct A;
| ^^^^^^^^ must implement `Add<_>`
-note: the following trait must be implemented
+note: the trait `Add` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | pub trait Add<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: cannot subtract `A` from `A`
--> $DIR/issue-28837.rs:8:7
|
LL | struct A;
| ^^^^^^^^ must implement `Sub<_>`
-note: the following trait must be implemented
+note: the trait `Sub` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | pub trait Sub<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: cannot multiply `A` by `A`
--> $DIR/issue-28837.rs:10:7
|
LL | struct A;
| ^^^^^^^^ must implement `Mul<_>`
-note: the following trait must be implemented
+note: the trait `Mul` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | pub trait Mul<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: cannot divide `A` by `A`
--> $DIR/issue-28837.rs:12:7
|
LL | struct A;
| ^^^^^^^^ must implement `Div<_>`
-note: the following trait must be implemented
+note: the trait `Div` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | pub trait Div<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: cannot mod `A` by `A`
--> $DIR/issue-28837.rs:14:7
|
LL | struct A;
| ^^^^^^^^ must implement `Rem<_>`
-note: the following trait must be implemented
+note: the trait `Rem` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | pub trait Rem<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: no implementation for `A & A`
--> $DIR/issue-28837.rs:16:7
|
LL | struct A;
| ^^^^^^^^ must implement `BitAnd<_>`
-note: the following trait must be implemented
+note: the trait `BitAnd` must be implemented
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
- |
-LL | pub trait BitAnd<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: no implementation for `A | A`
--> $DIR/issue-28837.rs:18:7
|
LL | struct A;
| ^^^^^^^^ must implement `BitOr<_>`
-note: the following trait must be implemented
+note: the trait `BitOr` must be implemented
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
- |
-LL | pub trait BitOr<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: no implementation for `A << A`
--> $DIR/issue-28837.rs:20:7
|
LL | struct A;
| ^^^^^^^^ must implement `Shl<_>`
-note: the following trait must be implemented
+note: the trait `Shl` must be implemented
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
- |
-LL | pub trait Shl<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: no implementation for `A >> A`
--> $DIR/issue-28837.rs:22:7
|
LL | struct A;
| ^^^^^^^^ must implement `Shr<_>`
-note: the following trait must be implemented
+note: the trait `Shr` must be implemented
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
- |
-LL | pub trait Shr<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: binary operation `==` cannot be applied to type `A`
--> $DIR/issue-28837.rs:24:7
|
LL | struct Thing {
| ^^^^^^^^^^^^ must implement `Mul<_>`
-note: the following trait must be implemented
+note: the trait `Mul` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | pub trait Mul<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
|
LL | match *s { S(v) => v }
| ^^ -
- | | |
- | | data moved here
- | | move occurs because `v` has type `Vec<isize>`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*s`
+ | |
+ | data moved here
+ | move occurs because `v` has type `Vec<isize>`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - match *s { S(v) => v }
+LL + match s { S(v) => v }
+ |
error: aborting due to previous error
--> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:12:15
|
LL | for &a in x.iter() {
- | -- ^^^^^^^^
- | ||
- | |data moved here
- | |move occurs because `a` has type `&mut i32`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `a`
+ | - ^^^^^^^^
+ | |
+ | data moved here
+ | move occurs because `a` has type `&mut i32`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - for &a in x.iter() {
+LL + for a in x.iter() {
+ |
error[E0507]: cannot move out of a shared reference
--> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:18:15
|
LL | for &a in &f.a {
- | -- ^^^^
- | ||
- | |data moved here
- | |move occurs because `a` has type `Box<isize>`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `a`
+ | - ^^^^
+ | |
+ | data moved here
+ | move occurs because `a` has type `Box<isize>`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - for &a in &f.a {
+LL + for a in &f.a {
+ |
error[E0507]: cannot move out of a shared reference
--> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:22:15
|
LL | for &a in x.iter() {
- | -- ^^^^^^^^
- | ||
- | |data moved here
- | |move occurs because `a` has type `Box<i32>`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `a`
+ | - ^^^^^^^^
+ | |
+ | data moved here
+ | move occurs because `a` has type `Box<i32>`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - for &a in x.iter() {
+LL + for a in x.iter() {
+ |
error: aborting due to 3 previous errors
--- /dev/null
+// run-rustfix
+fn main() {
+
+ let x: Option<Box<_>> = Some(Box::new(1));
+
+ match x {
+ Some(ref y) => {
+ let _b = y; //~ ERROR cannot move out
+ }
+ _ => {}
+ }
+}
+// run-rustfix
fn main() {
let x: Option<Box<_>> = Some(Box::new(1));
error[E0507]: cannot move out of `*y` which is behind a shared reference
- --> $DIR/borrowck-issue-2657-2.rs:7:18
+ --> $DIR/borrowck-issue-2657-2.rs:8:18
|
LL | let _b = *y;
- | ^^
- | |
- | move occurs because `*y` has type `Box<i32>`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*y`
+ | ^^ move occurs because `*y` has type `Box<i32>`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let _b = *y;
+LL + let _b = y;
+ |
error: aborting due to previous error
--- /dev/null
+// run-rustfix
+#![allow(unused)]
+enum Foo {
+ Foo1(Box<u32>, Box<u32>),
+ Foo2(Box<u32>),
+ Foo3,
+}
+
+
+
+fn blah() {
+ let f = &Foo::Foo1(Box::new(1), Box::new(2));
+ match f { //~ ERROR cannot move out of
+ Foo::Foo1(num1,
+ num2) => (),
+ Foo::Foo2(num) => (),
+ Foo::Foo3 => ()
+ }
+}
+
+struct S {
+ f: String,
+ g: String
+}
+impl Drop for S {
+ fn drop(&mut self) { println!("{}", self.f); }
+}
+
+fn move_in_match() {
+ match (S {f: "foo".to_string(), g: "bar".to_string()}) {
+ //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+ S {
+ f: ref _s,
+ g: ref _t
+ } => {}
+ }
+}
+
+// from issue-8064
+struct A {
+ a: Box<isize>,
+}
+
+fn free<T>(_: T) {}
+
+fn blah2() {
+ let a = &A { a: Box::new(1) };
+ match &a.a { //~ ERROR cannot move out of
+ n => {
+ free(n)
+ }
+ }
+ free(a)
+}
+
+fn main() {}
+// run-rustfix
+#![allow(unused)]
enum Foo {
Foo1(Box<u32>, Box<u32>),
Foo2(Box<u32>),
error[E0507]: cannot move out of `f` as enum variant `Foo1` which is behind a shared reference
- --> $DIR/borrowck-move-error-with-note.rs:11:11
+ --> $DIR/borrowck-move-error-with-note.rs:13:11
|
LL | match *f {
- | ^^ help: consider borrowing here: `&*f`
+ | ^^
LL | Foo::Foo1(num1,
| ---- data moved here
LL | num2) => (),
| --- ...and here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the dereference here
+ |
+LL - match *f {
+LL + match f {
+ |
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
- --> $DIR/borrowck-move-error-with-note.rs:28:11
+ --> $DIR/borrowck-move-error-with-note.rs:30:11
|
LL | match (S {f: "foo".to_string(), g: "bar".to_string()}) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
| -- ...and here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider borrowing the pattern binding
+ |
+LL | f: ref _s,
+ | +++
+help: consider borrowing the pattern binding
+ |
+LL | g: ref _t
+ | +++
error[E0507]: cannot move out of `a.a` which is behind a shared reference
- --> $DIR/borrowck-move-error-with-note.rs:46:11
+ --> $DIR/borrowck-move-error-with-note.rs:48:11
|
LL | match a.a {
- | ^^^ help: consider borrowing here: `&a.a`
+ | ^^^
LL | n => {
| -
| |
| data moved here
| move occurs because `n` has type `Box<isize>`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &a.a {
+ | +
error: aborting due to 3 previous errors
--> $DIR/borrowck-move-from-unsafe-ptr.rs:2:13
|
LL | let y = *x;
- | ^^
- | |
- | move occurs because `*x` has type `Box<isize>`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*x`
+ | ^^ move occurs because `*x` has type `Box<isize>`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let y = *x;
+LL + let y = x;
+ |
error: aborting due to previous error
|
LL | fn arg_item(&_x: &String) {}
| ^--
- | ||
- | |data moved here
- | |move occurs because `_x` has type `String`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `_x`
+ | |
+ | data moved here
+ | move occurs because `_x` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - fn arg_item(&_x: &String) {}
+LL + fn arg_item(_x: &String) {}
+ |
error[E0507]: cannot move out of a shared reference
--> $DIR/borrowck-move-in-irrefut-pat.rs:7:11
|
LL | with(|&_x| ())
| ^--
- | ||
- | |data moved here
- | |move occurs because `_x` has type `String`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `_x`
+ | |
+ | data moved here
+ | move occurs because `_x` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - with(|&_x| ())
+LL + with(|_x| ())
+ |
error[E0507]: cannot move out of a shared reference
--> $DIR/borrowck-move-in-irrefut-pat.rs:12:15
|
LL | let &_x = &"hi".to_string();
- | --- ^^^^^^^^^^^^^^^^^
- | ||
- | |data moved here
- | |move occurs because `_x` has type `String`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `_x`
+ | -- ^^^^^^^^^^^^^^^^^
+ | |
+ | data moved here
+ | move occurs because `_x` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - let &_x = &"hi".to_string();
+LL + let _x = &"hi".to_string();
+ |
error: aborting due to 3 previous errors
| | value moved due to this method call
| move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
|
-note: this function takes ownership of the receiver `self`, which moves value
+note: `into_iter` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
error: aborting due to previous error
--> $DIR/borrowck-move-out-of-overloaded-deref.rs:4:14
|
LL | let _x = *Rc::new("hi".to_string());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | move occurs because value has type `String`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*Rc::new("hi".to_string())`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let _x = *Rc::new("hi".to_string());
+LL + let _x = Rc::new("hi".to_string());
+ |
error: aborting due to previous error
--- /dev/null
+// run-rustfix
+#![allow(unused)]
+struct S {f:String}
+impl Drop for S {
+ fn drop(&mut self) { println!("{}", self.f); }
+}
+
+fn move_in_match() {
+ match (S {f:"foo".to_string()}) {
+ //~^ ERROR [E0509]
+ S {f:ref _s} => {}
+ }
+}
+
+fn move_in_let() {
+ let S {f:ref _s} = S {f:"foo".to_string()};
+ //~^ ERROR [E0509]
+}
+
+fn move_in_fn_arg(S {f:ref _s}: S) {
+ //~^ ERROR [E0509]
+}
+
+fn main() {}
+// run-rustfix
+#![allow(unused)]
struct S {f:String}
impl Drop for S {
fn drop(&mut self) { println!("{}", self.f); }
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
- --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:7:11
+ --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:9:11
|
LL | match (S {f:"foo".to_string()}) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
| |
| data moved here
| move occurs because `_s` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | S {f:ref _s} => {}
+ | +++
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
- --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:14:20
+ --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:16:20
|
LL | let S {f:_s} = S {f:"foo".to_string()};
| -- ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
| |
| data moved here
| move occurs because `_s` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | let S {f:ref _s} = S {f:"foo".to_string()};
+ | +++
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
- --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:18:19
+ --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:20:19
|
LL | fn move_in_fn_arg(S {f:_s}: S) {
| ^^^^^--^
| | data moved here
| | move occurs because `_s` has type `String`, which does not implement the `Copy` trait
| cannot move out of here
+ |
+help: consider borrowing the pattern binding
+ |
+LL | fn move_in_fn_arg(S {f:ref _s}: S) {
+ | +++
error: aborting due to 3 previous errors
--- /dev/null
+// run-rustfix
+#![allow(unused)]
+struct S(String);
+impl Drop for S {
+ fn drop(&mut self) { }
+}
+
+fn move_in_match() {
+ match S("foo".to_string()) {
+ //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+ S(ref _s) => {}
+ }
+}
+
+fn move_in_let() {
+ let S(ref _s) = S("foo".to_string());
+ //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+}
+
+fn move_in_fn_arg(S(ref _s): S) {
+ //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+}
+
+fn main() {}
+// run-rustfix
+#![allow(unused)]
struct S(String);
impl Drop for S {
fn drop(&mut self) { }
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
- --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:7:11
+ --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:9:11
|
LL | match S("foo".to_string()) {
| ^^^^^^^^^^^^^^^^^^^^ cannot move out of here
| |
| data moved here
| move occurs because `_s` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | S(ref _s) => {}
+ | +++
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
- --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:14:17
+ --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:16:17
|
LL | let S(_s) = S("foo".to_string());
| -- ^^^^^^^^^^^^^^^^^^^^ cannot move out of here
| |
| data moved here
| move occurs because `_s` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | let S(ref _s) = S("foo".to_string());
+ | +++
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
- --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:18:19
+ --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:20:19
|
LL | fn move_in_fn_arg(S(_s): S) {
| ^^--^
| | data moved here
| | move occurs because `_s` has type `String`, which does not implement the `Copy` trait
| cannot move out of here
+ |
+help: consider borrowing the pattern binding
+ |
+LL | fn move_in_fn_arg(S(ref _s): S) {
+ | +++
error: aborting due to 3 previous errors
| - ...and here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
-help: consider removing the `&`
+help: consider removing the borrow
|
-LL ~ [Foo { string: a },
-LL ~ Foo { string: b }] => {
+LL - &[Foo { string: a },
+LL + [Foo { string: a },
|
error: aborting due to previous error
--> $DIR/borrowck-overloaded-index-move-from-vec.rs:20:15
|
LL | let bad = v[0];
- | ^^^^
- | |
- | move occurs because value has type `Box<i32>`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&v[0]`
+ | ^^^^ move occurs because value has type `Box<i32>`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let bad = &v[0];
+ | +
error: aborting due to previous error
&mut [_a,
//~^ NOTE data moved here
//~| NOTE move occurs because `_a` has type
- //~| HELP consider removing the `&mut`
+ //~| HELP consider removing the mutable borrow
..
] => {
}
//~^ ERROR cannot move out
//~| NOTE cannot move out
&mut [
- //~^ HELP consider removing the `&mut`
+ //~^ HELP consider removing the mutable borrow
_b] => {}
//~^ NOTE data moved here
//~| NOTE move occurs because `_b` has type
//~^ NOTE data moved here
//~| NOTE and here
//~| NOTE and here
- //~| HELP consider removing the `&mut`
+ //~| HELP consider removing the mutable borrow
_ => {}
}
let a = vec[0]; //~ ERROR cannot move out
| data moved here
| move occurs because `_a` has type `Box<isize>`, which does not implement the `Copy` trait
|
-help: consider removing the `&mut`
+help: consider removing the mutable borrow
|
-LL ~ [_a,
-LL +
-LL +
-LL +
-LL + ..
-LL ~ ] => {
+LL - &mut [_a,
+LL + [_a,
|
error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
| |
| cannot move out of here
| move occurs because `vec[_]` has type `Box<isize>`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&vec[0]`
+ |
+help: consider borrowing here
+ |
+LL | let a = &vec[0];
+ | +
error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
--> $DIR/borrowck-vec-pattern-nesting.rs:55:11
| data moved here
| move occurs because `_b` has type `Box<isize>`, which does not implement the `Copy` trait
|
-help: consider removing the `&mut`
+help: consider removing the mutable borrow
|
-LL ~ [
-LL +
-LL ~ _b] => {}
+LL - &mut [
+LL + [
|
error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
| |
| cannot move out of here
| move occurs because `vec[_]` has type `Box<isize>`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&vec[0]`
+ |
+help: consider borrowing here
+ |
+LL | let a = &vec[0];
+ | +
error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
--> $DIR/borrowck-vec-pattern-nesting.rs:74:11
| ^^^ cannot move out of here
...
LL | &mut [_a, _b, _c] => {}
- | -----------------
- | | | | |
- | | | | ...and here
- | | | ...and here
- | | data moved here
- | help: consider removing the `&mut`: `[_a, _b, _c]`
+ | -- -- -- ...and here
+ | | |
+ | | ...and here
+ | data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the mutable borrow
+ |
+LL - &mut [_a, _b, _c] => {}
+LL + [_a, _b, _c] => {}
+ |
error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
--> $DIR/borrowck-vec-pattern-nesting.rs:85:13
| |
| cannot move out of here
| move occurs because `vec[_]` has type `Box<isize>`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&vec[0]`
+ |
+help: consider borrowing here
+ |
+LL | let a = &vec[0];
+ | +
error: aborting due to 8 previous errors
--- /dev/null
+// edition:2018
+// check-pass
+
+#![allow(dead_code)]
+async fn fail<'a, 'b, 'c>(_: &'static str) where 'a: 'c, 'b: 'c, {}
+async fn pass<'a, 'c, 'b>(_: &'static str) where 'a: 'c, 'b: 'c, {}
+async fn pass2<'a, 'b, 'c>(_: &'static str) where 'a: 'c, 'b: 'c, 'c: 'a, {}
+async fn pass3<'a, 'b, 'c>(_: &'static str) where 'a: 'b, 'b: 'c, 'c: 'a, {}
+
+fn main() { }
--> $DIR/issue-17718-static-move.rs:6:14
|
LL | let _a = FOO;
- | ^^^
- | |
- | move occurs because `FOO` has type `Foo`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&FOO`
+ | ^^^ move occurs because `FOO` has type `Foo`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let _a = &FOO;
+ | +
error: aborting due to previous error
--> $DIR/issue-20801.rs:26:22
|
LL | let a = unsafe { *mut_ref() };
- | ^^^^^^^^^^
- | |
- | move occurs because value has type `T`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*mut_ref()`
+ | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let a = unsafe { *mut_ref() };
+LL + let a = unsafe { mut_ref() };
+ |
error[E0507]: cannot move out of a shared reference
--> $DIR/issue-20801.rs:29:22
|
LL | let b = unsafe { *imm_ref() };
- | ^^^^^^^^^^
- | |
- | move occurs because value has type `T`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*imm_ref()`
+ | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let b = unsafe { *imm_ref() };
+LL + let b = unsafe { imm_ref() };
+ |
error[E0507]: cannot move out of a raw pointer
--> $DIR/issue-20801.rs:32:22
|
LL | let c = unsafe { *mut_ptr() };
- | ^^^^^^^^^^
- | |
- | move occurs because value has type `T`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*mut_ptr()`
+ | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let c = unsafe { *mut_ptr() };
+LL + let c = unsafe { mut_ptr() };
+ |
error[E0507]: cannot move out of a raw pointer
--> $DIR/issue-20801.rs:35:22
|
LL | let d = unsafe { *const_ptr() };
- | ^^^^^^^^^^^^
- | |
- | move occurs because value has type `T`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*const_ptr()`
+ | ^^^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let d = unsafe { *const_ptr() };
+LL + let d = unsafe { const_ptr() };
+ |
error: aborting due to 4 previous errors
--> $DIR/issue-47215-ice-from-drop-elab.rs:17:21
|
LL | let mut x = X;
- | ^
- | |
- | move occurs because `X` has type `AtomicUsize`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&X`
+ | ^ move occurs because `X` has type `AtomicUsize`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let mut x = &X;
+ | +
error: aborting due to previous error
| |
| data moved here
| move occurs because `event_type` has type `EventType`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | .find(|(&ref event_type, _)| event == event_type)
+ | +++
error: aborting due to previous error
--- /dev/null
+// run-rustfix
+// Regression test for #51415: match default bindings were failing to
+// see the "move out" implied by `&s` below.
+
+fn main() {
+ let a = vec![String::from("a")];
+ let opt = a.iter().enumerate().find(|(_, &ref s)| {
+ //~^ ERROR cannot move out
+ *s == String::from("d")
+ }).map(|(i, _)| i);
+ println!("{:?}", opt);
+}
+// run-rustfix
// Regression test for #51415: match default bindings were failing to
// see the "move out" implied by `&s` below.
error[E0507]: cannot move out of a shared reference
- --> $DIR/issue-51415.rs:6:42
+ --> $DIR/issue-51415.rs:7:42
|
LL | let opt = a.iter().enumerate().find(|(_, &s)| {
| ^^^^^-^
| |
| data moved here
| move occurs because `s` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | let opt = a.iter().enumerate().find(|(_, &ref s)| {
+ | +++
error: aborting due to previous error
--> $DIR/issue-54597-reject-move-out-of-borrow-via-pat.rs:14:13
|
LL | *array
- | ^^^^^^
- | |
- | move occurs because `*array` has type `Vec<Value>`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*array`
+ | ^^^^^^ move occurs because `*array` has type `Vec<Value>`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - *array
+LL + array
+ |
error: aborting due to previous error
LL | let _y = foo;
| ^^^ value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `foo`
+note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `foo`
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | pub const fn unwrap(self) -> T {
- | ^^^^
error[E0382]: use of moved value: `foo`
--> $DIR/issue-83760.rs:37:14
LL | } else if true {
LL | foo = Some(Struct);
| ^^^^^^^^^^^^^^^^^^
-note: this function takes ownership of the receiver `self`, which moves `foo`
+note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `foo`
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | pub const fn unwrap(self) -> T {
- | ^^^^
error: aborting due to 3 previous errors
| -- captured by this `FnMut` closure
LL |
LL | let _foo: String = val;
- | ^^^
- | |
- | move occurs because `val` has type `String`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&val`
+ | ^^^ move occurs because `val` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let _foo: String = &val;
+ | +
error: aborting due to previous error
--> $DIR/move-error-snippets-ext.rs:5:17
|
LL | let a = $c;
- | ^^
- | |
- | move occurs because `D` has type `A`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&$c`
+ | ^^ move occurs because `D` has type `A`, which does not implement the `Copy` trait
|
::: $DIR/move-error-snippets.rs:21:1
|
| ------ in this macro invocation
|
= note: this error originates in the macro `aaa` which comes from the expansion of the macro `sss` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider borrowing here
+ |
+LL | let a = &$c;
+ | +
error: aborting due to previous error
LL | fill_segment(state);
| ^^^^^ value borrowed here after move
|
-note: this function takes ownership of the receiver `self`, which moves `state`
+note: `into_iter` takes ownership of the receiver `self`, which moves `state`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
help: consider creating a fresh reborrow of `state` here
|
LL | for _ in &mut *state {}
| help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
| move occurs because `*cb` has type `Option<&mut dyn FnMut()>`, which does not implement the `Copy` trait
|
-note: this function takes ownership of the receiver `self`, which moves `*cb`
+note: `Option::<T>::map` takes ownership of the receiver `self`, which moves `*cb`
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | pub const fn map<U, F>(self, f: F) -> Option<U>
- | ^^^^
error[E0596]: cannot borrow `*cb` as mutable, as it is behind a `&` reference
--> $DIR/suggest-as-ref-on-mut-closure.rs:12:26
| |
| move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
|
-note: this function takes ownership of the receiver `self`, which moves `y`
+note: `into_iter` takes ownership of the receiver `self`, which moves `y`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
error: aborting due to previous error
= help: the trait `Sized` is not implemented for `[u8]`
note: required by a bound in `Box::<T, A>::into_boxed_slice`
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
- |
-LL | impl<T, A: Allocator> Box<T, A> {
- | ^ required by this bound in `Box::<T, A>::into_boxed_slice`
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/into-boxed-slice-fail.rs:7:13
= help: the trait `Sized` is not implemented for `dyn Debug`
note: required by a bound in `Box::<T, A>::into_boxed_slice`
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
- |
-LL | impl<T, A: Allocator> Box<T, A> {
- | ^ required by this bound in `Box::<T, A>::into_boxed_slice`
error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time
--> $DIR/into-boxed-slice-fail.rs:11:13
&E::Foo => {}
&E::Bar(ref identifier) => println!("{}", *identifier)
};
+ if let &E::Bar(identifier) = &s.x { //~ ERROR cannot move
+ f(identifier.clone());
+ };
+ let &E::Bar(identifier) = &s.x else { //~ ERROR cannot move
+ return;
+ };
+ f(identifier.clone());
}
| ^^^^
LL | &E::Foo => {}
LL | &E::Bar(identifier) => f(identifier.clone())
- | -------------------
- | | |
- | | data moved here
- | | move occurs because `identifier` has type `String`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `E::Bar(identifier)`
+ | ----------
+ | |
+ | data moved here
+ | move occurs because `identifier` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - &E::Bar(identifier) => f(identifier.clone())
+LL + E::Bar(identifier) => f(identifier.clone())
+ |
+
+error[E0507]: cannot move out of a shared reference
+ --> $DIR/by-move-pattern-binding.rs:22:34
+ |
+LL | if let &E::Bar(identifier) = &s.x {
+ | ---------- ^^^^
+ | |
+ | data moved here
+ | move occurs because `identifier` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - if let &E::Bar(identifier) = &s.x {
+LL + if let E::Bar(identifier) = &s.x {
+ |
+
+error[E0507]: cannot move out of a shared reference
+ --> $DIR/by-move-pattern-binding.rs:25:31
+ |
+LL | let &E::Bar(identifier) = &s.x else {
+ | ---------- ^^^^
+ | |
+ | data moved here
+ | move occurs because `identifier` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - let &E::Bar(identifier) = &s.x else {
+LL + let E::Bar(identifier) = &s.x else {
+ |
-error: aborting due to previous error
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0507`.
|
LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
| ^
+ --> $SRC_DIR/core/src/ops/function.rs:LL:COL
|
- ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
- | -------------------------------------- similarly named trait `Fn` defined here
+ = note: similarly named trait `Fn` defined here
|
help: a trait with a similar name exists
|
= note: [async fn body@$DIR/async.rs:7:29: 9:2] must be a future or must implement `IntoFuture` to be awaited
note: required by a bound in `identity_future`
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
- |
-LL | pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
- | ^^^^^^^^^^^^^^^^^^ required by this bound in `identity_future`
error[E0277]: the size for values of type `<[async fn body@$DIR/async.rs:7:29: 9:2] as Future>::Output` cannot be known at compilation time
--> $DIR/async.rs:7:29
= help: the trait `Sized` is not implemented for `<[async fn body@$DIR/async.rs:7:29: 9:2] as Future>::Output`
note: required by a bound in `identity_future`
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
- |
-LL | pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
- | ^ required by this bound in `identity_future`
error[E0277]: `[async fn body@$DIR/async.rs:7:29: 9:2]` is not a future
--> $DIR/async.rs:7:25
--> $DIR/check-static-values-constraints.rs:110:45
|
LL | let y = { static x: Box<isize> = box 3; x };
- | ^
- | |
- | move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&x`
+ | ^ move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let y = { static x: Box<isize> = box 3; &x };
+ | +
error[E0010]: allocations are not allowed in statics
--> $DIR/check-static-values-constraints.rs:110:38
|
help: consider giving this closure parameter an explicit type
|
-LL | with_closure(|x: u32, y: _| {});
- | +++
+LL | with_closure(|x: u32, y: /* Type */| {});
+ | ++++++++++++
error: aborting due to previous error
= note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
note: required by a bound in `Option::<T>::or_else`
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | F: ~const FnOnce() -> Option<T>,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::or_else`
error: aborting due to previous error
| ^^
note: required by a bound in `spawn`
--> $SRC_DIR/std/src/thread/mod.rs:LL:COL
- |
-LL | F: Send + 'static,
- | ^^^^ required by this bound in `spawn`
error[E0277]: `Sender<()>` cannot be shared between threads safely
--> $DIR/closure-move-sync.rs:18:19
| ^^
note: required by a bound in `spawn`
--> $SRC_DIR/std/src/thread/mod.rs:LL:COL
- |
-LL | F: Send + 'static,
- | ^^^^ required by this bound in `spawn`
error: aborting due to 2 previous errors
= note: unsafe function cannot be called generically without an unsafe block
note: required by a bound in `Option::<T>::map`
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | F: ~const FnOnce(T) -> U,
- | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
error: aborting due to previous error
|
help: consider giving this closure parameter an explicit type
|
-LL | [(); &(&'static: loop { |x: _| {}; }) as *const _ as usize]
- | +++
+LL | [(); &(&'static: loop { |x: /* Type */| {}; }) as *const _ as usize]
+ | ++++++++++++
error: aborting due to 2 previous errors
|
LL | _func: F,
| ^
+ --> $SRC_DIR/core/src/ops/function.rs:LL:COL
|
- ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
- | -------------------------------------- similarly named trait `Fn` defined here
+ = note: similarly named trait `Fn` defined here
|
help: a trait with a similar name exists
|
|
note: tuple variant defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^
error[E0308]: mismatched types
--> $DIR/issue-87461.rs:17:8
|
note: tuple variant defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^
error[E0308]: mismatched types
--> $DIR/issue-87461.rs:26:12
|
note: tuple variant defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^
error: aborting due to 3 previous errors
|
LL | type_ascribe!(2, n([u8; || 1]))
| ^ help: a trait with a similar name exists: `Fn`
+ --> $SRC_DIR/core/src/ops/function.rs:LL:COL
|
- ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
- | -------------------------------------- similarly named trait `Fn` defined here
+ = note: similarly named trait `Fn` defined here
error[E0308]: mismatched types
--> $DIR/issue-90871.rs:4:29
--> $DIR/multiple-fn-bounds.rs:10:5
|
LL | foo(move |x| v);
- | ^^^ -------- found signature defined here
- | |
+ | ^^^ --------
+ | | | |
+ | | | help: do not borrow the argument: `char`
+ | | found signature defined here
| expected due to this
|
= note: expected closure signature `fn(char) -> _`
LL | println!("{:?}", some_vec);
| ^^^^^^^^ value borrowed here after move
|
-note: this function takes ownership of the receiver `self`, which moves `some_vec`
+note: `into_iter` takes ownership of the receiver `self`, which moves `some_vec`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
|
-error[E0599]: no method named `closure` found for reference `&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:45]>` in the current scope
+error[E0599]: no method named `closure` found for reference `&Obj<[closure@issue-33784.rs:25:43]>` in the current scope
--> $DIR/issue-33784.rs:27:7
|
LL | p.closure();
LL | (p.closure)();
| + +
-error[E0599]: no method named `fn_ptr` found for reference `&&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:45]>` in the current scope
+error[E0599]: no method named `fn_ptr` found for reference `&&Obj<[closure@issue-33784.rs:25:43]>` in the current scope
--> $DIR/issue-33784.rs:29:7
|
LL | q.fn_ptr();
| ^ ------------------- type must be known at this point
|
= note: cannot satisfy `_: MaskElement`
+ = help: the following types implement trait `MaskElement`:
+ i16
+ i32
+ i64
+ i8
+ isize
note: required by a bound in `Mask::<T, LANES>::splat`
--> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL
- |
-LL | T: MaskElement,
- | ^^^^^^^^^^^ required by this bound in `Mask::<T, LANES>::splat`
help: consider giving `y` an explicit type, where the type for type parameter `T` is specified
|
LL | let y: Mask<_, LANES> = Mask::<_, _>::splat(false);
--- /dev/null
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+struct Combination<const STRATEGIES: usize>;
+
+impl<const STRATEGIES: usize> Combination<STRATEGIES> {
+ fn and<M>(self) -> Combination<{ STRATEGIES + 1 }> {
+ Combination
+ }
+}
+
+pub fn main() {
+ Combination::<0>.and::<_>().and::<_>();
+ //~^ ERROR: type annotations needed
+}
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/issue-105608.rs:13:22
+ |
+LL | Combination::<0>.and::<_>().and::<_>();
+ | ^^^ cannot infer type of the type parameter `M` declared on the associated function `and`
+ |
+help: consider specifying the generic argument
+ |
+LL | Combination::<0>.and::<_>().and::<_>();
+ | ~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
LL | IsLessOrEqual<I, 8>: True,
| ^^^^
|
- = note: cannot satisfy `IsLessOrEqual<I, 8>: True`
+note: multiple `impl`s or `where` clauses satisfying `IsLessOrEqual<I, 8>: True` found
+ --> $DIR/issue-72787.rs:10:1
+ |
+LL | impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | IsLessOrEqual<I, 8>: True,
+ | ^^^^
+...
+LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
+ | ^^^^
error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8>: True`
--> $DIR/issue-72787.rs:21:26
LL | IsLessOrEqual<I, 8>: True,
| ^^^^
|
- = note: cannot satisfy `IsLessOrEqual<I, 8>: True`
+note: multiple `impl`s or `where` clauses satisfying `IsLessOrEqual<I, 8>: True` found
+ --> $DIR/issue-72787.rs:10:1
+ |
+LL | impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | IsLessOrEqual<I, 8>: True,
+ | ^^^^
+...
+LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
+ | ^^^^
error: aborting due to 6 previous errors
error[E0080]: evaluation of `Inline::<dyn std::fmt::Debug>::{constant#0}` failed
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
-LL | intrinsics::size_of::<T>()
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ size_of called on unsized type `dyn Debug`
+ = note: size_of called on unsized type `dyn Debug`
|
note: inside `std::mem::size_of::<dyn Debug>`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | intrinsics::size_of::<T>()
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `Inline::<dyn Debug>::{constant#0}`
--> $DIR/issue-80742.rs:22:10
|
...
LL | let dst = Inline::<dyn Debug>::new(0);
| ^^^ function or associated item cannot be called on `Inline<dyn Debug>` due to unsatisfied trait bounds
+ --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
|
- ::: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- |
-LL | pub trait Debug {
- | --------------- doesn't satisfy `dyn Debug: Sized`
+ = note: doesn't satisfy `dyn Debug: Sized`
|
= note: the following trait bounds were not satisfied:
`dyn Debug: Sized`
error[E0080]: evaluation of `Inline::<dyn std::fmt::Debug>::{constant#0}` failed
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
-LL | intrinsics::size_of::<T>()
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ size_of called on unsized type `dyn Debug`
+ = note: size_of called on unsized type `dyn Debug`
|
note: inside `std::mem::size_of::<dyn Debug>`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | intrinsics::size_of::<T>()
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `Inline::<dyn Debug>::{constant#0}`
--> $DIR/issue-80742.rs:14:10
|
LL | let _: u32 = 5i32.try_into::<32>().unwrap();
| ^^^^^^^^ expected 0 generic arguments
|
-note: associated function defined here, with 0 generic parameters
- --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
- |
-LL | fn try_into(self) -> Result<T, Self::Error>;
- | ^^^^^^^^
help: consider moving this generic argument to the `TryInto` trait, which takes up to 1 argument
|
LL | let _: u32 = TryInto::<32>::try_into(5i32).unwrap();
| ^^^^ --- help: remove this generic argument
| |
| expected 1 generic argument
- |
-note: struct defined here, with 1 generic parameter: `T`
- --> $SRC_DIR/core/src/cell.rs:LL:COL
- |
-LL | pub struct Cell<T: ?Sized> {
- | ^^^^ -
error: aborting due to previous error
|
help: consider giving this pattern a type
|
-LL | let _: _ = foo([0; 1]);
- | +++
+LL | let _: /* Type */ = foo([0; 1]);
+ | ++++++++++++
error: aborting due to previous error
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
+ = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
|
note: inside `std::slice::from_raw_parts::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `S0`
--> $DIR/forbidden_slices.rs:18:34
|
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
+ = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
|
note: inside `std::slice::from_raw_parts::<'_, ()>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `S1`
--> $DIR/forbidden_slices.rs:19:33
|
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+ = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
|
note: inside `std::slice::from_raw_parts::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `S2`
--> $DIR/forbidden_slices.rs:22:34
|
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─ALLOC_ID─╼ 01 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
= help: this code performed an operation that depends on the underlying bytes representing a pointer
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─ALLOC_ID─╼ 04 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─ALLOC_ID─╼ 04 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/forbidden_slices.rs:32:1
|
LL | pub static S7: &[u16] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+ | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─A_ID+0x1─╼ 04 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID+0x2╼ 04 00 00 00 │ ╾──╼....
}
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+ = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
|
note: inside `std::slice::from_raw_parts::<'_, u64>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `S8`
--> $DIR/forbidden_slices.rs:43:5
|
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
+ = note: out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
|
note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `from_ptr_range::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `R0`
--> $DIR/forbidden_slices.rs:46:34
|
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ = note: the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
note: inside `ptr::const_ptr::<impl *const ()>::sub_ptr`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `from_ptr_range::<'_, ()>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `R1`
--> $DIR/forbidden_slices.rs:47:33
|
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+ = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
|
note: inside `ptr::const_ptr::<impl *const u32>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `ptr::const_ptr::<impl *const u32>::add`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { self.offset(count as isize) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `R2`
--> $DIR/forbidden_slices.rs:50:25
|
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- â\95¾ALLOC_IDâ\94\80â\95¼ 01 00 00 00 â\94\82 â\95¾â\94\80â\94\80â\95¼....
+ ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
= help: this code performed an operation that depends on the underlying bytes representing a pointer
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
= note: the raw bytes of the constant (size: 8, align: 4) {
- â\95¾ALLOC_IDâ\94\80â\95¼ 04 00 00 00 â\94\82 â\95¾â\94\80â\94\80â\95¼....
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- â\95¾ALLOC_IDâ\94\80â\95¼ 04 00 00 00 â\94\82 â\95¾â\94\80â\94\80â\95¼....
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
}
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:67:1
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
-LL | pub static R7: &[u16] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+ = note: accessing memory with alignment 1, but alignment 2 is required
|
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾A_ID+0x1─╼ 04 00 00 00 │ ╾──╼....
- }
+note: inside `std::slice::from_raw_parts::<'_, u16>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `from_ptr_range::<'_, u16>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R7`
+ --> $DIR/forbidden_slices.rs:69:5
+ |
+LL | from_ptr_range(ptr..ptr.add(4))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+ = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
|
note: inside `ptr::const_ptr::<impl *const u64>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `ptr::const_ptr::<impl *const u64>::add`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { self.offset(count as isize) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `R8`
- --> $DIR/forbidden_slices.rs:74:25
+ --> $DIR/forbidden_slices.rs:73:25
|
LL | from_ptr_range(ptr..ptr.add(1))
| ^^^^^^^^^^
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations
+ = note: `ptr_offset_from_unsigned` called on pointers into different allocations
|
note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `from_ptr_range::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `R9`
- --> $DIR/forbidden_slices.rs:79:34
+ --> $DIR/forbidden_slices.rs:78:34
|
LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations
+ = note: `ptr_offset_from_unsigned` called on pointers into different allocations
|
note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `from_ptr_range::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `R10`
- --> $DIR/forbidden_slices.rs:80:35
+ --> $DIR/forbidden_slices.rs:79:35
|
LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
+ = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
|
note: inside `std::slice::from_raw_parts::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `S0`
--> $DIR/forbidden_slices.rs:18:34
|
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
+ = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
|
note: inside `std::slice::from_raw_parts::<'_, ()>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `S1`
--> $DIR/forbidden_slices.rs:19:33
|
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+ = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
|
note: inside `std::slice::from_raw_parts::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `S2`
--> $DIR/forbidden_slices.rs:22:34
|
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────ALLOC_ID───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
= help: this code performed an operation that depends on the underlying bytes representing a pointer
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────ALLOC_ID───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/forbidden_slices.rs:32:1
|
LL | pub static S7: &[u16] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+ | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾─────ALLOC_ID+0x1─────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID+0x2╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+ = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
|
note: inside `std::slice::from_raw_parts::<'_, u64>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | &*ptr::slice_from_raw_parts(data, len)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `S8`
--> $DIR/forbidden_slices.rs:43:5
|
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
+ = note: out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
|
note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `from_ptr_range::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `R0`
--> $DIR/forbidden_slices.rs:46:34
|
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ = note: the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
note: inside `ptr::const_ptr::<impl *const ()>::sub_ptr`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `from_ptr_range::<'_, ()>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `R1`
--> $DIR/forbidden_slices.rs:47:33
|
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+ = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
|
note: inside `ptr::const_ptr::<impl *const u32>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `ptr::const_ptr::<impl *const u32>::add`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { self.offset(count as isize) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `R2`
--> $DIR/forbidden_slices.rs:50:25
|
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────ALLOC_ID───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
= help: this code performed an operation that depends on the underlying bytes representing a pointer
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────ALLOC_ID───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
}
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:67:1
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
-LL | pub static R7: &[u16] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+ = note: accessing memory with alignment 1, but alignment 2 is required
|
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾────ALLOC_ID+0x1─────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
- }
+note: inside `std::slice::from_raw_parts::<'_, u16>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `from_ptr_range::<'_, u16>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R7`
+ --> $DIR/forbidden_slices.rs:69:5
+ |
+LL | from_ptr_range(ptr..ptr.add(4))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+ = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
|
note: inside `ptr::const_ptr::<impl *const u64>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `ptr::const_ptr::<impl *const u64>::add`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { self.offset(count as isize) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `R8`
- --> $DIR/forbidden_slices.rs:74:25
+ --> $DIR/forbidden_slices.rs:73:25
|
LL | from_ptr_range(ptr..ptr.add(1))
| ^^^^^^^^^^
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations
+ = note: `ptr_offset_from_unsigned` called on pointers into different allocations
|
note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `from_ptr_range::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `R9`
- --> $DIR/forbidden_slices.rs:79:34
+ --> $DIR/forbidden_slices.rs:78:34
|
LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations
+ = note: `ptr_offset_from_unsigned` called on pointers into different allocations
|
note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `from_ptr_range::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
- |
-LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `R10`
- --> $DIR/forbidden_slices.rs:80:35
+ --> $DIR/forbidden_slices.rs:79:35
|
LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^
// stderr-per-bitwidth
-// normalize-stderr-test "alloc[0-9]+" -> "ALLOC_ID"
-// normalize-stderr-test "a[0-9]+\+0x" -> "A_ID+0x"
+// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼"
+// normalize-stderr-test "alloc\d+" -> "allocN"
// error-pattern: could not evaluate static initializer
#![feature(
slice_from_ptr_range,
// Reading padding is not ok
pub static S7: &[u16] = unsafe {
//~^ ERROR: it is undefined behavior to use this value
- let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+ let ptr = (&D2 as *const Struct as *const u16).add(1);
from_raw_parts(ptr, 4)
};
from_ptr_range(ptr..ptr.add(4))
};
pub static R7: &[u16] = unsafe {
- //~^ ERROR: it is undefined behavior to use this value
let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
- from_ptr_range(ptr..ptr.add(4))
+ from_ptr_range(ptr..ptr.add(4)) //~ inside `R7`
};
pub static R8: &[u64] = unsafe {
let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::<u64>();
- from_ptr_range(ptr..ptr.add(1))
+ from_ptr_range(ptr..ptr.add(1)) //~ inside `R8`
};
// This is sneaky: &D0 and &D0 point to different objects
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
-LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
+ = note: memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
|
note: inside `std::ptr::read::<u32>`
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
-LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `_READ`
--> $DIR/out_of_bounds_read.rs:12:33
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
-LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
+ = note: memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
|
note: inside `std::ptr::read::<u32>`
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
-LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `ptr::const_ptr::<impl *const u32>::read`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { read(self) }
- | ^^^^^^^^^^
note: inside `_CONST_READ`
--> $DIR/out_of_bounds_read.rs:13:39
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
-LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
+ = note: memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
|
note: inside `std::ptr::read::<u32>`
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
-LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `ptr::mut_ptr::<impl *mut u32>::read`
--> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
- |
-LL | unsafe { read(self) }
- | ^^^^^^^^^^
note: inside `_MUT_READ`
--> $DIR/out_of_bounds_read.rs:14:37
|
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:13:1
+ --> $DIR/ub-ref-ptr.rs:14:1
|
LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
| ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:17:1
+ --> $DIR/ub-ref-ptr.rs:18:1
|
LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:21:1
+ --> $DIR/ub-ref-ptr.rs:22:1
|
LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:24:1
+ --> $DIR/ub-ref-ptr.rs:25:1
|
LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:31:1
+ --> $DIR/ub-ref-ptr.rs:32:1
|
LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:34:39
+ --> $DIR/ub-ref-ptr.rs:35:39
|
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
note: erroneous constant used
- --> $DIR/ub-ref-ptr.rs:34:38
+ --> $DIR/ub-ref-ptr.rs:35:38
|
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:37:86
+ --> $DIR/ub-ref-ptr.rs:38:86
|
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
| ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
note: erroneous constant used
- --> $DIR/ub-ref-ptr.rs:37:85
+ --> $DIR/ub-ref-ptr.rs:38:85
|
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
| ^^^^^^^^^^^^^^^^^^^^^
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:40:1
+ --> $DIR/ub-ref-ptr.rs:41:1
|
LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:43:1
+ --> $DIR/ub-ref-ptr.rs:44:1
|
LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:46:41
+ --> $DIR/ub-ref-ptr.rs:47:41
|
LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:50:1
+ --> $DIR/ub-ref-ptr.rs:51:1
|
LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:52:38
+ --> $DIR/ub-ref-ptr.rs:53:38
|
LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:55:1
+ --> $DIR/ub-ref-ptr.rs:56:1
|
LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:57:1
+ --> $DIR/ub-ref-ptr.rs:58:1
|
LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
╾─alloc41─╼ │ ╾──╼
}
-error: aborting due to 14 previous errors
+error: accessing memory with alignment 1, but alignment 4 is required
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+ --> $DIR/ub-ref-ptr.rs:65:5
+ |
+LL | ptr.read();
+ | ^^^^^^^^^^
+ = note: `#[deny(invalid_alignment)]` on by default
+
+error: aborting due to 15 previous errors
For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: accessing memory with alignment 1, but alignment 4 is required
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+ --> $DIR/ub-ref-ptr.rs:65:5
+ |
+LL | ptr.read();
+ | ^^^^^^^^^^
+ = note: `#[deny(invalid_alignment)]` on by default
+
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:13:1
+ --> $DIR/ub-ref-ptr.rs:14:1
|
LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
| ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:17:1
+ --> $DIR/ub-ref-ptr.rs:18:1
|
LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:21:1
+ --> $DIR/ub-ref-ptr.rs:22:1
|
LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:24:1
+ --> $DIR/ub-ref-ptr.rs:25:1
|
LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:31:1
+ --> $DIR/ub-ref-ptr.rs:32:1
|
LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:34:39
+ --> $DIR/ub-ref-ptr.rs:35:39
|
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
note: erroneous constant used
- --> $DIR/ub-ref-ptr.rs:34:38
+ --> $DIR/ub-ref-ptr.rs:35:38
|
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:37:86
+ --> $DIR/ub-ref-ptr.rs:38:86
|
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
| ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
note: erroneous constant used
- --> $DIR/ub-ref-ptr.rs:37:85
+ --> $DIR/ub-ref-ptr.rs:38:85
|
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
| ^^^^^^^^^^^^^^^^^^^^^
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:40:1
+ --> $DIR/ub-ref-ptr.rs:41:1
|
LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:43:1
+ --> $DIR/ub-ref-ptr.rs:44:1
|
LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:46:41
+ --> $DIR/ub-ref-ptr.rs:47:41
|
LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:50:1
+ --> $DIR/ub-ref-ptr.rs:51:1
|
LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:52:38
+ --> $DIR/ub-ref-ptr.rs:53:38
|
LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:55:1
+ --> $DIR/ub-ref-ptr.rs:56:1
|
LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:57:1
+ --> $DIR/ub-ref-ptr.rs:58:1
|
LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
╾───────alloc41───────╼ │ ╾──────╼
}
-error: aborting due to 14 previous errors
+error: accessing memory with alignment 1, but alignment 4 is required
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+ --> $DIR/ub-ref-ptr.rs:65:5
+ |
+LL | ptr.read();
+ | ^^^^^^^^^^
+ = note: `#[deny(invalid_alignment)]` on by default
+
+error: aborting due to 15 previous errors
For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: accessing memory with alignment 1, but alignment 4 is required
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+ --> $DIR/ub-ref-ptr.rs:65:5
+ |
+LL | ptr.read();
+ | ^^^^^^^^^^
+ = note: `#[deny(invalid_alignment)]` on by default
+
// ignore-tidy-linelength
// stderr-per-bitwidth
#![allow(invalid_value)]
+#![feature(const_ptr_read)]
use std::mem;
const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
//~^ ERROR it is undefined behavior to use this value
+
+const UNALIGNED_READ: () = unsafe {
+ let x = &[0u8; 4];
+ let ptr = x.as_ptr().cast::<u32>();
+ ptr.read(); //~ inside `UNALIGNED_READ`
+};
+
+
fn main() {}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:36:1
+ --> $DIR/ub-wide-ptr.rs:37:1
|
LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN──╼ e7 03 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:38:1
+ --> $DIR/ub-wide-ptr.rs:39:1
|
LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN─╼ ff ff ff ff │ ╾──╼....
+ ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼....
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:41:1
+ --> $DIR/ub-wide-ptr.rs:42:1
|
LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:44:1
+ --> $DIR/ub-wide-ptr.rs:45:1
|
LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:46:1
+ --> $DIR/ub-wide-ptr.rs:47:1
|
LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN─╼ ff ff ff ff │ ╾──╼....
+ ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:50:1
+ --> $DIR/ub-wide-ptr.rs:51:1
|
LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN─╼ 01 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:53:1
+ --> $DIR/ub-wide-ptr.rs:54:1
|
LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN─╼ 01 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:60:1
+ --> $DIR/ub-wide-ptr.rs:61:1
|
LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:67:1
+ --> $DIR/ub-wide-ptr.rs:68:1
|
LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN─╼ e7 03 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:70:1
+ --> $DIR/ub-wide-ptr.rs:71:1
|
LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN─╼ ff ff ff 7f │ ╾──╼....
+ ╾ALLOC_ID╼ ff ff ff 7f │ ╾──╼....
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:73:1
+ --> $DIR/ub-wide-ptr.rs:74:1
|
LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:76:1
+ --> $DIR/ub-wide-ptr.rs:77:1
|
LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN─╼ e7 03 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼....
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:79:1
+ --> $DIR/ub-wide-ptr.rs:80:1
|
LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:83:1
+ --> $DIR/ub-wide-ptr.rs:84:1
|
LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
- ╾─allocN─╼ │ ╾──╼
+ ╾ALLOC_ID╼ │ ╾──╼
}
note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:83:40
+ --> $DIR/ub-wide-ptr.rs:84:40
|
LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:90:1
+ --> $DIR/ub-wide-ptr.rs:91:1
|
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
- ╾allocN─╼ │ ╾──╼
+ ╾ALLOC_ID╼ │ ╾──╼
}
note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:90:42
+ --> $DIR/ub-wide-ptr.rs:91:42
|
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:94:1
+ --> $DIR/ub-wide-ptr.rs:95:1
|
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
- ╾allocN─╼ │ ╾──╼
+ ╾ALLOC_ID╼ │ ╾──╼
}
note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:94:42
+ --> $DIR/ub-wide-ptr.rs:95:42
|
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:102:1
+ --> $DIR/ub-wide-ptr.rs:103:1
|
LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:111:1
+ --> $DIR/ub-wide-ptr.rs:112:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:115:1
+ --> $DIR/ub-wide-ptr.rs:116:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:119:1
+ --> $DIR/ub-wide-ptr.rs:120:1
|
LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾allocN─╼ 04 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:122:57
+ --> $DIR/ub-wide-ptr.rs:123:57
|
LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:125:57
+ --> $DIR/ub-wide-ptr.rs:126:57
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:128:56
+ --> $DIR/ub-wide-ptr.rs:129:56
|
LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:131:1
+ --> $DIR/ub-wide-ptr.rs:132:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:136:1
+ --> $DIR/ub-wide-ptr.rs:137:1
|
LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:141:1
+ --> $DIR/ub-wide-ptr.rs:142:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾allocN─╼ 00 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ 00 00 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:143:1
+ --> $DIR/ub-wide-ptr.rs:144:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
}
error[E0080]: could not evaluate static initializer
- --> $DIR/ub-wide-ptr.rs:149:5
+ --> $DIR/ub-wide-ptr.rs:150:5
|
LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
error[E0080]: could not evaluate static initializer
- --> $DIR/ub-wide-ptr.rs:153:5
+ --> $DIR/ub-wide-ptr.rs:154:5
|
LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:36:1
+ --> $DIR/ub-wide-ptr.rs:37:1
|
LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN────────╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:38:1
+ --> $DIR/ub-wide-ptr.rs:39:1
|
LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN───────╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
+ ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:41:1
+ --> $DIR/ub-wide-ptr.rs:42:1
|
LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:44:1
+ --> $DIR/ub-wide-ptr.rs:45:1
|
LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:46:1
+ --> $DIR/ub-wide-ptr.rs:47:1
|
LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN───────╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
+ ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:50:1
+ --> $DIR/ub-wide-ptr.rs:51:1
|
LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:53:1
+ --> $DIR/ub-wide-ptr.rs:54:1
|
LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:60:1
+ --> $DIR/ub-wide-ptr.rs:61:1
|
LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:67:1
+ --> $DIR/ub-wide-ptr.rs:68:1
|
LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN───────╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:70:1
+ --> $DIR/ub-wide-ptr.rs:71:1
|
LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN───────╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........
+ ╾ALLOC_ID╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:73:1
+ --> $DIR/ub-wide-ptr.rs:74:1
|
LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:76:1
+ --> $DIR/ub-wide-ptr.rs:77:1
|
LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN───────╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:79:1
+ --> $DIR/ub-wide-ptr.rs:80:1
|
LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:83:1
+ --> $DIR/ub-wide-ptr.rs:84:1
|
LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
- ╾───────allocN───────╼ │ ╾──────╼
+ ╾ALLOC_ID╼ │ ╾──────╼
}
note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:83:40
+ --> $DIR/ub-wide-ptr.rs:84:40
|
LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:90:1
+ --> $DIR/ub-wide-ptr.rs:91:1
|
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
- ╾──────allocN───────╼ │ ╾──────╼
+ ╾ALLOC_ID╼ │ ╾──────╼
}
note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:90:42
+ --> $DIR/ub-wide-ptr.rs:91:42
|
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:94:1
+ --> $DIR/ub-wide-ptr.rs:95:1
|
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
- ╾──────allocN───────╼ │ ╾──────╼
+ ╾ALLOC_ID╼ │ ╾──────╼
}
note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:94:42
+ --> $DIR/ub-wide-ptr.rs:95:42
|
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:102:1
+ --> $DIR/ub-wide-ptr.rs:103:1
|
LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:111:1
+ --> $DIR/ub-wide-ptr.rs:112:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:115:1
+ --> $DIR/ub-wide-ptr.rs:116:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:119:1
+ --> $DIR/ub-wide-ptr.rs:120:1
|
LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────allocN───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:122:57
+ --> $DIR/ub-wide-ptr.rs:123:57
|
LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:125:57
+ --> $DIR/ub-wide-ptr.rs:126:57
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:128:56
+ --> $DIR/ub-wide-ptr.rs:129:56
|
LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:131:1
+ --> $DIR/ub-wide-ptr.rs:132:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:136:1
+ --> $DIR/ub-wide-ptr.rs:137:1
|
LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:141:1
+ --> $DIR/ub-wide-ptr.rs:142:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────allocN───────╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:143:1
+ --> $DIR/ub-wide-ptr.rs:144:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
}
error[E0080]: could not evaluate static initializer
- --> $DIR/ub-wide-ptr.rs:149:5
+ --> $DIR/ub-wide-ptr.rs:150:5
|
LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
error[E0080]: could not evaluate static initializer
- --> $DIR/ub-wide-ptr.rs:153:5
+ --> $DIR/ub-wide-ptr.rs:154:5
|
LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
use std::mem;
+// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼"
// normalize-stderr-test "offset \d+" -> "offset N"
// normalize-stderr-test "alloc\d+" -> "allocN"
// normalize-stderr-test "size \d+" -> "size N"
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/num/f32.rs:LL:COL
|
-LL | panic!("const-eval error: cannot use f32::to_bits on a NaN")
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL
+ = note: the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL
|
note: inside `core::f32::<impl f32>::to_bits::ct_f32_to_u32`
--> $SRC_DIR/core/src/num/f32.rs:LL:COL
- |
-LL | panic!("const-eval error: cannot use f32::to_bits on a NaN")
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `core::f32::<impl f32>::to_bits`
--> $SRC_DIR/core/src/num/f32.rs:LL:COL
- |
-LL | unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `f32::MASKED_NAN1`
--> $DIR/const-float-bits-reject-conv.rs:28:30
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/num/f32.rs:LL:COL
|
-LL | panic!("const-eval error: cannot use f32::to_bits on a NaN")
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL
+ = note: the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL
|
note: inside `core::f32::<impl f32>::to_bits::ct_f32_to_u32`
--> $SRC_DIR/core/src/num/f32.rs:LL:COL
- |
-LL | panic!("const-eval error: cannot use f32::to_bits on a NaN")
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `core::f32::<impl f32>::to_bits`
--> $SRC_DIR/core/src/num/f32.rs:LL:COL
- |
-LL | unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `f32::MASKED_NAN2`
--> $DIR/const-float-bits-reject-conv.rs:30:30
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/num/f64.rs:LL:COL
|
-LL | panic!("const-eval error: cannot use f64::to_bits on a NaN")
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL
+ = note: the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL
|
note: inside `core::f64::<impl f64>::to_bits::ct_f64_to_u64`
--> $SRC_DIR/core/src/num/f64.rs:LL:COL
- |
-LL | panic!("const-eval error: cannot use f64::to_bits on a NaN")
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `core::f64::<impl f64>::to_bits`
--> $SRC_DIR/core/src/num/f64.rs:LL:COL
- |
-LL | unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `f64::MASKED_NAN1`
--> $DIR/const-float-bits-reject-conv.rs:50:30
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/num/f64.rs:LL:COL
|
-LL | panic!("const-eval error: cannot use f64::to_bits on a NaN")
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL
+ = note: the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL
|
note: inside `core::f64::<impl f64>::to_bits::ct_f64_to_u64`
--> $SRC_DIR/core/src/num/f64.rs:LL:COL
- |
-LL | panic!("const-eval error: cannot use f64::to_bits on a NaN")
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `core::f64::<impl f64>::to_bits`
--> $SRC_DIR/core/src/num/f64.rs:LL:COL
- |
-LL | unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `f64::MASKED_NAN2`
--> $DIR/const-float-bits-reject-conv.rs:52:30
|
|
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | impl<I: Iterator> const IntoIterator for I {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
error[E0658]: mutable references are not allowed in constant functions
|
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | impl<I: Iterator> const IntoIterator for I {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/hint.rs:LL:COL
|
-LL | intrinsics::unreachable()
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code
+ = note: entering unreachable code
|
note: inside `unreachable_unchecked`
--> $SRC_DIR/core/src/hint.rs:LL:COL
- |
-LL | intrinsics::unreachable()
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `foo`
--> $DIR/const_unsafe_unreachable_ub.rs:6:18
|
// Since we are not copying anything, this should be allowed.
let src = ();
let mut dst = ();
- copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0);
+ copy_nonoverlapping(&src as *const _ as *const u8, &mut dst as *mut _ as *mut u8, 0);
};
const COPY_OOB_1: () = unsafe {
//[with_flag]~| invalid value
};
-const UNALIGNED_READ: () = {
- INNER; //[with_flag]~ constant
- // There is an error here but its span is in the standard library so we cannot match it...
- // so we have this in a *nested* const, such that the *outer* const fails to use it.
- const INNER: () = unsafe {
- let x = &[0u8; 4];
- let ptr = x.as_ptr().cast::<u32>();
- ptr.read();
- };
-};
-
fn main() {}
LL | let _x: &u32 = transmute(&[0u8; 4]);
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1)
-error[E0080]: evaluation of constant value failed
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
-LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment 1, but alignment 4 is required
- |
-note: inside `std::ptr::read::<u32>`
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
-LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: inside `ptr::const_ptr::<impl *const u32>::read`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { read(self) }
- | ^^^^^^^^^^
-note: inside `INNER`
- --> $DIR/detect-extra-ub.rs:38:9
- |
-LL | ptr.read();
- | ^^^^^^^^^^
-
-note: erroneous constant used
- --> $DIR/detect-extra-ub.rs:32:5
- |
-LL | INNER;
- | ^^^^^
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0080`.
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
-LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to copy parts of a pointer from memory at ALLOC
+ = note: unable to copy parts of a pointer from memory at ALLOC
|
= help: this code performed an operation that depends on the underlying bytes representing a pointer
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
note: inside `std::ptr::read::<u8>`
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
-LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `ptr::const_ptr::<impl *const u8>::read`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { read(self) }
- | ^^^^^^^^^^
note: inside `C`
--> $DIR/issue-miri-1910.rs:8:5
|
error[E0080]: evaluation of `<std::string::String as Bar<std::vec::Vec<u32>, std::string::String>>::F` failed
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
-LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling non-const function `<Vec<u32> as Drop>::drop`
+ = note: calling non-const function `<Vec<u32> as Drop>::drop`
|
note: inside `std::ptr::drop_in_place::<Vec<u32>> - shim(Some(Vec<u32>))`
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
-LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `std::ptr::drop_in_place::<(Vec<u32>, u32)> - shim(Some((Vec<u32>, u32)))`
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
-LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `<String as Bar<Vec<u32>, String>>::F`
--> $DIR/assoc_const.rs:12:31
|
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
-LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling non-const function `<Vec<i32> as Drop>::drop`
+ = note: calling non-const function `<Vec<i32> as Drop>::drop`
|
note: inside `std::ptr::drop_in_place::<Vec<i32>> - shim(Some(Vec<i32>))`
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
-LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `TEST_BAD`
--> $DIR/drop.rs:17:1
|
-// compile-flags: -Z simulate-remapped-rust-src-base=/rustc/FAKE_PREFIX -Z translate-remapped-path-to-local-path=no -Z ui-testing=no
+// compile-flags: -Z ui-testing=no
// normalize-stderr-test "alloc[0-9]+" -> "ALLOC_ID"
#![feature(const_swap)]
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::ptr_offset_from(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on pointers into different allocations
+ = note: `ptr_offset_from` called on pointers into different allocations
|
note: inside `ptr::const_ptr::<impl *const u8>::offset_from`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::ptr_offset_from(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `NOT_PTR`
--> $DIR/offset_from_ub.rs:24:14
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::ptr_offset_from(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
+ = note: out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
|
note: inside `ptr::const_ptr::<impl *const u8>::offset_from`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::ptr_offset_from(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `OFFSET_VERY_FAR1`
--> $DIR/offset_from_ub.rs:115:14
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::ptr_offset_from(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
+ = note: out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
|
note: inside `ptr::const_ptr::<impl *const u8>::offset_from`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::ptr_offset_from(self, origin) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `OFFSET_VERY_FAR2`
--> $DIR/offset_from_ub.rs:121:14
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic
+ = note: overflowing in-bounds pointer arithmetic
|
note: inside `ptr::const_ptr::<impl *const u8>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `BEFORE_START`
--> $DIR/offset_ub.rs:7:46
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset 0 is out-of-bounds
+ = note: out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset 0 is out-of-bounds
|
note: inside `ptr::const_ptr::<impl *const u8>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `AFTER_END`
--> $DIR/offset_ub.rs:8:43
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: allocN has size 100, so pointer to 101 bytes starting at offset 0 is out-of-bounds
+ = note: out-of-bounds pointer arithmetic: allocN has size 100, so pointer to 101 bytes starting at offset 0 is out-of-bounds
|
note: inside `ptr::const_ptr::<impl *const u8>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `AFTER_ARRAY`
--> $DIR/offset_ub.rs:9:45
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic
+ = note: overflowing in-bounds pointer arithmetic
|
note: inside `ptr::const_ptr::<impl *const u16>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `OVERFLOW`
--> $DIR/offset_ub.rs:11:43
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic
+ = note: overflowing in-bounds pointer arithmetic
|
note: inside `ptr::const_ptr::<impl *const u16>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `UNDERFLOW`
--> $DIR/offset_ub.rs:12:44
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic
+ = note: overflowing in-bounds pointer arithmetic
|
note: inside `ptr::const_ptr::<impl *const u8>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `OVERFLOW_ADDRESS_SPACE`
--> $DIR/offset_ub.rs:13:56
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic
+ = note: overflowing in-bounds pointer arithmetic
|
note: inside `ptr::const_ptr::<impl *const u8>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `UNDERFLOW_ADDRESS_SPACE`
--> $DIR/offset_ub.rs:14:57
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset -4 is out-of-bounds
+ = note: out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset -4 is out-of-bounds
|
note: inside `ptr::const_ptr::<impl *const u8>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `NEGATIVE_OFFSET`
--> $DIR/offset_ub.rs:15:49
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: allocN has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds
+ = note: out-of-bounds pointer arithmetic: allocN has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds
|
note: inside `ptr::const_ptr::<impl *const u8>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `ZERO_SIZED_ALLOC`
--> $DIR/offset_ub.rs:17:50
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) as *mut T }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance)
+ = note: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance)
|
note: inside `ptr::mut_ptr::<impl *mut u8>::offset`
--> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) as *mut T }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `DANGLING`
--> $DIR/offset_ub.rs:18:42
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance)
+ = note: out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance)
|
note: inside `ptr::const_ptr::<impl *const u8>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `NULL_OFFSET_ZERO`
--> $DIR/offset_ub.rs:21:50
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x7f..f[noalloc] is a dangling pointer (it has no provenance)
+ = note: out-of-bounds pointer arithmetic: 0x7f..f[noalloc] is a dangling pointer (it has no provenance)
|
note: inside `ptr::const_ptr::<impl *const u8>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `UNDERFLOW_ABS`
--> $DIR/offset_ub.rs:24:47
|
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds
+ = note: out-of-bounds pointer arithmetic: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds
|
note: inside `ptr::const_ptr::<impl *const usize>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- |
-LL | unsafe { intrinsics::offset(self, count) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `_`
--> $DIR/ptr_comparisons.rs:50:34
|
|
note: required by a bound in `AssertParamIsEq`
--> $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
- | ^^ required by this bound in `AssertParamIsEq`
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Eq)]`
|
|
note: required by a bound in `AssertParamIsEq`
--> $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
- | ^^ required by this bound in `AssertParamIsEq`
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Eq)]`
|
|
note: required by a bound in `AssertParamIsEq`
--> $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
- | ^^ required by this bound in `AssertParamIsEq`
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Eq)]`
|
|
note: required by a bound in `AssertParamIsEq`
--> $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
- | ^^ required by this bound in `AssertParamIsEq`
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Error` with `#[derive(Eq)]`
|
|
LL | #[derive(Eqr)]
| ^^^ help: a derive macro with a similar name exists: `Eq`
+ --> $SRC_DIR/core/src/cmp.rs:LL:COL
|
- ::: $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub macro Eq($item:item) {
- | ------------ similarly named derive macro `Eq` defined here
+ = note: similarly named derive macro `Eq` defined here
error: cannot find derive macro `Eqr` in this scope
--> $DIR/deriving-meta-unknown-trait.rs:1:10
|
LL | #[derive(Eqr)]
| ^^^ help: a derive macro with a similar name exists: `Eq`
+ --> $SRC_DIR/core/src/cmp.rs:LL:COL
|
- ::: $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub macro Eq($item:item) {
- | ------------ similarly named derive macro `Eq` defined here
+ = note: similarly named derive macro `Eq` defined here
error: aborting due to 2 previous errors
= note: required for `Option<f64>` to implement `Eq`
note: required by a bound in `AssertParamIsEq`
--> $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
- | ^^ required by this bound in `AssertParamIsEq`
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | struct S { x: u8, y: u8 }
| ^^^^^^^^ must implement `AddAssign<_>`
-note: the following trait must be implemented
+note: the trait `AddAssign` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | pub trait AddAssign<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0067]: invalid left-hand side of assignment
--> $DIR/note-unsupported.rs:17:22
--- /dev/null
+// run-rustfix
+struct X {
+ x: String,
+}
+
+impl Drop for X {
+ fn drop(&mut self) {
+ println!("value: {}", self.x);
+ }
+}
+
+fn unwrap(x: X) -> String {
+ let X { x: ref y } = x; //~ ERROR cannot move out of type
+ y.to_string()
+}
+
+fn main() {
+ let x = X { x: "hello".to_string() };
+ let y = unwrap(x);
+ println!("contents: {}", y);
+}
+// run-rustfix
struct X {
x: String,
}
fn unwrap(x: X) -> String {
let X { x: y } = x; //~ ERROR cannot move out of type
- y
+ y.to_string()
}
fn main() {
error[E0509]: cannot move out of type `X`, which implements the `Drop` trait
- --> $DIR/disallowed-deconstructing-destructing-struct-let.rs:12:22
+ --> $DIR/disallowed-deconstructing-destructing-struct-let.rs:13:22
|
LL | let X { x: y } = x;
| - ^ cannot move out of here
| |
| data moved here
| move occurs because `y` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | let X { x: ref y } = x;
+ | +++
error: aborting due to previous error
--- /dev/null
+// run-rustfix
+struct X {
+ x: String,
+}
+
+impl Drop for X {
+ fn drop(&mut self) {
+ println!("value: {}", self.x);
+ }
+}
+
+fn main() {
+ let x = X { x: "hello".to_string() };
+
+ match x {
+ //~^ ERROR cannot move out of type `X`, which implements the `Drop` trait
+ X { x: ref y } => println!("contents: {}", y)
+ }
+}
+// run-rustfix
struct X {
x: String,
}
error[E0509]: cannot move out of type `X`, which implements the `Drop` trait
- --> $DIR/disallowed-deconstructing-destructing-struct-match.rs:14:11
+ --> $DIR/disallowed-deconstructing-destructing-struct-match.rs:15:11
|
LL | match x {
| ^ cannot move out of here
| |
| data moved here
| move occurs because `y` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | X { x: ref y } => println!("contents: {}", y)
+ | +++
error: aborting due to previous error
= help: the trait `Sized` is not implemented for `str`
note: required by a bound in `Box::<T>::new`
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
- |
-LL | impl<T> Box<T> {
- | ^ required by this bound in `Box::<T>::new`
error[E0277]: the size for values of type `[isize]` cannot be known at compilation time
--> $DIR/dst-rvalue.rs:8:37
= help: the trait `Sized` is not implemented for `[isize]`
note: required by a bound in `Box::<T>::new`
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
- |
-LL | impl<T> Box<T> {
- | ^ required by this bound in `Box::<T>::new`
error: aborting due to 2 previous errors
LL | let xe1 = XEmpty2();
| ~~~~~~~
-error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope
+error[E0599]: no variant or associated item named `Empty3` found for enum `XE` in the current scope
--> $DIR/empty-struct-braces-expr.rs:25:19
|
LL | let xe3 = XE::Empty3;
| ^^^^^^
| |
- | variant or associated item not found in `empty_struct::XE`
+ | variant or associated item not found in `XE`
| help: there is a variant with a similar name: `XEmpty3`
-error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope
+error[E0599]: no variant or associated item named `Empty3` found for enum `XE` in the current scope
--> $DIR/empty-struct-braces-expr.rs:26:19
|
LL | let xe3 = XE::Empty3();
| ^^^^^^
| |
- | variant or associated item not found in `empty_struct::XE`
+ | variant or associated item not found in `XE`
| help: there is a variant with a similar name: `XEmpty3`
error[E0599]: no variant named `Empty1` found for enum `empty_struct::XE`
|
note: `Option<i32>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub enum Option<T> {
- | ------------------
-...
-LL | None,
- | ^^^^ not covered
-...
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^ not covered
+ = note: not covered
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
+ |
+ = note: not covered
= note: the matched value is of type `Option<i32>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
|
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Option<i32>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub enum Option<T> {
- | ------------------
-...
-LL | None,
- | ^^^^ not covered
+ = note: not covered
= note: the matched value is of type `Option<i32>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
|
note: required by a bound in `Fn`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
- | ^^^^^ required by this bound in `Fn`
error: aborting due to previous error
|
help: consider giving `x` an explicit type
|
-LL | let x: _ = "hello".chars().rev().collect();
- | +++
+LL | let x: Vec<_> = "hello".chars().rev().collect();
+ | ++++++++
error: aborting due to previous error
|
note: `Option<i32>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub enum Option<T> {
- | ------------------
-...
-LL | None,
- | ^^^^ not covered
+ = note: not covered
= note: the matched value is of type `Option<i32>`
error: aborting due to previous error
|
LL | fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
| ^^^^ required by this bound in `bfnr`
-help: consider specifying the type arguments in the function call
+help: consider specifying the generic arguments
|
LL | bfnr::<U, V, W>(x);
| +++++++++++
| | value moved due to this method call
| move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait
|
-note: this function takes ownership of the receiver `self`, which moves value
+note: `TheDarkKnight::nothing_is_true` takes ownership of the receiver `self`, which moves value
--> $DIR/E0507.rs:6:24
|
LL | fn nothing_is_true(self) {}
| |
| cannot move out of here
| move occurs because `array[_]` has type `NonCopy`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&array[0]`
+ |
+help: consider borrowing here
+ |
+LL | let _value = &array[0];
+ | +
error: aborting due to previous error
| |
| cannot move out of here
| move occurs because `array[_]` has type `NonCopy`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&array[0]`
+ |
+help: consider borrowing here
+ |
+LL | let _value = &array[0];
+ | +
error: aborting due to previous error
| |
| cannot move out of here
| move occurs because `drop_struct.fancy` has type `FancyNum`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&drop_struct.fancy`
+ |
+help: consider borrowing here
+ |
+LL | let fancy_field = &drop_struct.fancy;
+ | +
error: aborting due to previous error
|
LL | enum Question {
| ^^^^^^^^^^^^^ must implement `Not`
-note: the following trait must be implemented
+note: the trait `Not` must be implemented
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
- |
-LL | pub trait Not {
- | ^^^^^^^^^^^^^
error[E0604]: only `u8` can be cast as `char`, not `u32`
--> $DIR/error-festival.rs:25:5
LL | |
LL | | |x| println!("doubling {}", x);
LL | | Some(x * 2)
- | | ----------- this tail expression is of type `std::option::Option<_>`
+ | | ----------- this tail expression is of type `Option<_>`
LL | |
LL | | });
| |_____^ expected an `FnOnce<({integer},)>` closure, found `Option<_>`
= help: the trait `FnOnce<({integer},)>` is not implemented for `Option<_>`
note: required by a bound in `Option::<T>::and_then`
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | F: ~const FnOnce(T) -> Option<U>,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::and_then`
error: aborting due to 2 previous errors
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Result<u32, !>` defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
+ ::: $SRC_DIR/core/src/result.rs:LL:COL
|
-LL | pub enum Result<T, E> {
- | ---------------------
-...
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | ^^^ not covered
+ = note: not covered
= note: the matched value is of type `Result<u32, !>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
found reference `&{float}`
note: associated function defined here
--> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- |
-LL | pub fn from_usize(x: &usize) -> ArgumentV1<'_> {
- | ^^^^^^^^^^
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0308]: mismatched types
found reference `&{float}`
note: associated function defined here
--> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- |
-LL | pub fn from_usize(x: &usize) -> ArgumentV1<'_> {
- | ^^^^^^^^^^
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 38 previous errors
= note: required for `&str` to implement `UpperHex`
note: required by a bound in `ArgumentV1::<'a>::new_upper_hex`
--> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
- |
-LL | arg_new!(new_upper_hex, UpperHex);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `ArgumentV1::<'a>::new_upper_hex`
= note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `arg_new` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
LL | trait Bar {
| ^^^^^^^^^
-error[E0599]: no method named `bar` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:22:36: 22:38]>` in the current scope
+error[E0599]: no method named `bar` found for struct `Arc<[closure@fn-help-with-err.rs:22:36]>` in the current scope
--> $DIR/fn-help-with-err.rs:23:10
|
LL | arc2.bar();
- | ^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:22:36: 22:38]>`
+ | ^^^ method not found in `Arc<[closure@fn-help-with-err.rs:22:36]>`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `Bar` defines an item `bar`, perhaps you need to implement it
|
note: associated function defined here
--> $SRC_DIR/core/src/ops/generator.rs:LL:COL
- |
-LL | fn resume(self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return>;
- | ^^^^^^
help: provide the argument
|
LL | Pin::new(&mut b).resume(());
= help: the trait `Sized` is not implemented for `str`
note: required by a bound in `GeneratorState`
--> $SRC_DIR/core/src/ops/generator.rs:LL:COL
- |
-LL | pub enum GeneratorState<Y, R> {
- | ^ required by this bound in `GeneratorState`
error: aborting due to 2 previous errors
error[E0277]: the trait bound `for<'a> &'a mut (): Foo<&'a mut ()>` is not satisfied
- --> $DIR/issue-101020.rs:31:5
+ --> $DIR/issue-101020.rs:31:22
|
LL | (&mut EmptyIter).consume(());
- | ^^^^^^^^^^^^^^^^ ------- required by a bound introduced by this call
- | |
- | the trait `for<'a> Foo<&'a mut ()>` is not implemented for `&'a mut ()`
+ | ^^^^^^^ the trait `for<'a> Foo<&'a mut ()>` is not implemented for `&'a mut ()`
|
note: required for `&'a mut ()` to implement `for<'a> FuncInput<'a, &'a mut ()>`
--> $DIR/issue-101020.rs:27:20
LL | type A = HashMap;
| ^^^^^^^ expected at least 2 generic arguments
|
-note: struct defined here, with at least 2 generic parameters: `K`, `V`
- --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
- |
-LL | pub struct HashMap<K, V, S = RandomState> {
- | ^^^^^^^ - -
help: add missing generic arguments
|
LL | type A = HashMap<K, V>;
| |
| expected at least 2 generic arguments
|
-note: struct defined here, with at least 2 generic parameters: `K`, `V`
- --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
- |
-LL | pub struct HashMap<K, V, S = RandomState> {
- | ^^^^^^^ - -
help: add missing generic argument
|
LL | type B = HashMap<String, V>;
| ^^^^^^^--------- help: remove these generics
| |
| expected 0 lifetime arguments
- |
-note: struct defined here, with 0 lifetime parameters
- --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
- |
-LL | pub struct HashMap<K, V, S = RandomState> {
- | ^^^^^^^
error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
--> $DIR/wrong-number-of-args.rs:318:18
LL | type C = HashMap<'static>;
| ^^^^^^^ expected at least 2 generic arguments
|
-note: struct defined here, with at least 2 generic parameters: `K`, `V`
- --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
- |
-LL | pub struct HashMap<K, V, S = RandomState> {
- | ^^^^^^^ - -
help: add missing generic arguments
|
LL | type C = HashMap<'static, K, V>;
| ^^^^^^^ --- help: remove this generic argument
| |
| expected at most 3 generic arguments
- |
-note: struct defined here, with at most 3 generic parameters: `K`, `V`, `S`
- --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
- |
-LL | pub struct HashMap<K, V, S = RandomState> {
- | ^^^^^^^ - - ---------------
error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
--> $DIR/wrong-number-of-args.rs:328:18
LL | type E = HashMap<>;
| ^^^^^^^ expected at least 2 generic arguments
|
-note: struct defined here, with at least 2 generic parameters: `K`, `V`
- --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
- |
-LL | pub struct HashMap<K, V, S = RandomState> {
- | ^^^^^^^ - -
help: add missing generic arguments
|
LL | type E = HashMap<K, V>;
LL | type A = Result;
| ^^^^^^ expected 2 generic arguments
|
-note: enum defined here, with 2 generic parameters: `T`, `E`
- --> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | pub enum Result<T, E> {
- | ^^^^^^ - -
help: add missing generic arguments
|
LL | type A = Result<T, E>;
| |
| expected 2 generic arguments
|
-note: enum defined here, with 2 generic parameters: `T`, `E`
- --> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | pub enum Result<T, E> {
- | ^^^^^^ - -
help: add missing generic argument
|
LL | type B = Result<String, E>;
| ^^^^^^--------- help: remove these generics
| |
| expected 0 lifetime arguments
- |
-note: enum defined here, with 0 lifetime parameters
- --> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | pub enum Result<T, E> {
- | ^^^^^^
error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
--> $DIR/wrong-number-of-args.rs:342:18
LL | type C = Result<'static>;
| ^^^^^^ expected 2 generic arguments
|
-note: enum defined here, with 2 generic parameters: `T`, `E`
- --> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | pub enum Result<T, E> {
- | ^^^^^^ - -
help: add missing generic arguments
|
LL | type C = Result<'static, T, E>;
| ^^^^^^ ---- help: remove this generic argument
| |
| expected 2 generic arguments
- |
-note: enum defined here, with 2 generic parameters: `T`, `E`
- --> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | pub enum Result<T, E> {
- | ^^^^^^ - -
error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
--> $DIR/wrong-number-of-args.rs:352:18
LL | type E = Result<>;
| ^^^^^^ expected 2 generic arguments
|
-note: enum defined here, with 2 generic parameters: `T`, `E`
- --> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | pub enum Result<T, E> {
- | ^^^^^^ - -
help: add missing generic arguments
|
LL | type E = Result<T, E>;
--- /dev/null
+// normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
+
+fn id(
+ f: &dyn Fn(u32),
+) -> &dyn Fn(
+ &dyn Fn(
+ &dyn Fn(
+ &dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(u32))))))))),
+ ),
+ ),
+) {
+ f
+ //~^ ERROR mismatched types
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/hang-on-deeply-nested-dyn.rs:12:5
+ |
+LL | ) -> &dyn Fn(
+ | ______-
+LL | | &dyn Fn(
+LL | | &dyn Fn(
+LL | | &dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(u32))))))))),
+LL | | ),
+LL | | ),
+LL | | ) {
+ | |_- expected `&dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn Fn(u32) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a))` because of return type
+LL | f
+ | ^ expected reference, found `u32`
+ |
+ = note: expected reference `&dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a ...) + 'a)) + 'a)) + 'a))`
+ the full type name has been written to '$TEST_BUILD_DIR/higher-rank-trait-bounds/hang-on-deeply-nested-dyn/hang-on-deeply-nested-dyn.long-type-hash.txt'
+ found reference `&dyn Fn(u32)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
-error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>`, but its trait bounds were not satisfied
+error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@issue-30786.rs:117:27]>`, but its trait bounds were not satisfied
--> $DIR/issue-30786.rs:118:22
|
LL | pub struct Map<S, F> {
| doesn't satisfy `_: StreamExt`
...
LL | let filter = map.filterx(|x: &_| true);
- | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>` due to unsatisfied trait bounds
+ | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@issue-30786.rs:117:27]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>: Stream`
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| --------- - ^^^^^^ unsatisfied trait bound introduced here
-error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>`, but its trait bounds were not satisfied
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@issue-30786.rs:129:30]>`, but its trait bounds were not satisfied
--> $DIR/issue-30786.rs:130:24
|
LL | pub struct Filter<S, F> {
| doesn't satisfy `_: StreamExt`
...
LL | let count = filter.countx();
- | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>` due to unsatisfied trait bounds
+ | ^^^^^^ method cannot be called due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`&'a mut &Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
LL | F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m`
-error[E0271]: expected `[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]` to be a closure that returns `Unit3`, but it returns `Unit4`
+error[E0271]: expected `[closure@issue-62203-hrtb-ice.rs:42:16]` to be a closure that returns `Unit3`, but it returns `Unit4`
--> $DIR/issue-62203-hrtb-ice.rs:39:9
|
LL | let v = Unit2.m(
--- /dev/null
+struct MutType;
+
+pub trait MutTrait {
+ fn function(&mut self)
+ where
+ Self: Sized;
+ //~^ this has a `Sized` requirement
+}
+
+impl MutTrait for MutType {
+ fn function(&mut self) {}
+}
+
+struct Type;
+
+pub trait Trait {
+ fn function(&self)
+ where
+ Self: Sized;
+ //~^ this has a `Sized` requirement
+}
+
+impl Trait for Type {
+ fn function(&self) {}
+}
+
+fn main() {
+ (&MutType as &dyn MutTrait).function();
+ //~^ ERROR the `function` method cannot be invoked on a trait object
+ //~| NOTE you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
+ (&mut Type as &mut dyn Trait).function();
+ //~^ ERROR the `function` method cannot be invoked on a trait object
+ //~| NOTE you need `&dyn Trait` instead of `&mut dyn Trait`
+}
--- /dev/null
+error: the `function` method cannot be invoked on a trait object
+ --> $DIR/mutability-mismatch.rs:28:33
+ |
+LL | Self: Sized;
+ | ----- this has a `Sized` requirement
+...
+LL | (&MutType as &dyn MutTrait).function();
+ | ^^^^^^^^
+ |
+ = note: you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
+
+error: the `function` method cannot be invoked on a trait object
+ --> $DIR/mutability-mismatch.rs:31:35
+ |
+LL | Self: Sized;
+ | ----- this has a `Sized` requirement
+...
+LL | (&mut Type as &mut dyn Trait).function();
+ | ^^^^^^^^
+ |
+ = note: you need `&dyn Trait` instead of `&mut dyn Trait`
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+struct MutType;
+
+pub trait MutTrait {
+ fn function(&mut self)
+ where
+ Self: Sized;
+ //~^ this has a `Sized` requirement
+}
+
+impl MutTrait for MutType {
+ fn function(&mut self) {}
+}
+
+struct Type;
+
+pub trait Trait {
+ fn function(&self)
+ where
+ Self: Sized;
+ //~^ this has a `Sized` requirement
+}
+
+impl Trait for Type {
+ fn function(&self) {}
+}
+
+fn main() {
+ (&mut MutType as &mut dyn MutTrait).function();
+ //~^ ERROR the `function` method cannot be invoked on a trait object
+ (&Type as &dyn Trait).function();
+ //~^ ERROR the `function` method cannot be invoked on a trait object
+}
--- /dev/null
+error: the `function` method cannot be invoked on a trait object
+ --> $DIR/regular.rs:28:41
+ |
+LL | Self: Sized;
+ | ----- this has a `Sized` requirement
+...
+LL | (&mut MutType as &mut dyn MutTrait).function();
+ | ^^^^^^^^
+
+error: the `function` method cannot be invoked on a trait object
+ --> $DIR/regular.rs:30:27
+ |
+LL | Self: Sized;
+ | ----- this has a `Sized` requirement
+...
+LL | (&Type as &dyn Trait).function();
+ | ^^^^^^^^
+
+error: aborting due to 2 previous errors
+
|
LL | fn hash(&self, hasher: &mut impl Hasher) {}
| ^^^^^^^^^^^ expected generic parameter, found `impl Trait`
+ --> $SRC_DIR/core/src/hash/mod.rs:LL:COL
|
- ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL
- |
-LL | fn hash<H: Hasher>(&self, state: &mut H);
- | - declaration in trait here
+ = note: declaration in trait here
error: aborting due to 4 previous errors
= help: the trait `Sized` is not implemented for `[u8]`
note: required by a bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- |
-LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
- | ^ required by this bound in `Vec`
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/wf-bounds.rs:12:23
|
= note: the following trait bounds were not satisfied:
`RawImpl<()>: Raw<()>`
-note: the following trait must be implemented
+note: the trait `Raw` must be implemented
--> $DIR/issue-62742.rs:12:1
|
LL | pub trait Raw<T: ?Sized> {
|
help: consider giving this closure parameter an explicit type
|
-LL | |_: _| true
- | +++
+LL | |_: /* Type */| true
+ | ++++++++++++
error: aborting due to 3 previous errors
LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec> {
| ^^^ expected at least 1 generic argument
|
-note: struct defined here, with at least 1 generic parameter: `T`
- --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- |
-LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
- | ^^^ -
help: add missing generic argument
|
LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec<T>> {
LL | pub trait Bar {
| ^^^^^^^^^^^^^
-error[E0599]: no method named `method2` found for struct `no_method_suggested_traits::Foo` in the current scope
+error[E0599]: no method named `method2` found for struct `Foo` in the current scope
--> $DIR/no-method-suggested-traits.rs:50:37
|
LL | no_method_suggested_traits::Foo.method2();
- | ^^^^^^^ method not found in `no_method_suggested_traits::Foo`
+ | ^^^^^^^ method not found in `Foo`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
LL | pub trait Bar {
| ^^^^^^^^^^^^^
-error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope
+error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&Foo>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:52:71
|
LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2();
- | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Foo>>`
+ | ^^^^^^^ method not found in `Rc<&mut Box<&Foo>>`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
LL | pub trait Bar {
| ^^^^^^^^^^^^^
-error[E0599]: no method named `method2` found for enum `no_method_suggested_traits::Bar` in the current scope
+error[E0599]: no method named `method2` found for enum `Bar` in the current scope
--> $DIR/no-method-suggested-traits.rs:54:40
|
LL | no_method_suggested_traits::Bar::X.method2();
- | ^^^^^^^ method not found in `no_method_suggested_traits::Bar`
+ | ^^^^^^^ method not found in `Bar`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
LL | pub trait Bar {
| ^^^^^^^^^^^^^
-error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope
+error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&Bar>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:56:74
|
LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2();
- | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Bar>>`
+ | ^^^^^^^ method not found in `Rc<&mut Box<&Bar>>`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
LL | std::rc::Rc::new(&mut Box::new(&1_usize)).method3();
| ^^^^^^^ method not found in `Rc<&mut Box<&usize>>`
-error[E0599]: no method named `method3` found for struct `no_method_suggested_traits::Foo` in the current scope
+error[E0599]: no method named `method3` found for struct `Foo` in the current scope
--> $DIR/no-method-suggested-traits.rs:71:37
|
LL | no_method_suggested_traits::Foo.method3();
- | ^^^^^^^ method not found in `no_method_suggested_traits::Foo`
+ | ^^^^^^^ method not found in `Foo`
-error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope
+error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Foo>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:72:71
|
LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3();
- | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Foo>>`
+ | ^^^^^^^ method not found in `Rc<&mut Box<&Foo>>`
-error[E0599]: no method named `method3` found for enum `no_method_suggested_traits::Bar` in the current scope
+error[E0599]: no method named `method3` found for enum `Bar` in the current scope
--> $DIR/no-method-suggested-traits.rs:74:40
|
LL | no_method_suggested_traits::Bar::X.method3();
- | ^^^^^^^ method not found in `no_method_suggested_traits::Bar`
+ | ^^^^^^^ method not found in `Bar`
-error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope
+error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Bar>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:75:74
|
LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3();
- | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Bar>>`
+ | ^^^^^^^ method not found in `Rc<&mut Box<&Bar>>`
error: aborting due to 24 previous errors
...
LL | define_vec!();
| ------------- in this macro invocation
-note: `Vec` could also refer to the struct defined here
+note: `Vec` could also refer to a struct from prelude
--> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
- |
-LL | pub use super::v1::*;
- | ^^^^^^^^^^^^
= note: this error originates in the macro `define_vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
|
LL | fn foo<T, K, W: Default, Z: Default>(t: T, k: K) -> Foo<T, K, W, Z> {
| ^^^^^^^ required by this bound in `foo`
-help: consider specifying the type arguments in the function call
+help: consider giving `foo` an explicit type, where the type for type parameter `W` is specified
|
-LL | let foo = foo::<T, K, W, Z>(1, "");
- | ++++++++++++++
+LL | let foo: Foo<i32, &str, W, Z> = foo(1, "");
+ | ++++++++++++++++++++++
error[E0283]: type annotations needed for `Bar<i32, &str, Z>`
--> $DIR/erase-type-params-in-label.rs:5:9
|
LL | fn bar<T, K, Z: Default>(t: T, k: K) -> Bar<T, K, Z> {
| ^^^^^^^ required by this bound in `bar`
-help: consider specifying the type arguments in the function call
+help: consider giving `bar` an explicit type, where the type for type parameter `Z` is specified
|
-LL | let bar = bar::<T, K, Z>(1, "");
- | +++++++++++
+LL | let bar: Bar<i32, &str, Z> = bar(1, "");
+ | +++++++++++++++++++
error: aborting due to 2 previous errors
where T: ?Sized;
note: required by a bound in `HashMap::<K, V, S>::get`
--> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
- |
-LL | K: Borrow<Q>,
- | ^^^^^^^^^ required by this bound in `HashMap::<K, V, S>::get`
help: consider specifying the generic argument
|
LL | .get::<Q>(&"key".into())
|
help: consider giving this closure parameter an explicit type
|
-LL | |x: _| String::from("x".as_ref());
- | +++
+LL | |x: /* Type */| String::from("x".as_ref());
+ | ++++++++++++
error[E0283]: type annotations needed
--> $DIR/issue-72690.rs:12:26
--- /dev/null
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/expr-unsafe-err.rs:8:9
+ |
+LL | require_unsafe();
+ | ^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+#![feature(inline_const)]
+const unsafe fn require_unsafe() -> usize { 1 }
+
+fn main() {
+ const {
+ require_unsafe();
+ //~^ ERROR [E0133]
+ }
+}
--- /dev/null
+error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
+ --> $DIR/expr-unsafe-err.rs:8:9
+ |
+LL | require_unsafe();
+ | ^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+warning: unnecessary `unsafe` block
+ --> $DIR/expr-unsafe.rs:12:13
+ |
+LL | unsafe {}
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+note: the lint level is defined here
+ --> $DIR/expr-unsafe.rs:4:9
+ |
+LL | #![warn(unused_unsafe)]
+ | ^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
--- /dev/null
+// check-pass
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+#![warn(unused_unsafe)]
+#![feature(inline_const)]
+const unsafe fn require_unsafe() -> usize { 1 }
+
+fn main() {
+ unsafe {
+ const {
+ require_unsafe();
+ unsafe {}
+ //~^ WARNING unnecessary `unsafe` block
+ }
+ }
+}
--- /dev/null
+warning: unnecessary `unsafe` block
+ --> $DIR/expr-unsafe.rs:12:13
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+...
+LL | unsafe {}
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+note: the lint level is defined here
+ --> $DIR/expr-unsafe.rs:4:9
+ |
+LL | #![warn(unused_unsafe)]
+ | ^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
--- /dev/null
+// ignore-test This is currently broken
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+#![allow(incomplete_features)]
+#![feature(inline_const_pat)]
+
+const unsafe fn require_unsafe() -> usize { 1 }
+
+fn main() {
+ match () {
+ const {
+ require_unsafe();
+ //~^ ERROR [E0133]
+ } => (),
+ }
+}
--- /dev/null
+// ignore-test This is currently broken
+// check-pass
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+#![allow(incomplete_features)]
+#![warn(unused_unsafe)]
+#![feature(inline_const_pat)]
+
+const unsafe fn require_unsafe() -> usize { 1 }
+
+fn main() {
+ unsafe {
+ match () {
+ const {
+ require_unsafe();
+ unsafe {}
+ //~^ WARNING unnecessary `unsafe` block
+ } => (),
+ }
+ }
+}
| ^^
note: required by a bound in `catch_unwind`
--> $SRC_DIR/std/src/panic.rs:LL:COL
- |
-LL | pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
- | ^^^^^^^^^^ required by this bound in `catch_unwind`
error: aborting due to previous error
= note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
note: required by a bound in `const_eval_select`
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
- |
-LL | F: FnOnce<ARG, Output = RET>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
error: this argument must be a function item
--> $DIR/const-eval-select-bad.rs:10:31
= note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
note: required by a bound in `const_eval_select`
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
- |
-LL | G: FnOnce<ARG, Output = RET>,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
error[E0271]: expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it returns `bool`
--> $DIR/const-eval-select-bad.rs:32:34
|
note: required by a bound in `const_eval_select`
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
- |
-LL | G: FnOnce<ARG, Output = RET>,
- | ^^^^^^^^^^^^ required by this bound in `const_eval_select`
error[E0631]: type mismatch in function arguments
--> $DIR/const-eval-select-bad.rs:37:32
found function signature `fn(i32) -> _`
note: required by a bound in `const_eval_select`
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
- |
-LL | F: FnOnce<ARG, Output = RET>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
error: this argument must be a `const fn`
--> $DIR/const-eval-select-bad.rs:42:29
--> $DIR/issue-105330.rs:12:11
|
LL | foo::<Demo>()();
- | ^^^^ types differ
+ | ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
|
+ = note: expected constant `32`
+ found constant `<Demo as TraitWAssocConst>::A`
note: required by a bound in `foo`
--> $DIR/issue-105330.rs:11:28
|
--> $DIR/issue-105330.rs:19:11
|
LL | foo::<Demo>();
- | ^^^^ types differ
+ | ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
|
+ = note: expected constant `32`
+ found constant `<Demo as TraitWAssocConst>::A`
note: required by a bound in `foo`
--> $DIR/issue-105330.rs:11:28
|
| --- ...and here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider borrowing the pattern binding
+ |
+LL | (&[], &[ref hd, ..]) | (&[hd, ..], &[])
+ | +++
+help: consider borrowing the pattern binding
+ |
+LL | (&[ref hd1, ..], &[hd2, ..])
+ | +++
error[E0508]: cannot move out of type `[T]`, a non-copy slice
--> $DIR/issue-12567.rs:2:11
| --- ...and here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider borrowing the pattern binding
+ |
+LL | (&[], &[ref hd, ..]) | (&[hd, ..], &[])
+ | +++
+help: consider borrowing the pattern binding
+ |
+LL | (&[hd1, ..], &[ref hd2, ..])
+ | +++
error: aborting due to 2 previous errors
|
LL | pub struct BytePos(pub u32);
| ^^^^^^^^^^^^^^^^^^ must implement `Not`
-note: the following trait must be implemented
+note: the trait `Not` must be implemented
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
- |
-LL | pub trait Not {
- | ^^^^^^^^^^^^^
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
LL | fn fn1(0: Box) {}
| ^^^ expected at least 1 generic argument
|
-note: struct defined here, with at least 1 generic parameter: `T`
- --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
- |
-LL | pub struct Box<
- | ^^^
-LL | T: ?Sized,
- | -
help: add missing generic argument
|
LL | fn fn1(0: Box<T>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `M` declared on the function `begin_panic`
|
= note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider specifying the generic argument
- --> $SRC_DIR/std/src/panic.rs:LL:COL
- |
-LL | $crate::rt::begin_panic::<M>($msg)
- | +++++
error: aborting due to previous error
|
LL | fn new() -> NoResult<MyEnum, String> {
| ^^^^^^^^^^^^^^^^^^^^^^^^
+ --> $SRC_DIR/core/src/result.rs:LL:COL
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | pub enum Result<T, E> {
- | --------------------- similarly named enum `Result` defined here
+ = note: similarly named enum `Result` defined here
|
help: try using the variant's enum
|
|
LL | fn newer() -> NoResult<foo::MyEnum, String> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ --> $SRC_DIR/core/src/result.rs:LL:COL
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | pub enum Result<T, E> {
- | --------------------- similarly named enum `Result` defined here
+ = note: similarly named enum `Result` defined here
|
help: try using the variant's enum
|
= help: the trait `Sized` is not implemented for `[{integer}]`
note: required by a bound in `Box::<T>::new`
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
- |
-LL | impl<T> Box<T> {
- | ^ required by this bound in `Box::<T>::new`
error: aborting due to previous error
|
help: consider giving `x` an explicit type
|
-LL | let x: _;
- | +++
+LL | let x: /* Type */;
+ | ++++++++++++
error: aborting due to previous error
| ^^^ -- help: remove this lifetime argument
| |
| expected 0 lifetime arguments
- |
-note: struct defined here, with 0 lifetime parameters
- --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
- |
-LL | pub struct Box<
- | ^^^
error: aborting due to previous error
error[E0277]: the trait bound `X: Ord` is not satisfied
- --> $DIR/issue-20162.rs:5:5
+ --> $DIR/issue-20162.rs:5:7
|
LL | b.sort();
- | ^ ---- required by a bound introduced by this call
- | |
- | the trait `Ord` is not implemented for `X`
+ | ^^^^ the trait `Ord` is not implemented for `X`
|
note: required by a bound in `slice::<impl [T]>::sort`
--> $SRC_DIR/alloc/src/slice.rs:LL:COL
- |
-LL | T: Ord,
- | ^^^ required by this bound in `slice::<impl [T]>::sort`
help: consider annotating `X` with `#[derive(Ord)]`
|
LL | #[derive(Ord)]
= help: the trait `Sized` is not implemented for `[i32]`
note: required by a bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- |
-LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
- | ^ required by this bound in `Vec`
error: aborting due to previous error
|
help: consider giving `x` an explicit type
|
-LL | let x: _ = panic!();
- | +++
+LL | let x: /* Type */ = panic!();
+ | ++++++++++++
error: aborting due to previous error
LL | where &'a T : Foo,
| ^^^
|
- = note: cannot satisfy `&'a T: Foo`
+note: multiple `impl`s or `where` clauses satisfying `&'a T: Foo` found
+ --> $DIR/issue-21974.rs:11:19
+ |
+LL | where &'a T : Foo,
+ | ^^^
+LL | &'b T : Foo
+ | ^^^
error: aborting due to previous error
LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3));
| ^^ expected 1 generic argument
|
-note: trait defined here, with 1 generic parameter: `Args`
- --> $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
- | ^^ ----
help: add missing generic argument
|
LL | println!("{:?}",(vfnfer[0] as dyn Fn<Args>)(3));
= help: the trait `FnMut<(_, char)>` is not implemented for `()`
note: required by a bound in `fold`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | F: FnMut(B, Self::Item) -> B,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::fold`
error: aborting due to previous error
|
help: consider giving this closure parameter an explicit type
|
-LL | 1 => |c: _| c + 1,
- | +++
+LL | 1 => |c: /* Type */| c + 1,
+ | ++++++++++++
error: aborting due to 2 previous errors
LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
| ^^^^^^^^^^^
|
- = note: cannot satisfy `T0: Trait0<'l0>`
+note: multiple `impl`s or `where` clauses satisfying `T0: Trait0<'l0>` found
+ --> $DIR/issue-24424.rs:4:57
+ |
+LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
+ | ^^^^^^^^^^^ ^^^^^^^^^^^
error: aborting due to previous error
|
LL | None @ _ => {}
| ^^^^ cannot be named the same as a unit variant
+ --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
|
- ::: $SRC_DIR/std/src/prelude/mod.rs:LL:COL
- |
-LL | pub use super::v1::*;
- | ------------ the unit variant `None` is defined here
+ = note: the unit variant `None` is defined here
error[E0530]: match bindings cannot shadow constants
--> $DIR/issue-27033.rs:7:9
-error[E0599]: no function or associated item named `new_undirected` found for struct `issue_30123_aux::Graph<i32, i32>` in the current scope
+error[E0599]: no function or associated item named `new_undirected` found for struct `Graph<i32, i32>` in the current scope
--> $DIR/issue-30123.rs:7:33
|
LL | let ug = Graph::<i32, i32>::new_undirected();
- | ^^^^^^^^^^^^^^ function or associated item not found in `issue_30123_aux::Graph<i32, i32>`
+ | ^^^^^^^^^^^^^^ function or associated item not found in `Graph<i32, i32>`
|
= note: the function or associated item was found for
- `issue_30123_aux::Graph<N, E, Undirected>`
|
note: associated function defined here
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | fn fold<B, F>(mut self, init: B, mut f: F) -> B
- | ^^^^
help: provide the argument
|
LL ~ needlesArr.iter().fold(|x, y| {
let mut found_e = false;
let temp: Vec<u8> = it
- //~^ ERROR to be an iterator that yields `&_`, but it yields `u8`
.take_while(|&x| {
found_e = true;
false
})
- .cloned()
+ .cloned() //~ ERROR to be an iterator that yields `&_`, but it yields `u8`
.collect(); //~ ERROR the method
}
-error[E0271]: expected `TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:8:21: 8:25]>` to be an iterator that yields `&_`, but it yields `u8`
- --> $DIR/issue-31173.rs:6:25
+error[E0271]: expected `TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>` to be an iterator that yields `&_`, but it yields `u8`
+ --> $DIR/issue-31173.rs:11:10
|
-LL | let temp: Vec<u8> = it
- | _________________________^
-LL | |
-LL | | .take_while(|&x| {
-LL | | found_e = true;
-LL | | false
-LL | | })
- | |__________^ expected reference, found `u8`
-LL | .cloned()
- | ------ required by a bound introduced by this call
+LL | .cloned()
+ | ^^^^^^ expected reference, found `u8`
|
= note: expected reference `&_`
found type `u8`
+note: the method call chain might not have had the expected associated types
+ --> $DIR/issue-31173.rs:3:20
+ |
+LL | pub fn get_tok(it: &mut IntoIter<u8>) {
+ | ^^^^^^^^^^^^^^^^^ `Iterator::Item` is `u8` here
+...
+LL | .take_while(|&x| {
+ | __________-
+LL | | found_e = true;
+LL | | false
+LL | | })
+ | |__________- `Iterator::Item` remains `u8` here
note: required by a bound in `cloned`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | Self: Sized + Iterator<Item = &'a T>,
- | ^^^^^^^^^^^^ required by this bound in `Iterator::cloned`
-error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:8:21: 8:25]>>`, but its trait bounds were not satisfied
- --> $DIR/issue-31173.rs:13:10
+error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>>`, but its trait bounds were not satisfied
+ --> $DIR/issue-31173.rs:12:10
|
LL | .collect();
- | ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:8:21: 8:25]>>` due to unsatisfied trait bounds
- |
- ::: $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL
- |
-LL | pub struct TakeWhile<I, P> {
- | -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_`
+ | ^^^^^^^ method cannot be called due to unsatisfied trait bounds
+ --> $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL
|
- ::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
+ = note: doesn't satisfy `<_ as Iterator>::Item = &_`
+ --> $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
|
-LL | pub struct Cloned<I> {
- | -------------------- doesn't satisfy `_: Iterator`
+ = note: doesn't satisfy `_: Iterator`
|
= note: the following trait bounds were not satisfied:
- `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:8:21: 8:25]> as Iterator>::Item = &_`
- which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:8:21: 8:25]>>: Iterator`
- `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:8:21: 8:25]>>: Iterator`
- which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:8:21: 8:25]>>: Iterator`
+ `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]> as Iterator>::Item = &_`
+ which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
+ `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
+ which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
error: aborting due to 2 previous errors
...
LL | foo!();
| ------ in this macro invocation
+ --> $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
- ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- |
-LL | pub macro derive_const($item:item) {
- | ---------------------- similarly named attribute macro `derive_const` defined here
+ = note: similarly named attribute macro `derive_const` defined here
|
= note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
LL | #[derive_Clone]
| ^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `derive_const`
+ --> $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
- ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- |
-LL | pub macro derive_const($item:item) {
- | ---------------------- similarly named attribute macro `derive_const` defined here
+ = note: similarly named attribute macro `derive_const` defined here
error: aborting due to 2 previous errors
use std::collections::HashMap;
fn main() {
- for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
- //~^ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
- //~| ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+ for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+ //~^ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+ //~| ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
}
-error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
- --> $DIR/issue-33941.rs:6:14
+error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+ --> $DIR/issue-33941.rs:6:36
|
LL | for _ in HashMap::new().iter().cloned() {}
- | ^^^^^^^^^^^^^^^^^^^^^ ------ required by a bound introduced by this call
- | |
- | expected reference, found tuple
+ | ^^^^^^ expected reference, found tuple
|
= note: expected reference `&_`
found tuple `(&_, &_)`
+note: the method call chain might not have had the expected associated types
+ --> $DIR/issue-33941.rs:6:29
+ |
+LL | for _ in HashMap::new().iter().cloned() {}
+ | -------------- ^^^^^^ `Iterator::Item` is `(&_, &_)` here
+ | |
+ | this expression has type `HashMap<_, _>`
note: required by a bound in `cloned`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | Self: Sized + Iterator<Item = &'a T>,
- | ^^^^^^^^^^^^ required by this bound in `Iterator::cloned`
-error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:14
|
LL | for _ in HashMap::new().iter().cloned() {}
= note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `Iterator`
= note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `IntoIterator`
-error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:14
|
LL | for _ in HashMap::new().iter().cloned() {}
| +
error[E0277]: a value of type `Vec<(u32, _, _)>` cannot be built from an iterator over elements of type `()`
- --> $DIR/issue-34334.rs:5:33
+ --> $DIR/issue-34334.rs:5:87
|
LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- required by a bound introduced by this call
- | |
- | value of type `Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator<Item=()>`
+ | ^^^^^^^ value of type `Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator<Item=()>`
|
= help: the trait `FromIterator<()>` is not implemented for `Vec<(u32, _, _)>`
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
+note: the method call chain might not have had the expected associated types
+ --> $DIR/issue-34334.rs:5:43
+ |
+LL | let sr: Vec<(u32, _, _) = vec![];
+ | ------ this expression has type `Vec<(_, _, _)>`
+...
+LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
+ | ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Iterator::Item` changed to `()` here
+ | |
+ | `Iterator::Item` is `&(_, _, _)` here
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | fn collect<B: FromIterator<Self::Item>>(self) -> B
- | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
error: aborting due to 2 previous errors
LL | x.zero()
| ^ value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `x`
+note: `Foo::zero` takes ownership of the receiver `self`, which moves `x`
--> $DIR/issue-34721.rs:4:13
|
LL | fn zero(self) -> Self;
|
note: the module `sys` is defined here
--> $SRC_DIR/std/src/lib.rs:LL:COL
- |
-LL | mod sys;
- | ^^^^^^^
error: aborting due to 2 previous errors
--> $DIR/issue-40402-1.rs:9:13
|
LL | let e = f.v[0];
- | ^^^^^^
- | |
- | move occurs because value has type `String`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&f.v[0]`
+ | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let e = &f.v[0];
+ | +
error: aborting due to previous error
--> $DIR/issue-40402-2.rs:5:18
|
LL | let (a, b) = x[0];
- | - - ^^^^ help: consider borrowing here: `&x[0]`
+ | - - ^^^^
| | |
| | ...and here
| data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider borrowing here
+ |
+LL | let (a, b) = &x[0];
+ | +
error: aborting due to previous error
| ------------------------ method `iter` not found for this struct
...
LL | println!("{:?}", a.iter().take(10).collect::<Vec<usize>>());
- | ^^^^ method not found in `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:27]>`
+ | ^^^^ method not found in `Iterate<{integer}, [closure@issue-41880.rs:26:24]>`
error: aborting due to previous error
found reference `&'static str`
note: associated function defined here
--> $SRC_DIR/core/src/slice/mod.rs:LL:COL
- |
-LL | pub fn starts_with(&self, needle: &[T]) -> bool
- | ^^^^^^^^^^^
= note: this error originates in the macro `stringify` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
= help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `F`
note: associated function defined here
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
- |
-LL | pub fn new(x: T) -> Self {
- | ^^^
error: aborting due to previous error
LL | bad_letters.push('s');
| ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
|
-note: this function takes ownership of the receiver `self`, which moves `bad_letters`
+note: `into_iter` takes ownership of the receiver `self`, which moves `bad_letters`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
help: consider iterating over a slice of the `Vec<char>`'s content to avoid moving into the `for` loop
|
LL | for l in &bad_letters {
| |
| value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `orig`
+note: `into_iter` takes ownership of the receiver `self`, which moves `orig`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
help: consider iterating over a slice of the `Vec<bool>`'s content to avoid moving into the `for` loop
|
LL | for _val in &orig {}
error[E0277]: a value of type `Vec<f64>` cannot be built from an iterator over elements of type `&f64`
- --> $DIR/issue-66923-show-error-for-correct-call.rs:8:24
+ --> $DIR/issue-66923-show-error-for-correct-call.rs:8:39
|
LL | let x2: Vec<f64> = x1.into_iter().collect();
- | ^^^^^^^^^^^^^^ ------- required by a bound introduced by this call
- | |
- | value of type `Vec<f64>` cannot be built from `std::iter::Iterator<Item=&f64>`
+ | ^^^^^^^ value of type `Vec<f64>` cannot be built from `std::iter::Iterator<Item=&f64>`
|
= help: the trait `FromIterator<&f64>` is not implemented for `Vec<f64>`
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
+note: the method call chain might not have had the expected associated types
+ --> $DIR/issue-66923-show-error-for-correct-call.rs:8:27
+ |
+LL | let x1: &[f64] = &v;
+ | -- this expression has type `&Vec<f64>`
+LL | let x2: Vec<f64> = x1.into_iter().collect();
+ | ^^^^^^^^^^^ `Iterator::Item` is `&f64` here
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | fn collect<B: FromIterator<Self::Item>>(self) -> B
- | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
error[E0277]: a value of type `Vec<f64>` cannot be built from an iterator over elements of type `&f64`
- --> $DIR/issue-66923-show-error-for-correct-call.rs:12:14
+ --> $DIR/issue-66923-show-error-for-correct-call.rs:12:29
|
LL | let x3 = x1.into_iter().collect::<Vec<f64>>();
- | ^^^^^^^^^^^^^^ ------- required by a bound introduced by this call
- | |
- | value of type `Vec<f64>` cannot be built from `std::iter::Iterator<Item=&f64>`
+ | ^^^^^^^ value of type `Vec<f64>` cannot be built from `std::iter::Iterator<Item=&f64>`
|
= help: the trait `FromIterator<&f64>` is not implemented for `Vec<f64>`
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
+note: the method call chain might not have had the expected associated types
+ --> $DIR/issue-66923-show-error-for-correct-call.rs:12:17
+ |
+LL | let x1: &[f64] = &v;
+ | -- this expression has type `&Vec<f64>`
+...
+LL | let x3 = x1.into_iter().collect::<Vec<f64>>();
+ | ^^^^^^^^^^^ `Iterator::Item` is `&f64` here
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | fn collect<B: FromIterator<Self::Item>>(self) -> B
- | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
error: aborting due to 2 previous errors
|
LL | impl Fo {
| ^^ help: a trait with a similar name exists: `Fn`
+ --> $SRC_DIR/core/src/ops/function.rs:LL:COL
|
- ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
- | -------------------------------------- similarly named trait `Fn` defined here
+ = note: similarly named trait `Fn` defined here
error: aborting due to previous error
LL | for n in v {
| ^ value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `v`
+note: `into_iter` takes ownership of the receiver `self`, which moves `v`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
help: consider creating a fresh reborrow of `v` here
|
LL | for n in &mut *v {
//~^ ERROR an array of type `[u32; 10]` cannot be built directly from an iterator
//~| NOTE try collecting into a `Vec<{integer}>`, then using `.try_into()`
//~| NOTE required by a bound in `collect`
- //~| NOTE required by a bound introduced by this call
}
error[E0277]: an array of type `[u32; 10]` cannot be built directly from an iterator
- --> $DIR/collect-into-array.rs:2:31
+ --> $DIR/collect-into-array.rs:2:39
|
LL | let whatever: [u32; 10] = (0..10).collect();
- | ^^^^^^^ ------- required by a bound introduced by this call
- | |
- | try collecting into a `Vec<{integer}>`, then using `.try_into()`
+ | ^^^^^^^ try collecting into a `Vec<{integer}>`, then using `.try_into()`
|
= help: the trait `FromIterator<{integer}>` is not implemented for `[u32; 10]`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | fn collect<B: FromIterator<Self::Item>>(self) -> B
- | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
error: aborting due to previous error
//~| NOTE all local variables must have a statically known size
//~| NOTE doesn't have a size known at compile-time
//~| NOTE doesn't have a size known at compile-time
- //~| NOTE required by a bound introduced by this call
process_slice(&some_generated_vec);
}
= help: the trait `Sized` is not implemented for `[i32]`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | fn collect<B: FromIterator<Self::Item>>(self) -> B
- | ^ required by this bound in `Iterator::collect`
error[E0277]: a slice of type `[i32]` cannot be built since `[i32]` has no definite size
- --> $DIR/collect-into-slice.rs:6:30
+ --> $DIR/collect-into-slice.rs:6:38
|
LL | let some_generated_vec = (0..10).collect();
- | ^^^^^^^ ------- required by a bound introduced by this call
- | |
- | try explicitly collecting into a `Vec<{integer}>`
+ | ^^^^^^^ try explicitly collecting into a `Vec<{integer}>`
|
= help: the trait `FromIterator<{integer}>` is not implemented for `[i32]`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | fn collect<B: FromIterator<Self::Item>>(self) -> B
- | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
error: aborting due to 3 previous errors
--- /dev/null
+use std::collections::hash_set::Iter;
+use std::collections::HashSet;
+
+fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> {
+ let i = i.map(|x| x.clone());
+ i.collect() //~ ERROR E0277
+}
+
+fn main() {
+ let scores = vec![(0, 0)]
+ .iter()
+ .map(|(a, b)| {
+ a + b;
+ });
+ println!("{}", scores.sum::<i32>()); //~ ERROR E0277
+ println!(
+ "{}",
+ vec![0, 1]
+ .iter()
+ .map(|x| x * 2)
+ .map(|x| x as f64)
+ .map(|x| x as i64)
+ .filter(|x| *x > 0)
+ .map(|x| { x + 1 })
+ .map(|x| { x; })
+ .sum::<i32>(), //~ ERROR E0277
+ );
+ println!(
+ "{}",
+ vec![0, 1]
+ .iter()
+ .map(|x| x * 2)
+ .map(|x| x as f64)
+ .filter(|x| *x > 0.0)
+ .map(|x| { x + 1.0 })
+ .sum::<i32>(), //~ ERROR E0277
+ );
+ println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>()); //~ ERROR E0277
+ println!("{}", vec![(), ()].iter().sum::<i32>()); //~ ERROR E0277
+ let a = vec![0];
+ let b = a.into_iter();
+ let c = b.map(|x| x + 1);
+ let d = c.filter(|x| *x > 10 );
+ let e = d.map(|x| {
+ x + 1;
+ });
+ let f = e.filter(|_| false);
+ let g: Vec<i32> = f.collect(); //~ ERROR E0277
+
+ let mut s = HashSet::new();
+ s.insert(1u8);
+ println!("{:?}", iter_to_vec(s.iter()));
+}
--- /dev/null
+error[E0277]: a value of type `Vec<X>` cannot be built from an iterator over elements of type `&X`
+ --> $DIR/invalid-iterator-chain.rs:6:7
+ |
+LL | i.collect()
+ | ^^^^^^^ value of type `Vec<X>` cannot be built from `std::iter::Iterator<Item=&X>`
+ |
+ = help: the trait `FromIterator<&X>` is not implemented for `Vec<X>`
+ = help: the trait `FromIterator<T>` is implemented for `Vec<T>`
+note: the method call chain might not have had the expected associated types
+ --> $DIR/invalid-iterator-chain.rs:4:26
+ |
+LL | fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> {
+ | ^^^^^^^^^^^ `Iterator::Item` is `&X` here
+LL | let i = i.map(|x| x.clone());
+ | ------------------ `Iterator::Item` remains `&X` here
+note: required by a bound in `collect`
+ --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
+ --> $DIR/invalid-iterator-chain.rs:15:27
+ |
+LL | println!("{}", scores.sum::<i32>());
+ | ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
+ |
+ = help: the trait `Sum<()>` is not implemented for `i32`
+ = help: the following other types implement trait `Sum<A>`:
+ <i32 as Sum<&'a i32>>
+ <i32 as Sum>
+note: the method call chain might not have had the expected associated types
+ --> $DIR/invalid-iterator-chain.rs:12:10
+ |
+LL | let scores = vec![(0, 0)]
+ | ------------ this expression has type `Vec<({integer}, {integer})>`
+LL | .iter()
+ | ------ `Iterator::Item` is `&({integer}, {integer})` here
+LL | .map(|(a, b)| {
+ | __________^
+LL | | a + b;
+LL | | });
+ | |__________^ `Iterator::Item` changed to `()` here
+note: required by a bound in `std::iter::Iterator::sum`
+ --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
+ --> $DIR/invalid-iterator-chain.rs:26:14
+ |
+LL | .sum::<i32>(),
+ | ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
+ |
+ = help: the trait `Sum<()>` is not implemented for `i32`
+ = help: the following other types implement trait `Sum<A>`:
+ <i32 as Sum<&'a i32>>
+ <i32 as Sum>
+note: the method call chain might not have had the expected associated types
+ --> $DIR/invalid-iterator-chain.rs:20:14
+ |
+LL | vec![0, 1]
+ | ---------- this expression has type `Vec<{integer}>`
+LL | .iter()
+ | ------ `Iterator::Item` is `&{integer}` here
+LL | .map(|x| x * 2)
+ | ^^^^^^^^^^^^^^ `Iterator::Item` changed to `{integer}` here
+LL | .map(|x| x as f64)
+ | ----------------- `Iterator::Item` changed to `f64` here
+LL | .map(|x| x as i64)
+ | ----------------- `Iterator::Item` changed to `i64` here
+LL | .filter(|x| *x > 0)
+ | ------------------ `Iterator::Item` remains `i64` here
+LL | .map(|x| { x + 1 })
+ | ------------------ `Iterator::Item` remains `i64` here
+LL | .map(|x| { x; })
+ | ^^^^^^^^^^^^^^^ `Iterator::Item` changed to `()` here
+note: required by a bound in `std::iter::Iterator::sum`
+ --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `f64`
+ --> $DIR/invalid-iterator-chain.rs:36:14
+ |
+LL | .sum::<i32>(),
+ | ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=f64>`
+ |
+ = help: the trait `Sum<f64>` is not implemented for `i32`
+ = help: the following other types implement trait `Sum<A>`:
+ <i32 as Sum<&'a i32>>
+ <i32 as Sum>
+note: the method call chain might not have had the expected associated types
+ --> $DIR/invalid-iterator-chain.rs:32:14
+ |
+LL | vec![0, 1]
+ | ---------- this expression has type `Vec<{integer}>`
+LL | .iter()
+ | ------ `Iterator::Item` is `&{integer}` here
+LL | .map(|x| x * 2)
+ | ^^^^^^^^^^^^^^ `Iterator::Item` changed to `{integer}` here
+LL | .map(|x| x as f64)
+ | ^^^^^^^^^^^^^^^^^ `Iterator::Item` changed to `f64` here
+LL | .filter(|x| *x > 0.0)
+ | -------------------- `Iterator::Item` remains `f64` here
+LL | .map(|x| { x + 1.0 })
+ | -------------------- `Iterator::Item` remains `f64` here
+note: required by a bound in `std::iter::Iterator::sum`
+ --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
+ --> $DIR/invalid-iterator-chain.rs:38:54
+ |
+LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
+ | ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
+ |
+ = help: the trait `Sum<()>` is not implemented for `i32`
+ = help: the following other types implement trait `Sum<A>`:
+ <i32 as Sum<&'a i32>>
+ <i32 as Sum>
+note: the method call chain might not have had the expected associated types
+ --> $DIR/invalid-iterator-chain.rs:38:38
+ |
+LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
+ | ---------- ------ ^^^^^^^^^^^^^^^ `Iterator::Item` changed to `()` here
+ | | |
+ | | `Iterator::Item` is `&{integer}` here
+ | this expression has type `Vec<{integer}>`
+note: required by a bound in `std::iter::Iterator::sum`
+ --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `&()`
+ --> $DIR/invalid-iterator-chain.rs:39:40
+ |
+LL | println!("{}", vec![(), ()].iter().sum::<i32>());
+ | ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=&()>`
+ |
+ = help: the trait `Sum<&()>` is not implemented for `i32`
+ = help: the following other types implement trait `Sum<A>`:
+ <i32 as Sum<&'a i32>>
+ <i32 as Sum>
+note: the method call chain might not have had the expected associated types
+ --> $DIR/invalid-iterator-chain.rs:39:33
+ |
+LL | println!("{}", vec![(), ()].iter().sum::<i32>());
+ | ------------ ^^^^^^ `Iterator::Item` is `&()` here
+ | |
+ | this expression has type `Vec<()>`
+note: required by a bound in `std::iter::Iterator::sum`
+ --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error[E0277]: a value of type `Vec<i32>` cannot be built from an iterator over elements of type `()`
+ --> $DIR/invalid-iterator-chain.rs:48:25
+ |
+LL | let g: Vec<i32> = f.collect();
+ | ^^^^^^^ value of type `Vec<i32>` cannot be built from `std::iter::Iterator<Item=()>`
+ |
+ = help: the trait `FromIterator<()>` is not implemented for `Vec<i32>`
+ = help: the trait `FromIterator<T>` is implemented for `Vec<T>`
+note: the method call chain might not have had the expected associated types
+ --> $DIR/invalid-iterator-chain.rs:44:15
+ |
+LL | let a = vec![0];
+ | ------- this expression has type `Vec<{integer}>`
+LL | let b = a.into_iter();
+ | ----------- `Iterator::Item` is `{integer}` here
+LL | let c = b.map(|x| x + 1);
+ | -------------- `Iterator::Item` remains `{integer}` here
+LL | let d = c.filter(|x| *x > 10 );
+ | -------------------- `Iterator::Item` remains `{integer}` here
+LL | let e = d.map(|x| {
+ | _______________^
+LL | | x + 1;
+LL | | });
+ | |______^ `Iterator::Item` changed to `()` here
+LL | let f = e.filter(|_| false);
+ | ----------------- `Iterator::Item` remains `()` here
+note: required by a bound in `collect`
+ --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
|
LL | vec![true, false].map(|v| !v).collect::<Vec<_>>();
| ^^^ `Vec<bool>` is not an iterator; try calling `.into_iter()` or `.iter()`
+ --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
- ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- |
-LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
- | ------------------------------------------------------------------------------------------------ doesn't satisfy `Vec<bool>: Iterator`
+ = note: doesn't satisfy `Vec<bool>: Iterator`
|
= note: the following trait bounds were not satisfied:
`Vec<bool>: Iterator`
error[E0277]: a value of type `Bar` cannot be built from an iterator over elements of type `_`
- --> $DIR/branches.rs:19:9
+ --> $DIR/branches.rs:19:28
|
LL | std::iter::empty().collect()
- | ^^^^^^^^^^^^^^^^^^ ------- required by a bound introduced by this call
- | |
- | value of type `Bar` cannot be built from `std::iter::Iterator<Item=_>`
+ | ^^^^^^^ value of type `Bar` cannot be built from `std::iter::Iterator<Item=_>`
|
= help: the trait `FromIterator<_>` is not implemented for `Bar`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | fn collect<B: FromIterator<Self::Item>>(self) -> B
- | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
error: aborting due to previous error
|
help: consider giving this closure parameter an explicit type
|
-LL | |s: _| s.len()
- | +++
+LL | |s: /* Type */| s.len()
+ | ++++++++++++
error[E0282]: type annotations needed
--> $DIR/branches3.rs:15:10
|
help: consider giving this closure parameter an explicit type
|
-LL | |s: _| s.len()
- | +++
+LL | |s: /* Type */| s.len()
+ | ++++++++++++
error[E0282]: type annotations needed
--> $DIR/branches3.rs:23:10
|
help: consider giving this closure parameter an explicit type
|
-LL | |s: _| s.len()
- | +++
+LL | |s: /* Type */| s.len()
+ | ++++++++++++
error[E0282]: type annotations needed
--> $DIR/branches3.rs:30:10
|
help: consider giving this closure parameter an explicit type
|
-LL | |s: _| s.len()
- | +++
+LL | |s: /* Type */| s.len()
+ | ++++++++++++
error: aborting due to 4 previous errors
error[E0277]: a value of type `Foo` cannot be built from an iterator over elements of type `_`
- --> $DIR/recursion4.rs:10:9
+ --> $DIR/recursion4.rs:10:28
|
LL | x = std::iter::empty().collect();
- | ^^^^^^^^^^^^^^^^^^ ------- required by a bound introduced by this call
- | |
- | value of type `Foo` cannot be built from `std::iter::Iterator<Item=_>`
+ | ^^^^^^^ value of type `Foo` cannot be built from `std::iter::Iterator<Item=_>`
|
= help: the trait `FromIterator<_>` is not implemented for `Foo`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | fn collect<B: FromIterator<Self::Item>>(self) -> B
- | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
error[E0277]: a value of type `impl Debug` cannot be built from an iterator over elements of type `_`
- --> $DIR/recursion4.rs:19:9
+ --> $DIR/recursion4.rs:19:28
|
LL | x = std::iter::empty().collect();
- | ^^^^^^^^^^^^^^^^^^ ------- required by a bound introduced by this call
- | |
- | value of type `impl Debug` cannot be built from `std::iter::Iterator<Item=_>`
+ | ^^^^^^^ value of type `impl Debug` cannot be built from `std::iter::Iterator<Item=_>`
|
= help: the trait `FromIterator<_>` is not implemented for `impl Debug`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | fn collect<B: FromIterator<Self::Item>>(self) -> B
- | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
error: aborting due to 2 previous errors
--- /dev/null
+//~ type annotations needed: cannot satisfy `Self: Gen<'source>`
+
+pub trait Gen<'source> {
+ type Output;
+
+ fn gen<T>(&self) -> T
+ where
+ Self: for<'s> Gen<'s, Output = T>;
+}
+
+fn main() {}
--- /dev/null
+error[E0283]: type annotations needed: cannot satisfy `Self: Gen<'source>`
+ |
+note: multiple `impl`s or `where` clauses satisfying `Self: Gen<'source>` found
+ --> $DIR/conflicting-bounds.rs:3:1
+ |
+LL | pub trait Gen<'source> {
+ | ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | Self: for<'s> Gen<'s, Output = T>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.
LL | &'a (): Foo,
| ^^^
|
- = note: cannot satisfy `&'a (): Foo`
+note: multiple `impl`s or `where` clauses satisfying `&'a (): Foo` found
+ --> $DIR/issue-34979.rs:2:1
+ |
+LL | impl<'a, T> Foo for &'a T {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | &'a (): Foo,
+ | ^^^
+LL | &'static (): Foo;
+ | ^^^
error: aborting due to previous error
error[E0080]: values of the type `[u8; SIZE]` are too big for the current architecture
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
-LL | intrinsics::size_of::<T>()
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
note: inside `std::mem::size_of::<[u8; SIZE]>`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | intrinsics::size_of::<T>()
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `main`
--> $DIR/issue-55878.rs:7:26
|
|
note: enums with multiple inhabited variants have to be initialized to a variant
--> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | pub enum Result<T, E> {
- | ^^^^^^^^^^^^^^^^^^^^^
error: the type `&i32` does not permit zero-initialization
--> $DIR/invalid_value.rs:152:34
= note: the mutable reference will refer to this temporary, not the original `const` item
note: mutable reference created due to call to this method
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- |
-LL | pub fn push(&mut self, value: T) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: `const` item defined here
--> $DIR/lint-const-item-mutation.rs:31:1
|
LL | let z = x;
| ^ value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `x`
+note: `into_iter` takes ownership of the receiver `self`, which moves `x`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
help: consider iterating over a slice of the `Vec<S>`'s content to avoid moving into the `for` loop
|
LL | for y in &x {
| |
| `mutex` dropped here while still borrowed
|
-help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
- --> $SRC_DIR/core/src/macros/mod.rs:LL:COL
- |
-LL | $dst.write_fmt($crate::format_args!($($arg)*));
- | +
error[E0597]: `mutex` does not live long enough
--> $DIR/format-args-temporaries-in-write.rs:47:29
| |
| `mutex` dropped here while still borrowed
|
-help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
- --> $SRC_DIR/core/src/macros/mod.rs:LL:COL
- |
-LL | $dst.write_fmt($crate::format_args_nl!($($arg)*));
- | +
error: aborting due to 2 previous errors
|
LL | printlx!("oh noes!");
| ^^^^^^^ help: a macro with a similar name exists: `println`
+ --> $SRC_DIR/std/src/macros.rs:LL:COL
|
- ::: $SRC_DIR/std/src/macros.rs:LL:COL
- |
-LL | macro_rules! println {
- | -------------------- similarly named macro `println` defined here
+ = note: similarly named macro `println` defined here
error: aborting due to previous error
|
LL | inline!();
| ^^^^^^ help: a macro with a similar name exists: `line`
+ --> $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
- ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- |
-LL | macro_rules! line {
- | ----------------- similarly named macro `line` defined here
+ = note: similarly named macro `line` defined here
|
= note: `inline` is in scope, but it is an attribute: `#[inline]`
error[E0773]: attempted to define built-in macro more than once
--> $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
-LL | macro_rules! line {
- | ^^^^^^^^^^^^^^^^^
- |
note: previously defined here
--> $DIR/unknown-builtin.rs:9:1
|
|
note: required by a bound in `Copy`
--> $SRC_DIR/core/src/marker.rs:LL:COL
- |
-LL | pub trait Copy: Clone {
- | ^^^^^ required by this bound in `Copy`
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Test1` with `#[derive(Clone)]`
|
|
note: required by a bound in `Copy`
--> $SRC_DIR/core/src/marker.rs:LL:COL
- |
-LL | pub trait Copy: Clone {
- | ^^^^^ required by this bound in `Copy`
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Test2` with `#[derive(Clone)]`
|
|
help: consider giving `x` an explicit type
|
-LL | let x: _ = match () {
- | +++
+LL | let x: /* Type */ = match () {
+ | ++++++++++++
error: aborting due to previous error
= note: the following trait bounds were not satisfied:
`Foo: Iterator`
which is required by `&mut Foo: Iterator`
-note: the following trait must be implemented
+note: the trait `Iterator` must be implemented
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | pub trait Iterator {
- | ^^^^^^^^^^^^^^^^^^
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `take`, perhaps you need to implement it:
candidate #1: `Iterator`
|
LL | 0.clone::<'a>();
| ^^
+ --> $SRC_DIR/core/src/clone.rs:LL:COL
|
- ::: $SRC_DIR/core/src/clone.rs:LL:COL
- |
-LL | fn clone(&self) -> Self;
- | - the late bound lifetime parameter is introduced here
+ = note: the late bound lifetime parameter is introduced here
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
--> $DIR/method-not-found-generic-arg-elision.rs:87:29
|
LL | v.iter().map(|x| x * x).extend(std::iter::once(100));
- | ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:21]>`
+ | ^^^^^^ method not found in `Map<Iter<'_, i32>, [closure@method-not-found-generic-arg-elision.rs:87:18]>`
error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope
--> $DIR/method-not-found-generic-arg-elision.rs:90:13
|
LL | struct Foo;
| ^^^^^^^^^^ must implement `AddAssign<_>`
-note: the following trait must be implemented
+note: the trait `AddAssign` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | pub trait AddAssign<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
|
note: required by a bound in `map`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | F: FnMut(Self::Item) -> B,
- | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 3 distinct arguments
--> $DIR/closure-arg-count.rs:27:57
|
note: required by a bound in `map`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | F: FnMut(Self::Item) -> B,
- | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
error[E0593]: function is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments
--> $DIR/closure-arg-count.rs:29:57
|
note: required by a bound in `map`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | F: FnMut(Self::Item) -> B,
- | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
error[E0593]: function is expected to take 1 argument, but it takes 2 arguments
--> $DIR/closure-arg-count.rs:32:45
|
note: required by a bound in `map`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | F: FnMut(Self::Item) -> B,
- | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
error[E0593]: function is expected to take 0 arguments, but it takes 1 argument
--> $DIR/closure-arg-count.rs:35:10
--> $DIR/closure-arg-type-mismatch.rs:3:14
|
LL | a.iter().map(|_: (u32, u32)| 45);
- | ^^^ --------------- found signature defined here
- | |
+ | ^^^ ---------------
+ | | | |
+ | | | help: consider borrowing the argument: `&(u32, u32)`
+ | | found signature defined here
| expected due to this
|
= note: expected closure signature `fn(&(u32, u32)) -> _`
found closure signature `fn((u32, u32)) -> _`
note: required by a bound in `map`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | F: FnMut(Self::Item) -> B,
- | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
error[E0631]: type mismatch in closure arguments
--> $DIR/closure-arg-type-mismatch.rs:4:14
found closure signature `for<'a> fn(&'a (u16, u16)) -> _`
note: required by a bound in `map`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | F: FnMut(Self::Item) -> B,
- | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
error[E0631]: type mismatch in closure arguments
--> $DIR/closure-arg-type-mismatch.rs:5:14
found closure signature `fn((u16, u16)) -> _`
note: required by a bound in `map`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | F: FnMut(Self::Item) -> B,
- | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
error: aborting due to 3 previous errors
found type `bool` (`bool`)
note: tuple variant defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^
error: aborting due to previous error
--> $DIR/issue-36053-2.rs:7:32
|
LL | once::<&str>("str").fuse().filter(|a: &str| true).count();
- | ^^^^^^ --------- found signature defined here
- | |
+ | ^^^^^^ ---------
+ | | | |
+ | | | help: consider borrowing the argument: `&&str`
+ | | found signature defined here
| expected due to this
|
= note: expected closure signature `for<'a> fn(&'a &str) -> _`
found closure signature `for<'a> fn(&'a str) -> _`
note: required by a bound in `filter`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | P: FnMut(&Self::Item) -> bool,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::filter`
-error[E0599]: the method `count` exists for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>`, but its trait bounds were not satisfied
+error[E0599]: the method `count` exists for struct `Filter<Fuse<Once<&str>>, [closure@issue-36053-2.rs:7:39]>`, but its trait bounds were not satisfied
--> $DIR/issue-36053-2.rs:7:55
|
LL | once::<&str>("str").fuse().filter(|a: &str| true).count();
- | --------- ^^^^^ method cannot be called on `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>` due to unsatisfied trait bounds
+ | --------- ^^^^^ method cannot be called due to unsatisfied trait bounds
| |
| doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool`
| doesn't satisfy `_: FnMut<(&&str,)>`
+ --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL
|
- ::: $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL
- |
-LL | pub struct Filter<I, P> {
- | ----------------------- doesn't satisfy `_: Iterator`
+ = note: doesn't satisfy `_: Iterator`
|
= note: the following trait bounds were not satisfied:
`<[closure@$DIR/issue-36053-2.rs:7:39: 7:48] as FnOnce<(&&str,)>>::Output = bool`
|
note: required by a bound in `Option::<T>::map`
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | F: ~const FnOnce(T) -> U,
- | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
error: aborting due to previous error
|
note: required by a bound in `Option::<T>::map`
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | F: ~const FnOnce(T) -> U,
- | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
error[E0593]: function is expected to take 0 arguments, but it takes 1 argument
--> $DIR/issue-47706.rs:27:9
|
LL | fn next(&mut self) -> Option<IteratorChunk<T, S>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'1, T, S>>`
+ --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
- ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | fn next(&mut self) -> Option<Self::Item>;
- | ----------------------------------------- expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
+ = note: expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
|
= note: expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
found `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'1, T, S>>`
error[E0277]: `Foo` doesn't implement `Debug`
- --> $DIR/method-help-unsatisfied-bound.rs:5:5
+ --> $DIR/method-help-unsatisfied-bound.rs:5:7
|
LL | a.unwrap();
- | ^ ------ required by a bound introduced by this call
- | |
- | `Foo` cannot be formatted using `{:?}`
+ | ^^^^^^ `Foo` cannot be formatted using `{:?}`
|
= help: the trait `Debug` is not implemented for `Foo`
= note: add `#[derive(Debug)]` to `Foo` or manually `impl Debug for Foo`
note: required by a bound in `Result::<T, E>::unwrap`
--> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | E: fmt::Debug,
- | ^^^^^^^^^^ required by this bound in `Result::<T, E>::unwrap`
help: consider annotating `Foo` with `#[derive(Debug)]`
|
LL | #[derive(Debug)]
= note: enum `std::option::Option` and enum `Option` have similar names, but are actually distinct types
note: enum `std::option::Option` is defined in crate `core`
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | pub enum Option<T> {
- | ^^^^^^^^^^^^^^^^^^
note: enum `Option` is defined in the current crate
--> $DIR/similar_paths.rs:1:1
|
| ^
LL |
LL | &Some(_y) => (),
- | ---------
- | | |
- | | data moved here
- | | move occurs because `_y` has type `Box<i32>`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `Some(_y)`
+ | --
+ | |
+ | data moved here
+ | move occurs because `_y` has type `Box<i32>`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - &Some(_y) => (),
+LL + Some(_y) => (),
+ |
error: aborting due to previous error
LL | val.0;
| ^^^^^ value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `val.0`
+note: `into_iter` takes ownership of the receiver `self`, which moves `val.0`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
= note: move occurs because `val.0` has type `Vec<bool>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `foo`
LL | foo;
| ^^^ value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `foo`
+note: `Foo::use_self` takes ownership of the receiver `self`, which moves `foo`
--> $DIR/move-fn-self-receiver.rs:13:17
|
LL | fn use_self(self) {}
LL | boxed_foo;
| ^^^^^^^^^ value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `boxed_foo`
+note: `Foo::use_box_self` takes ownership of the receiver `self`, which moves `boxed_foo`
--> $DIR/move-fn-self-receiver.rs:14:21
|
LL | fn use_box_self(self: Box<Self>) {}
LL | pin_box_foo;
| ^^^^^^^^^^^ value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `pin_box_foo`
+note: `Foo::use_pin_box_self` takes ownership of the receiver `self`, which moves `pin_box_foo`
--> $DIR/move-fn-self-receiver.rs:15:25
|
LL | fn use_pin_box_self(self: Pin<Box<Self>>) {}
LL | rc_foo;
| ^^^^^^ value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `rc_foo`
+note: `Foo::use_rc_self` takes ownership of the receiver `self`, which moves `rc_foo`
--> $DIR/move-fn-self-receiver.rs:16:20
|
LL | fn use_rc_self(self: Rc<Self>) {}
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | fn add(self, rhs: Rhs) -> Self::Output;
- | ^^^^
error[E0382]: use of moved value: `implicit_into_iter`
--> $DIR/move-fn-self-receiver.rs:63:5
LL | container;
| ^^^^^^^^^ value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `container`
+note: `Container::custom_into_iter` takes ownership of the receiver `self`, which moves `container`
--> $DIR/move-fn-self-receiver.rs:23:25
|
LL | fn custom_into_iter(self) -> impl Iterator<Item = bool> {
--> $DIR/move-out-of-array-ref.rs:8:24
|
LL | let [_, e, _, _] = *a;
- | - ^^
- | | |
- | | cannot move out of here
- | | help: consider borrowing here: `&*a`
+ | - ^^ cannot move out of here
+ | |
| data moved here
| move occurs because `e` has type `D`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let [_, e, _, _] = *a;
+LL + let [_, e, _, _] = a;
+ |
error[E0508]: cannot move out of type `[D; 4]`, a non-copy array
--> $DIR/move-out-of-array-ref.rs:13:27
|
LL | let [_, s @ .. , _] = *a;
- | - ^^
- | | |
- | | cannot move out of here
- | | help: consider borrowing here: `&*a`
+ | - ^^ cannot move out of here
+ | |
| data moved here
| move occurs because `s` has type `[D; 2]`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let [_, s @ .. , _] = *a;
+LL + let [_, s @ .. , _] = a;
+ |
error[E0508]: cannot move out of type `[D; 4]`, a non-copy array
--> $DIR/move-out-of-array-ref.rs:18:24
|
LL | let [_, e, _, _] = *a;
- | - ^^
- | | |
- | | cannot move out of here
- | | help: consider borrowing here: `&*a`
+ | - ^^ cannot move out of here
+ | |
| data moved here
| move occurs because `e` has type `D`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let [_, e, _, _] = *a;
+LL + let [_, e, _, _] = a;
+ |
error[E0508]: cannot move out of type `[D; 4]`, a non-copy array
--> $DIR/move-out-of-array-ref.rs:23:27
|
LL | let [_, s @ .. , _] = *a;
- | - ^^
- | | |
- | | cannot move out of here
- | | help: consider borrowing here: `&*a`
+ | - ^^ cannot move out of here
+ | |
| data moved here
| move occurs because `s` has type `[D; 2]`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let [_, s @ .. , _] = *a;
+LL + let [_, s @ .. , _] = a;
+ |
error: aborting due to 4 previous errors
| |
| data moved here
| move occurs because `a` has type `A`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | box [ref a] => {},
+ | +++
error: aborting due to previous error
#![feature(unsized_locals)]
//~^ WARN the feature `unsized_locals` is incomplete
+#![allow(unused)]
struct A;
#[derive(Clone, Copy)]
= note: `#[warn(incomplete_features)]` on by default
error[E0508]: cannot move out of type `[A]`, a non-copy slice
- --> $DIR/move-out-of-slice-2.rs:10:11
+ --> $DIR/move-out-of-slice-2.rs:11:11
|
LL | match *a {
| ^^ cannot move out of here
| |
| data moved here
| move occurs because `a` has type `[A]`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | [ref a @ ..] => {}
+ | +++
error[E0508]: cannot move out of type `[A]`, a non-copy slice
- --> $DIR/move-out-of-slice-2.rs:16:11
+ --> $DIR/move-out-of-slice-2.rs:17:11
|
LL | match *b {
| ^^ cannot move out of here
| |
| data moved here
| move occurs because `b` has type `[A]`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | [_, _, ref b @ .., _] => {}
+ | +++
error[E0508]: cannot move out of type `[C]`, a non-copy slice
- --> $DIR/move-out-of-slice-2.rs:24:11
+ --> $DIR/move-out-of-slice-2.rs:25:11
|
LL | match *c {
| ^^ cannot move out of here
| |
| data moved here
| move occurs because `c` has type `[C]`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | [ref c @ ..] => {}
+ | +++
error[E0508]: cannot move out of type `[C]`, a non-copy slice
- --> $DIR/move-out-of-slice-2.rs:30:11
+ --> $DIR/move-out-of-slice-2.rs:31:11
|
LL | match *d {
| ^^ cannot move out of here
| |
| data moved here
| move occurs because `d` has type `[C]`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | [_, _, ref d @ .., _] => {}
+ | +++
error: aborting due to 4 previous errors; 1 warning emitted
LL | touch(&x[0]);
| ^ value borrowed here after move
|
-note: this function takes ownership of the receiver `self`, which moves `x`
+note: `into_iter` takes ownership of the receiver `self`, which moves `x`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
help: consider cloning the value if the performance cost is acceptable
|
LL | consume(x.clone().into_iter().next().unwrap());
--> $DIR/moves-based-on-type-block-bad.rs:22:19
|
LL | match hellothere.x {
- | ^^^^^^^^^^^^ help: consider borrowing here: `&hellothere.x`
+ | ^^^^^^^^^^^^
LL | box E::Foo(_) => {}
LL | box E::Bar(x) => println!("{}", x.to_string()),
| -
| |
| data moved here
| move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &hellothere.x {
+ | +
error: aborting due to previous error
LL | touch(&x);
| ^^ value borrowed here after move
|
-note: this function takes ownership of the receiver `self`, which moves `x`
+note: `into_iter` takes ownership of the receiver `self`, which moves `x`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
help: consider cloning the value if the performance cost is acceptable
|
LL | let _y = x.clone().into_iter().next().unwrap();
LL | touch(&x);
| ^^ value borrowed here after move
|
-note: this function takes ownership of the receiver `self`, which moves `x`
+note: `into_iter` takes ownership of the receiver `self`, which moves `x`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
help: consider cloning the value if the performance cost is acceptable
|
LL | let _y = [x.clone().into_iter().next().unwrap(); 1];
-error[E0271]: expected `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to be a closure that returns `()`, but it returns `!`
+error[E0271]: expected `[closure@fallback-closure-wrap.rs:18:40]` to be a closure that returns `()`, but it returns `!`
--> $DIR/fallback-closure-wrap.rs:18:31
|
LL | let error = Closure::wrap(Box::new(move || {
| --- ^^^^^^^^
| | |
| | the trait `T` is not implemented for `()`
- | | this tail expression is of type `_`
+ | | this tail expression is of type `()`
| required by a bound introduced by this call
|
note: required by a bound in `foo`
|
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | impl<I: Iterator> const IntoIterator for I {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
error[E0658]: mutable references are not allowed in constants
found struct `RangeTo<{integer}>`
note: associated function defined here
--> $SRC_DIR/core/src/ops/range.rs:LL:COL
- |
-LL | pub const fn new(start: Idx, end: Idx) -> Self {
- | ^^^
error: aborting due to 2 previous errors
--> $DIR/cannot-move-block-spans.rs:5:15
|
LL | let x = { *r };
- | ^^
- | |
- | move occurs because `*r` has type `String`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*r`
+ | ^^ move occurs because `*r` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let x = { *r };
+LL + let x = { r };
+ |
error[E0507]: cannot move out of `*r` which is behind a shared reference
--> $DIR/cannot-move-block-spans.rs:6:22
|
LL | let y = unsafe { *r };
- | ^^
- | |
- | move occurs because `*r` has type `String`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*r`
+ | ^^ move occurs because `*r` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let y = unsafe { *r };
+LL + let y = unsafe { r };
+ |
error[E0507]: cannot move out of `*r` which is behind a shared reference
--> $DIR/cannot-move-block-spans.rs:7:26
|
LL | let z = loop { break *r; };
- | ^^
- | |
- | move occurs because `*r` has type `String`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*r`
+ | ^^ move occurs because `*r` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let z = loop { break *r; };
+LL + let z = loop { break r; };
+ |
error[E0508]: cannot move out of type `[String; 2]`, a non-copy array
--> $DIR/cannot-move-block-spans.rs:11:15
| |
| cannot move out of here
| move occurs because `arr[_]` has type `String`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&arr[0]`
+ |
+help: consider borrowing here
+ |
+LL | let x = { &arr[0] };
+ | +
error[E0508]: cannot move out of type `[String; 2]`, a non-copy array
--> $DIR/cannot-move-block-spans.rs:12:22
| |
| cannot move out of here
| move occurs because `arr[_]` has type `String`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&arr[0]`
+ |
+help: consider borrowing here
+ |
+LL | let y = unsafe { &arr[0] };
+ | +
error[E0508]: cannot move out of type `[String; 2]`, a non-copy array
--> $DIR/cannot-move-block-spans.rs:13:26
| |
| cannot move out of here
| move occurs because `arr[_]` has type `String`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&arr[0]`
+ |
+help: consider borrowing here
+ |
+LL | let z = loop { break &arr[0]; };
+ | +
error[E0507]: cannot move out of `*r` which is behind a shared reference
--> $DIR/cannot-move-block-spans.rs:17:38
|
LL | let x = { let mut u = 0; u += 1; *r };
- | ^^
- | |
- | move occurs because `*r` has type `String`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*r`
+ | ^^ move occurs because `*r` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let x = { let mut u = 0; u += 1; *r };
+LL + let x = { let mut u = 0; u += 1; r };
+ |
error[E0507]: cannot move out of `*r` which is behind a shared reference
--> $DIR/cannot-move-block-spans.rs:18:45
|
LL | let y = unsafe { let mut u = 0; u += 1; *r };
- | ^^
- | |
- | move occurs because `*r` has type `String`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*r`
+ | ^^ move occurs because `*r` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let y = unsafe { let mut u = 0; u += 1; *r };
+LL + let y = unsafe { let mut u = 0; u += 1; r };
+ |
error[E0507]: cannot move out of `*r` which is behind a shared reference
--> $DIR/cannot-move-block-spans.rs:19:49
|
LL | let z = loop { let mut u = 0; u += 1; break *r; u += 2; };
- | ^^
- | |
- | move occurs because `*r` has type `String`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*r`
+ | ^^ move occurs because `*r` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let z = loop { let mut u = 0; u += 1; break *r; u += 2; };
+LL + let z = loop { let mut u = 0; u += 1; break r; u += 2; };
+ |
error: aborting due to 9 previous errors
| |
| cannot move out of here
| move occurs because `s.url` has type `&mut String`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&s.url`
+ |
+help: consider borrowing here
+ |
+LL | let p = &s.url; p
+ | +
error: aborting due to 4 previous errors
--> $DIR/move-errors.rs:6:13
|
LL | let b = *a;
- | ^^
- | |
- | move occurs because `*a` has type `A`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*a`
+ | ^^ move occurs because `*a` has type `A`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let b = *a;
+LL + let b = a;
+ |
error[E0508]: cannot move out of type `[A; 1]`, a non-copy array
--> $DIR/move-errors.rs:12:13
| |
| cannot move out of here
| move occurs because `a[_]` has type `A`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&a[0]`
+ |
+help: consider borrowing here
+ |
+LL | let b = &a[0];
+ | +
error[E0507]: cannot move out of `**r` which is behind a shared reference
--> $DIR/move-errors.rs:19:13
|
LL | let s = **r;
- | ^^^
- | |
- | move occurs because `**r` has type `A`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&**r`
+ | ^^^ move occurs because `**r` has type `A`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let s = **r;
+LL + let s = *r;
+ |
error[E0507]: cannot move out of an `Rc`
--> $DIR/move-errors.rs:27:13
|
LL | let s = *r;
- | ^^
- | |
- | move occurs because value has type `A`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*r`
+ | ^^ move occurs because value has type `A`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let s = *r;
+LL + let s = r;
+ |
error[E0508]: cannot move out of type `[A; 1]`, a non-copy array
--> $DIR/move-errors.rs:32:13
| |
| cannot move out of here
| move occurs because value has type `A`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&[A("".to_string())][0]`
+ |
+help: consider borrowing here
+ |
+LL | let a = &[A("".to_string())][0];
+ | +
error[E0507]: cannot move out of `a` which is behind a shared reference
--> $DIR/move-errors.rs:38:16
|
LL | let A(s) = *a;
- | - ^^ help: consider borrowing here: `&*a`
+ | - ^^
| |
| data moved here
| move occurs because `s` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let A(s) = *a;
+LL + let A(s) = a;
+ |
error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
--> $DIR/move-errors.rs:44:19
| |
| data moved here
| move occurs because `s` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | let C(D(ref s)) = c;
+ | +++
error[E0507]: cannot move out of `*a` which is behind a shared reference
--> $DIR/move-errors.rs:51:9
--> $DIR/move-errors.rs:74:11
|
LL | match x[0] {
- | ^^^^
- | |
- | cannot move out of here
- | help: consider borrowing here: `&x[0]`
+ | ^^^^ cannot move out of here
LL |
LL | B::U(d) => (),
| - data moved here
| - ...and here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider borrowing here
+ |
+LL | match &x[0] {
+ | +
error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
--> $DIR/move-errors.rs:83:11
| |
| data moved here
| move occurs because `s` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | B::U(D(ref s)) => (),
+ | +++
error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
--> $DIR/move-errors.rs:92:11
| |
| data moved here
| move occurs because `s` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | (D(ref s), &t) => (),
+ | +++
error[E0507]: cannot move out of `*x.1` which is behind a shared reference
--> $DIR/move-errors.rs:92:11
| |
| data moved here
| move occurs because `t` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | (D(s), &ref t) => (),
+ | +++
error[E0509]: cannot move out of type `F`, which implements the `Drop` trait
--> $DIR/move-errors.rs:102:11
| data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider borrowing the pattern binding
+ |
+LL | F(ref s, mut t) => (),
+ | +++
+help: consider borrowing the pattern binding
+ |
+LL | F(s, ref mut t) => (),
+ | +++
error[E0507]: cannot move out of `x` as enum variant `Err` which is behind a shared reference
--> $DIR/move-errors.rs:110:11
|
LL | match *x {
- | ^^ help: consider borrowing here: `&*x`
+ | ^^
LL |
LL | Ok(s) | Err(s) => (),
| -
| |
| data moved here
| move occurs because `s` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - match *x {
+LL + match x {
+ |
error: aborting due to 14 previous errors
| ^^^^^^^^ value borrowed here after move
|
= note: borrow occurs due to deref coercion to `Vec<i32>`
-note: deref defined here
- --> $SRC_DIR/alloc/src/sync.rs:LL:COL
- |
-LL | type Target = T;
- | ^^^^^^^^^^^
error: aborting due to previous error
| ^^^^^^^^ value borrowed here after move
|
= note: borrow occurs due to deref coercion to `Vec<i32>`
-note: deref defined here
- --> $SRC_DIR/alloc/src/sync.rs:LL:COL
- |
-LL | type Target = T;
- | ^^^^^^^^^^^
error: aborting due to previous error
| ^^^^^^
note: required by a bound in `spawn`
--> $SRC_DIR/std/src/thread/mod.rs:LL:COL
- |
-LL | F: Send + 'static,
- | ^^^^ required by this bound in `spawn`
error: aborting due to previous error
error[E0277]: the trait bound `S: Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 7:24]`
- --> $DIR/not-clone-closure.rs:11:17
+ --> $DIR/not-clone-closure.rs:11:23
|
LL | let hello = move || {
| ------- within this `[closure@$DIR/not-clone-closure.rs:7:17: 7:24]`
...
LL | let hello = hello.clone();
- | ^^^^^ ----- required by a bound introduced by this call
- | |
- | within `[closure@$DIR/not-clone-closure.rs:7:17: 7:24]`, the trait `Clone` is not implemented for `S`
+ | ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 7:24]`, the trait `Clone` is not implemented for `S`
|
note: required because it's used within this closure
--> $DIR/not-clone-closure.rs:7:17
--- /dev/null
+// Checks that integers with seeming uppercase base prefixes do not get bogus capitalization
+// suggestions.
+
+fn main() {
+ _ = 123X1a3;
+ //~^ ERROR invalid suffix `X1a3` for number literal
+ //~| NOTE invalid suffix `X1a3`
+ //~| HELP the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+ _ = 456O123;
+ //~^ ERROR invalid suffix `O123` for number literal
+ //~| NOTE invalid suffix `O123`
+ //~| HELP the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+ _ = 789B101;
+ //~^ ERROR invalid suffix `B101` for number literal
+ //~| NOTE invalid suffix `B101`
+ //~| HELP the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+ _ = 0XYZ;
+ //~^ ERROR invalid suffix `XYZ` for number literal
+ //~| NOTE invalid suffix `XYZ`
+ //~| HELP the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+ _ = 0OPQ;
+ //~^ ERROR invalid suffix `OPQ` for number literal
+ //~| NOTE invalid suffix `OPQ`
+ //~| HELP the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+ _ = 0BCD;
+ //~^ ERROR invalid suffix `BCD` for number literal
+ //~| NOTE invalid suffix `BCD`
+ //~| HELP the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+}
--- /dev/null
+error: invalid suffix `X1a3` for number literal
+ --> $DIR/uppercase-base-prefix-invalid-no-fix.rs:5:9
+ |
+LL | _ = 123X1a3;
+ | ^^^^^^^ invalid suffix `X1a3`
+ |
+ = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+error: invalid suffix `O123` for number literal
+ --> $DIR/uppercase-base-prefix-invalid-no-fix.rs:10:9
+ |
+LL | _ = 456O123;
+ | ^^^^^^^ invalid suffix `O123`
+ |
+ = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+error: invalid suffix `B101` for number literal
+ --> $DIR/uppercase-base-prefix-invalid-no-fix.rs:15:9
+ |
+LL | _ = 789B101;
+ | ^^^^^^^ invalid suffix `B101`
+ |
+ = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+error: invalid suffix `XYZ` for number literal
+ --> $DIR/uppercase-base-prefix-invalid-no-fix.rs:20:9
+ |
+LL | _ = 0XYZ;
+ | ^^^^ invalid suffix `XYZ`
+ |
+ = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+error: invalid suffix `OPQ` for number literal
+ --> $DIR/uppercase-base-prefix-invalid-no-fix.rs:25:9
+ |
+LL | _ = 0OPQ;
+ | ^^^^ invalid suffix `OPQ`
+ |
+ = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+error: invalid suffix `BCD` for number literal
+ --> $DIR/uppercase-base-prefix-invalid-no-fix.rs:30:9
+ |
+LL | _ = 0BCD;
+ | ^^^^ invalid suffix `BCD`
+ |
+ = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+error: aborting due to 6 previous errors
+
error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `&()`
- --> $DIR/sum.rs:4:5
+ --> $DIR/sum.rs:4:25
|
LL | vec![(), ()].iter().sum::<i32>();
- | ^^^^^^^^^^^^^^^^^^^ --- required by a bound introduced by this call
- | |
- | value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=&()>`
+ | ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=&()>`
|
= help: the trait `Sum<&()>` is not implemented for `i32`
= help: the following other types implement trait `Sum<A>`:
<i32 as Sum<&'a i32>>
<i32 as Sum>
+note: the method call chain might not have had the expected associated types
+ --> $DIR/sum.rs:4:18
+ |
+LL | vec![(), ()].iter().sum::<i32>();
+ | ------------ ^^^^^^ `Iterator::Item` is `&()` here
+ | |
+ | this expression has type `Vec<()>`
note: required by a bound in `std::iter::Iterator::sum`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | S: Sum<Self::Item>,
- | ^^^^^^^^^^^^^^^ required by this bound in `Iterator::sum`
error[E0277]: a value of type `i32` cannot be made by multiplying all elements of type `&()` from an iterator
- --> $DIR/sum.rs:7:5
+ --> $DIR/sum.rs:7:25
|
LL | vec![(), ()].iter().product::<i32>();
- | ^^^^^^^^^^^^^^^^^^^ ------- required by a bound introduced by this call
- | |
- | value of type `i32` cannot be made by multiplying all elements from a `std::iter::Iterator<Item=&()>`
+ | ^^^^^^^ value of type `i32` cannot be made by multiplying all elements from a `std::iter::Iterator<Item=&()>`
|
= help: the trait `Product<&()>` is not implemented for `i32`
= help: the following other types implement trait `Product<A>`:
<i32 as Product<&'a i32>>
<i32 as Product>
+note: the method call chain might not have had the expected associated types
+ --> $DIR/sum.rs:7:18
+ |
+LL | vec![(), ()].iter().product::<i32>();
+ | ------------ ^^^^^^ `Iterator::Item` is `&()` here
+ | |
+ | this expression has type `Vec<()>`
note: required by a bound in `std::iter::Iterator::product`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | P: Product<Self::Item>,
- | ^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::product`
error: aborting due to 2 previous errors
|
LL | enum E { A, B }
| ^^^^^^ must implement `BitOr<_>`
-note: the following trait must be implemented
+note: the trait `BitOr` must be implemented
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
- |
-LL | pub trait BitOr<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 5 previous errors
|
note: required by a bound in `FnMut`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | pub trait FnMut<Args: Tuple>: FnOnce<Args> {
- | ^^^^^ required by this bound in `FnMut`
error[E0059]: type parameter to bare `FnOnce` trait must be a tuple
--> $DIR/overloaded-calls-nontuple.rs:18:6
|
note: required by a bound in `FnOnce`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | pub trait FnOnce<Args: Tuple> {
- | ^^^^^ required by this bound in `FnOnce`
error[E0277]: functions with the "rust-call" ABI must take a single non-self tuple argument
--> $DIR/overloaded-calls-nontuple.rs:12:5
--- /dev/null
+// run-rustfix
+
+struct Foo {
+ bar: Bar,
+}
+
+struct Bar {
+ qux: i32,
+}
+
+pub fn post_regular() {
+ let mut i = 0;
+ i += 1; //~ ERROR Rust has no postfix increment operator
+ println!("{}", i);
+}
+
+pub fn post_while() {
+ let mut i = 0;
+ while { let tmp = i; i += 1; tmp } < 5 {
+ //~^ ERROR Rust has no postfix increment operator
+ println!("{}", i);
+ }
+}
+
+pub fn post_regular_tmp() {
+ let mut tmp = 0;
+ tmp += 1; //~ ERROR Rust has no postfix increment operator
+ println!("{}", tmp);
+}
+
+pub fn post_while_tmp() {
+ let mut tmp = 0;
+ while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 {
+ //~^ ERROR Rust has no postfix increment operator
+ println!("{}", tmp);
+ }
+}
+
+pub fn post_field() {
+ let mut foo = Foo { bar: Bar { qux: 0 } };
+ foo.bar.qux += 1;
+ //~^ ERROR Rust has no postfix increment operator
+ println!("{}", foo.bar.qux);
+}
+
+pub fn post_field_tmp() {
+ struct S {
+ tmp: i32
+ }
+ let mut s = S { tmp: 0 };
+ s.tmp += 1;
+ //~^ ERROR Rust has no postfix increment operator
+ println!("{}", s.tmp);
+}
+
+pub fn pre_field() {
+ let mut foo = Foo { bar: Bar { qux: 0 } };
+ foo.bar.qux += 1;
+ //~^ ERROR Rust has no prefix increment operator
+ println!("{}", foo.bar.qux);
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+
+struct Foo {
+ bar: Bar,
+}
+
+struct Bar {
+ qux: i32,
+}
+
+pub fn post_regular() {
+ let mut i = 0;
+ i++; //~ ERROR Rust has no postfix increment operator
+ println!("{}", i);
+}
+
+pub fn post_while() {
+ let mut i = 0;
+ while i++ < 5 {
+ //~^ ERROR Rust has no postfix increment operator
+ println!("{}", i);
+ }
+}
+
+pub fn post_regular_tmp() {
+ let mut tmp = 0;
+ tmp++; //~ ERROR Rust has no postfix increment operator
+ println!("{}", tmp);
+}
+
+pub fn post_while_tmp() {
+ let mut tmp = 0;
+ while tmp++ < 5 {
+ //~^ ERROR Rust has no postfix increment operator
+ println!("{}", tmp);
+ }
+}
+
+pub fn post_field() {
+ let mut foo = Foo { bar: Bar { qux: 0 } };
+ foo.bar.qux++;
+ //~^ ERROR Rust has no postfix increment operator
+ println!("{}", foo.bar.qux);
+}
+
+pub fn post_field_tmp() {
+ struct S {
+ tmp: i32
+ }
+ let mut s = S { tmp: 0 };
+ s.tmp++;
+ //~^ ERROR Rust has no postfix increment operator
+ println!("{}", s.tmp);
+}
+
+pub fn pre_field() {
+ let mut foo = Foo { bar: Bar { qux: 0 } };
+ ++foo.bar.qux;
+ //~^ ERROR Rust has no prefix increment operator
+ println!("{}", foo.bar.qux);
+}
+
+fn main() {}
--- /dev/null
+error: Rust has no postfix increment operator
+ --> $DIR/increment-autofix-2.rs:13:6
+ |
+LL | i++;
+ | ^^ not a valid postfix operator
+ |
+help: use `+= 1` instead
+ |
+LL | i += 1;
+ | ~~~~
+
+error: Rust has no postfix increment operator
+ --> $DIR/increment-autofix-2.rs:19:12
+ |
+LL | while i++ < 5 {
+ | ----- ^^ not a valid postfix operator
+ | |
+ | while parsing the condition of this `while` expression
+ |
+help: use `+= 1` instead
+ |
+LL | while { let tmp = i; i += 1; tmp } < 5 {
+ | +++++++++++ ~~~~~~~~~~~~~~~
+
+error: Rust has no postfix increment operator
+ --> $DIR/increment-autofix-2.rs:27:8
+ |
+LL | tmp++;
+ | ^^ not a valid postfix operator
+ |
+help: use `+= 1` instead
+ |
+LL | tmp += 1;
+ | ~~~~
+
+error: Rust has no postfix increment operator
+ --> $DIR/increment-autofix-2.rs:33:14
+ |
+LL | while tmp++ < 5 {
+ | ----- ^^ not a valid postfix operator
+ | |
+ | while parsing the condition of this `while` expression
+ |
+help: use `+= 1` instead
+ |
+LL | while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 {
+ | ++++++++++++ ~~~~~~~~~~~~~~~~~~
+
+error: Rust has no postfix increment operator
+ --> $DIR/increment-autofix-2.rs:41:16
+ |
+LL | foo.bar.qux++;
+ | ^^ not a valid postfix operator
+ |
+help: use `+= 1` instead
+ |
+LL | foo.bar.qux += 1;
+ | ~~~~
+
+error: Rust has no postfix increment operator
+ --> $DIR/increment-autofix-2.rs:51:10
+ |
+LL | s.tmp++;
+ | ^^ not a valid postfix operator
+ |
+help: use `+= 1` instead
+ |
+LL | s.tmp += 1;
+ | ~~~~
+
+error: Rust has no prefix increment operator
+ --> $DIR/increment-autofix-2.rs:58:5
+ |
+LL | ++foo.bar.qux;
+ | ^^ not a valid prefix operator
+ |
+help: use `+= 1` instead
+ |
+LL - ++foo.bar.qux;
+LL + foo.bar.qux += 1;
+ |
+
+error: aborting due to 7 previous errors
+
+++ /dev/null
-struct Foo {
- bar: Bar,
-}
-
-struct Bar {
- qux: i32,
-}
-
-pub fn post_regular() {
- let mut i = 0;
- i++; //~ ERROR Rust has no postfix increment operator
- println!("{}", i);
-}
-
-pub fn post_while() {
- let mut i = 0;
- while i++ < 5 {
- //~^ ERROR Rust has no postfix increment operator
- println!("{}", i);
- }
-}
-
-pub fn post_regular_tmp() {
- let mut tmp = 0;
- tmp++; //~ ERROR Rust has no postfix increment operator
- println!("{}", tmp);
-}
-
-pub fn post_while_tmp() {
- let mut tmp = 0;
- while tmp++ < 5 {
- //~^ ERROR Rust has no postfix increment operator
- println!("{}", tmp);
- }
-}
-
-pub fn post_field() {
- let foo = Foo { bar: Bar { qux: 0 } };
- foo.bar.qux++;
- //~^ ERROR Rust has no postfix increment operator
- println!("{}", foo.bar.qux);
-}
-
-pub fn post_field_tmp() {
- struct S {
- tmp: i32
- }
- let s = S { tmp: 0 };
- s.tmp++;
- //~^ ERROR Rust has no postfix increment operator
- println!("{}", s.tmp);
-}
-
-pub fn pre_field() {
- let foo = Foo { bar: Bar { qux: 0 } };
- ++foo.bar.qux;
- //~^ ERROR Rust has no prefix increment operator
- println!("{}", foo.bar.qux);
-}
-
-fn main() {}
+++ /dev/null
-error: Rust has no postfix increment operator
- --> $DIR/increment-notfixed.rs:11:6
- |
-LL | i++;
- | ^^ not a valid postfix operator
- |
-help: use `+= 1` instead
- |
-LL | { let tmp = i; i += 1; tmp };
- | +++++++++++ ~~~~~~~~~~~~~~~
-LL | i += 1;
- | ~~~~
-
-error: Rust has no postfix increment operator
- --> $DIR/increment-notfixed.rs:17:12
- |
-LL | while i++ < 5 {
- | ----- ^^ not a valid postfix operator
- | |
- | while parsing the condition of this `while` expression
- |
-help: use `+= 1` instead
- |
-LL | while { let tmp = i; i += 1; tmp } < 5 {
- | +++++++++++ ~~~~~~~~~~~~~~~
-LL | while i += 1 < 5 {
- | ~~~~
-
-error: Rust has no postfix increment operator
- --> $DIR/increment-notfixed.rs:25:8
- |
-LL | tmp++;
- | ^^ not a valid postfix operator
- |
-help: use `+= 1` instead
- |
-LL | { let tmp_ = tmp; tmp += 1; tmp_ };
- | ++++++++++++ ~~~~~~~~~~~~~~~~~~
-LL | tmp += 1;
- | ~~~~
-
-error: Rust has no postfix increment operator
- --> $DIR/increment-notfixed.rs:31:14
- |
-LL | while tmp++ < 5 {
- | ----- ^^ not a valid postfix operator
- | |
- | while parsing the condition of this `while` expression
- |
-help: use `+= 1` instead
- |
-LL | while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 {
- | ++++++++++++ ~~~~~~~~~~~~~~~~~~
-LL | while tmp += 1 < 5 {
- | ~~~~
-
-error: Rust has no postfix increment operator
- --> $DIR/increment-notfixed.rs:39:16
- |
-LL | foo.bar.qux++;
- | ^^ not a valid postfix operator
- |
-help: use `+= 1` instead
- |
-LL | { let tmp = foo.bar.qux; foo.bar.qux += 1; tmp };
- | +++++++++++ ~~~~~~~~~~~~~~~~~~~~~~~~~
-LL | foo.bar.qux += 1;
- | ~~~~
-
-error: Rust has no postfix increment operator
- --> $DIR/increment-notfixed.rs:49:10
- |
-LL | s.tmp++;
- | ^^ not a valid postfix operator
- |
-help: use `+= 1` instead
- |
-LL | { let tmp = s.tmp; s.tmp += 1; tmp };
- | +++++++++++ ~~~~~~~~~~~~~~~~~~~
-LL | s.tmp += 1;
- | ~~~~
-
-error: Rust has no prefix increment operator
- --> $DIR/increment-notfixed.rs:56:5
- |
-LL | ++foo.bar.qux;
- | ^^ not a valid prefix operator
- |
-help: use `+= 1` instead
- |
-LL - ++foo.bar.qux;
-LL + foo.bar.qux += 1;
- |
-
-error: aborting due to 7 previous errors
-
--- /dev/null
+fn test1() {
+ let mut i = 0;
+ let _ = i + ++i; //~ ERROR Rust has no prefix increment operator
+}
+
+fn test2() {
+ let mut i = 0;
+ let _ = ++i + i; //~ ERROR Rust has no prefix increment operator
+}
+
+fn test3() {
+ let mut i = 0;
+ let _ = ++i + ++i; //~ ERROR Rust has no prefix increment operator
+}
+
+fn test4() {
+ let mut i = 0;
+ let _ = i + i++; //~ ERROR Rust has no postfix increment operator
+ // won't suggest since we can not handle the precedences
+}
+
+fn test5() {
+ let mut i = 0;
+ let _ = i++ + i; //~ ERROR Rust has no postfix increment operator
+}
+
+fn test6() {
+ let mut i = 0;
+ let _ = i++ + i++; //~ ERROR Rust has no postfix increment operator
+}
+
+fn test7() {
+ let mut i = 0;
+ let _ = ++i + i++; //~ ERROR Rust has no prefix increment operator
+}
+
+fn test8() {
+ let mut i = 0;
+ let _ = i++ + ++i; //~ ERROR Rust has no postfix increment operator
+}
+
+fn test9() {
+ let mut i = 0;
+ let _ = (1 + 2 + i)++; //~ ERROR Rust has no postfix increment operator
+}
+
+fn test10() {
+ let mut i = 0;
+ let _ = (i++ + 1) + 2; //~ ERROR Rust has no postfix increment operator
+}
+
+fn main() { }
--- /dev/null
+error: Rust has no prefix increment operator
+ --> $DIR/issue-104867-inc-dec-2.rs:3:17
+ |
+LL | let _ = i + ++i;
+ | ^^ not a valid prefix operator
+ |
+help: use `+= 1` instead
+ |
+LL | let _ = i + { i += 1; i };
+ | ~ +++++++++
+
+error: Rust has no prefix increment operator
+ --> $DIR/issue-104867-inc-dec-2.rs:8:13
+ |
+LL | let _ = ++i + i;
+ | ^^ not a valid prefix operator
+ |
+help: use `+= 1` instead
+ |
+LL | let _ = { i += 1; i } + i;
+ | ~ +++++++++
+
+error: Rust has no prefix increment operator
+ --> $DIR/issue-104867-inc-dec-2.rs:13:13
+ |
+LL | let _ = ++i + ++i;
+ | ^^ not a valid prefix operator
+ |
+help: use `+= 1` instead
+ |
+LL | let _ = { i += 1; i } + ++i;
+ | ~ +++++++++
+
+error: Rust has no postfix increment operator
+ --> $DIR/issue-104867-inc-dec-2.rs:18:18
+ |
+LL | let _ = i + i++;
+ | ^^ not a valid postfix operator
+
+error: Rust has no postfix increment operator
+ --> $DIR/issue-104867-inc-dec-2.rs:24:14
+ |
+LL | let _ = i++ + i;
+ | ^^ not a valid postfix operator
+ |
+help: use `+= 1` instead
+ |
+LL | let _ = { let tmp = i; i += 1; tmp } + i;
+ | +++++++++++ ~~~~~~~~~~~~~~~
+
+error: Rust has no postfix increment operator
+ --> $DIR/issue-104867-inc-dec-2.rs:29:14
+ |
+LL | let _ = i++ + i++;
+ | ^^ not a valid postfix operator
+ |
+help: use `+= 1` instead
+ |
+LL | let _ = { let tmp = i; i += 1; tmp } + i++;
+ | +++++++++++ ~~~~~~~~~~~~~~~
+
+error: Rust has no prefix increment operator
+ --> $DIR/issue-104867-inc-dec-2.rs:34:13
+ |
+LL | let _ = ++i + i++;
+ | ^^ not a valid prefix operator
+ |
+help: use `+= 1` instead
+ |
+LL | let _ = { i += 1; i } + i++;
+ | ~ +++++++++
+
+error: Rust has no postfix increment operator
+ --> $DIR/issue-104867-inc-dec-2.rs:39:14
+ |
+LL | let _ = i++ + ++i;
+ | ^^ not a valid postfix operator
+ |
+help: use `+= 1` instead
+ |
+LL | let _ = { let tmp = i; i += 1; tmp } + ++i;
+ | +++++++++++ ~~~~~~~~~~~~~~~
+
+error: Rust has no postfix increment operator
+ --> $DIR/issue-104867-inc-dec-2.rs:44:24
+ |
+LL | let _ = (1 + 2 + i)++;
+ | ^^ not a valid postfix operator
+ |
+help: use `+= 1` instead
+ |
+LL | let _ = { let tmp = (1 + 2 + i); (1 + 2 + i) += 1; tmp };
+ | +++++++++++ ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: Rust has no postfix increment operator
+ --> $DIR/issue-104867-inc-dec-2.rs:49:15
+ |
+LL | let _ = (i++ + 1) + 2;
+ | ^^ not a valid postfix operator
+ |
+help: use `+= 1` instead
+ |
+LL | let _ = ({ let tmp = i; i += 1; tmp } + 1) + 2;
+ | +++++++++++ ~~~~~~~~~~~~~~~
+
+error: aborting due to 10 previous errors
+
--- /dev/null
+struct S {
+ x: i32,
+}
+
+fn test1() {
+ let mut i = 0;
+ i++; //~ ERROR Rust has no postfix increment operator
+}
+
+fn test2() {
+ let s = S { x: 0 };
+ s.x++; //~ ERROR Rust has no postfix increment operator
+}
+
+fn test3() {
+ let mut i = 0;
+ if i++ == 1 {} //~ ERROR Rust has no postfix increment operator
+}
+
+fn test4() {
+ let mut i = 0;
+ ++i; //~ ERROR Rust has no prefix increment operator
+}
+
+fn test5() {
+ let mut i = 0;
+ if ++i == 1 { } //~ ERROR Rust has no prefix increment operator
+}
+
+fn test6() {
+ let mut i = 0;
+ loop { break; }
+ i++; //~ ERROR Rust has no postfix increment operator
+ loop { break; }
+ ++i;
+}
+
+fn test7() {
+ let mut i = 0;
+ loop { break; }
+ ++i; //~ ERROR Rust has no prefix increment operator
+}
+
+
+fn main() {}
--- /dev/null
+error: Rust has no postfix increment operator
+ --> $DIR/issue-104867-inc-dec.rs:7:6
+ |
+LL | i++;
+ | ^^ not a valid postfix operator
+ |
+help: use `+= 1` instead
+ |
+LL | i += 1;
+ | ~~~~
+
+error: Rust has no postfix increment operator
+ --> $DIR/issue-104867-inc-dec.rs:12:8
+ |
+LL | s.x++;
+ | ^^ not a valid postfix operator
+ |
+help: use `+= 1` instead
+ |
+LL | s.x += 1;
+ | ~~~~
+
+error: Rust has no postfix increment operator
+ --> $DIR/issue-104867-inc-dec.rs:17:9
+ |
+LL | if i++ == 1 {}
+ | ^^ not a valid postfix operator
+ |
+help: use `+= 1` instead
+ |
+LL | if { let tmp = i; i += 1; tmp } == 1 {}
+ | +++++++++++ ~~~~~~~~~~~~~~~
+
+error: Rust has no prefix increment operator
+ --> $DIR/issue-104867-inc-dec.rs:22:5
+ |
+LL | ++i;
+ | ^^ not a valid prefix operator
+ |
+help: use `+= 1` instead
+ |
+LL - ++i;
+LL + i += 1;
+ |
+
+error: Rust has no prefix increment operator
+ --> $DIR/issue-104867-inc-dec.rs:27:8
+ |
+LL | if ++i == 1 { }
+ | ^^ not a valid prefix operator
+ |
+help: use `+= 1` instead
+ |
+LL | if { i += 1; i } == 1 { }
+ | ~ +++++++++
+
+error: Rust has no postfix increment operator
+ --> $DIR/issue-104867-inc-dec.rs:33:6
+ |
+LL | i++;
+ | ^^ not a valid postfix operator
+ |
+help: use `+= 1` instead
+ |
+LL | i += 1;
+ | ~~~~
+
+error: Rust has no prefix increment operator
+ --> $DIR/issue-104867-inc-dec.rs:41:5
+ |
+LL | ++i;
+ | ^^ not a valid prefix operator
+ |
+help: use `+= 1` instead
+ |
+LL - ++i;
+LL + i += 1;
+ |
+
+error: aborting due to 7 previous errors
+
--- /dev/null
+// run-rustfix
+
+struct Foo;
+
+impl From<i32> for Foo {
+ //~^ ERROR you might have meant to write `impl` instead of `fn`
+ fn from(_a: i32) -> Self {
+ Foo
+ }
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+
+struct Foo;
+
+fn From<i32> for Foo {
+ //~^ ERROR you might have meant to write `impl` instead of `fn`
+ fn from(_a: i32) -> Self {
+ Foo
+ }
+}
+
+fn main() {}
--- /dev/null
+error: you might have meant to write `impl` instead of `fn`
+ --> $DIR/issue-105366.rs:5:1
+ |
+LL | fn From<i32> for Foo {
+ | ^^
+ |
+help: replace `fn` with `impl` here
+ |
+LL | impl From<i32> for Foo {
+ | ~~~~
+
+error: aborting due to previous error
+
LL |
LL | fn main() {}
| ^^ unexpected token
+ --> $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
- ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- |
-LL | ($left:expr, $right:expr $(,)?) => {
- | ---------- while parsing argument for this `expr` macro fragment
+ = note: while parsing argument for this `expr` macro fragment
error: aborting due to 4 previous errors
|
LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
| ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
+ --> $SRC_DIR/core/src/ops/function.rs:LL:COL
|
- ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
- | -------------------------------------- similarly named trait `Fn` defined here
+ = note: similarly named trait `Fn` defined here
error[E0405]: cannot find trait `r#fn` in this scope
--> $DIR/kw-in-trait-bounds.rs:17:4
|
LL | G: fn(),
| ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
+ --> $SRC_DIR/core/src/ops/function.rs:LL:COL
|
- ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
- | -------------------------------------- similarly named trait `Fn` defined here
+ = note: similarly named trait `Fn` defined here
error[E0405]: cannot find trait `r#fn` in this scope
--> $DIR/kw-in-trait-bounds.rs:3:27
|
LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
| ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
+ --> $SRC_DIR/core/src/ops/function.rs:LL:COL
|
- ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
- | -------------------------------------- similarly named trait `Fn` defined here
+ = note: similarly named trait `Fn` defined here
error[E0405]: cannot find trait `r#fn` in this scope
--> $DIR/kw-in-trait-bounds.rs:3:41
|
LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
| ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
+ --> $SRC_DIR/core/src/ops/function.rs:LL:COL
|
- ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
- | -------------------------------------- similarly named trait `Fn` defined here
+ = note: similarly named trait `Fn` defined here
error[E0405]: cannot find trait `r#struct` in this scope
--> $DIR/kw-in-trait-bounds.rs:24:10
--- /dev/null
+// run-rustfix
+#![allow(unused_variables)]
+fn main() {
+ struct U;
+
+ // A tuple is a "non-reference pattern".
+ // A `mut` binding pattern resets the binding mode to by-value.
+
+ let mut p = (U, U);
+ let (a, ref mut b) = &mut p;
+ //~^ ERROR cannot move out of a mutable reference
+}
--- /dev/null
+// run-rustfix
+#![allow(unused_variables)]
+fn main() {
+ struct U;
+
+ // A tuple is a "non-reference pattern".
+ // A `mut` binding pattern resets the binding mode to by-value.
+
+ let mut p = (U, U);
+ let (a, mut b) = &mut p;
+ //~^ ERROR cannot move out of a mutable reference
+}
--- /dev/null
+error[E0507]: cannot move out of a mutable reference
+ --> $DIR/move-ref-patterns-default-binding-modes-fixable.rs:10:22
+ |
+LL | let (a, mut b) = &mut p;
+ | ----- ^^^^^^
+ | |
+ | data moved here
+ | move occurs because `b` has type `U`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | let (a, ref mut b) = &mut p;
+ | +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
let p = (U, U);
let (a, mut b) = &p;
//~^ ERROR cannot move out of a shared reference
-
- let mut p = (U, U);
- let (a, mut b) = &mut p;
- //~^ ERROR cannot move out of a mutable reference
}
| |
| data moved here
| move occurs because `b` has type `U`, which does not implement the `Copy` trait
-
-error[E0507]: cannot move out of a mutable reference
- --> $DIR/move-ref-patterns-default-binding-modes.rs:12:22
|
-LL | let (a, mut b) = &mut p;
- | ----- ^^^^^^
- | |
- | data moved here
- | move occurs because `b` has type `U`, which does not implement the `Copy` trait
+help: consider borrowing the pattern binding
+ |
+LL | let (a, ref mut b) = &p;
+ | +++
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0507`.
|
help: consider giving `x` an explicit type
|
-LL | let x: _;
- | +++
+LL | let x: /* Type */;
+ | ++++++++++++
error[E0308]: mismatched types
--> $DIR/pat-tuple-bad-type.rs:10:9
|
help: consider giving this pattern a type
|
-LL | let x @ ..: _;
- | +++
+LL | let x @ ..: /* Type */;
+ | ++++++++++++
error: aborting due to 23 previous errors
|
note: `Option<i32>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub enum Option<T> {
- | ------------------
-...
-LL | None,
- | ^^^^ not covered
+ = note: not covered
= note: the matched value is of type `Option<i32>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
|
note: `Option<HiddenEnum>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub enum Option<T> {
- | ------------------
-...
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^ not covered
+ = note: not covered
= note: the matched value is of type `Option<HiddenEnum>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
|
|
note: `Option<Enum>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | pub enum Option<T> {
- | ^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `Option<Enum>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
|
|
note: `Box<ElementKind>` defined here
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
- |
-LL | / pub struct Box<
-LL | | T: ?Sized,
-LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
-LL | | >(Unique<T>, A);
- | |_^
= note: the matched value is of type `Box<ElementKind>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
|
note: `Option<Option<Direction>>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub enum Option<T> {
- | ------------------
-...
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^
- | |
- | not covered
- | not covered
+ = note: not covered
+ |
+ = note: not covered
= note: the matched value is of type `Option<Option<Direction>>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
|
note: `Option<Private>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub enum Option<T> {
- | ------------------
-...
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^ not covered
+ = note: not covered
= note: the matched value is of type `Option<Private>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
|
note: `Option<i32>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub enum Option<T> {
- | ------------------
-...
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^ not covered
+ = note: not covered
= note: the matched value is of type `Option<i32>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type lib
// edition:2021
// build-pass
// ignore-pass
-#![feature(start)]
-
async fn wait() {}
-async fn test(arg: [u8; 8192]) {
+pub async fn test(arg: [u8; 8192]) {
wait().await;
drop(arg);
}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
- let _ = test([0; 8192]);
- 0
-}
-print-type-size type: `[async fn body@$DIR/async.rs:10:32: 13:2]`: 16386 bytes, alignment: 1 bytes
+print-type-size type: `[async fn body@$DIR/async.rs:8:36: 11:2]`: 16386 bytes, alignment: 1 bytes
print-type-size discriminant: 1 bytes
print-type-size variant `Suspend0`: 16385 bytes
print-type-size field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
print-type-size variant `MaybeUninit`: 8192 bytes
print-type-size field `.uninit`: 0 bytes
print-type-size field `.value`: 8192 bytes
-print-type-size type: `[async fn body@$DIR/async.rs:8:17: 8:19]`: 1 bytes, alignment: 1 bytes
+print-type-size type: `[async fn body@$DIR/async.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<[async fn body@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async.rs:6:17: 6:19]>`: 1 bytes, alignment: 1 bytes
print-type-size field `.value`: 1 bytes
-print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async.rs:6:17: 6:19]>`: 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
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
-#![feature(start, generators, generator_trait)]
+#![feature(generators, generator_trait)]
use std::ops::Generator;
}
}
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn foo() {
let _ = generator([0; 8192]);
- 0
}
--- /dev/null
+// compile-flags: -Z print-type-sizes --crate-type lib
+// build-pass
+// ignore-pass
+
+// Tests a generator that has its discriminant as the *final* field.
+
+// Avoid emitting panic handlers, like the rest of these tests...
+#![feature(generators)]
+
+pub fn foo() {
+ let a = || {
+ {
+ let w: i32 = 4;
+ yield;
+ drop(w);
+ }
+ {
+ let z: i32 = 7;
+ yield;
+ drop(z);
+ }
+ };
+}
--- /dev/null
+print-type-size type: `[generator@$DIR/generator_discr_placement.rs:11:13: 11:15]`: 8 bytes, alignment: 4 bytes
+print-type-size discriminant: 1 bytes
+print-type-size variant `Suspend0`: 7 bytes
+print-type-size padding: 3 bytes
+print-type-size field `.w`: 4 bytes, alignment: 4 bytes
+print-type-size variant `Suspend1`: 7 bytes
+print-type-size padding: 3 bytes
+print-type-size field `.z`: 4 bytes, alignment: 4 bytes
+print-type-size variant `Unresumed`: 0 bytes
+print-type-size variant `Returned`: 0 bytes
+print-type-size variant `Panicked`: 0 bytes
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
// ^-- needed because `--pass check` does not emit the output needed.
// monomorphized, in the MIR of the original function in which they
// occur, to have their size reported.
-#![feature(start)]
-
-// In an ad-hoc attempt to avoid the injection of unwinding code
-// (which clutters the output of `-Z print-type-sizes` with types from
-// `unwind::libunwind`):
-//
-// * I am not using Default to build values because that seems to
-// cause the injection of unwinding code. (Instead I just make `fn new`
-// methods.)
-//
-// * Pair derive Copy to ensure that we don't inject
-// unwinding code into generic uses of Pair when T itself is also
-// Copy.
-//
-// (I suspect this reflect some naivety within the rust compiler
-// itself; it should be checking for drop glue, i.e., a destructor
-// somewhere in the monomorphized types. It should not matter whether
-// the type is Copy.)
#[derive(Copy, Clone)]
pub struct Pair<T> {
_car: T,
Pair::new(FiftyBytes::new(), FiftyBytes::new());
}
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn start() {
let _b: Pair<u8> = Pair::new(0, 0);
let _s: Pair<SevenBytes> = Pair::new(SevenBytes::new(), SevenBytes::new());
let ref _z: ZeroSized = ZeroSized;
f1::<SevenBytes>(SevenBytes::new());
- 0
}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// This file illustrates that when multiple structural types occur in
// a function, every one of them is included in the output.
-#![feature(start)]
-
pub struct SevenBytes([u8; 7]);
pub struct FiftyBytes([u8; 50]);
Small(SevenBytes),
Large(FiftyBytes),
}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
- let _e: Enum;
- let _f: FiftyBytes;
- let _s: SevenBytes;
- 0
-}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
// ^-- needed because `--pass check` does not emit the output needed.
// aligned (while on most it is 8-byte aligned) and so the resulting
// padding and overall computed sizes can be quite different.
-#![feature(start)]
#![feature(rustc_attrs)]
#![allow(dead_code)]
impl Default for NestedNonZero {
fn default() -> Self {
- NestedNonZero { pre: 0, val: NonZeroU32::new(1).unwrap(), post: 0 }
+ NestedNonZero { pre: 0, val: unsafe { NonZeroU32::new_unchecked(1) }, post: 0 }
}
}
b: B,
}
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn test() {
let _x: MyOption<NonZeroU32> = Default::default();
let _y: EmbeddedDiscr = Default::default();
let _z: MyOption<IndirectNonZero> = Default::default();
// ...even when theoretically possible.
let _j: MyOption<Union1<NonZeroU32>> = Default::default();
let _k: MyOption<Union2<NonZeroU32, NonZeroU32>> = Default::default();
-
- 0
}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
// ^-- needed because `--pass check` does not emit the output needed.
// (even if multiple functions), it is only printed once in the
// print-type-sizes output.
-#![feature(start)]
-
pub struct SevenBytes([u8; 7]);
pub fn f1() {
let _s: SevenBytes = SevenBytes([0; 7]);
}
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn test() {
let _s: SevenBytes = SevenBytes([0; 7]);
- 0
}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
// ^-- needed because `--pass check` does not emit the output needed.
// padding and overall computed sizes can be quite different.
#![allow(dead_code)]
-#![feature(start)]
#[derive(Default)]
#[repr(packed)]
-struct Packed1 {
+pub struct Packed1 {
a: u8,
b: u8,
g: i32,
#[derive(Default)]
#[repr(packed(2))]
-struct Packed2 {
+pub struct Packed2 {
a: u8,
b: u8,
g: i32,
#[derive(Default)]
#[repr(packed(2))]
#[repr(C)]
-struct Packed2C {
+pub struct Packed2C {
a: u8,
b: u8,
g: i32,
}
#[derive(Default)]
-struct Padded {
+pub struct Padded {
a: u8,
b: u8,
g: i32,
h: i16,
d: u8,
}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
- let _c: Packed1 = Default::default();
- let _d: Packed2 = Default::default();
- let _e: Packed2C = Default::default();
- let _f: Padded = Default::default();
- 0
-}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// This file illustrates how padding is handled: alignment
// aligned (while on most it is 8-byte aligned) and so the resulting
// padding and overall computed sizes can be quite different.
-#![feature(start)]
#![allow(dead_code)]
struct S {
A(i8, i32),
B(S),
}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
- 0
-}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
// ^-- needed because `--pass check` does not emit the output needed.
// It avoids using u64/i64 because on some targets that is only 4-byte
// aligned (while on most it is 8-byte aligned) and so the resulting
// padding and overall computed sizes can be quite different.
-#![feature(start)]
+
#![allow(dead_code)]
#[repr(align(16))]
}
#[derive(Default)]
-struct S {
+pub struct S {
a: i32,
b: i32,
c: A,
d: i8,
}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
- let _s: S = Default::default();
- 0
-}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// This test makes sure that the tag is not grown for `repr(C)` or `repr(u8)`
// variants (see https://github.com/rust-lang/rust/issues/50098 for the original bug).
-#![feature(start)]
#![allow(dead_code)]
#[repr(C, u8)]
A(u16),
B,
}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
- 0
-}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
// ^-- needed because `--pass check` does not emit the output needed.
// FIXME: consider using an attribute instead of side-effects.
#![feature(never_type)]
-#![feature(start)]
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn test() {
let _x: Option<!> = None;
let _y: Result<u32, !> = Ok(42);
let _z: Result<!, !> = loop {};
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// This file illustrates two things:
// 2. For an enum, the print-type-sizes output will also include the
// size of each variant.
-#![feature(start)]
-
pub struct SevenBytes([u8; 7]);
pub struct FiftyBytes([u8; 50]);
Small(SevenBytes),
Large(FiftyBytes),
}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
- let _e: Enum;
- 0
-}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
// At one point, zero-sized fields such as those in this file were causing
// incorrect output from `-Z print-type-sizes`.
-#![feature(start)]
-
struct S1 {
x: u32,
y: u32,
tagz: TagZ,
}
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn test() {
let _s1: S1 = S1 { x: 0, y: 0, tag: () };
let _s5: S5<(), Empty> = S5 {
z: 4,
tagz: Empty {},
};
- 0
}
Pub.method();
//~^ ERROR type `for<'a> fn(&'a Self) {<Self as PrivTr>::method}` is private
<Pub as PrivTr>::CONST;
- //~^ ERROR associated constant `<Pub as PrivTr>::CONST` is private
+ //~^ ERROR associated constant `PrivTr::CONST` is private
let _: <Pub as PrivTr>::AssocTy;
- //~^ ERROR associated type `<Pub as PrivTr>::AssocTy` is private
+ //~^ ERROR associated type `PrivTr::AssocTy` is private
pub type InSignatureTy = <Pub as PrivTr>::AssocTy;
//~^ ERROR trait `PrivTr` is private
pub trait InSignatureTr: PrivTr {}
|
= note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: associated constant `<Pub as PrivTr>::CONST` is private
+error: associated constant `PrivTr::CONST` is private
--> $DIR/associated-item-privacy-trait.rs:21:9
|
LL | <Pub as PrivTr>::CONST;
|
= note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: associated type `<Pub as PrivTr>::AssocTy` is private
+error: associated type `PrivTr::AssocTy` is private
--> $DIR/associated-item-privacy-trait.rs:23:16
|
LL | let _: <Pub as PrivTr>::AssocTy;
// aux-build:private-inferred-type.rs
// error-pattern:type `fn() {ext::priv_fn}` is private
-// error-pattern:static `PRIV_STATIC` is private
+// error-pattern:static `ext::PRIV_STATIC` is private
// error-pattern:type `ext::PrivEnum` is private
// error-pattern:type `fn() {<u8 as ext::PrivTrait>::method}` is private
// error-pattern:type `fn(u8) -> ext::PrivTupleStruct {ext::PrivTupleStruct}` is private
|
= note: this error originates in the macro `ext::m` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: static `PRIV_STATIC` is private
+error: static `ext::PRIV_STATIC` is private
--> $DIR/private-inferred-type-3.rs:16:5
|
LL | ext::m!();
= help: the trait `PartialEq` is not implemented for `PriorityQueue<T>`
note: required by a bound in `PartialOrd`
--> $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
- | ^^^^^^^^^^^^^^ required by this bound in `PartialOrd`
= note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `PriorityQueue<T>: Eq` is not satisfied
|
note: required by a bound in `Ord`
--> $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub trait Ord: Eq + PartialOrd<Self> {
- | ^^ required by this bound in `Ord`
= note: this error originates in the derive macro `AddImpl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: can't compare `T` with `T`
| ^^^^^^^^^^
note: required by a bound in `Ord`
--> $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub trait Ord: Eq + PartialOrd<Self> {
- | ^^^^^^^^^^^^^^^^ required by this bound in `Ord`
= note: this error originates in the derive macro `AddImpl` which comes from the expansion of the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 3 previous errors
...
LL | one!("hello", "world");
| ---------------------- in this macro invocation
+ --> $SRC_DIR/core/src/result.rs:LL:COL
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
- | -- similarly named tuple variant `Ok` defined here
+ = note: similarly named tuple variant `Ok` defined here
|
= note: this error originates in the macro `parent_source_spans` which comes from the expansion of the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info)
...
LL | two!("yay", "rust");
| ------------------- in this macro invocation
+ --> $SRC_DIR/core/src/result.rs:LL:COL
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
- | -- similarly named tuple variant `Ok` defined here
+ = note: similarly named tuple variant `Ok` defined here
|
= note: this error originates in the macro `parent_source_spans` which comes from the expansion of the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info)
...
LL | three!("hip", "hop");
| -------------------- in this macro invocation
+ --> $SRC_DIR/core/src/result.rs:LL:COL
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
- | -- similarly named tuple variant `Ok` defined here
+ = note: similarly named tuple variant `Ok` defined here
|
= note: this error originates in the macro `parent_source_spans` which comes from the expansion of the macro `three` (in Nightly builds, run with -Z macro-backtrace for more info)
|
LL | #[derive(Dlone)]
| ^^^^^ help: a derive macro with a similar name exists: `Clone`
+ --> $SRC_DIR/core/src/clone.rs:LL:COL
|
- ::: $SRC_DIR/core/src/clone.rs:LL:COL
- |
-LL | pub macro Clone($item:item) {
- | --------------- similarly named derive macro `Clone` defined here
+ = note: similarly named derive macro `Clone` defined here
error: cannot find derive macro `Dlone` in this scope
--> $DIR/resolve-error.rs:35:10
|
LL | #[derive(Dlone)]
| ^^^^^ help: a derive macro with a similar name exists: `Clone`
+ --> $SRC_DIR/core/src/clone.rs:LL:COL
|
- ::: $SRC_DIR/core/src/clone.rs:LL:COL
- |
-LL | pub macro Clone($item:item) {
- | --------------- similarly named derive macro `Clone` defined here
+ = note: similarly named derive macro `Clone` defined here
error: cannot find attribute `FooWithLongNan` in this scope
--> $DIR/resolve-error.rs:32:3
= note: unsafe function cannot be called generically without an unsafe block
note: required by a bound in `ProcMacro::custom_derive`
--> $SRC_DIR/proc_macro/src/bridge/client.rs:LL:COL
- |
-LL | expand: impl Fn(crate::TokenStream) -> crate::TokenStream + Copy,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `ProcMacro::custom_derive`
error: aborting due to previous error
// ignore-pretty
// aux-build:span-api-tests.rs
// aux-build:span-test-macros.rs
+// compile-flags: -Ztranslate-remapped-path-to-local-path=yes
#[macro_use]
extern crate span_test_macros;
= help: the trait `Sized` is not implemented for `[{integer}]`
note: required by a bound in `RangeFrom`
--> $SRC_DIR/core/src/ops/range.rs:LL:COL
- |
-LL | pub struct RangeFrom<Idx> {
- | ^^^ required by this bound in `RangeFrom`
error: aborting due to 3 previous errors
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Result<u32, &R<'_>>` defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
+ ::: $SRC_DIR/core/src/result.rs:LL:COL
|
-LL | pub enum Result<T, E> {
- | ---------------------
-...
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | ^^^ not covered
+ = note: not covered
= note: the matched value is of type `Result<u32, &R<'_>>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
--- /dev/null
+fn main() {
+ let foo = 1;
+ {
+ let bar = 2;
+ let test_func = |x| x > 3;
+ }
+ if bar == 2 { //~ ERROR cannot find value
+ println!("yes");
+ }
+ test_func(1); //~ ERROR cannot find function
+}
--- /dev/null
+error[E0425]: cannot find value `bar` in this scope
+ --> $DIR/issue-104700-inner_scope.rs:7:8
+ |
+LL | if bar == 2 {
+ | ^^^
+ |
+help: the binding `bar` is available in a different scope in the same function
+ --> $DIR/issue-104700-inner_scope.rs:4:13
+ |
+LL | let bar = 2;
+ | ^^^
+
+error[E0425]: cannot find function `test_func` in this scope
+ --> $DIR/issue-104700-inner_scope.rs:10:5
+ |
+LL | test_func(1);
+ | ^^^^^^^^^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
|
help: consider giving `N` an explicit type
|
-LL | let mut N: _;
- | +++
+LL | let mut N: /* Type */;
+ | ++++++++++++
error: aborting due to 3 previous errors
|
LL | type B = Opiton<u8>; // Misspelled type name from the prelude.
| ^^^^^^ help: an enum with a similar name exists: `Option`
+ --> $SRC_DIR/core/src/option.rs:LL:COL
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | pub enum Option<T> {
- | ------------------ similarly named enum `Option` defined here
+ = note: similarly named enum `Option` defined here
error[E0412]: cannot find type `Baz` in this scope
--> $DIR/levenshtein.rs:16:14
|
note: function defined here
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | pub const fn size_of<T>() -> usize {
- | ^^^^^^^
help: remove the extra argument
|
LL | std::mem::size_of();
= note: required for `Result<f32, ParseFloatError>` to implement `Termination`
note: required by a bound in `assert_test_result`
--> $SRC_DIR/test/src/lib.rs:LL:COL
- |
-LL | pub fn assert_test_result<T: Termination>(result: T) -> Result<(), String> {
- | ^^^^^^^^^^^ required by this bound in `assert_test_result`
= note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
| |
| data moved here
| move occurs because `m` has type `Foo`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | for (n, ref mut m) in &tups {
+ | +++
error: aborting due to previous error
LL | let _ = dbg!(a);
| ^ value used here after move
|
-help: borrow this binding in the pattern to avoid moving the value
- --> $SRC_DIR/std/src/macros.rs:LL:COL
- |
-LL | ref tmp => {
- | +++
error: aborting due to previous error
error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
- --> $DIR/const-default-method-bodies.rs:24:5
+ --> $DIR/const-default-method-bodies.rs:24:18
|
LL | NonConstImpl.a();
- | ^^^^^^^^^^^^ - required by a bound introduced by this call
- | |
- | the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl`
+ | ^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl`
|
note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that implementation is not `const`
--> $DIR/const-default-method-bodies.rs:24:5
error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
- --> $DIR/cross-crate.rs:17:5
+ --> $DIR/cross-crate.rs:17:14
|
LL | NonConst.func();
- | ^^^^^^^^ ---- required by a bound introduced by this call
- | |
- | the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
+ | ^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
|
note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const`
--> $DIR/cross-crate.rs:17:5
error[E0277]: the trait bound `cross_crate::NonConst: cross_crate::MyTrait` is not satisfied
- --> $DIR/cross-crate.rs:17:5
+ --> $DIR/cross-crate.rs:17:14
|
LL | NonConst.func();
- | ^^^^^^^^ ---- required by a bound introduced by this call
- | |
- | the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
+ | ^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
|
note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const`
--> $DIR/cross-crate.rs:17:5
error[E0277]: the trait bound `(): ~const Tr` is not satisfied
- --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:9
+ --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12
|
LL | ().a()
- | ^^ - required by a bound introduced by this call
- | |
- | the trait `~const Tr` is not implemented for `()`
+ | ^ the trait `~const Tr` is not implemented for `()`
|
note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
--> $DIR/default-method-body-is-const-same-trait-ck.rs:8:9
error[E0277]: the trait bound `T: ~const Foo` is not satisfied
- --> $DIR/super-traits-fail-2.rs:15:5
+ --> $DIR/super-traits-fail-2.rs:15:7
|
LL | x.a();
- | ^ - required by a bound introduced by this call
- | |
- | the trait `~const Foo` is not implemented for `T`
+ | ^ the trait `~const Foo` is not implemented for `T`
|
note: the trait `Foo` is implemented for `T`, but that implementation is not `const`
--> $DIR/super-traits-fail-2.rs:15:5
error[E0277]: the trait bound `T: ~const Foo` is not satisfied
- --> $DIR/super-traits-fail-2.rs:15:5
+ --> $DIR/super-traits-fail-2.rs:15:7
|
LL | x.a();
- | ^ - required by a bound introduced by this call
- | |
- | the trait `~const Foo` is not implemented for `T`
+ | ^ the trait `~const Foo` is not implemented for `T`
|
note: the trait `Foo` is implemented for `T`, but that implementation is not `const`
--> $DIR/super-traits-fail-2.rs:15:5
|
LL | enum World {
| ^^^^^^^^^^ must implement `Add<_>`
-note: the following trait must be implemented
+note: the trait `Add` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | pub trait Add<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: cannot add `String` to `&str`
--> $DIR/issue-39018.rs:11:22
-// compile-flags: -Z simulate-remapped-rust-src-base=/rustc/FAKE_PREFIX -Z translate-remapped-path-to-local-path=no -Z ui-testing=no
+// compile-flags: -Z ui-testing=no
struct MyError;
impl std::error::Error for MyError {}
|
help: consider giving `x` an explicit type
|
-LL | let mut x: _ = Default::default();
- | +++
+LL | let mut x: /* Type */ = Default::default();
+ | ++++++++++++
error[E0282]: type annotations needed
--> $DIR/method-and-field-eager-resolution.rs:11:9
|
help: consider giving `x` an explicit type
|
-LL | let mut x: _ = Default::default();
- | +++
+LL | let mut x: /* Type */ = Default::default();
+ | ++++++++++++
error: aborting due to 2 previous errors
|
note: tuple variant defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^
help: provide the argument
|
LL | let _: Result<(), String> = Ok(());
| ^^^^^^^^^^^^^^^^---^^^^^-
| |
| unsatisfied trait bound introduced here
-note: the following trait must be implemented
+note: the trait `Foo` must be implemented
--> $DIR/specialization-trait-not-implemented.rs:7:1
|
LL | trait Foo {
|
note: the module `thread_info` is defined here
--> $SRC_DIR/std/src/thread/mod.rs:LL:COL
- |
-LL | use crate::sys_common::thread_info;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
--> $DIR/std-uncopyable-atomics.rs:9:13
|
LL | let x = *&x;
- | ^^^
- | |
- | move occurs because value has type `std::sync::atomic::AtomicBool`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*&x`
+ | ^^^ move occurs because value has type `std::sync::atomic::AtomicBool`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let x = *&x;
+LL + let x = &x;
+ |
error[E0507]: cannot move out of a shared reference
--> $DIR/std-uncopyable-atomics.rs:11:13
|
LL | let x = *&x;
- | ^^^
- | |
- | move occurs because value has type `std::sync::atomic::AtomicIsize`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*&x`
+ | ^^^ move occurs because value has type `std::sync::atomic::AtomicIsize`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let x = *&x;
+LL + let x = &x;
+ |
error[E0507]: cannot move out of a shared reference
--> $DIR/std-uncopyable-atomics.rs:13:13
|
LL | let x = *&x;
- | ^^^
- | |
- | move occurs because value has type `std::sync::atomic::AtomicUsize`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*&x`
+ | ^^^ move occurs because value has type `std::sync::atomic::AtomicUsize`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let x = *&x;
+LL + let x = &x;
+ |
error[E0507]: cannot move out of a shared reference
--> $DIR/std-uncopyable-atomics.rs:15:13
|
LL | let x = *&x;
- | ^^^
- | |
- | move occurs because value has type `std::sync::atomic::AtomicPtr<usize>`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&*&x`
+ | ^^^ move occurs because value has type `std::sync::atomic::AtomicPtr<usize>`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let x = *&x;
+LL + let x = &x;
+ |
error: aborting due to 4 previous errors
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
note: required by a bound in `core::str::<impl str>::get`
--> $SRC_DIR/core/src/str/mod.rs:LL:COL
- |
-LL | pub const fn get<I: ~const SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
- | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get`
error[E0277]: the type `str` cannot be indexed by `{integer}`
--> $DIR/str-idx.rs:5:29
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
note: required by a bound in `core::str::<impl str>::get_unchecked`
--> $SRC_DIR/core/src/str/mod.rs:LL:COL
- |
-LL | pub const unsafe fn get_unchecked<I: ~const SliceIndex<str>>(&self, i: I) -> &I::Output {
- | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked`
error[E0277]: the type `str` cannot be indexed by `char`
--> $DIR/str-idx.rs:6:19
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
note: required by a bound in `core::str::<impl str>::get_mut`
--> $SRC_DIR/core/src/str/mod.rs:LL:COL
- |
-LL | pub const fn get_mut<I: ~const SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
- | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_mut`
error[E0277]: the type `str` cannot be indexed by `{integer}`
--> $DIR/str-mut-idx.rs:11:25
= help: the trait `SliceIndex<[T]>` is implemented for `usize`
note: required by a bound in `core::str::<impl str>::get_unchecked_mut`
--> $SRC_DIR/core/src/str/mod.rs:LL:COL
- |
-LL | pub const unsafe fn get_unchecked_mut<I: ~const SliceIndex<str>>(
- | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked_mut`
error[E0277]: the type `str` cannot be indexed by `char`
--> $DIR/str-mut-idx.rs:13:7
found type `{integer}`
note: tuple variant defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^
help: remove the extra argument
|
LL | let _: Option<(i32, bool)> = Some(/* (i32, bool) */);
|
note: tuple variant defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^
help: provide the argument
|
LL | let _: Option<(i8,)> = Some(/* (i8,) */);
found type `usize`
note: tuple variant defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^
error[E0308]: mismatched types
--> $DIR/args-instead-of-tuple-errors.rs:17:34
found type `usize`
note: tuple variant defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^
error: aborting due to 5 previous errors
|
note: tuple variant defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^
help: wrap these arguments in parentheses to construct a tuple
|
LL | let _: Result<(i32, i8), ()> = Ok((1, 2));
|
note: tuple variant defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^
help: wrap these arguments in parentheses to construct a tuple
|
LL | let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi"));
|
note: tuple variant defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^
help: provide the argument
|
LL | let _: Option<()> = Some(());
found type `{integer}`
note: tuple variant defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^
help: use a trailing comma to create a tuple with one element
|
LL | let _: Option<(i32,)> = Some((3,));
found type `{integer}`
note: tuple variant defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^
help: use a trailing comma to create a tuple with one element
|
LL | let _: Option<(i32,)> = Some((3,));
LL | let _y = foo;
| ^^^ value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `foo`
+note: `Option::<T>::map` takes ownership of the receiver `self`, which moves `foo`
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | pub const fn map<U, F>(self, f: F) -> Option<U>
- | ^^^^
error: aborting due to previous error
|
LL | #[tests]
| ^^^^^ help: an attribute macro with a similar name exists: `test`
+ --> $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
- ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- |
-LL | pub macro test($item:item) {
- | -------------- similarly named attribute macro `test` defined here
+ = note: similarly named attribute macro `test` defined here
error: cannot find attribute `deprcated` in this scope
--> $DIR/attribute-typos.rs:1:3
LL | for j in a {
| ^ `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop
|
-note: this function takes ownership of the receiver `self`, which moves `a`
+note: `into_iter` takes ownership of the receiver `self`, which moves `a`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
help: consider iterating over a slice of the `Vec<i32>`'s content to avoid moving into the `for` loop
|
LL | for j in &a {
|
note: required by a bound in `std::mem::size_of`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | pub const fn size_of<T>() -> usize {
- | ^ required by this bound in `size_of`
help: consider further restricting `Self`
|
LL | trait Foo<T>: Sized {
|
note: required by a bound in `std::mem::size_of`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | pub const fn size_of<T>() -> usize {
- | ^ required by this bound in `size_of`
help: consider further restricting `Self`
|
LL | trait Bar: std::fmt::Display + Sized {
|
note: required by a bound in `std::mem::size_of`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | pub const fn size_of<T>() -> usize {
- | ^ required by this bound in `size_of`
help: consider further restricting `Self`
|
LL | trait Baz: Sized where Self: std::fmt::Display {
|
note: required by a bound in `std::mem::size_of`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | pub const fn size_of<T>() -> usize {
- | ^ required by this bound in `size_of`
help: consider further restricting `Self`
|
LL | trait Qux<T>: Sized where Self: std::fmt::Display {
|
note: required by a bound in `std::mem::size_of`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | pub const fn size_of<T>() -> usize {
- | ^ required by this bound in `size_of`
help: consider further restricting `Self`
|
LL | trait Bat<T>: std::fmt::Display + Sized {
--- /dev/null
+// run-rustfix
+fn wat<T: Clone>(t: &T) -> T {
+ t.clone() //~ ERROR E0308
+}
+
+#[derive(Clone)]
+struct Foo;
+
+fn wut(t: &Foo) -> Foo {
+ t.clone() //~ ERROR E0308
+}
+
+fn main() {
+ wat(&42);
+ wut(&Foo);
+}
--- /dev/null
+// run-rustfix
+fn wat<T>(t: &T) -> T {
+ t.clone() //~ ERROR E0308
+}
+
+struct Foo;
+
+fn wut(t: &Foo) -> Foo {
+ t.clone() //~ ERROR E0308
+}
+
+fn main() {
+ wat(&42);
+ wut(&Foo);
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5
+ |
+LL | fn wat<T>(t: &T) -> T {
+ | - - expected `T` because of return type
+ | |
+ | this type parameter
+LL | t.clone()
+ | ^^^^^^^^^ expected type parameter `T`, found `&T`
+ |
+ = note: expected type parameter `T`
+ found reference `&T`
+note: `T` does not implement `Clone`, so `&T` was cloned instead
+ --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5
+ |
+LL | t.clone()
+ | ^
+help: consider restricting type parameter `T`
+ |
+LL | fn wat<T: Clone>(t: &T) -> T {
+ | +++++++
+
+error[E0308]: mismatched types
+ --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:9:5
+ |
+LL | fn wut(t: &Foo) -> Foo {
+ | --- expected `Foo` because of return type
+LL | t.clone()
+ | ^^^^^^^^^ expected struct `Foo`, found `&Foo`
+ |
+note: `Foo` does not implement `Clone`, so `&Foo` was cloned instead
+ --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:9:5
+ |
+LL | t.clone()
+ | ^
+help: consider annotating `Foo` with `#[derive(Clone)]`
+ |
+LL | #[derive(Clone)]
+ |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
| ^^^^^^^^^^^^ ^^^^^^^^^
note: required by a bound in `Eq`
--> $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub trait Eq: PartialEq<Self> {
- | ^^^^^^^^^^^^^^^ required by this bound in `Eq`
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider restricting type parameter `T`
|
`Enum: Clone`
`Enum: Default`
`CloneEnum: Default`
-note: the following trait must be implemented
+note: the trait `Default` must be implemented
--> $SRC_DIR/core/src/default.rs:LL:COL
- |
-LL | pub trait Default: Sized {
- | ^^^^^^^^^^^^^^^^^^^^^^^^
help: consider annotating `Enum` with `#[derive(Clone)]`
|
LL | #[derive(Clone)]
...
LL | let y = x.test();
| ^^^^ method cannot be called on `Foo<Vec<Enum>, Instant>` due to unsatisfied trait bounds
+ --> $SRC_DIR/std/src/time.rs:LL:COL
|
- ::: $SRC_DIR/std/src/time.rs:LL:COL
- |
-LL | pub struct Instant(time::Instant);
- | ------------------ doesn't satisfy `Instant: Default`
- |
- ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ = note: doesn't satisfy `Instant: Default`
+ --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
-LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
- | ------------------------------------------------------------------------------------------------ doesn't satisfy `Vec<Enum>: Clone`
+ = note: doesn't satisfy `Vec<Enum>: Clone`
|
= note: the following trait bounds were not satisfied:
`Vec<Enum>: Clone`
|
LL | impl result {
| ^^^^^^ help: an enum with a similar name exists: `Result`
+ --> $SRC_DIR/core/src/result.rs:LL:COL
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | pub enum Result<T, E> {
- | --------------------- similarly named enum `Result` defined here
+ = note: similarly named enum `Result` defined here
error[E0573]: expected type, found variant `Err`
--> $DIR/do-not-attempt-to-add-suggestions-with-no-changes.rs:3:25
let &(X(_t), X(_u)) = &(x.clone(), x.clone());
//~^ ERROR cannot move
- //~| HELP consider removing the `&`
- //~| SUGGESTION (X(_t), X(_u))
+ //~| HELP consider removing the borrow
if let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&`
- //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+ //~| HELP consider removing the borrow
while let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&`
- //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+ //~| HELP consider removing the borrow
match &(e.clone(), e.clone()) {
//~^ ERROR cannot move
&(Either::One(_t), Either::Two(_u)) => (),
- //~^ HELP consider removing the `&`
- //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+ //~^ HELP consider removing the borrow
&(Either::Two(_t), Either::One(_u)) => (),
- //~^ HELP consider removing the `&`
- //~| SUGGESTION (Either::Two(_t), Either::One(_u))
+ //~^ HELP consider removing the borrow
_ => (),
}
match &(e.clone(), e.clone()) {
//~^ ERROR cannot move
&(Either::One(_t), Either::Two(_u))
- //~^ HELP consider removing the `&`
- //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+ //~^ HELP consider removing the borrow
| &(Either::Two(_t), Either::One(_u)) => (),
// FIXME: would really like a suggestion here too
_ => (),
match &(e.clone(), e.clone()) {
//~^ ERROR cannot move
&(Either::One(_t), Either::Two(_u)) => (),
- //~^ HELP consider removing the `&`
- //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+ //~^ HELP consider removing the borrow
&(Either::Two(ref _t), Either::One(ref _u)) => (),
_ => (),
}
match &(e.clone(), e.clone()) {
//~^ ERROR cannot move
&(Either::One(_t), Either::Two(_u)) => (),
- //~^ HELP consider removing the `&`
- //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+ //~^ HELP consider removing the borrow
(Either::Two(_t), Either::One(_u)) => (),
_ => (),
}
fn f5(&(X(_t), X(_u)): &(X, X)) { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&`
- //~| SUGGESTION (X(_t), X(_u))
+ //~| HELP consider removing the borrow
let &mut (X(_t), X(_u)) = &mut (xm.clone(), xm.clone());
//~^ ERROR cannot move
- //~| HELP consider removing the `&mut`
- //~| SUGGESTION (X(_t), X(_u))
+ //~| HELP consider removing the mutable borrow
if let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&mut`
- //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+ //~| HELP consider removing the mutable borrow
while let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&mut`
- //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+ //~| HELP consider removing the mutable borrow
match &mut (em.clone(), em.clone()) {
//~^ ERROR cannot move
&mut (Either::One(_t), Either::Two(_u)) => (),
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+ //~^ HELP consider removing the mutable borrow
&mut (Either::Two(_t), Either::One(_u)) => (),
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION (Either::Two(_t), Either::One(_u))
+ //~^ HELP consider removing the mutable borrow
_ => (),
}
match &mut (em.clone(), em.clone()) {
//~^ ERROR cannot move
&mut (Either::One(_t), Either::Two(_u))
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+ //~^ HELP consider removing the mutable borrow
| &mut (Either::Two(_t), Either::One(_u)) => (),
// FIXME: would really like a suggestion here too
_ => (),
match &mut (em.clone(), em.clone()) {
//~^ ERROR cannot move
&mut (Either::One(_t), Either::Two(_u)) => (),
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+ //~^ HELP consider removing the mutable borrow
&mut (Either::Two(ref _t), Either::One(ref _u)) => (),
_ => (),
}
match &mut (em.clone(), em.clone()) {
//~^ ERROR cannot move
&mut (Either::One(_t), Either::Two(_u)) => (),
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+ //~^ HELP consider removing the mutable borrow
&mut (Either::Two(ref mut _t), Either::One(ref mut _u)) => (),
_ => (),
}
match &mut (em.clone(), em.clone()) {
//~^ ERROR cannot move
&mut (Either::One(_t), Either::Two(_u)) => (),
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+ //~^ HELP consider removing the mutable borrow
(Either::Two(_t), Either::One(_u)) => (),
_ => (),
}
fn f6(&mut (X(_t), X(_u)): &mut (X, X)) { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&mut`
- //~| SUGGESTION (X(_t), X(_u))
+ //~| HELP consider removing the mutable borrow
}
--> $DIR/duplicate-suggestions.rs:39:27
|
LL | let &(X(_t), X(_u)) = &(x.clone(), x.clone());
- | --------------- ^^^^^^^^^^^^^^^^^^^^^^^
- | | | |
- | | | ...and here
- | | data moved here
- | help: consider removing the `&`: `(X(_t), X(_u))`
+ | -- -- ^^^^^^^^^^^^^^^^^^^^^^^
+ | | |
+ | | ...and here
+ | data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the borrow
+ |
+LL - let &(X(_t), X(_u)) = &(x.clone(), x.clone());
+LL + let (X(_t), X(_u)) = &(x.clone(), x.clone());
+ |
error[E0507]: cannot move out of a shared reference
- --> $DIR/duplicate-suggestions.rs:43:50
+ --> $DIR/duplicate-suggestions.rs:42:50
|
LL | if let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
- | ----------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^
- | | | |
- | | | ...and here
- | | data moved here
- | help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))`
+ | -- -- ^^^^^^^^^^^^^^^^^^^^^^^
+ | | |
+ | | ...and here
+ | data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the borrow
+ |
+LL - if let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
+LL + if let (Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
+ |
error[E0507]: cannot move out of a shared reference
- --> $DIR/duplicate-suggestions.rs:47:53
+ --> $DIR/duplicate-suggestions.rs:45:53
|
LL | while let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
- | ----------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^
- | | | |
- | | | ...and here
- | | data moved here
- | help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))`
+ | -- -- ^^^^^^^^^^^^^^^^^^^^^^^
+ | | |
+ | | ...and here
+ | data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the borrow
+ |
+LL - while let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
+LL + while let (Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
+ |
error[E0507]: cannot move out of a shared reference
- --> $DIR/duplicate-suggestions.rs:51:11
+ --> $DIR/duplicate-suggestions.rs:48:11
|
LL | match &(e.clone(), e.clone()) {
| ^^^^^^^^^^^^^^^^^^^^^^^
| -- -- ...and here
| |
| data moved here
-...
+LL |
LL | &(Either::Two(_t), Either::One(_u)) => (),
| -- ...and here -- ...and here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
-help: consider removing the `&`
+help: consider removing the borrow
|
-LL | (Either::One(_t), Either::Two(_u)) => (),
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-help: consider removing the `&`
+LL - &(Either::One(_t), Either::Two(_u)) => (),
+LL + (Either::One(_t), Either::Two(_u)) => (),
+ |
+help: consider removing the borrow
+ |
+LL - &(Either::Two(_t), Either::One(_u)) => (),
+LL + (Either::Two(_t), Either::One(_u)) => (),
|
-LL | (Either::Two(_t), Either::One(_u)) => (),
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0507]: cannot move out of a shared reference
- --> $DIR/duplicate-suggestions.rs:61:11
+ --> $DIR/duplicate-suggestions.rs:56:11
|
LL | match &(e.clone(), e.clone()) {
| ^^^^^^^^^^^^^^^^^^^^^^^
| data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
-help: consider removing the `&`
+help: consider removing the borrow
|
-LL ~ (Either::One(_t), Either::Two(_u))
-LL +
-LL +
-LL ~ | &(Either::Two(_t), Either::One(_u)) => (),
+LL - &(Either::One(_t), Either::Two(_u))
+LL + (Either::One(_t), Either::Two(_u))
|
error[E0507]: cannot move out of a shared reference
- --> $DIR/duplicate-suggestions.rs:70:11
+ --> $DIR/duplicate-suggestions.rs:64:11
|
LL | match &(e.clone(), e.clone()) {
| ^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | &(Either::One(_t), Either::Two(_u)) => (),
- | -----------------------------------
- | | | |
- | | | ...and here
- | | data moved here
- | help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))`
+ | -- -- ...and here
+ | |
+ | data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the borrow
+ |
+LL - &(Either::One(_t), Either::Two(_u)) => (),
+LL + (Either::One(_t), Either::Two(_u)) => (),
+ |
error[E0507]: cannot move out of a shared reference
- --> $DIR/duplicate-suggestions.rs:78:11
+ --> $DIR/duplicate-suggestions.rs:71:11
|
LL | match &(e.clone(), e.clone()) {
| ^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | &(Either::One(_t), Either::Two(_u)) => (),
- | -----------------------------------
- | | | |
- | | | ...and here
- | | data moved here
- | help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))`
+ | -- -- ...and here
+ | |
+ | data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the borrow
+ |
+LL - &(Either::One(_t), Either::Two(_u)) => (),
+LL + (Either::One(_t), Either::Two(_u)) => (),
+ |
error[E0507]: cannot move out of a mutable reference
- --> $DIR/duplicate-suggestions.rs:91:31
+ --> $DIR/duplicate-suggestions.rs:82:31
|
LL | let &mut (X(_t), X(_u)) = &mut (xm.clone(), xm.clone());
- | ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | | | |
- | | | ...and here
- | | data moved here
- | help: consider removing the `&mut`: `(X(_t), X(_u))`
+ | -- -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | | |
+ | | ...and here
+ | data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the mutable borrow
+ |
+LL - let &mut (X(_t), X(_u)) = &mut (xm.clone(), xm.clone());
+LL + let (X(_t), X(_u)) = &mut (xm.clone(), xm.clone());
+ |
error[E0507]: cannot move out of a mutable reference
- --> $DIR/duplicate-suggestions.rs:95:54
+ --> $DIR/duplicate-suggestions.rs:85:54
|
LL | if let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
- | --------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | | | |
- | | | ...and here
- | | data moved here
- | help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
+ | -- -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | | |
+ | | ...and here
+ | data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the mutable borrow
+ |
+LL - if let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
+LL + if let (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
+ |
error[E0507]: cannot move out of a mutable reference
- --> $DIR/duplicate-suggestions.rs:99:57
+ --> $DIR/duplicate-suggestions.rs:88:57
|
LL | while let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
- | --------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | | | |
- | | | ...and here
- | | data moved here
- | help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
+ | -- -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | | |
+ | | ...and here
+ | data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the mutable borrow
+ |
+LL - while let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
+LL + while let (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
+ |
error[E0507]: cannot move out of a mutable reference
- --> $DIR/duplicate-suggestions.rs:103:11
+ --> $DIR/duplicate-suggestions.rs:91:11
|
LL | match &mut (em.clone(), em.clone()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| -- -- ...and here
| |
| data moved here
-...
+LL |
LL | &mut (Either::Two(_t), Either::One(_u)) => (),
| -- ...and here -- ...and here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
-help: consider removing the `&mut`
+help: consider removing the mutable borrow
+ |
+LL - &mut (Either::One(_t), Either::Two(_u)) => (),
+LL + (Either::One(_t), Either::Two(_u)) => (),
|
-LL | (Either::One(_t), Either::Two(_u)) => (),
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-help: consider removing the `&mut`
+help: consider removing the mutable borrow
+ |
+LL - &mut (Either::Two(_t), Either::One(_u)) => (),
+LL + (Either::Two(_t), Either::One(_u)) => (),
|
-LL | (Either::Two(_t), Either::One(_u)) => (),
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0507]: cannot move out of a mutable reference
- --> $DIR/duplicate-suggestions.rs:113:11
+ --> $DIR/duplicate-suggestions.rs:99:11
|
LL | match &mut (em.clone(), em.clone()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
-help: consider removing the `&mut`
+help: consider removing the mutable borrow
|
-LL ~ (Either::One(_t), Either::Two(_u))
-LL +
-LL +
-LL ~ | &mut (Either::Two(_t), Either::One(_u)) => (),
+LL - &mut (Either::One(_t), Either::Two(_u))
+LL + (Either::One(_t), Either::Two(_u))
|
error[E0507]: cannot move out of a mutable reference
- --> $DIR/duplicate-suggestions.rs:122:11
+ --> $DIR/duplicate-suggestions.rs:107:11
|
LL | match &mut (em.clone(), em.clone()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | &mut (Either::One(_t), Either::Two(_u)) => (),
- | ---------------------------------------
- | | | |
- | | | ...and here
- | | data moved here
- | help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
+ | -- -- ...and here
+ | |
+ | data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the mutable borrow
+ |
+LL - &mut (Either::One(_t), Either::Two(_u)) => (),
+LL + (Either::One(_t), Either::Two(_u)) => (),
+ |
error[E0507]: cannot move out of a mutable reference
- --> $DIR/duplicate-suggestions.rs:130:11
+ --> $DIR/duplicate-suggestions.rs:114:11
|
LL | match &mut (em.clone(), em.clone()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | &mut (Either::One(_t), Either::Two(_u)) => (),
- | ---------------------------------------
- | | | |
- | | | ...and here
- | | data moved here
- | help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
+ | -- -- ...and here
+ | |
+ | data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the mutable borrow
+ |
+LL - &mut (Either::One(_t), Either::Two(_u)) => (),
+LL + (Either::One(_t), Either::Two(_u)) => (),
+ |
error[E0507]: cannot move out of a mutable reference
- --> $DIR/duplicate-suggestions.rs:138:11
+ --> $DIR/duplicate-suggestions.rs:121:11
|
LL | match &mut (em.clone(), em.clone()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | &mut (Either::One(_t), Either::Two(_u)) => (),
- | ---------------------------------------
- | | | |
- | | | ...and here
- | | data moved here
- | help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
+ | -- -- ...and here
+ | |
+ | data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the mutable borrow
+ |
+LL - &mut (Either::One(_t), Either::Two(_u)) => (),
+LL + (Either::One(_t), Either::Two(_u)) => (),
+ |
error[E0507]: cannot move out of a shared reference
- --> $DIR/duplicate-suggestions.rs:86:11
+ --> $DIR/duplicate-suggestions.rs:78:11
|
LL | fn f5(&(X(_t), X(_u)): &(X, X)) { }
| ^^^^--^^^^^--^^
- | | | |
- | | | ...and here
- | | data moved here
- | help: consider removing the `&`: `(X(_t), X(_u))`
+ | | |
+ | | ...and here
+ | data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the borrow
+ |
+LL - fn f5(&(X(_t), X(_u)): &(X, X)) { }
+LL + fn f5((X(_t), X(_u)): &(X, X)) { }
+ |
error[E0507]: cannot move out of a mutable reference
- --> $DIR/duplicate-suggestions.rs:146:11
+ --> $DIR/duplicate-suggestions.rs:128:11
|
LL | fn f6(&mut (X(_t), X(_u)): &mut (X, X)) { }
| ^^^^^^^^--^^^^^--^^
- | | | |
- | | | ...and here
- | | data moved here
- | help: consider removing the `&mut`: `(X(_t), X(_u))`
+ | | |
+ | | ...and here
+ | data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider removing the mutable borrow
+ |
+LL - fn f6(&mut (X(_t), X(_u)): &mut (X, X)) { }
+LL + fn f6((X(_t), X(_u)): &mut (X, X)) { }
+ |
error: aborting due to 17 previous errors
let X(_t) = x;
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &x
if let Either::One(_t) = e { }
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &e
while let Either::One(_t) = e { }
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &e
match e {
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &e
Either::One(_t)
| Either::Two(_t) => (),
}
match e {
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &e
Either::One(_t) => (),
Either::Two(ref _t) => (),
// FIXME: should suggest removing `ref` too
let X(mut _t) = x;
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &x
if let Either::One(mut _t) = em { }
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &em
while let Either::One(mut _t) = em { }
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &em
match em {
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &em
Either::One(mut _t)
| Either::Two(mut _t) => (),
}
match em {
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &em
Either::One(mut _t) => (),
Either::Two(ref _t) => (),
// FIXME: should suggest removing `ref` too
let X(_t) = x;
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &x
if let Either::One(_t) = e { }
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &e
while let Either::One(_t) = e { }
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &e
match e {
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &e
Either::One(_t)
| Either::Two(_t) => (),
}
match e {
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &e
Either::One(_t) => (),
Either::Two(ref _t) => (),
// FIXME: should suggest removing `ref` too
let X(mut _t) = x;
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &x
if let Either::One(mut _t) = em { }
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &em
while let Either::One(mut _t) = em { }
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &em
match em {
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &em
Either::One(mut _t)
| Either::Two(mut _t) => (),
}
match em {
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &em
Either::One(mut _t) => (),
Either::Two(ref _t) => (),
// FIXME: should suggest removing `ref` too
match em {
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &em
Either::One(mut _t) => (),
Either::Two(ref mut _t) => (),
// FIXME: should suggest removing `ref` too
LL | consume_fn(|| {
| -- captured by this `Fn` closure
LL | let X(_t) = x;
- | -- ^ help: consider borrowing here: `&x`
+ | -- ^
| |
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let X(_t) = &x;
+ | +
error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
- --> $DIR/move-into-closure.rs:32:34
+ --> $DIR/move-into-closure.rs:31:34
|
LL | let e = Either::One(X(Y));
| - captured outer variable
| -- captured by this `Fn` closure
...
LL | if let Either::One(_t) = e { }
- | -- ^ help: consider borrowing here: `&e`
+ | -- ^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | if let Either::One(_t) = &e { }
+ | +
error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
- --> $DIR/move-into-closure.rs:36:37
+ --> $DIR/move-into-closure.rs:34:37
|
LL | let e = Either::One(X(Y));
| - captured outer variable
| -- captured by this `Fn` closure
...
LL | while let Either::One(_t) = e { }
- | -- ^ help: consider borrowing here: `&e`
+ | -- ^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | while let Either::One(_t) = &e { }
+ | +
error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
- --> $DIR/move-into-closure.rs:40:15
+ --> $DIR/move-into-closure.rs:37:15
|
LL | let e = Either::One(X(Y));
| - captured outer variable
| -- captured by this `Fn` closure
...
LL | match e {
- | ^ help: consider borrowing here: `&e`
+ | ^
...
LL | Either::One(_t)
| --
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &e {
+ | +
error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
- --> $DIR/move-into-closure.rs:47:15
+ --> $DIR/move-into-closure.rs:43:15
|
LL | let e = Either::One(X(Y));
| - captured outer variable
| -- captured by this `Fn` closure
...
LL | match e {
- | ^ help: consider borrowing here: `&e`
+ | ^
...
LL | Either::One(_t) => (),
| --
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &e {
+ | +
error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
- --> $DIR/move-into-closure.rs:56:25
+ --> $DIR/move-into-closure.rs:51:25
|
LL | let x = X(Y);
| - captured outer variable
| -- captured by this `Fn` closure
...
LL | let X(mut _t) = x;
- | ------ ^ help: consider borrowing here: `&x`
+ | ------ ^
| |
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let X(mut _t) = &x;
+ | +
error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
- --> $DIR/move-into-closure.rs:60:38
+ --> $DIR/move-into-closure.rs:54:38
|
LL | let mut em = Either::One(X(Y));
| ------ captured outer variable
| -- captured by this `Fn` closure
...
LL | if let Either::One(mut _t) = em { }
- | ------ ^^ help: consider borrowing here: `&em`
+ | ------ ^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | if let Either::One(mut _t) = &em { }
+ | +
error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
- --> $DIR/move-into-closure.rs:64:41
+ --> $DIR/move-into-closure.rs:57:41
|
LL | let mut em = Either::One(X(Y));
| ------ captured outer variable
| -- captured by this `Fn` closure
...
LL | while let Either::One(mut _t) = em { }
- | ------ ^^ help: consider borrowing here: `&em`
+ | ------ ^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | while let Either::One(mut _t) = &em { }
+ | +
error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
- --> $DIR/move-into-closure.rs:68:15
+ --> $DIR/move-into-closure.rs:60:15
|
LL | let mut em = Either::One(X(Y));
| ------ captured outer variable
| -- captured by this `Fn` closure
...
LL | match em {
- | ^^ help: consider borrowing here: `&em`
+ | ^^
...
LL | Either::One(mut _t)
| ------
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &em {
+ | +
error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
- --> $DIR/move-into-closure.rs:75:15
+ --> $DIR/move-into-closure.rs:66:15
|
LL | let mut em = Either::One(X(Y));
| ------ captured outer variable
| -- captured by this `Fn` closure
...
LL | match em {
- | ^^ help: consider borrowing here: `&em`
+ | ^^
...
LL | Either::One(mut _t) => (),
| ------
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &em {
+ | +
error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure
- --> $DIR/move-into-closure.rs:95:21
+ --> $DIR/move-into-closure.rs:85:21
|
LL | let x = X(Y);
| - captured outer variable
LL | consume_fnmut(|| {
| -- captured by this `FnMut` closure
LL | let X(_t) = x;
- | -- ^ help: consider borrowing here: `&x`
+ | -- ^
| |
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let X(_t) = &x;
+ | +
error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
- --> $DIR/move-into-closure.rs:99:34
+ --> $DIR/move-into-closure.rs:88:34
|
LL | let e = Either::One(X(Y));
| - captured outer variable
| -- captured by this `FnMut` closure
...
LL | if let Either::One(_t) = e { }
- | -- ^ help: consider borrowing here: `&e`
+ | -- ^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | if let Either::One(_t) = &e { }
+ | +
error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
- --> $DIR/move-into-closure.rs:103:37
+ --> $DIR/move-into-closure.rs:91:37
|
LL | let e = Either::One(X(Y));
| - captured outer variable
| -- captured by this `FnMut` closure
...
LL | while let Either::One(_t) = e { }
- | -- ^ help: consider borrowing here: `&e`
+ | -- ^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | while let Either::One(_t) = &e { }
+ | +
error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
- --> $DIR/move-into-closure.rs:107:15
+ --> $DIR/move-into-closure.rs:94:15
|
LL | let e = Either::One(X(Y));
| - captured outer variable
| -- captured by this `FnMut` closure
...
LL | match e {
- | ^ help: consider borrowing here: `&e`
+ | ^
...
LL | Either::One(_t)
| --
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &e {
+ | +
error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
- --> $DIR/move-into-closure.rs:114:15
+ --> $DIR/move-into-closure.rs:100:15
|
LL | let e = Either::One(X(Y));
| - captured outer variable
| -- captured by this `FnMut` closure
...
LL | match e {
- | ^ help: consider borrowing here: `&e`
+ | ^
...
LL | Either::One(_t) => (),
| --
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &e {
+ | +
error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure
- --> $DIR/move-into-closure.rs:123:25
+ --> $DIR/move-into-closure.rs:108:25
|
LL | let x = X(Y);
| - captured outer variable
| -- captured by this `FnMut` closure
...
LL | let X(mut _t) = x;
- | ------ ^ help: consider borrowing here: `&x`
+ | ------ ^
| |
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let X(mut _t) = &x;
+ | +
error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
- --> $DIR/move-into-closure.rs:127:38
+ --> $DIR/move-into-closure.rs:111:38
|
LL | let mut em = Either::One(X(Y));
| ------ captured outer variable
| -- captured by this `FnMut` closure
...
LL | if let Either::One(mut _t) = em { }
- | ------ ^^ help: consider borrowing here: `&em`
+ | ------ ^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | if let Either::One(mut _t) = &em { }
+ | +
error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
- --> $DIR/move-into-closure.rs:131:41
+ --> $DIR/move-into-closure.rs:114:41
|
LL | let mut em = Either::One(X(Y));
| ------ captured outer variable
| -- captured by this `FnMut` closure
...
LL | while let Either::One(mut _t) = em { }
- | ------ ^^ help: consider borrowing here: `&em`
+ | ------ ^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | while let Either::One(mut _t) = &em { }
+ | +
error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
- --> $DIR/move-into-closure.rs:135:15
+ --> $DIR/move-into-closure.rs:117:15
|
LL | let mut em = Either::One(X(Y));
| ------ captured outer variable
| -- captured by this `FnMut` closure
...
LL | match em {
- | ^^ help: consider borrowing here: `&em`
+ | ^^
...
LL | Either::One(mut _t)
| ------
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &em {
+ | +
error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
- --> $DIR/move-into-closure.rs:142:15
+ --> $DIR/move-into-closure.rs:123:15
|
LL | let mut em = Either::One(X(Y));
| ------ captured outer variable
| -- captured by this `FnMut` closure
...
LL | match em {
- | ^^ help: consider borrowing here: `&em`
+ | ^^
...
LL | Either::One(mut _t) => (),
| ------
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &em {
+ | +
error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
- --> $DIR/move-into-closure.rs:150:15
+ --> $DIR/move-into-closure.rs:130:15
|
LL | let mut em = Either::One(X(Y));
| ------ captured outer variable
| -- captured by this `FnMut` closure
...
LL | match em {
- | ^^ help: consider borrowing here: `&em`
+ | ^^
...
LL | Either::One(mut _t) => (),
| ------
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &em {
+ | +
error: aborting due to 21 previous errors
let X(_t) = *s;
//~^ ERROR cannot move
- //~| HELP consider borrowing here
- //~| SUGGESTION s
+ //~| HELP consider removing the dereference here
if let Either::One(_t) = *r { }
//~^ ERROR cannot move
- //~| HELP consider borrowing here
- //~| SUGGESTION r
+ //~| HELP consider removing the dereference here
while let Either::One(_t) = *r { }
//~^ ERROR cannot move
- //~| HELP consider borrowing here
- //~| SUGGESTION r
+ //~| HELP consider removing the dereference here
match *r {
//~^ ERROR cannot move
- //~| HELP consider borrowing here
- //~| SUGGESTION r
+ //~| HELP consider removing the dereference here
Either::One(_t)
| Either::Two(_t) => (),
}
match *r {
//~^ ERROR cannot move
- //~| HELP consider borrowing here
- //~| SUGGESTION r
+ //~| HELP consider removing the dereference here
Either::One(_t) => (),
Either::Two(ref _t) => (),
// FIXME: should suggest removing `ref` too
let X(_t) = *sm;
//~^ ERROR cannot move
- //~| HELP consider borrowing here
- //~| SUGGESTION sm
+ //~| HELP consider removing the dereference here
if let Either::One(_t) = *rm { }
//~^ ERROR cannot move
- //~| HELP consider borrowing here
- //~| SUGGESTION rm
+ //~| HELP consider removing the dereference here
while let Either::One(_t) = *rm { }
//~^ ERROR cannot move
- //~| HELP consider borrowing here
- //~| SUGGESTION rm
+ //~| HELP consider removing the dereference here
match *rm {
//~^ ERROR cannot move
- //~| HELP consider borrowing here
- //~| SUGGESTION rm
+ //~| HELP consider removing the dereference here
Either::One(_t)
| Either::Two(_t) => (),
}
match *rm {
//~^ ERROR cannot move
- //~| HELP consider borrowing here
- //~| SUGGESTION rm
+ //~| HELP consider removing the dereference here
Either::One(_t) => (),
Either::Two(ref _t) => (),
// FIXME: should suggest removing `ref` too
}
match *rm {
//~^ ERROR cannot move
- //~| HELP consider borrowing here
- //~| SUGGESTION rm
+ //~| HELP consider removing the dereference here
Either::One(_t) => (),
Either::Two(ref mut _t) => (),
// FIXME: should suggest removing `ref` too
let X(_t) = vs[0];
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &vs[0]
if let Either::One(_t) = vr[0] { }
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &vr[0]
while let Either::One(_t) = vr[0] { }
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &vr[0]
match vr[0] {
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &vr[0]
Either::One(_t)
| Either::Two(_t) => (),
}
match vr[0] {
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &vr[0]
Either::One(_t) => (),
Either::Two(ref _t) => (),
// FIXME: should suggest removing `ref` too
let X(_t) = vsm[0];
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &vsm[0]
if let Either::One(_t) = vrm[0] { }
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &vrm[0]
while let Either::One(_t) = vrm[0] { }
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &vrm[0]
match vrm[0] {
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &vrm[0]
Either::One(_t)
| Either::Two(_t) => (),
}
match vrm[0] {
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &vrm[0]
Either::One(_t) => (),
Either::Two(ref _t) => (),
// FIXME: should suggest removing `ref` too
match vrm[0] {
//~^ ERROR cannot move
//~| HELP consider borrowing here
- //~| SUGGESTION &vrm[0]
Either::One(_t) => (),
Either::Two(ref mut _t) => (),
// FIXME: should suggest removing `ref` too
let &X(_t) = s;
//~^ ERROR cannot move
- //~| HELP consider removing the `&`
- //~| SUGGESTION X(_t)
+ //~| HELP consider removing
if let &Either::One(_t) = r { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&`
- //~| SUGGESTION Either::One(_t)
+ //~| HELP consider removing
while let &Either::One(_t) = r { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&`
- //~| SUGGESTION Either::One(_t)
+ //~| HELP consider removing
match r {
//~^ ERROR cannot move
&Either::One(_t)
- //~^ HELP consider removing the `&`
- //~| SUGGESTION Either::One(_t)
+ //~^ HELP consider removing
| &Either::Two(_t) => (),
// FIXME: would really like a suggestion here too
}
match r {
//~^ ERROR cannot move
&Either::One(_t) => (),
- //~^ HELP consider removing the `&`
- //~| SUGGESTION Either::One(_t)
+ //~^ HELP consider removing
&Either::Two(ref _t) => (),
}
match r {
//~^ ERROR cannot move
&Either::One(_t) => (),
- //~^ HELP consider removing the `&`
- //~| SUGGESTION Either::One(_t)
+ //~^ HELP consider removing
Either::Two(_t) => (),
}
fn f1(&X(_t): &X) { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&`
- //~| SUGGESTION X(_t)
+ //~| HELP consider removing
let &mut X(_t) = sm;
//~^ ERROR cannot move
- //~| HELP consider removing the `&mut`
- //~| SUGGESTION X(_t)
+ //~| HELP consider removing
if let &mut Either::One(_t) = rm { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&mut`
- //~| SUGGESTION Either::One(_t)
+ //~| HELP consider removing
while let &mut Either::One(_t) = rm { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&mut`
- //~| SUGGESTION Either::One(_t)
+ //~| HELP consider removing
match rm {
//~^ ERROR cannot move
&mut Either::One(_t) => (),
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION Either::One(_t)
+ //~^ HELP consider removing
&mut Either::Two(_t) => (),
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION Either::Two(_t)
+ //~^ HELP consider removing
}
match rm {
//~^ ERROR cannot move
&mut Either::One(_t) => (),
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION Either::One(_t)
+ //~^ HELP consider removing
&mut Either::Two(ref _t) => (),
}
match rm {
//~^ ERROR cannot move
&mut Either::One(_t) => (),
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION Either::One(_t)
+ //~^ HELP consider removing
&mut Either::Two(ref mut _t) => (),
}
match rm {
//~^ ERROR cannot move
&mut Either::One(_t) => (),
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION Either::One(_t)
+ //~^ HELP consider removing
Either::Two(_t) => (),
}
fn f2(&mut X(_t): &mut X) { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&mut`
- //~| SUGGESTION X(_t)
+ //~| HELP consider removing
// move from tuple of &Either/&X
let (&X(_t),) = (&x.clone(),);
//~^ ERROR cannot move
+ //~| HELP consider borrowing the pattern binding
if let (&Either::One(_t),) = (&e.clone(),) { }
//~^ ERROR cannot move
+ //~| HELP consider borrowing the pattern binding
while let (&Either::One(_t),) = (&e.clone(),) { }
//~^ ERROR cannot move
+ //~| HELP consider borrowing the pattern binding
match (&e.clone(),) {
//~^ ERROR cannot move
(&Either::One(_t),)
+ //~^ HELP consider borrowing the pattern binding
| (&Either::Two(_t),) => (),
}
fn f3((&X(_t),): (&X,)) { }
//~^ ERROR cannot move
+ //~| HELP consider borrowing the pattern binding
let (&mut X(_t),) = (&mut xm.clone(),);
//~^ ERROR cannot move
+ //~| HELP consider borrowing the pattern binding
if let (&mut Either::One(_t),) = (&mut em.clone(),) { }
//~^ ERROR cannot move
+ //~| HELP consider borrowing the pattern binding
while let (&mut Either::One(_t),) = (&mut em.clone(),) { }
//~^ ERROR cannot move
+ //~| HELP consider borrowing the pattern binding
match (&mut em.clone(),) {
//~^ ERROR cannot move
(&mut Either::One(_t),) => (),
+ //~^ HELP consider borrowing the pattern binding
(&mut Either::Two(_t),) => (),
+ //~^ HELP consider borrowing the pattern binding
}
fn f4((&mut X(_t),): (&mut X,)) { }
//~^ ERROR cannot move
+ //~| HELP consider borrowing the pattern binding
// move from &Either/&X value
let &X(_t) = &x;
//~^ ERROR cannot move
- //~| HELP consider removing the `&`
- //~| SUGGESTION X(_t)
+ //~| HELP consider removing
if let &Either::One(_t) = &e { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&`
- //~| SUGGESTION Either::One(_t)
+ //~| HELP consider removing
while let &Either::One(_t) = &e { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&`
- //~| SUGGESTION Either::One(_t)
+ //~| HELP consider removing
match &e {
//~^ ERROR cannot move
&Either::One(_t)
- //~^ HELP consider removing the `&`
- //~| SUGGESTION Either::One(_t)
+ //~^ HELP consider removing
| &Either::Two(_t) => (),
// FIXME: would really like a suggestion here too
}
match &e {
//~^ ERROR cannot move
&Either::One(_t) => (),
- //~^ HELP consider removing the `&`
- //~| SUGGESTION Either::One(_t)
+ //~^ HELP consider removing
&Either::Two(ref _t) => (),
}
match &e {
//~^ ERROR cannot move
&Either::One(_t) => (),
- //~^ HELP consider removing the `&`
- //~| SUGGESTION Either::One(_t)
+ //~^ HELP consider removing
Either::Two(_t) => (),
}
let &mut X(_t) = &mut xm;
//~^ ERROR cannot move
- //~| HELP consider removing the `&mut`
- //~| SUGGESTION X(_t)
+ //~| HELP consider removing
if let &mut Either::One(_t) = &mut em { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&mut`
- //~| SUGGESTION Either::One(_t)
+ //~| HELP consider removing
while let &mut Either::One(_t) = &mut em { }
//~^ ERROR cannot move
- //~| HELP consider removing the `&mut`
- //~| SUGGESTION Either::One(_t)
+ //~| HELP consider removing
match &mut em {
//~^ ERROR cannot move
&mut Either::One(_t)
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION Either::One(_t)
+ //~^ HELP consider removing
| &mut Either::Two(_t) => (),
// FIXME: would really like a suggestion here too
}
match &mut em {
//~^ ERROR cannot move
&mut Either::One(_t) => (),
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION Either::One(_t)
+ //~^ HELP consider removing
&mut Either::Two(ref _t) => (),
}
match &mut em {
//~^ ERROR cannot move
&mut Either::One(_t) => (),
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION Either::One(_t)
+ //~^ HELP consider removing
&mut Either::Two(ref mut _t) => (),
}
match &mut em {
//~^ ERROR cannot move
&mut Either::One(_t) => (),
- //~^ HELP consider removing the `&mut`
- //~| SUGGESTION Either::One(_t)
+ //~^ HELP consider removing
Either::Two(_t) => (),
}
}
+
+struct Testing {
+ a: Option<String>
+}
+
+fn testing(a: &Testing) {
+ let Some(_s) = a.a else {
+ //~^ ERROR cannot move
+ //~| HELP consider borrowing the pattern binding
+ return;
+ };
+}
--> $DIR/simple.rs:38:17
|
LL | let X(_t) = *s;
- | -- ^^ help: consider borrowing here: `&*s`
+ | -- ^^
| |
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let X(_t) = *s;
+LL + let X(_t) = s;
+ |
error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
- --> $DIR/simple.rs:42:30
+ --> $DIR/simple.rs:41:30
|
LL | if let Either::One(_t) = *r { }
- | -- ^^ help: consider borrowing here: `&*r`
+ | -- ^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - if let Either::One(_t) = *r { }
+LL + if let Either::One(_t) = r { }
+ |
error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
- --> $DIR/simple.rs:46:33
+ --> $DIR/simple.rs:44:33
|
LL | while let Either::One(_t) = *r { }
- | -- ^^ help: consider borrowing here: `&*r`
+ | -- ^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - while let Either::One(_t) = *r { }
+LL + while let Either::One(_t) = r { }
+ |
error[E0507]: cannot move out of `r` as enum variant `Two` which is behind a shared reference
- --> $DIR/simple.rs:50:11
+ --> $DIR/simple.rs:47:11
|
LL | match *r {
- | ^^ help: consider borrowing here: `&*r`
+ | ^^
...
LL | Either::One(_t)
| --
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - match *r {
+LL + match r {
+ |
error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
- --> $DIR/simple.rs:57:11
+ --> $DIR/simple.rs:53:11
|
LL | match *r {
- | ^^ help: consider borrowing here: `&*r`
+ | ^^
...
LL | Either::One(_t) => (),
| --
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - match *r {
+LL + match r {
+ |
error[E0507]: cannot move out of `sm` which is behind a mutable reference
- --> $DIR/simple.rs:66:17
+ --> $DIR/simple.rs:61:17
|
LL | let X(_t) = *sm;
- | -- ^^^ help: consider borrowing here: `&*sm`
+ | -- ^^^
| |
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - let X(_t) = *sm;
+LL + let X(_t) = sm;
+ |
error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
- --> $DIR/simple.rs:70:30
+ --> $DIR/simple.rs:64:30
|
LL | if let Either::One(_t) = *rm { }
- | -- ^^^ help: consider borrowing here: `&*rm`
+ | -- ^^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - if let Either::One(_t) = *rm { }
+LL + if let Either::One(_t) = rm { }
+ |
error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
- --> $DIR/simple.rs:74:33
+ --> $DIR/simple.rs:67:33
|
LL | while let Either::One(_t) = *rm { }
- | -- ^^^ help: consider borrowing here: `&*rm`
+ | -- ^^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - while let Either::One(_t) = *rm { }
+LL + while let Either::One(_t) = rm { }
+ |
error[E0507]: cannot move out of `rm` as enum variant `Two` which is behind a mutable reference
- --> $DIR/simple.rs:78:11
+ --> $DIR/simple.rs:70:11
|
LL | match *rm {
- | ^^^ help: consider borrowing here: `&*rm`
+ | ^^^
...
LL | Either::One(_t)
| --
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - match *rm {
+LL + match rm {
+ |
error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
- --> $DIR/simple.rs:85:11
+ --> $DIR/simple.rs:76:11
|
LL | match *rm {
- | ^^^ help: consider borrowing here: `&*rm`
+ | ^^^
...
LL | Either::One(_t) => (),
| --
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - match *rm {
+LL + match rm {
+ |
error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
- --> $DIR/simple.rs:93:11
+ --> $DIR/simple.rs:83:11
|
LL | match *rm {
- | ^^^ help: consider borrowing here: `&*rm`
+ | ^^^
...
LL | Either::One(_t) => (),
| --
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the dereference here
+ |
+LL - match *rm {
+LL + match rm {
+ |
error[E0507]: cannot move out of index of `Vec<X>`
- --> $DIR/simple.rs:102:17
+ --> $DIR/simple.rs:91:17
|
LL | let X(_t) = vs[0];
- | -- ^^^^^ help: consider borrowing here: `&vs[0]`
+ | -- ^^^^^
| |
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let X(_t) = &vs[0];
+ | +
error[E0507]: cannot move out of index of `Vec<Either>`
- --> $DIR/simple.rs:106:30
+ --> $DIR/simple.rs:94:30
|
LL | if let Either::One(_t) = vr[0] { }
- | -- ^^^^^ help: consider borrowing here: `&vr[0]`
+ | -- ^^^^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | if let Either::One(_t) = &vr[0] { }
+ | +
error[E0507]: cannot move out of index of `Vec<Either>`
- --> $DIR/simple.rs:110:33
+ --> $DIR/simple.rs:97:33
|
LL | while let Either::One(_t) = vr[0] { }
- | -- ^^^^^ help: consider borrowing here: `&vr[0]`
+ | -- ^^^^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | while let Either::One(_t) = &vr[0] { }
+ | +
error[E0507]: cannot move out of index of `Vec<Either>`
- --> $DIR/simple.rs:114:11
+ --> $DIR/simple.rs:100:11
|
LL | match vr[0] {
- | ^^^^^ help: consider borrowing here: `&vr[0]`
+ | ^^^^^
...
LL | Either::One(_t)
| --
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &vr[0] {
+ | +
error[E0507]: cannot move out of index of `Vec<Either>`
- --> $DIR/simple.rs:121:11
+ --> $DIR/simple.rs:106:11
|
LL | match vr[0] {
- | ^^^^^ help: consider borrowing here: `&vr[0]`
+ | ^^^^^
...
LL | Either::One(_t) => (),
| --
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &vr[0] {
+ | +
error[E0507]: cannot move out of index of `Vec<X>`
- --> $DIR/simple.rs:130:17
+ --> $DIR/simple.rs:114:17
|
LL | let X(_t) = vsm[0];
- | -- ^^^^^^ help: consider borrowing here: `&vsm[0]`
+ | -- ^^^^^^
| |
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let X(_t) = &vsm[0];
+ | +
error[E0507]: cannot move out of index of `Vec<Either>`
- --> $DIR/simple.rs:134:30
+ --> $DIR/simple.rs:117:30
|
LL | if let Either::One(_t) = vrm[0] { }
- | -- ^^^^^^ help: consider borrowing here: `&vrm[0]`
+ | -- ^^^^^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | if let Either::One(_t) = &vrm[0] { }
+ | +
error[E0507]: cannot move out of index of `Vec<Either>`
- --> $DIR/simple.rs:138:33
+ --> $DIR/simple.rs:120:33
|
LL | while let Either::One(_t) = vrm[0] { }
- | -- ^^^^^^ help: consider borrowing here: `&vrm[0]`
+ | -- ^^^^^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | while let Either::One(_t) = &vrm[0] { }
+ | +
error[E0507]: cannot move out of index of `Vec<Either>`
- --> $DIR/simple.rs:142:11
+ --> $DIR/simple.rs:123:11
|
LL | match vrm[0] {
- | ^^^^^^ help: consider borrowing here: `&vrm[0]`
+ | ^^^^^^
...
LL | Either::One(_t)
| --
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &vrm[0] {
+ | +
error[E0507]: cannot move out of index of `Vec<Either>`
- --> $DIR/simple.rs:149:11
+ --> $DIR/simple.rs:129:11
|
LL | match vrm[0] {
- | ^^^^^^ help: consider borrowing here: `&vrm[0]`
+ | ^^^^^^
...
LL | Either::One(_t) => (),
| --
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &vrm[0] {
+ | +
error[E0507]: cannot move out of index of `Vec<Either>`
- --> $DIR/simple.rs:157:11
+ --> $DIR/simple.rs:136:11
|
LL | match vrm[0] {
- | ^^^^^^ help: consider borrowing here: `&vrm[0]`
+ | ^^^^^^
...
LL | Either::One(_t) => (),
| --
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | match &vrm[0] {
+ | +
error[E0507]: cannot move out of `s` which is behind a shared reference
- --> $DIR/simple.rs:168:18
+ --> $DIR/simple.rs:146:18
|
LL | let &X(_t) = s;
- | ------ ^
- | | |
- | | data moved here
- | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `X(_t)`
+ | -- ^
+ | |
+ | data moved here
+ | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - let &X(_t) = s;
+LL + let X(_t) = s;
+ |
error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
- --> $DIR/simple.rs:172:31
+ --> $DIR/simple.rs:149:31
|
LL | if let &Either::One(_t) = r { }
- | ---------------- ^
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `Either::One(_t)`
+ | -- ^
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - if let &Either::One(_t) = r { }
+LL + if let Either::One(_t) = r { }
+ |
error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
- --> $DIR/simple.rs:176:34
+ --> $DIR/simple.rs:152:34
|
LL | while let &Either::One(_t) = r { }
- | ---------------- ^
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `Either::One(_t)`
+ | -- ^
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - while let &Either::One(_t) = r { }
+LL + while let Either::One(_t) = r { }
+ |
error[E0507]: cannot move out of `r` as enum variant `Two` which is behind a shared reference
- --> $DIR/simple.rs:180:11
+ --> $DIR/simple.rs:155:11
|
LL | match r {
| ^
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
-help: consider removing the `&`
+help: consider removing the borrow
|
-LL ~ Either::One(_t)
-LL +
-LL +
-LL ~ | &Either::Two(_t) => (),
+LL - &Either::One(_t)
+LL + Either::One(_t)
|
error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
- --> $DIR/simple.rs:188:11
+ --> $DIR/simple.rs:162:11
|
LL | match r {
| ^
LL |
LL | &Either::One(_t) => (),
- | ----------------
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `Either::One(_t)`
+ | --
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - &Either::One(_t) => (),
+LL + Either::One(_t) => (),
+ |
error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
- --> $DIR/simple.rs:195:11
+ --> $DIR/simple.rs:168:11
|
LL | match r {
| ^
LL |
LL | &Either::One(_t) => (),
- | ----------------
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `Either::One(_t)`
+ | --
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - &Either::One(_t) => (),
+LL + Either::One(_t) => (),
+ |
error[E0507]: cannot move out of `sm` which is behind a mutable reference
- --> $DIR/simple.rs:207:22
+ --> $DIR/simple.rs:178:22
|
LL | let &mut X(_t) = sm;
- | ---------- ^^
- | | |
- | | data moved here
- | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
- | help: consider removing the `&mut`: `X(_t)`
+ | -- ^^
+ | |
+ | data moved here
+ | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider removing the mutable borrow
+ |
+LL - let &mut X(_t) = sm;
+LL + let X(_t) = sm;
+ |
error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
- --> $DIR/simple.rs:211:35
+ --> $DIR/simple.rs:181:35
|
LL | if let &mut Either::One(_t) = rm { }
- | -------------------- ^^
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&mut`: `Either::One(_t)`
+ | -- ^^
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the mutable borrow
+ |
+LL - if let &mut Either::One(_t) = rm { }
+LL + if let Either::One(_t) = rm { }
+ |
error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
- --> $DIR/simple.rs:215:38
+ --> $DIR/simple.rs:184:38
|
LL | while let &mut Either::One(_t) = rm { }
- | -------------------- ^^
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&mut`: `Either::One(_t)`
+ | -- ^^
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the mutable borrow
+ |
+LL - while let &mut Either::One(_t) = rm { }
+LL + while let Either::One(_t) = rm { }
+ |
error[E0507]: cannot move out of `rm` as enum variant `Two` which is behind a mutable reference
- --> $DIR/simple.rs:219:11
+ --> $DIR/simple.rs:187:11
|
LL | match rm {
| ^^
LL |
LL | &mut Either::One(_t) => (),
| -- data moved here
-...
+LL |
LL | &mut Either::Two(_t) => (),
| -- ...and here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
-help: consider removing the `&mut`
+help: consider removing the mutable borrow
|
-LL | Either::One(_t) => (),
- | ~~~~~~~~~~~~~~~
-help: consider removing the `&mut`
+LL - &mut Either::One(_t) => (),
+LL + Either::One(_t) => (),
+ |
+help: consider removing the mutable borrow
+ |
+LL - &mut Either::Two(_t) => (),
+LL + Either::Two(_t) => (),
|
-LL | Either::Two(_t) => (),
- | ~~~~~~~~~~~~~~~
error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
- --> $DIR/simple.rs:228:11
+ --> $DIR/simple.rs:194:11
|
LL | match rm {
| ^^
LL |
LL | &mut Either::One(_t) => (),
- | --------------------
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&mut`: `Either::One(_t)`
+ | --
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the mutable borrow
+ |
+LL - &mut Either::One(_t) => (),
+LL + Either::One(_t) => (),
+ |
error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
- --> $DIR/simple.rs:235:11
+ --> $DIR/simple.rs:200:11
|
LL | match rm {
| ^^
LL |
LL | &mut Either::One(_t) => (),
- | --------------------
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&mut`: `Either::One(_t)`
+ | --
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the mutable borrow
+ |
+LL - &mut Either::One(_t) => (),
+LL + Either::One(_t) => (),
+ |
error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
- --> $DIR/simple.rs:242:11
+ --> $DIR/simple.rs:206:11
|
LL | match rm {
| ^^
LL |
LL | &mut Either::One(_t) => (),
- | --------------------
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&mut`: `Either::One(_t)`
+ | --
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the mutable borrow
+ |
+LL - &mut Either::One(_t) => (),
+LL + Either::One(_t) => (),
+ |
error[E0507]: cannot move out of a shared reference
- --> $DIR/simple.rs:258:21
+ --> $DIR/simple.rs:220:21
|
LL | let (&X(_t),) = (&x.clone(),);
| -- ^^^^^^^^^^^^^
| |
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | let (&X(ref _t),) = (&x.clone(),);
+ | +++
error[E0507]: cannot move out of a shared reference
- --> $DIR/simple.rs:260:34
+ --> $DIR/simple.rs:223:34
|
LL | if let (&Either::One(_t),) = (&e.clone(),) { }
| -- ^^^^^^^^^^^^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | if let (&Either::One(ref _t),) = (&e.clone(),) { }
+ | +++
error[E0507]: cannot move out of a shared reference
- --> $DIR/simple.rs:262:37
+ --> $DIR/simple.rs:226:37
|
LL | while let (&Either::One(_t),) = (&e.clone(),) { }
| -- ^^^^^^^^^^^^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | while let (&Either::One(ref _t),) = (&e.clone(),) { }
+ | +++
error[E0507]: cannot move out of a shared reference
- --> $DIR/simple.rs:264:11
+ --> $DIR/simple.rs:229:11
|
LL | match (&e.clone(),) {
| ^^^^^^^^^^^^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | (&Either::One(ref _t),)
+ | +++
error[E0507]: cannot move out of a mutable reference
- --> $DIR/simple.rs:272:25
+ --> $DIR/simple.rs:239:25
|
LL | let (&mut X(_t),) = (&mut xm.clone(),);
| -- ^^^^^^^^^^^^^^^^^^
| |
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | let (&mut X(ref _t),) = (&mut xm.clone(),);
+ | +++
error[E0507]: cannot move out of a mutable reference
- --> $DIR/simple.rs:274:38
+ --> $DIR/simple.rs:242:38
|
LL | if let (&mut Either::One(_t),) = (&mut em.clone(),) { }
| -- ^^^^^^^^^^^^^^^^^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | if let (&mut Either::One(ref _t),) = (&mut em.clone(),) { }
+ | +++
error[E0507]: cannot move out of a mutable reference
- --> $DIR/simple.rs:276:41
+ --> $DIR/simple.rs:245:41
|
LL | while let (&mut Either::One(_t),) = (&mut em.clone(),) { }
| -- ^^^^^^^^^^^^^^^^^^
| |
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | while let (&mut Either::One(ref _t),) = (&mut em.clone(),) { }
+ | +++
error[E0507]: cannot move out of a mutable reference
- --> $DIR/simple.rs:278:11
+ --> $DIR/simple.rs:248:11
|
LL | match (&mut em.clone(),) {
| ^^^^^^^^^^^^^^^^^^
LL |
LL | (&mut Either::One(_t),) => (),
| -- data moved here
+LL |
LL | (&mut Either::Two(_t),) => (),
| -- ...and here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
+help: consider borrowing the pattern binding
+ |
+LL | (&mut Either::One(ref _t),) => (),
+ | +++
+help: consider borrowing the pattern binding
+ |
+LL | (&mut Either::Two(ref _t),) => (),
+ | +++
error[E0507]: cannot move out of a shared reference
- --> $DIR/simple.rs:288:18
+ --> $DIR/simple.rs:261:18
|
LL | let &X(_t) = &x;
- | ------ ^^
- | | |
- | | data moved here
- | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `X(_t)`
+ | -- ^^
+ | |
+ | data moved here
+ | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - let &X(_t) = &x;
+LL + let X(_t) = &x;
+ |
error[E0507]: cannot move out of a shared reference
- --> $DIR/simple.rs:292:31
+ --> $DIR/simple.rs:264:31
|
LL | if let &Either::One(_t) = &e { }
- | ---------------- ^^
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `Either::One(_t)`
+ | -- ^^
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - if let &Either::One(_t) = &e { }
+LL + if let Either::One(_t) = &e { }
+ |
error[E0507]: cannot move out of a shared reference
- --> $DIR/simple.rs:296:34
+ --> $DIR/simple.rs:267:34
|
LL | while let &Either::One(_t) = &e { }
- | ---------------- ^^
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `Either::One(_t)`
+ | -- ^^
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - while let &Either::One(_t) = &e { }
+LL + while let Either::One(_t) = &e { }
+ |
error[E0507]: cannot move out of a shared reference
- --> $DIR/simple.rs:300:11
+ --> $DIR/simple.rs:270:11
|
LL | match &e {
| ^^
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
-help: consider removing the `&`
+help: consider removing the borrow
|
-LL ~ Either::One(_t)
-LL +
-LL +
-LL ~ | &Either::Two(_t) => (),
+LL - &Either::One(_t)
+LL + Either::One(_t)
|
error[E0507]: cannot move out of a shared reference
- --> $DIR/simple.rs:308:11
+ --> $DIR/simple.rs:277:11
|
LL | match &e {
| ^^
LL |
LL | &Either::One(_t) => (),
- | ----------------
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `Either::One(_t)`
+ | --
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - &Either::One(_t) => (),
+LL + Either::One(_t) => (),
+ |
error[E0507]: cannot move out of a shared reference
- --> $DIR/simple.rs:315:11
+ --> $DIR/simple.rs:283:11
|
LL | match &e {
| ^^
LL |
LL | &Either::One(_t) => (),
- | ----------------
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `Either::One(_t)`
+ | --
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - &Either::One(_t) => (),
+LL + Either::One(_t) => (),
+ |
error[E0507]: cannot move out of a mutable reference
- --> $DIR/simple.rs:323:22
+ --> $DIR/simple.rs:290:22
|
LL | let &mut X(_t) = &mut xm;
- | ---------- ^^^^^^^
- | | |
- | | data moved here
- | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
- | help: consider removing the `&mut`: `X(_t)`
+ | -- ^^^^^^^
+ | |
+ | data moved here
+ | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider removing the mutable borrow
+ |
+LL - let &mut X(_t) = &mut xm;
+LL + let X(_t) = &mut xm;
+ |
error[E0507]: cannot move out of a mutable reference
- --> $DIR/simple.rs:327:35
+ --> $DIR/simple.rs:293:35
|
LL | if let &mut Either::One(_t) = &mut em { }
- | -------------------- ^^^^^^^
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&mut`: `Either::One(_t)`
+ | -- ^^^^^^^
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the mutable borrow
+ |
+LL - if let &mut Either::One(_t) = &mut em { }
+LL + if let Either::One(_t) = &mut em { }
+ |
error[E0507]: cannot move out of a mutable reference
- --> $DIR/simple.rs:331:38
+ --> $DIR/simple.rs:296:38
|
LL | while let &mut Either::One(_t) = &mut em { }
- | -------------------- ^^^^^^^
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&mut`: `Either::One(_t)`
+ | -- ^^^^^^^
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the mutable borrow
+ |
+LL - while let &mut Either::One(_t) = &mut em { }
+LL + while let Either::One(_t) = &mut em { }
+ |
error[E0507]: cannot move out of a mutable reference
- --> $DIR/simple.rs:335:11
+ --> $DIR/simple.rs:299:11
|
LL | match &mut em {
| ^^^^^^^
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
-help: consider removing the `&mut`
+help: consider removing the mutable borrow
|
-LL ~ Either::One(_t)
-LL +
-LL +
-LL ~ | &mut Either::Two(_t) => (),
+LL - &mut Either::One(_t)
+LL + Either::One(_t)
|
error[E0507]: cannot move out of a mutable reference
- --> $DIR/simple.rs:343:11
+ --> $DIR/simple.rs:306:11
|
LL | match &mut em {
| ^^^^^^^
LL |
LL | &mut Either::One(_t) => (),
- | --------------------
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&mut`: `Either::One(_t)`
+ | --
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the mutable borrow
+ |
+LL - &mut Either::One(_t) => (),
+LL + Either::One(_t) => (),
+ |
error[E0507]: cannot move out of a mutable reference
- --> $DIR/simple.rs:350:11
+ --> $DIR/simple.rs:312:11
|
LL | match &mut em {
| ^^^^^^^
LL |
LL | &mut Either::One(_t) => (),
- | --------------------
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&mut`: `Either::One(_t)`
+ | --
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the mutable borrow
+ |
+LL - &mut Either::One(_t) => (),
+LL + Either::One(_t) => (),
+ |
error[E0507]: cannot move out of a mutable reference
- --> $DIR/simple.rs:357:11
+ --> $DIR/simple.rs:318:11
|
LL | match &mut em {
| ^^^^^^^
LL |
LL | &mut Either::One(_t) => (),
- | --------------------
- | | |
- | | data moved here
- | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
- | help: consider removing the `&mut`: `Either::One(_t)`
+ | --
+ | |
+ | data moved here
+ | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+ |
+help: consider removing the mutable borrow
+ |
+LL - &mut Either::One(_t) => (),
+LL + Either::One(_t) => (),
+ |
error[E0507]: cannot move out of a shared reference
- --> $DIR/simple.rs:202:11
+ --> $DIR/simple.rs:174:11
|
LL | fn f1(&X(_t): &X) { }
| ^^^--^
- | | |
- | | data moved here
- | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
- | help: consider removing the `&`: `X(_t)`
+ | |
+ | data moved here
+ | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider removing the borrow
+ |
+LL - fn f1(&X(_t): &X) { }
+LL + fn f1(X(_t): &X) { }
+ |
error[E0507]: cannot move out of a mutable reference
- --> $DIR/simple.rs:249:11
+ --> $DIR/simple.rs:212:11
|
LL | fn f2(&mut X(_t): &mut X) { }
| ^^^^^^^--^
- | | |
- | | data moved here
- | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
- | help: consider removing the `&mut`: `X(_t)`
+ | |
+ | data moved here
+ | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider removing the mutable borrow
+ |
+LL - fn f2(&mut X(_t): &mut X) { }
+LL + fn f2(X(_t): &mut X) { }
+ |
error[E0507]: cannot move out of a shared reference
- --> $DIR/simple.rs:269:11
+ --> $DIR/simple.rs:235:11
|
LL | fn f3((&X(_t),): (&X,)) { }
| ^^^^--^^^
| |
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | fn f3((&X(ref _t),): (&X,)) { }
+ | +++
error[E0507]: cannot move out of a mutable reference
- --> $DIR/simple.rs:283:11
+ --> $DIR/simple.rs:255:11
|
LL | fn f4((&mut X(_t),): (&mut X,)) { }
| ^^^^^^^^--^^^
| |
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | fn f4((&mut X(ref _t),): (&mut X,)) { }
+ | +++
+
+error[E0507]: cannot move out of `a.a` as enum variant `Some` which is behind a shared reference
+ --> $DIR/simple.rs:331:20
+ |
+LL | let Some(_s) = a.a else {
+ | -- ^^^
+ | |
+ | data moved here
+ | move occurs because `_s` has type `String`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | let Some(ref _s) = a.a else {
+ | +++
-error: aborting due to 60 previous errors
+error: aborting due to 61 previous errors
For more information about this error, try `rustc --explain E0507`.
found type parameter `F`
note: associated function defined here
--> $SRC_DIR/core/src/pin.rs:LL:COL
- |
-LL | pub const fn new(pointer: P) -> Pin<P> {
- | ^^^
error[E0277]: `dyn Future<Output = i32> + Send` cannot be unpinned
--> $DIR/expected-boxed-future-isnt-pinned.rs:19:14
= note: consider using `Box::pin`
note: required by a bound in `Pin::<P>::new`
--> $SRC_DIR/core/src/pin.rs:LL:COL
- |
-LL | impl<P: Deref<Target: Unpin>> Pin<P> {
- | ^^^^^ required by this bound in `Pin::<P>::new`
error[E0277]: `dyn Future<Output = i32> + Send` cannot be unpinned
--> $DIR/expected-boxed-future-isnt-pinned.rs:24:14
= note: consider using `Box::pin`
note: required by a bound in `Pin::<P>::new`
--> $SRC_DIR/core/src/pin.rs:LL:COL
- |
-LL | impl<P: Deref<Target: Unpin>> Pin<P> {
- | ^^^^^ required by this bound in `Pin::<P>::new`
error[E0308]: mismatched types
--> $DIR/expected-boxed-future-isnt-pinned.rs:28:5
found `async` block `[async block@$DIR/expected-boxed-future-isnt-pinned.rs:28:5: 30:6]`
note: function defined here
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
- |
-LL | pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
- | ^^^^^^^^^^^^^^^
help: you need to pin and box this expression
|
LL ~ Box::pin(async {
| `self.v` moved due to this implicit call to `.into_iter()`
| move occurs because `self.v` has type `Vec<u32>`, which does not implement the `Copy` trait
|
-note: this function takes ownership of the receiver `self`, which moves `self.v`
+note: `into_iter` takes ownership of the receiver `self`, which moves `self.v`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
help: consider iterating over a slice of the `Vec<u32>`'s content to avoid moving into the `for` loop
|
LL | for _ in &self.v {
| value moved due to this implicit call to `.into_iter()`
| move occurs because value has type `Vec<&u8>`, which does not implement the `Copy` trait
|
-note: this function takes ownership of the receiver `self`, which moves value
+note: `into_iter` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | fn into_iter(self) -> Self::IntoIter;
- | ^^^^
help: consider iterating over a slice of the `Vec<&u8>`'s content to avoid moving into the `for` loop
|
LL | for loader in &*LOADERS {
|
LL | t.min().unwrap()
| ^^^
+ --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
- ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
- |
-LL | Self: Sized,
- | ----- this has a `Sized` requirement
+ = note: this has a `Sized` requirement
|
= note: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
|
LL | h.finish()
| ^^^^^^ method not found in `DefaultHasher`
+ --> $SRC_DIR/core/src/hash/mod.rs:LL:COL
|
- ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL
- |
-LL | fn finish(&self) -> u64;
- | ------ the method is available for `DefaultHasher` here
+ = note: the method is available for `DefaultHasher` here
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
| ^^^^^^^------ help: remove these generics
| |
| expected 0 generic arguments
- |
-note: associated function defined here, with 0 generic parameters
- --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/ord.rs:LL:COL
- |
-LL | fn simd_gt(self, other: Self) -> Self::Mask;
- | ^^^^^^^
error[E0425]: cannot find function `simd_gt` in this scope
--> $DIR/issue-104287.rs:6:5
= note: required for `String` to implement `Pattern<'_>`
note: required by a bound in `core::str::<impl str>::find`
--> $SRC_DIR/core/src/str/mod.rs:LL:COL
- |
-LL | pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
- | ^^^^^^^^^^^ required by this bound in `core::str::<impl str>::find`
help: consider borrowing here
|
LL | println!("{:?}", line.find(&pattern));
error[E0277]: the trait bound `&[i8]: From<&[u8]>` is not satisfied
- --> $DIR/issue-71394-no-from-impl.rs:3:20
+ --> $DIR/issue-71394-no-from-impl.rs:3:25
|
LL | let _: &[i8] = data.into();
- | ^^^^ ---- required by a bound introduced by this call
- | |
- | the trait `From<&[u8]>` is not implemented for `&[i8]`
+ | ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]`
|
= help: the following other types implement trait `From<T>`:
<[T; LANES] as From<Simd<T, LANES>>>
LL | let _ = 42.into::<Option<_>>();
| ^^^^ expected 0 generic arguments
|
-note: associated function defined here, with 0 generic parameters
- --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
- |
-LL | fn into(self) -> T;
- | ^^^^
help: consider moving this generic argument to the `Into` trait, which takes up to 1 argument
|
LL | let _ = Into::<Option<_>>::into(42);
= note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write`
note: required by a bound in `BufWriter::<W>::new`
--> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
- |
-LL | impl<W: Write> BufWriter<W> {
- | ^^^^^ required by this bound in `BufWriter::<W>::new`
error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
--> $DIR/mut-borrow-needed-by-trait.rs:17:14
= note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write`
note: required by a bound in `BufWriter`
--> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
- |
-LL | pub struct BufWriter<W: Write> {
- | ^^^^^ required by this bound in `BufWriter`
-error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn std::io::Write>`, but its trait bounds were not satisfied
+error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, but its trait bounds were not satisfied
--> $DIR/mut-borrow-needed-by-trait.rs:21:5
|
LL | writeln!(fp, "hello world").unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn std::io::Write>` due to unsatisfied trait bounds
- |
- ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds
+ --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
|
-LL | pub struct BufWriter<W: Write> {
- | ------------------------------ doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write`
+ = note: doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write`
|
= note: the following trait bounds were not satisfied:
`&dyn std::io::Write: std::io::Write`
| |
| data moved here
| move occurs because `c` has type `Option<String>`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | (None, &ref c) => &c.unwrap(),
+ | +++
error: aborting due to previous error
| help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
| move occurs because `selection.1` has type `Option<String>`, which does not implement the `Copy` trait
|
-note: this function takes ownership of the receiver `self`, which moves `selection.1`
+note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `selection.1`
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | pub const fn unwrap(self) -> T {
- | ^^^^
error[E0507]: cannot move out of `selection.1` which is behind a shared reference
--> $DIR/option-content-move.rs:27:20
| help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
| move occurs because `selection.1` has type `Result<String, String>`, which does not implement the `Copy` trait
|
-note: this function takes ownership of the receiver `self`, which moves `selection.1`
+note: `Result::<T, E>::unwrap` takes ownership of the receiver `self`, which moves `selection.1`
--> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | pub fn unwrap(self) -> T
- | ^^^^
error: aborting due to 2 previous errors
|
LL | struct Wrapper<T>(T);
| ^^^^^^^^^^^^^^^^^ must implement `Add<_>`
-note: the following trait must be implemented
+note: the trait `Add` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | pub trait Add<Rhs = Self> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
|
LL | fn qux<T>(a: Wrapper<T>, b: T) -> T where Wrapper<T>: Add<T, Output = T> {
found closure `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]`
note: associated function defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | pub const fn unwrap_or(self, default: T) -> T
- | ^^^^^^^^^
help: try calling `unwrap_or_else` instead
|
LL | let _s = y.unwrap_or_else(|| x.split('.').nth(1).unwrap());
|
note: required by a bound in `BufReader::<R>::new`
--> $SRC_DIR/std/src/io/buffered/bufreader.rs:LL:COL
- |
-LL | impl<R: Read> BufReader<R> {
- | ^^^^ required by this bound in `BufReader::<R>::new`
help: consider removing the leading `&`-reference
|
LL - let mut stream_reader = BufReader::new(&stream);
|
LL | stream_reader.read_until(b'\n', &mut buffer).expect("Reading into buffer failed");
| ^^^^^^^^^^ method cannot be called on `BufReader<&T>` due to unsatisfied trait bounds
+ --> $SRC_DIR/std/src/io/buffered/bufreader.rs:LL:COL
|
- ::: $SRC_DIR/std/src/io/buffered/bufreader.rs:LL:COL
- |
-LL | pub struct BufReader<R> {
- | ----------------------- doesn't satisfy `BufReader<&T>: BufRead`
+ = note: doesn't satisfy `BufReader<&T>: BufRead`
|
= note: the following trait bounds were not satisfied:
`&T: std::io::Read`
|
LL | let _i: i16 = 0_i32.try_into().unwrap();
| ^^^^^^^^ method not found in `i32`
+ --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
- ::: $SRC_DIR/core/src/convert/mod.rs:LL:COL
- |
-LL | fn try_into(self) -> Result<T, Self::Error>;
- | -------- the method is available for `i32` here
+ = note: the method is available for `i32` here
|
= help: items from traits can only be used if the trait is in scope
= note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
LL | let _: Vec<A:B> = A::B;
| ^^^ expected at least 1 generic argument
|
-note: struct defined here, with at least 1 generic parameter: `T`
- --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- |
-LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
- | ^^^ -
help: add missing generic argument
|
LL | let _: Vec<T, A:B> = A::B;
|
LL | struct Foo<T>(dyn SendEqAlias<T>);
| ^^^^^^^^^^^^^^ missing reference to `Rhs`
+ --> $SRC_DIR/core/src/cmp.rs:LL:COL
|
- ::: $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub trait PartialEq<Rhs: ?Sized = Self> {
- | --------------------------------------- type parameter `Rhs` must be specified for this
+ = note: type parameter `Rhs` must be specified for this
|
= note: because of the default `Self` reference, type parameters must be specified on object types
|
LL | struct Bar<T>(dyn SendEqAlias<T>, T);
| ^^^^^^^^^^^^^^ missing reference to `Rhs`
+ --> $SRC_DIR/core/src/cmp.rs:LL:COL
|
- ::: $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub trait PartialEq<Rhs: ?Sized = Self> {
- | --------------------------------------- type parameter `Rhs` must be specified for this
+ = note: type parameter `Rhs` must be specified for this
|
= note: because of the default `Self` reference, type parameters must be specified on object types
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
-LL | pub trait Eq: PartialEq<Self> {
- | ^^^^^^^^^^^^^^^ the trait cannot be made into an object because it uses `Self` as a type parameter
+ = note: the trait cannot be made into an object because it uses `Self` as a type parameter
error[E0191]: the value of the associated type `Item` (from trait `Iterator`) must be specified
--> $DIR/object-fail.rs:9:17
impl Foo for IntoIter<i32> {
type Key = u32;
- //~^ ERROR expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
+ //~^ ERROR expected `IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
}
fn main() {}
-error[E0271]: expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
+error[E0271]: expected `IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
--> $DIR/assoc-type-in-superbad.rs:12:16
|
LL | type Key = u32;
|
LL | struct Foo<T> where T: Bar, <T as Bar>::Baz: String {
| ^^^^^^ not a trait
+ --> $SRC_DIR/alloc/src/string.rs:LL:COL
|
- ::: $SRC_DIR/alloc/src/string.rs:LL:COL
- |
-LL | pub trait ToString {
- | ------------------ similarly named trait `ToString` defined here
+ = note: similarly named trait `ToString` defined here
|
help: constrain the associated type to `String`
|
|
LL | struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String {
| ^^^^^^ not a trait
+ --> $SRC_DIR/alloc/src/string.rs:LL:COL
|
- ::: $SRC_DIR/alloc/src/string.rs:LL:COL
- |
-LL | pub trait ToString {
- | ------------------ similarly named trait `ToString` defined here
+ = note: similarly named trait `ToString` defined here
|
help: constrain the associated type to `String`
|
|
LL | fn foo<T: Bar>(_: T) where <T as Bar>::Baz: String {
| ^^^^^^ not a trait
+ --> $SRC_DIR/alloc/src/string.rs:LL:COL
|
- ::: $SRC_DIR/alloc/src/string.rs:LL:COL
- |
-LL | pub trait ToString {
- | ------------------ similarly named trait `ToString` defined here
+ = note: similarly named trait `ToString` defined here
|
help: constrain the associated type to `String`
|
|
LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String {
| ^^^^^^ not a trait
+ --> $SRC_DIR/alloc/src/string.rs:LL:COL
|
- ::: $SRC_DIR/alloc/src/string.rs:LL:COL
- |
-LL | pub trait ToString {
- | ------------------ similarly named trait `ToString` defined here
+ = note: similarly named trait `ToString` defined here
|
help: constrain the associated type to `String`
|
|
LL | fn issue_95327() where <u8 as Unresolved>::Assoc: String {}
| ^^^^^^ help: a trait with a similar name exists: `ToString`
+ --> $SRC_DIR/alloc/src/string.rs:LL:COL
|
- ::: $SRC_DIR/alloc/src/string.rs:LL:COL
- |
-LL | pub trait ToString {
- | ------------------ similarly named trait `ToString` defined here
+ = note: similarly named trait `ToString` defined here
error: aborting due to 6 previous errors
= help: the trait `Sized` is not implemented for `dyn Trait`
note: required by a bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- |
-LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
- | ^ required by this bound in `Vec`
error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
--> $DIR/bad-sized.rs:4:37
= help: the trait `Sized` is not implemented for `dyn Trait`
note: required by a bound in `Vec::<T>::new`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- |
-LL | impl<T> Vec<T> {
- | ^ required by this bound in `Vec::<T>::new`
error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
--> $DIR/bad-sized.rs:4:37
= help: the trait `Sized` is not implemented for `dyn Trait`
note: required by a bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- |
-LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
- | ^ required by this bound in `Vec`
error: aborting due to 4 previous errors
where T: ?Sized;
note: required by a bound in `HashMap::<K, V, S>::get`
--> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
- |
-LL | K: Borrow<Q>,
- | ^^^^^^^^^ required by this bound in `HashMap::<K, V, S>::get`
help: consider specifying the generic argument
|
LL | opts.get::<Q>(opt.as_ref());
| |
| required by a bound introduced by this call
|
- = note: cannot satisfy `u32: From<_>`
+ = note: multiple `impl`s satisfying `u32: From<_>` found in the following crates: `core`, `std`:
+ - impl From<Ipv4Addr> for u32;
+ - impl From<NonZeroU32> for u32;
+ - impl From<bool> for u32;
+ - impl From<char> for u32;
+ - impl From<u16> for u32;
+ - impl From<u8> for u32;
+ - impl<T> From<!> for T;
+ - impl<T> From<T> for T;
help: try using a fully qualified path to specify the expected types
|
LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<T>>::into(0u32))).collect();
LL | T: FnMut(&'a ()),
| ^^^^^^^^^^^^^
|
- = note: cannot satisfy `T: FnMut<(&'a (),)>`
+note: multiple `impl`s or `where` clauses satisfying `T: FnMut<(&'a (),)>` found
+ --> $DIR/issue-85735.rs:7:8
+ |
+LL | T: FnMut(&'a ()),
+ | ^^^^^^^^^^^^^
+LL |
+LL | T: FnMut(&'b ()),
+ | ^^^^^^^^^^^^^
error: aborting due to previous error
error[E0277]: the trait bound `String: From<impl ToString>` is not satisfied
- --> $DIR/issue-97576.rs:8:18
+ --> $DIR/issue-97576.rs:8:22
|
LL | bar: bar.into(),
- | ^^^ ---- required by a bound introduced by this call
- | |
- | the trait `From<impl ToString>` is not implemented for `String`
+ | ^^^^ the trait `From<impl ToString>` is not implemented for `String`
|
= note: required for `impl ToString` to implement `Into<String>`
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`mutual_recursion_issue_75860`)
note: required by a bound in `Option`
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | pub enum Option<T> {
- | ^ required by this bound in `Option`
error: aborting due to previous error
= note: required for `&NoToSocketAddrs` to implement `ToSocketAddrs`
note: required by a bound in `TcpListener::bind`
--> $SRC_DIR/std/src/net/tcp.rs:LL:COL
- |
-LL | pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
- | ^^^^^^^^^^^^^ required by this bound in `TcpListener::bind`
help: consider dereferencing here
|
LL | let _errors = TcpListener::bind(&*bad);
= note: required for `&char` to implement `Pattern<'_>`
note: required by a bound in `core::str::<impl str>::contains`
--> $SRC_DIR/core/src/str/mod.rs:LL:COL
- |
-LL | pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
- | ^^^^^^^^^^^ required by this bound in `core::str::<impl str>::contains`
help: consider dereferencing here
|
LL | .filter(|c| "aeiou".contains(*c))
--- /dev/null
+// run-rustfix
+
+struct TargetStruct;
+
+impl From<usize> for TargetStruct {
+ fn from(_unchecked: usize) -> Self {
+ TargetStruct
+ }
+}
+
+fn main() {
+ let a = &3;
+ let _b: TargetStruct = (*a).into(); //~ ERROR the trait bound `TargetStruct: From<&{integer}>` is not satisfied
+}
--- /dev/null
+// run-rustfix
+
+struct TargetStruct;
+
+impl From<usize> for TargetStruct {
+ fn from(_unchecked: usize) -> Self {
+ TargetStruct
+ }
+}
+
+fn main() {
+ let a = &3;
+ let _b: TargetStruct = a.into(); //~ ERROR the trait bound `TargetStruct: From<&{integer}>` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `TargetStruct: From<&{integer}>` is not satisfied
+ --> $DIR/suggest-dereferencing-receiver-argument.rs:13:30
+ |
+LL | let _b: TargetStruct = a.into();
+ | ^^^^ the trait `From<&{integer}>` is not implemented for `TargetStruct`
+ |
+ = note: required for `&{integer}` to implement `Into<TargetStruct>`
+help: consider dereferencing here
+ |
+LL | let _b: TargetStruct = (*a).into();
+ | ++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
|
note: required by a bound in `std::mem::size_of`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | pub const fn size_of<T>() -> usize {
- | ^ required by this bound in `size_of`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - fn check<T: Iterator, U: ?Sized>() {
| ^^^^
note: required by a bound in `std::mem::size_of`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | pub const fn size_of<T>() -> usize {
- | ^ required by this bound in `size_of`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - fn check<T: Iterator, U: ?Sized>() {
= help: the trait `Sized` is not implemented for `[T]`
note: required by a bound in `std::mem::size_of`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | pub const fn size_of<T>() -> usize {
- | ^ required by this bound in `size_of`
error[E0277]: the size for values of type `[&U]` cannot be known at compilation time
--> $DIR/suggest-where-clause.rs:31:20
= help: the trait `Sized` is not implemented for `[&U]`
note: required by a bound in `std::mem::size_of`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | pub const fn size_of<T>() -> usize {
- | ^ required by this bound in `size_of`
error: aborting due to 7 previous errors
LL | | ASSUME_VALIDITY,
LL | | ASSUME_VISIBILITY,
| |_____________________________- help: remove these generic arguments
- |
-note: trait defined here, with at most 3 generic parameters: `Src`, `Context`, `ASSUME`
- --> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL
- |
-LL | pub unsafe trait BikeshedIntrinsicFrom<Src, Context, const ASSUME: Assume = { Assume::NOTHING }>
- | ^^^^^^^^^^^^^^^^^^^^^ --- ------- ------------------------------------------
error: aborting due to previous error
found struct `Vec<String>`
note: associated function defined here
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- |
-LL | pub fn push(&mut self, value: T) {
- | ^^^^
help: remove the extra argument
|
LL | groups.push(/* (Vec<String>, Vec<Process>) */);
|
note: associated function defined here
--> $SRC_DIR/alloc/src/collections/vec_deque/mod.rs:LL:COL
- |
-LL | pub fn push_back(&mut self, value: T) {
- | ^^^^^^^^^
help: wrap these arguments in parentheses to construct a tuple
|
LL | self.acc.push_back((self.current_provides, self.current_requires));
|
help: consider giving this closure parameter an explicit type
|
-LL | |x: _| x.len()
- | +++
+LL | |x: /* Type */| x.len()
+ | ++++++++++++
error[E0282]: type annotations needed
--> $DIR/closures_in_branches.rs:21:10
|
help: consider giving this closure parameter an explicit type
|
-LL | |x: _| x.len()
- | +++
+LL | |x: /* Type */| x.len()
+ | ++++++++++++
error: aborting due to 2 previous errors
impl Foo for () {
type Bar = std::vec::IntoIter<u32>;
- //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
+ //~^ ERROR expected `IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
}
fn incoherent() {
-error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
+error[E0271]: expected `IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
--> $DIR/issue-57961.rs:10:16
|
LL | type X = impl Sized;
LL | input_cells: Vec::new()
| ^^^ expected at least 1 generic argument
|
-note: struct defined here, with at least 1 generic parameter: `T`
- --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- |
-LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
- | ^^^ -
help: add missing generic argument
|
LL | input_cells: Vec<T>::new()
|
LL | fn foo<T: Into<String>>(x: i32) {}
| ^^^^^^^^^^^^ required by this bound in `foo`
-help: consider specifying the type argument in the function call
+help: consider specifying the generic argument
|
LL | foo::<T>(42);
| +++++
|
note: associated function defined here
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
- |
-LL | pub fn with_capacity(capacity: usize) -> Self {
- | ^^^^^^^^^^^^^
help: remove the extra argument
|
LL | let x: Vec::with_capacity(10);
|
LL | struct Z;
| ^^^^^^^^ must implement `std::ops::Neg`
-note: the following trait must be implemented
+note: the trait `std::ops::Neg` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | pub trait Neg {
- | ^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/type-ascription-precedence.rs:45:5
LL | where &'a T : Foo,
| ^^^
|
- = note: cannot satisfy `&'a T: Foo`
+note: multiple `impl`s or `where` clauses satisfying `&'a T: Foo` found
+ --> $DIR/issue-40294.rs:6:19
+ |
+LL | where &'a T : Foo,
+ | ^^^
+LL | &'b T : Foo
+ | ^^^
error: aborting due to previous error
|
help: consider giving this closure parameter an explicit type
|
-LL | let x = |_: _| {};
- | +++
+LL | let x = |_: /* Type */| {};
+ | ++++++++++++
error[E0282]: type annotations needed
--> $DIR/unknown_type_for_closure.rs:10:14
|
help: consider giving this closure parameter an explicit type
|
-LL | let _ = |a: _, b: _| -> _ { 0 };
- | +++
+LL | let _ = |a: /* Type */, b: _| -> _ { 0 };
+ | ++++++++++++
error: aborting due to 5 previous errors
error: reached the type-length limit while instantiating `std::mem::drop::<Option<((((..., ..., ...), ..., ...), ..., ...), ..., ...)>>`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
-LL | pub fn drop<T>(_x: T) {}
- | ^^^^^^^^^^^^^^^^^^^^^
- |
= help: consider adding a `#![type_length_limit="10"]` attribute to your crate
= note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt'
|
LL | nc.clone()
| ^^
+help: consider annotating `NotClone` with `#[derive(Clone)]`
+ |
+LL | #[derive(Clone)]
+ |
error: aborting due to previous error
found unit type `()`
note: tuple variant defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^
help: try wrapping the expression in `Some`
|
LL | fn main() { test(Ok(Some(()))); }
| |
| expected 2 generic arguments
|
-note: enum defined here, with 2 generic parameters: `T`, `E`
- --> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | pub enum Result<T, E> {
- | ^^^^^^ - -
help: add missing generic argument
|
LL | pub fn run() -> Result<_, E> {
| |
| expected 2 generic arguments
|
-note: enum defined here, with 2 generic parameters: `T`, `E`
- --> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | pub enum Result<T, E> {
- | ^^^^^^ - -
help: add missing generic argument
|
LL | pub fn interact(&mut self) -> Result<_, E> {
|
LL | impl F {
| ^ help: a trait with a similar name exists: `Fn`
+ --> $SRC_DIR/core/src/ops/function.rs:LL:COL
|
- ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
- | -------------------------------------- similarly named trait `Fn` defined here
+ = note: similarly named trait `Fn` defined here
error[E0412]: cannot find type `TestResult` in this scope
--> $DIR/issue-83693.rs:9:22
found type `{integer}`
note: associated function defined here
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
- | ^^^^^^^^^
error: aborting due to 2 previous errors
--- /dev/null
+//check-fail
+
+#![crate_type="lib"]
+
+fn r({) {
+ Ok { //~ ERROR mismatched types [E0308]
+ d..||_=m
+ }
+}
+//~^^^^^ ERROR expected parameter name, found `{`
+//~| ERROR expected one of `,`, `:`, or `}`, found `..`
+//~^^^^^ ERROR cannot find value `d` in this scope [E0425]
+//~| ERROR cannot find value `m` in this scope [E0425]
+//~| ERROR variant `Result<_, _>::Ok` has no field named `d` [E0559]
--- /dev/null
+error: expected parameter name, found `{`
+ --> $DIR/issue-92481.rs:5:6
+ |
+LL | fn r({) {
+ | ^ expected parameter name
+
+error: expected one of `,`, `:`, or `}`, found `..`
+ --> $DIR/issue-92481.rs:5:6
+ |
+LL | fn r({) {
+ | ^ unclosed delimiter
+LL | Ok {
+LL | d..||_=m
+ | -^
+ | |
+ | help: `}` may belong here
+
+error[E0425]: cannot find value `d` in this scope
+ --> $DIR/issue-92481.rs:7:9
+ |
+LL | d..||_=m
+ | ^ not found in this scope
+
+error[E0425]: cannot find value `m` in this scope
+ --> $DIR/issue-92481.rs:7:16
+ |
+LL | d..||_=m
+ | ^ not found in this scope
+
+error[E0559]: variant `Result<_, _>::Ok` has no field named `d`
+ --> $DIR/issue-92481.rs:7:9
+ |
+LL | d..||_=m
+ | ^ field does not exist
+ --> $SRC_DIR/core/src/result.rs:LL:COL
+ |
+ = note: `Result<_, _>::Ok` defined here
+ |
+help: `Result<_, _>::Ok` is a tuple variant, use the appropriate syntax
+ |
+LL | Result<_, _>::Ok(/* fields */)
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/issue-92481.rs:6:5
+ |
+LL | fn r({) {
+ | - help: a return type might be missing here: `-> _`
+LL | / Ok {
+LL | | d..||_=m
+LL | | }
+ | |_____^ expected `()`, found enum `Result`
+ |
+ = note: expected unit type `()`
+ found enum `Result<_, _>`
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0308, E0425, E0559.
+For more information about an error, try `rustc --explain E0308`.
|
note: tuple variant defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^^^
help: remove the extra argument
|
LL | let _ = Some(3);
|
note: tuple variant defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^
help: remove the extra arguments
|
LL | let _ = Ok(3);
|
note: tuple variant defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ^^
help: provide the argument
|
LL | let _ = Ok(/* value */);
| ^^^^--- help: remove these generics
| |
| expected 0 generic arguments
- |
-note: trait defined here, with 0 generic parameters
- --> $SRC_DIR/core/src/marker.rs:LL:COL
- |
-LL | pub trait Copy: Clone {
- | ^^^^
error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
--> $DIR/typeck-builtin-bound-type-parameters.rs:4:14
| ^^^^---------- help: remove these generics
| |
| expected 0 generic arguments
- |
-note: trait defined here, with 0 generic parameters
- --> $SRC_DIR/core/src/marker.rs:LL:COL
- |
-LL | pub trait Copy: Clone {
- | ^^^^
error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
--> $DIR/typeck-builtin-bound-type-parameters.rs:7:21
| ^^^^--- help: remove these generics
| |
| expected 0 generic arguments
- |
-note: trait defined here, with 0 generic parameters
- --> $SRC_DIR/core/src/marker.rs:LL:COL
- |
-LL | pub trait Copy: Clone {
- | ^^^^
error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
--> $DIR/typeck-builtin-bound-type-parameters.rs:10:25
| ^^^^---- help: remove these generics
| |
| expected 0 lifetime arguments
- |
-note: trait defined here, with 0 lifetime parameters
- --> $SRC_DIR/core/src/marker.rs:LL:COL
- |
-LL | pub trait Copy: Clone {
- | ^^^^
error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
--> $DIR/typeck-builtin-bound-type-parameters.rs:13:15
| ^^^^ -- help: remove this lifetime argument
| |
| expected 0 lifetime arguments
- |
-note: trait defined here, with 0 lifetime parameters
- --> $SRC_DIR/core/src/marker.rs:LL:COL
- |
-LL | pub trait Copy: Clone {
- | ^^^^
error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
--> $DIR/typeck-builtin-bound-type-parameters.rs:13:15
| ^^^^ - help: remove this generic argument
| |
| expected 0 generic arguments
- |
-note: trait defined here, with 0 generic parameters
- --> $SRC_DIR/core/src/marker.rs:LL:COL
- |
-LL | pub trait Copy: Clone {
- | ^^^^
error: aborting due to 6 previous errors
|
note: associated function defined here
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | fn add(self, rhs: Rhs) -> Self::Output;
- | ^^^
help: change the type of the numeric literal from `u32` to `i32`
|
LL | <i32 as Add<i32>>::add(1i32, 2);
|
note: associated function defined here
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
- |
-LL | fn add(self, rhs: Rhs) -> Self::Output;
- | ^^^
help: change the type of the numeric literal from `u32` to `i32`
|
LL | <i32 as Add<i32>>::add(1, 2i32);
|
note: required by a bound in `Fn`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
- |
-LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
- | ^^^^^ required by this bound in `Fn`
error: aborting due to previous error
-error[E0599]: no method named `call` found for closure `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]` in the current scope
+error[E0599]: no method named `call` found for closure `[closure@unboxed-closures-static-call-wrong-trait.rs:6:26]` in the current scope
--> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10
|
LL | mut_.call((0, ));
- | ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]`
+ | ^^^^ method not found in `[closure@unboxed-closures-static-call-wrong-trait.rs:6:26]`
error: aborting due to previous error
|
note: `Result<u32, &Void>` defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
+ ::: $SRC_DIR/core/src/result.rs:LL:COL
|
-LL | pub enum Result<T, E> {
- | ---------------------
-...
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | ^^^ not covered
+ = note: not covered
= note: the matched value is of type `Result<u32, &Void>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
|
note: `Result<u32, Void>` defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
+ ::: $SRC_DIR/core/src/result.rs:LL:COL
|
-LL | pub enum Result<T, E> {
- | ---------------------
-...
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | ^^^ not covered
+ = note: not covered
= note: the matched value is of type `Result<u32, Void>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Result<u32, Void>` defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
+ ::: $SRC_DIR/core/src/result.rs:LL:COL
|
-LL | pub enum Result<T, E> {
- | ---------------------
-...
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | ^^^ not covered
+ = note: not covered
= note: the matched value is of type `Result<u32, Void>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
--> $DIR/union-borrow-move-parent-sibling.rs:62:13
|
LL | let a = u.x.0;
- | ^^^^^
- | |
- | move occurs because value has type `(MockVec<u8>, MockVec<u8>)`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&u.x.0`
+ | ^^^^^ move occurs because value has type `(MockVec<u8>, MockVec<u8>)`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let a = &u.x.0;
+ | +
error[E0382]: use of moved value: `u`
--> $DIR/union-borrow-move-parent-sibling.rs:64:13
--> $DIR/union-borrow-move-parent-sibling.rs:76:13
|
LL | let a = (u.x.0).0;
- | ^^^^^^^^^
- | |
- | move occurs because value has type `MockVec<u8>`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&(u.x.0).0`
+ | ^^^^^^^^^ move occurs because value has type `MockVec<u8>`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let a = &(u.x.0).0;
+ | +
error[E0382]: use of moved value: `u`
--> $DIR/union-borrow-move-parent-sibling.rs:78:13
--> $DIR/union-borrow-move-parent-sibling.rs:62:13
|
LL | let a = u.x.0;
- | ^^^^^
- | |
- | move occurs because value has type `(MockVec<u8>, MockVec<u8>)`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&u.x.0`
+ | ^^^^^ move occurs because value has type `(MockVec<u8>, MockVec<u8>)`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let a = &u.x.0;
+ | +
error[E0382]: use of moved value: `u`
--> $DIR/union-borrow-move-parent-sibling.rs:64:13
--> $DIR/union-borrow-move-parent-sibling.rs:76:13
|
LL | let a = (u.x.0).0;
- | ^^^^^^^^^
- | |
- | move occurs because value has type `MockVec<u8>`, which does not implement the `Copy` trait
- | help: consider borrowing here: `&(u.x.0).0`
+ | ^^^^^^^^^ move occurs because value has type `MockVec<u8>`, which does not implement the `Copy` trait
+ |
+help: consider borrowing here
+ |
+LL | let a = &(u.x.0).0;
+ | +
error[E0382]: use of moved value: `u`
--> $DIR/union-borrow-move-parent-sibling.rs:78:13
|
note: required by a bound in `AssertParamIsCopy`
--> $SRC_DIR/core/src/clone.rs:LL:COL
- |
-LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> {
- | ^^^^ required by this bound in `AssertParamIsCopy`
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `U1` with `#[derive(Copy)]`
|
|
note: required by a bound in `AssertParamIsCopy`
--> $SRC_DIR/core/src/clone.rs:LL:COL
- |
-LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> {
- | ^^^^ required by this bound in `AssertParamIsCopy`
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `U1` with `#[derive(Copy)]`
|
|
note: required by a bound in `AssertParamIsEq`
--> $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
- | ^^ required by this bound in `AssertParamIsEq`
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]`
|
|
note: required by a bound in `AssertParamIsEq`
--> $SRC_DIR/core/src/cmp.rs:LL:COL
- |
-LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
- | ^^ required by this bound in `AssertParamIsEq`
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]`
|
...
LL | let _z = y.clone();
| ^^^^^ method cannot be called on `Box<dyn Foo>` due to unsatisfied trait bounds
- |
+ --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
|
-LL | / pub struct Box<
-LL | | T: ?Sized,
-LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
-LL | | >(Unique<T>, A);
- | |_- doesn't satisfy `Box<dyn Foo>: Clone`
+ = note: doesn't satisfy `Box<dyn Foo>: Clone`
|
= note: the following trait bounds were not satisfied:
`dyn Foo: Sized`
...
LL | let _j = i.clone();
| ^^^^^ method cannot be called on `Box<R>` due to unsatisfied trait bounds
- |
+ --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
|
-LL | / pub struct Box<
-LL | | T: ?Sized,
-LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
-LL | | >(Unique<T>, A);
- | |_- doesn't satisfy `Box<R>: Clone`
+ = note: doesn't satisfy `Box<R>: Clone`
|
= note: the following trait bounds were not satisfied:
`R: Clone`
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
- |
-LL | fn not(self) -> Self::Output;
- | ^^^^
help: consider cloning the value if the performance cost is acceptable
|
LL | !x.clone();
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
- |
-LL | fn not(self) -> Self::Output;
- | ^^^^
error[E0507]: cannot move out of `*n` which is behind a shared reference
--> $DIR/unop-move-semantics.rs:26:6
LL | println!("{}", &y);
| ^^ value borrowed here after move
|
-note: this function takes ownership of the receiver `self`, which moves `y`
+note: `Foo::foo` takes ownership of the receiver `self`, which moves `y`
--> $DIR/borrow-after-move.rs:5:12
|
LL | fn foo(self) -> String;
LL | y.foo();
| ^ value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `y`
+note: `Foo::foo` takes ownership of the receiver `self`, which moves `y`
--> $DIR/double-move.rs:5:12
|
LL | fn foo(self) -> String;
error[E0277]: the trait bound `dyn Foo: CastTo<[i32]>` is not satisfied
- --> $DIR/issue-71659.rs:30:13
+ --> $DIR/issue-71659.rs:30:15
|
LL | let x = x.cast::<[i32]>();
- | ^ ---- required by a bound introduced by this call
- | |
- | the trait `CastTo<[i32]>` is not implemented for `dyn Foo`
+ | ^^^^ the trait `CastTo<[i32]>` is not implemented for `dyn Foo`
|
note: required by a bound in `Cast::cast`
--> $DIR/issue-71659.rs:19:15
LL | return self.x;
| ^^^^^^ value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `self`
+note: `S::bar` takes ownership of the receiver `self`, which moves `self`
--> $DIR/use-after-move-self-based-on-type.rs:15:16
|
LL | pub fn bar(self) {}
LL | return *self.x;
| ^^^^^^^ value used here after move
|
-note: this function takes ownership of the receiver `self`, which moves `self`
+note: `S::bar` takes ownership of the receiver `self`, which moves `self`
--> $DIR/use-after-move-self.rs:13:16
|
LL | pub fn bar(self) {}
LL | println!("{}", start.test);
| ^^^^^^^^^^ value borrowed here after move
|
-note: this function takes ownership of the receiver `self`, which moves `start`
+note: `Mine::make_string_bar` takes ownership of the receiver `self`, which moves `start`
--> $DIR/walk-struct-literal-with.rs:7:28
|
LL | fn make_string_bar(mut self) -> Mine{
= note: required for `&T` to implement `IntoIterator`
note: required by a bound in `Flatten`
--> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL
- |
-LL | pub struct Flatten<I: Iterator<Item: IntoIterator>> {
- | ^^^^^^^^^^^^ required by this bound in `Flatten`
error[E0277]: `&T` is not an iterator
--> $DIR/hir-wf-check-erase-regions.rs:10:27
= note: required for `&T` to implement `IntoIterator`
note: required by a bound in `Flatten`
--> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL
- |
-LL | pub struct Flatten<I: Iterator<Item: IntoIterator>> {
- | ^^^^^^^^^^^^ required by this bound in `Flatten`
error: aborting due to 2 previous errors
= help: the trait `Sized` is not implemented for `[u8]`
note: required by a bound in `Option`
--> $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | pub enum Option<T> {
- | ^ required by this bound in `Option`
error: aborting due to previous error
-Subproject commit 70898e522116f6c23971e2a554b2dc85fd4c84cd
+Subproject commit cc0a320879c17207bbfb96b5d778e28a2c62030d
let mut projection_ty = projection_predicate.projection_ty;
loop {
match projection_ty.self_ty().kind() {
- ty::Projection(inner_projection_ty) => {
+ ty::Alias(ty::Projection, inner_projection_ty) => {
projection_ty = *inner_projection_ty;
}
ty::Param(param_ty) => {
&& let Some(term_ty) = projection_predicate.term.ty()
&& let ty::Param(term_param_ty) = term_ty.kind()
{
- let item_def_id = projection_predicate.projection_ty.item_def_id;
+ let item_def_id = projection_predicate.projection_ty.def_id;
let assoc_item = cx.tcx.associated_item(item_def_id);
let projection = cx.tcx
.mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, []));
continue;
},
ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
- ty::Projection(_) if ty.has_non_region_param() => TyPosition::new_deref_stable_for_result(precedence, ty),
- ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Opaque(..) | ty::Placeholder(_) | ty::Dynamic(..) => {
+ ty::Alias(ty::Projection, _) if ty.has_non_region_param() => TyPosition::new_deref_stable_for_result(precedence, ty),
+ ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Alias(ty::Opaque, ..) | ty::Placeholder(_) | ty::Dynamic(..) => {
Position::ReborrowStable(precedence).into()
},
ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
| ty::Closure(..)
| ty::Never
| ty::Tuple(_)
- | ty::Projection(_) => {
+ | ty::Alias(ty::Projection, _) => {
Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds())).into()
},
};
use rustc_middle::traits::Reveal;
use rustc_middle::ty::{
self, Binder, BoundConstness, Clause, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate,
- TraitRef, Ty, TyCtxt,
+ Ty, TyCtxt,
};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain(
params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate {
- trait_ref: TraitRef::new(
+ trait_ref: tcx.mk_trait_ref(
eq_trait_id,
- tcx.mk_substs(std::iter::once(tcx.mk_param_from_def(param))),
+ [tcx.mk_param_from_def(param)],
),
constness: BoundConstness::NotConst,
polarity: ImplPolarity::Positive,
use rustc_hir::{Body, FnDecl, HirId};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{Clause, EarlyBinder, Opaque, PredicateKind};
+use rustc_middle::ty::{self, AliasTy, Clause, EarlyBinder, PredicateKind};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span};
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
return;
}
let ret_ty = return_ty(cx, hir_id);
- if let Opaque(id, subst) = *ret_ty.kind() {
- let preds = cx.tcx.explicit_item_bounds(id);
+ if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() {
+ let preds = cx.tcx.explicit_item_bounds(def_id);
let mut is_future = false;
for &(p, _span) in preds {
- let p = EarlyBinder(p).subst(cx.tcx, subst);
+ let p = EarlyBinder(p).subst(cx.tcx, substs);
if let Some(trait_pred) = p.to_opt_poly_trait_pred() {
if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
is_future = true;
.filter_by_name_unhygienic(is_empty)
.any(|item| is_is_empty(cx, item))
}),
- ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
+ ty::Alias(ty::Projection, ref proj) => has_is_empty_impl(cx, proj.def_id),
ty::Adt(id, _) => has_is_empty_impl(cx, id.did()),
ty::Array(..) | ty::Slice(..) | ty::Str => true,
_ => false,
&& let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty])
&& let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
cx.param_env,
- cx.tcx.mk_projection(into_iter_item_proj.item_def_id, into_iter_item_proj.substs)
+ cx.tcx.mk_projection(into_iter_item_proj.def_id, into_iter_item_proj.substs)
)
{
iter_item_ty == into_iter_item_ty
ty::Ref(_, _, hir::Mutability::Mut) => {
return Err((span, "mutable references in const fn are unstable".into()));
},
- ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
+ ty::Alias(ty::Opaque, ..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
ty::FnPtr(..) => {
return Err((span, "function pointers in const fn are unstable".into()));
},
use rustc_middle::mir::interpret::{ConstValue, Scalar};
use rustc_middle::ty::{
self, AdtDef, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind,
- ProjectionTy, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
+ AliasTy, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
VariantDef, VariantDiscr,
};
use rustc_middle::ty::{GenericArg, GenericArgKind};
return true;
}
- if let ty::Opaque(def_id, _) = *inner_ty.kind() {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() {
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
match predicate.kind().skip_binder() {
// For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
is_must_use_ty(cx, *ty)
},
ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)),
- ty::Opaque(def_id, _) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() {
if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
},
ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
- ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id)),
ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
ty::Dynamic(bounds, _, _) => {
let lang_items = cx.tcx.lang_items();
_ => None,
}
},
- ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) {
+ ty::Alias(ty::Projection, proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) {
Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty),
_ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)),
},
inputs = Some(i);
},
PredicateKind::Clause(ty::Clause::Projection(p))
- if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output()
+ if Some(p.projection_ty.def_id) == lang_items.fn_once_output()
&& p.projection_ty.self_ty() == ty =>
{
if output.is_some() {
inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id))
}
-fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option<ExprFnSig<'tcx>> {
+fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option<ExprFnSig<'tcx>> {
let mut inputs = None;
let mut output = None;
let lang_items = cx.tcx.lang_items();
for (pred, _) in cx
.tcx
- .bound_explicit_item_bounds(ty.item_def_id)
+ .bound_explicit_item_bounds(ty.def_id)
.subst_iter_copied(cx.tcx, ty.substs)
{
match pred.kind().skip_binder() {
inputs = Some(i);
},
PredicateKind::Clause(ty::Clause::Projection(p))
- if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() =>
+ if Some(p.projection_ty.def_id) == lang_items.fn_once_output() =>
{
if output.is_some() {
// Multiple different fn trait impls. Is this even allowed?
container_id: DefId,
assoc_ty: Symbol,
substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
-) -> Option<ProjectionTy<'tcx>> {
+) -> Option<AliasTy<'tcx>> {
fn helper<'tcx>(
tcx: TyCtxt<'tcx>,
container_id: DefId,
assoc_ty: Symbol,
substs: SubstsRef<'tcx>,
- ) -> Option<ProjectionTy<'tcx>> {
+ ) -> Option<AliasTy<'tcx>> {
let Some(assoc_item) = tcx
.associated_items(container_id)
.find_by_name_and_kind(tcx, Ident::with_dummy_span(assoc_ty), AssocKind::Type, container_id)
}
}
- Some(ProjectionTy {
+ Some(tcx.mk_alias_ty(
+ assoc_item.def_id,
substs,
- item_def_id: assoc_item.def_id,
- })
+ ))
}
helper(
tcx,
assoc_ty: Symbol,
substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
) -> Option<Ty<'tcx>> {
- fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: ProjectionTy<'tcx>) -> Option<Ty<'tcx>> {
+ fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
#[cfg(debug_assertions)]
if let Some((i, subst)) = ty
.substs
);
return None;
}
- match tcx.try_normalize_erasing_regions(param_env, tcx.mk_projection(ty.item_def_id, ty.substs)) {
+ match tcx.try_normalize_erasing_regions(param_env, tcx.mk_projection(ty.def_id, ty.substs)) {
Ok(ty) => Some(ty),
Err(e) => {
debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}");
rustc.args(&["--json", "future-incompat"]);
}
rustc.arg("-Ccodegen-units=1");
+ // Hide line numbers to reduce churn
rustc.arg("-Zui-testing");
+ // Hide libstd sources from ui tests to make sure we generate the stderr
+ // output that users will see.
+ // Without this, we may be producing good diagnostics in-tree but users
+ // will not see half the information.
+ rustc.arg("-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX");
+ rustc.arg("-Ztranslate-remapped-path-to-local-path=no");
+
rustc.arg("-Zdeduplicate-diagnostics=no");
// FIXME: use this for other modes too, for perf?
rustc.arg("-Cstrip=debuginfo");
};
use rustc_span::def_id::{CrateNum, DefId};
use rustc_span::Symbol;
-use rustc_target::abi::Size;
+use rustc_target::abi::{Size, Align};
use rustc_target::spec::abi::Abi;
+use rustc_const_eval::const_eval::CheckAlignment;
use crate::{
concurrency::{data_race, weak_memory},
const PANIC_ON_ALLOC_FAIL: bool = false;
#[inline(always)]
- fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
- ecx.machine.check_alignment != AlignmentCheck::None
+ fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> CheckAlignment {
+ if ecx.machine.check_alignment == AlignmentCheck::None {
+ CheckAlignment::No
+ } else {
+ CheckAlignment::Error
+ }
}
#[inline(always)]
ecx.machine.check_alignment == AlignmentCheck::Int
}
+ fn alignment_check_failed(
+ _ecx: &InterpCx<'mir, 'tcx, Self>,
+ has: Align,
+ required: Align,
+ _check: CheckAlignment,
+ ) -> InterpResult<'tcx, ()> {
+ throw_ub!(AlignmentCheckFailed { has, required })
+ }
+
#[inline(always)]
fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
ecx.machine.validate
("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"),
("cranelift-codegen-meta", "Apache-2.0 WITH LLVM-exception"),
("cranelift-codegen-shared", "Apache-2.0 WITH LLVM-exception"),
+ ("cranelift-egraph", "Apache-2.0 WITH LLVM-exception"),
("cranelift-entity", "Apache-2.0 WITH LLVM-exception"),
("cranelift-frontend", "Apache-2.0 WITH LLVM-exception"),
("cranelift-isle", "Apache-2.0 WITH LLVM-exception"),
("mach", "BSD-2-Clause"),
("regalloc2", "Apache-2.0 WITH LLVM-exception"),
("target-lexicon", "Apache-2.0 WITH LLVM-exception"),
+ ("wasmtime-jit-icache-coherence", "Apache-2.0 WITH LLVM-exception"),
];
const EXCEPTIONS_BOOTSTRAP: &[(&str, &str)] = &[
"cranelift-codegen",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
+ "cranelift-egraph",
"cranelift-entity",
"cranelift-frontend",
"cranelift-isle",
"cranelift-native",
"cranelift-object",
"crc32fast",
+ "fallible-iterator",
"fxhash",
"getrandom",
"gimli",
"region",
"slice-group-by",
"smallvec",
+ "stable_deref_trait",
"target-lexicon",
"version_check",
"wasi",
+ "wasmtime-jit-icache-coherence",
"winapi",
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
"@compiler-errors",
"@eholk",
"@jackh726",
- "@fee1-dead",
"@TaKO8Ki",
"@Nilstrieb",
]