[[package]]
name = "semver"
-version = "1.0.12"
+version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
+checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
dependencies = [
"serde",
]
[[package]]
name = "serde"
-version = "1.0.147"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.147"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "serde_json"
-version = "1.0.85"
+version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
+checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
dependencies = [
"indexmap",
"itoa",
[[package]]
name = "syn"
-version = "1.0.102"
+version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
"lazy_static",
"miropt-test-tools",
"regex",
+ "semver",
"termcolor",
"walkdir",
]
/// `extern` qualifier on a function item or function type.
#[derive(Clone, Copy, Encodable, Decodable, Debug)]
pub enum Extern {
+ /// No explicit extern keyword was used
+ ///
+ /// E.g. `fn foo() {}`
None,
+ /// An explicit extern keyword was used, but with implicit ABI
+ ///
+ /// E.g. `extern fn foo() {}`
+ ///
+ /// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`)
Implicit(Span),
+ /// An explicit extern keyword was used with an explicit ABI
+ ///
+ /// E.g. `extern "C" fn foo() {}`
Explicit(StrLit, Span),
}
/// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
#[derive(Clone, Copy, Encodable, Decodable, Debug)]
pub struct FnHeader {
+ /// The `unsafe` keyword, if any
pub unsafety: Unsafe,
+ /// The `async` keyword, if any
pub asyncness: Async,
+ /// The `const` keyword, if any
pub constness: Const,
+ /// The `extern` keyword and corresponding ABI string, if any
pub ext: Extern,
}
/// Intercept all spans entering HIR.
/// Mark a span as relative to the current owning item.
fn lower_span(&self, span: Span) -> Span {
- if self.tcx.sess.opts.unstable_opts.incremental_relative_spans {
+ if self.tcx.sess.opts.incremental_relative_spans() {
span.with_parent(Some(self.current_hir_id_owner.def_id))
} else {
// Do not make spans relative when not using incremental compilation.
place: &str,
borrow_place: &str,
value_place: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
self.infcx.tcx.sess.create_err(crate::session_diagnostics::MoveBorrow {
place,
span,
desc: &str,
borrow_span: Span,
borrow_desc: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
span,
old_loan_span: Span,
old_opt_via: &str,
old_load_end_span: Option<Span>,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let via =
|msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) };
let mut err = struct_span_err!(
desc: &str,
old_loan_span: Span,
old_load_end_span: Option<Span>,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
new_loan_span,
&self,
span: Span,
desc: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0594, "cannot assign to {}", desc)
}
span: Span,
path: &str,
reason: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,)
}
immutable_place: &str,
immutable_section: &str,
action: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
mutate_span,
&self,
span: Span,
yield_span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
span,
pub(crate) fn cannot_borrow_across_destructor(
&self,
borrow_span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(
self,
borrow_span,
&self,
span: Span,
path: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0597, "{} does not live long enough", path,)
}
return_kind: &str,
reference_desc: &str,
path_desc: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
span,
closure_kind: &str,
borrowed_path: &str,
capture_span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
closure_span,
pub(crate) fn thread_local_value_does_not_live_long_enough(
&self,
span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",)
}
pub(crate) fn temporary_value_borrowed_for_too_long(
&self,
span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",)
}
// that are *partially* initialized by assigning to a field of an uninitialized
// binding. We differentiate between them for more accurate wording here.
"isn't fully initialized"
- } else if spans
- .iter()
- .filter(|i| {
- // We filter these to avoid misleading wording in cases like the following,
- // where `x` has an `init`, but it is in the same place we're looking at:
- // ```
- // let x;
- // x += 1;
- // ```
- !i.contains(span)
- // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`
- && !visitor
- .errors
- .iter()
- .map(|(sp, _)| *sp)
- .any(|sp| span < sp && !sp.contains(span))
- })
- .count()
- == 0
- {
+ } else if !spans.iter().any(|i| {
+ // We filter these to avoid misleading wording in cases like the following,
+ // where `x` has an `init`, but it is in the same place we're looking at:
+ // ```
+ // let x;
+ // x += 1;
+ // ```
+ !i.contains(span)
+ // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`
+ && !visitor
+ .errors
+ .iter()
+ .map(|(sp, _)| *sp)
+ .any(|sp| span < sp && !sp.contains(span))
+ }) {
show_assign_sugg = true;
"isn't initialized"
} else {
// the verbs used in some diagnostic messages.
let act;
let acted_on;
+ let mut suggest = true;
+ let mut mut_error = None;
+ let mut count = 1;
let span = match error_access {
AccessKind::Mutate => {
let borrow_spans = self.borrow_spans(span, location);
let borrow_span = borrow_spans.args_or_use();
- err = self.cannot_borrow_path_as_mutable_because(borrow_span, &item_msg, &reason);
- borrow_spans.var_span_label(
- &mut err,
- format!(
- "mutable borrow occurs due to use of {} in closure",
- self.describe_any_place(access_place.as_ref()),
- ),
- "mutable",
- );
+ match the_place_err {
+ PlaceRef { local, projection: [] }
+ if self.body.local_decls[local].can_be_made_mutable() =>
+ {
+ let span = self.body.local_decls[local].source_info.span;
+ mut_error = Some(span);
+ if let Some((buffer, c)) = self.get_buffered_mut_error(span) {
+ // We've encountered a second (or more) attempt to mutably borrow an
+ // immutable binding, so the likely problem is with the binding
+ // declaration, not the use. We collect these in a single diagnostic
+ // and make the binding the primary span of the error.
+ err = buffer;
+ count = c + 1;
+ if count == 2 {
+ err.replace_span_with(span, false);
+ err.span_label(span, "not mutable");
+ }
+ suggest = false;
+ } else {
+ err = self.cannot_borrow_path_as_mutable_because(
+ borrow_span,
+ &item_msg,
+ &reason,
+ );
+ }
+ }
+ _ => {
+ err = self.cannot_borrow_path_as_mutable_because(
+ borrow_span,
+ &item_msg,
+ &reason,
+ );
+ }
+ }
+ if suggest {
+ borrow_spans.var_span_label(
+ &mut err,
+ format!(
+ "mutable borrow occurs due to use of {} in closure",
+ self.describe_any_place(access_place.as_ref()),
+ ),
+ "mutable",
+ );
+ }
borrow_span
}
};
pat_span: _,
},
)))) => {
- err.span_note(sp, "the binding is already a mutable borrow");
+ if suggest {
+ err.span_note(sp, "the binding is already a mutable borrow");
+ }
}
_ => {
err.span_note(
let local_decl = &self.body.local_decls[local];
assert_eq!(local_decl.mutability, Mutability::Not);
- err.span_label(span, format!("cannot {act}"));
- err.span_suggestion(
- local_decl.source_info.span,
- "consider changing this to be mutable",
- format!("mut {}", self.local_names[local].unwrap()),
- Applicability::MachineApplicable,
- );
- let tcx = self.infcx.tcx;
- if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
- self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+ if count < 10 {
+ err.span_label(span, format!("cannot {act}"));
+ }
+ if suggest {
+ err.span_suggestion_verbose(
+ local_decl.source_info.span.shrink_to_lo(),
+ "consider changing this to be mutable",
+ "mut ".to_string(),
+ Applicability::MachineApplicable,
+ );
+ let tcx = self.infcx.tcx;
+ if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
+ self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+ }
}
}
}
}
- self.buffer_error(err);
+ if let Some(span) = mut_error {
+ self.buffer_mut_error(span, err, count);
+ } else {
+ self.buffer_error(err);
+ }
}
fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) {
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
+use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
-use rustc_hir::{self as hir, Item, ItemKind, Node};
use rustc_infer::infer::{
error_reporting::nice_region_error::{
self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
outlives_suggestion.add_suggestion(self);
}
- fn get_impl_ident_and_self_ty_from_trait(
- &self,
- def_id: DefId,
- trait_objects: &FxIndexSet<DefId>,
- ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
- let tcx = self.infcx.tcx;
- match tcx.hir().get_if_local(def_id) {
- Some(Node::ImplItem(impl_item)) => {
- match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
- {
- Some(Node::Item(Item {
- kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
- ..
- })) => Some((impl_item.ident, self_ty)),
- _ => None,
- }
- }
- Some(Node::TraitItem(trait_item)) => {
- let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
- match tcx.hir().find_by_def_id(trait_did.def_id) {
- Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
- // The method being called is defined in the `trait`, but the `'static`
- // obligation comes from the `impl`. Find that `impl` so that we can point
- // at it in the suggestion.
- let trait_did = trait_did.to_def_id();
- match tcx
- .hir()
- .trait_impls(trait_did)
- .iter()
- .filter_map(|&impl_did| {
- match tcx.hir().get_if_local(impl_did.to_def_id()) {
- Some(Node::Item(Item {
- kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
- ..
- })) if trait_objects.iter().all(|did| {
- // FIXME: we should check `self_ty` against the receiver
- // type in the `UnifyReceiver` context, but for now, use
- // this imperfect proxy. This will fail if there are
- // multiple `impl`s for the same trait like
- // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
- // In that case, only the first one will get suggestions.
- let mut traits = vec![];
- let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
- hir_v.visit_ty(self_ty);
- !traits.is_empty()
- }) =>
- {
- Some(self_ty)
- }
- _ => None,
- }
- })
- .next()
- {
- Some(self_ty) => Some((trait_item.ident, self_ty)),
- _ => None,
- }
- }
- _ => None,
- }
- }
- _ => None,
- }
- }
-
/// Report an error because the universal region `fr` was required to outlive
/// `outlived_fr` but it is not known to do so. For example:
///
visitor.visit_ty(param.param_ty);
let Some((ident, self_ty)) =
- self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &visitor.0) else {return};
+ NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &visitor.0) else { return; };
self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
}
/// same primary span come out in a consistent order.
buffered_move_errors:
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>)>,
+ buffered_mut_errors: FxHashMap<Span, (DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)>,
/// Diagnostics to be reported buffer.
buffered: Vec<Diagnostic>,
/// Set to Some if we emit an error during borrowck
BorrowckErrors {
tcx,
buffered_move_errors: BTreeMap::new(),
+ buffered_mut_errors: Default::default(),
buffered: Default::default(),
tainted_by_errors: None,
}
}
}
+ pub fn get_buffered_mut_error(
+ &mut self,
+ span: Span,
+ ) -> Option<(DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)> {
+ self.errors.buffered_mut_errors.remove(&span)
+ }
+
+ pub fn buffer_mut_error(
+ &mut self,
+ span: Span,
+ t: DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ count: usize,
+ ) {
+ self.errors.buffered_mut_errors.insert(span, (t, count));
+ }
+
pub fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
// Buffer any move errors that we collected and de-duplicated.
for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
// We have already set tainted for this error, so just buffer it.
diag.buffer(&mut self.errors.buffered);
}
+ for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
+ if count > 10 {
+ diag.note(&format!("...and {} other attempted mutable borrows", count - 10));
+ }
+ diag.buffer(&mut self.errors.buffered);
+ }
if !self.errors.buffered.is_empty() {
self.errors.buffered.sort_by_key(|diag| diag.sort_span);
if show_doc_note {
diag.note(concat!(
stringify!($kind),
- " formatting not supported; see the documentation for `std::fmt`",
+ " formatting is not supported; see the documentation for `std::fmt`",
));
}
if suggestions.len() > 0 {
) -> RValue<'gcc> {
// FIXME(antoyo): remove when having a proper API.
let gcc_func = unsafe { std::mem::transmute(func) };
- let call = if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() {
+ let call = if self.functions.borrow().values().any(|value| *value == gcc_func) {
self.function_call(func, args, funclet)
}
else {
pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> {
let function: Function<'gcc> = unsafe { std::mem::transmute(value) };
- debug_assert!(self.functions.borrow().values().find(|value| **value == function).is_some(),
+ debug_assert!(self.functions.borrow().values().any(|value| *value == function),
"{:?} ({:?}) is not a function", value, value.get_type());
function
}
// Implement the "linker flavor" part of -Zgcc-ld
// by asking cc to use some kind of lld.
cmd.arg("-fuse-ld=lld");
+
if !flavor.is_gnu() {
// Tell clang to use a non-default LLD flavor.
// Gcc doesn't understand the target option, but we currently assume
// that gcc is not used for Apple and Wasm targets (#97402).
- cmd.arg(format!("--target={}", sess.target.llvm_target));
+ //
+ // Note that we don't want to do that by default on macOS: e.g. passing a
+ // 10.7 target to LLVM works, but not to recent versions of clang/macOS, as
+ // shown in issue #101653 and the discussion in PR #101792.
+ //
+ // It could be required in some cases of cross-compiling with
+ // `-Zgcc-ld=lld`, but this is generally unspecified, and we don't know
+ // which specific versions of clang, macOS SDK, host and target OS
+ // combinations impact us here.
+ //
+ // So we do a simple first-approximation until we know more of what the
+ // Apple targets require (and which would be handled prior to hitting this
+ // `-Zgcc-ld=lld` codepath anyway), but the expectation is that until then
+ // this should be manually passed if needed. We specify the target when
+ // targeting a different linker flavor on macOS, and that's also always
+ // the case when targeting WASM.
+ if sess.target.linker_flavor != sess.host.linker_flavor {
+ cmd.arg(format!("--target={}", sess.target.llvm_target));
+ }
}
}
}
use crate::stable_hasher::{HashStable, StableHasher, StableOrd};
use std::borrow::Borrow;
use std::cmp::Ordering;
+use std::fmt::Debug;
use std::mem;
use std::ops::{Bound, Index, IndexMut, RangeBounds};
/// stores data in a more compact way. It also supports accessing contiguous
/// ranges of elements as a slice, and slices of already sorted elements can be
/// inserted efficiently.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
pub struct SortedMap<K, V> {
data: Vec<(K, V)>,
}
}
}
+impl<K: Debug, V: Debug> Debug for SortedMap<K, V> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_map().entries(self.data.iter().map(|(a, b)| (a, b))).finish()
+ }
+}
+
#[cfg(test)]
mod tests;
metadata_lib_required =
crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
+metadata_rustc_lib_required =
+ crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
+ .note = only .rmeta files are distributed for `rustc_private` crates other than `rustc_driver`
+ .help = try adding `extern crate rustc_driver;` at the top level of this crate
+
metadata_crate_dep_multiple =
cannot satisfy dependencies so `{$crate_name}` only shows up once
.help = having upstream crates all available in one format will likely make this go away
self
}
- pub fn replace_span_with(&mut self, after: Span) -> &mut Self {
+ pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
let before = self.span.clone();
self.set_span(after);
for span_label in before.span_labels() {
if let Some(label) = span_label.label {
- if span_label.is_primary {
+ if span_label.is_primary && keep_label {
self.span.push_span_label(after, label);
} else {
self.span.push_span_label(span_label.span, label);
CallAssocMethod,
}
-fn default_track_diagnostic(_: &Diagnostic) {}
+fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
+ (*f)(d)
+}
-pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&Diagnostic)> =
- AtomicRef::new(&(default_track_diagnostic as fn(&_)));
+pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&mut Diagnostic, &mut dyn FnMut(&mut Diagnostic))> =
+ AtomicRef::new(&(default_track_diagnostic as _));
#[derive(Copy, Clone, Default)]
pub struct HandlerFlags {
/// Retrieve a stashed diagnostic with `steal_diagnostic`.
pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
let mut inner = self.inner.borrow_mut();
- inner.stash((span, key), diag);
+ inner.stash((span.with_parent(None), key), diag);
}
/// Steal a previously stashed diagnostic with the given `Span` and [`StashKey`] as the key.
pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> {
let mut inner = self.inner.borrow_mut();
- inner.steal((span, key)).map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
+ inner
+ .steal((span.with_parent(None), key))
+ .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
}
pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
- self.inner.borrow().stashed_diagnostics.get(&(span, key)).is_some()
+ self.inner.borrow().stashed_diagnostics.get(&(span.with_parent(None), key)).is_some()
}
/// Emit all stashed diagnostics.
&& !diagnostic.is_force_warn()
{
if diagnostic.has_future_breakage() {
- (*TRACK_DIAGNOSTICS)(diagnostic);
+ (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
}
return None;
}
- (*TRACK_DIAGNOSTICS)(diagnostic);
-
if matches!(diagnostic.level, Level::Expect(_) | Level::Allow) {
+ (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
return None;
}
- if let Some(ref code) = diagnostic.code {
- self.emitted_diagnostic_codes.insert(code.clone());
- }
-
- let already_emitted = |this: &mut Self| {
- let mut hasher = StableHasher::new();
- diagnostic.hash(&mut hasher);
- let diagnostic_hash = hasher.finish();
- !this.emitted_diagnostics.insert(diagnostic_hash)
- };
+ let mut guaranteed = None;
+ (*TRACK_DIAGNOSTICS)(diagnostic, &mut |diagnostic| {
+ if let Some(ref code) = diagnostic.code {
+ self.emitted_diagnostic_codes.insert(code.clone());
+ }
- // Only emit the diagnostic if we've been asked to deduplicate or
- // haven't already emitted an equivalent diagnostic.
- if !(self.flags.deduplicate_diagnostics && already_emitted(self)) {
- debug!(?diagnostic);
- debug!(?self.emitted_diagnostics);
- let already_emitted_sub = |sub: &mut SubDiagnostic| {
- debug!(?sub);
- if sub.level != Level::OnceNote {
- return false;
- }
+ let already_emitted = |this: &mut Self| {
let mut hasher = StableHasher::new();
- sub.hash(&mut hasher);
+ diagnostic.hash(&mut hasher);
let diagnostic_hash = hasher.finish();
- debug!(?diagnostic_hash);
- !self.emitted_diagnostics.insert(diagnostic_hash)
+ !this.emitted_diagnostics.insert(diagnostic_hash)
};
- diagnostic.children.drain_filter(already_emitted_sub).for_each(|_| {});
-
- self.emitter.emit_diagnostic(diagnostic);
- if diagnostic.is_error() {
- self.deduplicated_err_count += 1;
- } else if let Warning(_) = diagnostic.level {
- self.deduplicated_warn_count += 1;
+ // Only emit the diagnostic if we've been asked to deduplicate or
+ // haven't already emitted an equivalent diagnostic.
+ if !(self.flags.deduplicate_diagnostics && already_emitted(self)) {
+ debug!(?diagnostic);
+ debug!(?self.emitted_diagnostics);
+ let already_emitted_sub = |sub: &mut SubDiagnostic| {
+ debug!(?sub);
+ if sub.level != Level::OnceNote {
+ return false;
+ }
+ let mut hasher = StableHasher::new();
+ sub.hash(&mut hasher);
+ let diagnostic_hash = hasher.finish();
+ debug!(?diagnostic_hash);
+ !self.emitted_diagnostics.insert(diagnostic_hash)
+ };
+
+ diagnostic.children.drain_filter(already_emitted_sub).for_each(|_| {});
+
+ self.emitter.emit_diagnostic(diagnostic);
+ if diagnostic.is_error() {
+ self.deduplicated_err_count += 1;
+ } else if let Warning(_) = diagnostic.level {
+ self.deduplicated_warn_count += 1;
+ }
}
- }
- if diagnostic.is_error() {
- if matches!(diagnostic.level, Level::Error { lint: true }) {
- self.bump_lint_err_count();
+ if diagnostic.is_error() {
+ if matches!(diagnostic.level, Level::Error { lint: true }) {
+ self.bump_lint_err_count();
+ } else {
+ self.bump_err_count();
+ }
+
+ guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
} else {
- self.bump_err_count();
+ self.bump_warn_count();
}
+ });
- Some(ErrorGuaranteed::unchecked_claim_error_was_emitted())
- } else {
- self.bump_warn_count();
-
- None
- }
+ guaranteed
}
fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
.resolver
.visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment);
- if self.cx.sess.opts.unstable_opts.incremental_relative_spans {
+ if self.cx.sess.opts.incremental_relative_spans() {
for (invoc, _) in invocations.iter_mut() {
let expn_id = invoc.expansion_data.id;
let parent_def = self.cx.resolver.invocation_parent(expn_id);
);
if !e.span.is_dummy() {
// early end of macro arm (#52866)
- e.replace_span_with(parser.token.span.shrink_to_hi());
+ e.replace_span_with(parser.token.span.shrink_to_hi(), true);
}
}
if e.span.is_dummy() {
// Get around lack of span in error (#30128)
- e.replace_span_with(site_span);
+ e.replace_span_with(site_span, true);
if !parser.sess.source_map().is_imported(arm_span) {
e.span_label(arm_span, "in this macro arm");
}
/// Allows `#[doc(masked)]`.
(active, doc_masked, "1.21.0", Some(44027), None),
/// Allows `dyn* Trait` objects.
- (incomplete, dyn_star, "1.65.0", Some(91611), None),
+ (incomplete, dyn_star, "1.65.0", Some(102425), None),
/// Allows `X..Y` patterns.
(active, exclusive_range_pattern, "1.11.0", Some(37854), None),
/// Allows exhaustive pattern matching on types that contain uninhabited types.
&self
.nodes
.iter_enumerated()
- .map(|(id, parented_node)| (id, parented_node.as_ref().map(|node| node.parent)))
+ .map(|(id, parented_node)| {
+ let parented_node = parented_node.as_ref().map(|node| node.parent);
+
+ debug_fn(move |f| write!(f, "({id:?}, {parented_node:?})"))
+ })
.collect::<Vec<_>>(),
)
.field("bodies", &self.bodies)
static_assert_size!(TyKind<'_>, 32);
// tidy-alphabetical-end
}
+
+fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Debug {
+ struct DebugFn<F>(F);
+ impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Debug for DebugFn<F> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ (self.0)(fmt)
+ }
+ }
+ DebugFn(f)
+}
use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_ID};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
use rustc_span::{def_id::DefPathHash, HashStableContext};
-use std::fmt;
+use std::fmt::{self, Debug};
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Encodable, Decodable)]
pub struct OwnerId {
pub def_id: LocalDefId,
}
+impl Debug for OwnerId {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Example: DefId(0:1 ~ aa[7697]::{use#0})
+ Debug::fmt(&self.def_id, f)
+ }
+}
+
impl From<OwnerId> for HirId {
fn from(owner: OwnerId) -> HirId {
HirId { owner, local_id: ItemLocalId::from_u32(0) }
/// the `local_id` part of the `HirId` changing, which is a very useful property in
/// incremental compilation where we have to persist things through changes to
/// the code base.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Encodable, Decodable, HashStable_Generic)]
#[rustc_pass_by_value]
pub struct HirId {
pub local_id: ItemLocalId,
}
+impl Debug for HirId {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Example: HirId(DefId(0:1 ~ aa[7697]::{use#0}).10)
+ // Don't use debug_tuple to always keep this on one line.
+ write!(f, "HirId({:?}.{:?})", self.owner, self.local_id)
+ }
+}
+
impl HirId {
/// Signal local id which should never be used.
pub const INVALID: HirId =
sp,
item.span,
tr.path.span,
- trait_ref.self_ty(),
+ trait_ref,
impl_.self_ty.span,
&impl_.generics,
err,
sp: Span,
full_impl_span: Span,
trait_span: Span,
- self_ty: Ty<'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
self_ty_span: Span,
generics: &hir::Generics<'tcx>,
err: traits::OrphanCheckErr<'tcx>,
) -> Result<!, ErrorGuaranteed> {
+ let self_ty = trait_ref.self_ty();
Err(match err {
traits::OrphanCheckErr::NonLocalInputType(tys) => {
let msg = match self_ty.kind() {
let msg = |ty: &str, postfix: &str| {
format!("{ty} is not defined in the current crate{postfix}")
};
- let this = |name: &str| msg("this", &format!(" because {name} are always foreign"));
+
+ let this = |name: &str| {
+ if !trait_ref.def_id.is_local() && !is_target_ty {
+ msg("this", &format!(" because this is a foreign trait"))
+ } else {
+ msg("this", &format!(" because {name} are always foreign"))
+ }
+ };
let msg = match &ty.kind() {
ty::Slice(_) => this("slices"),
ty::Array(..) => this("arrays"),
E0614,
"type `{oprnd_t}` cannot be dereferenced",
);
- let sp = tcx.sess.source_map().start_point(expr.span);
+ let sp = tcx.sess.source_map().start_point(expr.span).with_parent(None);
if let Some(sp) =
tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
{
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
) -> bool {
- let sp = self.tcx.sess.source_map().start_point(expr.span);
+ let sp = self.tcx.sess.source_map().start_point(expr.span).with_parent(None);
if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
}),
Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
| Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
- let operand_ty = asm
- .operands
- .iter()
- .filter_map(|(op, _op_sp)| match op {
+ let operand_ty =
+ asm.operands.iter().find_map(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const }
if anon_const.hir_id == id =>
{
}))
}
_ => None,
- })
- .next();
+ });
operand_ty.unwrap_or_else(fallback)
}
_ => fallback(),
// Find an identifier with which this trait was imported (note that `_` doesn't count).
let any_id = import_items
.iter()
- .filter_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None })
- .next();
+ .find_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None });
if let Some(any_id) = any_id {
if any_id.name == Empty {
// Glob import, so just use its name.
// a raw pointer
!step.self_ty.references_error() && !step.from_unsafe_deref
})
- .flat_map(|step| {
+ .find_map(|step| {
let InferOk { value: self_ty, obligations: _ } = self
.fcx
.probe_instantiate_query_response(
})
})
})
- .next()
}
/// For each type `T` in the step list, this attempts to find a method where
pub fn report_method_error(
&self,
- mut span: Span,
+ span: Span,
rcvr_ty: Ty<'tcx>,
item_name: Ident,
source: SelfSource<'tcx>,
return None;
}
- let report_candidates = |span: Span,
- err: &mut Diagnostic,
- sources: &mut Vec<CandidateSource>,
- sugg_span: Option<Span>| {
- sources.sort();
- sources.dedup();
- // Dynamic limit to avoid hiding just one candidate, which is silly.
- let limit = if sources.len() == 5 { 5 } else { 4 };
-
- for (idx, source) in sources.iter().take(limit).enumerate() {
- match *source {
- CandidateSource::Impl(impl_did) => {
- // Provide the best span we can. Use the item, if local to crate, else
- // the impl, if local to crate (item may be defaulted), else nothing.
- let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
- let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
- self.associated_value(impl_trait_ref.def_id, item_name)
- }) else {
- continue;
- };
-
- let note_span = if item.def_id.is_local() {
- Some(self.tcx.def_span(item.def_id))
- } else if impl_did.is_local() {
- Some(self.tcx.def_span(impl_did))
- } else {
- None
- };
-
- let impl_ty = self.tcx.at(span).type_of(impl_did);
-
- let insertion = match self.tcx.impl_trait_ref(impl_did) {
- None => String::new(),
- Some(trait_ref) => format!(
- " of the trait `{}`",
- self.tcx.def_path_str(trait_ref.def_id)
- ),
- };
-
- let (note_str, idx) = if sources.len() > 1 {
- (
- format!(
- "candidate #{} is defined in an impl{} for the type `{}`",
- idx + 1,
- insertion,
- impl_ty,
- ),
- Some(idx + 1),
- )
- } else {
- (
- format!(
- "the candidate is defined in an impl{} for the type `{}`",
- insertion, impl_ty,
- ),
- None,
- )
- };
- if let Some(note_span) = note_span {
- // We have a span pointing to the method. Show note with snippet.
- err.span_note(note_span, ¬e_str);
- } else {
- err.note(¬e_str);
- }
- if let Some(sugg_span) = sugg_span
- && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
- let path = self.tcx.def_path_str(trait_ref.def_id);
-
- let ty = match item.kind {
- ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
- ty::AssocKind::Fn => self
- .tcx
- .fn_sig(item.def_id)
- .inputs()
- .skip_binder()
- .get(0)
- .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
- .copied()
- .unwrap_or(rcvr_ty),
- };
- print_disambiguation_help(
- item_name,
- args,
- err,
- path,
- ty,
- item.kind,
- item.def_id,
- sugg_span,
- idx,
- self.tcx.sess.source_map(),
- item.fn_has_self_parameter,
- );
- }
- }
- CandidateSource::Trait(trait_did) => {
- let Some(item) = self.associated_value(trait_did, item_name) else { continue };
- let item_span = self.tcx.def_span(item.def_id);
- let idx = if sources.len() > 1 {
- let msg = &format!(
- "candidate #{} is defined in the trait `{}`",
- idx + 1,
- self.tcx.def_path_str(trait_did)
- );
- err.span_note(item_span, msg);
- Some(idx + 1)
- } else {
- let msg = &format!(
- "the candidate is defined in the trait `{}`",
- self.tcx.def_path_str(trait_did)
- );
- err.span_note(item_span, msg);
- None
- };
- if let Some(sugg_span) = sugg_span {
- let path = self.tcx.def_path_str(trait_did);
- print_disambiguation_help(
- item_name,
- args,
- err,
- path,
- rcvr_ty,
- item.kind,
- item.def_id,
- sugg_span,
- idx,
- self.tcx.sess.source_map(),
- item.fn_has_self_parameter,
- );
- }
- }
- }
- }
- if sources.len() > limit {
- err.note(&format!("and {} others", sources.len() - limit));
- }
- };
-
let sugg_span = if let SelfSource::MethodCall(expr) = source {
// Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span
};
match error {
- MethodError::NoMatch(NoMatchData {
- mut static_candidates,
- unsatisfied_predicates,
- out_of_scope_traits,
- lev_candidate,
- mode,
- }) => {
- let tcx = self.tcx;
-
- let rcvr_ty = self.resolve_vars_if_possible(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"
- } else if rcvr_ty.is_enum() {
- "variant or associated item"
- } else {
- match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
- (Some(name), false) if name.is_lowercase() => "function or associated item",
- (Some(_), false) => "associated item",
- (Some(_), true) | (None, false) => "variant or associated item",
- (None, true) => "variant",
- }
- };
-
- if self.suggest_wrapping_range_with_parens(
- tcx, rcvr_ty, source, span, item_name, &ty_str,
- ) || self.suggest_constraining_numerical_ty(
- tcx, rcvr_ty, source, span, item_kind, item_name, &ty_str,
- ) {
- return None;
- }
- span = item_name.span;
-
- // Don't show generic arguments when the method can't be found in any implementation (#81576).
- let mut ty_str_reported = ty_str.clone();
- if let ty::Adt(_, generics) = rcvr_ty.kind() {
- if generics.len() > 0 {
- let mut autoderef = self.autoderef(span, rcvr_ty);
- let candidate_found = autoderef.any(|(ty, _)| {
- if let ty::Adt(adt_def, _) = ty.kind() {
- self.tcx
- .inherent_impls(adt_def.did())
- .iter()
- .filter_map(|def_id| self.associated_value(*def_id, item_name))
- .count()
- >= 1
- } else {
- false
- }
- });
- let has_deref = autoderef.step_count() > 0;
- if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
- if let Some((path_string, _)) = ty_str.split_once('<') {
- ty_str_reported = path_string.to_string();
- }
- }
- }
- }
-
- let mut err = struct_span_err!(
- tcx.sess,
+ MethodError::NoMatch(mut no_match_data) => {
+ return self.report_no_match_method_error(
span,
- E0599,
- "no {} named `{}` found for {} `{}` in the current scope",
- item_kind,
+ rcvr_ty,
item_name,
- rcvr_ty.prefix_string(self.tcx),
- ty_str_reported,
+ source,
+ args,
+ sugg_span,
+ &mut no_match_data,
);
- if rcvr_ty.references_error() {
- err.downgrade_to_delayed_bug();
- }
-
- if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
- self.suggest_await_before_method(
- &mut err, item_name, rcvr_ty, cal, span,
- );
- }
- if let Some(span) = tcx.resolutions(()).confused_type_with_std_module.get(&span) {
- err.span_suggestion(
- span.shrink_to_lo(),
- "you are looking for the module in `std`, not the primitive type",
- "std::",
- Applicability::MachineApplicable,
- );
- }
- if let ty::RawPtr(_) = &rcvr_ty.kind() {
- err.note(
- "try using `<*const T>::as_ref()` to get a reference to the \
- type behind the pointer: https://doc.rust-lang.org/std/\
- primitive.pointer.html#method.as_ref",
- );
- err.note(
- "using `<*const T>::as_ref()` on a pointer which is unaligned or points \
- to invalid or uninitialized memory is undefined behavior",
- );
- }
-
- let ty_span = match rcvr_ty.kind() {
- ty::Param(param_type) => Some(
- param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()),
- ),
- ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
- _ => None,
- };
- if let Some(span) = ty_span {
- err.span_label(
- span,
- format!(
- "{item_kind} `{item_name}` not found for this {}",
- rcvr_ty.prefix_string(self.tcx)
- ),
- );
- }
-
- if let SelfSource::MethodCall(rcvr_expr) = source {
- self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
- let call_expr = self
- .tcx
- .hir()
- .expect_expr(self.tcx.hir().get_parent_node(rcvr_expr.hir_id));
- let probe = self.lookup_probe(
- item_name,
- output_ty,
- call_expr,
- ProbeScope::AllTraits,
- );
- probe.is_ok()
- });
- }
-
- let mut custom_span_label = false;
-
- if !static_candidates.is_empty() {
- err.note(
- "found the following associated functions; to be used as methods, \
- functions must have a `self` parameter",
- );
- err.span_label(span, "this is an associated function, not a method");
- custom_span_label = true;
- }
- if static_candidates.len() == 1 {
- self.suggest_associated_call_syntax(
- &mut err,
- &static_candidates,
- rcvr_ty,
- source,
- item_name,
- args,
- sugg_span,
- );
-
- report_candidates(span, &mut err, &mut static_candidates, None);
- } else if static_candidates.len() > 1 {
- report_candidates(span, &mut err, &mut static_candidates, Some(sugg_span));
- }
-
- let mut bound_spans = vec![];
- let mut restrict_type_params = false;
- let mut unsatisfied_bounds = false;
- if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
- let msg = "consider using `len` instead";
- if let SelfSource::MethodCall(_expr) = source {
- err.span_suggestion_short(
- span,
- msg,
- "len",
- Applicability::MachineApplicable,
- );
- } else {
- err.span_label(span, msg);
- }
- if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
- let iterator_trait = self.tcx.def_path_str(iterator_trait);
- err.note(&format!("`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"));
- }
- } else if !unsatisfied_predicates.is_empty() {
- let mut type_params = FxHashMap::default();
-
- // Pick out the list of unimplemented traits on the receiver.
- // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
- let mut unimplemented_traits = FxHashMap::default();
- let mut unimplemented_traits_only = true;
- for (predicate, _parent_pred, cause) in &unsatisfied_predicates {
- if let (ty::PredicateKind::Clause(ty::Clause::Trait(p)), Some(cause)) =
- (predicate.kind().skip_binder(), cause.as_ref())
- {
- if p.trait_ref.self_ty() != rcvr_ty {
- // This is necessary, not just to keep the errors clean, but also
- // because our derived obligations can wind up with a trait ref that
- // requires a different param_env to be correctly compared.
- continue;
- }
- unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
- predicate.kind().rebind(p.trait_ref),
- Obligation {
- cause: cause.clone(),
- param_env: self.param_env,
- predicate: *predicate,
- recursion_depth: 0,
- },
- ));
- }
- }
-
- // Make sure that, if any traits other than the found ones were involved,
- // we don't don't report an unimplemented trait.
- // We don't want to say that `iter::Cloned` is not an iterator, just
- // because of some non-Clone item being iterated over.
- for (predicate, _parent_pred, _cause) in &unsatisfied_predicates {
- match predicate.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(p))
- if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
- _ => {
- unimplemented_traits_only = false;
- break;
- }
- }
- }
-
- let mut collect_type_param_suggestions =
- |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
- // We don't care about regions here, so it's fine to skip the binder here.
- if let (ty::Param(_), ty::PredicateKind::Clause(ty::Clause::Trait(p))) =
- (self_ty.kind(), parent_pred.kind().skip_binder())
- {
- let hir = self.tcx.hir();
- let node = match p.trait_ref.self_ty().kind() {
- ty::Param(_) => {
- // Account for `fn` items like in `issue-35677.rs` to
- // suggest restricting its type params.
- let parent_body =
- hir.body_owner(hir::BodyId { hir_id: self.body_id });
- Some(hir.get(parent_body))
- }
- ty::Adt(def, _) => {
- def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
- }
- _ => None,
- };
- if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
- if let Some(g) = kind.generics() {
- let key = (
- g.tail_span_for_predicate_suggestion(),
- g.add_where_or_trailing_comma(),
- );
- type_params
- .entry(key)
- .or_insert_with(FxHashSet::default)
- .insert(obligation.to_owned());
- }
- }
- }
- };
- let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
- let msg = format!(
- "doesn't satisfy `{}`",
- if obligation.len() > 50 { quiet } else { obligation }
- );
- match &self_ty.kind() {
- // Point at the type that couldn't satisfy the bound.
- ty::Adt(def, _) => {
- bound_spans.push((self.tcx.def_span(def.did()), msg))
- }
- // Point at the trait object that couldn't satisfy the bound.
- ty::Dynamic(preds, _, _) => {
- for pred in preds.iter() {
- match pred.skip_binder() {
- ty::ExistentialPredicate::Trait(tr) => bound_spans
- .push((self.tcx.def_span(tr.def_id), msg.clone())),
- ty::ExistentialPredicate::Projection(_)
- | ty::ExistentialPredicate::AutoTrait(_) => {}
- }
- }
- }
- // Point at the closure that couldn't satisfy the bound.
- ty::Closure(def_id, _) => bound_spans.push((
- tcx.def_span(*def_id),
- format!("doesn't satisfy `{}`", quiet),
- )),
- _ => {}
- }
- };
- let mut format_pred = |pred: ty::Predicate<'tcx>| {
- let bound_predicate = pred.kind();
- match bound_predicate.skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
- let pred = bound_predicate.rebind(pred);
- // `<Foo as Iterator>::Item = String`.
- let projection_ty = pred.skip_binder().projection_ty;
-
- let substs_with_infer_self = tcx.mk_substs(
- iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
- .chain(projection_ty.substs.iter().skip(1)),
- );
-
- 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 = with_forced_trimmed_paths!(format!(
- "{} = {}",
- quiet_projection_ty, term
- ));
-
- bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
- Some((obligation, projection_ty.self_ty()))
- }
- ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
- let p = poly_trait_ref.trait_ref;
- let self_ty = p.self_ty();
- let path = p.print_only_trait_path();
- let obligation = format!("{}: {}", self_ty, path);
- let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
- bound_span_label(self_ty, &obligation, &quiet);
- Some((obligation, self_ty))
- }
- _ => None,
- }
- };
-
- // Find all the requirements that come from a local `impl` block.
- let mut skip_list: FxHashSet<_> = Default::default();
- let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
- for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates
- .iter()
- .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
- .filter_map(|(p, parent, c)| match c.code() {
- ObligationCauseCode::ImplDerivedObligation(data) => {
- Some((&data.derived, p, parent, data.impl_def_id, data))
- }
- _ => None,
- })
- {
- let parent_trait_ref = data.parent_trait_pred;
- let path = parent_trait_ref.print_modifiers_and_trait_path();
- let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
- let unsatisfied_msg = "unsatisfied trait bound introduced here";
- let derive_msg =
- "unsatisfied trait bound introduced in this `derive` macro";
- match self.tcx.hir().get_if_local(impl_def_id) {
- // Unmet obligation comes from a `derive` macro, point at it once to
- // avoid multiple span labels pointing at the same place.
- Some(Node::Item(hir::Item {
- kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
- ..
- })) if matches!(
- self_ty.span.ctxt().outer_expn_data().kind,
- ExpnKind::Macro(MacroKind::Derive, _)
- ) || matches!(
- of_trait.as_ref().map(|t| t
- .path
- .span
- .ctxt()
- .outer_expn_data()
- .kind),
- Some(ExpnKind::Macro(MacroKind::Derive, _))
- ) =>
- {
- let span = self_ty.span.ctxt().outer_expn_data().call_site;
- let mut spans: MultiSpan = span.into();
- spans.push_span_label(span, derive_msg);
- let entry = spanned_predicates.entry(spans);
- entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
- }
-
- // Unmet obligation coming from an `impl`.
- Some(Node::Item(hir::Item {
- kind:
- hir::ItemKind::Impl(hir::Impl {
- of_trait, self_ty, generics, ..
- }),
- span: item_span,
- ..
- })) => {
- let sized_pred =
- unsatisfied_predicates.iter().any(|(pred, _, _)| {
- match pred.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
- Some(pred.def_id())
- == self.tcx.lang_items().sized_trait()
- && pred.polarity == ty::ImplPolarity::Positive
- }
- _ => false,
- }
- });
- for param in generics.params {
- if param.span == cause.span && sized_pred {
- let (sp, sugg) = match param.colon_span {
- Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
- None => (param.span.shrink_to_hi(), ": ?Sized"),
- };
- err.span_suggestion_verbose(
- sp,
- "consider relaxing the type parameter's implicit \
- `Sized` bound",
- sugg,
- Applicability::MachineApplicable,
- );
- }
- }
- if let Some(pred) = parent_p {
- // Done to add the "doesn't satisfy" `span_label`.
- let _ = format_pred(*pred);
- }
- skip_list.insert(p);
- let mut spans = if cause.span != *item_span {
- let mut spans: MultiSpan = cause.span.into();
- spans.push_span_label(cause.span, unsatisfied_msg);
- spans
- } else {
- let mut spans = Vec::with_capacity(2);
- if let Some(trait_ref) = of_trait {
- spans.push(trait_ref.path.span);
- }
- spans.push(self_ty.span);
- spans.into()
- };
- if let Some(trait_ref) = of_trait {
- spans.push_span_label(trait_ref.path.span, "");
- }
- spans.push_span_label(self_ty.span, "");
-
- let entry = spanned_predicates.entry(spans);
- entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
- }
- Some(Node::Item(hir::Item {
- kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
- span: item_span,
- ..
- })) => {
- tcx.sess.delay_span_bug(
- *item_span,
- "auto trait is invoked with no method error, but no error reported?",
- );
- }
- Some(_) => unreachable!(),
- None => (),
- }
- }
- let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
- spanned_predicates.sort_by_key(|(span, (_, _, _))| span.primary_span());
- for (span, (_path, _self_ty, preds)) in spanned_predicates {
- let mut preds: Vec<_> = preds
- .into_iter()
- .filter_map(|pred| format_pred(*pred))
- .map(|(p, _)| format!("`{}`", p))
- .collect();
- preds.sort();
- preds.dedup();
- let msg = if let [pred] = &preds[..] {
- format!("trait bound {} was not satisfied", pred)
- } else {
- format!(
- "the following trait bounds were not satisfied:\n{}",
- preds.join("\n"),
- )
- };
- err.span_note(span, &msg);
- unsatisfied_bounds = true;
- }
-
- // The requirements that didn't have an `impl` span to show.
- let mut bound_list = unsatisfied_predicates
- .iter()
- .filter_map(|(pred, parent_pred, _cause)| {
- format_pred(*pred).map(|(p, self_ty)| {
- collect_type_param_suggestions(self_ty, *pred, &p);
- (
- match parent_pred {
- None => format!("`{}`", &p),
- Some(parent_pred) => match format_pred(*parent_pred) {
- None => format!("`{}`", &p),
- Some((parent_p, _)) => {
- collect_type_param_suggestions(
- self_ty,
- *parent_pred,
- &p,
- );
- format!(
- "`{}`\nwhich is required by `{}`",
- p, parent_p
- )
- }
- },
- },
- *pred,
- )
- })
- })
- .filter(|(_, pred)| !skip_list.contains(&pred))
- .map(|(t, _)| t)
- .enumerate()
- .collect::<Vec<(usize, String)>>();
-
- for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
- restrict_type_params = true;
- // #74886: Sort here so that the output is always the same.
- let mut obligations = obligations.into_iter().collect::<Vec<_>>();
- obligations.sort();
- err.span_suggestion_verbose(
- span,
- &format!(
- "consider restricting the type parameter{s} to satisfy the \
- trait bound{s}",
- s = pluralize!(obligations.len())
- ),
- format!("{} {}", add_where_or_comma, obligations.join(", ")),
- Applicability::MaybeIncorrect,
- );
- }
-
- bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
- bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
- bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
-
- if !bound_list.is_empty() || !skip_list.is_empty() {
- let bound_list = bound_list
- .into_iter()
- .map(|(_, path)| path)
- .collect::<Vec<_>>()
- .join("\n");
- let actual_prefix = rcvr_ty.prefix_string(self.tcx);
- info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
- let (primary_message, label) =
- if unimplemented_traits.len() == 1 && unimplemented_traits_only {
- unimplemented_traits
- .into_iter()
- .next()
- .map(|(_, (trait_ref, obligation))| {
- if trait_ref.self_ty().references_error()
- || rcvr_ty.references_error()
- {
- // Avoid crashing.
- return (None, None);
- }
- let OnUnimplementedNote { message, label, .. } = self
- .err_ctxt()
- .on_unimplemented_note(trait_ref, &obligation);
- (message, label)
- })
- .unwrap()
- } else {
- (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"
- ));
- err.set_primary_message(&primary_message);
- if let Some(label) = label {
- custom_span_label = true;
- err.span_label(span, label);
- }
- if !bound_list.is_empty() {
- err.note(&format!(
- "the following trait bounds were not satisfied:\n{bound_list}"
- ));
- }
- self.suggest_derive(&mut err, &unsatisfied_predicates);
-
- unsatisfied_bounds = true;
- }
- }
-
- let label_span_not_found = |err: &mut Diagnostic| {
- if unsatisfied_predicates.is_empty() {
- err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
- let is_string_or_ref_str = match rcvr_ty.kind() {
- ty::Ref(_, ty, _) => {
- ty.is_str()
- || matches!(
- ty.kind(),
- ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string()
- )
- }
- ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(),
- _ => false,
- };
- if is_string_or_ref_str && item_name.name == sym::iter {
- err.span_suggestion_verbose(
- item_name.span,
- "because of the in-memory representation of `&str`, to obtain \
- an `Iterator` over each of its codepoint use method `chars`",
- "chars",
- Applicability::MachineApplicable,
- );
- }
- if let ty::Adt(adt, _) = rcvr_ty.kind() {
- let mut inherent_impls_candidate = self
- .tcx
- .inherent_impls(adt.did())
- .iter()
- .copied()
- .filter(|def_id| {
- if let Some(assoc) = self.associated_value(*def_id, item_name) {
- // Check for both mode is the same so we avoid suggesting
- // incorrect associated item.
- match (mode, assoc.fn_has_self_parameter, source) {
- (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
- // We check that the suggest type is actually
- // different from the received one
- // So we avoid suggestion method with Box<Self>
- // for instance
- self.tcx.at(span).type_of(*def_id) != rcvr_ty
- && self.tcx.at(span).type_of(*def_id) != rcvr_ty
- }
- (Mode::Path, false, _) => true,
- _ => false,
- }
- } else {
- false
- }
- })
- .collect::<Vec<_>>();
- if !inherent_impls_candidate.is_empty() {
- inherent_impls_candidate.sort();
- inherent_impls_candidate.dedup();
-
- // number of type to shows at most.
- let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
- let type_candidates = inherent_impls_candidate
- .iter()
- .take(limit)
- .map(|impl_item| {
- format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
- })
- .collect::<Vec<_>>()
- .join("\n");
- let additional_types = if inherent_impls_candidate.len() > limit {
- format!(
- "\nand {} more types",
- inherent_impls_candidate.len() - limit
- )
- } else {
- "".to_string()
- };
- err.note(&format!(
- "the {item_kind} was found for\n{}{}",
- type_candidates, additional_types
- ));
- }
- }
- } else {
- 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"
- ));
- }
- };
-
- // If the method name is the name of a field with a function or closure type,
- // give a helping note that it has to be called as `(x.f)(...)`.
- if let SelfSource::MethodCall(expr) = source {
- if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
- && lev_candidate.is_none()
- && !custom_span_label
- {
- label_span_not_found(&mut err);
- }
- } else if !custom_span_label {
- label_span_not_found(&mut err);
- }
-
- // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
- // can't be called due to `typeof(expr): Clone` not holding.
- if unsatisfied_predicates.is_empty() {
- self.suggest_calling_method_on_field(
- &mut err, source, span, rcvr_ty, item_name,
- );
- }
-
- self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
-
- bound_spans.sort();
- bound_spans.dedup();
- for (span, msg) in bound_spans.into_iter() {
- err.span_label(span, &msg);
- }
-
- if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
- } else {
- self.suggest_traits_to_import(
- &mut err,
- span,
- rcvr_ty,
- item_name,
- args.map(|(_, args)| args.len() + 1),
- source,
- out_of_scope_traits,
- &unsatisfied_predicates,
- &static_candidates,
- unsatisfied_bounds,
- );
- }
-
- // Don't emit a suggestion if we found an actual method
- // that had unsatisfied trait bounds
- if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
- let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
- if let Some(suggestion) = lev_distance::find_best_match_for_name(
- &adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
- item_name.name,
- None,
- ) {
- err.span_suggestion(
- span,
- "there is a variant with a similar name",
- suggestion,
- Applicability::MaybeIncorrect,
- );
- }
- }
-
- if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
- let msg = "remove this method call";
- let mut fallback_span = true;
- if let SelfSource::MethodCall(expr) = source {
- let call_expr =
- self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
- if let Some(span) = call_expr.span.trim_start(expr.span) {
- err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
- fallback_span = false;
- }
- }
- if fallback_span {
- err.span_label(span, msg);
- }
- } else if let Some(lev_candidate) = lev_candidate {
- // Don't emit a suggestion if we found an actual method
- // that had unsatisfied trait bounds
- if unsatisfied_predicates.is_empty() {
- let def_kind = lev_candidate.kind.as_def_kind();
- // Methods are defined within the context of a struct and their first parameter is always self,
- // which represents the instance of the struct the method is being called on
- // Associated functions don’t take self as a parameter and
- // they are not methods because they don’t have an instance of the struct to work with.
- if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
- err.span_suggestion(
- span,
- "there is a method with a similar name",
- lev_candidate.name,
- Applicability::MaybeIncorrect,
- );
- } else {
- err.span_suggestion(
- span,
- &format!(
- "there is {} {} with a similar name",
- def_kind.article(),
- def_kind.descr(lev_candidate.def_id),
- ),
- lev_candidate.name,
- Applicability::MaybeIncorrect,
- );
- }
- }
- }
-
- self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
-
- return Some(err);
}
MethodError::Ambiguity(mut sources) => {
);
err.span_label(item_name.span, format!("multiple `{}` found", item_name));
- report_candidates(span, &mut err, &mut sources, Some(sugg_span));
+ self.note_candidates_on_method_error(
+ rcvr_ty,
+ item_name,
+ args,
+ span,
+ &mut err,
+ &mut sources,
+ Some(sugg_span),
+ );
err.emit();
}
None
}
+ pub fn report_no_match_method_error(
+ &self,
+ mut span: Span,
+ rcvr_ty: Ty<'tcx>,
+ item_name: Ident,
+ source: SelfSource<'tcx>,
+ args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+ sugg_span: Span,
+ no_match_data: &mut NoMatchData<'tcx>,
+ ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
+ let mode = no_match_data.mode;
+ let tcx = self.tcx;
+ let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
+ let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
+ let is_method = mode == Mode::MethodCall;
+ let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
+ let lev_candidate = no_match_data.lev_candidate;
+ let item_kind = if is_method {
+ "method"
+ } else if rcvr_ty.is_enum() {
+ "variant or associated item"
+ } else {
+ match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
+ (Some(name), false) if name.is_lowercase() => "function or associated item",
+ (Some(_), false) => "associated item",
+ (Some(_), true) | (None, false) => "variant or associated item",
+ (None, true) => "variant",
+ }
+ };
+
+ if self.suggest_wrapping_range_with_parens(tcx, rcvr_ty, source, span, item_name, &ty_str)
+ || self.suggest_constraining_numerical_ty(
+ tcx, rcvr_ty, source, span, item_kind, item_name, &ty_str,
+ )
+ {
+ return None;
+ }
+ span = item_name.span;
+
+ // Don't show generic arguments when the method can't be found in any implementation (#81576).
+ let mut ty_str_reported = ty_str.clone();
+ if let ty::Adt(_, generics) = rcvr_ty.kind() {
+ if generics.len() > 0 {
+ let mut autoderef = self.autoderef(span, rcvr_ty);
+ let candidate_found = autoderef.any(|(ty, _)| {
+ if let ty::Adt(adt_def, _) = ty.kind() {
+ self.tcx
+ .inherent_impls(adt_def.did())
+ .iter()
+ .any(|def_id| self.associated_value(*def_id, item_name).is_some())
+ } else {
+ false
+ }
+ });
+ let has_deref = autoderef.step_count() > 0;
+ if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
+ if let Some((path_string, _)) = ty_str.split_once('<') {
+ ty_str_reported = path_string.to_string();
+ }
+ }
+ }
+ }
+
+ let mut err = struct_span_err!(
+ tcx.sess,
+ span,
+ E0599,
+ "no {} named `{}` found for {} `{}` in the current scope",
+ item_kind,
+ item_name,
+ rcvr_ty.prefix_string(self.tcx),
+ ty_str_reported,
+ );
+ if rcvr_ty.references_error() {
+ err.downgrade_to_delayed_bug();
+ }
+
+ if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
+ self.suggest_await_before_method(
+ &mut err, item_name, rcvr_ty, cal, span,
+ );
+ }
+ if let Some(span) =
+ tcx.resolutions(()).confused_type_with_std_module.get(&span.with_parent(None))
+ {
+ err.span_suggestion(
+ span.shrink_to_lo(),
+ "you are looking for the module in `std`, not the primitive type",
+ "std::",
+ Applicability::MachineApplicable,
+ );
+ }
+ if let ty::RawPtr(_) = &rcvr_ty.kind() {
+ err.note(
+ "try using `<*const T>::as_ref()` to get a reference to the \
+ type behind the pointer: https://doc.rust-lang.org/std/\
+ primitive.pointer.html#method.as_ref",
+ );
+ err.note(
+ "using `<*const T>::as_ref()` on a pointer which is unaligned or points \
+ to invalid or uninitialized memory is undefined behavior",
+ );
+ }
+
+ let ty_span = match rcvr_ty.kind() {
+ ty::Param(param_type) => {
+ Some(param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()))
+ }
+ ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
+ _ => None,
+ };
+ if let Some(span) = ty_span {
+ err.span_label(
+ span,
+ format!(
+ "{item_kind} `{item_name}` not found for this {}",
+ rcvr_ty.prefix_string(self.tcx)
+ ),
+ );
+ }
+
+ if let SelfSource::MethodCall(rcvr_expr) = source {
+ self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
+ let call_expr =
+ self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(rcvr_expr.hir_id));
+ let probe =
+ self.lookup_probe(item_name, output_ty, call_expr, ProbeScope::AllTraits);
+ probe.is_ok()
+ });
+ }
+
+ let mut custom_span_label = false;
+
+ let static_candidates = &mut no_match_data.static_candidates;
+ if !static_candidates.is_empty() {
+ err.note(
+ "found the following associated functions; to be used as methods, \
+ functions must have a `self` parameter",
+ );
+ err.span_label(span, "this is an associated function, not a method");
+ custom_span_label = true;
+ }
+ if static_candidates.len() == 1 {
+ self.suggest_associated_call_syntax(
+ &mut err,
+ &static_candidates,
+ rcvr_ty,
+ source,
+ item_name,
+ args,
+ sugg_span,
+ );
+
+ self.note_candidates_on_method_error(
+ rcvr_ty,
+ item_name,
+ args,
+ span,
+ &mut err,
+ static_candidates,
+ None,
+ );
+ } else if static_candidates.len() > 1 {
+ self.note_candidates_on_method_error(
+ rcvr_ty,
+ item_name,
+ args,
+ span,
+ &mut err,
+ static_candidates,
+ Some(sugg_span),
+ );
+ }
+
+ let mut bound_spans = vec![];
+ let mut restrict_type_params = false;
+ let mut unsatisfied_bounds = false;
+ if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
+ let msg = "consider using `len` instead";
+ if let SelfSource::MethodCall(_expr) = source {
+ err.span_suggestion_short(span, msg, "len", Applicability::MachineApplicable);
+ } else {
+ err.span_label(span, msg);
+ }
+ if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
+ let iterator_trait = self.tcx.def_path_str(iterator_trait);
+ err.note(&format!(
+ "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
+ ));
+ }
+ } else if !unsatisfied_predicates.is_empty() {
+ let mut type_params = FxHashMap::default();
+
+ // Pick out the list of unimplemented traits on the receiver.
+ // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
+ let mut unimplemented_traits = FxHashMap::default();
+ let mut unimplemented_traits_only = true;
+ for (predicate, _parent_pred, cause) in unsatisfied_predicates {
+ if let (ty::PredicateKind::Clause(ty::Clause::Trait(p)), Some(cause)) =
+ (predicate.kind().skip_binder(), cause.as_ref())
+ {
+ if p.trait_ref.self_ty() != rcvr_ty {
+ // This is necessary, not just to keep the errors clean, but also
+ // because our derived obligations can wind up with a trait ref that
+ // requires a different param_env to be correctly compared.
+ continue;
+ }
+ unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
+ predicate.kind().rebind(p.trait_ref),
+ Obligation {
+ cause: cause.clone(),
+ param_env: self.param_env,
+ predicate: *predicate,
+ recursion_depth: 0,
+ },
+ ));
+ }
+ }
+
+ // Make sure that, if any traits other than the found ones were involved,
+ // we don't don't report an unimplemented trait.
+ // We don't want to say that `iter::Cloned` is not an iterator, just
+ // because of some non-Clone item being iterated over.
+ for (predicate, _parent_pred, _cause) in unsatisfied_predicates {
+ match predicate.kind().skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Trait(p))
+ if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
+ _ => {
+ unimplemented_traits_only = false;
+ break;
+ }
+ }
+ }
+
+ let mut collect_type_param_suggestions =
+ |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
+ // We don't care about regions here, so it's fine to skip the binder here.
+ if let (ty::Param(_), ty::PredicateKind::Clause(ty::Clause::Trait(p))) =
+ (self_ty.kind(), parent_pred.kind().skip_binder())
+ {
+ let hir = self.tcx.hir();
+ let node = match p.trait_ref.self_ty().kind() {
+ ty::Param(_) => {
+ // Account for `fn` items like in `issue-35677.rs` to
+ // suggest restricting its type params.
+ let parent_body =
+ hir.body_owner(hir::BodyId { hir_id: self.body_id });
+ Some(hir.get(parent_body))
+ }
+ ty::Adt(def, _) => {
+ def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
+ }
+ _ => None,
+ };
+ if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
+ if let Some(g) = kind.generics() {
+ let key = (
+ g.tail_span_for_predicate_suggestion(),
+ g.add_where_or_trailing_comma(),
+ );
+ type_params
+ .entry(key)
+ .or_insert_with(FxHashSet::default)
+ .insert(obligation.to_owned());
+ }
+ }
+ }
+ };
+ let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
+ let msg = format!(
+ "doesn't satisfy `{}`",
+ if obligation.len() > 50 { quiet } else { obligation }
+ );
+ match &self_ty.kind() {
+ // Point at the type that couldn't satisfy the bound.
+ ty::Adt(def, _) => bound_spans.push((self.tcx.def_span(def.did()), msg)),
+ // Point at the trait object that couldn't satisfy the bound.
+ ty::Dynamic(preds, _, _) => {
+ for pred in preds.iter() {
+ match pred.skip_binder() {
+ ty::ExistentialPredicate::Trait(tr) => {
+ bound_spans.push((self.tcx.def_span(tr.def_id), msg.clone()))
+ }
+ ty::ExistentialPredicate::Projection(_)
+ | ty::ExistentialPredicate::AutoTrait(_) => {}
+ }
+ }
+ }
+ // Point at the closure that couldn't satisfy the bound.
+ ty::Closure(def_id, _) => bound_spans
+ .push((tcx.def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
+ _ => {}
+ }
+ };
+ let mut format_pred = |pred: ty::Predicate<'tcx>| {
+ let bound_predicate = pred.kind();
+ match bound_predicate.skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
+ let pred = bound_predicate.rebind(pred);
+ // `<Foo as Iterator>::Item = String`.
+ let projection_ty = pred.skip_binder().projection_ty;
+
+ let substs_with_infer_self = tcx.mk_substs(
+ iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
+ .chain(projection_ty.substs.iter().skip(1)),
+ );
+
+ 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 = with_forced_trimmed_paths!(format!(
+ "{} = {}",
+ quiet_projection_ty, term
+ ));
+
+ bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
+ Some((obligation, projection_ty.self_ty()))
+ }
+ ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
+ let p = poly_trait_ref.trait_ref;
+ let self_ty = p.self_ty();
+ let path = p.print_only_trait_path();
+ let obligation = format!("{}: {}", self_ty, path);
+ let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
+ bound_span_label(self_ty, &obligation, &quiet);
+ Some((obligation, self_ty))
+ }
+ _ => None,
+ }
+ };
+
+ // Find all the requirements that come from a local `impl` block.
+ let mut skip_list: FxHashSet<_> = Default::default();
+ let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
+ for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates
+ .iter()
+ .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
+ .filter_map(|(p, parent, c)| match c.code() {
+ ObligationCauseCode::ImplDerivedObligation(data) => {
+ Some((&data.derived, p, parent, data.impl_def_id, data))
+ }
+ _ => None,
+ })
+ {
+ let parent_trait_ref = data.parent_trait_pred;
+ let path = parent_trait_ref.print_modifiers_and_trait_path();
+ let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
+ let unsatisfied_msg = "unsatisfied trait bound introduced here";
+ let derive_msg = "unsatisfied trait bound introduced in this `derive` macro";
+ match self.tcx.hir().get_if_local(impl_def_id) {
+ // Unmet obligation comes from a `derive` macro, point at it once to
+ // avoid multiple span labels pointing at the same place.
+ Some(Node::Item(hir::Item {
+ kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
+ ..
+ })) if matches!(
+ self_ty.span.ctxt().outer_expn_data().kind,
+ ExpnKind::Macro(MacroKind::Derive, _)
+ ) || matches!(
+ of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind),
+ Some(ExpnKind::Macro(MacroKind::Derive, _))
+ ) =>
+ {
+ let span = self_ty.span.ctxt().outer_expn_data().call_site;
+ let mut spans: MultiSpan = span.into();
+ spans.push_span_label(span, derive_msg);
+ let entry = spanned_predicates.entry(spans);
+ entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
+ }
+
+ // Unmet obligation coming from an `impl`.
+ Some(Node::Item(hir::Item {
+ kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }),
+ span: item_span,
+ ..
+ })) => {
+ let sized_pred =
+ unsatisfied_predicates.iter().any(|(pred, _, _)| {
+ match pred.kind().skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
+ Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
+ && pred.polarity == ty::ImplPolarity::Positive
+ }
+ _ => false,
+ }
+ });
+ for param in generics.params {
+ if param.span == cause.span && sized_pred {
+ let (sp, sugg) = match param.colon_span {
+ Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
+ None => (param.span.shrink_to_hi(), ": ?Sized"),
+ };
+ err.span_suggestion_verbose(
+ sp,
+ "consider relaxing the type parameter's implicit \
+ `Sized` bound",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ if let Some(pred) = parent_p {
+ // Done to add the "doesn't satisfy" `span_label`.
+ let _ = format_pred(*pred);
+ }
+ skip_list.insert(p);
+ let mut spans = if cause.span != *item_span {
+ let mut spans: MultiSpan = cause.span.into();
+ spans.push_span_label(cause.span, unsatisfied_msg);
+ spans
+ } else {
+ let mut spans = Vec::with_capacity(2);
+ if let Some(trait_ref) = of_trait {
+ spans.push(trait_ref.path.span);
+ }
+ spans.push(self_ty.span);
+ spans.into()
+ };
+ if let Some(trait_ref) = of_trait {
+ spans.push_span_label(trait_ref.path.span, "");
+ }
+ spans.push_span_label(self_ty.span, "");
+
+ let entry = spanned_predicates.entry(spans);
+ entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
+ }
+ Some(Node::Item(hir::Item {
+ kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
+ span: item_span,
+ ..
+ })) => {
+ tcx.sess.delay_span_bug(
+ *item_span,
+ "auto trait is invoked with no method error, but no error reported?",
+ );
+ }
+ Some(_) => unreachable!(),
+ None => (),
+ }
+ }
+ let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
+ spanned_predicates.sort_by_key(|(span, (_, _, _))| span.primary_span());
+ for (span, (_path, _self_ty, preds)) in spanned_predicates {
+ let mut preds: Vec<_> = preds
+ .into_iter()
+ .filter_map(|pred| format_pred(*pred))
+ .map(|(p, _)| format!("`{}`", p))
+ .collect();
+ preds.sort();
+ preds.dedup();
+ let msg = if let [pred] = &preds[..] {
+ format!("trait bound {} was not satisfied", pred)
+ } else {
+ format!("the following trait bounds were not satisfied:\n{}", preds.join("\n"),)
+ };
+ err.span_note(span, &msg);
+ unsatisfied_bounds = true;
+ }
+
+ // The requirements that didn't have an `impl` span to show.
+ let mut bound_list = unsatisfied_predicates
+ .iter()
+ .filter_map(|(pred, parent_pred, _cause)| {
+ format_pred(*pred).map(|(p, self_ty)| {
+ collect_type_param_suggestions(self_ty, *pred, &p);
+ (
+ match parent_pred {
+ None => format!("`{}`", &p),
+ Some(parent_pred) => match format_pred(*parent_pred) {
+ None => format!("`{}`", &p),
+ Some((parent_p, _)) => {
+ collect_type_param_suggestions(self_ty, *parent_pred, &p);
+ format!("`{}`\nwhich is required by `{}`", p, parent_p)
+ }
+ },
+ },
+ *pred,
+ )
+ })
+ })
+ .filter(|(_, pred)| !skip_list.contains(&pred))
+ .map(|(t, _)| t)
+ .enumerate()
+ .collect::<Vec<(usize, String)>>();
+
+ for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
+ restrict_type_params = true;
+ // #74886: Sort here so that the output is always the same.
+ let mut obligations = obligations.into_iter().collect::<Vec<_>>();
+ obligations.sort();
+ err.span_suggestion_verbose(
+ span,
+ &format!(
+ "consider restricting the type parameter{s} to satisfy the \
+ trait bound{s}",
+ s = pluralize!(obligations.len())
+ ),
+ format!("{} {}", add_where_or_comma, obligations.join(", ")),
+ Applicability::MaybeIncorrect,
+ );
+ }
+
+ bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
+ bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
+ bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
+
+ if !bound_list.is_empty() || !skip_list.is_empty() {
+ let bound_list =
+ bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n");
+ let actual_prefix = rcvr_ty.prefix_string(self.tcx);
+ info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
+ let (primary_message, label) = if unimplemented_traits.len() == 1
+ && unimplemented_traits_only
+ {
+ unimplemented_traits
+ .into_iter()
+ .next()
+ .map(|(_, (trait_ref, obligation))| {
+ if trait_ref.self_ty().references_error() || rcvr_ty.references_error()
+ {
+ // Avoid crashing.
+ return (None, None);
+ }
+ let OnUnimplementedNote { message, label, .. } =
+ self.err_ctxt().on_unimplemented_note(trait_ref, &obligation);
+ (message, label)
+ })
+ .unwrap()
+ } else {
+ (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"
+ )
+ });
+ err.set_primary_message(&primary_message);
+ if let Some(label) = label {
+ custom_span_label = true;
+ err.span_label(span, label);
+ }
+ if !bound_list.is_empty() {
+ err.note(&format!(
+ "the following trait bounds were not satisfied:\n{bound_list}"
+ ));
+ }
+ self.suggest_derive(&mut err, &unsatisfied_predicates);
+
+ unsatisfied_bounds = true;
+ }
+ }
+
+ let label_span_not_found = |err: &mut Diagnostic| {
+ if unsatisfied_predicates.is_empty() {
+ err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+ let is_string_or_ref_str = match rcvr_ty.kind() {
+ ty::Ref(_, ty, _) => {
+ ty.is_str()
+ || matches!(
+ ty.kind(),
+ ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string()
+ )
+ }
+ ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(),
+ _ => false,
+ };
+ if is_string_or_ref_str && item_name.name == sym::iter {
+ err.span_suggestion_verbose(
+ item_name.span,
+ "because of the in-memory representation of `&str`, to obtain \
+ an `Iterator` over each of its codepoint use method `chars`",
+ "chars",
+ Applicability::MachineApplicable,
+ );
+ }
+ if let ty::Adt(adt, _) = rcvr_ty.kind() {
+ let mut inherent_impls_candidate = self
+ .tcx
+ .inherent_impls(adt.did())
+ .iter()
+ .copied()
+ .filter(|def_id| {
+ if let Some(assoc) = self.associated_value(*def_id, item_name) {
+ // Check for both mode is the same so we avoid suggesting
+ // incorrect associated item.
+ match (mode, assoc.fn_has_self_parameter, source) {
+ (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
+ // We check that the suggest type is actually
+ // different from the received one
+ // So we avoid suggestion method with Box<Self>
+ // for instance
+ self.tcx.at(span).type_of(*def_id) != rcvr_ty
+ && self.tcx.at(span).type_of(*def_id) != rcvr_ty
+ }
+ (Mode::Path, false, _) => true,
+ _ => false,
+ }
+ } else {
+ false
+ }
+ })
+ .collect::<Vec<_>>();
+ if !inherent_impls_candidate.is_empty() {
+ inherent_impls_candidate.sort();
+ inherent_impls_candidate.dedup();
+
+ // number of type to shows at most.
+ let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
+ let type_candidates = inherent_impls_candidate
+ .iter()
+ .take(limit)
+ .map(|impl_item| {
+ format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
+ })
+ .collect::<Vec<_>>()
+ .join("\n");
+ let additional_types = if inherent_impls_candidate.len() > limit {
+ format!("\nand {} more types", inherent_impls_candidate.len() - limit)
+ } else {
+ "".to_string()
+ };
+ err.note(&format!(
+ "the {item_kind} was found for\n{}{}",
+ type_candidates, additional_types
+ ));
+ }
+ }
+ } else {
+ 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"),
+ );
+ }
+ };
+
+ // If the method name is the name of a field with a function or closure type,
+ // give a helping note that it has to be called as `(x.f)(...)`.
+ if let SelfSource::MethodCall(expr) = source {
+ if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
+ && lev_candidate.is_none()
+ && !custom_span_label
+ {
+ label_span_not_found(&mut err);
+ }
+ } else if !custom_span_label {
+ label_span_not_found(&mut err);
+ }
+
+ // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
+ // can't be called due to `typeof(expr): Clone` not holding.
+ if unsatisfied_predicates.is_empty() {
+ self.suggest_calling_method_on_field(&mut err, source, span, rcvr_ty, item_name);
+ }
+
+ self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
+
+ bound_spans.sort();
+ bound_spans.dedup();
+ for (span, msg) in bound_spans.into_iter() {
+ err.span_label(span, &msg);
+ }
+
+ if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
+ } else {
+ self.suggest_traits_to_import(
+ &mut err,
+ span,
+ rcvr_ty,
+ item_name,
+ args.map(|(_, args)| args.len() + 1),
+ source,
+ no_match_data.out_of_scope_traits.clone(),
+ &unsatisfied_predicates,
+ &static_candidates,
+ unsatisfied_bounds,
+ );
+ }
+
+ // Don't emit a suggestion if we found an actual method
+ // that had unsatisfied trait bounds
+ if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
+ let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
+ if let Some(suggestion) = lev_distance::find_best_match_for_name(
+ &adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
+ item_name.name,
+ None,
+ ) {
+ err.span_suggestion(
+ span,
+ "there is a variant with a similar name",
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+
+ if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
+ let msg = "remove this method call";
+ let mut fallback_span = true;
+ if let SelfSource::MethodCall(expr) = source {
+ let call_expr =
+ self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
+ if let Some(span) = call_expr.span.trim_start(expr.span) {
+ err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
+ fallback_span = false;
+ }
+ }
+ if fallback_span {
+ err.span_label(span, msg);
+ }
+ } else if let Some(lev_candidate) = lev_candidate {
+ // Don't emit a suggestion if we found an actual method
+ // that had unsatisfied trait bounds
+ if unsatisfied_predicates.is_empty() {
+ let def_kind = lev_candidate.kind.as_def_kind();
+ // Methods are defined within the context of a struct and their first parameter is always self,
+ // which represents the instance of the struct the method is being called on
+ // Associated functions don’t take self as a parameter and
+ // they are not methods because they don’t have an instance of the struct to work with.
+ if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
+ err.span_suggestion(
+ span,
+ "there is a method with a similar name",
+ lev_candidate.name,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_suggestion(
+ span,
+ &format!(
+ "there is {} {} with a similar name",
+ def_kind.article(),
+ def_kind.descr(lev_candidate.def_id),
+ ),
+ lev_candidate.name,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+
+ self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
+ return Some(err);
+ }
+
+ fn note_candidates_on_method_error(
+ &self,
+ rcvr_ty: Ty<'tcx>,
+ item_name: Ident,
+ args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+ span: Span,
+ err: &mut Diagnostic,
+ sources: &mut Vec<CandidateSource>,
+ sugg_span: Option<Span>,
+ ) {
+ sources.sort();
+ sources.dedup();
+ // Dynamic limit to avoid hiding just one candidate, which is silly.
+ let limit = if sources.len() == 5 { 5 } else { 4 };
+
+ for (idx, source) in sources.iter().take(limit).enumerate() {
+ match *source {
+ CandidateSource::Impl(impl_did) => {
+ // Provide the best span we can. Use the item, if local to crate, else
+ // the impl, if local to crate (item may be defaulted), else nothing.
+ let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
+ let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
+ self.associated_value(impl_trait_ref.def_id, item_name)
+ }) else {
+ continue;
+ };
+
+ let note_span = if item.def_id.is_local() {
+ Some(self.tcx.def_span(item.def_id))
+ } else if impl_did.is_local() {
+ Some(self.tcx.def_span(impl_did))
+ } else {
+ None
+ };
+
+ let impl_ty = self.tcx.at(span).type_of(impl_did);
+
+ let insertion = match self.tcx.impl_trait_ref(impl_did) {
+ None => String::new(),
+ Some(trait_ref) => {
+ format!(" of the trait `{}`", self.tcx.def_path_str(trait_ref.def_id))
+ }
+ };
+
+ let (note_str, idx) = if sources.len() > 1 {
+ (
+ format!(
+ "candidate #{} is defined in an impl{} for the type `{}`",
+ idx + 1,
+ insertion,
+ impl_ty,
+ ),
+ Some(idx + 1),
+ )
+ } else {
+ (
+ format!(
+ "the candidate is defined in an impl{} for the type `{}`",
+ insertion, impl_ty,
+ ),
+ None,
+ )
+ };
+ if let Some(note_span) = note_span {
+ // We have a span pointing to the method. Show note with snippet.
+ err.span_note(note_span, ¬e_str);
+ } else {
+ err.note(¬e_str);
+ }
+ if let Some(sugg_span) = sugg_span
+ && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
+ let path = self.tcx.def_path_str(trait_ref.def_id);
+
+ let ty = match item.kind {
+ ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
+ ty::AssocKind::Fn => self
+ .tcx
+ .fn_sig(item.def_id)
+ .inputs()
+ .skip_binder()
+ .get(0)
+ .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
+ .copied()
+ .unwrap_or(rcvr_ty),
+ };
+ print_disambiguation_help(
+ item_name,
+ args,
+ err,
+ path,
+ ty,
+ item.kind,
+ item.def_id,
+ sugg_span,
+ idx,
+ self.tcx.sess.source_map(),
+ item.fn_has_self_parameter,
+ );
+ }
+ }
+ CandidateSource::Trait(trait_did) => {
+ let Some(item) = self.associated_value(trait_did, item_name) else { continue };
+ let item_span = self.tcx.def_span(item.def_id);
+ let idx = if sources.len() > 1 {
+ let msg = &format!(
+ "candidate #{} is defined in the trait `{}`",
+ idx + 1,
+ self.tcx.def_path_str(trait_did)
+ );
+ err.span_note(item_span, msg);
+ Some(idx + 1)
+ } else {
+ let msg = &format!(
+ "the candidate is defined in the trait `{}`",
+ self.tcx.def_path_str(trait_did)
+ );
+ err.span_note(item_span, msg);
+ None
+ };
+ if let Some(sugg_span) = sugg_span {
+ let path = self.tcx.def_path_str(trait_did);
+ print_disambiguation_help(
+ item_name,
+ args,
+ err,
+ path,
+ rcvr_ty,
+ item.kind,
+ item.def_id,
+ sugg_span,
+ idx,
+ self.tcx.sess.source_map(),
+ item.fn_has_self_parameter,
+ );
+ }
+ }
+ }
+ }
+ if sources.len() > limit {
+ err.note(&format!("and {} others", sources.len() - limit));
+ }
+ }
+
/// Suggest calling `Ty::method` if `.method()` isn't found because the method
/// doesn't take a `self` receiver.
fn suggest_associated_call_syntax(
}
}
- let sp = self.tcx.sess.source_map().start_point(ex.span);
+ let sp = self.tcx.sess.source_map().start_point(ex.span).with_parent(None);
if let Some(sp) =
self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
{
let mut v = TraitObjectVisitor(FxIndexSet::default());
v.visit_ty(param.param_ty);
if let Some((ident, self_ty)) =
- self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0)
+ NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, item_def_id, &v.0)
&& self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty)
{
override_error_code = Some(ident.name);
let did = item_id.owner_id.to_def_id();
let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did));
- if let Some(span) = opaque
- .bounds
- .iter()
- .filter_map(|arg| match arg {
- GenericBound::Outlives(Lifetime {
- res: LifetimeName::Static,
- ident,
- ..
- }) => Some(ident.span),
- _ => None,
- })
- .next()
- {
+ if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg {
+ GenericBound::Outlives(Lifetime {
+ res: LifetimeName::Static, ident, ..
+ }) => Some(ident.span),
+ _ => None,
+ }) {
if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose(
span,
Applicability::MaybeIncorrect,
);
}
- } else if opaque
- .bounds
- .iter()
- .filter_map(|arg| match arg {
- GenericBound::Outlives(Lifetime { ident, .. })
- if ident.name.to_string() == lifetime_name =>
- {
- Some(ident.span)
- }
- _ => None,
- })
- .next()
- .is_some()
- {
+ } else if opaque.bounds.iter().any(|arg| match arg {
+ GenericBound::Outlives(Lifetime { ident, .. })
+ if ident.name.to_string() == lifetime_name =>
+ {
+ true
+ }
+ _ => false,
+ }) {
} else {
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
}
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
- fn get_impl_ident_and_self_ty_from_trait(
- &self,
+ pub fn get_impl_ident_and_self_ty_from_trait(
+ tcx: TyCtxt<'tcx>,
def_id: DefId,
trait_objects: &FxIndexSet<DefId>,
) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
- let tcx = self.tcx();
- match tcx.hir().get_if_local(def_id) {
- Some(Node::ImplItem(impl_item)) => {
- match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
+ match tcx.hir().get_if_local(def_id)? {
+ Node::ImplItem(impl_item) => {
+ let impl_did = tcx.hir().get_parent_item(impl_item.hir_id());
+ if let hir::OwnerNode::Item(Item {
+ kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+ ..
+ }) = tcx.hir().owner(impl_did)
{
- Some(Node::Item(Item {
- kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
- ..
- })) => Some((impl_item.ident, self_ty)),
- _ => None,
+ Some((impl_item.ident, self_ty))
+ } else {
+ None
}
}
- Some(Node::TraitItem(trait_item)) => {
- let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
- match tcx.hir().find_by_def_id(trait_did.def_id) {
- Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
- // The method being called is defined in the `trait`, but the `'static`
- // obligation comes from the `impl`. Find that `impl` so that we can point
- // at it in the suggestion.
- let trait_did = trait_did.to_def_id();
- match tcx
- .hir()
- .trait_impls(trait_did)
- .iter()
- .filter_map(|&impl_did| {
- match tcx.hir().get_if_local(impl_did.to_def_id()) {
- Some(Node::Item(Item {
- kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
- ..
- })) if trait_objects.iter().all(|did| {
- // FIXME: we should check `self_ty` against the receiver
- // type in the `UnifyReceiver` context, but for now, use
- // this imperfect proxy. This will fail if there are
- // multiple `impl`s for the same trait like
- // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
- // In that case, only the first one will get suggestions.
- let mut traits = vec![];
- let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
- hir_v.visit_ty(self_ty);
- !traits.is_empty()
- }) =>
- {
- Some(self_ty)
- }
- _ => None,
- }
- })
- .next()
- {
- Some(self_ty) => Some((trait_item.ident, self_ty)),
- _ => None,
- }
+ Node::TraitItem(trait_item) => {
+ let trait_id = tcx.hir().get_parent_item(trait_item.hir_id());
+ debug_assert_eq!(tcx.def_kind(trait_id.def_id), hir::def::DefKind::Trait);
+ // The method being called is defined in the `trait`, but the `'static`
+ // obligation comes from the `impl`. Find that `impl` so that we can point
+ // at it in the suggestion.
+ let trait_did = trait_id.to_def_id();
+ tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
+ if let Node::Item(Item {
+ kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+ ..
+ }) = tcx.hir().find_by_def_id(impl_did)?
+ && trait_objects.iter().all(|did| {
+ // FIXME: we should check `self_ty` against the receiver
+ // type in the `UnifyReceiver` context, but for now, use
+ // this imperfect proxy. This will fail if there are
+ // multiple `impl`s for the same trait like
+ // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
+ // In that case, only the first one will get suggestions.
+ let mut traits = vec![];
+ let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
+ hir_v.visit_ty(self_ty);
+ !traits.is_empty()
+ })
+ {
+ Some((trait_item.ident, *self_ty))
+ } else {
+ None
}
- _ => None,
- }
+ })
}
_ => None,
}
// Get the `Ident` of the method being called and the corresponding `impl` (to point at
// `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
- let Some((ident, self_ty)) = self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0) else {
+ let Some((ident, self_ty)) = NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &v.0) else {
return false;
};
//! origin crate when the `TyCtxt` is not present in TLS.
use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
+use rustc_middle::dep_graph::TaskDepsRef;
use rustc_middle::ty::tls;
use std::fmt;
/// This is a callback from `rustc_ast` as it cannot access the implicit state
/// in `rustc_middle` otherwise. It is used when diagnostic messages are
/// emitted and stores them in the current query, if there is one.
-fn track_diagnostic(diagnostic: &Diagnostic) {
+fn track_diagnostic(diagnostic: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
tls::with_context_opt(|icx| {
if let Some(icx) = icx {
if let Some(diagnostics) = icx.diagnostics {
let mut diagnostics = diagnostics.lock();
diagnostics.extend(Some(diagnostic.clone()));
+ std::mem::drop(diagnostics);
}
+
+ // Diagnostics are tracked, we can ignore the dependency.
+ let icx = tls::ImplicitCtxt { task_deps: TaskDepsRef::Ignore, ..icx.clone() };
+ return tls::enter_context(&icx, move |_| (*f)(diagnostic));
}
+
+ // In any other case, invoke diagnostics anyway.
+ (*f)(diagnostic);
})
}
pub fn setup_callbacks() {
rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
- TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_)));
+ TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _));
}
untracked!(future_incompat_test, true);
untracked!(hir_stats, true);
untracked!(identify_regions, true);
- untracked!(incremental_ignore_spans, true);
untracked!(incremental_info, true);
untracked!(incremental_verify_ich, true);
untracked!(input_stats, true);
tracked!(fuel, Some(("abc".to_string(), 99)));
tracked!(function_sections, Some(false));
tracked!(human_readable_cgu_names, true);
+ tracked!(incremental_ignore_spans, true);
tracked!(inline_in_all_cgus, Some(true));
tracked!(inline_mir, Some(true));
tracked!(inline_mir_hint_threshold, Some(123));
///
/// The attribute must be used in conjunction with the
/// [`closure_track_caller` feature flag]. Otherwise, the `#[track_caller]`
- /// annotation will function as as no-op.
+ /// annotation will function as a no-op.
///
/// [`closure_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/closure-track-caller.html
UNGATED_ASYNC_FN_TRACK_CALLER,
$cx.pass.$f(&$cx.context, $($args),*);
}) }
-/// Implements the AST traversal for early lint passes. `T` provides the the
+/// Implements the AST traversal for early lint passes. `T` provides the
/// `check_*` methods.
pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
context: EarlyContext<'a>,
$cx.pass.$f(&$cx.context, $($args),*);
}) }
-/// Implements the AST traversal for late lint passes. `T` provides the the
+/// Implements the AST traversal for late lint passes. `T` provides the
/// `check_*` methods.
pub struct LateContextAndPass<'tcx, T: LateLintPass<'tcx>> {
context: LateContext<'tcx>,
cx.tcx,
cx.tcx.explicit_item_bounds(def).iter().cloned(),
)
- .filter_map(|obligation| {
+ .find_map(|obligation| {
// We only look at the `DefId`, so it is safe to skip the binder here.
if let ty::PredicateKind::Clause(ty::Clause::Trait(
ref poly_trait_predicate,
}
})
.map(|inner| MustUsePath::Opaque(Box::new(inner)))
- .next()
}
- ty::Dynamic(binders, _, _) => binders
- .iter()
- .filter_map(|predicate| {
- if let ty::ExistentialPredicate::Trait(ref trait_ref) =
- predicate.skip_binder()
- {
- let def_id = trait_ref.def_id;
- is_def_must_use(cx, def_id, span)
- } else {
- None
- }
- .map(|inner| MustUsePath::TraitObject(Box::new(inner)))
- })
- .next(),
+ ty::Dynamic(binders, _, _) => binders.iter().find_map(|predicate| {
+ if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
+ {
+ let def_id = trait_ref.def_id;
+ is_def_must_use(cx, def_id, span)
+ .map(|inner| MustUsePath::TraitObject(Box::new(inner)))
+ } else {
+ None
+ }
+ }),
ty::Tuple(tys) => {
let elem_exprs = if let hir::ExprKind::Tup(elem_exprs) = expr.kind {
debug_assert_eq!(elem_exprs.len(), tys.len());
let m: &syn::ItemMacro = file
.items
.iter()
- .filter_map(|i| {
+ .find_map(|i| {
if let syn::Item::Macro(m) = i {
if m.mac.path == symbols_path { Some(m) } else { None }
} else {
None
}
})
- .next()
.expect("did not find `symbols!` macro invocation.");
let body_tokens = m.mac.tokens.clone();
use crate::creader::CStore;
use crate::errors::{
BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired,
- RequiredPanicStrategy, RlibRequired, TwoPanicRuntimes,
+ RequiredPanicStrategy, RlibRequired, RustcLibRequired, TwoPanicRuntimes,
};
use rustc_data_structures::fx::FxHashMap;
Linkage::Static => "rlib",
_ => "dylib",
};
- sess.emit_err(LibRequired { crate_name: tcx.crate_name(cnum), kind: kind });
+ let crate_name = tcx.crate_name(cnum);
+ if crate_name.as_str().starts_with("rustc_") {
+ sess.emit_err(RustcLibRequired { crate_name, kind });
+ } else {
+ sess.emit_err(LibRequired { crate_name, kind });
+ }
}
}
}
pub kind: &'a str,
}
+#[derive(Diagnostic)]
+#[diag(metadata_rustc_lib_required)]
+#[help]
+pub struct RustcLibRequired<'a> {
+ pub crate_name: Symbol,
+ pub kind: &'a str,
+}
+
#[derive(Diagnostic)]
#[diag(metadata_crate_dep_multiple)]
#[help]
hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
- if tcx.sess.opts.unstable_opts.incremental_relative_spans {
+ if tcx.sess.opts.incremental_relative_spans() {
let definitions = tcx.definitions_untracked();
let mut owner_spans: Vec<_> = krate
.owners
//! ## Overview
//!
//! There are two visitors, one for immutable and one for mutable references,
-//! but both are generated by the following macro. The code is written according
-//! to the following conventions:
+//! but both are generated by the `make_mir_visitor` macro.
+//! The code is written according to the following conventions:
//!
//! - introduce a `visit_foo` and a `super_foo` method for every MIR type
//! - `visit_foo`, by default, calls `super_foo`
//! - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
//!
-//! This allows you as a user to override `visit_foo` for types are
-//! interested in, and invoke (within that method) call
+//! This allows you to override `visit_foo` for types you are
+//! interested in, and invoke (within that method call)
//! `self.super_foo` to get the default behavior. Just as in an OO
//! language, you should never call `super` methods ordinarily except
//! in that circumstance.
use rustc_hir as hir;
use rustc_middle::mir::BorrowKind;
use rustc_middle::thir::*;
+use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
use rustc_session::lint::Level;
hir_id: hir::HirId,
span: Span,
) {
+ // FIXME: ideally we would want to trim the def paths, but this is not
+ // feasible with the current lint emission API (see issue #106126).
match self {
- CallToUnsafeFunction(did) if did.is_some() => tcx.emit_spanned_lint(
+ CallToUnsafeFunction(Some(did)) => tcx.emit_spanned_lint(
UNSAFE_OP_IN_UNSAFE_FN,
hir_id,
span,
UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe {
span,
- function: &tcx.def_path_str(did.unwrap()),
+ function: &with_no_trimmed_paths!(tcx.def_path_str(*did)),
},
),
- CallToUnsafeFunction(..) => tcx.emit_spanned_lint(
+ CallToUnsafeFunction(None) => tcx.emit_spanned_lint(
UNSAFE_OP_IN_UNSAFE_FN,
hir_id,
span,
span,
UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
span,
- function: &tcx.def_path_str(*did),
+ function: &with_no_trimmed_paths!(tcx.def_path_str(*did)),
},
),
}
unsafe_op_in_unsafe_fn_allowed: bool,
) {
match self {
- CallToUnsafeFunction(did) if did.is_some() && unsafe_op_in_unsafe_fn_allowed => {
+ CallToUnsafeFunction(Some(did)) if unsafe_op_in_unsafe_fn_allowed => {
tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
span,
- function: &tcx.def_path_str(did.unwrap()),
+ function: &tcx.def_path_str(*did),
});
}
- CallToUnsafeFunction(did) if did.is_some() => {
+ CallToUnsafeFunction(Some(did)) => {
tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafe {
span,
- function: &tcx.def_path_str(did.unwrap()),
+ function: &tcx.def_path_str(*did),
});
}
- CallToUnsafeFunction(..) if unsafe_op_in_unsafe_fn_allowed => {
+ CallToUnsafeFunction(None) if unsafe_op_in_unsafe_fn_allowed => {
tcx.sess.emit_err(
CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { span },
);
}
- CallToUnsafeFunction(..) => {
+ CallToUnsafeFunction(None) => {
tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless { span });
}
UseOfInlineAssembly if unsafe_op_in_unsafe_fn_allowed => {
//! Inlining pass for MIR functions
use crate::deref_separator::deref_finder;
use rustc_attr::InlineAttr;
+use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
const UNKNOWN_SIZE_COST: usize = 10;
+const TOP_DOWN_DEPTH_LIMIT: usize = 5;
+
pub struct Inline;
#[derive(Copy, Clone, Debug)]
let param_env = tcx.param_env_reveal_all_normalized(def_id);
- let mut this =
- Inliner { tcx, param_env, codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), changed: false };
+ let mut this = Inliner {
+ tcx,
+ param_env,
+ codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
+ history: Vec::new(),
+ changed: false,
+ };
let blocks = BasicBlock::new(0)..body.basic_blocks.next_index();
this.process_blocks(body, blocks);
this.changed
param_env: ParamEnv<'tcx>,
/// Caller codegen attributes.
codegen_fn_attrs: &'tcx CodegenFnAttrs,
+ /// Stack of inlined instances.
+ /// We only check the `DefId` and not the substs because we want to
+ /// avoid inlining cases of polymorphic recursion.
+ /// The number of `DefId`s is finite, so checking history is enough
+ /// to ensure that we do not loop endlessly while inlining.
+ history: Vec<DefId>,
/// Indicates that the caller body has been modified.
changed: bool,
}
impl<'tcx> Inliner<'tcx> {
fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBlock>) {
+ // How many callsites in this body are we allowed to inline? We need to limit this in order
+ // to prevent super-linear growth in MIR size
+ let inline_limit = match self.history.len() {
+ 0 => usize::MAX,
+ 1..=TOP_DOWN_DEPTH_LIMIT => 1,
+ _ => return,
+ };
+ let mut inlined_count = 0;
for bb in blocks {
let bb_data = &caller_body[bb];
if bb_data.is_cleanup {
debug!("not-inlined {} [{}]", callsite.callee, reason);
continue;
}
- Ok(_) => {
+ Ok(new_blocks) => {
debug!("inlined {}", callsite.callee);
self.changed = true;
- // We could process the blocks returned by `try_inlining` here. However, that
- // leads to exponential compile times due to the top-down nature of this kind
- // of inlining.
+ inlined_count += 1;
+ if inlined_count == inline_limit {
+ return;
+ }
+ self.history.push(callsite.callee.def_id());
+ self.process_blocks(caller_body, new_blocks);
+ self.history.pop();
}
}
}
return None;
}
+ if self.history.contains(&callee.def_id()) {
+ return None;
+ }
+
let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs);
let source_info = SourceInfo { span: fn_span, ..terminator.source_info };
pub use rustc_query_system::query::{deadlock, QueryContext};
pub use rustc_query_system::query::QueryConfig;
-pub(crate) use rustc_query_system::query::QueryVTable;
mod on_disk_cache;
pub use on_disk_cache::OnDiskCache;
&tcx.query_caches.$name
}
+ fn execute_query(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Stored {
+ tcx.$name(key)
+ }
+
#[inline]
- fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
- QueryVTable<QueryCtxt<'tcx>, Self::Key, Self::Value>
- {
- let compute = get_provider!([$($modifiers)*][tcx, $name, key]);
- let cache_on_disk = Self::cache_on_disk(tcx.tcx, key);
- QueryVTable {
- anon: is_anon!([$($modifiers)*]),
- eval_always: is_eval_always!([$($modifiers)*]),
- depth_limit: depth_limit!([$($modifiers)*]),
- feedable: feedable!([$($modifiers)*]),
- dep_kind: dep_graph::DepKind::$name,
- hash_result: hash_result!([$($modifiers)*]),
- handle_cycle_error: handle_cycle_error!([$($modifiers)*]),
- compute,
- try_load_from_disk: if cache_on_disk { should_ever_cache_on_disk!([$($modifiers)*]) } else { None },
- }
+ // key is only sometimes used
+ #[allow(unused_variables)]
+ fn compute(qcx: QueryCtxt<'tcx>, key: &Self::Key) -> fn(TyCtxt<'tcx>, Self::Key) -> Self::Value {
+ get_provider!([$($modifiers)*][qcx, $name, key])
}
- fn execute_query(tcx: TyCtxt<'tcx>, k: Self::Key) -> Self::Stored {
- tcx.$name(k)
+ #[inline]
+ fn try_load_from_disk(qcx: QueryCtxt<'tcx>, key: &Self::Key) -> rustc_query_system::query::TryLoadFromDisk<QueryCtxt<'tcx>, Self> {
+ let cache_on_disk = Self::cache_on_disk(qcx.tcx, key);
+ if cache_on_disk { should_ever_cache_on_disk!([$($modifiers)*]) } else { None }
}
+
+ const ANON: bool = is_anon!([$($modifiers)*]);
+ const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
+ const DEPTH_LIMIT: bool = depth_limit!([$($modifiers)*]);
+ const FEEDABLE: bool = feedable!([$($modifiers)*]);
+
+ const DEP_KIND: rustc_middle::dep_graph::DepKind = dep_graph::DepKind::$name;
+ const HANDLE_CYCLE_ERROR: rustc_query_system::HandleCycleError = handle_cycle_error!([$($modifiers)*]);
+
+ const HASH_RESULT: rustc_query_system::query::HashResult<QueryCtxt<'tcx>, Self> = hash_result!([$($modifiers)*]);
})*
#[allow(nonstandard_style)]
if dep_node_debug.borrow().contains_key(&dep_node) {
return;
}
- let debug_str = debug_str_gen();
+ let debug_str = self.with_ignore(debug_str_gen);
dep_node_debug.borrow_mut().insert(dep_node, debug_str);
}
);
if !side_effects.is_empty() {
- self.emit_side_effects(qcx, data, dep_node_index, side_effects);
+ self.with_query_deserialization(|| {
+ self.emit_side_effects(qcx, data, dep_node_index, side_effects)
+ });
}
// ... and finally storing a "Green" entry in the color map.
//! Query configuration and description traits.
-use crate::dep_graph::DepNode;
-use crate::dep_graph::SerializedDepNodeIndex;
+use crate::dep_graph::{DepNode, DepNodeParams, SerializedDepNodeIndex};
use crate::error::HandleCycleError;
use crate::ich::StableHashingContext;
use crate::query::caches::QueryCache;
use std::fmt::Debug;
use std::hash::Hash;
+pub type HashResult<Qcx, Q> =
+ Option<fn(&mut StableHashingContext<'_>, &<Q as QueryConfig<Qcx>>::Value) -> Fingerprint>;
+
+pub type TryLoadFromDisk<Qcx, Q> =
+ Option<fn(Qcx, SerializedDepNodeIndex) -> Option<<Q as QueryConfig<Qcx>>::Value>>;
+
pub trait QueryConfig<Qcx: QueryContext> {
const NAME: &'static str;
- type Key: Eq + Hash + Clone + Debug;
+ type Key: DepNodeParams<Qcx::DepContext> + Eq + Hash + Clone + Debug;
type Value: Debug;
type Stored: Debug + Clone + std::borrow::Borrow<Self::Value>;
where
Qcx: 'a;
- // Don't use this method to compute query results, instead use the methods on TyCtxt
- fn make_vtable(tcx: Qcx, key: &Self::Key) -> QueryVTable<Qcx, Self::Key, Self::Value>;
-
fn cache_on_disk(tcx: Qcx::DepContext, key: &Self::Key) -> bool;
// Don't use this method to compute query results, instead use the methods on TyCtxt
fn execute_query(tcx: Qcx::DepContext, k: Self::Key) -> Self::Stored;
-}
-#[derive(Copy, Clone)]
-pub struct QueryVTable<Qcx: QueryContext, K, V> {
- pub anon: bool,
- pub dep_kind: Qcx::DepKind,
- pub eval_always: bool,
- pub depth_limit: bool,
- pub feedable: bool,
-
- pub compute: fn(Qcx::DepContext, K) -> V,
- pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
- pub handle_cycle_error: HandleCycleError,
- // NOTE: this is also `None` if `cache_on_disk()` returns false, not just if it's unsupported by the query
- pub try_load_from_disk: Option<fn(Qcx, SerializedDepNodeIndex) -> Option<V>>,
-}
+ fn compute(tcx: Qcx, key: &Self::Key) -> fn(Qcx::DepContext, Self::Key) -> Self::Value;
-impl<Qcx: QueryContext, K, V> QueryVTable<Qcx, K, V> {
- pub(crate) fn to_dep_node(&self, tcx: Qcx::DepContext, key: &K) -> DepNode<Qcx::DepKind>
- where
- K: crate::dep_graph::DepNodeParams<Qcx::DepContext>,
- {
- DepNode::construct(tcx, self.dep_kind, key)
- }
+ fn try_load_from_disk(qcx: Qcx, idx: &Self::Key) -> TryLoadFromDisk<Qcx, Self>;
+
+ const ANON: bool;
+ const EVAL_ALWAYS: bool;
+ const DEPTH_LIMIT: bool;
+ const FEEDABLE: bool;
+
+ const DEP_KIND: Qcx::DepKind;
+ const HANDLE_CYCLE_ERROR: HandleCycleError;
+
+ const HASH_RESULT: HashResult<Qcx, Self>;
- pub(crate) fn compute(&self, tcx: Qcx::DepContext, key: K) -> V {
- (self.compute)(tcx, key)
+ // Just here for convernience and checking that the key matches the kind, don't override this.
+ fn construct_dep_node(tcx: Qcx::DepContext, key: &Self::Key) -> DepNode<Qcx::DepKind> {
+ DepNode::construct(tcx, Self::DEP_KIND, key)
}
}
};
mod config;
-pub use self::config::{QueryConfig, QueryVTable};
+pub use self::config::{HashResult, QueryConfig, TryLoadFromDisk};
use crate::dep_graph::DepKind;
use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
//! generate the actual methods on tcx which find and execute the provider,
//! manage the caches, and so forth.
-use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams};
+use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex};
use crate::ich::StableHashingContext;
use crate::query::caches::QueryCache;
-use crate::query::config::QueryVTable;
use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo};
use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
use crate::values::Value;
})
}
-fn try_execute_query<Qcx, C>(
+fn try_execute_query<Q, Qcx>(
qcx: Qcx,
- state: &QueryState<C::Key, Qcx::DepKind>,
- cache: &C,
+ state: &QueryState<Q::Key, Qcx::DepKind>,
+ cache: &Q::Cache,
span: Span,
- key: C::Key,
+ key: Q::Key,
dep_node: Option<DepNode<Qcx::DepKind>>,
- query: &QueryVTable<Qcx, C::Key, C::Value>,
-) -> (C::Stored, Option<DepNodeIndex>)
+) -> (Q::Stored, Option<DepNodeIndex>)
where
- C: QueryCache,
- C::Key: Clone + DepNodeParams<Qcx::DepContext>,
- C::Value: Value<Qcx::DepContext, Qcx::DepKind>,
- C::Stored: Debug + std::borrow::Borrow<C::Value>,
+ Q: QueryConfig<Qcx>,
Qcx: QueryContext,
{
- match JobOwner::<'_, C::Key, Qcx::DepKind>::try_start(&qcx, state, span, key.clone()) {
+ match JobOwner::<'_, Q::Key, Qcx::DepKind>::try_start(&qcx, state, span, key.clone()) {
TryGetJob::NotYetStarted(job) => {
- let (result, dep_node_index) = execute_job(qcx, key.clone(), dep_node, query, job.id);
- if query.feedable {
+ let (result, dep_node_index) =
+ execute_job::<Q, Qcx>(qcx, key.clone(), dep_node, job.id);
+ if Q::FEEDABLE {
// We may have put a value inside the cache from inside the execution.
// Verify that it has the same hash as what we have now, to ensure consistency.
let _ = cache.lookup(&key, |cached_result, _| {
- let hasher = query.hash_result.expect("feedable forbids no_hash");
+ let hasher = Q::HASH_RESULT.expect("feedable forbids no_hash");
+
let old_hash = qcx.dep_context().with_stable_hashing_context(|mut hcx| hasher(&mut hcx, cached_result.borrow()));
let new_hash = qcx.dep_context().with_stable_hashing_context(|mut hcx| hasher(&mut hcx, &result));
debug_assert_eq!(
old_hash, new_hash,
"Computed query value for {:?}({:?}) is inconsistent with fed value,\ncomputed={:#?}\nfed={:#?}",
- query.dep_kind, key, result, cached_result,
+ Q::DEP_KIND, key, result, cached_result,
);
});
}
(result, Some(dep_node_index))
}
TryGetJob::Cycle(error) => {
- let result = mk_cycle(qcx, error, query.handle_cycle_error, cache);
+ let result = mk_cycle(qcx, error, Q::HANDLE_CYCLE_ERROR, cache);
(result, None)
}
#[cfg(parallel_compiler)]
}
}
-fn execute_job<Qcx, K, V>(
+fn execute_job<Q, Qcx>(
qcx: Qcx,
- key: K,
+ key: Q::Key,
mut dep_node_opt: Option<DepNode<Qcx::DepKind>>,
- query: &QueryVTable<Qcx, K, V>,
job_id: QueryJobId,
-) -> (V, DepNodeIndex)
+) -> (Q::Value, DepNodeIndex)
where
- K: Clone + DepNodeParams<Qcx::DepContext>,
- V: Debug,
+ Q: QueryConfig<Qcx>,
Qcx: QueryContext,
{
let dep_graph = qcx.dep_context().dep_graph();
// Fast path for when incr. comp. is off.
if !dep_graph.is_fully_enabled() {
let prof_timer = qcx.dep_context().profiler().query_provider();
- let result = qcx.start_query(job_id, query.depth_limit, None, || {
- query.compute(*qcx.dep_context(), key)
+ let result = qcx.start_query(job_id, Q::DEPTH_LIMIT, None, || {
+ Q::compute(qcx, &key)(*qcx.dep_context(), key)
});
let dep_node_index = dep_graph.next_virtual_depnode_index();
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
return (result, dep_node_index);
}
- if !query.anon && !query.eval_always {
+ if !Q::ANON && !Q::EVAL_ALWAYS {
// `to_dep_node` is expensive for some `DepKind`s.
let dep_node =
- dep_node_opt.get_or_insert_with(|| query.to_dep_node(*qcx.dep_context(), &key));
+ dep_node_opt.get_or_insert_with(|| Q::construct_dep_node(*qcx.dep_context(), &key));
// The diagnostics for this query will be promoted to the current session during
// `try_mark_green()`, so we can ignore them here.
if let Some(ret) = qcx.start_query(job_id, false, None, || {
- try_load_from_disk_and_cache_in_memory(qcx, &key, &dep_node, query)
+ try_load_from_disk_and_cache_in_memory::<Q, Qcx>(qcx, &key, &dep_node)
}) {
return ret;
}
let diagnostics = Lock::new(ThinVec::new());
let (result, dep_node_index) =
- qcx.start_query(job_id, query.depth_limit, Some(&diagnostics), || {
- if query.anon {
- return dep_graph.with_anon_task(*qcx.dep_context(), query.dep_kind, || {
- query.compute(*qcx.dep_context(), key)
+ qcx.start_query(job_id, Q::DEPTH_LIMIT, Some(&diagnostics), || {
+ if Q::ANON {
+ return dep_graph.with_anon_task(*qcx.dep_context(), Q::DEP_KIND, || {
+ Q::compute(qcx, &key)(*qcx.dep_context(), key)
});
}
// `to_dep_node` is expensive for some `DepKind`s.
let dep_node =
- dep_node_opt.unwrap_or_else(|| query.to_dep_node(*qcx.dep_context(), &key));
+ dep_node_opt.unwrap_or_else(|| Q::construct_dep_node(*qcx.dep_context(), &key));
- dep_graph.with_task(dep_node, *qcx.dep_context(), key, query.compute, query.hash_result)
+ let task = Q::compute(qcx, &key);
+ dep_graph.with_task(dep_node, *qcx.dep_context(), key, task, Q::HASH_RESULT)
});
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
let side_effects = QuerySideEffects { diagnostics };
if std::intrinsics::unlikely(!side_effects.is_empty()) {
- if query.anon {
+ if Q::ANON {
qcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
} else {
qcx.store_side_effects(dep_node_index, side_effects);
(result, dep_node_index)
}
-fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
+fn try_load_from_disk_and_cache_in_memory<Q, Qcx>(
qcx: Qcx,
- key: &K,
+ key: &Q::Key,
dep_node: &DepNode<Qcx::DepKind>,
- query: &QueryVTable<Qcx, K, V>,
-) -> Option<(V, DepNodeIndex)>
+) -> Option<(Q::Value, DepNodeIndex)>
where
- K: Clone,
+ Q: QueryConfig<Qcx>,
Qcx: QueryContext,
- V: Debug,
{
// Note this function can be called concurrently from the same query
// We must ensure that this is handled correctly.
// First we try to load the result from the on-disk cache.
// Some things are never cached on disk.
- if let Some(try_load_from_disk) = query.try_load_from_disk {
+ if let Some(try_load_from_disk) = Q::try_load_from_disk(qcx, &key) {
let prof_timer = qcx.dep_context().profiler().incr_cache_loading();
// The call to `with_query_deserialization` enforces that no new `DepNodes`
if std::intrinsics::unlikely(
try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich,
) {
- incremental_verify_ich(*qcx.dep_context(), &result, dep_node, query.hash_result);
+ incremental_verify_ich(*qcx.dep_context(), &result, dep_node, Q::HASH_RESULT);
}
return Some((result, dep_node_index));
let prof_timer = qcx.dep_context().profiler().query_provider();
// The dep-graph for this computation is already in-place.
- let result = dep_graph.with_ignore(|| query.compute(*qcx.dep_context(), key.clone()));
+ let result = dep_graph.with_ignore(|| Q::compute(qcx, key)(*qcx.dep_context(), key.clone()));
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
//
// See issue #82920 for an example of a miscompilation that would get turned into
// an ICE by this check
- incremental_verify_ich(*qcx.dep_context(), &result, dep_node, query.hash_result);
+ incremental_verify_ich(*qcx.dep_context(), &result, dep_node, Q::HASH_RESULT);
Some((result, dep_node_index))
}
///
/// Note: The optimization is only available during incr. comp.
#[inline(never)]
-fn ensure_must_run<Qcx, K, V>(
- qcx: Qcx,
- key: &K,
- query: &QueryVTable<Qcx, K, V>,
-) -> (bool, Option<DepNode<Qcx::DepKind>>)
+fn ensure_must_run<Q, Qcx>(qcx: Qcx, key: &Q::Key) -> (bool, Option<DepNode<Qcx::DepKind>>)
where
- K: crate::dep_graph::DepNodeParams<Qcx::DepContext>,
+ Q: QueryConfig<Qcx>,
Qcx: QueryContext,
{
- if query.eval_always {
+ if Q::EVAL_ALWAYS {
return (true, None);
}
// Ensuring an anonymous query makes no sense
- assert!(!query.anon);
+ assert!(!Q::ANON);
- let dep_node = query.to_dep_node(*qcx.dep_context(), key);
+ let dep_node = Q::construct_dep_node(*qcx.dep_context(), key);
let dep_graph = qcx.dep_context().dep_graph();
match dep_graph.try_mark_green(qcx, &dep_node) {
where
D: DepKind,
Q: QueryConfig<Qcx>,
- Q::Key: DepNodeParams<Qcx::DepContext>,
Q::Value: Value<Qcx::DepContext, D>,
Qcx: QueryContext,
{
- let query = Q::make_vtable(qcx, &key);
let dep_node = if let QueryMode::Ensure = mode {
- let (must_run, dep_node) = ensure_must_run(qcx, &key, &query);
+ let (must_run, dep_node) = ensure_must_run::<Q, _>(qcx, &key);
if !must_run {
return None;
}
None
};
- let (result, dep_node_index) = try_execute_query(
+ let (result, dep_node_index) = try_execute_query::<Q, Qcx>(
qcx,
Q::query_state(qcx),
Q::query_cache(qcx),
span,
key,
dep_node,
- &query,
);
if let Some(dep_node_index) = dep_node_index {
qcx.dep_context().dep_graph().read_index(dep_node_index)
where
D: DepKind,
Q: QueryConfig<Qcx>,
- Q::Key: DepNodeParams<Qcx::DepContext>,
Q::Value: Value<Qcx::DepContext, D>,
Qcx: QueryContext,
{
Err(()) => {}
}
- let query = Q::make_vtable(qcx, &key);
let state = Q::query_state(qcx);
- debug_assert!(!query.anon);
+ debug_assert!(!Q::ANON);
- try_execute_query(qcx, state, cache, DUMMY_SP, key, Some(dep_node), &query);
+ try_execute_query::<Q, _>(qcx, state, cache, DUMMY_SP, key, Some(dep_node));
}
// binding if it exists. What we really want here is having two separate scopes in
// a module - one for non-globs and one for globs, but until that's done use this
// hack to avoid inconsistent resolution ICEs during import validation.
- let binding = [resolution.binding, resolution.shadowed_glob]
- .into_iter()
- .filter_map(|binding| match (binding, ignore_binding) {
+ let binding = [resolution.binding, resolution.shadowed_glob].into_iter().find_map(
+ |binding| match (binding, ignore_binding) {
(Some(binding), Some(ignored)) if ptr::eq(binding, ignored) => None,
_ => binding,
- })
- .next();
+ },
+ );
let Some(binding) = binding else {
return Err((Determined, Weak::No));
};
pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
}
+
+ #[allow(rustc::bad_opt_access)]
+ pub fn incremental_relative_spans(&self) -> bool {
+ self.unstable_opts.incremental_relative_spans
+ || (self.unstable_features.is_nightly_build() && self.incremental.is_some())
+ }
}
impl UnstableOptions {
"generate human-readable, predictable names for codegen units (default: no)"),
identify_regions: bool = (false, parse_bool, [UNTRACKED],
"display unnamed regions as `'<id>`, using a non-ident unique id (default: no)"),
- incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
+ incremental_ignore_spans: bool = (false, parse_bool, [TRACKED],
"ignore spans during ICH computation -- used for testing (default: no)"),
incremental_info: bool = (false, parse_bool, [UNTRACKED],
"print high-level information about incremental reuse (or the lack thereof) \
(default: no)"),
+ #[rustc_lint_opt_deny_field_access("use `Session::incremental_relative_spans` instead of this field")]
incremental_relative_spans: bool = (false, parse_bool, [TRACKED],
"hash spans relative to their parent item for incr. comp. (default: no)"),
incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
// `-Z incremental-ignore-spans` option. Normally, this option is disabled,
// which will cause us to require that this method always be called with `Span` hashing
// enabled.
+ //
+ // Span hashing can also be disabled without `-Z incremental-ignore-spans`.
+ // This is the case for instance when building a hash for name mangling.
+ // Such configuration must not be used for metadata.
HashingControls { hash_spans }
if hash_spans == !ctx.unstable_opts_incremental_ignore_spans() => {}
other => panic!("Attempted hashing of {msg} with non-default HashingControls: {:?}", other),
// The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
// See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28
-use crate::def_id::LocalDefId;
+use crate::def_id::{DefIndex, LocalDefId};
use crate::hygiene::SyntaxContext;
use crate::SPAN_TRACK;
use crate::{BytePos, SpanData};
/// A compressed span.
///
-/// Whereas [`SpanData`] is 12 bytes, which is a bit too big to stick everywhere, `Span`
-/// is a form that only takes up 8 bytes, with less space for the length and
+/// Whereas [`SpanData`] is 16 bytes, which is a bit too big to stick everywhere, `Span`
+/// is a form that only takes up 8 bytes, with less space for the length, parent and
/// context. The vast majority (99.9%+) of `SpanData` instances will fit within
/// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are
/// stored in a separate interner table, and the `Span` will index into that
/// slower because only 80--90% of spans could be stored inline (even less in
/// very large crates) and so the interner was used a lot more.
///
-/// Inline (compressed) format:
+/// Inline (compressed) format with no parent:
/// - `span.base_or_index == span_data.lo`
/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
///
+/// Inline (compressed) format with root context:
+/// - `span.base_or_index == span_data.lo`
+/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
+/// - `span.len_or_tag` has top bit (`PARENT_MASK`) set
+/// - `span.ctxt == span_data.parent` (must be `<= MAX_CTXT`)
+///
/// Interned format:
/// - `span.base_or_index == index` (indexes into the interner table)
/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
ctxt_or_tag: u16,
}
-const LEN_TAG: u16 = 0b1000_0000_0000_0000;
+const LEN_TAG: u16 = 0b1111_1111_1111_1111;
+const PARENT_MASK: u16 = 0b1000_0000_0000_0000;
const MAX_LEN: u32 = 0b0111_1111_1111_1111;
const CTXT_TAG: u32 = 0b1111_1111_1111_1111;
const MAX_CTXT: u32 = CTXT_TAG - 1;
let (base, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32());
- if len <= MAX_LEN && ctxt2 <= MAX_CTXT && parent.is_none() {
- // Inline format.
- Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_tag: ctxt2 as u16 }
- } else {
- // Interned format.
- let index =
- with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
- let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
- Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
+ if len <= MAX_LEN && ctxt2 <= MAX_CTXT {
+ let len_or_tag = len as u16;
+ debug_assert_eq!(len_or_tag & PARENT_MASK, 0);
+
+ if let Some(parent) = parent {
+ // Inline format with parent.
+ let len_or_tag = len_or_tag | PARENT_MASK;
+ let parent2 = parent.local_def_index.as_u32();
+ if ctxt2 == SyntaxContext::root().as_u32() && parent2 <= MAX_CTXT {
+ return Span { base_or_index: base, len_or_tag, ctxt_or_tag: parent2 as u16 };
+ }
+ } else {
+ // Inline format with ctxt.
+ return Span {
+ base_or_index: base,
+ len_or_tag: len as u16,
+ ctxt_or_tag: ctxt2 as u16,
+ };
+ }
}
+
+ // Interned format.
+ let index =
+ with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
+ let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
+ Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
}
#[inline]
pub fn data_untracked(self) -> SpanData {
if self.len_or_tag != LEN_TAG {
// Inline format.
- debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
- SpanData {
- lo: BytePos(self.base_or_index),
- hi: BytePos(self.base_or_index + self.len_or_tag as u32),
- ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
- parent: None,
+ if self.len_or_tag & PARENT_MASK == 0 {
+ debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
+ SpanData {
+ lo: BytePos(self.base_or_index),
+ hi: BytePos(self.base_or_index + self.len_or_tag as u32),
+ ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
+ parent: None,
+ }
+ } else {
+ let len = self.len_or_tag & !PARENT_MASK;
+ debug_assert!(len as u32 <= MAX_LEN);
+ let parent =
+ LocalDefId { local_def_index: DefIndex::from_u32(self.ctxt_or_tag as u32) };
+ SpanData {
+ lo: BytePos(self.base_or_index),
+ hi: BytePos(self.base_or_index + len as u32),
+ ctxt: SyntaxContext::root(),
+ parent: Some(parent),
+ }
}
} else {
// Interned format.
pub fn ctxt(self) -> SyntaxContext {
let ctxt_or_tag = self.ctxt_or_tag as u32;
if ctxt_or_tag <= MAX_CTXT {
- // Inline format or interned format with inline ctxt.
- SyntaxContext::from_u32(ctxt_or_tag)
+ if self.len_or_tag == LEN_TAG || self.len_or_tag & PARENT_MASK == 0 {
+ // Inline format or interned format with inline ctxt.
+ SyntaxContext::from_u32(ctxt_or_tag)
+ } else {
+ // Inline format or interned format with inline parent.
+ // We know that the SyntaxContext is root.
+ SyntaxContext::root()
+ }
} else {
// Interned format.
let index = self.base_or_index;
#[inline]
pub(super) fn has_overflow(&self, depth: usize) -> bool {
- self.current_limit.value_within_limit(depth + self.additional_depth)
+ !self.current_limit.value_within_limit(depth + self.additional_depth)
}
/// Updating the current limit when hitting overflow.
})) = call_node
{
if Some(rcvr.span) == err.span.primary_span() {
- err.replace_span_with(path.ident.span);
+ err.replace_span_with(path.ident.span, true);
}
}
if let Some(Node::Expr(hir::Expr {
| PointerKind::UniqueBorrowed
| PointerKind::UniqueBorrowedPinned => false,
PointerKind::UniqueOwned => noalias_for_box,
- PointerKind::Frozen => !is_return,
+ PointerKind::Frozen => true,
};
- if no_alias {
+ // We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics
+ // (see <https://github.com/rust-lang/unsafe-code-guidelines/issues/385#issuecomment-1368055745>).
+ if no_alias && !is_return {
attrs.set(ArgAttribute::NoAlias);
}
// `#[alloc_error_handler]`.
#[rustc_std_internal_symbol]
pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
- panic!("memory allocation of {size} bytes failed")
+ extern "Rust" {
+ // This symbol is emitted by rustc next to __rust_alloc_error_handler.
+ // Its value depends on the -Zoom={panic,abort} compiler option.
+ static __rust_alloc_error_handler_should_panic: u8;
+ }
+
+ #[allow(unused_unsafe)]
+ if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
+ panic!("memory allocation of {size} bytes failed")
+ } else {
+ core::panicking::panic_nounwind_fmt(format_args!(
+ "memory allocation of {size} bytes failed"
+ ))
+ }
}
}
#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_refs_to_cell)]
#![feature(core_intrinsics)]
+#![feature(core_panic)]
#![feature(const_eval_select)]
#![feature(const_pin)]
#![feature(const_waker)]
#![feature(const_unsafecell_get_mut)]
#![feature(const_waker)]
#![feature(core_panic)]
+#![feature(char_indices_offset)]
#![feature(duration_consts_float)]
#![feature(maybe_uninit_uninit_array)]
#![feature(ptr_alignment_type)]
#![feature(slice_ptr_get)]
#![feature(slice_split_at_unchecked)]
#![feature(str_internals)]
+#![feature(str_split_remainder)]
+#![feature(str_split_inclusive_remainder)]
#![feature(strict_provenance)]
#![feature(utf16_extra)]
#![feature(utf16_extra_const)]
unsafe { panic_impl(&pi) }
}
-/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize.
-/// (No `fmt` variant as a `fmt::Arguments` needs more space to be passed.)
+/// Like `panic_fmt`, but for non-unwinding panics.
+///
+/// Has to be a separate function so that it can carry the `rustc_nounwind` attribute.
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cfg_attr(not(bootstrap), lang = "panic_nounwind")] // needed by codegen for non-unwinding panics
+#[track_caller]
+// This attribute has the key side-effect that if the panic handler ignores `can_unwind`
+// and unwinds anyway, we will hit the "unwinding out of nounwind function" guard,
+// which causes a "panic in a function that cannot unwind".
#[rustc_nounwind]
-pub fn panic_nounwind(msg: &'static str) -> ! {
+pub fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>) -> ! {
if cfg!(feature = "panic_immediate_abort") {
super::intrinsics::abort()
}
}
// PanicInfo with the `can_unwind` flag set to false forces an abort.
- let pieces = [msg];
- let fmt = fmt::Arguments::new_v1(&pieces, &[]);
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]));
}
+/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize.
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(bootstrap), lang = "panic_nounwind")] // needed by codegen for non-unwinding panics
+#[rustc_nounwind]
+pub fn panic_nounwind(expr: &'static str) -> ! {
+ panic_nounwind_fmt(fmt::Arguments::new_v1(&[expr], &[]));
+}
+
#[inline]
#[track_caller]
#[rustc_diagnostic_item = "panic_str"]
impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
#[inline]
fn get_end(&mut self) -> Option<&'a str> {
- if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) {
+ if !self.finished {
self.finished = true;
- // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
- unsafe {
- let string = self.matcher.haystack().get_unchecked(self.start..self.end);
- Some(string)
+
+ if self.allow_trailing_empty || self.end - self.start > 0 {
+ // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
+ let string = unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) };
+ return Some(string);
}
- } else {
- None
}
+
+ None
}
#[inline]
}
#[inline]
- fn as_str(&self) -> &'a str {
+ fn remainder(&self) -> Option<&'a str> {
// `Self::get_end` doesn't change `self.start`
if self.finished {
- return "";
+ return None;
}
// SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
- unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) }
+ Some(unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) })
}
}
}
impl<'a, P: Pattern<'a>> Split<'a, P> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_as_str)]
+ /// #![feature(str_split_remainder)]
/// let mut split = "Mary had a little lamb".split(' ');
- /// assert_eq!(split.as_str(), "Mary had a little lamb");
+ /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
/// split.next();
- /// assert_eq!(split.as_str(), "had a little lamb");
+ /// assert_eq!(split.remainder(), Some("had a little lamb"));
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
- #[unstable(feature = "str_split_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.0.as_str()
+ #[unstable(feature = "str_split_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.0.remainder()
}
}
impl<'a, P: Pattern<'a>> RSplit<'a, P> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_as_str)]
+ /// #![feature(str_split_remainder)]
/// let mut split = "Mary had a little lamb".rsplit(' ');
- /// assert_eq!(split.as_str(), "Mary had a little lamb");
+ /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
/// split.next();
- /// assert_eq!(split.as_str(), "Mary had a little");
+ /// assert_eq!(split.remainder(), Some("Mary had a little"));
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
- #[unstable(feature = "str_split_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.0.as_str()
+ #[unstable(feature = "str_split_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.0.remainder()
}
}
}
impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_as_str)]
+ /// #![feature(str_split_remainder)]
/// let mut split = "A..B..".split_terminator('.');
- /// assert_eq!(split.as_str(), "A..B..");
+ /// assert_eq!(split.remainder(), Some("A..B.."));
/// split.next();
- /// assert_eq!(split.as_str(), ".B..");
+ /// assert_eq!(split.remainder(), Some(".B.."));
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
- #[unstable(feature = "str_split_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.0.as_str()
+ #[unstable(feature = "str_split_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.0.remainder()
}
}
impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_as_str)]
+ /// #![feature(str_split_remainder)]
/// let mut split = "A..B..".rsplit_terminator('.');
- /// assert_eq!(split.as_str(), "A..B..");
+ /// assert_eq!(split.remainder(), Some("A..B.."));
/// split.next();
- /// assert_eq!(split.as_str(), "A..B");
+ /// assert_eq!(split.remainder(), Some("A..B"));
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
- #[unstable(feature = "str_split_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.0.as_str()
+ #[unstable(feature = "str_split_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.0.remainder()
}
}
}
#[inline]
- fn as_str(&self) -> &'a str {
- self.iter.as_str()
+ fn remainder(&self) -> Option<&'a str> {
+ self.iter.remainder()
}
}
}
impl<'a, P: Pattern<'a>> SplitN<'a, P> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_as_str)]
+ /// #![feature(str_split_remainder)]
/// let mut split = "Mary had a little lamb".splitn(3, ' ');
- /// assert_eq!(split.as_str(), "Mary had a little lamb");
+ /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
/// split.next();
- /// assert_eq!(split.as_str(), "had a little lamb");
+ /// assert_eq!(split.remainder(), Some("had a little lamb"));
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
- #[unstable(feature = "str_split_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.0.as_str()
+ #[unstable(feature = "str_split_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.0.remainder()
}
}
impl<'a, P: Pattern<'a>> RSplitN<'a, P> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_as_str)]
+ /// #![feature(str_split_remainder)]
/// let mut split = "Mary had a little lamb".rsplitn(3, ' ');
- /// assert_eq!(split.as_str(), "Mary had a little lamb");
+ /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
/// split.next();
- /// assert_eq!(split.as_str(), "Mary had a little");
+ /// assert_eq!(split.remainder(), Some("Mary had a little"));
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
- #[unstable(feature = "str_split_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.0.as_str()
+ #[unstable(feature = "str_split_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.0.remainder()
}
}
/// # Examples
///
/// ```
- /// #![feature(str_split_whitespace_as_str)]
+ /// #![feature(str_split_whitespace_remainder)]
///
/// let mut split = "Mary had a little lamb".split_whitespace();
- /// assert_eq!(split.as_str(), "Mary had a little lamb");
+ /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
///
/// split.next();
- /// assert_eq!(split.as_str(), "had a little lamb");
+ /// assert_eq!(split.remainder(), Some("had a little lamb"));
///
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
#[must_use]
- #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.inner.iter.as_str()
+ #[unstable(feature = "str_split_whitespace_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.inner.iter.remainder()
}
}
impl FusedIterator for SplitAsciiWhitespace<'_> {}
impl<'a> SplitAsciiWhitespace<'a> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_whitespace_as_str)]
+ /// #![feature(str_split_whitespace_remainder)]
///
/// let mut split = "Mary had a little lamb".split_ascii_whitespace();
- /// assert_eq!(split.as_str(), "Mary had a little lamb");
+ /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
///
/// split.next();
- /// assert_eq!(split.as_str(), "had a little lamb");
+ /// assert_eq!(split.remainder(), Some("had a little lamb"));
///
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
#[must_use]
- #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
+ #[unstable(feature = "str_split_whitespace_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
if self.inner.iter.iter.finished {
- return "";
+ return None;
}
// SAFETY: Slice is created from str.
- unsafe { crate::str::from_utf8_unchecked(&self.inner.iter.iter.v) }
+ Some(unsafe { crate::str::from_utf8_unchecked(&self.inner.iter.iter.v) })
}
}
impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> {
- /// Returns remainder of the split string
+ /// Returns remainder of the split string.
+ ///
+ /// If the iterator is empty, returns `None`.
///
/// # Examples
///
/// ```
- /// #![feature(str_split_inclusive_as_str)]
+ /// #![feature(str_split_inclusive_remainder)]
/// let mut split = "Mary had a little lamb".split_inclusive(' ');
- /// assert_eq!(split.as_str(), "Mary had a little lamb");
+ /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
/// split.next();
- /// assert_eq!(split.as_str(), "had a little lamb");
+ /// assert_eq!(split.remainder(), Some("had a little lamb"));
/// split.by_ref().for_each(drop);
- /// assert_eq!(split.as_str(), "");
+ /// assert_eq!(split.remainder(), None);
/// ```
#[inline]
- #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")]
- pub fn as_str(&self) -> &'a str {
- self.0.as_str()
+ #[unstable(feature = "str_split_inclusive_remainder", issue = "77998")]
+ pub fn remainder(&self) -> Option<&'a str> {
+ self.0.remainder()
}
}
// are contravariant while return-position lifetimes are
// covariant).
_marker: PhantomData<fn(&'a ()) -> &'a ()>,
+ // Ensure `Context` is `!Send` and `!Sync` in order to allow
+ // for future `!Send` and / or `!Sync` fields.
+ _marker2: PhantomData<*mut ()>,
}
impl<'a> Context<'a> {
#[must_use]
#[inline]
pub const fn from_waker(waker: &'a Waker) -> Self {
- Context { waker, _marker: PhantomData }
+ Context { waker, _marker: PhantomData, _marker2: PhantomData }
}
/// Returns a reference to the [`Waker`] for the current task.
-use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
+use core::task::{Poll, RawWaker, RawWakerVTable, Waker};
#[test]
fn poll_const() {
static WAKER: Waker = unsafe { Waker::from_raw(VOID_WAKER) };
- static CONTEXT: Context<'static> = Context::from_waker(&WAKER);
-
- static WAKER_REF: &'static Waker = CONTEXT.waker();
-
- WAKER_REF.wake_by_ref();
+ WAKER.wake_by_ref();
}
#[allow(unused_unsafe)]
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
- panic!("memory allocation of {} bytes failed\n", layout.size());
+ panic!("memory allocation of {} bytes failed", layout.size());
} else {
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
}
}
/// Read all bytes until a newline (the `0xA` byte) is reached, and append
- /// them to the provided buffer. You do not need to clear the buffer before
- /// appending.
+ /// them to the provided `String` buffer.
+ ///
+ /// Previous content of the buffer will be preserved. To avoid appending to
+ /// the buffer, you need to [`clear`] it first.
///
/// This function will read bytes from the underlying stream until the
/// newline delimiter (the `0xA` byte) or EOF is found. Once found, all bytes
///
/// This function is blocking and should be used carefully: it is possible for
/// an attacker to continuously send bytes without ever sending a newline
- /// or EOF.
+ /// or EOF. You can use [`take`] to limit the maximum number of bytes read.
///
/// [`Ok(0)`]: Ok
+ /// [`clear`]: String::clear
+ /// [`take`]: crate::io::Read::take
///
/// # Errors
///
self.push(file_name);
}
- /// Updates [`self.extension`] to `extension`.
+ /// Updates [`self.extension`] to `Some(extension)` or to `None` if
+ /// `extension` is empty.
///
/// Returns `false` and does nothing if [`self.file_name`] is [`None`],
/// returns `true` and updates the extension otherwise.
/// If [`self.extension`] is [`None`], the extension is added; otherwise
/// it is replaced.
///
+ /// If `extension` is the empty string, [`self.extension`] will be [`None`]
+ /// afterwards, not `Some("")`.
+ ///
+ /// # Caveats
+ ///
+ /// The new `extension` may contain dots and will be used in its entirety,
+ /// but only the part after the final dot will be reflected in
+ /// [`self.extension`].
+ ///
+ /// If the file stem contains internal dots and `extension` is empty, part
+ /// of the old file stem will be considered the new [`self.extension`].
+ ///
+ /// See the examples below.
+ ///
/// [`self.file_name`]: Path::file_name
/// [`self.extension`]: Path::extension
///
/// p.set_extension("force");
/// assert_eq!(Path::new("/feel/the.force"), p.as_path());
///
- /// p.set_extension("dark_side");
- /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path());
+ /// p.set_extension("dark.side");
+ /// assert_eq!(Path::new("/feel/the.dark.side"), p.as_path());
+ ///
+ /// p.set_extension("cookie");
+ /// assert_eq!(Path::new("/feel/the.dark.cookie"), p.as_path());
+ ///
+ /// p.set_extension("");
+ /// assert_eq!(Path::new("/feel/the.dark"), p.as_path());
+ ///
+ /// p.set_extension("");
+ /// assert_eq!(Path::new("/feel/the"), p.as_path());
+ ///
+ /// p.set_extension("");
+ /// assert_eq!(Path::new("/feel/the"), p.as_path());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
if len(sys.argv) > 1 and sys.argv[1] == 'help':
sys.argv = [sys.argv[0], '-h'] + sys.argv[2:]
- help_triggered = (
- '-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1)
+ help_triggered = len(sys.argv) == 1 or any(x in ["-h", "--help", "--version"] for x in sys.argv)
try:
bootstrap(help_triggered)
if not help_triggered:
"Checking stage{} library artifacts ({} -> {})",
builder.top_stage, &compiler.host, target
));
- run_cargo(builder, cargo, &libstd_stamp(builder, compiler, target), vec![], true);
+ run_cargo(builder, cargo, &libstd_stamp(builder, compiler, target), vec![], true, false);
// We skip populating the sysroot in non-zero stage because that'll lead
// to rlib/rmeta conflicts if std gets built during this session.
"Checking stage{} library test/bench/example targets ({} -> {})",
builder.top_stage, &compiler.host, target
));
- run_cargo(builder, cargo, &libstd_test_stamp(builder, compiler, target), vec![], true);
+ run_cargo(
+ builder,
+ cargo,
+ &libstd_test_stamp(builder, compiler, target),
+ vec![],
+ true,
+ false,
+ );
}
}
"Checking stage{} compiler artifacts ({} -> {})",
builder.top_stage, &compiler.host, target
));
- run_cargo(builder, cargo, &librustc_stamp(builder, compiler, target), vec![], true);
+ run_cargo(builder, cargo, &librustc_stamp(builder, compiler, target), vec![], true, false);
let libdir = builder.sysroot_libdir(compiler, target);
let hostdir = builder.sysroot_libdir(compiler, compiler.host);
&codegen_backend_stamp(builder, compiler, target, backend),
vec![],
true,
+ false,
);
}
}
"Checking stage{} {} artifacts ({} -> {})",
compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple
));
- run_cargo(builder, cargo, &stamp(builder, compiler, target), vec![], true);
+ run_cargo(builder, cargo, &stamp(builder, compiler, target), vec![], true, false);
/// Cargo's output path in a given stage, compiled by a particular
/// compiler for the specified target.
&stamp(builder, compiler, target),
vec![],
true,
+ false,
);
/// Cargo's output path in a given stage, compiled by a particular
&compiler.host,
target,
));
- run_cargo(builder, cargo, &libstd_stamp(builder, compiler, target), target_deps, false);
+ run_cargo(
+ builder,
+ cargo,
+ &libstd_stamp(builder, compiler, target),
+ target_deps,
+ false,
+ false,
+ );
builder.ensure(StdLink::from_std(
self,
&compiler.host,
target,
));
- run_cargo(builder, cargo, &librustc_stamp(builder, compiler, target), vec![], false);
+ run_cargo(
+ builder,
+ cargo,
+ &librustc_stamp(builder, compiler, target),
+ vec![],
+ false,
+ true, // Only ship rustc_driver.so and .rmeta files, not all intermediate .rlib files.
+ );
builder.ensure(RustcLink::from_rustc(
self,
"Building stage{} codegen backend {} ({} -> {})",
compiler.stage, backend, &compiler.host, target
));
- let files = run_cargo(builder, cargo, &tmp_stamp, vec![], false);
+ let files = run_cargo(builder, cargo, &tmp_stamp, vec![], false, false);
if builder.config.dry_run() {
return;
}
stamp: &Path,
additional_target_deps: Vec<(PathBuf, DependencyType)>,
is_check: bool,
+ rlib_only_metadata: bool,
) -> Vec<PathBuf> {
if builder.config.dry_run() {
return Vec::new();
};
for filename in filenames {
// Skip files like executables
- if !(filename.ends_with(".rlib")
- || filename.ends_with(".lib")
+ let mut keep = false;
+ if filename.ends_with(".lib")
|| filename.ends_with(".a")
|| is_debug_info(&filename)
|| is_dylib(&filename)
- || (is_check && filename.ends_with(".rmeta")))
{
+ // Always keep native libraries, rust dylibs and debuginfo
+ keep = true;
+ }
+ if is_check && filename.ends_with(".rmeta") {
+ // During check builds we need to keep crate metadata
+ keep = true;
+ } else if rlib_only_metadata {
+ if filename.contains("jemalloc_sys") || filename.contains("rustc_smir") {
+ // jemalloc_sys and rustc_smir are not linked into librustc_driver.so,
+ // so we need to distribute them as rlib to be able to use them.
+ keep |= filename.ends_with(".rlib");
+ } else {
+ // Distribute the rest of the rustc crates as rmeta files only to reduce
+ // the tarball sizes by about 50%. The object files are linked into
+ // librustc_driver.so, so it is still possible to link against them.
+ keep |= filename.ends_with(".rmeta");
+ }
+ } else {
+ // In all other cases keep all rlibs
+ keep |= filename.ends_with(".rlib");
+ }
+
+ if !keep {
continue;
}
builder.ensure(crate::native::Llvm { target });
+ // We want to package `lld` to use it with `download-ci-llvm`.
+ builder.ensure(crate::native::Lld { target });
+
let src_bindir = builder.llvm_out(target).join("bin");
// If updating this list, you likely want to change
// src/bootstrap/download-ci-llvm-stamp as well, otherwise local users
Change this file to make users of the `download-ci-llvm` configuration download
a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
-Last change is for: https://github.com/rust-lang/rust/pull/102790
+Last change is for: https://github.com/rust-lang/rust/pull/104748
}
}
-// This returns whether we've already previously built LLVM.
-//
-// It's used to avoid busting caches during x.py check -- if we've already built
-// LLVM, it's fine for us to not try to avoid doing so.
-//
-// This will return the llvm-config if it can get it (but it will not build it
-// if not).
+/// This returns whether we've already previously built LLVM.
+///
+/// It's used to avoid busting caches during x.py check -- if we've already built
+/// LLVM, it's fine for us to not try to avoid doing so.
+///
+/// This will return the llvm-config if it can get it (but it will not build it
+/// if not).
pub fn prebuilt_llvm_config(
builder: &Builder<'_>,
target: TargetSelection,
}
let target = self.target;
- let LlvmResult { llvm_config, llvm_cmake_dir } =
- builder.ensure(Llvm { target: self.target });
+ let LlvmResult { llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target });
+
+ // The `dist` step packages LLD next to LLVM's binaries for download-ci-llvm. The root path
+ // we usually expect here is `./build/$triple/ci-llvm/`, with the binaries in its `bin`
+ // subfolder. We check if that's the case, and if LLD's binary already exists there next to
+ // `llvm-config`: if so, we can use it instead of building LLVM/LLD from source.
+ let ci_llvm_bin = llvm_config.parent().unwrap();
+ if ci_llvm_bin.is_dir() && ci_llvm_bin.file_name().unwrap() == "bin" {
+ let lld_path = ci_llvm_bin.join(exe("lld", target));
+ if lld_path.exists() {
+ // The following steps copying `lld` as `rust-lld` to the sysroot, expect it in the
+ // `bin` subfolder of this step's out dir.
+ return ci_llvm_bin.parent().unwrap().to_path_buf();
+ }
+ }
let out_dir = builder.lld_out(target);
let done_stamp = out_dir.join("lld-finished-building");
COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
-ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
ENV SCRIPT python3 ../x.py test --stage 0 src/tools/tidy tidyselftest
$SRC/configure --set rust.parallel-compiler
# Save the build metrics before we wipe the directory
- if [ $HAS_METRICS = 1 ]; then
+ if [ "$HAS_METRICS" = 1 ]; then
mv build/metrics.json .
fi
rm -rf build
- if [ $HAS_METRICS = 1 ]; then
+ if [ "$HAS_METRICS" = 1 ]; then
mkdir build
mv metrics.json build
fi
-Subproject commit a60f4316ec923a5ac2ed6a2eba6960edb832d855
+Subproject commit 2bd5d42c9956369132228da6409f0e68da56c51a
-Subproject commit dd37e21ccee43918ed18a71581bb2af537ffe4fc
+Subproject commit 8ca261268068d80c0969260fff15199bad87b587
-Subproject commit 995df09b65c582eb6290ab7ea5d9485983eb4c37
+Subproject commit 8888f9428fe9a48f31de6bd2cef9b9bf80791edc
-Subproject commit 8b42eb5f57d3d8ed2257a22d0e850d9db52afed3
+Subproject commit b3e2a6e6c8a3aae5b5d950c63046f23bae07096d
ty::Placeholder(..) => panic!("Placeholder"),
ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
ty::Infer(..) => panic!("Infer"),
- ty::Error(_) => panic!("Error"),
+ ty::Error(_) => rustc_errors::FatalError.raise(),
}
}
}
pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
+ let discriminant = match variant.discr {
+ ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
+ ty::VariantDiscr::Relative(_) => None,
+ };
+
let kind = match variant.ctor_kind() {
- Some(CtorKind::Const) => Variant::CLike(match variant.discr {
- ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
- ty::VariantDiscr::Relative(_) => None,
- }),
- Some(CtorKind::Fn) => Variant::Tuple(
+ Some(CtorKind::Const) => VariantKind::CLike,
+ Some(CtorKind::Fn) => VariantKind::Tuple(
variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
),
- None => Variant::Struct(VariantStruct {
- ctor_kind: None,
+ None => VariantKind::Struct(VariantStruct {
fields: variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
}),
};
- Item::from_def_id_and_parts(variant.def_id, Some(variant.name), VariantItem(kind), cx)
+
+ Item::from_def_id_and_parts(
+ variant.def_id,
+ Some(variant.name),
+ VariantItem(Variant { kind, discriminant }),
+ cx,
+ )
}
fn clean_variant_data<'tcx>(
disr_expr: &Option<hir::AnonConst>,
cx: &mut DocContext<'tcx>,
) -> Variant {
- match variant {
- hir::VariantData::Struct(..) => Variant::Struct(VariantStruct {
- ctor_kind: None,
+ let discriminant = disr_expr.map(|disr| Discriminant {
+ expr: Some(disr.body),
+ value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
+ });
+
+ let kind = match variant {
+ hir::VariantData::Struct(..) => VariantKind::Struct(VariantStruct {
fields: variant.fields().iter().map(|x| clean_field(x, cx)).collect(),
}),
hir::VariantData::Tuple(..) => {
- Variant::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
+ VariantKind::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
}
- hir::VariantData::Unit(..) => Variant::CLike(disr_expr.map(|disr| Discriminant {
- expr: Some(disr.body),
- value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
- })),
- }
+ hir::VariantData::Unit(..) => VariantKind::CLike,
+ };
+
+ Variant { discriminant, kind }
}
fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
match self {
StructItem(s) => s.fields.iter(),
UnionItem(u) => u.fields.iter(),
- VariantItem(Variant::Struct(v)) => v.fields.iter(),
- VariantItem(Variant::Tuple(v)) => v.iter(),
+ VariantItem(v) => match &v.kind {
+ VariantKind::CLike => [].iter(),
+ VariantKind::Tuple(t) => t.iter(),
+ VariantKind::Struct(s) => s.fields.iter(),
+ },
EnumItem(e) => e.variants.iter(),
TraitItem(t) => t.items.iter(),
ImplItem(i) => i.items.iter(),
| TyMethodItem(_)
| MethodItem(_, _)
| StructFieldItem(_)
- | VariantItem(_)
| ForeignFunctionItem(_)
| ForeignStaticItem(_)
| ForeignTypeItem
/// only as a variant in an enum.
#[derive(Clone, Debug)]
pub(crate) struct VariantStruct {
- pub(crate) ctor_kind: Option<CtorKind>,
pub(crate) fields: Vec<Item>,
}
}
#[derive(Clone, Debug)]
-pub(crate) enum Variant {
- CLike(Option<Discriminant>),
+pub(crate) struct Variant {
+ pub kind: VariantKind,
+ pub discriminant: Option<Discriminant>,
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum VariantKind {
+ CLike,
Tuple(Vec<Item>),
Struct(VariantStruct),
}
impl Variant {
pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
- match *self {
- Self::Struct(ref struct_) => Some(struct_.has_stripped_entries()),
- Self::CLike(..) | Self::Tuple(_) => None,
+ match &self.kind {
+ VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
+ VariantKind::CLike | VariantKind::Tuple(_) => None,
}
}
}
i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
ImplItem(i)
}
- VariantItem(i) => match i {
- Variant::Struct(mut j) => {
- j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
- VariantItem(Variant::Struct(j))
- }
- Variant::Tuple(fields) => {
- let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
- VariantItem(Variant::Tuple(fields))
- }
- Variant::CLike(disr) => VariantItem(Variant::CLike(disr)),
- },
+ VariantItem(Variant { kind, discriminant }) => {
+ let kind = match kind {
+ VariantKind::Struct(mut j) => {
+ j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+ VariantKind::Struct(j)
+ }
+ VariantKind::Tuple(fields) => {
+ let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+ VariantKind::Tuple(fields)
+ }
+ VariantKind::CLike => VariantKind::CLike,
+ };
+
+ VariantItem(Variant { kind, discriminant })
+ }
ExternCrateItem { src: _ }
| ImportItem(_)
| FunctionItem(_)
w.write_str(" ");
let name = v.name.unwrap();
match *v.kind {
- clean::VariantItem(ref var) => match var {
- // FIXME(#101337): Show discriminant
- clean::Variant::CLike(..) => write!(w, "{}", name),
- clean::Variant::Tuple(ref s) => {
+ // FIXME(#101337): Show discriminant
+ clean::VariantItem(ref var) => match var.kind {
+ clean::VariantKind::CLike => write!(w, "{}", name),
+ clean::VariantKind::Tuple(ref s) => {
write!(w, "{}(", name);
print_tuple_struct_fields(w, cx, s);
w.write_str(")");
}
- clean::Variant::Struct(ref s) => {
- render_struct(
- w,
- v,
- None,
- s.ctor_kind,
- &s.fields,
- " ",
- false,
- cx,
- );
+ clean::VariantKind::Struct(ref s) => {
+ render_struct(w, v, None, None, &s.fields, " ", false, cx);
}
},
_ => unreachable!(),
" rightside",
);
write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap());
- if let clean::VariantItem(clean::Variant::Tuple(ref s)) = *variant.kind {
+
+ let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() };
+
+ if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
w.write_str("(");
print_tuple_struct_fields(w, cx, s);
w.write_str(")");
}
w.write_str("</h3></section>");
- use crate::clean::Variant;
-
- let heading_and_fields = match &*variant.kind {
- clean::VariantItem(Variant::Struct(s)) => Some(("Fields", &s.fields)),
- // Documentation on tuple variant fields is rare, so to reduce noise we only emit
- // the section if at least one field is documented.
- clean::VariantItem(Variant::Tuple(fields))
- if fields.iter().any(|f| f.doc_value().is_some()) =>
- {
- Some(("Tuple Fields", fields))
+ let heading_and_fields = match &variant_data.kind {
+ clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)),
+ clean::VariantKind::Tuple(fields) => {
+ // Documentation on tuple variant fields is rare, so to reduce noise we only emit
+ // the section if at least one field is documented.
+ if fields.iter().any(|f| f.doc_value().is_some()) {
+ Some(("Tuple Fields", fields))
+ } else {
+ None
+ }
}
- _ => None,
+ clean::VariantKind::CLike => None,
};
if let Some((heading, fields)) = heading_and_fields {
}
* {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
box-sizing: border-box;
}
padding-left: 4px;
}
-details.dir-entry > summary::after {
- content: " â–º";
- position: absolute;
- left: -15px;
- top: 0px;
- font-size: 80%;
- padding: 2px 0px;
- /* set width to cover gap between arrow and text */
- width: 25px;
-}
-
-details[open].dir-entry > summary::after {
- content: " â–¼";
-}
-
-details.dir-entry > summary::-webkit-details-marker,
-details.dir-entry > summary::marker {
- display: none;
-}
-
details.dir-entry > summary {
- margin: 0 0 0 13px;
- list-style: none;
+ margin: 0 0 0 -4px;
+ padding: 0 0 0 4px;
cursor: pointer;
- position: relative;
}
details.dir-entry div.folders, details.dir-entry div.files {
impl FromWithTcx<clean::Variant> for Variant {
fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
- use clean::Variant::*;
- match variant {
- CLike(disr) => Variant::Plain(disr.map(|disr| disr.into_tcx(tcx))),
- Tuple(fields) => Variant::Tuple(ids_keeping_stripped(fields, tcx)),
- Struct(s) => Variant::Struct {
+ use clean::VariantKind::*;
+
+ let discriminant = variant.discriminant.map(|d| d.into_tcx(tcx));
+
+ let kind = match variant.kind {
+ CLike => VariantKind::Plain,
+ Tuple(fields) => VariantKind::Tuple(ids_keeping_stripped(fields, tcx)),
+ Struct(s) => VariantKind::Struct {
fields_stripped: s.has_stripped_entries(),
fields: ids(s.fields, tcx),
},
- }
+ };
+
+ Variant { kind, discriminant }
}
}
// implementations of traits are always public.
clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
// Variant fields have inherited visibility
- clean::VariantItem(clean::Variant::Struct(..) | clean::Variant::Tuple(..)) => true,
+ clean::VariantItem(clean::Variant {
+ kind: clean::VariantKind::Struct(..) | clean::VariantKind::Tuple(..),
+ ..
+ }) => true,
_ => false,
};
EnumItem(i) => i.variants.iter().for_each(|x| self.visit_item(x)),
TraitItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
ImplItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
- VariantItem(i) => match i {
- Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
- Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
- Variant::CLike(_) => {}
+ VariantItem(i) => match &i.kind {
+ VariantKind::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
+ VariantKind::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
+ VariantKind::CLike => {}
},
ExternCrateItem { src: _ }
| ImportItem(_)
/// This method will create a new module and push it onto the "modules stack" then call
/// `visit_mod_contents`. Once done, it'll remove it from the "modules stack" and instead
- /// add into into the list of modules of the current module.
+ /// add into the list of modules of the current module.
fn enter_mod(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>, name: Symbol) {
self.modules.push(Module::new(name, id, m.spans.inner_span));
use serde::{Deserialize, Serialize};
/// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 23;
+pub const FORMAT_VERSION: u32 = 24;
/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
/// about the language items in the local crate, as well as info about external items to allow
pub impls: Vec<Id>,
}
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Variant {
+ /// Whether the variant is plain, a tuple-like, or struct-like. Contains the fields.
+ pub kind: VariantKind,
+ /// The discriminant, if explicitly specified.
+ pub discriminant: Option<Discriminant>,
+}
+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
-#[serde(tag = "variant_kind", content = "variant_inner")]
-pub enum Variant {
- /// A variant with no parentheses, and possible discriminant.
+pub enum VariantKind {
+ /// A variant with no parentheses
///
/// ```rust
/// enum Demo {
/// PlainWithDiscriminant = 1,
/// }
/// ```
- Plain(Option<Discriminant>),
+ Plain,
/// A variant with unnamed fields.
///
/// Unlike most of json, `#[doc(hidden)]` fields will be given as `None`
// `Box` can get deallocated during execution of the function, so it should
// not get `dereferenceable`.
-// CHECK: noalias noundef nonnull align 4 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x)
+// CHECK: noundef nonnull align 4 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x)
#[no_mangle]
pub fn _box(x: Box<i32>) -> Box<i32> {
x
--- /dev/null
+// compile-flags: -O
+#![crate_type = "lib"]
+
+pub fn foo(t: &mut Vec<usize>) {
+ // CHECK-NOT: __rust_dealloc
+ let mut taken = std::mem::take(t);
+ taken.pop();
+ *t = taken;
+}
// compile-flags: -Zquery-dep-graph
// [rpass1]compile-flags: -Zincremental-ignore-spans
// [rpass2]compile-flags: -Zincremental-ignore-spans
-// [rpass3]compile-flags: -Zincremental-relative-spans
-// [rpass4]compile-flags: -Zincremental-relative-spans
#![feature(rustc_attrs)]
#![rustc_partition_reused(module = "change_symbol_export_status-mod1", cfg = "rpass2")]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(linkage)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// [cfail1]compile-flags: -Zincremental-ignore-spans
// [cfail2]compile-flags: -Zincremental-ignore-spans
// [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
#![allow(warnings)]
#![feature(rustc_attrs)]
// This test makes sure that just changing a definition's location in the
// source file also changes its incr. comp. hash, if debuginfo is enabled.
-// revisions:rpass1 rpass2 rpass3 rpass4
+// revisions:rpass1 rpass2
// ignore-asmjs wasm2js does not support source maps yet
// compile-flags: -g -Z query-dep-graph
-// [rpass3]compile-flags: -Zincremental-relative-spans
-// [rpass4]compile-flags: -Zincremental-relative-spans
#![feature(rustc_attrs)]
#![rustc_partition_codegened(module = "spans_significant_w_debuginfo", cfg = "rpass2")]
-#![rustc_partition_codegened(module = "spans_significant_w_debuginfo", cfg = "rpass4")]
-#[cfg(any(rpass1, rpass3))]
+#[cfg(rpass1)]
pub fn main() {}
-#[cfg(any(rpass2, rpass4))]
-#[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir", cfg = "rpass2")]
-#[rustc_clean(cfg = "rpass4")]
+#[cfg(rpass2)]
+#[rustc_clean(cfg = "rpass2")]
pub fn main() {}
// This test makes sure that just changing a definition's location in the
// source file also changes its incr. comp. hash, if debuginfo is enabled.
-// revisions:rpass1 rpass2 rpass3 rpass4
-// [rpass3]compile-flags: -Zincremental-relative-spans
-// [rpass4]compile-flags: -Zincremental-relative-spans
+// revisions:rpass1 rpass2
// compile-flags: -C overflow-checks=on -Z query-dep-graph
#![feature(rustc_attrs)]
#![rustc_partition_codegened(module = "spans_significant_w_panic", cfg = "rpass2")]
-#![rustc_partition_codegened(module = "spans_significant_w_panic", cfg = "rpass4")]
-#[cfg(any(rpass1, rpass3))]
+#[cfg(rpass1)]
pub fn main() {
if std::hint::black_box(false) {
panic!()
}
}
-#[cfg(any(rpass2, rpass4))]
-#[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir", cfg = "rpass2")]
-#[rustc_clean(cfg = "rpass4")]
+#[cfg(rpass2)]
+#[rustc_clean(cfg = "rpass2")]
pub fn main() {
if std::hint::black_box(false) {
panic!()
-// revisions: cfail1 cfail2 cfail3 cfail4
+// revisions: cfail1 cfail2
// compile-flags: -Z query-dep-graph
-// [cfail3]compile-flags: -Zincremental-relative-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
// build-pass (FIXME(62277): could be check-pass?)
#![allow(warnings)]
// needed even for callers of `x`.
pub mod x {
- #[cfg(any(cfail1, cfail3))]
+ #[cfg(cfail1)]
pub fn x() {
println!("{}", "1");
}
- #[cfg(any(cfail2, cfail4))]
- #[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir,promoted_mir", cfg = "cfail2")]
- #[rustc_clean(except = "hir_owner_nodes,promoted_mir", cfg = "cfail4")]
+ #[cfg(cfail2)]
+ #[rustc_clean(except = "hir_owner_nodes,promoted_mir", cfg = "cfail2")]
pub fn x() {
println!("{}", "2");
}
use x;
#[rustc_clean(cfg = "cfail2")]
- #[rustc_clean(cfg = "cfail4")]
pub fn y() {
x::x();
}
use y;
#[rustc_clean(cfg = "cfail2")]
- #[rustc_clean(cfg = "cfail4")]
pub fn z() {
y::y();
}
// ends up with any spans in its LLVM bitecode, so LLVM is able to skip
// re-building any modules which import 'inlined_fn'
-// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
+// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph -O
// build-pass (FIXME(62277): could be check-pass?)
cfg = "cfail3",
kind = "post-lto"
)]
-#![rustc_expected_cgu_reuse(
- module = "cgu_keeps_identical_fn-foo",
- cfg = "cfail5",
- kind = "post-lto"
-)]
-#![rustc_expected_cgu_reuse(
- module = "cgu_keeps_identical_fn-foo",
- cfg = "cfail6",
- kind = "post-lto"
-)]
#![rustc_expected_cgu_reuse(
module = "cgu_keeps_identical_fn-bar",
cfg = "cfail2",
cfg = "cfail3",
kind = "post-lto"
)]
-#![rustc_expected_cgu_reuse(
- module = "cgu_keeps_identical_fn-bar",
- cfg = "cfail5",
- kind = "post-lto"
-)]
-#![rustc_expected_cgu_reuse(
- module = "cgu_keeps_identical_fn-bar",
- cfg = "cfail6",
- kind = "post-lto"
-)]
mod foo {
+ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
+ let mut _4: &fn() {main}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6
+ let mut _5: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
++ scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
++ }
+ }
bb0: {
+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+ _3 = <fn() {main} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+ // mir::Constant
-+ // + span: $DIR/cycle.rs:6:5: 6:6
-+ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {main}, ()) -> <fn() {main} as FnOnce<()>>::Output {<fn() {main} as Fn<()>>::call}, val: Value(<ZST>) }
++ _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
}
bb1: {
return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2
+ }
+
-+ bb2: {
-+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9
-+ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2
++ bb2 (cleanup): {
++ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:7:1: 7:2
+ }
+
+ bb3 (cleanup): {
-+ drop(_2) -> bb4; // scope 1 at $DIR/cycle.rs:7:1: 7:2
++ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
+ }
+
-+ bb4 (cleanup): {
-+ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
++ bb4: {
++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
++ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8
++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9
++ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2
}
}
+ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
+ let mut _4: &fn() {g}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6
+ let mut _5: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
++ scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8
++ }
+ }
bb0: {
+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+ _3 = <fn() {g} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+ // mir::Constant
-+ // + span: $DIR/cycle.rs:6:5: 6:6
-+ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {g}, ()) -> <fn() {g} as FnOnce<()>>::Output {<fn() {g} as Fn<()>>::call}, val: Value(<ZST>) }
++ _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
}
bb1: {
return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2
+ }
+
-+ bb2: {
-+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9
-+ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2
++ bb2 (cleanup): {
++ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:7:1: 7:2
+ }
+
+ bb3 (cleanup): {
-+ drop(_2) -> bb4; // scope 1 at $DIR/cycle.rs:7:1: 7:2
++ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
+ }
+
-+ bb4 (cleanup): {
-+ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
++ bb4: {
++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
++ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8
++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9
++ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2
}
}
+ let _2: (); // in scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
+ let _3: (); // in scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
+ let _4: (); // in scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++ scope 2 (inlined <() as F>::call) { // at $DIR/exponential_runtime.rs:73:9: 73:25
++ let _5: (); // in scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
++ let _6: (); // in scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++ let _7: (); // in scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++ }
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
- _1 = <() as G>::call() -> bb1; // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
+ StorageLive(_2); // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
-+ _2 = <() as F>::call() -> bb1; // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++ StorageLive(_5); // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
++ _5 = <() as E>::call() -> bb3; // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
// mir::Constant
- // + span: $DIR/exponential_runtime.rs:86:5: 86:20
- // + literal: Const { ty: fn() {<() as G>::call}, val: Value(<ZST>) }
-+ // + span: $DIR/exponential_runtime.rs:73:9: 73:23
-+ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
++ // + span: $DIR/exponential_runtime.rs:61:9: 61:23
++ // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
}
bb1: {
-+ StorageDead(_2); // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
-+ StorageLive(_3); // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
-+ _3 = <() as F>::call() -> bb2; // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
-+ // mir::Constant
-+ // + span: $DIR/exponential_runtime.rs:74:9: 74:23
-+ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
-+ }
-+
-+ bb2: {
+ StorageDead(_3); // scope 1 at $DIR/exponential_runtime.rs:74:25: 74:26
+ StorageLive(_4); // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
-+ _4 = <() as F>::call() -> bb3; // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++ _4 = <() as F>::call() -> bb2; // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
+ // mir::Constant
+ // + span: $DIR/exponential_runtime.rs:75:9: 75:23
+ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
+ }
+
-+ bb3: {
++ bb2: {
+ StorageDead(_4); // scope 1 at $DIR/exponential_runtime.rs:75:25: 75:26
StorageDead(_1); // scope 0 at $DIR/exponential_runtime.rs:+1:22: +1:23
_0 = const (); // scope 0 at $DIR/exponential_runtime.rs:+0:11: +2:2
return; // scope 0 at $DIR/exponential_runtime.rs:+2:2: +2:2
++ }
++
++ bb3: {
++ StorageDead(_5); // scope 2 at $DIR/exponential_runtime.rs:61:25: 61:26
++ StorageLive(_6); // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++ _6 = <() as E>::call() -> bb4; // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++ // mir::Constant
++ // + span: $DIR/exponential_runtime.rs:62:9: 62:23
++ // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
++ }
++
++ bb4: {
++ StorageDead(_6); // scope 2 at $DIR/exponential_runtime.rs:62:25: 62:26
++ StorageLive(_7); // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++ _7 = <() as E>::call() -> bb5; // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++ // mir::Constant
++ // + span: $DIR/exponential_runtime.rs:63:9: 63:23
++ // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
++ }
++
++ bb5: {
++ StorageDead(_7); // scope 2 at $DIR/exponential_runtime.rs:63:25: 63:26
++ StorageDead(_2); // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
++ StorageLive(_3); // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++ _3 = <() as F>::call() -> bb1; // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++ // mir::Constant
++ // + span: $DIR/exponential_runtime.rs:74:9: 74:23
++ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
}
}
let mut _0: (); // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10
let _1: (); // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
+ scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle.rs:14:5: 14:24
++ scope 2 (inlined <A<C> as Call>::call) { // at $DIR/inline_cycle.rs:43:9: 43:23
++ scope 3 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle.rs:28:9: 28:31
++ }
++ }
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
-+ _1 = <A<C> as Call>::call() -> bb1; // scope 1 at $DIR/inline_cycle.rs:43:9: 43:23
++ _1 = <C as Call>::call() -> bb1; // scope 3 at $DIR/inline_cycle.rs:36:9: 36:28
// mir::Constant
- // + span: $DIR/inline_cycle.rs:14:5: 14:22
-- // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
-+ // + span: $DIR/inline_cycle.rs:43:9: 43:21
-+ // + literal: Const { ty: fn() {<A<C> as Call>::call}, val: Value(<ZST>) }
++ // + span: $DIR/inline_cycle.rs:36:9: 36:26
+ // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
}
bb1: {
+ debug f => _2; // in scope 1 at $DIR/inline_cycle.rs:53:22: 53:23
+ let _3: (); // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
+ let mut _4: (); // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
++ scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline_cycle.rs:54:5: 54:8
++ }
+ }
bb0: {
// + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
+ StorageLive(_3); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
+ StorageLive(_4); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+ _3 = <fn() {f} as FnOnce<()>>::call_once(move _2, move _4) -> bb1; // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+ // mir::Constant
-+ // + span: $DIR/inline_cycle.rs:54:5: 54:6
-+ // + literal: Const { ty: extern "rust-call" fn(fn() {f}, ()) -> <fn() {f} as FnOnce<()>>::Output {<fn() {f} as FnOnce<()>>::call_once}, val: Value(<ZST>) }
++ _3 = move _2() -> bb1; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
}
bb1: {
let _1: (); // in scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
+ scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle_generic.rs:9:5: 9:24
+ scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline_cycle_generic.rs:38:9: 38:31
++ scope 3 (inlined <A as Call>::call) { // at $DIR/inline_cycle_generic.rs:31:9: 31:28
++ scope 4 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle_generic.rs:23:9: 23:31
++ }
++ }
+ }
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
-+ _1 = <A as Call>::call() -> bb1; // scope 2 at $DIR/inline_cycle_generic.rs:31:9: 31:28
++ _1 = <C as Call>::call() -> bb1; // scope 4 at $DIR/inline_cycle_generic.rs:31:9: 31:28
// mir::Constant
- // + span: $DIR/inline_cycle_generic.rs:9:5: 9:22
-- // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
+ // + span: $DIR/inline_cycle_generic.rs:31:9: 31:26
-+ // + literal: Const { ty: fn() {<A as Call>::call}, val: Value(<ZST>) }
+ // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
}
bb1: {
+ debug b => _9; // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10
+ }
+ }
++ scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16
++ }
+ }
bb0: {
+ StorageLive(_4); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
+ _4 = &_2; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
+ StorageLive(_5); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+ _3 = <fn() -> ! {sleep} as Fn<()>>::call(move _4, move _5) -> [return: bb1, unwind: bb5]; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+ // mir::Constant
-+ // + span: $DIR/inline_diverging.rs:27:13: 27:14
-+ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
++ _3 = move (*_4)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL
+ }
+
+ bb1: {
-+ StorageDead(_5); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
-+ StorageDead(_4); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
-+ StorageLive(_6); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
-+ _6 = &_2; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
-+ StorageLive(_7); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
-+ _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb2, unwind: bb4]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
-+ // mir::Constant
-+ // + span: $DIR/inline_diverging.rs:28:13: 28:14
-+ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
-+ }
-+
-+ bb2: {
+ StorageDead(_7); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
+ StorageDead(_6); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
+ StorageLive(_8); // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
+ (_1.1: !) = move _9; // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
+ StorageDead(_8); // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11
+ StorageDead(_3); // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
-+ drop(_2) -> bb3; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++ drop(_2) -> bb2; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
+ }
+
-+ bb3: {
++ bb2: {
+ unreachable; // scope 0 at $DIR/inline_diverging.rs:30:2: 30:2
+ }
+
++ bb3 (cleanup): {
++ drop(_3) -> bb4; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++ }
++
+ bb4 (cleanup): {
-+ drop(_3) -> bb5; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++ drop(_2) -> bb5; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
+ }
+
+ bb5 (cleanup): {
-+ drop(_2) -> bb6; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++ resume; // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2
+ }
+
-+ bb6 (cleanup): {
-+ resume; // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2
++ bb6: {
++ StorageDead(_5); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++ StorageDead(_4); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++ StorageLive(_6); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++ _6 = &_2; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++ StorageLive(_7); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++ _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++ // mir::Constant
++ // + span: $DIR/inline_diverging.rs:28:13: 28:14
++ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
}
}
let mut _18: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
scope 9 {
debug e => _16; // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
+ debug t => _18; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+ }
}
}
}
StorageLive(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
StorageLive(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
_18 = move _16; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-- _17 = <i32 as From<i32>>::from(move _18) -> bb8; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-+ _17 = <i32 as From<i32>>::from(move _18) -> bb7; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/result.rs:LL:COL
- // + literal: Const { ty: fn(i32) -> i32 {<i32 as From<i32>>::from}, val: Value(<ZST>) }
+ _17 = move _18; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+ StorageDead(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ StorageDead(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ StorageDead(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+ StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
+ StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
+ StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
+ StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
}
- bb5: {
+ _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
+ switchInt(move _5) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
}
-
-- bb8: {
-+ bb7: {
- StorageDead(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
- StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
- StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
- StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
- return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
- }
}
--- /dev/null
+// MIR for `ezmap` after PreCodegen
+
+fn ezmap(_1: Option<i32>) -> Option<i32> {
+ debug x => _1; // in scope 0 at $DIR/simple_option_map_e2e.rs:+0:14: +0:15
+ let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/simple_option_map_e2e.rs:+0:33: +0:44
+ let mut _2: [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]; // in scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21
+ scope 1 (inlined map::<i32, i32, [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]>) { // at $DIR/simple_option_map_e2e.rs:14:5: 14:22
+ debug slf => _1; // in scope 1 at $DIR/simple_option_map_e2e.rs:2:17: 2:20
+ debug f => _2; // in scope 1 at $DIR/simple_option_map_e2e.rs:2:33: 2:34
+ let mut _3: isize; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:9: 7:16
+ let mut _4: i32; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+ let mut _5: i32; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+ scope 2 {
+ debug x => _5; // in scope 2 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+ scope 3 (inlined ezmap::{closure#0}) { // at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+ debug n => _5; // in scope 3 at $DIR/simple_option_map_e2e.rs:+1:13: +1:14
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21
+ _3 = discriminant(_1); // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14
+ switchInt(move _3) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 1 at $DIR/simple_option_map_e2e.rs:6:5: 6:14
+ }
+
+ bb1: {
+ Deinit(_0); // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+ discriminant(_0) = 0; // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+ goto -> bb4; // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+ }
+
+ bb2: {
+ unreachable; // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14
+ }
+
+ bb3: {
+ _5 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+ StorageLive(_4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+ _4 = Add(move _5, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
+ Deinit(_0); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
+ ((_0 as Some).0: i32) = move _4; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
+ discriminant(_0) = 1; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
+ StorageDead(_4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:29: 7:30
+ goto -> bb4; // scope 1 at $DIR/simple_option_map_e2e.rs:10:1: 10:2
+ }
+
+ bb4: {
+ StorageDead(_2); // scope 0 at $DIR/simple_option_map_e2e.rs:+1:21: +1:22
+ return; // scope 0 at $DIR/simple_option_map_e2e.rs:+2:2: +2:2
+ }
+}
--- /dev/null
+#[inline(always)]
+fn map<T, U, F>(slf: Option<T>, f: F) -> Option<U>
+where
+ F: FnOnce(T) -> U,
+{
+ match slf {
+ Some(x) => Some(f(x)),
+ None => None,
+ }
+}
+
+// EMIT_MIR simple_option_map_e2e.ezmap.PreCodegen.after.mir
+pub fn ezmap(x: Option<i32>) -> Option<i32> {
+ map(x, |n| n + 1)
+}
+
+fn main() {
+ assert_eq!(None, ezmap(None));
+}
extern crate rustc_graphviz;
// A simple rust project
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
extern crate krate2;
extern crate krate2 as krate3;
+// This test checks the appearance of the tables in the doc comments.
goto: "file://" + |DOC_PATH| + "/test_docs/doc_block_table/struct.DocBlockTable.html#method.func"
compare-elements-css: (".impl-items .docblock table th", ".top-doc .docblock table th", ["border"])
click: "#source-sidebar details:first-of-type > summary"
assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
-// Check the spacing.
-assert-css: ("#source-sidebar > details.dir-entry", {"padding-left": "4px"})
+// And open it again, since it'll be the reference we use to check positions.
+click: "#source-sidebar details:first-of-type > summary"
+assert-property: ("#source-sidebar details:first-of-type", {"open": "true"})
+
+// Check the sidebar directory entries have a marker and spacing (desktop).
+store-property: (
+ link_height,
+ "#source-sidebar > details:first-of-type.dir-entry[open] > .files > a",
+ "offsetHeight"
+)
+define-function: (
+ "check-sidebar-dir-entry",
+ (x, y),
+ [
+ ("assert", "details:first-of-type.dir-entry[open] > summary::marker"),
+ ("assert-css", ("#source-sidebar > details:first-of-type.dir-entry", {"padding-left": "4px"})),
+ // This check ensures that the summary is only one line.
+ ("assert-property", (
+ "#source-sidebar > details:first-of-type.dir-entry[open] > summary",
+ {"offsetHeight": |link_height|}
+ )),
+ ("assert-position", (
+ "#source-sidebar > details:first-of-type.dir-entry[open] > summary",
+ {"x": |x|, "y": |y|}
+ )),
+ ("assert-property", (
+ "#source-sidebar > details:first-of-type.dir-entry[open] > .files > a",
+ {"offsetHeight": |link_height|}
+ )),
+ ("assert-position", (
+ "#source-sidebar > details:first-of-type.dir-entry[open] > .files > a",
+ // left margin
+ {"x": |x| + 27, "y": |y| + |link_height|}
+ )),
+ ]
+)
+store-property: (
+ source_sidebar_title_height,
+ "#source-sidebar > .title",
+ "offsetHeight"
+)
+store-property: (
+ source_sidebar_title_y,
+ "#source-sidebar > .title",
+ "offsetTop"
+)
+call-function: ("check-sidebar-dir-entry", {
+ "x": 0,
+ // border + margin = 6
+ "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
+})
// Check the search form
assert-css: ("nav.sub", {"flex-direction": "row"})
assert-property: ("#main-content", {"offsetTop": 90})
// 28 = 90 - 34 - 28
-// Now do the same check on moderately-sized mobile.
+// Now do the same check on moderately-sized, tablet mobile.
size: (700, 700)
assert-css: ("nav.sub", {"flex-direction": "row"})
assert-property: ("nav.sub form", {"offsetTop": 21, "offsetHeight": 34})
assert-property: ("#main-content", {"offsetTop": 76})
// 21 = 76 - 34 - 21
-// Tiny mobile gets a different display where the logo is stacked on top.
+// Check the sidebar directory entries have a marker and spacing (tablet).
+store-property: (
+ source_sidebar_title_height,
+ "#source-sidebar > .title",
+ "offsetHeight"
+)
+store-property: (
+ source_sidebar_title_y,
+ "#source-sidebar > .title",
+ "offsetTop"
+)
+call-function: ("check-sidebar-dir-entry", {
+ "x": 0,
+ "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
+})
+
+// Tiny, phone mobile gets a different display where the logo is stacked on top.
size: (450, 700)
assert-css: ("nav.sub", {"flex-direction": "column"})
+
+// Check the sidebar directory entries have a marker and spacing (phone).
+store-property: (
+ source_sidebar_title_height,
+ "#source-sidebar > .title",
+ "offsetHeight"
+)
+store-property: (
+ source_sidebar_title_y,
+ "#source-sidebar > .title",
+ "offsetTop"
+)
+call-function: ("check-sidebar-dir-entry", {
+ "x": 0,
+ "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
+})
#[repr(i8)]
pub enum Ordering {
- // @is "$.index[*][?(@.name=='Less')].inner.variant_inner.expr" '"-1"'
- // @is "$.index[*][?(@.name=='Less')].inner.variant_inner.value" '"-1"'
+ // @is "$.index[*][?(@.name=='Less')].inner.discriminant.expr" '"-1"'
+ // @is "$.index[*][?(@.name=='Less')].inner.discriminant.value" '"-1"'
Less = -1,
- // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.expr" '"0"'
- // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.value" '"0"'
+ // @is "$.index[*][?(@.name=='Equal')].inner.discriminant.expr" '"0"'
+ // @is "$.index[*][?(@.name=='Equal')].inner.discriminant.value" '"0"'
Equal = 0,
- // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.expr" '"1"'
- // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.value" '"1"'
+ // @is "$.index[*][?(@.name=='Greater')].inner.discriminant.expr" '"1"'
+ // @is "$.index[*][?(@.name=='Greater')].inner.discriminant.value" '"1"'
Greater = 1,
}
pub enum Foo {
- // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.value" '"0"'
- // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.expr" '"{ _ }"'
+ // @is "$.index[*][?(@.name=='Addition')].inner.discriminant.value" '"0"'
+ // @is "$.index[*][?(@.name=='Addition')].inner.discriminant.expr" '"{ _ }"'
Addition = 0 + 0,
- // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.value" '"1"'
- // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.expr" '"0b1"'
+ // @is "$.index[*][?(@.name=='Bin')].inner.discriminant.value" '"1"'
+ // @is "$.index[*][?(@.name=='Bin')].inner.discriminant.expr" '"0b1"'
Bin = 0b1,
- // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.value" '"2"'
- // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.expr" '"0o2"'
+ // @is "$.index[*][?(@.name=='Oct')].inner.discriminant.value" '"2"'
+ // @is "$.index[*][?(@.name=='Oct')].inner.discriminant.expr" '"0o2"'
Oct = 0o2,
- // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.value" '"3"'
- // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.expr" '"THREE"'
+ // @is "$.index[*][?(@.name=='PubConst')].inner.discriminant.value" '"3"'
+ // @is "$.index[*][?(@.name=='PubConst')].inner.discriminant.expr" '"THREE"'
PubConst = THREE,
- // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.value" '"4"'
- // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.expr" '"0x4"'
+ // @is "$.index[*][?(@.name=='Hex')].inner.discriminant.value" '"4"'
+ // @is "$.index[*][?(@.name=='Hex')].inner.discriminant.expr" '"0x4"'
Hex = 0x4,
- // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.value" '"5"'
- // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.expr" '"{ _ }"'
+ // @is "$.index[*][?(@.name=='Cast')].inner.discriminant.value" '"5"'
+ // @is "$.index[*][?(@.name=='Cast')].inner.discriminant.expr" '"{ _ }"'
Cast = 5 as isize,
- // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.value" '"6"'
- // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.expr" '"{ _ }"'
+ // @is "$.index[*][?(@.name=='PubCall')].inner.discriminant.value" '"6"'
+ // @is "$.index[*][?(@.name=='PubCall')].inner.discriminant.expr" '"{ _ }"'
PubCall = six(),
- // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.value" '"7"'
- // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.expr" '"{ _ }"'
+ // @is "$.index[*][?(@.name=='PrivCall')].inner.discriminant.value" '"7"'
+ // @is "$.index[*][?(@.name=='PrivCall')].inner.discriminant.expr" '"{ _ }"'
PrivCall = seven(),
- // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.value" '"8"'
- // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.expr" '"EIGHT"'
+ // @is "$.index[*][?(@.name=='PrivConst')].inner.discriminant.value" '"8"'
+ // @is "$.index[*][?(@.name=='PrivConst')].inner.discriminant.expr" '"EIGHT"'
PrivConst = EIGHT,
}
#[repr(u64)]
pub enum U64 {
- // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.value" '"0"'
- // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.expr" '"u64::MIN"'
+ // @is "$.index[*][?(@.name=='U64Min')].inner.discriminant.value" '"0"'
+ // @is "$.index[*][?(@.name=='U64Min')].inner.discriminant.expr" '"u64::MIN"'
U64Min = u64::MIN,
- // @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.value" '"18446744073709551615"'
- // @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.expr" '"u64::MAX"'
+ // @is "$.index[*][?(@.name=='U64Max')].inner.discriminant.value" '"18446744073709551615"'
+ // @is "$.index[*][?(@.name=='U64Max')].inner.discriminant.expr" '"u64::MAX"'
U64Max = u64::MAX,
}
#[repr(i64)]
pub enum I64 {
- // @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.value" '"-9223372036854775808"'
- // @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.expr" '"i64::MIN"'
+ // @is "$.index[*][?(@.name=='I64Min')].inner.discriminant.value" '"-9223372036854775808"'
+ // @is "$.index[*][?(@.name=='I64Min')].inner.discriminant.expr" '"i64::MIN"'
I64Min = i64::MIN,
- // @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.value" '"9223372036854775807"'
- // @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.expr" '"i64::MAX"'
+ // @is "$.index[*][?(@.name=='I64Max')].inner.discriminant.value" '"9223372036854775807"'
+ // @is "$.index[*][?(@.name=='I64Max')].inner.discriminant.expr" '"i64::MAX"'
I64Max = i64::MAX,
}
#[repr(u128)]
pub enum U128 {
- // @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.value" '"0"'
- // @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.expr" '"u128::MIN"'
+ // @is "$.index[*][?(@.name=='U128Min')].inner.discriminant.value" '"0"'
+ // @is "$.index[*][?(@.name=='U128Min')].inner.discriminant.expr" '"u128::MIN"'
U128Min = u128::MIN,
- // @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.value" '"340282366920938463463374607431768211455"'
- // @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.expr" '"u128::MAX"'
+ // @is "$.index[*][?(@.name=='U128Max')].inner.discriminant.value" '"340282366920938463463374607431768211455"'
+ // @is "$.index[*][?(@.name=='U128Max')].inner.discriminant.expr" '"u128::MAX"'
U128Max = u128::MAX,
}
#[repr(i128)]
pub enum I128 {
- // @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.value" '"-170141183460469231731687303715884105728"'
- // @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.expr" '"i128::MIN"'
+ // @is "$.index[*][?(@.name=='I128Min')].inner.discriminant.value" '"-170141183460469231731687303715884105728"'
+ // @is "$.index[*][?(@.name=='I128Min')].inner.discriminant.expr" '"i128::MIN"'
I128Min = i128::MIN,
- // @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.value" '"170141183460469231731687303715884105727"'
- // @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.expr" '"i128::MAX"'
+ // @is "$.index[*][?(@.name=='I128Max')].inner.discriminant.value" '"170141183460469231731687303715884105727"'
+ // @is "$.index[*][?(@.name=='I128Max')].inner.discriminant.expr" '"i128::MAX"'
I128Max = i128::MAX,
}
#[repr(u32)]
pub enum Foo {
- // @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.value" '"0"'
- // @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.expr" '"0"'
+ // @is "$.index[*][?(@.name=='Basic')].inner.discriminant.value" '"0"'
+ // @is "$.index[*][?(@.name=='Basic')].inner.discriminant.expr" '"0"'
Basic = 0,
- // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.value" '"10"'
- // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.expr" '"10u32"'
+ // @is "$.index[*][?(@.name=='Suffix')].inner.discriminant.value" '"10"'
+ // @is "$.index[*][?(@.name=='Suffix')].inner.discriminant.expr" '"10u32"'
Suffix = 10u32,
- // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.value" '"100"'
- // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.expr" '"1_0_0"'
+ // @is "$.index[*][?(@.name=='Underscore')].inner.discriminant.value" '"100"'
+ // @is "$.index[*][?(@.name=='Underscore')].inner.discriminant.expr" '"1_0_0"'
Underscore = 1_0_0,
- // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.value" '"1000"'
- // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.expr" '"1_0_0_0u32"'
+ // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.discriminant.value" '"1000"'
+ // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.discriminant.expr" '"1_0_0_0u32"'
SuffixUnderscore = 1_0_0_0u32,
}
pub enum Foo {
- // @is "$.index[*][?(@.name=='Has')].inner.variant_inner" '{"expr":"0", "value":"0"}'
+ // @is "$.index[*][?(@.name=='Has')].inner.discriminant" '{"expr":"0", "value":"0"}'
Has = 0,
- // @is "$.index[*][?(@.name=='Doesnt')].inner.variant_inner" null
+ // @is "$.index[*][?(@.name=='Doesnt')].inner.discriminant" null
Doesnt,
- // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant_inner" null
+ // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.discriminant" null
AlsoDoesnt,
- // @is "$.index[*][?(@.name=='AlsoHas')].inner.variant_inner" '{"expr":"44", "value":"44"}'
+ // @is "$.index[*][?(@.name=='AlsoHas')].inner.discriminant" '{"expr":"44", "value":"44"}'
AlsoHas = 44,
}
--- /dev/null
+// ignore-tidy-linelength
+
+#[repr(i32)]
+// @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(i32)]"]'
+pub enum Foo {
+ // @is "$.index[*][?(@.name=='Struct')].inner.discriminant" null
+ // @count "$.index[*][?(@.name=='Struct')].inner.kind.struct.fields[*]" 0
+ Struct {},
+ // @is "$.index[*][?(@.name=='StructWithDiscr')].inner.discriminant" '{"expr": "42", "value": "42"}'
+ // @count "$.index[*][?(@.name=='StructWithDiscr')].inner.kind.struct.fields[*]" 1
+ StructWithDiscr { x: i32 } = 42,
+ // @is "$.index[*][?(@.name=='StructWithHexDiscr')].inner.discriminant" '{"expr": "0x42", "value": "66"}'
+ // @count "$.index[*][?(@.name=='StructWithHexDiscr')].inner.kind.struct.fields[*]" 2
+ StructWithHexDiscr { x: i32, y: bool } = 0x42,
+}
--- /dev/null
+// ignore-tidy-linelength
+
+#[repr(u32)]
+// @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(u32)]"]'
+pub enum Foo {
+ // @is "$.index[*][?(@.name=='Tuple')].inner.discriminant" null
+ // @count "$.index[*][?(@.name=='Tuple')].inner.kind.tuple[*]" 0
+ Tuple(),
+ // @is "$.index[*][?(@.name=='TupleWithDiscr')].inner.discriminant" '{"expr": "1", "value": "1"}'
+ // @count "$.index[*][?(@.name=='TupleWithDiscr')].inner.kind.tuple[*]" 1
+ TupleWithDiscr(i32) = 1,
+ // @is "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.discriminant" '{"expr": "0b10", "value": "2"}'
+ // @count "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.kind.tuple[*]" 2
+ TupleWithBinDiscr(i32, i32) = 0b10,
+}
// @has "$.index[*][?(@.name=='ParseError')]"
// @has "$.index[*][?(@.name=='UnexpectedEndTag')]"
-// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_kind" '"tuple"'
-// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_inner" [null]
+// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.kind.tuple" [null]
+// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.discriminant" null
pub enum ParseError {
UnexpectedEndTag(#[doc(hidden)] u32),
pub enum Foo {
// @set Unit = "$.index[*][?(@.name=='Unit')].id"
- // @is "$.index[*][?(@.name=='Unit')].inner.variant_kind" '"plain"'
- // @is "$.index[*][?(@.name=='Unit')].inner.variant_inner" null
+ // @is "$.index[*][?(@.name=='Unit')].inner.kind" '"plain"'
Unit,
// @set Named = "$.index[*][?(@.name=='Named')].id"
- // @is "$.index[*][?(@.name=='Named')].inner.variant_kind" '"struct"'
- // @is "$.index[*][?(@.name=='Named')].inner.variant_inner" '{"fields": [], "fields_stripped": false}'
+ // @is "$.index[*][?(@.name=='Named')].inner.kind.struct" '{"fields": [], "fields_stripped": false}'
Named {},
// @set Tuple = "$.index[*][?(@.name=='Tuple')].id"
- // @is "$.index[*][?(@.name=='Tuple')].inner.variant_kind" '"tuple"'
- // @is "$.index[*][?(@.name=='Tuple')].inner.variant_inner" []
+ // @is "$.index[*][?(@.name=='Tuple')].inner.kind.tuple" []
Tuple(),
// @set NamedField = "$.index[*][?(@.name=='NamedField')].id"
// @set x = "$.index[*][?(@.name=='x' && @.kind=='struct_field')].id"
- // @is "$.index[*][?(@.name=='NamedField')].inner.variant_kind" '"struct"'
- // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields[*]" $x
- // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields_stripped" false
+ // @is "$.index[*][?(@.name=='NamedField')].inner.kind.struct.fields[*]" $x
+ // @is "$.index[*][?(@.name=='NamedField')].inner.kind.struct.fields_stripped" false
NamedField { x: i32 },
// @set TupleField = "$.index[*][?(@.name=='TupleField')].id"
- // @is "$.index[*][?(@.name=='TupleField')].inner.variant_kind" '"tuple"'
// @set tup_field = "$.index[*][?(@.name=='0' && @.kind=='struct_field')].id"
- // @is "$.index[*][?(@.name=='TupleField')].inner.variant_inner[*]" $tup_field
+ // @is "$.index[*][?(@.name=='TupleField')].inner.kind.tuple[*]" $tup_field
TupleField(i32),
}
// @set y = "$.index[*][?(@.name=='y')].id"
y: i32,
},
- // @is "$.index[*][?(@.name=='Variant')].inner.variant_kind" '"struct"'
- // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields_stripped" true
- // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[0]" $b
- // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[1]" $y
- // @count "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[*]" 2
+ // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields_stripped" true
+ // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[0]" $b
+ // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[1]" $y
+ // @count "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[*]" 2
}
// @set 3.3.1 = "$.index[*][?(@.docs=='3.3.1')].id"
pub enum EnumWithStrippedTupleVariants {
- // @is "$.index[*][?(@.name=='None')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='None')].inner.variant_inner[*]" 0
+ // @count "$.index[*][?(@.name=='None')].inner.kind.tuple[*]" 0
None(),
- // @is "$.index[*][?(@.name=='One')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='One')].inner.variant_inner[*]" 1
- // @is "$.index[*][?(@.name=='One')].inner.variant_inner[0]" $1.1.0
+ // @count "$.index[*][?(@.name=='One')].inner.kind.tuple[*]" 1
+ // @is "$.index[*][?(@.name=='One')].inner.kind.tuple[0]" $1.1.0
One(/** 1.1.0*/ bool),
- // @is "$.index[*][?(@.name=='OneHidden')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[*]" 1
- // @is "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[0]" null
+ // @count "$.index[*][?(@.name=='OneHidden')].inner.kind.tuple[*]" 1
+ // @is "$.index[*][?(@.name=='OneHidden')].inner.kind.tuple[0]" null
OneHidden(#[doc(hidden)] bool),
- // @is "$.index[*][?(@.name=='Two')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='Two')].inner.variant_inner[*]" 2
- // @is "$.index[*][?(@.name=='Two')].inner.variant_inner[0]" $2.1.0
- // @is "$.index[*][?(@.name=='Two')].inner.variant_inner[1]" $2.1.1
+ // @count "$.index[*][?(@.name=='Two')].inner.kind.tuple[*]" 2
+ // @is "$.index[*][?(@.name=='Two')].inner.kind.tuple[0]" $2.1.0
+ // @is "$.index[*][?(@.name=='Two')].inner.kind.tuple[1]" $2.1.1
Two(/** 2.1.0*/ bool, /** 2.1.1*/ bool),
- // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[*]" 2
- // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[0]" null
- // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[1]" $2.2.1
+ // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[*]" 2
+ // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[0]" null
+ // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[1]" $2.2.1
TwoLeftHidden(#[doc(hidden)] bool, /** 2.2.1*/ bool),
- // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[*]" 2
- // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[0]" $2.3.0
- // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[1]" null
+ // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[*]" 2
+ // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[0]" $2.3.0
+ // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[1]" null
TwoRightHidden(/** 2.3.0*/ bool, #[doc(hidden)] bool),
- // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[*]" 2
- // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[0]" null
- // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[1]" null
+ // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[*]" 2
+ // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[0]" null
+ // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[1]" null
TwoBothHidden(#[doc(hidden)] bool, #[doc(hidden)] bool),
- // @is "$.index[*][?(@.name=='Three1')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='Three1')].inner.variant_inner[*]" 3
- // @is "$.index[*][?(@.name=='Three1')].inner.variant_inner[0]" null
- // @is "$.index[*][?(@.name=='Three1')].inner.variant_inner[1]" $3.1.1
- // @is "$.index[*][?(@.name=='Three1')].inner.variant_inner[2]" $3.1.2
+ // @count "$.index[*][?(@.name=='Three1')].inner.kind.tuple[*]" 3
+ // @is "$.index[*][?(@.name=='Three1')].inner.kind.tuple[0]" null
+ // @is "$.index[*][?(@.name=='Three1')].inner.kind.tuple[1]" $3.1.1
+ // @is "$.index[*][?(@.name=='Three1')].inner.kind.tuple[2]" $3.1.2
Three1(#[doc(hidden)] bool, /** 3.1.1*/ bool, /** 3.1.2*/ bool),
- // @is "$.index[*][?(@.name=='Three2')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='Three2')].inner.variant_inner[*]" 3
- // @is "$.index[*][?(@.name=='Three2')].inner.variant_inner[0]" $3.2.0
- // @is "$.index[*][?(@.name=='Three2')].inner.variant_inner[1]" null
- // @is "$.index[*][?(@.name=='Three2')].inner.variant_inner[2]" $3.2.2
+ // @count "$.index[*][?(@.name=='Three2')].inner.kind.tuple[*]" 3
+ // @is "$.index[*][?(@.name=='Three2')].inner.kind.tuple[0]" $3.2.0
+ // @is "$.index[*][?(@.name=='Three2')].inner.kind.tuple[1]" null
+ // @is "$.index[*][?(@.name=='Three2')].inner.kind.tuple[2]" $3.2.2
Three2(/** 3.2.0*/ bool, #[doc(hidden)] bool, /** 3.2.2*/ bool),
- // @is "$.index[*][?(@.name=='Three3')].inner.variant_kind" '"tuple"'
- // @count "$.index[*][?(@.name=='Three3')].inner.variant_inner[*]" 3
- // @is "$.index[*][?(@.name=='Three3')].inner.variant_inner[0]" $3.3.0
- // @is "$.index[*][?(@.name=='Three3')].inner.variant_inner[1]" $3.3.1
- // @is "$.index[*][?(@.name=='Three3')].inner.variant_inner[2]" null
+ // @count "$.index[*][?(@.name=='Three3')].inner.kind.tuple[*]" 3
+ // @is "$.index[*][?(@.name=='Three3')].inner.kind.tuple[0]" $3.3.0
+ // @is "$.index[*][?(@.name=='Three3')].inner.kind.tuple[1]" $3.3.1
+ // @is "$.index[*][?(@.name=='Three3')].inner.kind.tuple[2]" null
Three3(/** 3.3.0*/ bool, /** 3.3.1*/ bool, #[doc(hidden)] bool),
}
-
// @is "$.index[*][?(@.docs=='1.1.0')].name" '"0"'
// @is "$.index[*][?(@.docs=='2.1.0')].name" '"0"'
// @is "$.index[*][?(@.docs=='2.1.1')].name" '"1"'
// @is "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\"
// @is "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\"
pub enum EnumStruct {
- // @is "$.index[*][?(@.name=='VariantS')].inner.variant_kind" \"struct\"
// @is "$.index[*][?(@.name=='x')].kind" \"struct_field\"
+ // @set x = "$.index[*][?(@.name=='x')].id"
// @is "$.index[*][?(@.name=='y')].kind" \"struct_field\"
- VariantS {
- x: u32,
- y: String,
- },
+ // @set y = "$.index[*][?(@.name=='y')].id"
+ // @ismany "$.index[*][?(@.name=='VariantS')].inner.kind.struct.fields[*]" $x $y
+ VariantS { x: u32, y: String },
}
// @is "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\"
// @is "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\"
pub enum EnumTupleStruct {
- // @is "$.index[*][?(@.name=='VariantA')].inner.variant_kind" \"tuple\"
// @is "$.index[*][?(@.name=='0')].kind" \"struct_field\"
+ // @set f0 = "$.index[*][?(@.name=='0')].id"
// @is "$.index[*][?(@.name=='1')].kind" \"struct_field\"
+ // @set f1 = "$.index[*][?(@.name=='1')].id"
+ // @ismany "$.index[*][?(@.name=='VariantA')].inner.kind.tuple[*]" $f0 $f1
VariantA(u32, String),
}
--- /dev/null
+impl Vec< br##"*.."## > {}
+//~^ ERROR
--- /dev/null
+error[E0747]: constant provided when a type was expected
+ --> $DIR/issue-105334.rs:1:11
+ |
+LL | impl Vec< br##"*.."## > {}
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0747`.
--- /dev/null
+impl Vec<lol> {}
+//~^ ERROR
+
+pub fn lol() {}
--- /dev/null
+error[E0747]: constant provided when a type was expected
+ --> $DIR/issue-105737.rs:1:10
+ |
+LL | impl Vec<lol> {}
+ | ^^^
+ |
+ = help: `lol` is a function item, not a type
+ = help: function item types cannot be named directly
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0747`.
--- /dev/null
+// compile-flags: -Znormalize-docs
+
+use std::ops::Index;
+
+pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+ let _ = s;
+}
+
+pub trait SVec: Index<
+ <Self as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+ Output = <Index<<Self as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+ Output = <Self as SVec>::Item> as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+//~^^^^^ ERROR
+//~^^^^^^ ERROR
+//~^^^^^^^ ERROR
+//~^^^^^^^^ ERROR
+> {
+ type Item<'a, T>;
+
+ fn len(&self) -> <Self as SVec>::Item;
+ //~^ ERROR
+ //~^^ ERROR
+ //~^^^ ERROR
+ //~^^^^ ERROR
+}
--- /dev/null
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:13:21
+ |
+LL | <Self as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | <Self as SVec>::Item<'a>,
+ | ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:13:21
+ |
+LL | <Self as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | <Self as SVec>::Item<T>,
+ | ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:18:37
+ |
+LL | Output = <Index<<Self as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | Output = <Index<<Self as SVec>::Item<'a>,
+ | ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:18:37
+ |
+LL | Output = <Index<<Self as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | Output = <Index<<Self as SVec>::Item<T>,
+ | ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:30
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | Output = <Self as SVec>::Item<'a>> as SVec>::Item,
+ | ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:30
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | Output = <Self as SVec>::Item<T>> as SVec>::Item,
+ | ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:46
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item<'a>,
+ | ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:46
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item<T>,
+ | ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:5:40
+ |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item<'_> = T, Output = T>) {
+ | ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:5:40
+ |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item<T> = T, Output = T>) {
+ | ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:13:21
+ |
+LL | <Self as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | <Self as SVec>::Item<'a>,
+ | ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:13:21
+ |
+LL | <Self as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | <Self as SVec>::Item<T>,
+ | ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:18:37
+ |
+LL | Output = <Index<<Self as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | Output = <Index<<Self as SVec>::Item<'a>,
+ | ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:18:37
+ |
+LL | Output = <Index<<Self as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | Output = <Index<<Self as SVec>::Item<T>,
+ | ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:30
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | Output = <Self as SVec>::Item<'a>> as SVec>::Item,
+ | ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:30
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | Output = <Self as SVec>::Item<T>> as SVec>::Item,
+ | ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:46
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item<'a>,
+ | ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:23:46
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item,
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | Output = <Self as SVec>::Item> as SVec>::Item<T>,
+ | ~~~~~~~
+
+error[E0038]: the trait `SVec` cannot be made into an object
+ --> $DIR/issue-105742.rs:5:31
+ |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` cannot be made into an object
+ |
+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>
+ --> $DIR/issue-105742.rs:12:17
+ |
+LL | pub trait SVec: Index<
+ | ____________----__^
+ | | |
+ | | this trait cannot be made into an object...
+LL | | <Self as SVec>::Item,
+LL | |
+LL | |
+... |
+LL | |/ Output = <Index<<Self as SVec>::Item,
+LL | ||
+LL | ||
+LL | ||
+LL | ||
+LL | || Output = <Self as SVec>::Item> as SVec>::Item,
+ | ||_________________________________________________^ ...because it uses `Self` as a type parameter
+... |
+LL | |
+LL | | > {
+ | |__^ ...because it uses `Self` as a type parameter
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:35:38
+ |
+LL | fn len(&self) -> <Self as SVec>::Item;
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | fn len(&self) -> <Self as SVec>::Item<'_>;
+ | ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:35:38
+ |
+LL | fn len(&self) -> <Self as SVec>::Item;
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | fn len(&self) -> <Self as SVec>::Item<T>;
+ | ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:35:38
+ |
+LL | fn len(&self) -> <Self as SVec>::Item;
+ | ^^^^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ --
+help: add missing lifetime argument
+ |
+LL | fn len(&self) -> <Self as SVec>::Item<'_>;
+ | ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+ --> $DIR/issue-105742.rs:35:38
+ |
+LL | fn len(&self) -> <Self as SVec>::Item;
+ | ^^^^ expected 1 generic argument
+ |
+note: associated type defined here, with 1 generic parameter: `T`
+ --> $DIR/issue-105742.rs:33:10
+ |
+LL | type Item<'a, T>;
+ | ^^^^ -
+help: add missing generic argument
+ |
+LL | fn len(&self) -> <Self as SVec>::Item<T>;
+ | ~~~~~~~
+
+error: aborting due to 23 previous errors
+
+Some errors have detailed explanations: E0038, E0107.
+For more information about an error, try `rustc --explain E0038`.
--- /dev/null
+// This is a regression test for <https://github.com/rust-lang/rust/issues/106226>.
+type F = [_; ()];
+//~^ ERROR
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-106226.rs:2:14
+ |
+LL | type F = [_; ()];
+ | ^^ expected `usize`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+pub trait TraitWithAssoc {
+ type Assoc;
+}
+
+pub type Foo<V> = impl Trait<V::Assoc>;
+//~^ ERROR
+//~^^ ERROR
+
+pub trait Trait<U> {}
+
+impl<W> Trait<W> for () {}
+
+pub fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T> {
+ ()
+}
--- /dev/null
+error[E0220]: associated type `Assoc` not found for `V`
+ --> $DIR/issue-96287.rs:7:33
+ |
+LL | pub type Foo<V> = impl Trait<V::Assoc>;
+ | ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
+
+error[E0220]: associated type `Assoc` not found for `V`
+ --> $DIR/issue-96287.rs:7:33
+ |
+LL | pub type Foo<V> = impl Trait<V::Assoc>;
+ | ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0220`.
extern crate rustc_macros;
extern crate rustc_serialize;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{MemDecoder, MemEncoder};
use rustc_serialize::{Decodable, Encodable, Encoder};
extern crate rustc_macros;
extern crate rustc_serialize;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{MemDecoder, MemEncoder};
use rustc_serialize::{Decodable, Encodable, Encoder};
extern crate rustc_macros;
extern crate rustc_serialize;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
mod submod {
use rustc_macros::{Decodable, Encodable};
use rustc_macros::{Decodable, Encodable};
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
pub const other: u8 = 1;
pub const f: u8 = 1;
pub const d: u8 = 1;
extern crate rustc_arena;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_arena::TypedArena;
trait HasId { fn count(&self) -> usize; }
extern crate rustc_macros;
extern crate rustc_serialize;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_macros::{Decodable, Encodable};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encodable, Decodable)]
extern crate rustc_macros;
extern crate rustc_serialize;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{MemDecoder, MemEncoder};
use rustc_serialize::{Decodable, Encodable, Encoder};
--- /dev/null
+// Test that we get the following hint when trying to use a compiler crate without rustc_driver.
+// error-pattern: try adding `extern crate rustc_driver;` at the top level of this crate
+// compile-flags: --emit link
+// The exactly list of required crates depends on the target. as such only test Unix targets.
+// only-unix
+
+#![feature(rustc_private)]
+
+extern crate rustc_serialize;
+
+fn main() {}
--- /dev/null
+error: crate `rustc_serialize` required to be available in rlib format, but was not found in this form
+ |
+ = help: try adding `extern crate rustc_driver;` at the top level of this crate
+
+error: crate `smallvec` required to be available in rlib format, but was not found in this form
+
+error: crate `thin_vec` required to be available in rlib format, but was not found in this form
+
+error: crate `indexmap` required to be available in rlib format, but was not found in this form
+
+error: crate `hashbrown` required to be available in rlib format, but was not found in this form
+
+error: crate `ahash` required to be available in rlib format, but was not found in this form
+
+error: crate `once_cell` required to be available in rlib format, but was not found in this form
+
+error: crate `getrandom` required to be available in rlib format, but was not found in this form
+
+error: crate `cfg_if` required to be available in rlib format, but was not found in this form
+
+error: crate `libc` required to be available in rlib format, but was not found in this form
+
+error: aborting due to 10 previous errors
+
extern crate rustc_session;
extern crate rustc_span;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_parse::new_parser_from_file;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::FilePathMapping;
extern crate rustc_span;
extern crate thin_vec;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_ast::mut_visit::{self, visit_clobber, MutVisitor};
use rustc_ast::ptr::P;
use rustc_ast::*;
extern crate rustc_arena;
extern crate libc;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use TypeStructure::{TypeInt, TypeFunction};
use AstKind::{ExprInt, ExprVar, ExprLambda};
use rustc_arena::TypedArena;
#[allow(dead_code)]
extern crate rustc_serialize;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use rustc_macros::{Decodable, Encodable};
#[derive(Decodable, Encodable, Debug)]
// Outputs require mutable places
- let v: Vec<u64> = vec![0, 1, 2];
+ let v: Vec<u64> = vec![0, 1, 2]; //~ ERROR cannot borrow `v` as mutable
asm!("{}", in(reg) v[0]);
asm!("{}", out(reg) v[0]);
- //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
asm!("{}", inout(reg) v[0]);
- //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
// Sym operands must point to a function or static
}
| +++
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-2-2.rs:30:29
+ --> $DIR/type-check-2-2.rs:28:13
|
LL | let v: Vec<u64> = vec![0, 1, 2];
- | - help: consider changing this to be mutable: `mut v`
+ | ^ not mutable
LL | asm!("{}", in(reg) v[0]);
LL | asm!("{}", out(reg) v[0]);
- | ^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-2-2.rs:32:31
- |
-LL | let v: Vec<u64> = vec![0, 1, 2];
- | - help: consider changing this to be mutable: `mut v`
-...
+ | - cannot borrow as mutable
LL | asm!("{}", inout(reg) v[0]);
- | ^ cannot borrow as mutable
+ | - cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut v: Vec<u64> = vec![0, 1, 2];
+ | +++
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
Some errors have detailed explanations: E0381, E0596.
For more information about an error, try `rustc --explain E0381`.
// Outputs require mutable places
let v: Vec<u64> = vec![0, 1, 2];
+ //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
asm!("{}", in(reg) v[0]);
asm!("{}", out(reg) v[0]);
- //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
asm!("{}", inout(reg) v[0]);
- //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
// Sym operands must point to a function or static
| +++
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-5.rs:26:29
+ --> $DIR/type-check-5.rs:24:13
|
LL | let v: Vec<u64> = vec![0, 1, 2];
- | - help: consider changing this to be mutable: `mut v`
-LL | asm!("{}", in(reg) v[0]);
-LL | asm!("{}", out(reg) v[0]);
- | ^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-5.rs:28:31
- |
-LL | let v: Vec<u64> = vec![0, 1, 2];
- | - help: consider changing this to be mutable: `mut v`
+ | ^ not mutable
...
+LL | asm!("{}", out(reg) v[0]);
+ | - cannot borrow as mutable
LL | asm!("{}", inout(reg) v[0]);
- | ^ cannot borrow as mutable
+ | - cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut v: Vec<u64> = vec![0, 1, 2];
+ | +++
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
Some errors have detailed explanations: E0381, E0596.
For more information about an error, try `rustc --explain E0381`.
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/issue-61452.rs:4:5
|
-LL | pub async fn f(x: Option<usize>) {
- | - help: consider changing this to be mutable: `mut x`
LL | x.take();
| ^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | pub async fn f(mut x: Option<usize>) {
+ | +++
error[E0384]: cannot assign twice to immutable variable `x`
--> $DIR/issue-61452.rs:9:5
error[E0596]: cannot borrow `data` as mutable, as it is not declared as mutable
--> $DIR/issue-61187.rs:6:5
|
-LL | async fn response(data: Vec<u8>) {
- | ---- help: consider changing this to be mutable: `mut data`
LL | data.reverse();
| ^^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | async fn response(mut data: Vec<u8>) {
+ | +++
error: aborting due to previous error
let y = Int(2);
//~^ HELP consider changing this to be mutable
- //~| SUGGESTION mut y
+ //~| SUGGESTION mut
y //~ ERROR cannot borrow `y` as mutable, as it is not declared as mutable
//~| cannot borrow as mutable
+=
error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
--> $DIR/augmented-assignments.rs:23:5
|
-LL | let y = Int(2);
- | - help: consider changing this to be mutable: `mut y`
-...
LL | y
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut y = Int(2);
+ | +++
error: aborting due to 2 previous errors
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrow-raw-address-of-mutability.rs:5:13
|
-LL | let x = 0;
- | - help: consider changing this to be mutable: `mut x`
LL | let y = &raw mut x;
| ^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x = 0;
+ | +++
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrow-raw-address-of-mutability.rs:11:17
error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
--> $DIR/borrow-raw-address-of-mutability.rs:21:5
|
-LL | let f = || {
- | - help: consider changing this to be mutable: `mut f`
LL | let y = &raw mut x;
| - calling `f` requires mutable binding due to mutable borrow of `x`
LL | };
LL | f();
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut f = || {
+ | +++
error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-raw-address-of-mutability.rs:29:17
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-access-permissions.rs:9:19
|
-LL | let x = 1;
- | - help: consider changing this to be mutable: `mut x`
-...
LL | let _y1 = &mut x;
| ^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x = 1;
+ | +++
error[E0596]: cannot borrow immutable static item `static_x` as mutable
--> $DIR/borrowck-access-permissions.rs:14:19
error[E0596]: cannot borrow `*box_x` as mutable, as `box_x` is not declared as mutable
--> $DIR/borrowck-access-permissions.rs:22:19
|
-LL | let box_x = Box::new(1);
- | ----- help: consider changing this to be mutable: `mut box_x`
-...
LL | let _y1 = &mut *box_x;
| ^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut box_x = Box::new(1);
+ | +++
error[E0596]: cannot borrow `*ref_x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-access-permissions.rs:30:19
error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
--> $DIR/borrowck-argument.rs:10:5
|
-LL | fn func(arg: S) {
- | --- help: consider changing this to be mutable: `mut arg`
LL | arg.mutate();
| ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn func(mut arg: S) {
+ | +++
error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
--> $DIR/borrowck-argument.rs:15:9
|
-LL | fn method(&self, arg: S) {
- | --- help: consider changing this to be mutable: `mut arg`
LL | arg.mutate();
| ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn method(&self, mut arg: S) {
+ | +++
error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
--> $DIR/borrowck-argument.rs:21:9
|
-LL | fn default(&self, arg: S) {
- | --- help: consider changing this to be mutable: `mut arg`
LL | arg.mutate();
| ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn default(&self, mut arg: S) {
+ | +++
error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
--> $DIR/borrowck-argument.rs:32:17
|
LL | (|arg: S| { arg.mutate() })(s);
- | --- ^^^^^^^^^^^^ cannot borrow as mutable
- | |
- | help: consider changing this to be mutable: `mut arg`
+ | ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | (|mut arg: S| { arg.mutate() })(s);
+ | +++
error: aborting due to 4 previous errors
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-auto-mut-ref-to-immut-var.rs:15:5
|
-LL | let x = Foo { x: 3 };
- | - help: consider changing this to be mutable: `mut x`
LL | x.printme();
| ^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x = Foo { x: 3 };
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable
--> $DIR/borrowck-borrow-from-owned-ptr.rs:122:16
|
-LL | let foo = make_foo();
- | --- help: consider changing this to be mutable: `mut foo`
LL | let bar1 = &mut foo.bar1;
| ^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut foo = make_foo();
+ | +++
error: aborting due to 11 previous errors
error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable
--> $DIR/borrowck-borrow-from-stack-variable.rs:120:16
|
-LL | let foo = make_foo();
- | --- help: consider changing this to be mutable: `mut foo`
LL | let bar1 = &mut foo.bar1;
| ^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut foo = make_foo();
+ | +++
error: aborting due to 11 previous errors
error[E0596]: cannot borrow `*a` as mutable, as `a` is not declared as mutable
--> $DIR/borrowck-borrow-immut-deref-of-box-as-mut.rs:12:5
|
-LL | let a: Box<_> = Box::new(A);
- | - help: consider changing this to be mutable: `mut a`
LL | a.foo();
| ^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut a: Box<_> = Box::new(A);
+ | +++
error: aborting due to previous error
+#![feature(if_let_guard)]
+
fn foo(_:String) {}
fn main()
Some(_) => {}
None => { foo(my_str); } //~ ERROR [E0382]
}
+
+ let my_str = "hello".to_owned();
+ match Some(42) {
+ Some(_) if let Some(()) = { drop(my_str); None } => {}
+ Some(_) => {}
+ None => { foo(my_str); } //~ ERROR [E0382]
+ }
}
error[E0382]: use of moved value: `my_str`
- --> $DIR/borrowck-drop-from-guard.rs:9:23
+ --> $DIR/borrowck-drop-from-guard.rs:11:23
|
LL | let my_str = "hello".to_owned();
| ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
LL | Some(_) if { drop(my_str.clone()); false } => {}
| ++++++++
-error: aborting due to previous error
+error[E0382]: use of moved value: `my_str`
+ --> $DIR/borrowck-drop-from-guard.rs:18:23
+ |
+LL | let my_str = "hello".to_owned();
+ | ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
+LL | match Some(42) {
+LL | Some(_) if let Some(()) = { drop(my_str); None } => {}
+ | ------ value moved here
+LL | Some(_) => {}
+LL | None => { foo(my_str); }
+ | ^^^^^^ value used here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | Some(_) if let Some(()) = { drop(my_str.clone()); None } => {}
+ | ++++++++
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0382`.
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-mut-addr-of-imm-var.rs:3:25
|
-LL | let x: isize = 3;
- | - help: consider changing this to be mutable: `mut x`
LL | let y: &mut isize = &mut x;
| ^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x: isize = 3;
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
--> $DIR/borrowck-mut-slice-of-imm-vec.rs:7:11
|
-LL | let v = vec![1, 2, 3];
- | - help: consider changing this to be mutable: `mut v`
LL | write(&mut v);
| ^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut v = vec![1, 2, 3];
+ | +++
error: aborting due to previous error
+#![feature(if_let_guard)]
+
enum Enum<'a> {
A(&'a isize),
B(bool),
}
-fn foo() -> isize {
+fn if_guard() -> isize {
let mut n = 42;
let mut x = Enum::A(&mut n);
match x {
}
}
-fn main() {
- foo();
+fn if_let_guard() -> isize {
+ let mut n = 42;
+ let mut x = Enum::A(&mut n);
+ match x {
+ Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
+ //~^ ERROR cannot assign `x` in match guard
+ Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
+ //~^ ERROR cannot mutably borrow `x` in match guard
+ Enum::A(p) => *p,
+ Enum::B(_) => 2,
+ }
}
+
+fn main() {}
error[E0510]: cannot assign `x` in match guard
- --> $DIR/borrowck-mutate-in-guard.rs:10:25
+ --> $DIR/borrowck-mutate-in-guard.rs:12:25
|
LL | match x {
| - value is immutable in match guard
| ^^^^^^^^^^^^^^^^^^ cannot assign
error[E0510]: cannot mutably borrow `x` in match guard
- --> $DIR/borrowck-mutate-in-guard.rs:12:33
+ --> $DIR/borrowck-mutate-in-guard.rs:14:33
|
LL | match x {
| - value is immutable in match guard
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
| ^^^^^^ cannot mutably borrow
-error: aborting due to 2 previous errors
+error[E0510]: cannot assign `x` in match guard
+ --> $DIR/borrowck-mutate-in-guard.rs:25:40
+ |
+LL | match x {
+ | - value is immutable in match guard
+LL | Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
+ | ^^^^^^^^^^^^^^^^^^ cannot assign
+
+error[E0510]: cannot mutably borrow `x` in match guard
+ --> $DIR/borrowck-mutate-in-guard.rs:27:48
+ |
+LL | match x {
+ | - value is immutable in match guard
+...
+LL | Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
+ | ^^^^^^ cannot mutably borrow
+
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0510`.
error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable
--> $DIR/borrowck-overloaded-call.rs:67:5
|
-LL | let s = SFnMut {
- | - help: consider changing this to be mutable: `mut s`
-...
LL | s(3);
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut s = SFnMut {
+ | +++
error[E0382]: use of moved value: `s`
--> $DIR/borrowck-overloaded-call.rs:75:5
error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
--> $DIR/borrowck-ref-mut-of-imm.rs:4:12
|
-LL | fn destructure(x: Option<isize>) -> isize {
- | - help: consider changing this to be mutable: `mut x`
-...
LL | Some(ref mut v) => *v
| ^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn destructure(mut x: Option<isize>) -> isize {
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
--> $DIR/borrowck-unboxed-closures.rs:7:5
|
-LL | fn b<F:FnMut(isize, isize) -> isize>(f: F) {
- | - help: consider changing this to be mutable: `mut f`
LL | f(1, 2);
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn b<F:FnMut(isize, isize) -> isize>(mut f: F) {
+ | +++
error[E0382]: use of moved value: `f`
--> $DIR/borrowck-unboxed-closures.rs:12:5
error[E0594]: cannot assign to `*y`, as `y` is not declared as mutable
--> $DIR/immut-function-arguments.rs:2:5
|
-LL | fn f(y: Box<isize>) {
- | - help: consider changing this to be mutable: `mut y`
LL | *y = 5;
| ^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | fn f(mut y: Box<isize>) {
+ | +++
error[E0594]: cannot assign to `*q`, as `q` is not declared as mutable
--> $DIR/immut-function-arguments.rs:6:35
|
LL | let _frob = |q: Box<isize>| { *q = 2; };
- | - ^^^^^^ cannot assign
- | |
- | help: consider changing this to be mutable: `mut q`
+ | ^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let _frob = |mut q: Box<isize>| { *q = 2; };
+ | +++
error: aborting due to 2 previous errors
+#![feature(if_let_guard)]
+
fn main() {
let a = Some("...".to_owned());
let b = match a {
Some(_) if { drop(a); false } => None,
x => x, //~ ERROR use of moved value: `a`
};
- println!("{:?}", b);
+
+ let a = Some("...".to_owned());
+ let b = match a {
+ Some(_) if let Some(()) = { drop(a); None } => None,
+ x => x, //~ ERROR use of moved value: `a`
+ };
}
error[E0382]: use of moved value: `a`
- --> $DIR/issue-31287-drop-in-guard.rs:5:9
+ --> $DIR/issue-31287-drop-in-guard.rs:7:9
|
LL | let a = Some("...".to_owned());
| - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
LL | Some(_) if { drop(a.clone()); false } => None,
| ++++++++
-error: aborting due to previous error
+error[E0382]: use of moved value: `a`
+ --> $DIR/issue-31287-drop-in-guard.rs:13:9
+ |
+LL | let a = Some("...".to_owned());
+ | - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
+LL | let b = match a {
+LL | Some(_) if let Some(()) = { drop(a); None } => None,
+ | - value moved here
+LL | x => x,
+ | ^ value used here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | Some(_) if let Some(()) = { drop(a.clone()); None } => None,
+ | ++++++++
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0382`.
error[E0594]: cannot assign to `t.0`, as `t` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:13:9
|
-LL | let t: Tuple = (S(0), 0);
- | - help: consider changing this to be mutable: `mut t`
-LL | drop(t);
LL | t.0 = S(1);
| ^^^^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut t: Tuple = (S(0), 0);
+ | +++
error[E0382]: assign to part of moved value: `t`
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:13:9
error[E0594]: cannot assign to `t.1`, as `t` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:16:9
|
-LL | let t: Tuple = (S(0), 0);
- | - help: consider changing this to be mutable: `mut t`
-...
LL | t.1 = 2;
| ^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut t: Tuple = (S(0), 0);
+ | +++
error[E0594]: cannot assign to `u.0`, as `u` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:24:9
|
-LL | let u: Tpair = Tpair(S(0), 0);
- | - help: consider changing this to be mutable: `mut u`
-LL | drop(u);
LL | u.0 = S(1);
| ^^^^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut u: Tpair = Tpair(S(0), 0);
+ | +++
error[E0382]: assign to part of moved value: `u`
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:24:9
error[E0594]: cannot assign to `u.1`, as `u` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9
|
-LL | let u: Tpair = Tpair(S(0), 0);
- | - help: consider changing this to be mutable: `mut u`
-...
LL | u.1 = 2;
| ^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut u: Tpair = Tpair(S(0), 0);
+ | +++
error[E0594]: cannot assign to `v.x`, as `v` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:35:9
|
-LL | let v: Spair = Spair { x: S(0), y: 0 };
- | - help: consider changing this to be mutable: `mut v`
-LL | drop(v);
LL | v.x = S(1);
| ^^^^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut v: Spair = Spair { x: S(0), y: 0 };
+ | +++
error[E0382]: assign to part of moved value: `v`
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:35:9
error[E0594]: cannot assign to `v.y`, as `v` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9
|
-LL | let v: Spair = Spair { x: S(0), y: 0 };
- | - help: consider changing this to be mutable: `mut v`
-...
LL | v.y = 2;
| ^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut v: Spair = Spair { x: S(0), y: 0 };
+ | +++
error: aborting due to 9 previous errors
--- /dev/null
+fn main() {
+ let v = Vec::new(); //~ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+ v.push(0);
+}
--- /dev/null
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+ --> $DIR/many-mutable-borrows.rs:2:9
+ |
+LL | let v = Vec::new();
+ | ^ not mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+LL | v.push(0);
+ | --------- cannot borrow as mutable
+ |
+ = note: ...and 5 other attempted mutable borrows
+help: consider changing this to be mutable
+ |
+LL | let mut v = Vec::new();
+ | +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
#![crate_type = "rlib"]
pub fn f(b: &mut i32) {
- //~^ NOTE the binding is already a mutable borrow
+ //~^ ERROR cannot borrow
+ //~| NOTE not mutable
//~| NOTE the binding is already a mutable borrow
h(&mut b);
- //~^ ERROR cannot borrow
- //~| NOTE cannot borrow as mutable
+ //~^ NOTE cannot borrow as mutable
//~| HELP try removing `&mut` here
g(&mut &mut b);
- //~^ ERROR cannot borrow
- //~| NOTE cannot borrow as mutable
+ //~^ NOTE cannot borrow as mutable
//~| HELP try removing `&mut` here
}
error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
- --> $DIR/mut-borrow-of-mut-ref.rs:7:7
+ --> $DIR/mut-borrow-of-mut-ref.rs:4:10
|
+LL | pub fn f(b: &mut i32) {
+ | ^ not mutable
+...
LL | h(&mut b);
- | ^^^^^^ cannot borrow as mutable
+ | ------ cannot borrow as mutable
+...
+LL | g(&mut &mut b);
+ | ------ cannot borrow as mutable
|
note: the binding is already a mutable borrow
--> $DIR/mut-borrow-of-mut-ref.rs:4:13
LL - h(&mut b);
LL + h(b);
|
-
-error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
- --> $DIR/mut-borrow-of-mut-ref.rs:11:12
- |
-LL | g(&mut &mut b);
- | ^^^^^^ cannot borrow as mutable
- |
-note: the binding is already a mutable borrow
- --> $DIR/mut-borrow-of-mut-ref.rs:4:13
- |
-LL | pub fn f(b: &mut i32) {
- | ^^^^^^^^
help: try removing `&mut` here
|
LL - g(&mut &mut b);
|
error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
- --> $DIR/mut-borrow-of-mut-ref.rs:18:12
+ --> $DIR/mut-borrow-of-mut-ref.rs:17:12
|
LL | h(&mut &mut b);
| ^^^^^^ cannot borrow as mutable
|
note: the binding is already a mutable borrow
- --> $DIR/mut-borrow-of-mut-ref.rs:17:13
+ --> $DIR/mut-borrow-of-mut-ref.rs:16:13
|
LL | pub fn g(b: &mut i32) {
| ^^^^^^^^
|
error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
- --> $DIR/mut-borrow-of-mut-ref.rs:35:5
+ --> $DIR/mut-borrow-of-mut-ref.rs:34:5
|
LL | f.bar();
| ^^^^^^^ cannot borrow as mutable
LL | pub fn baz(mut f: &mut String) {
| +++
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0596`.
});
}
-fn imm_local(x: (i32,)) {
- &mut x; //~ ERROR
- &mut x.0; //~ ERROR
+fn imm_local(x: (i32,)) { //~ ERROR
+ &mut x;
+ &mut x.0;
}
fn imm_capture(x: (i32,)) {
| ^^^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
- --> $DIR/mutability-errors.rs:54:5
+ --> $DIR/mutability-errors.rs:53:14
|
LL | fn imm_local(x: (i32,)) {
- | - help: consider changing this to be mutable: `mut x`
-LL | &mut x;
- | ^^^^^^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
- --> $DIR/mutability-errors.rs:55:5
- |
-LL | fn imm_local(x: (i32,)) {
- | - help: consider changing this to be mutable: `mut x`
+ | ^ not mutable
LL | &mut x;
+ | ------ cannot borrow as mutable
LL | &mut x.0;
- | ^^^^^^^^ cannot borrow as mutable
+ | -------- cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn imm_local(mut x: (i32,)) {
+ | +++
error[E0594]: cannot assign to `x`, as it is not declared as mutable
--> $DIR/mutability-errors.rs:60:9
LL | &mut X.0;
| ^^^^^^^^ cannot borrow as mutable
-error: aborting due to 38 previous errors
+error: aborting due to 37 previous errors
Some errors have detailed explanations: E0594, E0596.
For more information about an error, try `rustc --explain E0594`.
error[E0594]: cannot assign to `x.b`, as `x` is not declared as mutable
--> $DIR/reassignment_immutable_fields_overlapping.rs:13:5
|
-LL | let x: Foo;
- | - help: consider changing this to be mutable: `mut x`
-LL | x.a = 1;
LL | x.b = 22;
| ^^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x: Foo;
+ | +++
error: aborting due to 2 previous errors
error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
--> $DIR/reassignment_immutable_fields_twice.rs:7:5
|
-LL | let x: (u32, u32);
- | - help: consider changing this to be mutable: `mut x`
-LL | x = (22, 44);
LL | x.0 = 1;
| ^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x: (u32, u32);
+ | +++
error[E0381]: partially assigned binding `x` isn't fully initialized
--> $DIR/reassignment_immutable_fields_twice.rs:12:5
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
--> $DIR/issue-80313-mutable-borrow-in-closure.rs:6:5
|
-LL | let callback = || {
- | -------- help: consider changing this to be mutable: `mut callback`
LL | &mut my_var;
| ------ calling `callback` requires mutable binding due to mutable borrow of `my_var`
LL | };
LL | callback();
| ^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut callback = || {
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
--> $DIR/issue-80313-mutable-borrow-in-move-closure.rs:6:5
|
-LL | let callback = move || {
- | -------- help: consider changing this to be mutable: `mut callback`
LL | &mut my_var;
| ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
LL | };
LL | callback();
| ^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut callback = move || {
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
--> $DIR/issue-80313-mutation-in-closure.rs:6:5
|
-LL | let callback = || {
- | -------- help: consider changing this to be mutable: `mut callback`
LL | my_var = true;
| ------ calling `callback` requires mutable binding due to mutable borrow of `my_var`
LL | };
LL | callback();
| ^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut callback = || {
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
--> $DIR/issue-80313-mutation-in-move-closure.rs:6:5
|
-LL | let callback = move || {
- | -------- help: consider changing this to be mutable: `mut callback`
LL | my_var = true;
| ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
LL | };
LL | callback();
| ^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut callback = move || {
+ | +++
error: aborting due to previous error
--> $DIR/issue-81700-mut-borrow.rs:3:5
|
LL | let bar = || { foo(x); };
- | --- - calling `bar` requires mutable binding due to mutable borrow of `x`
- | |
- | help: consider changing this to be mutable: `mut bar`
+ | - calling `bar` requires mutable binding due to mutable borrow of `x`
LL | bar();
| ^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut bar = || { foo(x); };
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `c` as mutable, as it is not declared as mutable
--> $DIR/issue-82438-mut-without-upvar.rs:27:27
|
-LL | let c = |a, b, c, d| {};
- | - help: consider changing this to be mutable: `mut c`
-LL |
LL | A.f(participant_name, &mut c);
| ^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut c = |a, b, c, d| {};
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
--> $DIR/issue-84044-drop-non-mut.rs:5:10
|
-LL | let f = || {};
- | - help: consider changing this to be mutable: `mut f`
LL | drop(&mut f);
| ^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut f = || {};
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/huge_multispan_highlight.rs:90:13
|
-LL | let x = "foo";
- | - help: consider changing this to be mutable: `mut x`
-...
LL | let y = &mut x;
| ^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x = "foo";
+ | +++
error: aborting due to previous error
error[E0596]: cannot borrow `f.v` as mutable, as `f` is not declared as mutable
--> $DIR/issue-35937.rs:7:5
|
-LL | let f = Foo { v: Vec::new() };
- | - help: consider changing this to be mutable: `mut f`
LL | f.v.push("cat".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut f = Foo { v: Vec::new() };
+ | +++
error[E0594]: cannot assign to `s.x`, as `s` is not declared as mutable
--> $DIR/issue-35937.rs:16:5
|
-LL | let s = S { x: 42 };
- | - help: consider changing this to be mutable: `mut s`
LL | s.x += 1;
| ^^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut s = S { x: 42 };
+ | +++
error[E0594]: cannot assign to `s.x`, as `s` is not declared as mutable
--> $DIR/issue-35937.rs:20:5
|
-LL | fn bar(s: S) {
- | - help: consider changing this to be mutable: `mut s`
LL | s.x += 1;
| ^^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | fn bar(mut s: S) {
+ | +++
error: aborting due to 3 previous errors
error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable
--> $DIR/issue-39544.rs:11:13
|
-LL | let z = Z { x: X::Y };
- | - help: consider changing this to be mutable: `mut z`
LL | let _ = &mut z.x;
| ^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut z = Z { x: X::Y };
+ | +++
error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference
--> $DIR/issue-39544.rs:16:17
error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable
--> $DIR/issue-39544.rs:41:13
|
-LL | pub fn with_arg(z: Z, w: &Z) {
- | - help: consider changing this to be mutable: `mut z`
LL | let _ = &mut z.x;
| ^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | pub fn with_arg(mut z: Z, w: &Z) {
+ | +++
error[E0596]: cannot borrow `w.x` as mutable, as it is behind a `&` reference
--> $DIR/issue-39544.rs:42:13
LL | #![feature(dyn_star)]
| ^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted
LL | #![feature(dyn_star)]
| ^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0277]: `AlignedUsize` needs to be a pointer-sized type
LL | #![feature(dyn_star)]
| ^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted
LL | #![feature(dyn_star)]
| ^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted
LL | pub fn dyn_star_parameter(_: &dyn* Send) {
| ^^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= help: add `#![feature(dyn_star)]` to the crate attributes to enable
error: aborting due to previous error
LL | let dyn_i: dyn* Debug = i as dyn* Debug;
| ^^^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= help: add `#![feature(dyn_star)]` to the crate attributes to enable
error[E0658]: dyn* trait objects are unstable
LL | let dyn_i: dyn* Debug = i as dyn* Debug;
| ^^^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= help: add `#![feature(dyn_star)]` to the crate attributes to enable
error[E0606]: casting `usize` as `dyn* Debug` is invalid
LL | #![feature(dyn_star, trait_upcasting)]
| ^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0308]: mismatched types
LL | #![feature(dyn_star)]
| ^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted
LL | #![feature(dyn_star, trait_upcasting)]
| ^^^^^^^^
|
- = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0277]: `dyn* Foo` needs to be a pointer-sized type
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/E0596.rs:3:13
|
-LL | let x = 1;
- | - help: consider changing this to be mutable: `mut x`
LL | let y = &mut x;
| ^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x = 1;
+ | +++
error: aborting due to previous error
| |
| help: format specifiers use curly braces: `{}`
|
- = note: printf formatting not supported; see the documentation for `std::fmt`
+ = note: printf formatting is not supported; see the documentation for `std::fmt`
error: invalid format string: expected `'}'`, found `'t'`
--> $DIR/ifmt-bad-arg.rs:75:1
//~| NOTE: argument never used
//~| NOTE: argument never used
//~| NOTE: format specifiers use curly braces, and you have to use a positional or named parameter for the width
- //~| NOTE: printf formatting not supported
+ //~| NOTE: printf formatting is not supported
}
|
LL | print!("%0*x", width, num);
| ^^^^
- = note: printf formatting not supported; see the documentation for `std::fmt`
+ = note: printf formatting is not supported; see the documentation for `std::fmt`
error: aborting due to previous error
// test for https://github.com/rust-lang/rust/issues/29723
+#![feature(if_let_guard)]
+
fn main() {
let s = String::new();
let _s = match 0 {
//~^ ERROR use of moved value: `s`
}
};
+
+ let s = String::new();
+ let _s = match 0 {
+ 0 if let Some(()) = { drop(s); None } => String::from("oops"),
+ _ => s //~ ERROR use of moved value: `s`
+ };
}
error[E0382]: use of moved value: `s`
- --> $DIR/issue-29723.rs:10:13
+ --> $DIR/issue-29723.rs:12:13
|
LL | let s = String::new();
| - move occurs because `s` has type `String`, which does not implement the `Copy` trait
LL | 0 if { drop(s.clone()); false } => String::from("oops"),
| ++++++++
-error: aborting due to previous error
+error[E0382]: use of moved value: `s`
+ --> $DIR/issue-29723.rs:20:14
+ |
+LL | let s = String::new();
+ | - move occurs because `s` has type `String`, which does not implement the `Copy` trait
+LL | let _s = match 0 {
+LL | 0 if let Some(()) = { drop(s); None } => String::from("oops"),
+ | - value moved here
+LL | _ => s
+ | ^ value used here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | 0 if let Some(()) = { drop(s.clone()); None } => String::from("oops"),
+ | ++++++++
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0382`.
error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable
--> $DIR/issue-36400.rs:5:7
|
-LL | let x = Box::new(3);
- | - help: consider changing this to be mutable: `mut x`
LL | f(&mut *x);
| ^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut x = Box::new(3);
+ | +++
error: aborting due to previous error
--- /dev/null
+fn main() {}
+
+impl std::ops::AddAssign for () {
+ //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
+ fn add_assign(&self, other: ()) -> () {
+ ()
+ }
+}
+
+impl std::ops::AddAssign for [(); 1] {
+ //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
+ fn add_assign(&self, other: [(); 1]) -> [(); 1] {
+ [()]
+ }
+}
+
+impl std::ops::AddAssign for &[u8] {
+ //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
+ fn add_assign(&self, other: &[u8]) -> &[u8] {
+ self
+ }
+}
--- /dev/null
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/issue-67535.rs:3:1
+ |
+LL | impl std::ops::AddAssign for () {
+ | ^^^^^-------------------^^^^^--
+ | | | |
+ | | | this is not defined in the current crate because tuples are always foreign
+ | | this is not defined in the current crate because this is a foreign trait
+ | impl doesn't use only types from inside the current crate
+ |
+ = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/issue-67535.rs:10:1
+ |
+LL | impl std::ops::AddAssign for [(); 1] {
+ | ^^^^^-------------------^^^^^-------
+ | | | |
+ | | | this is not defined in the current crate because arrays are always foreign
+ | | this is not defined in the current crate because this is a foreign trait
+ | impl doesn't use only types from inside the current crate
+ |
+ = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/issue-67535.rs:17:1
+ |
+LL | impl std::ops::AddAssign for &[u8] {
+ | ^^^^^-------------------^^^^^-----
+ | | | |
+ | | | this is not defined in the current crate because slices are always foreign
+ | | this is not defined in the current crate because this is a foreign trait
+ | impl doesn't use only types from inside the current crate
+ |
+ = note: define and implement a trait or new type instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0117`.
error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
--> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3
|
-LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
- | - help: consider changing this to be mutable: `mut y`
LL | y.push(z);
| ^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn foo(x:fn(&u8, &u8), mut y: Vec<&u8>, z: &u8) {
+ | +++
error: aborting due to 2 previous errors
error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
--> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3
|
-LL | fn foo(x:Box<dyn Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) {
- | - help: consider changing this to be mutable: `mut y`
LL | y.push(z);
| ^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn foo(x:Box<dyn Fn(&u8, &u8)> , mut y: Vec<&u8>, z: &u8) {
+ | +++
error: aborting due to 2 previous errors
| | argument never used
| multiple missing formatting specifiers
|
- = note: printf formatting not supported; see the documentation for `std::fmt`
+ = note: printf formatting is not supported; see the documentation for `std::fmt`
help: format specifiers use curly braces
|
LL | println!("{:.2$} {}!\n", "Hello,", "World", 4);
| |
| help: format specifiers use curly braces: `{0:1$.2$}`
|
- = note: printf formatting not supported; see the documentation for `std::fmt`
+ = note: printf formatting is not supported; see the documentation for `std::fmt`
error: multiple unused formatting arguments
--> $DIR/format-foreign.rs:6:7
| |____| argument never used
| multiple missing formatting specifiers
|
- = note: printf formatting not supported; see the documentation for `std::fmt`
+ = note: printf formatting is not supported; see the documentation for `std::fmt`
help: format specifiers use curly braces
|
LL ~ println!(r###"{:.2$}
| |
| help: format specifiers use curly braces: `{NAME}`
|
- = note: shell formatting not supported; see the documentation for `std::fmt`
+ = note: shell formatting is not supported; see the documentation for `std::fmt`
error: multiple unused formatting arguments
--> $DIR/format-foreign.rs:15:32
| | argument never used
| multiple missing formatting specifiers
|
- = note: shell formatting not supported; see the documentation for `std::fmt`
+ = note: shell formatting is not supported; see the documentation for `std::fmt`
help: format specifiers use curly braces
|
LL | println!("{1} {0} $$ {NAME}", 1, 2, NAME=3);
LL | , UNUSED="args");
| ^^^^^^ named argument never used
|
- = note: shell formatting not supported; see the documentation for `std::fmt`
+ = note: shell formatting is not supported; see the documentation for `std::fmt`
error: aborting due to 4 previous errors
|
LL | pub fn main() { println!("🦀%%%", 0) }
| ^^
- = note: printf formatting not supported; see the documentation for `std::fmt`
+ = note: printf formatting is not supported; see the documentation for `std::fmt`
error: aborting due to previous error
error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable
--> $DIR/span-covering-argument-1.rs:5:14
|
-LL | let $s = 0;
- | -- help: consider changing this to be mutable: `mut foo`
LL | *&mut $s = 0;
| ^^^^^^^ cannot borrow as mutable
...
| ------------------ in this macro invocation
|
= note: this error originates in the macro `bad` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider changing this to be mutable
+ |
+LL | let mut $s = 0;
+ | +++
error: aborting due to previous error
fn func(arg: S) {
//~^ HELP consider changing this to be mutable
- //~| SUGGESTION mut arg
+ //~| SUGGESTION mut
arg.mutate();
//~^ ERROR cannot borrow `arg` as mutable, as it is not declared as mutable
}
fn main() {
let local = S;
//~^ HELP consider changing this to be mutable
- //~| SUGGESTION mut local
+ //~| SUGGESTION mut
local.mutate();
//~^ ERROR cannot borrow `local` as mutable, as it is not declared as mutable
}
error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
--> $DIR/mut-suggestion.rs:12:5
|
-LL | fn func(arg: S) {
- | --- help: consider changing this to be mutable: `mut arg`
-...
LL | arg.mutate();
| ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn func(mut arg: S) {
+ | +++
error[E0596]: cannot borrow `local` as mutable, as it is not declared as mutable
--> $DIR/mut-suggestion.rs:20:5
|
-LL | let local = S;
- | ----- help: consider changing this to be mutable: `mut local`
-...
LL | local.mutate();
| ^^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut local = S;
+ | +++
error: aborting due to 2 previous errors
error[E0594]: cannot assign to `nyan.how_hungry`, as `nyan` is not declared as mutable
--> $DIR/mutable-class-fields.rs:15:3
|
-LL | let nyan : Cat = cat(52, 99);
- | ---- help: consider changing this to be mutable: `mut nyan`
LL | nyan.how_hungry = 0;
| ^^^^^^^^^^^^^^^^^^^ cannot assign
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut nyan : Cat = cat(52, 99);
+ | +++
error: aborting due to previous error
// See further discussion on rust-lang/rust#24535,
// rust-lang/rfcs#1006, and rust-lang/rfcs#107
+#![feature(if_let_guard)]
+
fn main() {
rust_issue_24535();
rfcs_issue_1006_1();
3 if compare(&a, &mut 3) => (),
_ => panic!("nope"),
}
+
+ match a {
+ 0 => panic!("nope"),
+ 3 if let true = compare(&a, &mut 3) => (),
+ _ => panic!("nope"),
+ }
}
fn rfcs_issue_1006_1() {
// reaches the panic code when executed, despite the compiler warning
// about that match arm being unreachable.
+#![feature(if_let_guard)]
+
fn main() {
let b = &mut true;
match b {
&mut true => { println!("You might think we should get here"); },
_ => panic!("surely we could never get here, since rustc warns it is unreachable."),
}
+
+ let b = &mut true;
+ match b {
+ //~^ ERROR use of moved value: `b` [E0382]
+ &mut false => {}
+ _ if let Some(()) = {
+ (|| { let bar = b; *bar = false; })();
+ None
+ } => {}
+ &mut true => {}
+ _ => {}
+ }
}
error[E0382]: use of moved value: `b`
- --> $DIR/issue-27282-move-match-input-into-guard.rs:12:5
+ --> $DIR/issue-27282-move-match-input-into-guard.rs:14:5
|
LL | let b = &mut true;
| - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
| |
| value moved into closure here
-error: aborting due to previous error
+error[E0382]: use of moved value: `b`
+ --> $DIR/issue-27282-move-match-input-into-guard.rs:24:5
+ |
+LL | let b = &mut true;
+ | - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
+LL | match b {
+ | ^^^^^^^ value used here after move
+...
+LL | (|| { let bar = b; *bar = false; })();
+ | -- - variable moved due to use in closure
+ | |
+ | value moved into closure here
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0382`.
// mutable borrows in match guards by hiding the mutable borrow in a
// guard behind a move (of the ref mut pattern id) within a closure.
+#![feature(if_let_guard)]
+
fn main() {
match Some(&4) {
None => {},
//~^ ERROR cannot move out of `foo` in pattern guard [E0507]
Some(s) => std::process::exit(*s),
}
+
+ match Some(&4) {
+ None => {},
+ ref mut foo
+ if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+ //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+ Some(s) => std::process::exit(*s),
+ }
}
error[E0507]: cannot move out of `foo` in pattern guard
- --> $DIR/issue-27282-move-ref-mut-into-guard.rs:9:19
+ --> $DIR/issue-27282-move-ref-mut-into-guard.rs:11:19
|
LL | if { (|| { let bar = foo; bar.take() })(); false } => {},
| ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+ --> $DIR/issue-27282-move-ref-mut-into-guard.rs:19:34
+ |
+LL | if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
+ | move out of `foo` occurs here
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0507`.
+#![feature(if_let_guard)]
+
fn main() {
match Some(&4) {
None => {},
Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."),
_ => println!("Here is some supposedly unreachable code."),
}
+
+ match Some(&4) {
+ None => {},
+ ref mut foo
+ if let Some(()) = {
+ (|| { let bar = foo; bar.take() })();
+ //~^ ERROR cannot move out of `foo` in pattern guard
+ None
+ } => {},
+ Some(_) => {},
+ }
}
error[E0507]: cannot move out of `foo` in pattern guard
- --> $DIR/issue-27282-mutation-in-guard.rs:6:18
+ --> $DIR/issue-27282-mutation-in-guard.rs:8:18
|
LL | (|| { let bar = foo; bar.take() })();
| ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+ --> $DIR/issue-27282-mutation-in-guard.rs:20:18
+ |
+LL | (|| { let bar = foo; bar.take() })();
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
+ | move out of `foo` occurs here
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0507`.
// It reborrows instead of moving the `ref mut` pattern borrow. This
// means that our conservative check for mutation in guards will
// reject it. But I want to make sure that we continue to reject it
-// (under NLL) even when that conservaive check goes away.
+// (under NLL) even when that conservative check goes away.
+
+#![feature(if_let_guard)]
fn main() {
let mut b = &mut true;
&mut true => { println!("You might think we should get here"); },
_ => panic!("surely we could never get here, since rustc warns it is unreachable."),
}
+
+ let mut b = &mut true;
+ match b {
+ &mut false => {},
+ ref mut r if let Some(()) = { (|| { let bar = &mut *r; **bar = false; })();
+ //~^ ERROR cannot borrow `r` as mutable, as it is immutable for the pattern guard
+ None } => { &mut *r; },
+ &mut true => {},
+ _ => {},
+ }
}
error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
- --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:12:25
+ --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:14:25
|
LL | ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
| ^^ -- mutable borrow occurs due to use of `r` in closure
|
= note: variables bound in patterns are immutable until the end of the pattern guard
-error: aborting due to previous error
+error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
+ --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:24:40
+ |
+LL | ref mut r if let Some(()) = { (|| { let bar = &mut *r; **bar = false; })();
+ | ^^ -- mutable borrow occurs due to use of `r` in closure
+ | |
+ | cannot borrow as mutable
+ |
+ = note: variables bound in patterns are immutable until the end of the pattern guard
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0596`.
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
--> $DIR/issue-51191.rs:13:9
|
-LL | fn imm(self) {
- | ---- help: consider changing this to be mutable: `mut self`
LL | (&mut self).bar();
| ^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn imm(mut self) {
+ | +++
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
--> $DIR/issue-51191.rs:22:9
// Test that we have enough false edges to avoid exposing the exact matching
// algorithm in borrow checking.
+#![feature(if_let_guard)]
+
fn guard_always_precedes_arm(y: i32) {
let mut x;
// x should always be initialized, as the only way to reach the arm is
0 | 2 if { x = 2; true } => x,
_ => 2,
};
+
+ let mut x;
+ match y {
+ 0 | 2 if let Some(()) = { x = 2; Some(()) } => x,
+ _ => 2,
+ };
}
fn guard_may_be_skipped(y: i32) {
} => 2,
_ => 3,
};
+
+ let x;
+ match y {
+ _ if let Some(()) = { x = 2; Some(()) } => 1,
+ _ if let Some(()) = {
+ x; //~ ERROR E0381
+ None
+ } => 2,
+ _ => 3,
+ };
}
fn guard_may_be_taken(y: bool) {
}
false => 3,
};
+
+ let x = String::new();
+ match y {
+ false if let Some(()) = { drop(x); Some(()) } => 1,
+ true => {
+ x; //~ ERROR use of moved value: `x`
+ 2
+ }
+ false => 3,
+ };
}
fn main() {}
error[E0381]: used binding `x` isn't initialized
- --> $DIR/match-cfg-fake-edges.rs:21:13
+ --> $DIR/match-cfg-fake-edges.rs:29:13
|
LL | let x;
| - binding declared here but left uninitialized
LL | let x = 0;
| +++
+error[E0381]: used binding `x` isn't initialized
+ --> $DIR/match-cfg-fake-edges.rs:39:13
+ |
+LL | let x;
+ | - binding declared here but left uninitialized
+LL | match y {
+LL | _ if let Some(()) = { x = 2; Some(()) } => 1,
+ | ----- binding initialized here in some conditions
+LL | _ if let Some(()) = {
+LL | x;
+ | ^ `x` used here but it isn't initialized
+ |
+help: consider assigning a value
+ |
+LL | let x = 0;
+ | +++
+
error[E0382]: use of moved value: `x`
- --> $DIR/match-cfg-fake-edges.rs:35:13
+ --> $DIR/match-cfg-fake-edges.rs:53:13
|
LL | let x = String::new();
| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
LL | false if { drop(x.clone()); true } => 1,
| ++++++++
-error: aborting due to 2 previous errors
+error[E0382]: use of moved value: `x`
+ --> $DIR/match-cfg-fake-edges.rs:63:13
+ |
+LL | let x = String::new();
+ | - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+LL | match y {
+LL | false if let Some(()) = { drop(x); Some(()) } => 1,
+ | - value moved here
+LL | true => {
+LL | x;
+ | ^ value used here after move
+ |
+help: consider cloning the value if the performance cost is acceptable
+ |
+LL | false if let Some(()) = { drop(x.clone()); Some(()) } => 1,
+ | ++++++++
+
+error: aborting due to 4 previous errors
Some errors have detailed explanations: E0381, E0382.
For more information about an error, try `rustc --explain E0381`.
+#![feature(if_let_guard)]
+
// Here is arielb1's basic example from rust-lang/rust#27282
// that AST borrowck is flummoxed by:
false } => { },
Some(s) => std::process::exit(*s),
}
+
+ match Some(&4) {
+ None => {},
+ ref mut foo if let Some(()) = {
+ (|| { let bar = foo; bar.take() })();
+ //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+ None } => { },
+ Some(s) => std::process::exit(*s),
+ }
}
// Here below is a case that needs to keep working: we only use the
fn allow_mutate_in_arm_body() {
match Some(&4) {
None => {},
- ref mut foo if foo.is_some() && false => { foo.take(); () }
+ ref mut foo if foo.is_some() => { foo.take(); () }
+ Some(s) => std::process::exit(*s),
+ }
+
+ match Some(&4) {
+ None => {},
+ ref mut foo if let Some(_) = foo => { foo.take(); () }
Some(s) => std::process::exit(*s),
}
}
fn allow_move_into_arm_body() {
match Some(&4) {
None => {},
- mut foo if foo.is_some() && false => { foo.take(); () }
+ mut foo if foo.is_some() => { foo.unwrap(); () }
+ Some(s) => std::process::exit(*s),
+ }
+
+ match Some(&4) {
+ None => {},
+ mut foo if let Some(_) = foo => { foo.unwrap(); () }
Some(s) => std::process::exit(*s),
}
}
error[E0507]: cannot move out of `foo` in pattern guard
- --> $DIR/match-guards-always-borrow.rs:8:14
+ --> $DIR/match-guards-always-borrow.rs:10:14
|
LL | (|| { let bar = foo; bar.take() })();
| ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+ --> $DIR/match-guards-always-borrow.rs:19:14
+ |
+LL | (|| { let bar = foo; bar.take() })();
+ | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+ | |
+ | move out of `foo` occurs here
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0507`.
// Test that we don't allow mutating the value being matched on in a way that
// changes which patterns it matches, until we have chosen an arm.
-fn ok_mutation_in_guard(mut q: i32) {
+#![feature(if_let_guard)]
+
+fn ok_mutation_in_if_guard(mut q: i32) {
match q {
// OK, mutation doesn't change which patterns g matches
_ if { q = 1; false } => (),
}
}
-fn ok_mutation_in_guard2(mut u: bool) {
+fn ok_mutation_in_if_let_guard(mut q: i32) {
+ match q {
+ // OK, mutation doesn't change which patterns g matches
+ _ if let Some(()) = { q = 1; None } => (),
+ _ => (),
+ }
+}
+
+fn ok_mutation_in_if_guard2(mut u: bool) {
// OK value of u is unused before modification
match u {
_ => (),
}
}
-fn ok_mutation_in_guard4(mut w: (&mut bool,)) {
+fn ok_mutation_in_if_let_guard2(mut u: bool) {
+ // OK value of u is unused before modification
+ match u {
+ _ => (),
+ _ if let Some(()) = {
+ u = true;
+ None
+ } => (),
+ x => (),
+ }
+}
+
+fn ok_mutation_in_if_guard4(mut w: (&mut bool,)) {
// OK value of u is unused before modification
match w {
_ => (),
}
}
-fn ok_indirect_mutation_in_guard(mut p: &bool) {
+fn ok_mutation_in_if_let_guard4(mut w: (&mut bool,)) {
+ // OK value of u is unused before modification
+ match w {
+ _ => (),
+ _ if let Some(()) = {
+ *w.0 = true;
+ None
+ } => (),
+ x => (),
+ }
+}
+
+fn ok_indirect_mutation_in_if_guard(mut p: &bool) {
match *p {
// OK, mutation doesn't change which patterns s matches
_ if {
}
}
-fn mutation_invalidates_pattern_in_guard(mut q: bool) {
+fn ok_indirect_mutation_in_if_let_guard(mut p: &bool) {
+ match *p {
+ // OK, mutation doesn't change which patterns s matches
+ _ if let Some(()) = {
+ p = &true;
+ None
+ } => (),
+ _ => (),
+ }
+}
+
+fn mutation_invalidates_pattern_in_if_guard(mut q: bool) {
match q {
// q doesn't match the pattern with the guard by the end of the guard.
false if {
}
}
-fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
+fn mutation_invalidates_pattern_in_if_let_guard(mut q: bool) {
+ match q {
+ // q doesn't match the pattern with the guard by the end of the guard.
+ false if let Some(()) = {
+ q = true; //~ ERROR
+ Some(())
+ } => (),
+ _ => (),
+ }
+}
+
+fn mutation_invalidates_previous_pattern_in_if_guard(mut r: bool) {
match r {
// r matches a previous pattern by the end of the guard.
true => (),
}
}
-fn match_on_borrowed_early_end(mut s: bool) {
+fn mutation_invalidates_previous_pattern_in_if_let_guard(mut r: bool) {
+ match r {
+ // r matches a previous pattern by the end of the guard.
+ true => (),
+ _ if let Some(()) = {
+ r = true; //~ ERROR
+ Some(())
+ } => (),
+ _ => (),
+ }
+}
+
+fn match_on_borrowed_early_end_if_guard(mut s: bool) {
let h = &mut s;
// OK value of s is unused before modification.
match s {
}
}
-fn bad_mutation_in_guard(mut t: bool) {
+fn match_on_borrowed_early_end_if_let_guard(mut s: bool) {
+ let h = &mut s;
+ // OK value of s is unused before modification.
+ match s {
+ _ if let Some(()) = {
+ *h = !*h;
+ None
+ } => (),
+ true => (),
+ false => (),
+ }
+}
+
+fn bad_mutation_in_if_guard(mut t: bool) {
match t {
true => (),
false if {
}
}
-fn bad_mutation_in_guard2(mut x: Option<Option<&i32>>) {
+fn bad_mutation_in_if_let_guard(mut t: bool) {
+ match t {
+ true => (),
+ false if let Some(()) = {
+ t = true; //~ ERROR
+ None
+ } => (),
+ false => (),
+ }
+}
+
+fn bad_mutation_in_if_guard2(mut x: Option<Option<&i32>>) {
// Check that nested patterns are checked.
match x {
None => (),
}
}
-fn bad_mutation_in_guard3(mut t: bool) {
+fn bad_mutation_in_if_let_guard2(mut x: Option<Option<&i32>>) {
+ // Check that nested patterns are checked.
+ match x {
+ None => (),
+ Some(None) => (),
+ _ if let Some(()) = {
+ match x {
+ Some(ref mut r) => *r = None, //~ ERROR
+ _ => return,
+ };
+ None
+ } => (),
+ Some(Some(r)) => println!("{}", r),
+ }
+}
+
+fn bad_mutation_in_if_guard3(mut t: bool) {
match t {
s if {
t = !t; //~ ERROR
}
}
-fn bad_indirect_mutation_in_guard(mut y: &bool) {
+fn bad_mutation_in_if_let_guard3(mut t: bool) {
+ match t {
+ s if let Some(()) = {
+ t = !t; //~ ERROR
+ None
+ } => (), // What value should `s` have in the arm?
+ _ => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_guard(mut y: &bool) {
match *y {
true => (),
false if {
}
}
-fn bad_indirect_mutation_in_guard2(mut z: &bool) {
+fn bad_indirect_mutation_in_if_let_guard(mut y: &bool) {
+ match *y {
+ true => (),
+ false if let Some(()) = {
+ y = &true; //~ ERROR
+ None
+ } => (),
+ false => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_guard2(mut z: &bool) {
match z {
&true => (),
&false if {
}
}
-fn bad_indirect_mutation_in_guard3(mut a: &bool) {
- // Same as bad_indirect_mutation_in_guard2, but using match ergonomics
+fn bad_indirect_mutation_in_if_let_guard2(mut z: &bool) {
+ match z {
+ &true => (),
+ &false if let Some(()) = {
+ z = &true; //~ ERROR
+ None
+ } => (),
+ &false => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_guard3(mut a: &bool) {
+ // Same as bad_indirect_mutation_in_if_guard2, but using match ergonomics
match a {
true => (),
false if {
}
}
-fn bad_indirect_mutation_in_guard4(mut b: &bool) {
+fn bad_indirect_mutation_in_if_let_guard3(mut a: &bool) {
+ // Same as bad_indirect_mutation_in_if_guard2, but using match ergonomics
+ match a {
+ true => (),
+ false if let Some(()) = {
+ a = &true; //~ ERROR
+ None
+ } => (),
+ false => (),
+ }
+}
+
+fn bad_indirect_mutation_in_if_guard4(mut b: &bool) {
match b {
&_ => (),
&_ if {
}
}
+fn bad_indirect_mutation_in_if_let_guard4(mut b: &bool) {
+ match b {
+ &_ => (),
+ &_ if let Some(()) = {
+ b = &true; //~ ERROR
+ None
+ } => (),
+ &b => (),
+ }
+}
+
fn main() {}
error[E0510]: cannot assign `q` in match guard
- --> $DIR/match-guards-partially-borrow.rs:55:13
+ --> $DIR/match-guards-partially-borrow.rs:100:13
|
LL | match q {
| - value is immutable in match guard
LL | q = true;
| ^^^^^^^^ cannot assign
+error[E0510]: cannot assign `q` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:111:13
+ |
+LL | match q {
+ | - value is immutable in match guard
+...
+LL | q = true;
+ | ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `r` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:123:13
+ |
+LL | match r {
+ | - value is immutable in match guard
+...
+LL | r = true;
+ | ^^^^^^^^ cannot assign
+
error[E0510]: cannot assign `r` in match guard
- --> $DIR/match-guards-partially-borrow.rs:67:13
+ --> $DIR/match-guards-partially-borrow.rs:135:13
|
LL | match r {
| - value is immutable in match guard
| ^^^^^^^^ cannot assign
error[E0510]: cannot assign `t` in match guard
- --> $DIR/match-guards-partially-borrow.rs:91:13
+ --> $DIR/match-guards-partially-borrow.rs:172:13
+ |
+LL | match t {
+ | - value is immutable in match guard
+...
+LL | t = true;
+ | ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `t` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:183:13
|
LL | match t {
| - value is immutable in match guard
| ^^^^^^^^ cannot assign
error[E0510]: cannot mutably borrow `x.0` in match guard
- --> $DIR/match-guards-partially-borrow.rs:105:22
+ --> $DIR/match-guards-partially-borrow.rs:197:22
+ |
+LL | match x {
+ | - value is immutable in match guard
+...
+LL | Some(ref mut r) => *r = None,
+ | ^^^^^^^^^ cannot mutably borrow
+
+error[E0510]: cannot mutably borrow `x.0` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:213:22
|
LL | match x {
| - value is immutable in match guard
| ^^^^^^^^^ cannot mutably borrow
error[E0506]: cannot assign to `t` because it is borrowed
- --> $DIR/match-guards-partially-borrow.rs:117:13
+ --> $DIR/match-guards-partially-borrow.rs:225:13
|
LL | s if {
| - borrow of `t` occurs here
LL | } => (), // What value should `s` have in the arm?
| - borrow later used here
+error[E0506]: cannot assign to `t` because it is borrowed
+ --> $DIR/match-guards-partially-borrow.rs:235:13
+ |
+LL | s if let Some(()) = {
+ | - borrow of `t` occurs here
+LL | t = !t;
+ | ^^^^^^ assignment to borrowed `t` occurs here
+LL | None
+LL | } => (), // What value should `s` have in the arm?
+ | - borrow later used here
+
+error[E0510]: cannot assign `y` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:246:13
+ |
+LL | match *y {
+ | -- value is immutable in match guard
+...
+LL | y = &true;
+ | ^^^^^^^^^ cannot assign
+
error[E0510]: cannot assign `y` in match guard
- --> $DIR/match-guards-partially-borrow.rs:128:13
+ --> $DIR/match-guards-partially-borrow.rs:257:13
|
LL | match *y {
| -- value is immutable in match guard
| ^^^^^^^^^ cannot assign
error[E0510]: cannot assign `z` in match guard
- --> $DIR/match-guards-partially-borrow.rs:139:13
+ --> $DIR/match-guards-partially-borrow.rs:268:13
+ |
+LL | match z {
+ | - value is immutable in match guard
+...
+LL | z = &true;
+ | ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `z` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:279:13
|
LL | match z {
| - value is immutable in match guard
| ^^^^^^^^^ cannot assign
error[E0510]: cannot assign `a` in match guard
- --> $DIR/match-guards-partially-borrow.rs:151:13
+ --> $DIR/match-guards-partially-borrow.rs:291:13
+ |
+LL | match a {
+ | - value is immutable in match guard
+...
+LL | a = &true;
+ | ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `a` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:303:13
|
LL | match a {
| - value is immutable in match guard
| ^^^^^^^^^ cannot assign
error[E0510]: cannot assign `b` in match guard
- --> $DIR/match-guards-partially-borrow.rs:162:13
+ --> $DIR/match-guards-partially-borrow.rs:314:13
+ |
+LL | match b {
+ | - value is immutable in match guard
+...
+LL | b = &true;
+ | ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `b` in match guard
+ --> $DIR/match-guards-partially-borrow.rs:325:13
|
LL | match b {
| - value is immutable in match guard
LL | b = &true;
| ^^^^^^^^^ cannot assign
-error: aborting due to 9 previous errors
+error: aborting due to 18 previous errors
Some errors have detailed explanations: E0506, E0510.
For more information about an error, try `rustc --explain E0506`.
error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable
--> $DIR/nested-binding-modes-mut.rs:4:5
|
-LL | let mut is_mut @ not_mut = 42;
- | ------- help: consider changing this to be mutable: `mut not_mut`
-LL | &mut is_mut;
LL | &mut not_mut;
| ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut is_mut @ mut not_mut = 42;
+ | +++
error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable
--> $DIR/nested-binding-modes-mut.rs:9:5
|
-LL | let not_mut @ mut is_mut = 42;
- | ------- help: consider changing this to be mutable: `mut not_mut`
-LL | &mut is_mut;
LL | &mut not_mut;
| ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut not_mut @ mut is_mut = 42;
+ | +++
error: aborting due to 2 previous errors
+#![feature(if_let_guard)]
+
enum VecWrapper { A(Vec<i32>) }
-fn foo(x: VecWrapper) -> usize {
+fn if_guard(x: VecWrapper) -> usize {
match x {
VecWrapper::A(v) if { drop(v); false } => 1,
//~^ ERROR cannot move out of `v` in pattern guard
}
}
+fn if_let_guard(x: VecWrapper) -> usize {
+ match x {
+ VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1,
+ //~^ ERROR cannot move out of `v` in pattern guard
+ VecWrapper::A(v) => v.len()
+ }
+}
+
fn main() {
- foo(VecWrapper::A(vec![107]));
+ if_guard(VecWrapper::A(vec![107]));
+ if_let_guard(VecWrapper::A(vec![107]));
}
error[E0507]: cannot move out of `v` in pattern guard
- --> $DIR/rfc-reject-double-move-across-arms.rs:5:36
+ --> $DIR/rfc-reject-double-move-across-arms.rs:7:36
|
LL | VecWrapper::A(v) if { drop(v); false } => 1,
| ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
-error: aborting due to previous error
+error[E0507]: cannot move out of `v` in pattern guard
+ --> $DIR/rfc-reject-double-move-across-arms.rs:15:51
+ |
+LL | VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1,
+ | ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0507`.
+#![feature(if_let_guard)]
+
struct A { a: Box<i32> }
-fn foo(n: i32) {
+fn if_guard(n: i32) {
let x = A { a: Box::new(n) };
let _y = match x {
A { a: v } if { drop(v); true } => v,
};
}
+fn if_let_guard(n: i32) {
+ let x = A { a: Box::new(n) };
+ let _y = match x {
+ A { a: v } if let Some(()) = { drop(v); Some(()) } => v,
+ //~^ ERROR cannot move out of `v` in pattern guard
+ _ => Box::new(0),
+ };
+}
+
fn main() {
- foo(107);
+ if_guard(107);
+ if_let_guard(107);
}
error[E0507]: cannot move out of `v` in pattern guard
- --> $DIR/rfc-reject-double-move-in-first-arm.rs:6:30
+ --> $DIR/rfc-reject-double-move-in-first-arm.rs:8:30
|
LL | A { a: v } if { drop(v); true } => v,
| ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
-error: aborting due to previous error
+error[E0507]: cannot move out of `v` in pattern guard
+ --> $DIR/rfc-reject-double-move-in-first-arm.rs:17:45
+ |
+LL | A { a: v } if let Some(()) = { drop(v); Some(()) } => v,
+ | ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0507`.
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:53:24
|
-LL | fn deref_mut_field1(x: Own<Point>) {
- | - help: consider changing this to be mutable: `mut x`
LL | let __isize = &mut x.y;
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn deref_mut_field1(mut x: Own<Point>) {
+ | +++
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:65:10
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:88:5
|
-LL | fn assign_field1<'a>(x: Own<Point>) {
- | - help: consider changing this to be mutable: `mut x`
LL | x.y = 3;
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn assign_field1<'a>(mut x: Own<Point>) {
+ | +++
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:92:5
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:109:5
|
-LL | fn deref_mut_method1(x: Own<Point>) {
- | - help: consider changing this to be mutable: `mut x`
LL | x.set(0, 0);
| ^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn deref_mut_method1(mut x: Own<Point>) {
+ | +++
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:121:5
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:129:6
|
-LL | fn assign_method1<'a>(x: Own<Point>) {
- | - help: consider changing this to be mutable: `mut x`
LL | *x.y_mut() = 3;
| ^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn assign_method1<'a>(mut x: Own<Point>) {
+ | +++
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:133:6
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:29:25
|
-LL | fn deref_mut1(x: Own<isize>) {
- | - help: consider changing this to be mutable: `mut x`
LL | let __isize = &mut *x;
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn deref_mut1(mut x: Own<isize>) {
+ | +++
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:41:11
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:49:6
|
-LL | fn assign1<'a>(x: Own<isize>) {
- | - help: consider changing this to be mutable: `mut x`
LL | *x = 3;
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn assign1<'a>(mut x: Own<isize>) {
+ | +++
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:53:6
error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable
--> $DIR/borrowck-object-mutability.rs:18:5
|
-LL | fn owned_receiver(x: Box<dyn Foo>) {
- | - help: consider changing this to be mutable: `mut x`
-LL | x.borrowed();
LL | x.borrowed_mut();
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | fn owned_receiver(mut x: Box<dyn Foo>) {
+ | +++
error: aborting due to 2 previous errors
kind: Scope {
region_scope: Node(2),
lint_level: Explicit(
- HirId {
- owner: OwnerId {
- def_id: DefId(0:3 ~ thir_tree[8f1d]::main),
- },
- local_id: 2,
- },
+ HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2),
),
value: e0,
},
error[E0596]: cannot borrow `tick2` as mutable, as it is not declared as mutable
--> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:19:5
|
-LL | let tick2 = || {
- | ----- help: consider changing this to be mutable: `mut tick2`
LL | tick1();
| ----- calling `tick2` requires mutable binding due to mutable borrow of `tick1`
...
LL | tick2();
| ^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut tick2 = || {
+ | +++
error: aborting due to 2 previous errors
--> $DIR/unboxed-closures-infer-fnmut-missing-mut.rs:7:5
|
LL | let tick = || counter += 1;
- | ---- ------- calling `tick` requires mutable binding due to mutable borrow of `counter`
- | |
- | help: consider changing this to be mutable: `mut tick`
+ | ------- calling `tick` requires mutable binding due to mutable borrow of `counter`
LL | tick();
| ^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut tick = || counter += 1;
+ | +++
error: aborting due to previous error
--> $DIR/unboxed-closures-infer-fnmut-move-missing-mut.rs:7:5
|
LL | let tick = move || counter += 1;
- | ---- ------- calling `tick` requires mutable binding due to possible mutation of `counter`
- | |
- | help: consider changing this to be mutable: `mut tick`
+ | ------- calling `tick` requires mutable binding due to possible mutation of `counter`
LL | tick();
| ^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut tick = move || counter += 1;
+ | +++
error: aborting due to previous error
--- /dev/null
+#[macro_export]
+macro_rules! foo {
+ () => {
+ unsafe fn __unsf() {}
+ unsafe fn __foo() {
+ __unsf();
+ }
+ };
+}
--- /dev/null
+// Regression test for #106126.
+// check-pass
+// aux-build:issue-106126.rs
+
+#![deny(unsafe_op_in_unsafe_fn)]
+
+#[macro_use]
+extern crate issue_106126;
+
+foo!();
+
+fn main() {}
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
--> $DIR/writing-to-immutable-vec.rs:3:5
|
-LL | let v: Vec<isize> = vec![1, 2, 3];
- | - help: consider changing this to be mutable: `mut v`
LL | v[1] = 4;
| ^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut v: Vec<isize> = vec![1, 2, 3];
+ | +++
error: aborting due to previous error
Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs,
GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, Module, OpaqueTy, Path,
Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding,
- TypeBindingKind, Typedef, Union, Variant, WherePredicate,
+ TypeBindingKind, Typedef, Union, Variant, VariantKind, WherePredicate,
};
use crate::{item_kind::Kind, Error, ErrorKind};
}
fn check_variant(&mut self, x: &'a Variant, id: &'a Id) {
- match x {
- Variant::Plain(discr) => {
- if let Some(discr) = discr {
- if let (Err(_), Err(_)) =
- (discr.value.parse::<i128>(), discr.value.parse::<u128>())
- {
- self.fail(
- id,
- ErrorKind::Custom(format!(
- "Failed to parse discriminant value `{}`",
- discr.value
- )),
- );
- }
- }
+ let Variant { kind, discriminant } = x;
+
+ if let Some(discr) = discriminant {
+ if let (Err(_), Err(_)) = (discr.value.parse::<i128>(), discr.value.parse::<u128>()) {
+ self.fail(
+ id,
+ ErrorKind::Custom(format!(
+ "Failed to parse discriminant value `{}`",
+ discr.value
+ )),
+ );
}
- Variant::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
- Variant::Struct { fields, fields_stripped: _ } => {
+ }
+
+ match kind {
+ VariantKind::Plain => {}
+ VariantKind::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
+ VariantKind::Struct { fields, fields_stripped: _ } => {
fields.iter().for_each(|f| self.add_field_id(f))
}
}
extern crate rustc_span;
extern crate rustc_target;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
mod borrow_tracker;
mod clock;
mod concurrency;
extern crate rustc_session;
extern crate rustc_span;
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
lazy_static = "1"
walkdir = "2"
ignore = "0.4.18"
+semver = "1.0.14"
termcolor = "1.1.3"
[[bin]]
pub mod unit_tests;
pub mod unstable_book;
pub mod walk;
+pub mod x_version;
let handle = s.spawn(|| {
let mut flag = false;
- $p::check($($args),* , &mut flag);
+ $p::check($($args, )* &mut flag);
if (flag) {
bad.store(true, Ordering::Relaxed);
}
check!(alphabetical, &compiler_path);
check!(alphabetical, &library_path);
+ check!(x_version, &root_path, &cargo);
+
let collected = {
drain_handles(&mut handles);
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
const ROOT_ENTRY_LIMIT: usize = 939;
-const ISSUES_ENTRY_LIMIT: usize = 2020;
+const ISSUES_ENTRY_LIMIT: usize = 2050;
fn check_entries(path: &Path, bad: &mut bool) {
for dir in Walk::new(&path.join("test/ui")) {
--- /dev/null
+use semver::Version;
+use std::io::ErrorKind;
+use std::path::Path;
+use std::process::{Command, Stdio};
+
+pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
+ let result = Command::new("x").arg("--wrapper-version").stdout(Stdio::piped()).spawn();
+ // This runs the command inside a temporary directory.
+ // This allows us to compare output of result to see if `--wrapper-version` is not a recognized argument to x.
+ let temp_result = Command::new("x")
+ .arg("--wrapper-version")
+ .current_dir(std::env::temp_dir())
+ .stdout(Stdio::piped())
+ .spawn();
+
+ let (child, temp_child) = match (result, temp_result) {
+ (Ok(child), Ok(temp_child)) => (child, temp_child),
+ (Err(e), _) | (_, Err(e)) => match e.kind() {
+ ErrorKind::NotFound => return,
+ _ => return tidy_error!(bad, "failed to run `x`: {}", e),
+ },
+ };
+
+ let output = child.wait_with_output().unwrap();
+ let temp_output = temp_child.wait_with_output().unwrap();
+
+ if output != temp_output {
+ return tidy_error!(
+ bad,
+ "Current version of x does not support the `--wrapper-version` argument\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+ );
+ }
+
+ if output.status.success() {
+ let version = String::from_utf8_lossy(&output.stdout);
+ let version = Version::parse(version.trim_end()).unwrap();
+
+ if let Some(expected) = get_x_wrapper_version(root, cargo) {
+ if version < expected {
+ return tidy_error!(
+ bad,
+ "Current version of x is {version}, but the latest version is {expected}\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+ );
+ }
+ } else {
+ return tidy_error!(
+ bad,
+ "Unable to parse the latest version of `x` at `src/tools/x/Cargo.toml`"
+ );
+ }
+ } else {
+ return tidy_error!(bad, "failed to check version of `x`: {}", output.status);
+ }
+}
+
+// Parse latest version out of `x` Cargo.toml
+fn get_x_wrapper_version(root: &Path, cargo: &Path) -> Option<Version> {
+ let mut cmd = cargo_metadata::MetadataCommand::new();
+ cmd.cargo_path(cargo)
+ .manifest_path(root.join("src/tools/x/Cargo.toml"))
+ .no_deps()
+ .features(cargo_metadata::CargoOpt::AllFeatures);
+ let mut metadata = t!(cmd.exec());
+ metadata.packages.pop().map(|x| x.version)
+}
}
fn main() {
+ match env::args().skip(1).next().as_deref() {
+ Some("--wrapper-version") => {
+ let version = env!("CARGO_PKG_VERSION");
+ println!("{}", version);
+ return;
+ }
+ _ => {}
+ }
let current = match env::current_dir() {
Ok(dir) => dir,
Err(err) => {