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:
bors 2025-01-14 03:08:59 +00:00
commit 35c2908177
34 changed files with 492 additions and 83 deletions

View file

@ -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,

View file

@ -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"
}); });

View file

@ -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)?;
} }

View file

@ -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<'_>,

View file

@ -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()

View file

@ -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,

View file

@ -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))
} }
} }

View file

@ -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.

View file

@ -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
} }

View file

@ -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`",
} }

View file

@ -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)) => {

View file

@ -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?

View file

@ -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)]

View file

@ -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 },
); );
} }
} }

View file

@ -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>,

View file

@ -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();

View file

@ -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 }

View file

@ -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

View file

@ -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)
} }

View file

@ -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)
} }

View 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();
}

View file

@ -15,6 +15,4 @@ const BAR::promoted[0]: &[&i32; 1] = {
} }
} }
ALLOC0 (static: Y, size: 4, align: 4) { ALLOC0 (static: Y)
2a 00 00 00 *...
}

View file

@ -38,9 +38,7 @@
bb2 (cleanup): { bb2 (cleanup): {
resume; resume;
} }
- }
-
- ALLOC0 (static: Y, size: 4, align: 4) {
- 2a 00 00 00 │ *...
} }
-
- ALLOC0 (static: Y)

View file

@ -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() {}

View file

@ -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`.

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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