mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 06:51:58 +00:00
Auto merge of #95840 - Dylan-DPC:rollup-erz5u6w, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #95308 (Reduce the amount of unstable features used in libproc_macro) - #95676 (Update RLS) - #95769 (Hide cross-crate `#[doc(hidden)]` associated items in trait impls) - #95785 (interpret: err instead of ICE on size mismatches in to_bits_or_ptr_internal) - #95802 (fix unused constant warning on some Windows targets) - #95810 (Use `format-args-capture` and remove unnecessary nested blocks) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
fbdb10f9fa
@ -2950,9 +2950,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "racer"
|
||||
version = "2.2.0"
|
||||
version = "2.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0b4b5faaf07040474e8af74a9e19ff167d5d204df5db5c5c765edecfb900358"
|
||||
checksum = "64954e44fc0d1dcc64e0b9f2b155249ad62849eba25354b76ae1598d1e8f0fa0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap 2.34.0",
|
||||
|
@ -157,14 +157,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
// Error with the match place
|
||||
LookupResult::Parent(_) => {
|
||||
for ge in &mut *grouped_errors {
|
||||
if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge {
|
||||
if match_span == *span {
|
||||
debug!("appending local({:?}) to list", bind_to);
|
||||
if !binds_to.is_empty() {
|
||||
binds_to.push(bind_to);
|
||||
}
|
||||
return;
|
||||
if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge
|
||||
&& match_span == *span
|
||||
{
|
||||
debug!("appending local({:?}) to list", bind_to);
|
||||
if !binds_to.is_empty() {
|
||||
binds_to.push(bind_to);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
debug!("found a new move error location");
|
||||
@ -353,7 +353,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
None => bug!("closure kind not inferred by borrowck"),
|
||||
};
|
||||
let capture_description =
|
||||
format!("captured variable in an `{}` closure", closure_kind);
|
||||
format!("captured variable in an `{closure_kind}` closure");
|
||||
|
||||
let upvar = &self.upvars[upvar_field.unwrap().index()];
|
||||
let upvar_hir_id = upvar.place.get_root_variable();
|
||||
@ -364,9 +364,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
let place_description =
|
||||
if self.is_upvar_field_projection(move_place.as_ref()).is_some() {
|
||||
format!("{}, a {}", place_name, capture_description)
|
||||
format!("{place_name}, a {capture_description}")
|
||||
} else {
|
||||
format!("{}, as `{}` is a {}", place_name, upvar_name, capture_description)
|
||||
format!("{place_name}, as `{upvar_name}` is a {capture_description}")
|
||||
};
|
||||
|
||||
debug!(
|
||||
@ -379,7 +379,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
diag.span_label(upvar_span, "captured outer variable");
|
||||
diag.span_label(
|
||||
self.body.span,
|
||||
format!("captured by this `{}` closure", closure_kind),
|
||||
format!("captured by this `{closure_kind}` closure"),
|
||||
);
|
||||
|
||||
diag
|
||||
@ -390,7 +390,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
{
|
||||
(Some(place_desc), Some(source_desc)) => self.cannot_move_out_of(
|
||||
span,
|
||||
&format!("`{}` which is behind a {}", place_desc, source_desc),
|
||||
&format!("`{place_desc}` which is behind a {source_desc}"),
|
||||
),
|
||||
(_, _) => self.cannot_move_out_of(
|
||||
span,
|
||||
@ -435,7 +435,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"consider borrowing here",
|
||||
format!("&{}", snippet),
|
||||
format!("&{snippet}"),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
@ -443,7 +443,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
if binds_to.is_empty() {
|
||||
let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
|
||||
let place_desc = match self.describe_place(move_from.as_ref()) {
|
||||
Some(desc) => format!("`{}`", desc),
|
||||
Some(desc) => format!("`{desc}`"),
|
||||
None => "value".to_string(),
|
||||
};
|
||||
|
||||
@ -472,12 +472,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
let span = use_spans.var_or_use();
|
||||
let place_ty = original_path.ty(self.body, self.infcx.tcx).ty;
|
||||
let place_desc = match self.describe_place(original_path.as_ref()) {
|
||||
Some(desc) => format!("`{}`", desc),
|
||||
Some(desc) => format!("`{desc}`"),
|
||||
None => "value".to_string(),
|
||||
};
|
||||
self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), "");
|
||||
|
||||
use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc));
|
||||
use_spans.args_span_label(err, format!("move out of {place_desc} occurs here"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -511,7 +511,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
for (span, to_remove, suggestion) in suggestions {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
&format!("consider removing the `{}`", to_remove),
|
||||
&format!("consider removing the `{to_remove}`"),
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
@ -55,7 +55,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
reason = ", as it is not declared as mutable".to_string();
|
||||
} else {
|
||||
let name = self.local_names[local].expect("immutable unnamed local");
|
||||
reason = format!(", as `{}` is not declared as mutable", name);
|
||||
reason = format!(", as `{name}` is not declared as mutable");
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
reason = ", as it is not declared as mutable".to_string();
|
||||
} else {
|
||||
let name = self.upvars[upvar_index.index()].place.to_string(self.infcx.tcx);
|
||||
reason = format!(", as `{}` is not declared as mutable", name);
|
||||
reason = format!(", as `{name}` is not declared as mutable");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -103,14 +103,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
if self.body.local_decls[local].is_ref_to_static() =>
|
||||
{
|
||||
if access_place.projection.len() == 1 {
|
||||
item_msg = format!("immutable static item {}", access_place_desc);
|
||||
item_msg = format!("immutable static item {access_place_desc}");
|
||||
reason = String::new();
|
||||
} else {
|
||||
item_msg = access_place_desc;
|
||||
let local_info = &self.body.local_decls[local].local_info;
|
||||
if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
|
||||
let static_name = &self.infcx.tcx.item_name(def_id);
|
||||
reason = format!(", as `{}` is an immutable static item", static_name);
|
||||
reason = format!(", as `{static_name}` is an immutable static item");
|
||||
} else {
|
||||
bug!("is_ref_to_static return true, but not ref to static?");
|
||||
}
|
||||
@ -148,15 +148,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
let pointer_type = source.describe_for_immutable_place(self.infcx.tcx);
|
||||
opt_source = Some(source);
|
||||
if let Some(desc) = self.describe_place(access_place.as_ref()) {
|
||||
item_msg = format!("`{}`", desc);
|
||||
item_msg = format!("`{desc}`");
|
||||
reason = match error_access {
|
||||
AccessKind::Mutate => format!(", which is behind {}", pointer_type),
|
||||
AccessKind::Mutate => format!(", which is behind {pointer_type}"),
|
||||
AccessKind::MutableBorrow => {
|
||||
format!(", as it is behind {}", pointer_type)
|
||||
format!(", as it is behind {pointer_type}")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
item_msg = format!("data in {}", pointer_type);
|
||||
item_msg = format!("data in {pointer_type}");
|
||||
reason = String::new();
|
||||
}
|
||||
}
|
||||
@ -362,29 +362,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
let upvar_hir_id = captured_place.get_root_variable();
|
||||
|
||||
if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_hir_id) {
|
||||
if let hir::PatKind::Binding(
|
||||
if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
|
||||
&& let hir::PatKind::Binding(
|
||||
hir::BindingAnnotation::Unannotated,
|
||||
_,
|
||||
upvar_ident,
|
||||
_,
|
||||
) = pat.kind
|
||||
{
|
||||
err.span_suggestion(
|
||||
upvar_ident.span,
|
||||
"consider changing this to be mutable",
|
||||
format!("mut {}", upvar_ident.name),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
{
|
||||
err.span_suggestion(
|
||||
upvar_ident.span,
|
||||
"consider changing this to be mutable",
|
||||
format!("mut {}", upvar_ident.name),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind()
|
||||
&& let ty::Closure(id, _) = *ty.kind()
|
||||
{
|
||||
if let ty::Closure(id, _) = *ty.kind() {
|
||||
self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
|
||||
}
|
||||
self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
|
||||
}
|
||||
}
|
||||
|
||||
@ -544,8 +542,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
err.span_suggestion(
|
||||
err_help_span,
|
||||
&format!(
|
||||
"consider changing this to be a mutable {}",
|
||||
pointer_desc
|
||||
"consider changing this to be a mutable {pointer_desc}"
|
||||
),
|
||||
suggested_code,
|
||||
Applicability::MachineApplicable,
|
||||
@ -554,8 +551,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
err.span_suggestion(
|
||||
x,
|
||||
&format!(
|
||||
"consider changing that to be a mutable {}",
|
||||
pointer_desc
|
||||
"consider changing that to be a mutable {pointer_desc}"
|
||||
),
|
||||
suggested_code,
|
||||
Applicability::MachineApplicable,
|
||||
@ -606,15 +602,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
Some(BorrowedContentSource::OverloadedDeref(ty)) => {
|
||||
err.help(&format!(
|
||||
"trait `DerefMut` is required to modify through a dereference, \
|
||||
but it is not implemented for `{}`",
|
||||
ty,
|
||||
but it is not implemented for `{ty}`",
|
||||
));
|
||||
}
|
||||
Some(BorrowedContentSource::OverloadedIndex(ty)) => {
|
||||
err.help(&format!(
|
||||
"trait `IndexMut` is required to modify indexed content, \
|
||||
but it is not implemented for `{}`",
|
||||
ty,
|
||||
but it is not implemented for `{ty}`",
|
||||
));
|
||||
}
|
||||
_ => (),
|
||||
@ -724,18 +718,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
ty::UpvarCapture::ByRef(
|
||||
ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
|
||||
) => {
|
||||
capture_reason = format!("mutable borrow of `{}`", upvar);
|
||||
capture_reason = format!("mutable borrow of `{upvar}`");
|
||||
}
|
||||
ty::UpvarCapture::ByValue => {
|
||||
capture_reason = format!("possible mutation of `{}`", upvar);
|
||||
capture_reason = format!("possible mutation of `{upvar}`");
|
||||
}
|
||||
_ => bug!("upvar `{}` borrowed, but not mutably", upvar),
|
||||
_ => bug!("upvar `{upvar}` borrowed, but not mutably"),
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if capture_reason.is_empty() {
|
||||
bug!("upvar `{}` borrowed, but cannot find reason", upvar);
|
||||
bug!("upvar `{upvar}` borrowed, but cannot find reason");
|
||||
}
|
||||
capture_reason
|
||||
} else {
|
||||
@ -829,19 +823,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
.as_str()
|
||||
.starts_with(&original_method_ident.name.to_string())
|
||||
})
|
||||
.map(|ident| format!("{}()", ident))
|
||||
.map(|ident| format!("{ident}()"))
|
||||
.peekable()
|
||||
});
|
||||
|
||||
if let Some(mut suggestions) = opt_suggestions {
|
||||
if suggestions.peek().is_some() {
|
||||
err.span_suggestions(
|
||||
*span,
|
||||
"use mutable method",
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
if let Some(mut suggestions) = opt_suggestions
|
||||
&& suggestions.peek().is_some()
|
||||
{
|
||||
err.span_suggestions(
|
||||
*span,
|
||||
"use mutable method",
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -849,7 +843,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
/// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
|
||||
fn expected_fn_found_fn_mut_call(&self, err: &mut Diagnostic, sp: Span, act: &str) {
|
||||
err.span_label(sp, format!("cannot {}", act));
|
||||
err.span_label(sp, format!("cannot {act}"));
|
||||
|
||||
let hir = self.infcx.tcx.hir();
|
||||
let closure_id = self.mir_hir_id();
|
||||
@ -1011,35 +1005,35 @@ fn suggest_ampmut<'tcx>(
|
||||
opt_assignment_rhs_span: Option<Span>,
|
||||
opt_ty_info: Option<Span>,
|
||||
) -> (Span, String) {
|
||||
if let Some(assignment_rhs_span) = opt_assignment_rhs_span {
|
||||
if let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) {
|
||||
let is_mutbl = |ty: &str| -> bool {
|
||||
if let Some(rest) = ty.strip_prefix("mut") {
|
||||
match rest.chars().next() {
|
||||
// e.g. `&mut x`
|
||||
Some(c) if c.is_whitespace() => true,
|
||||
// e.g. `&mut(x)`
|
||||
Some('(') => true,
|
||||
// e.g. `&mut{x}`
|
||||
Some('{') => true,
|
||||
// e.g. `&mutablevar`
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) {
|
||||
let lt_name = &src[1..ws_pos];
|
||||
let ty = src[ws_pos..].trim_start();
|
||||
if !is_mutbl(ty) {
|
||||
return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty));
|
||||
}
|
||||
} else if let Some(stripped) = src.strip_prefix('&') {
|
||||
let stripped = stripped.trim_start();
|
||||
if !is_mutbl(stripped) {
|
||||
return (assignment_rhs_span, format!("&mut {}", stripped));
|
||||
if let Some(assignment_rhs_span) = opt_assignment_rhs_span
|
||||
&& let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span)
|
||||
{
|
||||
let is_mutbl = |ty: &str| -> bool {
|
||||
if let Some(rest) = ty.strip_prefix("mut") {
|
||||
match rest.chars().next() {
|
||||
// e.g. `&mut x`
|
||||
Some(c) if c.is_whitespace() => true,
|
||||
// e.g. `&mut(x)`
|
||||
Some('(') => true,
|
||||
// e.g. `&mut{x}`
|
||||
Some('{') => true,
|
||||
// e.g. `&mutablevar`
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) {
|
||||
let lt_name = &src[1..ws_pos];
|
||||
let ty = src[ws_pos..].trim_start();
|
||||
if !is_mutbl(ty) {
|
||||
return (assignment_rhs_span, format!("&{lt_name} mut {ty}"));
|
||||
}
|
||||
} else if let Some(stripped) = src.strip_prefix('&') {
|
||||
let stripped = stripped.trim_start();
|
||||
if !is_mutbl(stripped) {
|
||||
return (assignment_rhs_span, format!("&mut {stripped}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1054,12 +1048,12 @@ fn suggest_ampmut<'tcx>(
|
||||
None => local_decl.source_info.span,
|
||||
};
|
||||
|
||||
if let Ok(src) = tcx.sess.source_map().span_to_snippet(highlight_span) {
|
||||
if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) {
|
||||
let lt_name = &src[1..ws_pos];
|
||||
let ty = &src[ws_pos..];
|
||||
return (highlight_span, format!("&{} mut{}", lt_name, ty));
|
||||
}
|
||||
if let Ok(src) = tcx.sess.source_map().span_to_snippet(highlight_span)
|
||||
&& let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace))
|
||||
{
|
||||
let lt_name = &src[1..ws_pos];
|
||||
let ty = &src[ws_pos..];
|
||||
return (highlight_span, format!("&{} mut{}", lt_name, ty));
|
||||
}
|
||||
|
||||
let ty_mut = local_decl.ty.builtin_deref(true).unwrap();
|
||||
|
@ -168,13 +168,12 @@ impl OutlivesSuggestionBuilder {
|
||||
let fr_name = self.region_vid_to_name(mbcx, errci.fr);
|
||||
let outlived_fr_name = self.region_vid_to_name(mbcx, errci.outlived_fr);
|
||||
|
||||
if let (Some(fr_name), Some(outlived_fr_name)) = (fr_name, outlived_fr_name) {
|
||||
if !matches!(outlived_fr_name.source, RegionNameSource::Static) {
|
||||
diag.help(&format!(
|
||||
"consider adding the following bound: `{}: {}`",
|
||||
fr_name, outlived_fr_name
|
||||
));
|
||||
}
|
||||
if let (Some(fr_name), Some(outlived_fr_name)) = (fr_name, outlived_fr_name)
|
||||
&& !matches!(outlived_fr_name.source, RegionNameSource::Static)
|
||||
{
|
||||
diag.help(&format!(
|
||||
"consider adding the following bound: `{fr_name}: {outlived_fr_name}`",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -337,7 +337,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
ty::Ref(_, inner_ty, mutbl) => {
|
||||
assert_eq!(*mutbl, rustc_hir::Mutability::Mut);
|
||||
(
|
||||
format!("a mutable reference to `{}`", inner_ty),
|
||||
format!("a mutable reference to `{inner_ty}`"),
|
||||
"mutable references are invariant over their type parameter"
|
||||
.to_string(),
|
||||
)
|
||||
@ -523,10 +523,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
|
||||
diag.span_label(
|
||||
outlived_fr_span,
|
||||
format!(
|
||||
"`{}` declared here, outside of the {} body",
|
||||
outlived_fr_name, escapes_from
|
||||
),
|
||||
format!("`{outlived_fr_name}` declared here, outside of the {escapes_from} body",),
|
||||
);
|
||||
}
|
||||
|
||||
@ -534,12 +531,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
diag.span_label(
|
||||
fr_span,
|
||||
format!(
|
||||
"`{}` is a reference that is only valid in the {} body",
|
||||
fr_name, escapes_from
|
||||
"`{fr_name}` is a reference that is only valid in the {escapes_from} body",
|
||||
),
|
||||
);
|
||||
|
||||
diag.span_label(*span, format!("`{}` escapes the {} body here", fr_name, escapes_from));
|
||||
diag.span_label(*span, format!("`{fr_name}` escapes the {escapes_from} body here"));
|
||||
}
|
||||
|
||||
// Only show an extra note if we can find an 'error region' for both of the region
|
||||
@ -611,9 +607,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
diag.span_label(
|
||||
*span,
|
||||
format!(
|
||||
"{} was supposed to return data with lifetime `{}` but it is returning \
|
||||
data with lifetime `{}`",
|
||||
mir_def_name, outlived_fr_name, fr_name
|
||||
"{mir_def_name} was supposed to return data with lifetime `{outlived_fr_name}` but it is returning \
|
||||
data with lifetime `{fr_name}`",
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -698,7 +693,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
// If there is a static predicate, then the only sensible suggestion is to replace
|
||||
// fr with `'static`.
|
||||
if has_static_predicate {
|
||||
diag.help(&format!("consider replacing `{}` with `{}`", fr_name, static_str));
|
||||
diag.help(&format!("consider replacing `{fr_name}` with `{static_str}`"));
|
||||
} else {
|
||||
// Otherwise, we should suggest adding a constraint on the return type.
|
||||
let span = self.infcx.tcx.def_span(did);
|
||||
@ -714,14 +709,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
} else {
|
||||
span
|
||||
};
|
||||
let suggestion = format!(" + {}", suggestable_fr_name);
|
||||
let suggestion = format!(" + {suggestable_fr_name}");
|
||||
let span = span.shrink_to_hi();
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
&format!(
|
||||
"to allow this `impl Trait` to capture borrowed data with lifetime \
|
||||
`{}`, add `{}` as a bound",
|
||||
fr_name, suggestable_fr_name,
|
||||
`{fr_name}`, add `{suggestable_fr_name}` as a bound",
|
||||
),
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
|
@ -102,27 +102,24 @@ impl RegionName {
|
||||
match &self.source {
|
||||
RegionNameSource::NamedFreeRegion(span)
|
||||
| RegionNameSource::NamedEarlyBoundRegion(span) => {
|
||||
diag.span_label(*span, format!("lifetime `{}` defined here", self));
|
||||
diag.span_label(*span, format!("lifetime `{self}` defined here"));
|
||||
}
|
||||
RegionNameSource::SynthesizedFreeEnvRegion(span, note) => {
|
||||
diag.span_label(
|
||||
*span,
|
||||
format!("lifetime `{}` represents this closure's body", self),
|
||||
);
|
||||
diag.span_label(*span, format!("lifetime `{self}` represents this closure's body"));
|
||||
diag.note(note);
|
||||
}
|
||||
RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::CannotMatchHirTy(
|
||||
span,
|
||||
type_name,
|
||||
)) => {
|
||||
diag.span_label(*span, format!("has type `{}`", type_name));
|
||||
diag.span_label(*span, format!("has type `{type_name}`"));
|
||||
}
|
||||
RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::MatchedHirTy(span))
|
||||
| RegionNameSource::AnonRegionFromOutput(RegionNameHighlight::MatchedHirTy(span), _)
|
||||
| RegionNameSource::AnonRegionFromAsyncFn(span) => {
|
||||
diag.span_label(
|
||||
*span,
|
||||
format!("let's call the lifetime of this reference `{}`", self),
|
||||
format!("let's call the lifetime of this reference `{self}`"),
|
||||
);
|
||||
}
|
||||
RegionNameSource::AnonRegionFromArgument(
|
||||
@ -132,7 +129,7 @@ impl RegionName {
|
||||
RegionNameHighlight::MatchedAdtAndSegment(span),
|
||||
_,
|
||||
) => {
|
||||
diag.span_label(*span, format!("let's call this `{}`", self));
|
||||
diag.span_label(*span, format!("let's call this `{self}`"));
|
||||
}
|
||||
RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::Occluded(
|
||||
span,
|
||||
@ -140,7 +137,7 @@ impl RegionName {
|
||||
)) => {
|
||||
diag.span_label(
|
||||
*span,
|
||||
format!("lifetime `{}` appears in the type {}", self, type_name),
|
||||
format!("lifetime `{self}` appears in the type {type_name}"),
|
||||
);
|
||||
}
|
||||
RegionNameSource::AnonRegionFromOutput(
|
||||
@ -150,25 +147,24 @@ impl RegionName {
|
||||
diag.span_label(
|
||||
*span,
|
||||
format!(
|
||||
"return type{} `{}` contains a lifetime `{}`",
|
||||
mir_description, type_name, self
|
||||
"return type{mir_description} `{type_name}` contains a lifetime `{self}`"
|
||||
),
|
||||
);
|
||||
}
|
||||
RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => {
|
||||
diag.span_label(
|
||||
*span,
|
||||
format!("lifetime `{}` appears in the type of `{}`", self, upvar_name),
|
||||
format!("lifetime `{self}` appears in the type of `{upvar_name}`"),
|
||||
);
|
||||
}
|
||||
RegionNameSource::AnonRegionFromOutput(
|
||||
RegionNameHighlight::CannotMatchHirTy(span, type_name),
|
||||
mir_description,
|
||||
) => {
|
||||
diag.span_label(*span, format!("return type{} is {}", mir_description, type_name));
|
||||
diag.span_label(*span, format!("return type{mir_description} is {type_name}"));
|
||||
}
|
||||
RegionNameSource::AnonRegionFromYieldTy(span, type_name) => {
|
||||
diag.span_label(*span, format!("yield type is {}", type_name));
|
||||
diag.span_label(*span, format!("yield type is {type_name}"));
|
||||
}
|
||||
RegionNameSource::Static => {}
|
||||
}
|
||||
@ -442,7 +438,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
"highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
|
||||
type_name, needle_fr
|
||||
);
|
||||
if type_name.contains(&format!("'{}", counter)) {
|
||||
if type_name.contains(&format!("'{counter}")) {
|
||||
// Only add a label if we can confirm that a region was labelled.
|
||||
RegionNameHighlight::CannotMatchHirTy(span, type_name)
|
||||
} else {
|
||||
@ -809,7 +805,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
// Note: generators from `async fn` yield `()`, so we don't have to
|
||||
// worry about them here.
|
||||
let yield_ty = self.regioncx.universal_regions().yield_ty?;
|
||||
debug!("give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}", yield_ty,);
|
||||
debug!("give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}", yield_ty);
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
|
@ -167,17 +167,18 @@ pub(super) fn op_to_const<'tcx>(
|
||||
},
|
||||
Immediate::ScalarPair(a, b) => {
|
||||
// We know `offset` is relative to the allocation, so we can use `into_parts`.
|
||||
let (data, start) = match ecx.scalar_to_ptr(a.check_init().unwrap()).into_parts() {
|
||||
(Some(alloc_id), offset) => {
|
||||
(ecx.tcx.global_alloc(alloc_id).unwrap_memory(), offset.bytes())
|
||||
}
|
||||
(None, _offset) => (
|
||||
ecx.tcx.intern_const_alloc(Allocation::from_bytes_byte_aligned_immutable(
|
||||
b"" as &[u8],
|
||||
)),
|
||||
0,
|
||||
),
|
||||
};
|
||||
let (data, start) =
|
||||
match ecx.scalar_to_ptr(a.check_init().unwrap()).unwrap().into_parts() {
|
||||
(Some(alloc_id), offset) => {
|
||||
(ecx.tcx.global_alloc(alloc_id).unwrap_memory(), offset.bytes())
|
||||
}
|
||||
(None, _offset) => (
|
||||
ecx.tcx.intern_const_alloc(
|
||||
Allocation::from_bytes_byte_aligned_immutable(b"" as &[u8]),
|
||||
),
|
||||
0,
|
||||
),
|
||||
};
|
||||
let len = b.to_machine_usize(ecx).unwrap();
|
||||
let start = start.try_into().unwrap();
|
||||
let len: usize = len.try_into().unwrap();
|
||||
|
@ -197,8 +197,8 @@ impl interpret::MayLeak for ! {
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||
fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> bool {
|
||||
match (a, b) {
|
||||
fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, bool> {
|
||||
Ok(match (a, b) {
|
||||
// Comparisons between integers are always known.
|
||||
(Scalar::Int { .. }, Scalar::Int { .. }) => a == b,
|
||||
// Equality with integers can never be known for sure.
|
||||
@ -207,11 +207,11 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||
// some things (like functions and vtables) do not have stable addresses
|
||||
// so we need to be careful around them (see e.g. #73722).
|
||||
(Scalar::Ptr(..), Scalar::Ptr(..)) => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> bool {
|
||||
match (a, b) {
|
||||
fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, bool> {
|
||||
Ok(match (a, b) {
|
||||
// Comparisons between integers are always known.
|
||||
(Scalar::Int(_), Scalar::Int(_)) => a != b,
|
||||
// Comparisons of abstract pointers with null pointers are known if the pointer
|
||||
@ -219,13 +219,13 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||
// Inequality with integers other than null can never be known for sure.
|
||||
(Scalar::Int(int), ptr @ Scalar::Ptr(..))
|
||||
| (ptr @ Scalar::Ptr(..), Scalar::Int(int)) => {
|
||||
int.is_null() && !self.scalar_may_be_null(ptr)
|
||||
int.is_null() && !self.scalar_may_be_null(ptr)?
|
||||
}
|
||||
// FIXME: return `true` for at least some comparisons where we can reliably
|
||||
// determine the result of runtime inequality tests at compile-time.
|
||||
// Examples include comparison of addresses in different static items.
|
||||
(Scalar::Ptr(..), Scalar::Ptr(..)) => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,9 +329,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||
let a = ecx.read_immediate(&args[0])?.to_scalar()?;
|
||||
let b = ecx.read_immediate(&args[1])?.to_scalar()?;
|
||||
let cmp = if intrinsic_name == sym::ptr_guaranteed_eq {
|
||||
ecx.guaranteed_eq(a, b)
|
||||
ecx.guaranteed_eq(a, b)?
|
||||
} else {
|
||||
ecx.guaranteed_ne(a, b)
|
||||
ecx.guaranteed_ne(a, b)?
|
||||
};
|
||||
ecx.write_scalar(Scalar::from_bool(cmp), dest)?;
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
if let Some(entry_idx) = vptr_entry_idx {
|
||||
let entry_idx = u64::try_from(entry_idx).unwrap();
|
||||
let (old_data, old_vptr) = val.to_scalar_pair()?;
|
||||
let old_vptr = self.scalar_to_ptr(old_vptr);
|
||||
let old_vptr = self.scalar_to_ptr(old_vptr)?;
|
||||
let new_vptr = self
|
||||
.read_new_vtable_after_trait_upcasting_from_vtable(old_vptr, entry_idx)?;
|
||||
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
|
||||
|
@ -640,7 +640,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Ok(Some((size, align)))
|
||||
}
|
||||
ty::Dynamic(..) => {
|
||||
let vtable = self.scalar_to_ptr(metadata.unwrap_meta());
|
||||
let vtable = self.scalar_to_ptr(metadata.unwrap_meta())?;
|
||||
// Read size and align from vtable (already checks size).
|
||||
Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
|
||||
if let ty::Dynamic(..) =
|
||||
tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind()
|
||||
{
|
||||
let ptr = self.ecx.scalar_to_ptr(mplace.meta.unwrap_meta());
|
||||
let ptr = self.ecx.scalar_to_ptr(mplace.meta.unwrap_meta())?;
|
||||
if let Some(alloc_id) = ptr.provenance {
|
||||
// Explicitly choose const mode here, since vtables are immutable, even
|
||||
// if the reference of the fat pointer is mutable.
|
||||
|
@ -1102,30 +1102,38 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
/// Machine pointer introspection.
|
||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
pub fn scalar_to_ptr(&self, scalar: Scalar<M::PointerTag>) -> Pointer<Option<M::PointerTag>> {
|
||||
pub fn scalar_to_ptr(
|
||||
&self,
|
||||
scalar: Scalar<M::PointerTag>,
|
||||
) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
|
||||
// We use `to_bits_or_ptr_internal` since we are just implementing the method people need to
|
||||
// call to force getting out a pointer.
|
||||
match scalar.to_bits_or_ptr_internal(self.pointer_size()) {
|
||||
Err(ptr) => ptr.into(),
|
||||
Ok(bits) => {
|
||||
let addr = u64::try_from(bits).unwrap();
|
||||
let ptr = M::ptr_from_addr(&self, addr);
|
||||
if addr == 0 {
|
||||
assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId");
|
||||
Ok(
|
||||
match scalar
|
||||
.to_bits_or_ptr_internal(self.pointer_size())
|
||||
.map_err(|s| err_ub!(ScalarSizeMismatch(s)))?
|
||||
{
|
||||
Err(ptr) => ptr.into(),
|
||||
Ok(bits) => {
|
||||
let addr = u64::try_from(bits).unwrap();
|
||||
let ptr = M::ptr_from_addr(&self, addr);
|
||||
if addr == 0 {
|
||||
assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId");
|
||||
}
|
||||
ptr
|
||||
}
|
||||
ptr
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Test if this value might be null.
|
||||
/// If the machine does not support ptr-to-int casts, this is conservative.
|
||||
pub fn scalar_may_be_null(&self, scalar: Scalar<M::PointerTag>) -> bool {
|
||||
match scalar.try_to_int() {
|
||||
pub fn scalar_may_be_null(&self, scalar: Scalar<M::PointerTag>) -> InterpResult<'tcx, bool> {
|
||||
Ok(match scalar.try_to_int() {
|
||||
Ok(int) => int.is_null(),
|
||||
Err(_) => {
|
||||
// Can only happen during CTFE.
|
||||
let ptr = self.scalar_to_ptr(scalar);
|
||||
let ptr = self.scalar_to_ptr(scalar)?;
|
||||
match self.ptr_try_get_alloc_id(ptr) {
|
||||
Ok((alloc_id, offset, _)) => {
|
||||
let (size, _align) = self
|
||||
@ -1138,7 +1146,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Err(_offset) => bug!("a non-int scalar is always a pointer"),
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Turning a "maybe pointer" into a proper pointer (and some information
|
||||
|
@ -342,7 +342,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
&self,
|
||||
op: &OpTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
|
||||
Ok(self.scalar_to_ptr(self.read_scalar(op)?.check_init()?))
|
||||
self.scalar_to_ptr(self.read_scalar(op)?.check_init()?)
|
||||
}
|
||||
|
||||
// Turn the wide MPlace into a string (must already be dereferenced!)
|
||||
@ -738,7 +738,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// okay. Everything else, we conservatively reject.
|
||||
let ptr_valid = niche_start == 0
|
||||
&& variants_start == variants_end
|
||||
&& !self.scalar_may_be_null(tag_val);
|
||||
&& !self.scalar_may_be_null(tag_val)?;
|
||||
if !ptr_valid {
|
||||
throw_ub!(InvalidTag(dbg_val))
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ where
|
||||
};
|
||||
|
||||
let mplace = MemPlace {
|
||||
ptr: self.scalar_to_ptr(ptr.check_init()?),
|
||||
ptr: self.scalar_to_ptr(ptr.check_init()?)?,
|
||||
// We could use the run-time alignment here. For now, we do not, because
|
||||
// the point of tracking the alignment here is to make sure that the *static*
|
||||
// alignment information emitted with the loads is correct. The run-time
|
||||
@ -1104,7 +1104,7 @@ where
|
||||
&self,
|
||||
mplace: &MPlaceTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
|
||||
let vtable = self.scalar_to_ptr(mplace.vtable()); // also sanity checks the type
|
||||
let vtable = self.scalar_to_ptr(mplace.vtable())?; // also sanity checks the type
|
||||
let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
|
||||
let layout = self.layout_of(ty)?;
|
||||
|
||||
|
@ -519,7 +519,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
.kind(),
|
||||
ty::Dynamic(..)
|
||||
));
|
||||
let vtable = self.scalar_to_ptr(receiver_place.meta.unwrap_meta());
|
||||
let vtable = self.scalar_to_ptr(receiver_place.meta.unwrap_meta())?;
|
||||
let fn_val = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?;
|
||||
|
||||
// `*mut receiver_place.layout.ty` is almost the layout that we
|
||||
|
@ -50,7 +50,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let vtable_slot = self
|
||||
.get_ptr_alloc(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)?
|
||||
.expect("cannot be a ZST");
|
||||
let fn_ptr = self.scalar_to_ptr(vtable_slot.read_ptr_sized(Size::ZERO)?.check_init()?);
|
||||
let fn_ptr = self.scalar_to_ptr(vtable_slot.read_ptr_sized(Size::ZERO)?.check_init()?)?;
|
||||
self.get_ptr_fn(fn_ptr)
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
.check_init()?;
|
||||
// We *need* an instance here, no other kind of function value, to be able
|
||||
// to determine the type.
|
||||
let drop_instance = self.get_ptr_fn(self.scalar_to_ptr(drop_fn))?.as_instance()?;
|
||||
let drop_instance = self.get_ptr_fn(self.scalar_to_ptr(drop_fn)?)?.as_instance()?;
|
||||
trace!("Found drop fn: {:?}", drop_instance);
|
||||
let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx);
|
||||
let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig);
|
||||
@ -132,7 +132,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
.get_ptr_alloc(vtable_slot, pointer_size, self.tcx.data_layout.pointer_align.abi)?
|
||||
.expect("cannot be a ZST");
|
||||
|
||||
let new_vtable = self.scalar_to_ptr(new_vtable.read_ptr_sized(Size::ZERO)?.check_init()?);
|
||||
let new_vtable =
|
||||
self.scalar_to_ptr(new_vtable.read_ptr_sized(Size::ZERO)?.check_init()?)?;
|
||||
|
||||
Ok(new_vtable)
|
||||
}
|
||||
|
@ -312,7 +312,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
|
||||
match tail.kind() {
|
||||
ty::Dynamic(..) => {
|
||||
let vtable = self.ecx.scalar_to_ptr(meta.unwrap_meta());
|
||||
let vtable = self.ecx.scalar_to_ptr(meta.unwrap_meta())?;
|
||||
// Direct call to `check_ptr_access_align` checks alignment even on CTFE machines.
|
||||
try_validation!(
|
||||
self.ecx.check_ptr_access_align(
|
||||
@ -577,7 +577,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
|
||||
// If we check references recursively, also check that this points to a function.
|
||||
if let Some(_) = self.ref_tracking {
|
||||
let ptr = self.ecx.scalar_to_ptr(value);
|
||||
let ptr = self.ecx.scalar_to_ptr(value)?;
|
||||
let _fn = try_validation!(
|
||||
self.ecx.get_ptr_fn(ptr),
|
||||
self.path,
|
||||
@ -590,7 +590,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
// FIXME: Check if the signature matches
|
||||
} else {
|
||||
// Otherwise (for standalone Miri), we have to still check it to be non-null.
|
||||
if self.ecx.scalar_may_be_null(value) {
|
||||
if self.ecx.scalar_may_be_null(value)? {
|
||||
throw_validation_failure!(self.path, { "a null function pointer" });
|
||||
}
|
||||
}
|
||||
@ -667,7 +667,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
// We support 2 kinds of ranges here: full range, and excluding zero.
|
||||
if start == 1 && end == max_value {
|
||||
// Only null is the niche. So make sure the ptr is NOT null.
|
||||
if self.ecx.scalar_may_be_null(value) {
|
||||
if self.ecx.scalar_may_be_null(value)? {
|
||||
throw_validation_failure!(self.path,
|
||||
{ "a potentially null pointer" }
|
||||
expected {
|
||||
|
@ -15,8 +15,8 @@ use rustc_target::abi::{Align, HasDataLayout, Size};
|
||||
|
||||
use super::{
|
||||
read_target_uint, write_target_uint, AllocId, InterpError, InterpResult, Pointer, Provenance,
|
||||
ResourceExhaustionInfo, Scalar, ScalarMaybeUninit, UndefinedBehaviorInfo, UninitBytesAccess,
|
||||
UnsupportedOpInfo,
|
||||
ResourceExhaustionInfo, Scalar, ScalarMaybeUninit, ScalarSizeMismatch, UndefinedBehaviorInfo,
|
||||
UninitBytesAccess, UnsupportedOpInfo,
|
||||
};
|
||||
use crate::ty;
|
||||
|
||||
@ -81,6 +81,8 @@ impl<'tcx, Tag, Extra> ConstAllocation<'tcx, Tag, Extra> {
|
||||
/// is added when converting to `InterpError`.
|
||||
#[derive(Debug)]
|
||||
pub enum AllocError {
|
||||
/// A scalar had the wrong size.
|
||||
ScalarSizeMismatch(ScalarSizeMismatch),
|
||||
/// Encountered a pointer where we needed raw bytes.
|
||||
ReadPointerAsBytes,
|
||||
/// Partially overwriting a pointer.
|
||||
@ -90,10 +92,19 @@ pub enum AllocError {
|
||||
}
|
||||
pub type AllocResult<T = ()> = Result<T, AllocError>;
|
||||
|
||||
impl From<ScalarSizeMismatch> for AllocError {
|
||||
fn from(s: ScalarSizeMismatch) -> Self {
|
||||
AllocError::ScalarSizeMismatch(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl AllocError {
|
||||
pub fn to_interp_error<'tcx>(self, alloc_id: AllocId) -> InterpError<'tcx> {
|
||||
use AllocError::*;
|
||||
match self {
|
||||
ScalarSizeMismatch(s) => {
|
||||
InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ScalarSizeMismatch(s))
|
||||
}
|
||||
ReadPointerAsBytes => InterpError::Unsupported(UnsupportedOpInfo::ReadPointerAsBytes),
|
||||
PartialPointerOverwrite(offset) => InterpError::Unsupported(
|
||||
UnsupportedOpInfo::PartialPointerOverwrite(Pointer::new(alloc_id, offset)),
|
||||
@ -425,7 +436,7 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
|
||||
|
||||
// `to_bits_or_ptr_internal` is the right method because we just want to store this data
|
||||
// as-is into memory.
|
||||
let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size) {
|
||||
let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size)? {
|
||||
Err(val) => {
|
||||
let (provenance, offset) = val.into_parts();
|
||||
(u128::from(offset.bytes()), Some(provenance))
|
||||
|
@ -221,6 +221,13 @@ pub struct UninitBytesAccess {
|
||||
pub uninit_size: Size,
|
||||
}
|
||||
|
||||
/// Information about a size mismatch.
|
||||
#[derive(Debug)]
|
||||
pub struct ScalarSizeMismatch {
|
||||
pub target_size: u64,
|
||||
pub data_size: u64,
|
||||
}
|
||||
|
||||
/// Error information for when the program caused Undefined Behavior.
|
||||
pub enum UndefinedBehaviorInfo<'tcx> {
|
||||
/// Free-form case. Only for errors that are never caught!
|
||||
@ -298,10 +305,7 @@ pub enum UndefinedBehaviorInfo<'tcx> {
|
||||
/// Working with a local that is not currently live.
|
||||
DeadLocal,
|
||||
/// Data size is not equal to target size.
|
||||
ScalarSizeMismatch {
|
||||
target_size: u64,
|
||||
data_size: u64,
|
||||
},
|
||||
ScalarSizeMismatch(ScalarSizeMismatch),
|
||||
/// A discriminant of an uninhabited enum variant is written.
|
||||
UninhabitedEnumVariantWritten,
|
||||
}
|
||||
@ -408,7 +412,7 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
|
||||
"using uninitialized data, but this operation requires initialized memory"
|
||||
),
|
||||
DeadLocal => write!(f, "accessing a dead local variable"),
|
||||
ScalarSizeMismatch { target_size, data_size } => write!(
|
||||
ScalarSizeMismatch(self::ScalarSizeMismatch { target_size, data_size }) => write!(
|
||||
f,
|
||||
"scalar size mismatch: expected {} bytes but got {} bytes instead",
|
||||
target_size, data_size
|
||||
|
@ -120,7 +120,8 @@ use crate::ty::{self, Instance, Ty, TyCtxt};
|
||||
pub use self::error::{
|
||||
struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult,
|
||||
InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType,
|
||||
ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
|
||||
ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, UninitBytesAccess,
|
||||
UnsupportedOpInfo,
|
||||
};
|
||||
|
||||
pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit};
|
||||
|
@ -12,6 +12,7 @@ use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt};
|
||||
|
||||
use super::{
|
||||
AllocId, AllocRange, ConstAllocation, InterpResult, Pointer, PointerArithmetic, Provenance,
|
||||
ScalarSizeMismatch,
|
||||
};
|
||||
|
||||
/// Represents the result of const evaluation via the `eval_to_allocation` query.
|
||||
@ -300,16 +301,29 @@ impl<Tag> Scalar<Tag> {
|
||||
///
|
||||
/// This method only exists for the benefit of low-level operations that truly need to treat the
|
||||
/// scalar in whatever form it is.
|
||||
///
|
||||
/// This throws UB (instead of ICEing) on a size mismatch since size mismatches can arise in
|
||||
/// Miri when someone declares a function that we shim (such as `malloc`) with a wrong type.
|
||||
#[inline]
|
||||
pub fn to_bits_or_ptr_internal(self, target_size: Size) -> Result<u128, Pointer<Tag>> {
|
||||
pub fn to_bits_or_ptr_internal(
|
||||
self,
|
||||
target_size: Size,
|
||||
) -> Result<Result<u128, Pointer<Tag>>, ScalarSizeMismatch> {
|
||||
assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
|
||||
match self {
|
||||
Scalar::Int(int) => Ok(int.assert_bits(target_size)),
|
||||
Ok(match self {
|
||||
Scalar::Int(int) => Ok(int.to_bits(target_size).map_err(|size| {
|
||||
ScalarSizeMismatch { target_size: target_size.bytes(), data_size: size.bytes() }
|
||||
})?),
|
||||
Scalar::Ptr(ptr, sz) => {
|
||||
assert_eq!(target_size.bytes(), u64::from(sz));
|
||||
if target_size.bytes() != sz.into() {
|
||||
return Err(ScalarSizeMismatch {
|
||||
target_size: target_size.bytes(),
|
||||
data_size: sz.into(),
|
||||
});
|
||||
}
|
||||
Err(ptr)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -348,10 +362,10 @@ impl<'tcx, Tag: Provenance> Scalar<Tag> {
|
||||
assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
|
||||
self.try_to_int().map_err(|_| err_unsup!(ReadPointerAsBytes))?.to_bits(target_size).map_err(
|
||||
|size| {
|
||||
err_ub!(ScalarSizeMismatch {
|
||||
err_ub!(ScalarSizeMismatch(ScalarSizeMismatch {
|
||||
target_size: target_size.bytes(),
|
||||
data_size: size.bytes(),
|
||||
})
|
||||
}))
|
||||
.into()
|
||||
},
|
||||
)
|
||||
|
@ -146,7 +146,7 @@ impl IntRange {
|
||||
// straight to the result, after doing a bit of checking. (We
|
||||
// could remove this branch and just fall through, which
|
||||
// is more general but much slower.)
|
||||
if let Ok(bits) = scalar.to_bits_or_ptr_internal(target_size) {
|
||||
if let Ok(bits) = scalar.to_bits_or_ptr_internal(target_size).unwrap() {
|
||||
return Some(bits);
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ pub unsafe extern "C-unwind" fn __rust_start_panic(_payload: *mut &mut dyn BoxMe
|
||||
//
|
||||
// Note: this is the same implementation as in libstd's `abort_internal`
|
||||
unsafe fn abort() -> ! {
|
||||
#[allow(unused)]
|
||||
const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
use super::*;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
macro_rules! define_handles {
|
||||
(
|
||||
'owned: $($oty:ident,)*
|
||||
@ -45,20 +47,25 @@ macro_rules! define_handles {
|
||||
|
||||
$(
|
||||
#[repr(C)]
|
||||
pub(crate) struct $oty(handle::Handle);
|
||||
impl !Send for $oty {}
|
||||
impl !Sync for $oty {}
|
||||
pub(crate) struct $oty {
|
||||
handle: handle::Handle,
|
||||
// Prevent Send and Sync impls
|
||||
_marker: PhantomData<*mut ()>,
|
||||
}
|
||||
|
||||
// Forward `Drop::drop` to the inherent `drop` method.
|
||||
impl Drop for $oty {
|
||||
fn drop(&mut self) {
|
||||
$oty(self.0).drop();
|
||||
$oty {
|
||||
handle: self.handle,
|
||||
_marker: PhantomData,
|
||||
}.drop();
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for $oty {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
let handle = self.0;
|
||||
let handle = self.handle;
|
||||
mem::forget(self);
|
||||
handle.encode(w, s);
|
||||
}
|
||||
@ -74,7 +81,7 @@ macro_rules! define_handles {
|
||||
|
||||
impl<S> Encode<S> for &$oty {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
self.0.encode(w, s);
|
||||
self.handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,7 +95,7 @@ macro_rules! define_handles {
|
||||
|
||||
impl<S> Encode<S> for &mut $oty {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
self.0.encode(w, s);
|
||||
self.handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,7 +120,10 @@ macro_rules! define_handles {
|
||||
|
||||
impl<S> DecodeMut<'_, '_, S> for $oty {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
$oty(handle::Handle::decode(r, s))
|
||||
$oty {
|
||||
handle: handle::Handle::decode(r, s),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
@ -121,13 +131,15 @@ macro_rules! define_handles {
|
||||
$(
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct $ity(handle::Handle);
|
||||
impl !Send for $ity {}
|
||||
impl !Sync for $ity {}
|
||||
pub(crate) struct $ity {
|
||||
handle: handle::Handle,
|
||||
// Prevent Send and Sync impls
|
||||
_marker: PhantomData<*mut ()>,
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for $ity {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
self.0.encode(w, s);
|
||||
self.handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,7 +161,10 @@ macro_rules! define_handles {
|
||||
|
||||
impl<S> DecodeMut<'_, '_, S> for $ity {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
$ity(handle::Handle::decode(r, s))
|
||||
$ity {
|
||||
handle: handle::Handle::decode(r, s),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
@ -310,7 +325,8 @@ impl Bridge<'_> {
|
||||
// NB. the server can't do this because it may use a different libstd.
|
||||
static HIDE_PANICS_DURING_EXPANSION: Once = Once::new();
|
||||
HIDE_PANICS_DURING_EXPANSION.call_once(|| {
|
||||
panic::update_hook(move |prev, info| {
|
||||
let prev = panic::take_hook();
|
||||
panic::set_hook(Box::new(move |info| {
|
||||
let show = BridgeState::with(|state| match state {
|
||||
BridgeState::NotConnected => true,
|
||||
BridgeState::Connected(_) | BridgeState::InUse => force_show_panics,
|
||||
@ -318,7 +334,7 @@ impl Bridge<'_> {
|
||||
if show {
|
||||
prev(info)
|
||||
}
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
BRIDGE_STATE.with(|state| state.set(BridgeState::Connected(self), f))
|
||||
|
@ -1,24 +1,23 @@
|
||||
//! Closure type (equivalent to `&mut dyn FnMut(A) -> R`) that's `repr(C)`.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Closure<'a, A, R> {
|
||||
call: unsafe extern "C" fn(&mut Env, A) -> R,
|
||||
env: &'a mut Env,
|
||||
call: unsafe extern "C" fn(*mut Env, A) -> R,
|
||||
env: *mut Env,
|
||||
// Ensure Closure is !Send and !Sync
|
||||
_marker: PhantomData<*mut &'a mut ()>,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
type Env;
|
||||
}
|
||||
|
||||
impl<'a, A, R> !Sync for Closure<'a, A, R> {}
|
||||
impl<'a, A, R> !Send for Closure<'a, A, R> {}
|
||||
struct Env;
|
||||
|
||||
impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> {
|
||||
fn from(f: &'a mut F) -> Self {
|
||||
unsafe extern "C" fn call<A, R, F: FnMut(A) -> R>(env: &mut Env, arg: A) -> R {
|
||||
unsafe extern "C" fn call<A, R, F: FnMut(A) -> R>(env: *mut Env, arg: A) -> R {
|
||||
(*(env as *mut _ as *mut F))(arg)
|
||||
}
|
||||
Closure { call: call::<A, R, F>, env: unsafe { &mut *(f as *mut _ as *mut Env) } }
|
||||
Closure { call: call::<A, R, F>, env: f as *mut _ as *mut Env, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,10 +231,10 @@ pub struct Bridge<'a> {
|
||||
|
||||
/// If 'true', always invoke the default panic hook
|
||||
force_show_panics: bool,
|
||||
}
|
||||
|
||||
impl<'a> !Sync for Bridge<'a> {}
|
||||
impl<'a> !Send for Bridge<'a> {}
|
||||
// Prevent Send and Sync impls
|
||||
_marker: marker::PhantomData<*mut ()>,
|
||||
}
|
||||
|
||||
#[forbid(unsafe_code)]
|
||||
#[allow(non_camel_case_types)]
|
||||
|
@ -153,7 +153,12 @@ impl ExecutionStrategy for SameThread {
|
||||
let mut dispatch = |b| dispatcher.dispatch(b);
|
||||
|
||||
run_client(
|
||||
Bridge { cached_buffer: input, dispatch: (&mut dispatch).into(), force_show_panics },
|
||||
Bridge {
|
||||
cached_buffer: input,
|
||||
dispatch: (&mut dispatch).into(),
|
||||
force_show_panics,
|
||||
_marker: marker::PhantomData,
|
||||
},
|
||||
client_data,
|
||||
)
|
||||
}
|
||||
@ -189,6 +194,7 @@ impl ExecutionStrategy for CrossThread1 {
|
||||
cached_buffer: input,
|
||||
dispatch: (&mut dispatch).into(),
|
||||
force_show_panics,
|
||||
_marker: marker::PhantomData,
|
||||
},
|
||||
client_data,
|
||||
)
|
||||
@ -241,6 +247,7 @@ impl ExecutionStrategy for CrossThread2 {
|
||||
cached_buffer: input,
|
||||
dispatch: (&mut dispatch).into(),
|
||||
force_show_panics,
|
||||
_marker: marker::PhantomData,
|
||||
},
|
||||
client_data,
|
||||
);
|
||||
|
@ -17,18 +17,18 @@
|
||||
test(no_crate_inject, attr(deny(warnings))),
|
||||
test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
|
||||
)]
|
||||
// This library is copied into rust-analyzer to allow loading rustc compiled proc macros.
|
||||
// Please avoid unstable features where possible to minimize the amount of changes necessary
|
||||
// to make it compile with rust-analyzer on stable.
|
||||
#![feature(rustc_allow_const_fn_unstable)]
|
||||
#![feature(nll)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(allow_internal_unstable)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(auto_traits)]
|
||||
#![feature(restricted_std)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(panic_update_hook)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[unstable(feature = "proc_macro_internals", issue = "27812")]
|
||||
|
@ -289,6 +289,7 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD {
|
||||
/// that function for more information on `__fastfail`
|
||||
#[allow(unreachable_code)]
|
||||
pub fn abort_internal() -> ! {
|
||||
#[allow(unused)]
|
||||
const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
|
||||
#[cfg(not(miri))] // inline assembly does not work in Miri
|
||||
unsafe {
|
||||
|
@ -425,13 +425,26 @@ crate fn build_impl(
|
||||
None => (
|
||||
tcx.associated_items(did)
|
||||
.in_definition_order()
|
||||
.filter_map(|item| {
|
||||
if associated_trait.is_some() || item.vis.is_public() {
|
||||
Some(item.clean(cx))
|
||||
.filter(|item| {
|
||||
// If this is a trait impl, filter out associated items whose corresponding item
|
||||
// in the associated trait is marked `doc(hidden)`.
|
||||
// If this is an inherent impl, filter out private associated items.
|
||||
if let Some(associated_trait) = associated_trait {
|
||||
let trait_item = tcx
|
||||
.associated_items(associated_trait.def_id)
|
||||
.find_by_name_and_kind(
|
||||
tcx,
|
||||
item.ident(tcx),
|
||||
item.kind,
|
||||
associated_trait.def_id,
|
||||
)
|
||||
.unwrap(); // corresponding associated item has to exist
|
||||
!tcx.is_doc_hidden(trait_item.def_id)
|
||||
} else {
|
||||
None
|
||||
item.vis.is_public()
|
||||
}
|
||||
})
|
||||
.map(|item| item.clean(cx))
|
||||
.collect::<Vec<_>>(),
|
||||
clean::enter_impl_trait(cx, |cx| {
|
||||
clean_ty_generics(cx, tcx.generics_of(did), predicates)
|
||||
|
@ -0,0 +1,19 @@
|
||||
pub trait Tr {
|
||||
type VisibleAssoc;
|
||||
#[doc(hidden)]
|
||||
type HiddenAssoc;
|
||||
|
||||
const VISIBLE_ASSOC: ();
|
||||
#[doc(hidden)]
|
||||
const HIDDEN_ASSOC: ();
|
||||
}
|
||||
|
||||
pub struct Ty;
|
||||
|
||||
impl Tr for Ty {
|
||||
type VisibleAssoc = ();
|
||||
type HiddenAssoc = ();
|
||||
|
||||
const VISIBLE_ASSOC: () = ();
|
||||
const HIDDEN_ASSOC: () = ();
|
||||
}
|
23
src/test/rustdoc/cross-crate-hidden-assoc-trait-items.rs
Normal file
23
src/test/rustdoc/cross-crate-hidden-assoc-trait-items.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// Regression test for issue #95717
|
||||
// Hide cross-crate `#[doc(hidden)]` associated items in trait impls.
|
||||
|
||||
#![crate_name = "dependent"]
|
||||
// edition:2021
|
||||
// aux-crate:dependency=cross-crate-hidden-assoc-trait-items.rs
|
||||
|
||||
// The trait `Tr` contains 2 hidden and 2 visisible associated items.
|
||||
// Instead of checking for the absence of the hidden items, check for the presence of the
|
||||
// visible items instead and assert that there are *exactly two* associated items
|
||||
// (by counting the number of `section`s). This is more robust and future-proof.
|
||||
|
||||
// @has dependent/struct.Ty.html
|
||||
// @has - '//*[@id="associatedtype.VisibleAssoc"]' 'type VisibleAssoc = ()'
|
||||
// @has - '//*[@id="associatedconstant.VISIBLE_ASSOC"]' 'const VISIBLE_ASSOC: ()'
|
||||
// @count - '//*[@class="impl-items"]/section' 2
|
||||
|
||||
// @has dependent/trait.Tr.html
|
||||
// @has - '//*[@id="associatedtype.VisibleAssoc-1"]' 'type VisibleAssoc = ()'
|
||||
// @has - '//*[@id="associatedconstant.VISIBLE_ASSOC-1"]' 'const VISIBLE_ASSOC: ()'
|
||||
// @count - '//*[@class="impl-items"]/section' 2
|
||||
|
||||
pub use dependency::{Tr, Ty};
|
@ -1 +1 @@
|
||||
Subproject commit 3df74381f37617ec800537c11fb0c3130f5f3616
|
||||
Subproject commit e6f71c9cadf9bbd2eff21334d1d51016c7f5e19d
|
Loading…
Reference in New Issue
Block a user