Skip to content

Commit 818811b

Browse files
committed
Auto merge of rust-lang#156111 - JonathanBrouwer:rollup-8X18OBD, r=JonathanBrouwer
Rollup of 4 pull requests Successful merges: - rust-lang#156073 ([rustdoc] Fix `doc_cfg` feature on reexports) - rust-lang#152216 (Fix 'assign to data in an index of' collection suggestions) - rust-lang#155433 (Rip out rustc_layout_scalar_valid_range_* attribute support) - rust-lang#156098 (Hand-implement `impl Debug for NumBuffer` to avoid constraining `T` or printing MaybeUninit)
2 parents 54f67d2 + 0d98c12 commit 818811b

96 files changed

Lines changed: 1524 additions & 1893 deletions

File tree

Some content is hidden

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

compiler/rustc_abi/src/layout.rs

Lines changed: 1 addition & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::collections::BTreeSet;
22
use std::fmt::{self, Write};
3-
use std::ops::{Bound, Deref};
3+
use std::ops::Deref;
44
use std::{cmp, iter};
55

66
use rustc_hashes::Hash64;
@@ -348,7 +348,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
348348
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
349349
is_enum: bool,
350350
is_special_no_niche: bool,
351-
scalar_valid_range: (Bound<u128>, Bound<u128>),
352351
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
353352
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
354353
always_sized: bool,
@@ -380,7 +379,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
380379
variants,
381380
is_enum,
382381
is_special_no_niche,
383-
scalar_valid_range,
384382
always_sized,
385383
present_first,
386384
)
@@ -530,7 +528,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
530528
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
531529
is_enum: bool,
532530
is_special_no_niche: bool,
533-
scalar_valid_range: (Bound<u128>, Bound<u128>),
534531
always_sized: bool,
535532
present_first: VariantIdx,
536533
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
@@ -570,52 +567,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
570567
return Ok(st);
571568
}
572569

573-
let (start, end) = scalar_valid_range;
574-
match st.backend_repr {
575-
BackendRepr::Scalar(ref mut scalar) | BackendRepr::ScalarPair(ref mut scalar, _) => {
576-
// Enlarging validity ranges would result in missed
577-
// optimizations, *not* wrongly assuming the inner
578-
// value is valid. e.g. unions already enlarge validity ranges,
579-
// because the values may be uninitialized.
580-
//
581-
// Because of that we only check that the start and end
582-
// of the range is representable with this scalar type.
583-
584-
let max_value = scalar.size(dl).unsigned_int_max();
585-
if let Bound::Included(start) = start {
586-
// FIXME(eddyb) this might be incorrect - it doesn't
587-
// account for wrap-around (end < start) ranges.
588-
assert!(start <= max_value, "{start} > {max_value}");
589-
scalar.valid_range_mut().start = start;
590-
}
591-
if let Bound::Included(end) = end {
592-
// FIXME(eddyb) this might be incorrect - it doesn't
593-
// account for wrap-around (end < start) ranges.
594-
assert!(end <= max_value, "{end} > {max_value}");
595-
scalar.valid_range_mut().end = end;
596-
}
597-
598-
// Update `largest_niche` if we have introduced a larger niche.
599-
let niche = Niche::from_scalar(dl, Size::ZERO, *scalar);
600-
if let Some(niche) = niche {
601-
match st.largest_niche {
602-
Some(largest_niche) => {
603-
// Replace the existing niche even if they're equal,
604-
// because this one is at a lower offset.
605-
if largest_niche.available(dl) <= niche.available(dl) {
606-
st.largest_niche = Some(niche);
607-
}
608-
}
609-
None => st.largest_niche = Some(niche),
610-
}
611-
}
612-
}
613-
_ => assert!(
614-
start == Bound::Unbounded && end == Bound::Unbounded,
615-
"nonscalar layout for layout_scalar_valid_range type: {st:#?}",
616-
),
617-
}
618-
619570
Ok(st)
620571
}
621572

compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -92,32 +92,6 @@ impl NoArgsAttributeParser for RustcNoImplicitAutorefsParser {
9292
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitAutorefs;
9393
}
9494

95-
pub(crate) struct RustcLayoutScalarValidRangeStartParser;
96-
97-
impl SingleAttributeParser for RustcLayoutScalarValidRangeStartParser {
98-
const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
99-
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
100-
const TEMPLATE: AttributeTemplate = template!(List: &["start"]);
101-
102-
fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
103-
parse_single_integer(cx, args)
104-
.map(|n| AttributeKind::RustcLayoutScalarValidRangeStart(Box::new(n), cx.attr_span))
105-
}
106-
}
107-
108-
pub(crate) struct RustcLayoutScalarValidRangeEndParser;
109-
110-
impl SingleAttributeParser for RustcLayoutScalarValidRangeEndParser {
111-
const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
112-
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
113-
const TEMPLATE: AttributeTemplate = template!(List: &["end"]);
114-
115-
fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
116-
parse_single_integer(cx, args)
117-
.map(|n| AttributeKind::RustcLayoutScalarValidRangeEnd(Box::new(n), cx.attr_span))
118-
}
119-
}
120-
12195
pub(crate) struct RustcLegacyConstGenericsParser;
12296

12397
impl SingleAttributeParser for RustcLegacyConstGenericsParser {

compiler/rustc_attr_parsing/src/attributes/util.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
3333
/// Parse a single integer.
3434
///
3535
/// Used by attributes that take a single integer as argument, such as
36-
/// `#[link_ordinal]` and `#[rustc_layout_scalar_valid_range_start]`.
36+
/// `#[link_ordinal]`.
3737
/// `cx` is the context given to the attribute.
3838
/// `args` is the parser for the attribute arguments.
3939
pub(crate) fn parse_single_integer(

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,6 @@ attribute_parsers!(
208208
Single<RustcDumpSymbolNameParser>,
209209
Single<RustcForceInlineParser>,
210210
Single<RustcIfThisChangedParser>,
211-
Single<RustcLayoutScalarValidRangeEndParser>,
212-
Single<RustcLayoutScalarValidRangeStartParser>,
213211
Single<RustcLegacyConstGenericsParser>,
214212
Single<RustcLintOptDenyFieldAccessParser>,
215213
Single<RustcMacroTransparencyParser>,

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

Lines changed: 141 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_abi::FieldIdx;
66
use rustc_errors::{Applicability, Diag};
77
use rustc_hir::def_id::DefId;
88
use rustc_hir::intravisit::Visitor;
9-
use rustc_hir::{self as hir, BindingMode, ByRef, Node};
9+
use rustc_hir::{self as hir, BindingMode, ByRef, Expr, Node};
1010
use rustc_middle::bug;
1111
use rustc_middle::hir::place::PlaceBase;
1212
use rustc_middle::mir::visit::PlaceContext;
@@ -669,7 +669,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
669669
err: &'a mut Diag<'infcx>,
670670
ty: Ty<'tcx>,
671671
suggested: bool,
672+
infcx: &'a rustc_infer::infer::InferCtxt<'tcx>,
672673
}
674+
673675
impl<'a, 'infcx, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'infcx, 'tcx> {
674676
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
675677
hir::intravisit::walk_stmt(self, stmt);
@@ -680,60 +682,166 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
680682
return;
681683
}
682684
};
685+
686+
// Because of TypeChecking and indexing, we know: index is &Q
687+
// with K: Eq + Hash + Borrow<Q>,
688+
// with Q: Eq + Hash + ?Sized,
689+
//
690+
// which fulfill the requirements of `get_mut`. If Q=K or Q=&{n}K, the requirements
691+
// of `entry` and `insert` are fulfilled too after dereferencing. If K is not
692+
// copy, a subsequent `clone` call may be needed.
693+
694+
/// Taken straight from https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/fn.peel_hir_ty_refs.html
695+
/// Adapted to mid using https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.peel_refs
696+
/// Simplified to counting only
697+
/// Peels off all references on the type. Returns the number of references
698+
/// removed.
699+
fn count_ty_refs<'tcx>(mut ty: Ty<'tcx>) -> usize {
700+
let mut count = 0;
701+
while let ty::Ref(_, inner_ty, _) = ty.kind() {
702+
ty = *inner_ty;
703+
count += 1;
704+
}
705+
count
706+
}
707+
708+
/// Try to strip `n` `&` reference from an expression.
709+
/// If the expression does not have enough leading `&`, return an Error
710+
/// containing a count of the successfully stripped ones and the stripped
711+
/// expression.
712+
fn strip_n_refs<'a, 'b>(
713+
mut expr: &'a Expr<'b>,
714+
n: usize,
715+
) -> Result<&'a Expr<'b>, (usize, &'a Expr<'b>)> {
716+
for count in 0..n {
717+
match expr {
718+
Expr {
719+
kind: ExprKind::AddrOf(hir::BorrowKind::Ref, _, inner),
720+
..
721+
} => expr = inner,
722+
_ => return Err((count, expr)),
723+
}
724+
}
725+
Ok(expr)
726+
}
727+
728+
// we know ty is a map, with a key type at walk distance 2.
729+
let key_ty = self.ty.walk().nth(1).unwrap().expect_ty();
730+
683731
if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind
684732
&& let hir::ExprKind::Index(val, index, _) = place.kind
685733
&& (expr.span == self.assign_span || place.span == self.assign_span)
686734
{
687735
// val[index] = rv;
688-
// ---------- place
689-
self.err.multipart_suggestions(
690-
format!(
691-
"use `.insert()` to insert a value into a `{}`, `.get_mut()` \
692-
to modify it, or the entry API for more flexibility",
693-
self.ty,
694-
),
695-
vec![
736+
let index_ty =
737+
self.infcx.tcx.typeck(val.hir_id.owner.def_id).expr_ty(index);
738+
739+
let (borrowed_prefix, borrowed_index);
740+
741+
// only suggest `insert` and `entry` if index is of type K or &{n}K or *{n}K (when there is a Borrow impl for this case).
742+
// We use `peel_refs` because borrow lifetimes may differ in both index and
743+
// key. I.e, if they are of the same base type:
744+
if index_ty.peel_refs() == key_ty.peel_refs() {
745+
let (index_refs, key_refs) =
746+
(count_ty_refs(index_ty), count_ty_refs(key_ty));
747+
748+
let (deref_prefix, deref_index) = if index_refs >= key_refs {
749+
// index is &{n}K
750+
strip_n_refs(index, index_refs - key_refs)
751+
.map(|val| ("".to_string(), val))
752+
.unwrap_or_else(|(depth, val)| {
753+
(
754+
if key_refs == 0 {
755+
"*".repeat(
756+
(index_refs-key_refs).checked_sub(depth).expect("return depth from strip_n_refs should be smaller than the input")
757+
)
758+
} else {
759+
String::new() //if key K is a ref, autoderef finish this for us.
760+
},
761+
val,
762+
)
763+
})
764+
} else {
765+
// in this case the minimal ref addition works for all subcases
766+
("&".repeat(key_refs - index_refs), index)
767+
};
768+
769+
self.err.multipart_suggestion(
770+
format!("use `.insert()` to insert a value into a `{}`", self.ty),
696771
vec![
697-
// val.insert(index, rv);
772+
// val.insert({deref_prefix}{deref_index}, rv);
698773
(
699-
val.span.shrink_to_hi().with_hi(index.span.lo()),
700-
".insert(".to_string(),
774+
val.span.shrink_to_hi().with_hi(deref_index.span.lo()),
775+
format!(".insert({deref_prefix}"),
701776
),
702777
(
703-
index.span.shrink_to_hi().with_hi(rv.span.lo()),
778+
deref_index.span.shrink_to_hi().with_hi(rv.span.lo()),
704779
", ".to_string(),
705780
),
706781
(rv.span.shrink_to_hi(), ")".to_string()),
707782
],
783+
Applicability::MaybeIncorrect,
784+
);
785+
self.err.multipart_suggestion(
786+
format!(
787+
"use the entry API to modify a `{}` for more flexibility",
788+
self.ty
789+
),
708790
vec![
709-
// if let Some(v) = val.get_mut(index) { *v = rv; }
710-
(val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
711-
(
712-
val.span.shrink_to_hi().with_hi(index.span.lo()),
713-
".get_mut(".to_string(),
714-
),
715-
(
716-
index.span.shrink_to_hi().with_hi(place.span.hi()),
717-
") { *val".to_string(),
718-
),
719-
(rv.span.shrink_to_hi(), "; }".to_string()),
720-
],
721-
vec![
722-
// let x = val.entry(index).or_insert(rv);
791+
// let x = val.entry({deref_prefix}{deref_index}).insert_entry(rv);
723792
(val.span.shrink_to_lo(), "let val = ".to_string()),
724793
(
725-
val.span.shrink_to_hi().with_hi(index.span.lo()),
726-
".entry(".to_string(),
794+
val.span.shrink_to_hi().with_hi(deref_index.span.lo()),
795+
format!(".entry({deref_prefix}"),
727796
),
728797
(
729-
index.span.shrink_to_hi().with_hi(rv.span.lo()),
730-
").or_insert(".to_string(),
798+
deref_index.span.shrink_to_hi().with_hi(rv.span.lo()),
799+
").insert_entry(".to_string(),
731800
),
732801
(rv.span.shrink_to_hi(), ")".to_string()),
733802
],
803+
Applicability::MaybeIncorrect,
804+
);
805+
806+
// we can make the next suggestions nicer by stripping as many leading `&` as
807+
// we can, autoderef will do the rest
808+
(borrowed_prefix, borrowed_index) = (
809+
String::new(),
810+
if index_refs > key_refs {
811+
strip_n_refs(index, index_refs - key_refs - 1)
812+
.unwrap_or_else(|(_depth, val)| val)
813+
// even if we tried to strip more, we can stop there thanks to autoderef
814+
} else {
815+
// when the diff is negative or zero, we already are in the index=&Q case.
816+
index
817+
},
818+
);
819+
} else {
820+
(borrowed_prefix, borrowed_index) = (String::new(), index)
821+
}
822+
// in all cases, suggest get_mut because K:Borrow<K> or Q:Borrow<K> as a
823+
// requirement of indexing.
824+
self.err.multipart_suggestion(
825+
format!(
826+
"use `.get_mut()` to modify an existing key in a `{}`",
827+
self.ty,
828+
),
829+
vec![
830+
// if let Some(v) = val.get_mut({borrowed_prefix}{borrowed_index}) { *v = rv; }
831+
(val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
832+
(
833+
val.span.shrink_to_hi().with_hi(borrowed_index.span.lo()),
834+
format!(".get_mut({borrowed_prefix}"),
835+
),
836+
(
837+
borrowed_index.span.shrink_to_hi().with_hi(place.span.hi()),
838+
") { *val".to_string(),
839+
),
840+
(rv.span.shrink_to_hi(), "; }".to_string()),
734841
],
735-
Applicability::MachineApplicable,
842+
Applicability::MaybeIncorrect,
736843
);
844+
737845
self.suggested = true;
738846
} else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
739847
&& let hir::ExprKind::Index(val, index, _) = receiver.kind
@@ -769,6 +877,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
769877
err,
770878
ty,
771879
suggested: false,
880+
infcx: self.infcx,
772881
};
773882
v.visit_body(&body);
774883
if !v.suggested {

0 commit comments

Comments
 (0)