Skip to content

Commit c67326b

Browse files
committed
Auto merge of rust-lang#122571 - matthiaskrgr:rollup-36wwovk, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - rust-lang#122254 (Detect calls to .clone() on T: !Clone types on borrowck errors) - rust-lang#122495 (Visually mark 👻hidden👻 items with document-hidden-items) - rust-lang#122543 (Add `#![rustc_never_type_mode = "..."]` crate-level attribute to allow experimenting) - rust-lang#122560 (Safe Transmute: Use 'not yet supported', not 'unspecified' in errors) - rust-lang#122562 (Mention labelled blocks in `break` docs) - rust-lang#122563 (CI: cache PR CI Docker builds) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 1ca424c + 948e031 commit c67326b

File tree

56 files changed

+711
-362
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+711
-362
lines changed

compiler/rustc_borrowck/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ borrowck_borrow_due_to_use_closure =
1616
borrowck_borrow_due_to_use_coroutine =
1717
borrow occurs due to use in coroutine
1818
19+
borrowck_calling_operator_moves =
20+
calling this operator moves the value
21+
1922
borrowck_calling_operator_moves_lhs =
2023
calling this operator moves the left-hand side
2124

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+106-7
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use rustc_hir::def::{DefKind, Res};
1212
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
1313
use rustc_hir::{CoroutineDesugaring, PatField};
1414
use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
15-
use rustc_infer::traits::ObligationCause;
1615
use rustc_middle::hir::nested_filter::OnlyBodies;
1716
use rustc_middle::mir::tcx::PlaceTy;
1817
use rustc_middle::mir::{
@@ -21,16 +20,21 @@ use rustc_middle::mir::{
2120
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
2221
VarBindingForm,
2322
};
24-
use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty, TyCtxt};
23+
use rustc_middle::ty::{
24+
self, suggest_constraining_type_params, PredicateKind, ToPredicate, Ty, TyCtxt,
25+
TypeSuperVisitable, TypeVisitor,
26+
};
2527
use rustc_middle::util::CallKind;
2628
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
29+
use rustc_span::def_id::DefId;
2730
use rustc_span::def_id::LocalDefId;
2831
use rustc_span::hygiene::DesugaringKind;
2932
use rustc_span::symbol::{kw, sym, Ident};
3033
use rustc_span::{BytePos, Span, Symbol};
3134
use rustc_trait_selection::infer::InferCtxtExt;
35+
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
3236
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
33-
use rustc_trait_selection::traits::ObligationCtxt;
37+
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
3438
use std::iter;
3539

3640
use crate::borrow_set::TwoPhaseActivation;
@@ -283,7 +287,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
283287
// something that already has `Fn`-like bounds (or is a closure), so we can't
284288
// restrict anyways.
285289
} else {
286-
self.suggest_adding_copy_bounds(&mut err, ty, span);
290+
let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, Some(span));
291+
self.suggest_adding_bounds(&mut err, ty, copy_did, span);
287292
}
288293

289294
if needs_note {
@@ -774,7 +779,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
774779
}
775780
}
776781

777-
fn suggest_adding_copy_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, span: Span) {
782+
fn suggest_adding_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, def_id: DefId, span: Span) {
778783
let tcx = self.infcx.tcx;
779784
let generics = tcx.generics_of(self.mir_def_id());
780785

@@ -787,10 +792,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
787792
};
788793
// Try to find predicates on *generic params* that would allow copying `ty`
789794
let ocx = ObligationCtxt::new(self.infcx);
790-
let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span));
791795
let cause = ObligationCause::misc(span, self.mir_def_id());
792796

793-
ocx.register_bound(cause, self.param_env, ty, copy_did);
797+
ocx.register_bound(cause, self.param_env, ty, def_id);
794798
let errors = ocx.select_all_or_error();
795799

796800
// Only emit suggestion if all required predicates are on generic
@@ -876,6 +880,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
876880
Some(borrow_span),
877881
None,
878882
);
883+
self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
879884
self.buffer_error(err);
880885
}
881886

@@ -1214,10 +1219,104 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
12141219
);
12151220

12161221
self.suggest_using_local_if_applicable(&mut err, location, issued_borrow, explanation);
1222+
self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
12171223

12181224
err
12191225
}
12201226

1227+
fn suggest_copy_for_type_in_cloned_ref(&self, err: &mut Diag<'tcx>, place: Place<'tcx>) {
1228+
let tcx = self.infcx.tcx;
1229+
let hir = tcx.hir();
1230+
let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
1231+
struct FindUselessClone<'hir> {
1232+
pub clones: Vec<&'hir hir::Expr<'hir>>,
1233+
}
1234+
impl<'hir> FindUselessClone<'hir> {
1235+
pub fn new() -> Self {
1236+
Self { clones: vec![] }
1237+
}
1238+
}
1239+
1240+
impl<'v> Visitor<'v> for FindUselessClone<'v> {
1241+
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
1242+
// FIXME: use `lookup_method_for_diagnostic`?
1243+
if let hir::ExprKind::MethodCall(segment, _rcvr, args, _span) = ex.kind
1244+
&& segment.ident.name == sym::clone
1245+
&& args.len() == 0
1246+
{
1247+
self.clones.push(ex);
1248+
}
1249+
hir::intravisit::walk_expr(self, ex);
1250+
}
1251+
}
1252+
let mut expr_finder = FindUselessClone::new();
1253+
1254+
let body = hir.body(body_id).value;
1255+
expr_finder.visit_expr(body);
1256+
1257+
pub struct Holds<'tcx> {
1258+
ty: Ty<'tcx>,
1259+
holds: bool,
1260+
}
1261+
1262+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Holds<'tcx> {
1263+
type Result = std::ops::ControlFlow<()>;
1264+
1265+
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
1266+
if t == self.ty {
1267+
self.holds = true;
1268+
}
1269+
t.super_visit_with(self)
1270+
}
1271+
}
1272+
1273+
let mut types_to_constrain = FxIndexSet::default();
1274+
1275+
let local_ty = self.body.local_decls[place.local].ty;
1276+
let typeck_results = tcx.typeck(self.mir_def_id());
1277+
let clone = tcx.require_lang_item(LangItem::Clone, Some(body.span));
1278+
for expr in expr_finder.clones {
1279+
if let hir::ExprKind::MethodCall(_, rcvr, _, span) = expr.kind
1280+
&& let Some(rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id)
1281+
&& let Some(ty) = typeck_results.node_type_opt(expr.hir_id)
1282+
&& rcvr_ty == ty
1283+
&& let ty::Ref(_, inner, _) = rcvr_ty.kind()
1284+
&& let inner = inner.peel_refs()
1285+
&& let mut v = (Holds { ty: inner, holds: false })
1286+
&& let _ = v.visit_ty(local_ty)
1287+
&& v.holds
1288+
&& let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env)
1289+
{
1290+
err.span_label(
1291+
span,
1292+
format!(
1293+
"this call doesn't do anything, the result is still `{rcvr_ty}` \
1294+
because `{inner}` doesn't implement `Clone`",
1295+
),
1296+
);
1297+
types_to_constrain.insert(inner);
1298+
}
1299+
}
1300+
for ty in types_to_constrain {
1301+
self.suggest_adding_bounds(err, ty, clone, body.span);
1302+
if let ty::Adt(..) = ty.kind() {
1303+
// The type doesn't implement Clone.
1304+
let trait_ref = ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, clone, [ty]));
1305+
let obligation = Obligation::new(
1306+
self.infcx.tcx,
1307+
ObligationCause::dummy(),
1308+
self.param_env,
1309+
trait_ref,
1310+
);
1311+
self.infcx.err_ctxt().suggest_derive(
1312+
&obligation,
1313+
err,
1314+
trait_ref.to_predicate(self.infcx.tcx),
1315+
);
1316+
}
1317+
}
1318+
}
1319+
12211320
#[instrument(level = "debug", skip(self, err))]
12221321
fn suggest_using_local_if_applicable(
12231322
&self,

compiler/rustc_borrowck/src/diagnostics/mod.rs

+15-8
Original file line numberDiff line numberDiff line change
@@ -1050,7 +1050,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
10501050
);
10511051
err.subdiagnostic(self.dcx(), CaptureReasonNote::FnOnceMoveInCall { var_span });
10521052
}
1053-
CallKind::Operator { self_arg, .. } => {
1053+
CallKind::Operator { self_arg, trait_id, .. } => {
10541054
let self_arg = self_arg.unwrap();
10551055
err.subdiagnostic(
10561056
self.dcx(),
@@ -1062,9 +1062,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
10621062
},
10631063
);
10641064
if self.fn_self_span_reported.insert(fn_span) {
1065+
let lang = self.infcx.tcx.lang_items();
10651066
err.subdiagnostic(
10661067
self.dcx(),
1067-
CaptureReasonNote::LhsMoveByOperator { span: self_arg.span },
1068+
if [lang.not_trait(), lang.deref_trait(), lang.neg_trait()]
1069+
.contains(&Some(trait_id))
1070+
{
1071+
CaptureReasonNote::UnOpMoveByOperator { span: self_arg.span }
1072+
} else {
1073+
CaptureReasonNote::LhsMoveByOperator { span: self_arg.span }
1074+
},
10681075
);
10691076
}
10701077
}
@@ -1226,20 +1233,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
12261233
{
12271234
let msg = match &errors[..] {
12281235
[] => "you can `clone` the value and consume it, but this \
1229-
might not be your desired behavior"
1236+
might not be your desired behavior"
12301237
.to_string(),
12311238
[error] => {
12321239
format!(
1233-
"you could `clone` the value and consume it, if \
1234-
the `{}` trait bound could be satisfied",
1240+
"you could `clone` the value and consume it, if the \
1241+
`{}` trait bound could be satisfied",
12351242
error.obligation.predicate,
12361243
)
12371244
}
12381245
[errors @ .., last] => {
12391246
format!(
1240-
"you could `clone` the value and consume it, if \
1241-
the following trait bounds could be satisfied: {} \
1242-
and `{}`",
1247+
"you could `clone` the value and consume it, if the \
1248+
following trait bounds could be satisfied: \
1249+
{} and `{}`",
12431250
errors
12441251
.iter()
12451252
.map(|e| format!("`{}`", e.obligation.predicate))

compiler/rustc_borrowck/src/session_diagnostics.rs

+5
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,11 @@ pub(crate) enum CaptureReasonNote {
368368
#[primary_span]
369369
var_span: Span,
370370
},
371+
#[note(borrowck_calling_operator_moves)]
372+
UnOpMoveByOperator {
373+
#[primary_span]
374+
span: Span,
375+
},
371376
#[note(borrowck_calling_operator_moves_lhs)]
372377
LhsMoveByOperator {
373378
#[primary_span]

compiler/rustc_feature/src/builtin_attrs.rs

+7
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
580580
"`may_dangle` has unstable semantics and may be removed in the future",
581581
),
582582

583+
rustc_attr!(
584+
rustc_never_type_mode, Normal, template!(NameValueStr: "fallback_to_unit|fallback_to_niko|fallback_to_never|no_fallback"), ErrorFollowing,
585+
@only_local: true,
586+
"`rustc_never_type_fallback` is used to experiment with never type fallback and work on \
587+
never type stabilization, and will never be stable"
588+
),
589+
583590
// ==========================================================================
584591
// Internal attributes: Runtime related:
585592
// ==========================================================================

0 commit comments

Comments
 (0)