Skip to content

Commit 280ec21

Browse files
committed
Auto merge of rust-lang#118617 - GuillaumeGomez:rollup-9zj8ylu, r=GuillaumeGomez
Rollup of 5 pull requests Successful merges: - rust-lang#118076 (Tweak `.clone()` suggestion to work in more cases) - rust-lang#118508 (rustdoc: do not escape quotes in body text) - rust-lang#118565 (interpret: make numeric_intrinsic accessible from Miri) - rust-lang#118591 (portable-simd: fix test suite build) - rust-lang#118600 ([rustdoc] Don't generate the "Fields" heading if there is no field displayed) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 0e2dac8 + 2d7b858 commit 280ec21

File tree

48 files changed

+916
-153
lines changed

Some content is hidden

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

48 files changed

+916
-153
lines changed

compiler/rustc_borrowck/src/diagnostics/mod.rs

+103-52
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_hir::def::{CtorKind, Namespace};
1111
use rustc_hir::CoroutineKind;
1212
use rustc_index::IndexSlice;
1313
use rustc_infer::infer::BoundRegionConversionTime;
14+
use rustc_infer::traits::{FulfillmentErrorCode, SelectionError};
1415
use rustc_middle::mir::tcx::PlaceTy;
1516
use rustc_middle::mir::{
1617
AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location,
@@ -24,10 +25,9 @@ use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
2425
use rustc_span::def_id::LocalDefId;
2526
use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
2627
use rustc_target::abi::{FieldIdx, VariantIdx};
27-
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
28-
use rustc_trait_selection::traits::{
29-
type_known_to_meet_bound_modulo_regions, Obligation, ObligationCause,
30-
};
28+
use rustc_trait_selection::infer::InferCtxtExt;
29+
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
30+
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
3131

3232
use super::borrow_set::BorrowData;
3333
use super::MirBorrowckCtxt;
@@ -1043,7 +1043,38 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
10431043
}
10441044
CallKind::Normal { self_arg, desugaring, method_did, method_args } => {
10451045
let self_arg = self_arg.unwrap();
1046+
let mut has_sugg = false;
10461047
let tcx = self.infcx.tcx;
1048+
// Avoid pointing to the same function in multiple different
1049+
// error messages.
1050+
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
1051+
self.explain_iterator_advancement_in_for_loop_if_applicable(
1052+
err,
1053+
span,
1054+
&move_spans,
1055+
);
1056+
1057+
let func = tcx.def_path_str(method_did);
1058+
err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
1059+
func,
1060+
place_name: place_name.clone(),
1061+
span: self_arg.span,
1062+
});
1063+
}
1064+
let parent_did = tcx.parent(method_did);
1065+
let parent_self_ty =
1066+
matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. })
1067+
.then_some(parent_did)
1068+
.and_then(|did| match tcx.type_of(did).instantiate_identity().kind() {
1069+
ty::Adt(def, ..) => Some(def.did()),
1070+
_ => None,
1071+
});
1072+
let is_option_or_result = parent_self_ty.is_some_and(|def_id| {
1073+
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
1074+
});
1075+
if is_option_or_result && maybe_reinitialized_locations_is_empty {
1076+
err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
1077+
}
10471078
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
10481079
let ty = moved_place.ty(self.body, tcx).ty;
10491080
let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
@@ -1108,7 +1139,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
11081139
// Erase and shadow everything that could be passed to the new infcx.
11091140
let ty = moved_place.ty(self.body, tcx).ty;
11101141

1111-
if let ty::Adt(def, args) = ty.kind()
1142+
if let ty::Adt(def, args) = ty.peel_refs().kind()
11121143
&& Some(def.did()) == tcx.lang_items().pin_type()
11131144
&& let ty::Ref(_, _, hir::Mutability::Mut) = args.type_at(0).kind()
11141145
&& let self_ty = self.infcx.instantiate_binder_with_fresh_vars(
@@ -1124,56 +1155,76 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
11241155
span: move_span.shrink_to_hi(),
11251156
},
11261157
);
1158+
has_sugg = true;
11271159
}
1128-
if let Some(clone_trait) = tcx.lang_items().clone_trait()
1129-
&& let trait_ref = ty::TraitRef::new(tcx, clone_trait, [ty])
1130-
&& let o = Obligation::new(
1131-
tcx,
1132-
ObligationCause::dummy(),
1133-
self.param_env,
1134-
ty::Binder::dummy(trait_ref),
1135-
)
1136-
&& self.infcx.predicate_must_hold_modulo_regions(&o)
1137-
{
1138-
err.span_suggestion_verbose(
1139-
move_span.shrink_to_hi(),
1140-
"you can `clone` the value and consume it, but this might not be \
1141-
your desired behavior",
1142-
".clone()".to_string(),
1143-
Applicability::MaybeIncorrect,
1144-
);
1160+
if let Some(clone_trait) = tcx.lang_items().clone_trait() {
1161+
let sugg = if moved_place
1162+
.iter_projections()
1163+
.any(|(_, elem)| matches!(elem, ProjectionElem::Deref))
1164+
{
1165+
vec![
1166+
// We use the fully-qualified path because `.clone()` can
1167+
// sometimes choose `<&T as Clone>` instead of `<T as Clone>`
1168+
// when going through auto-deref, so this ensures that doesn't
1169+
// happen, causing suggestions for `.clone().clone()`.
1170+
(move_span.shrink_to_lo(), format!("<{ty} as Clone>::clone(&")),
1171+
(move_span.shrink_to_hi(), ")".to_string()),
1172+
]
1173+
} else {
1174+
vec![(move_span.shrink_to_hi(), ".clone()".to_string())]
1175+
};
1176+
if let Some(errors) =
1177+
self.infcx.could_impl_trait(clone_trait, ty, self.param_env)
1178+
&& !has_sugg
1179+
{
1180+
let msg = match &errors[..] {
1181+
[] => "you can `clone` the value and consume it, but this \
1182+
might not be your desired behavior"
1183+
.to_string(),
1184+
[error] => {
1185+
format!(
1186+
"you could `clone` the value and consume it, if \
1187+
the `{}` trait bound could be satisfied",
1188+
error.obligation.predicate,
1189+
)
1190+
}
1191+
[errors @ .., last] => {
1192+
format!(
1193+
"you could `clone` the value and consume it, if \
1194+
the following trait bounds could be satisfied: {} \
1195+
and `{}`",
1196+
errors
1197+
.iter()
1198+
.map(|e| format!("`{}`", e.obligation.predicate))
1199+
.collect::<Vec<_>>()
1200+
.join(", "),
1201+
last.obligation.predicate,
1202+
)
1203+
}
1204+
};
1205+
err.multipart_suggestion_verbose(
1206+
msg,
1207+
sugg.clone(),
1208+
Applicability::MaybeIncorrect,
1209+
);
1210+
for error in errors {
1211+
if let FulfillmentErrorCode::CodeSelectionError(
1212+
SelectionError::Unimplemented,
1213+
) = error.code
1214+
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
1215+
pred,
1216+
)) = error.obligation.predicate.kind().skip_binder()
1217+
{
1218+
self.infcx.err_ctxt().suggest_derive(
1219+
&error.obligation,
1220+
err,
1221+
error.obligation.predicate.kind().rebind(pred),
1222+
);
1223+
}
1224+
}
1225+
}
11451226
}
11461227
}
1147-
// Avoid pointing to the same function in multiple different
1148-
// error messages.
1149-
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
1150-
self.explain_iterator_advancement_in_for_loop_if_applicable(
1151-
err,
1152-
span,
1153-
&move_spans,
1154-
);
1155-
1156-
let func = tcx.def_path_str(method_did);
1157-
err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
1158-
func,
1159-
place_name,
1160-
span: self_arg.span,
1161-
});
1162-
}
1163-
let parent_did = tcx.parent(method_did);
1164-
let parent_self_ty =
1165-
matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. })
1166-
.then_some(parent_did)
1167-
.and_then(|did| match tcx.type_of(did).instantiate_identity().kind() {
1168-
ty::Adt(def, ..) => Some(def.did()),
1169-
_ => None,
1170-
});
1171-
let is_option_or_result = parent_self_ty.is_some_and(|def_id| {
1172-
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
1173-
});
1174-
if is_option_or_result && maybe_reinitialized_locations_is_empty {
1175-
err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
1176-
}
11771228
}
11781229
// Other desugarings takes &self, which cannot cause a move
11791230
_ => {}

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

+101-1
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@ use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed
33
use rustc_hir as hir;
44
use rustc_hir::intravisit::Visitor;
55
use rustc_hir::Node;
6+
use rustc_infer::traits;
67
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
7-
use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt};
8+
use rustc_middle::ty::{self, InstanceDef, ToPredicate, Ty, TyCtxt};
89
use rustc_middle::{
910
hir::place::PlaceBase,
1011
mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
1112
};
1213
use rustc_span::symbol::{kw, Symbol};
1314
use rustc_span::{sym, BytePos, DesugaringKind, Span};
1415
use rustc_target::abi::FieldIdx;
16+
use rustc_trait_selection::infer::InferCtxtExt;
17+
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
1518

1619
use crate::diagnostics::BorrowedContentSource;
1720
use crate::util::FindAssignments;
@@ -1212,6 +1215,103 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
12121215
if let Some(hir_id) = hir_id
12131216
&& let Some(hir::Node::Local(local)) = hir_map.find(hir_id)
12141217
{
1218+
let tables = self.infcx.tcx.typeck(def_id.as_local().unwrap());
1219+
if let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait()
1220+
&& let Some(expr) = local.init
1221+
&& let ty = tables.node_type_opt(expr.hir_id)
1222+
&& let Some(ty) = ty
1223+
&& let ty::Ref(..) = ty.kind()
1224+
{
1225+
match self
1226+
.infcx
1227+
.could_impl_trait(clone_trait, ty.peel_refs(), self.param_env)
1228+
.as_deref()
1229+
{
1230+
Some([]) => {
1231+
// The type implements Clone.
1232+
err.span_help(
1233+
expr.span,
1234+
format!(
1235+
"you can `clone` the `{}` value and consume it, but this \
1236+
might not be your desired behavior",
1237+
ty.peel_refs(),
1238+
),
1239+
);
1240+
}
1241+
None => {
1242+
if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) =
1243+
expr.kind
1244+
&& segment.ident.name == sym::clone
1245+
{
1246+
err.span_help(
1247+
span,
1248+
format!(
1249+
"`{}` doesn't implement `Clone`, so this call clones \
1250+
the reference `{ty}`",
1251+
ty.peel_refs(),
1252+
),
1253+
);
1254+
}
1255+
// The type doesn't implement Clone.
1256+
let trait_ref = ty::Binder::dummy(ty::TraitRef::new(
1257+
self.infcx.tcx,
1258+
clone_trait,
1259+
[ty.peel_refs()],
1260+
));
1261+
let obligation = traits::Obligation::new(
1262+
self.infcx.tcx,
1263+
traits::ObligationCause::dummy(),
1264+
self.param_env,
1265+
trait_ref,
1266+
);
1267+
self.infcx.err_ctxt().suggest_derive(
1268+
&obligation,
1269+
err,
1270+
trait_ref.to_predicate(self.infcx.tcx),
1271+
);
1272+
}
1273+
Some(errors) => {
1274+
if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) =
1275+
expr.kind
1276+
&& segment.ident.name == sym::clone
1277+
{
1278+
err.span_help(
1279+
span,
1280+
format!(
1281+
"`{}` doesn't implement `Clone` because its \
1282+
implementations trait bounds could not be met, so \
1283+
this call clones the reference `{ty}`",
1284+
ty.peel_refs(),
1285+
),
1286+
);
1287+
err.note(format!(
1288+
"the following trait bounds weren't met: {}",
1289+
errors
1290+
.iter()
1291+
.map(|e| e.obligation.predicate.to_string())
1292+
.collect::<Vec<_>>()
1293+
.join("\n"),
1294+
));
1295+
}
1296+
// The type doesn't implement Clone because of unmet obligations.
1297+
for error in errors {
1298+
if let traits::FulfillmentErrorCode::CodeSelectionError(
1299+
traits::SelectionError::Unimplemented,
1300+
) = error.code
1301+
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
1302+
pred,
1303+
)) = error.obligation.predicate.kind().skip_binder()
1304+
{
1305+
self.infcx.err_ctxt().suggest_derive(
1306+
&error.obligation,
1307+
err,
1308+
error.obligation.predicate.kind().rebind(pred),
1309+
);
1310+
}
1311+
}
1312+
}
1313+
}
1314+
}
12151315
let (changing, span, sugg) = match local.ty {
12161316
Some(ty) => ("changing", ty.span, message),
12171317
None => {

0 commit comments

Comments
 (0)