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
|
||||
.take_opaque_types()
|
||||
.into_iter()
|
||||
.map(|(opaque_type_key, decl)| {
|
||||
let hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
|
||||
.map(|(opaque_type_key, hidden_type)| {
|
||||
let hidden_type = infcx.resolve_vars_if_possible(hidden_type);
|
||||
register_member_constraints(
|
||||
typeck,
|
||||
&mut member_constraints,
|
||||
|
|
|
@ -2451,10 +2451,10 @@ fn add_order_independent_options(
|
|||
}
|
||||
|
||||
if sess.target.os == "emscripten" {
|
||||
cmd.cc_arg(if sess.panic_strategy() == PanicStrategy::Abort {
|
||||
"-sDISABLE_EXCEPTION_CATCHING=1"
|
||||
} else if sess.opts.unstable_opts.emscripten_wasm_eh {
|
||||
cmd.cc_arg(if sess.opts.unstable_opts.emscripten_wasm_eh {
|
||||
"-fwasm-exceptions"
|
||||
} else if sess.panic_strategy() == PanicStrategy::Abort {
|
||||
"-sDISABLE_EXCEPTION_CATCHING=1"
|
||||
} else {
|
||||
"-sDISABLE_EXCEPTION_CATCHING=0"
|
||||
});
|
||||
|
|
|
@ -436,9 +436,9 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
} else {
|
||||
// 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() {
|
||||
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);
|
||||
sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?;
|
||||
sanity_check_found_hidden_type(tcx, key, ty)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1873,7 +1873,7 @@ pub(super) fn check_coroutine_obligations(
|
|||
// Check that any hidden types found when checking these stalled coroutine obligations
|
||||
// are valid.
|
||||
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);
|
||||
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_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
|
||||
// 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(
|
||||
&self,
|
||||
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
|
||||
// fixpoint.
|
||||
let opaque_types = self.fcx.infcx.clone_opaque_types();
|
||||
for (opaque_type_key, decl) in opaque_types {
|
||||
let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
|
||||
let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span);
|
||||
for (opaque_type_key, hidden_type) in opaque_types {
|
||||
let hidden_type = self.resolve(hidden_type, &hidden_type.span);
|
||||
let opaque_type_key = self.resolve(opaque_type_key, &hidden_type.span);
|
||||
|
||||
if !self.fcx.next_trait_solver() {
|
||||
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
|
||||
|
|
|
@ -155,12 +155,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
.opaque_type_storage
|
||||
.opaque_types
|
||||
.iter()
|
||||
.map(|(k, v)| (*k, v.hidden_type.ty))
|
||||
.map(|(k, v)| (*k, v.ty))
|
||||
.collect()
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -234,7 +234,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
|
|||
pub fn iter_opaque_types(
|
||||
&self,
|
||||
) -> 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;
|
||||
|
||||
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};
|
||||
|
||||
/// 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> {
|
||||
/// This is a backwards compatibility hack to prevent breaking changes from
|
||||
/// lazy TAIT around RPIT handling.
|
||||
|
|
|
@ -3,7 +3,7 @@ use rustc_middle::bug;
|
|||
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty};
|
||||
use tracing::instrument;
|
||||
|
||||
use super::{OpaqueTypeDecl, OpaqueTypeMap};
|
||||
use super::OpaqueTypeMap;
|
||||
use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog};
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
|
@ -11,15 +11,19 @@ pub(crate) struct OpaqueTypeStorage<'tcx> {
|
|||
/// Opaque types found in explicit return types and their
|
||||
/// associated fresh inference variable. Writeback resolves these
|
||||
/// 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>,
|
||||
}
|
||||
|
||||
impl<'tcx> OpaqueTypeStorage<'tcx> {
|
||||
#[instrument(level = "debug")]
|
||||
pub(crate) fn remove(&mut self, key: OpaqueTypeKey<'tcx>, idx: Option<OpaqueHiddenType<'tcx>>) {
|
||||
if let Some(idx) = idx {
|
||||
self.opaque_types.get_mut(&key).unwrap().hidden_type = idx;
|
||||
pub(crate) fn remove(
|
||||
&mut self,
|
||||
key: OpaqueTypeKey<'tcx>,
|
||||
prev: Option<OpaqueHiddenType<'tcx>>,
|
||||
) {
|
||||
if let Some(prev) = prev {
|
||||
*self.opaque_types.get_mut(&key).unwrap() = prev;
|
||||
} else {
|
||||
// FIXME(#120456) - is `swap_remove` correct?
|
||||
match self.opaque_types.swap_remove(&key) {
|
||||
|
@ -59,13 +63,12 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> {
|
|||
key: OpaqueTypeKey<'tcx>,
|
||||
hidden_type: OpaqueHiddenType<'tcx>,
|
||||
) -> Option<Ty<'tcx>> {
|
||||
if let Some(decl) = self.storage.opaque_types.get_mut(&key) {
|
||||
let prev = std::mem::replace(&mut decl.hidden_type, hidden_type);
|
||||
if let Some(entry) = self.storage.opaque_types.get_mut(&key) {
|
||||
let prev = std::mem::replace(entry, hidden_type);
|
||||
self.undo_log.push(UndoLog::OpaqueTypes(key, Some(prev)));
|
||||
return Some(prev.ty);
|
||||
}
|
||||
let decl = OpaqueTypeDecl { hidden_type };
|
||||
self.storage.opaque_types.insert(key, decl);
|
||||
self.storage.opaque_types.insert(key, hidden_type);
|
||||
self.undo_log.push(UndoLog::OpaqueTypes(key, None));
|
||||
None
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ declare_lint! {
|
|||
/// To fix this, remove the `use<'a>`, since the lifetime is already captured
|
||||
/// since it is in scope.
|
||||
pub IMPL_TRAIT_REDUNDANT_CAPTURES,
|
||||
Warn,
|
||||
Allow,
|
||||
"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})")?
|
||||
}
|
||||
Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
|
||||
match tcx.eval_static_initializer(did) {
|
||||
Ok(alloc) => {
|
||||
write!(w, " (static: {}, ", tcx.def_path_str(did))?;
|
||||
write_allocation_track_relocs(w, alloc)?;
|
||||
write!(w, " (static: {}", tcx.def_path_str(did))?;
|
||||
if body.phase <= MirPhase::Runtime(RuntimePhase::PostCleanup)
|
||||
&& tcx.hir().body_const_context(body.source.def_id()).is_some()
|
||||
{
|
||||
// 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)) => {
|
||||
|
|
|
@ -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
|
||||
.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
|
||||
.help = did you mean to capture by reference instead?
|
||||
|
||||
|
|
|
@ -1787,9 +1787,26 @@ pub(crate) struct IneffectiveUnstableImpl;
|
|||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_unused_assign)]
|
||||
#[help]
|
||||
pub(crate) struct UnusedAssign {
|
||||
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)]
|
||||
|
|
|
@ -1360,7 +1360,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, '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| {
|
||||
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.
|
||||
let ln = self.live_node(expr.hir_id, 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")]
|
||||
fn report_unused(
|
||||
&self,
|
||||
|
@ -1738,15 +1803,23 @@ impl<'tcx> Liveness<'_, 'tcx> {
|
|||
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)
|
||||
&& let Some(name) = self.should_warn(var)
|
||||
{
|
||||
let help = suggestion.is_none();
|
||||
self.ir.tcx.emit_node_span_lint(
|
||||
lint::builtin::UNUSED_ASSIGNMENTS,
|
||||
hir_id,
|
||||
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)
|
||||
}
|
||||
|
||||
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> {
|
||||
fn inner(
|
||||
p: &OsStr,
|
||||
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>>();
|
||||
if path_vec[..path_vec.len() - 1].contains(&0) {
|
||||
return Err(const_error!(
|
||||
|
@ -242,7 +242,7 @@ impl DevicePath {
|
|||
unsafe { ((*protocol.as_ptr()).convert_text_to_device_path)(path_vec.as_ptr()) };
|
||||
|
||||
NonNull::new(path)
|
||||
.map(DevicePath)
|
||||
.map(OwnedDevicePath)
|
||||
.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()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DevicePath {
|
||||
impl Drop for OwnedDevicePath {
|
||||
fn drop(&mut self) {
|
||||
if let Some(bt) = boot_services() {
|
||||
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> {
|
||||
guid: r_efi::efi::Guid,
|
||||
handle: NonNull<crate::ffi::c_void>,
|
||||
|
|
|
@ -326,7 +326,7 @@ mod uefi_command_internal {
|
|||
|
||||
impl Image {
|
||||
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()
|
||||
.ok_or_else(|| const_error!(io::ErrorKind::NotFound, "Boot Services not found"))?
|
||||
.cast();
|
||||
|
|
|
@ -65,7 +65,7 @@ xz2 = "0.1"
|
|||
# Dependencies needed by the build-metrics feature
|
||||
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-subscriber = { version = "0.3", optional = true, features = ["env-filter", "fmt", "registry", "std"] }
|
||||
tracing-tree = { version = "0.4.0", optional = true }
|
||||
|
|
|
@ -334,7 +334,11 @@ macro_rules! 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";
|
||||
Tidy, "src/tools/tidy", "tidy";
|
||||
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-NEXT: vpmovq2m k1, ymm0
|
||||
// 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)
|
||||
}
|
||||
|
|
|
@ -34,6 +34,6 @@ extern "rust-intrinsic" {
|
|||
pub unsafe extern "C" fn scatter_f64x4(values: f64x4, ptrs: pf64x4, mask: m64x4) {
|
||||
// x86-avx512: vpsllq ymm2, ymm2, 63
|
||||
// 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)
|
||||
}
|
||||
|
|
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) {
|
||||
2a 00 00 00 │ *...
|
||||
}
|
||||
ALLOC0 (static: Y)
|
||||
|
|
|
@ -38,9 +38,7 @@
|
|||
bb2 (cleanup): {
|
||||
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
|
||||
//@ check-pass
|
||||
|
||||
#![feature(precise_capturing_in_traits)]
|
||||
#![deny(impl_trait_redundant_captures)]
|
||||
|
||||
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;
|
||||
impl Inherent {
|
||||
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> {
|
||||
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 () {
|
||||
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() {}
|
||||
|
|
|
@ -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
|
||||
|
|
||||
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
|
||||
|
|
||||
= 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
|
||||
|
|
||||
LL | fn inherent(&self) -> impl Sized + use<'_> {}
|
||||
|
@ -16,7 +20,7 @@ LL | fn inherent(&self) -> impl Sized + use<'_> {}
|
|||
| |
|
||||
| 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
|
||||
|
|
||||
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
|
||||
|
||||
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
|
||||
|
|
||||
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
|
||||
|
||||
warning: 4 warnings emitted
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue