Auto merge of #135465 - jhpratt:rollup-7p93bct, r=jhpratt
Rollup of 10 pull requests Successful merges: - #134498 (Fix cycle error only occurring with -Zdump-mir) - #134977 (Detect `mut arg: &Ty` meant to be `arg: &mut Ty` and provide structured suggestion) - #135390 (Re-added regression test for #122638) - #135393 (uefi: helpers: Introduce OwnedDevicePath) - #135440 (rm unnecessary `OpaqueTypeDecl` wrapper) - #135441 (Make sure to mark `IMPL_TRAIT_REDUNDANT_CAPTURES` as `Allow` in edition 2024) - #135444 (Update books) - #135450 (Fix emscripten-wasm-eh with unwind=abort) - #135452 (bootstrap: fix outdated feature name in comment) - #135454 (llvm: Allow sized-word rather than ymmword in tests) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
35c2908177
34 changed files with 492 additions and 83 deletions
|
@ -25,8 +25,8 @@ pub(super) fn take_opaques_and_register_member_constraints<'tcx>(
|
||||||
let opaque_types = infcx
|
let opaque_types = infcx
|
||||||
.take_opaque_types()
|
.take_opaque_types()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(opaque_type_key, decl)| {
|
.map(|(opaque_type_key, hidden_type)| {
|
||||||
let hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
|
let hidden_type = infcx.resolve_vars_if_possible(hidden_type);
|
||||||
register_member_constraints(
|
register_member_constraints(
|
||||||
typeck,
|
typeck,
|
||||||
&mut member_constraints,
|
&mut member_constraints,
|
||||||
|
|
|
@ -2451,10 +2451,10 @@ fn add_order_independent_options(
|
||||||
}
|
}
|
||||||
|
|
||||||
if sess.target.os == "emscripten" {
|
if sess.target.os == "emscripten" {
|
||||||
cmd.cc_arg(if sess.panic_strategy() == PanicStrategy::Abort {
|
cmd.cc_arg(if sess.opts.unstable_opts.emscripten_wasm_eh {
|
||||||
"-sDISABLE_EXCEPTION_CATCHING=1"
|
|
||||||
} else if sess.opts.unstable_opts.emscripten_wasm_eh {
|
|
||||||
"-fwasm-exceptions"
|
"-fwasm-exceptions"
|
||||||
|
} else if sess.panic_strategy() == PanicStrategy::Abort {
|
||||||
|
"-sDISABLE_EXCEPTION_CATCHING=1"
|
||||||
} else {
|
} else {
|
||||||
"-sDISABLE_EXCEPTION_CATCHING=0"
|
"-sDISABLE_EXCEPTION_CATCHING=0"
|
||||||
});
|
});
|
||||||
|
|
|
@ -436,9 +436,9 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||||
} else {
|
} else {
|
||||||
// Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
|
// Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
|
||||||
for (mut key, mut ty) in infcx.take_opaque_types() {
|
for (mut key, mut ty) in infcx.take_opaque_types() {
|
||||||
ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty);
|
ty.ty = infcx.resolve_vars_if_possible(ty.ty);
|
||||||
key = infcx.resolve_vars_if_possible(key);
|
key = infcx.resolve_vars_if_possible(key);
|
||||||
sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?;
|
sanity_check_found_hidden_type(tcx, key, ty)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1873,7 +1873,7 @@ pub(super) fn check_coroutine_obligations(
|
||||||
// Check that any hidden types found when checking these stalled coroutine obligations
|
// Check that any hidden types found when checking these stalled coroutine obligations
|
||||||
// are valid.
|
// are valid.
|
||||||
for (key, ty) in infcx.take_opaque_types() {
|
for (key, ty) in infcx.take_opaque_types() {
|
||||||
let hidden_type = infcx.resolve_vars_if_possible(ty.hidden_type);
|
let hidden_type = infcx.resolve_vars_if_possible(ty);
|
||||||
let key = infcx.resolve_vars_if_possible(key);
|
let key = infcx.resolve_vars_if_possible(key);
|
||||||
sanity_check_found_hidden_type(tcx, key, hidden_type)?;
|
sanity_check_found_hidden_type(tcx, key, hidden_type)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
self.annotate_expected_due_to_let_ty(err, expr, error);
|
self.annotate_expected_due_to_let_ty(err, expr, error);
|
||||||
self.annotate_loop_expected_due_to_inference(err, expr, error);
|
self.annotate_loop_expected_due_to_inference(err, expr, error);
|
||||||
|
if self.annotate_mut_binding_to_immutable_binding(err, expr, error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME(#73154): For now, we do leak check when coercing function
|
// FIXME(#73154): For now, we do leak check when coercing function
|
||||||
// pointers in typeck, instead of only during borrowck. This can lead
|
// pointers in typeck, instead of only during borrowck. This can lead
|
||||||
|
@ -795,6 +798,98 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Detect the following case
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// fn change_object(mut a: &Ty) {
|
||||||
|
/// let a = Ty::new();
|
||||||
|
/// b = a;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// where the user likely meant to modify the value behind there reference, use `a` as an out
|
||||||
|
/// parameter, instead of mutating the local binding. When encountering this we suggest:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// fn change_object(a: &'_ mut Ty) {
|
||||||
|
/// let a = Ty::new();
|
||||||
|
/// *b = a;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn annotate_mut_binding_to_immutable_binding(
|
||||||
|
&self,
|
||||||
|
err: &mut Diag<'_>,
|
||||||
|
expr: &hir::Expr<'_>,
|
||||||
|
error: Option<TypeError<'tcx>>,
|
||||||
|
) -> bool {
|
||||||
|
if let Some(TypeError::Sorts(ExpectedFound { expected, found })) = error
|
||||||
|
&& let ty::Ref(_, inner, hir::Mutability::Not) = expected.kind()
|
||||||
|
|
||||||
|
// The difference between the expected and found values is one level of borrowing.
|
||||||
|
&& self.can_eq(self.param_env, *inner, found)
|
||||||
|
|
||||||
|
// We have an `ident = expr;` assignment.
|
||||||
|
&& let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) =
|
||||||
|
self.tcx.parent_hir_node(expr.hir_id)
|
||||||
|
&& rhs.hir_id == expr.hir_id
|
||||||
|
|
||||||
|
// We are assigning to some binding.
|
||||||
|
&& let hir::ExprKind::Path(hir::QPath::Resolved(
|
||||||
|
None,
|
||||||
|
hir::Path { res: hir::def::Res::Local(hir_id), .. },
|
||||||
|
)) = lhs.kind
|
||||||
|
&& let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id)
|
||||||
|
|
||||||
|
// The pattern we have is an fn argument.
|
||||||
|
&& let hir::Node::Param(hir::Param { ty_span, .. }) =
|
||||||
|
self.tcx.parent_hir_node(pat.hir_id)
|
||||||
|
&& let item = self.tcx.hir().get_parent_item(pat.hir_id)
|
||||||
|
&& let item = self.tcx.hir_owner_node(item)
|
||||||
|
&& let Some(fn_decl) = item.fn_decl()
|
||||||
|
|
||||||
|
// We have a mutable binding in the argument.
|
||||||
|
&& let hir::PatKind::Binding(hir::BindingMode::MUT, _hir_id, ident, _) = pat.kind
|
||||||
|
|
||||||
|
// Look for the type corresponding to the argument pattern we have in the argument list.
|
||||||
|
&& let Some(ty_sugg) = fn_decl
|
||||||
|
.inputs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|ty| {
|
||||||
|
if ty.span == *ty_span
|
||||||
|
&& let hir::TyKind::Ref(lt, x) = ty.kind
|
||||||
|
{
|
||||||
|
// `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
|
||||||
|
Some((
|
||||||
|
x.ty.span.shrink_to_lo(),
|
||||||
|
format!(
|
||||||
|
"{}mut ",
|
||||||
|
if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " }
|
||||||
|
),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
{
|
||||||
|
let sugg = vec![
|
||||||
|
ty_sugg,
|
||||||
|
(pat.span.until(ident.span), String::new()),
|
||||||
|
(lhs.span.shrink_to_lo(), "*".to_string()),
|
||||||
|
];
|
||||||
|
// We suggest changing the argument from `mut ident: &Ty` to `ident: &'_ mut Ty` and the
|
||||||
|
// assignment from `ident = val;` to `*ident = val;`.
|
||||||
|
err.multipart_suggestion_verbose(
|
||||||
|
"you might have meant to mutate the pointed at value being passed in, instead of \
|
||||||
|
changing the reference in the local binding",
|
||||||
|
sugg,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn annotate_alternative_method_deref(
|
fn annotate_alternative_method_deref(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
|
|
|
@ -562,9 +562,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||||
// types or by using this function at the end of writeback and running it as a
|
// types or by using this function at the end of writeback and running it as a
|
||||||
// fixpoint.
|
// fixpoint.
|
||||||
let opaque_types = self.fcx.infcx.clone_opaque_types();
|
let opaque_types = self.fcx.infcx.clone_opaque_types();
|
||||||
for (opaque_type_key, decl) in opaque_types {
|
for (opaque_type_key, hidden_type) in opaque_types {
|
||||||
let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
|
let hidden_type = self.resolve(hidden_type, &hidden_type.span);
|
||||||
let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span);
|
let opaque_type_key = self.resolve(opaque_type_key, &hidden_type.span);
|
||||||
|
|
||||||
if !self.fcx.next_trait_solver() {
|
if !self.fcx.next_trait_solver() {
|
||||||
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
|
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
|
||||||
|
|
|
@ -155,12 +155,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
.opaque_type_storage
|
.opaque_type_storage
|
||||||
.opaque_types
|
.opaque_types
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, v)| (*k, v.hidden_type.ty))
|
.map(|(k, v)| (*k, v.ty))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
|
fn take_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
|
||||||
self.take_opaque_types().into_iter().map(|(k, v)| (k, v.hidden_type.ty)).collect()
|
self.take_opaque_types().into_iter().map(|(k, v)| (k, v.ty)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given the (canonicalized) result to a canonical query,
|
/// Given the (canonicalized) result to a canonical query,
|
||||||
|
|
|
@ -234,7 +234,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
|
||||||
pub fn iter_opaque_types(
|
pub fn iter_opaque_types(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<Item = (ty::OpaqueTypeKey<'tcx>, ty::OpaqueHiddenType<'tcx>)> + '_ {
|
) -> impl Iterator<Item = (ty::OpaqueTypeKey<'tcx>, ty::OpaqueHiddenType<'tcx>)> + '_ {
|
||||||
self.opaque_type_storage.opaque_types.iter().map(|(&k, v)| (k, v.hidden_type))
|
self.opaque_type_storage.opaque_types.iter().map(|(&k, &v)| (k, v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,20 +19,9 @@ use crate::traits::{self, Obligation, PredicateObligations};
|
||||||
|
|
||||||
mod table;
|
mod table;
|
||||||
|
|
||||||
pub(crate) type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
|
pub(crate) type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>;
|
||||||
pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable};
|
pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable};
|
||||||
|
|
||||||
/// Information about the opaque types whose values we
|
|
||||||
/// are inferring in this function (these are the `impl Trait` that
|
|
||||||
/// appear in the return type).
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct OpaqueTypeDecl<'tcx> {
|
|
||||||
/// The hidden types that have been inferred for this opaque type.
|
|
||||||
/// There can be multiple, but they are all `lub`ed together at the end
|
|
||||||
/// to obtain the canonical hidden type.
|
|
||||||
pub hidden_type: OpaqueHiddenType<'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> InferCtxt<'tcx> {
|
impl<'tcx> InferCtxt<'tcx> {
|
||||||
/// This is a backwards compatibility hack to prevent breaking changes from
|
/// This is a backwards compatibility hack to prevent breaking changes from
|
||||||
/// lazy TAIT around RPIT handling.
|
/// lazy TAIT around RPIT handling.
|
||||||
|
|
|
@ -3,7 +3,7 @@ use rustc_middle::bug;
|
||||||
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty};
|
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use super::{OpaqueTypeDecl, OpaqueTypeMap};
|
use super::OpaqueTypeMap;
|
||||||
use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog};
|
use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog};
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
|
@ -11,15 +11,19 @@ pub(crate) struct OpaqueTypeStorage<'tcx> {
|
||||||
/// Opaque types found in explicit return types and their
|
/// Opaque types found in explicit return types and their
|
||||||
/// associated fresh inference variable. Writeback resolves these
|
/// associated fresh inference variable. Writeback resolves these
|
||||||
/// variables to get the concrete type, which can be used to
|
/// variables to get the concrete type, which can be used to
|
||||||
/// 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
|
/// 'de-opaque' OpaqueHiddenType, after typeck is done with all functions.
|
||||||
pub opaque_types: OpaqueTypeMap<'tcx>,
|
pub opaque_types: OpaqueTypeMap<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> OpaqueTypeStorage<'tcx> {
|
impl<'tcx> OpaqueTypeStorage<'tcx> {
|
||||||
#[instrument(level = "debug")]
|
#[instrument(level = "debug")]
|
||||||
pub(crate) fn remove(&mut self, key: OpaqueTypeKey<'tcx>, idx: Option<OpaqueHiddenType<'tcx>>) {
|
pub(crate) fn remove(
|
||||||
if let Some(idx) = idx {
|
&mut self,
|
||||||
self.opaque_types.get_mut(&key).unwrap().hidden_type = idx;
|
key: OpaqueTypeKey<'tcx>,
|
||||||
|
prev: Option<OpaqueHiddenType<'tcx>>,
|
||||||
|
) {
|
||||||
|
if let Some(prev) = prev {
|
||||||
|
*self.opaque_types.get_mut(&key).unwrap() = prev;
|
||||||
} else {
|
} else {
|
||||||
// FIXME(#120456) - is `swap_remove` correct?
|
// FIXME(#120456) - is `swap_remove` correct?
|
||||||
match self.opaque_types.swap_remove(&key) {
|
match self.opaque_types.swap_remove(&key) {
|
||||||
|
@ -59,13 +63,12 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> {
|
||||||
key: OpaqueTypeKey<'tcx>,
|
key: OpaqueTypeKey<'tcx>,
|
||||||
hidden_type: OpaqueHiddenType<'tcx>,
|
hidden_type: OpaqueHiddenType<'tcx>,
|
||||||
) -> Option<Ty<'tcx>> {
|
) -> Option<Ty<'tcx>> {
|
||||||
if let Some(decl) = self.storage.opaque_types.get_mut(&key) {
|
if let Some(entry) = self.storage.opaque_types.get_mut(&key) {
|
||||||
let prev = std::mem::replace(&mut decl.hidden_type, hidden_type);
|
let prev = std::mem::replace(entry, hidden_type);
|
||||||
self.undo_log.push(UndoLog::OpaqueTypes(key, Some(prev)));
|
self.undo_log.push(UndoLog::OpaqueTypes(key, Some(prev)));
|
||||||
return Some(prev.ty);
|
return Some(prev.ty);
|
||||||
}
|
}
|
||||||
let decl = OpaqueTypeDecl { hidden_type };
|
self.storage.opaque_types.insert(key, hidden_type);
|
||||||
self.storage.opaque_types.insert(key, decl);
|
|
||||||
self.undo_log.push(UndoLog::OpaqueTypes(key, None));
|
self.undo_log.push(UndoLog::OpaqueTypes(key, None));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ declare_lint! {
|
||||||
/// To fix this, remove the `use<'a>`, since the lifetime is already captured
|
/// To fix this, remove the `use<'a>`, since the lifetime is already captured
|
||||||
/// since it is in scope.
|
/// since it is in scope.
|
||||||
pub IMPL_TRAIT_REDUNDANT_CAPTURES,
|
pub IMPL_TRAIT_REDUNDANT_CAPTURES,
|
||||||
Warn,
|
Allow,
|
||||||
"redundant precise-capturing `use<...>` syntax on an `impl Trait`",
|
"redundant precise-capturing `use<...>` syntax on an `impl Trait`",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1555,16 +1555,22 @@ pub fn write_allocations<'tcx>(
|
||||||
write!(w, " (vtable: impl {dyn_ty} for {ty})")?
|
write!(w, " (vtable: impl {dyn_ty} for {ty})")?
|
||||||
}
|
}
|
||||||
Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
|
Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
|
||||||
match tcx.eval_static_initializer(did) {
|
write!(w, " (static: {}", tcx.def_path_str(did))?;
|
||||||
Ok(alloc) => {
|
if body.phase <= MirPhase::Runtime(RuntimePhase::PostCleanup)
|
||||||
write!(w, " (static: {}, ", tcx.def_path_str(did))?;
|
&& tcx.hir().body_const_context(body.source.def_id()).is_some()
|
||||||
write_allocation_track_relocs(w, alloc)?;
|
{
|
||||||
|
// Statics may be cyclic and evaluating them too early
|
||||||
|
// in the MIR pipeline may cause cycle errors even though
|
||||||
|
// normal compilation is fine.
|
||||||
|
write!(w, ")")?;
|
||||||
|
} else {
|
||||||
|
match tcx.eval_static_initializer(did) {
|
||||||
|
Ok(alloc) => {
|
||||||
|
write!(w, ", ")?;
|
||||||
|
write_allocation_track_relocs(w, alloc)?;
|
||||||
|
}
|
||||||
|
Err(_) => write!(w, ", error during initializer evaluation)")?,
|
||||||
}
|
}
|
||||||
Err(_) => write!(
|
|
||||||
w,
|
|
||||||
" (static: {}, error during initializer evaluation)",
|
|
||||||
tcx.def_path_str(did)
|
|
||||||
)?,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(GlobalAlloc::Static(did)) => {
|
Some(GlobalAlloc::Static(did)) => {
|
||||||
|
|
|
@ -799,6 +799,9 @@ passes_unused_assign = value assigned to `{$name}` is never read
|
||||||
passes_unused_assign_passed = value passed to `{$name}` is never read
|
passes_unused_assign_passed = value passed to `{$name}` is never read
|
||||||
.help = maybe it is overwritten before being read?
|
.help = maybe it is overwritten before being read?
|
||||||
|
|
||||||
|
passes_unused_assign_suggestion =
|
||||||
|
you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding
|
||||||
|
|
||||||
passes_unused_capture_maybe_capture_ref = value captured by `{$name}` is never read
|
passes_unused_capture_maybe_capture_ref = value captured by `{$name}` is never read
|
||||||
.help = did you mean to capture by reference instead?
|
.help = did you mean to capture by reference instead?
|
||||||
|
|
||||||
|
|
|
@ -1787,9 +1787,26 @@ pub(crate) struct IneffectiveUnstableImpl;
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(passes_unused_assign)]
|
#[diag(passes_unused_assign)]
|
||||||
#[help]
|
|
||||||
pub(crate) struct UnusedAssign {
|
pub(crate) struct UnusedAssign {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub suggestion: Option<UnusedAssignSuggestion>,
|
||||||
|
#[help]
|
||||||
|
pub help: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion(passes_unused_assign_suggestion, applicability = "maybe-incorrect")]
|
||||||
|
pub(crate) struct UnusedAssignSuggestion {
|
||||||
|
pub pre: &'static str,
|
||||||
|
#[suggestion_part(code = "{pre}mut ")]
|
||||||
|
pub ty_span: Span,
|
||||||
|
#[suggestion_part(code = "")]
|
||||||
|
pub ty_ref_span: Span,
|
||||||
|
#[suggestion_part(code = "*")]
|
||||||
|
pub ident_span: Span,
|
||||||
|
#[suggestion_part(code = "")]
|
||||||
|
pub expr_ref_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
|
|
|
@ -1360,7 +1360,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
|
||||||
fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
|
fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
|
||||||
self.check_unused_vars_in_pat(local.pat, None, None, |spans, hir_id, ln, var| {
|
self.check_unused_vars_in_pat(local.pat, None, None, |spans, hir_id, ln, var| {
|
||||||
if local.init.is_some() {
|
if local.init.is_some() {
|
||||||
self.warn_about_dead_assign(spans, hir_id, ln, var);
|
self.warn_about_dead_assign(spans, hir_id, ln, var, None);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1460,7 +1460,8 @@ impl<'tcx> Liveness<'_, 'tcx> {
|
||||||
// as being used.
|
// as being used.
|
||||||
let ln = self.live_node(expr.hir_id, expr.span);
|
let ln = self.live_node(expr.hir_id, expr.span);
|
||||||
let var = self.variable(var_hid, expr.span);
|
let var = self.variable(var_hid, expr.span);
|
||||||
self.warn_about_dead_assign(vec![expr.span], expr.hir_id, ln, var);
|
let sugg = self.annotate_mut_binding_to_immutable_binding(var_hid, expr);
|
||||||
|
self.warn_about_dead_assign(vec![expr.span], expr.hir_id, ln, var, sugg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -1585,6 +1586,70 @@ impl<'tcx> Liveness<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Detect the following case
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// fn change_object(mut a: &Ty) {
|
||||||
|
/// let a = Ty::new();
|
||||||
|
/// b = &a;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// where the user likely meant to modify the value behind there reference, use `a` as an out
|
||||||
|
/// parameter, instead of mutating the local binding. When encountering this we suggest:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// fn change_object(a: &'_ mut Ty) {
|
||||||
|
/// let a = Ty::new();
|
||||||
|
/// *b = a;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn annotate_mut_binding_to_immutable_binding(
|
||||||
|
&self,
|
||||||
|
var_hid: HirId,
|
||||||
|
expr: &'tcx Expr<'tcx>,
|
||||||
|
) -> Option<errors::UnusedAssignSuggestion> {
|
||||||
|
if let hir::Node::Expr(parent) = self.ir.tcx.parent_hir_node(expr.hir_id)
|
||||||
|
&& let hir::ExprKind::Assign(_, rhs, _) = parent.kind
|
||||||
|
&& let hir::ExprKind::AddrOf(borrow_kind, _mut, inner) = rhs.kind
|
||||||
|
&& let hir::BorrowKind::Ref = borrow_kind
|
||||||
|
&& let hir::Node::Pat(pat) = self.ir.tcx.hir_node(var_hid)
|
||||||
|
&& let hir::Node::Param(hir::Param { ty_span, .. }) =
|
||||||
|
self.ir.tcx.parent_hir_node(pat.hir_id)
|
||||||
|
&& let item_id = self.ir.tcx.hir().get_parent_item(pat.hir_id)
|
||||||
|
&& let item = self.ir.tcx.hir_owner_node(item_id)
|
||||||
|
&& let Some(fn_decl) = item.fn_decl()
|
||||||
|
&& let hir::PatKind::Binding(hir::BindingMode::MUT, _hir_id, ident, _) = pat.kind
|
||||||
|
&& let Some((ty_span, pre)) = fn_decl
|
||||||
|
.inputs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|ty| {
|
||||||
|
if ty.span == *ty_span
|
||||||
|
&& let hir::TyKind::Ref(lt, mut_ty) = ty.kind
|
||||||
|
{
|
||||||
|
// `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
|
||||||
|
Some((
|
||||||
|
mut_ty.ty.span.shrink_to_lo(),
|
||||||
|
if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " },
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
{
|
||||||
|
Some(errors::UnusedAssignSuggestion {
|
||||||
|
ty_span,
|
||||||
|
pre,
|
||||||
|
ty_ref_span: pat.span.until(ident.span),
|
||||||
|
ident_span: expr.span.shrink_to_lo(),
|
||||||
|
expr_ref_span: rhs.span.until(inner.span),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "INFO")]
|
#[instrument(skip(self), level = "INFO")]
|
||||||
fn report_unused(
|
fn report_unused(
|
||||||
&self,
|
&self,
|
||||||
|
@ -1738,15 +1803,23 @@ impl<'tcx> Liveness<'_, 'tcx> {
|
||||||
suggs
|
suggs
|
||||||
}
|
}
|
||||||
|
|
||||||
fn warn_about_dead_assign(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) {
|
fn warn_about_dead_assign(
|
||||||
|
&self,
|
||||||
|
spans: Vec<Span>,
|
||||||
|
hir_id: HirId,
|
||||||
|
ln: LiveNode,
|
||||||
|
var: Variable,
|
||||||
|
suggestion: Option<errors::UnusedAssignSuggestion>,
|
||||||
|
) {
|
||||||
if !self.live_on_exit(ln, var)
|
if !self.live_on_exit(ln, var)
|
||||||
&& let Some(name) = self.should_warn(var)
|
&& let Some(name) = self.should_warn(var)
|
||||||
{
|
{
|
||||||
|
let help = suggestion.is_none();
|
||||||
self.ir.tcx.emit_node_span_lint(
|
self.ir.tcx.emit_node_span_lint(
|
||||||
lint::builtin::UNUSED_ASSIGNMENTS,
|
lint::builtin::UNUSED_ASSIGNMENTS,
|
||||||
hir_id,
|
hir_id,
|
||||||
spans,
|
spans,
|
||||||
errors::UnusedAssign { name },
|
errors::UnusedAssign { name, suggestion, help },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,14 +222,14 @@ pub(crate) fn runtime_services() -> Option<NonNull<r_efi::efi::RuntimeServices>>
|
||||||
NonNull::new(runtime_services)
|
NonNull::new(runtime_services)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct DevicePath(NonNull<r_efi::protocols::device_path::Protocol>);
|
pub(crate) struct OwnedDevicePath(NonNull<r_efi::protocols::device_path::Protocol>);
|
||||||
|
|
||||||
impl DevicePath {
|
impl OwnedDevicePath {
|
||||||
pub(crate) fn from_text(p: &OsStr) -> io::Result<Self> {
|
pub(crate) fn from_text(p: &OsStr) -> io::Result<Self> {
|
||||||
fn inner(
|
fn inner(
|
||||||
p: &OsStr,
|
p: &OsStr,
|
||||||
protocol: NonNull<r_efi::protocols::device_path_from_text::Protocol>,
|
protocol: NonNull<r_efi::protocols::device_path_from_text::Protocol>,
|
||||||
) -> io::Result<DevicePath> {
|
) -> io::Result<OwnedDevicePath> {
|
||||||
let path_vec = p.encode_wide().chain(Some(0)).collect::<Vec<u16>>();
|
let path_vec = p.encode_wide().chain(Some(0)).collect::<Vec<u16>>();
|
||||||
if path_vec[..path_vec.len() - 1].contains(&0) {
|
if path_vec[..path_vec.len() - 1].contains(&0) {
|
||||||
return Err(const_error!(
|
return Err(const_error!(
|
||||||
|
@ -242,7 +242,7 @@ impl DevicePath {
|
||||||
unsafe { ((*protocol.as_ptr()).convert_text_to_device_path)(path_vec.as_ptr()) };
|
unsafe { ((*protocol.as_ptr()).convert_text_to_device_path)(path_vec.as_ptr()) };
|
||||||
|
|
||||||
NonNull::new(path)
|
NonNull::new(path)
|
||||||
.map(DevicePath)
|
.map(OwnedDevicePath)
|
||||||
.ok_or_else(|| const_error!(io::ErrorKind::InvalidFilename, "Invalid Device Path"))
|
.ok_or_else(|| const_error!(io::ErrorKind::InvalidFilename, "Invalid Device Path"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,12 +275,12 @@ impl DevicePath {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol {
|
pub(crate) const fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol {
|
||||||
self.0.as_ptr()
|
self.0.as_ptr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for DevicePath {
|
impl Drop for OwnedDevicePath {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(bt) = boot_services() {
|
if let Some(bt) = boot_services() {
|
||||||
let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
|
let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
|
||||||
|
@ -291,6 +291,15 @@ impl Drop for DevicePath {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::fmt::Debug for OwnedDevicePath {
|
||||||
|
fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
|
||||||
|
match device_path_to_text(self.0) {
|
||||||
|
Ok(p) => p.fmt(f),
|
||||||
|
Err(_) => f.debug_struct("OwnedDevicePath").finish_non_exhaustive(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct OwnedProtocol<T> {
|
pub(crate) struct OwnedProtocol<T> {
|
||||||
guid: r_efi::efi::Guid,
|
guid: r_efi::efi::Guid,
|
||||||
handle: NonNull<crate::ffi::c_void>,
|
handle: NonNull<crate::ffi::c_void>,
|
||||||
|
|
|
@ -326,7 +326,7 @@ mod uefi_command_internal {
|
||||||
|
|
||||||
impl Image {
|
impl Image {
|
||||||
pub fn load_image(p: &OsStr) -> io::Result<Self> {
|
pub fn load_image(p: &OsStr) -> io::Result<Self> {
|
||||||
let path = helpers::DevicePath::from_text(p)?;
|
let path = helpers::OwnedDevicePath::from_text(p)?;
|
||||||
let boot_services: NonNull<r_efi::efi::BootServices> = boot_services()
|
let boot_services: NonNull<r_efi::efi::BootServices> = boot_services()
|
||||||
.ok_or_else(|| const_error!(io::ErrorKind::NotFound, "Boot Services not found"))?
|
.ok_or_else(|| const_error!(io::ErrorKind::NotFound, "Boot Services not found"))?
|
||||||
.cast();
|
.cast();
|
||||||
|
|
|
@ -65,7 +65,7 @@ xz2 = "0.1"
|
||||||
# Dependencies needed by the build-metrics feature
|
# Dependencies needed by the build-metrics feature
|
||||||
sysinfo = { version = "0.33.0", default-features = false, optional = true, features = ["system"] }
|
sysinfo = { version = "0.33.0", default-features = false, optional = true, features = ["system"] }
|
||||||
|
|
||||||
# Dependencies needed by the `logging` feature
|
# Dependencies needed by the `tracing` feature
|
||||||
tracing = { version = "0.1", optional = true, features = ["attributes"] }
|
tracing = { version = "0.1", optional = true, features = ["attributes"] }
|
||||||
tracing-subscriber = { version = "0.3", optional = true, features = ["env-filter", "fmt", "registry", "std"] }
|
tracing-subscriber = { version = "0.3", optional = true, features = ["env-filter", "fmt", "registry", "std"] }
|
||||||
tracing-tree = { version = "0.4.0", optional = true }
|
tracing-tree = { version = "0.4.0", optional = true }
|
||||||
|
|
|
@ -334,7 +334,11 @@ macro_rules! bootstrap_tool {
|
||||||
}
|
}
|
||||||
|
|
||||||
bootstrap_tool!(
|
bootstrap_tool!(
|
||||||
Rustbook, "src/tools/rustbook", "rustbook", submodules = SUBMODULES_FOR_RUSTBOOK;
|
// This is marked as an external tool because it includes dependencies
|
||||||
|
// from submodules. Trying to keep the lints in sync between all the repos
|
||||||
|
// is a bit of a pain. Unfortunately it means the rustbook source itself
|
||||||
|
// doesn't deny warnings, but it is a relatively small piece of code.
|
||||||
|
Rustbook, "src/tools/rustbook", "rustbook", is_external_tool = true, submodules = SUBMODULES_FOR_RUSTBOOK;
|
||||||
UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen";
|
UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen";
|
||||||
Tidy, "src/tools/tidy", "tidy";
|
Tidy, "src/tools/tidy", "tidy";
|
||||||
Linkchecker, "src/tools/linkchecker", "linkchecker";
|
Linkchecker, "src/tools/linkchecker", "linkchecker";
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 04d06dfe541607e6419f3d028c3f9b245f3be4d9
|
Subproject commit 5a65e2af063ff701ae858f1f7536ee347b3cfe63
|
|
@ -1 +1 @@
|
||||||
Subproject commit 7ef05b9777c94836bc92f50f23e6e00981521a89
|
Subproject commit 625b200e5b33a5af35589db0bc454203a3d46d20
|
|
@ -1 +1 @@
|
||||||
Subproject commit acd6794e712d5e2ef6f5c84fb95688d32a69b816
|
Subproject commit 293af991003772bdccf2d6b980182d84dd055942
|
|
@ -1 +1 @@
|
||||||
Subproject commit 093397535b48ae13ec76bc526b7e6eb8c096a85c
|
Subproject commit 054259ed1bf01cdee4309ee764c7e103f6df3de5
|
|
@ -38,6 +38,6 @@ pub unsafe extern "C" fn gather_f64x4(mask: m64x4, ptrs: pf64x4) -> f64x4 {
|
||||||
// x86-avx512: vpsllq ymm0, ymm0, 63
|
// x86-avx512: vpsllq ymm0, ymm0, 63
|
||||||
// x86-avx512-NEXT: vpmovq2m k1, ymm0
|
// x86-avx512-NEXT: vpmovq2m k1, ymm0
|
||||||
// x86-avx512-NEXT: vpxor xmm0, xmm0, xmm0
|
// x86-avx512-NEXT: vpxor xmm0, xmm0, xmm0
|
||||||
// x86-avx512-NEXT: vgatherqpd ymm0 {k1}, ymmword ptr [1*ymm1]
|
// x86-avx512-NEXT: vgatherqpd ymm0 {k1}, {{(ymmword)|(qword)}} ptr [1*ymm1]
|
||||||
simd_gather(f64x4([0_f64, 0_f64, 0_f64, 0_f64]), ptrs, mask)
|
simd_gather(f64x4([0_f64, 0_f64, 0_f64, 0_f64]), ptrs, mask)
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,6 @@ extern "rust-intrinsic" {
|
||||||
pub unsafe extern "C" fn scatter_f64x4(values: f64x4, ptrs: pf64x4, mask: m64x4) {
|
pub unsafe extern "C" fn scatter_f64x4(values: f64x4, ptrs: pf64x4, mask: m64x4) {
|
||||||
// x86-avx512: vpsllq ymm2, ymm2, 63
|
// x86-avx512: vpsllq ymm2, ymm2, 63
|
||||||
// x86-avx512-NEXT: vpmovq2m k1, ymm2
|
// x86-avx512-NEXT: vpmovq2m k1, ymm2
|
||||||
// x86-avx512-NEXT: vscatterqpd ymmword ptr [1*ymm1] {k1}, ymm0
|
// x86-avx512-NEXT: vscatterqpd {{(ymmword)|(qword)}} ptr [1*ymm1] {k1}, ymm0
|
||||||
simd_scatter(values, ptrs, mask)
|
simd_scatter(values, ptrs, mask)
|
||||||
}
|
}
|
||||||
|
|
19
tests/mir-opt/building/dump_mir_cycle.rs
Normal file
19
tests/mir-opt/building/dump_mir_cycle.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Thing {
|
||||||
|
pub next: &'static Thing,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static THING: Thing = Thing { next: &THING };
|
||||||
|
// CHECK: alloc{{.+}} (static: THING)
|
||||||
|
|
||||||
|
const fn thing() -> &'static Thing {
|
||||||
|
&MUTUALLY_RECURSIVE
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static MUTUALLY_RECURSIVE: Thing = Thing { next: thing() };
|
||||||
|
// CHECK: alloc{{.+}} (static: MUTUALLY_RECURSIVE)
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Generate optimized MIR for the const fn, too.
|
||||||
|
thing();
|
||||||
|
}
|
|
@ -15,6 +15,4 @@ const BAR::promoted[0]: &[&i32; 1] = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ALLOC0 (static: Y, size: 4, align: 4) {
|
ALLOC0 (static: Y)
|
||||||
2a 00 00 00 │ *...
|
|
||||||
}
|
|
||||||
|
|
|
@ -38,9 +38,7 @@
|
||||||
bb2 (cleanup): {
|
bb2 (cleanup): {
|
||||||
resume;
|
resume;
|
||||||
}
|
}
|
||||||
- }
|
|
||||||
-
|
|
||||||
- ALLOC0 (static: Y, size: 4, align: 4) {
|
|
||||||
- 2a 00 00 00 │ *...
|
|
||||||
}
|
}
|
||||||
|
-
|
||||||
|
- ALLOC0 (static: Y)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
//! Regression test for <https://github.com/rust-lang/rust/issues/122638>.
|
||||||
|
//@ check-fail
|
||||||
|
#![feature(min_specialization)]
|
||||||
|
impl<'a, T: std::fmt::Debug, const N: usize> Iterator for ConstChunksExact<'a, T, { N }> {
|
||||||
|
//~^ ERROR not all trait items implemented, missing: `Item` [E0046]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {}
|
||||||
|
//~^ ERROR mismatched types [E0308]
|
||||||
|
}
|
||||||
|
struct ConstChunksExact<'a, T: '_, const assert: usize> {}
|
||||||
|
//~^ ERROR `'_` cannot be used here [E0637]
|
||||||
|
//~| ERROR lifetime parameter `'a` is never used [E0392]
|
||||||
|
//~| ERROR type parameter `T` is never used [E0392]
|
||||||
|
impl<'a, T: std::fmt::Debug, const N: usize> Iterator for ConstChunksExact<'a, T, {}> {
|
||||||
|
//~^ ERROR mismatched types [E0308]
|
||||||
|
//~| ERROR the const parameter `N` is not constrained by the impl trait, self type, or predicates [E0207]
|
||||||
|
type Item = &'a [T; N]; }
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,60 @@
|
||||||
|
error[E0637]: `'_` cannot be used here
|
||||||
|
--> $DIR/normalizing_with_unconstrained_impl_params.rs:9:32
|
||||||
|
|
|
||||||
|
LL | struct ConstChunksExact<'a, T: '_, const assert: usize> {}
|
||||||
|
| ^^ `'_` is a reserved lifetime name
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/normalizing_with_unconstrained_impl_params.rs:13:83
|
||||||
|
|
|
||||||
|
LL | impl<'a, T: std::fmt::Debug, const N: usize> Iterator for ConstChunksExact<'a, T, {}> {
|
||||||
|
| ^^ expected `usize`, found `()`
|
||||||
|
|
||||||
|
error[E0046]: not all trait items implemented, missing: `Item`
|
||||||
|
--> $DIR/normalizing_with_unconstrained_impl_params.rs:4:1
|
||||||
|
|
|
||||||
|
LL | impl<'a, T: std::fmt::Debug, const N: usize> Iterator for ConstChunksExact<'a, T, { N }> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Item` in implementation
|
||||||
|
|
|
||||||
|
= help: implement the missing item: `type Item = /* Type */;`
|
||||||
|
|
||||||
|
error[E0392]: lifetime parameter `'a` is never used
|
||||||
|
--> $DIR/normalizing_with_unconstrained_impl_params.rs:9:25
|
||||||
|
|
|
||||||
|
LL | struct ConstChunksExact<'a, T: '_, const assert: usize> {}
|
||||||
|
| ^^ unused lifetime parameter
|
||||||
|
|
|
||||||
|
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
|
||||||
|
|
||||||
|
error[E0392]: type parameter `T` is never used
|
||||||
|
--> $DIR/normalizing_with_unconstrained_impl_params.rs:9:29
|
||||||
|
|
|
||||||
|
LL | struct ConstChunksExact<'a, T: '_, const assert: usize> {}
|
||||||
|
| ^ unused type parameter
|
||||||
|
|
|
||||||
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
|
||||||
|
|
||||||
|
error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
|
||||||
|
--> $DIR/normalizing_with_unconstrained_impl_params.rs:13:30
|
||||||
|
|
|
||||||
|
LL | impl<'a, T: std::fmt::Debug, const N: usize> Iterator for ConstChunksExact<'a, T, {}> {
|
||||||
|
| ^^^^^^^^^^^^^^ unconstrained const parameter
|
||||||
|
|
|
||||||
|
= note: expressions using a const parameter must map each value to a distinct output value
|
||||||
|
= note: proving the result of expressions other than the parameter are unique is not supported
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/normalizing_with_unconstrained_impl_params.rs:6:27
|
||||||
|
|
|
||||||
|
LL | fn next(&mut self) -> Option<Self::Item> {}
|
||||||
|
| ---- ^^^^^^^^^^^^^^^^^^ expected `Option<_>`, found `()`
|
||||||
|
| |
|
||||||
|
| implicitly returns `()` as its body has no tail or `return` expression
|
||||||
|
|
|
||||||
|
= note: expected enum `Option<_>`
|
||||||
|
found unit type `()`
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0046, E0207, E0308, E0392, E0637.
|
||||||
|
For more information about an error, try `rustc --explain E0046`.
|
|
@ -0,0 +1,22 @@
|
||||||
|
//@ run-rustfix
|
||||||
|
#![deny(unused_assignments, unused_variables)]
|
||||||
|
struct Object;
|
||||||
|
|
||||||
|
fn change_object(object: &mut Object) { //~ HELP you might have meant to mutate
|
||||||
|
let object2 = Object;
|
||||||
|
*object = object2; //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_object2(object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used
|
||||||
|
//~^ HELP you might have meant to mutate
|
||||||
|
let object2 = Object;
|
||||||
|
*object = object2;
|
||||||
|
//~^ ERROR `object2` does not live long enough
|
||||||
|
//~| ERROR value assigned to `object` is never read
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut object = Object;
|
||||||
|
change_object(&mut object);
|
||||||
|
change_object2(&mut object);
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
//@ run-rustfix
|
||||||
|
#![deny(unused_assignments, unused_variables)]
|
||||||
|
struct Object;
|
||||||
|
|
||||||
|
fn change_object(mut object: &Object) { //~ HELP you might have meant to mutate
|
||||||
|
let object2 = Object;
|
||||||
|
object = object2; //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_object2(mut object: &Object) { //~ ERROR variable `object` is assigned to, but never used
|
||||||
|
//~^ HELP you might have meant to mutate
|
||||||
|
let object2 = Object;
|
||||||
|
object = &object2;
|
||||||
|
//~^ ERROR `object2` does not live long enough
|
||||||
|
//~| ERROR value assigned to `object` is never read
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut object = Object;
|
||||||
|
change_object(&mut object);
|
||||||
|
change_object2(&mut object);
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:7:14
|
||||||
|
|
|
||||||
|
LL | fn change_object(mut object: &Object) {
|
||||||
|
| ------- expected due to this parameter type
|
||||||
|
LL | let object2 = Object;
|
||||||
|
LL | object = object2;
|
||||||
|
| ^^^^^^^ expected `&Object`, found `Object`
|
||||||
|
|
|
||||||
|
help: you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding
|
||||||
|
|
|
||||||
|
LL ~ fn change_object(object: &mut Object) {
|
||||||
|
LL | let object2 = Object;
|
||||||
|
LL ~ *object = object2;
|
||||||
|
|
|
||||||
|
|
||||||
|
error: value assigned to `object` is never read
|
||||||
|
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:13:5
|
||||||
|
|
|
||||||
|
LL | object = &object2;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:2:9
|
||||||
|
|
|
||||||
|
LL | #![deny(unused_assignments, unused_variables)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
help: you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding
|
||||||
|
|
|
||||||
|
LL ~ fn change_object2(object: &mut Object) {
|
||||||
|
LL |
|
||||||
|
LL | let object2 = Object;
|
||||||
|
LL ~ *object = object2;
|
||||||
|
|
|
||||||
|
|
||||||
|
error: variable `object` is assigned to, but never used
|
||||||
|
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:10:23
|
||||||
|
|
|
||||||
|
LL | fn change_object2(mut object: &Object) {
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: consider using `_object` instead
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:2:29
|
||||||
|
|
|
||||||
|
LL | #![deny(unused_assignments, unused_variables)]
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0597]: `object2` does not live long enough
|
||||||
|
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:13:14
|
||||||
|
|
|
||||||
|
LL | fn change_object2(mut object: &Object) {
|
||||||
|
| - let's call the lifetime of this reference `'1`
|
||||||
|
LL |
|
||||||
|
LL | let object2 = Object;
|
||||||
|
| ------- binding `object2` declared here
|
||||||
|
LL | object = &object2;
|
||||||
|
| ---------^^^^^^^^
|
||||||
|
| | |
|
||||||
|
| | borrowed value does not live long enough
|
||||||
|
| assignment requires that `object2` is borrowed for `'1`
|
||||||
|
...
|
||||||
|
LL | }
|
||||||
|
| - `object2` dropped here while still borrowed
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0308, E0597.
|
||||||
|
For more information about an error, try `rustc --explain E0308`.
|
|
@ -1,24 +1,24 @@
|
||||||
//@ edition: 2024
|
//@ edition: 2024
|
||||||
//@ check-pass
|
|
||||||
|
|
||||||
#![feature(precise_capturing_in_traits)]
|
#![feature(precise_capturing_in_traits)]
|
||||||
|
#![deny(impl_trait_redundant_captures)]
|
||||||
|
|
||||||
fn hello<'a>() -> impl Sized + use<'a> {}
|
fn hello<'a>() -> impl Sized + use<'a> {}
|
||||||
//~^ WARN all possible in-scope parameters are already captured
|
//~^ ERROR all possible in-scope parameters are already captured
|
||||||
|
|
||||||
struct Inherent;
|
struct Inherent;
|
||||||
impl Inherent {
|
impl Inherent {
|
||||||
fn inherent(&self) -> impl Sized + use<'_> {}
|
fn inherent(&self) -> impl Sized + use<'_> {}
|
||||||
//~^ WARN all possible in-scope parameters are already captured
|
//~^ ERROR all possible in-scope parameters are already captured
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Test<'a> {
|
trait Test<'a> {
|
||||||
fn in_trait() -> impl Sized + use<'a, Self>;
|
fn in_trait() -> impl Sized + use<'a, Self>;
|
||||||
//~^ WARN all possible in-scope parameters are already captured
|
//~^ ERROR all possible in-scope parameters are already captured
|
||||||
}
|
}
|
||||||
impl<'a> Test<'a> for () {
|
impl<'a> Test<'a> for () {
|
||||||
fn in_trait() -> impl Sized + use<'a> {}
|
fn in_trait() -> impl Sized + use<'a> {}
|
||||||
//~^ WARN all possible in-scope parameters are already captured
|
//~^ ERROR all possible in-scope parameters are already captured
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
|
error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
|
||||||
--> $DIR/redundant.rs:6:19
|
--> $DIR/redundant.rs:6:19
|
||||||
|
|
|
|
||||||
LL | fn hello<'a>() -> impl Sized + use<'a> {}
|
LL | fn hello<'a>() -> impl Sized + use<'a> {}
|
||||||
|
@ -6,9 +6,13 @@ LL | fn hello<'a>() -> impl Sized + use<'a> {}
|
||||||
| |
|
| |
|
||||||
| help: remove the `use<...>` syntax
|
| help: remove the `use<...>` syntax
|
||||||
|
|
|
|
||||||
= note: `#[warn(impl_trait_redundant_captures)]` on by default
|
note: the lint level is defined here
|
||||||
|
--> $DIR/redundant.rs:4:9
|
||||||
|
|
|
||||||
|
LL | #![deny(impl_trait_redundant_captures)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
|
error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
|
||||||
--> $DIR/redundant.rs:11:27
|
--> $DIR/redundant.rs:11:27
|
||||||
|
|
|
|
||||||
LL | fn inherent(&self) -> impl Sized + use<'_> {}
|
LL | fn inherent(&self) -> impl Sized + use<'_> {}
|
||||||
|
@ -16,7 +20,7 @@ LL | fn inherent(&self) -> impl Sized + use<'_> {}
|
||||||
| |
|
| |
|
||||||
| help: remove the `use<...>` syntax
|
| help: remove the `use<...>` syntax
|
||||||
|
|
||||||
warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
|
error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
|
||||||
--> $DIR/redundant.rs:16:22
|
--> $DIR/redundant.rs:16:22
|
||||||
|
|
|
|
||||||
LL | fn in_trait() -> impl Sized + use<'a, Self>;
|
LL | fn in_trait() -> impl Sized + use<'a, Self>;
|
||||||
|
@ -24,7 +28,7 @@ LL | fn in_trait() -> impl Sized + use<'a, Self>;
|
||||||
| |
|
| |
|
||||||
| help: remove the `use<...>` syntax
|
| help: remove the `use<...>` syntax
|
||||||
|
|
||||||
warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
|
error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
|
||||||
--> $DIR/redundant.rs:20:22
|
--> $DIR/redundant.rs:20:22
|
||||||
|
|
|
|
||||||
LL | fn in_trait() -> impl Sized + use<'a> {}
|
LL | fn in_trait() -> impl Sized + use<'a> {}
|
||||||
|
@ -32,5 +36,5 @@ LL | fn in_trait() -> impl Sized + use<'a> {}
|
||||||
| |
|
| |
|
||||||
| help: remove the `use<...>` syntax
|
| help: remove the `use<...>` syntax
|
||||||
|
|
||||||
warning: 4 warnings emitted
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue